/** * This is a second generation histogram memory object. In contrast * to counters and motors no attempt is made to provide backwards * compatability with the old SICS way of doing things. This * histogram memory object quite sensibly is derived from * the counter object. It adds a rank, dimensions and variable * data and a configuration method. For TOF, methods and variables * for generating and maintaining time binnings are provided too. * * copyright: see file COPYRIGHT * * Mark Koennecke, May 2009 * * Added bridging routines implementing first gen HM interfaces * * Mark Koennecke, December 2012 */ #include #include #include #include "HistMem.h" #include "HistMem.i" #include "arrayutil.h" #define CONFIG 1005 /* from countersec.c. */ int SecCtrInvokeFunction(pCounter self, SConnection *pCon, int code); /*-------------------------------------------------------------------------*/ static int initArray(pCounter self, int value) { pHdb rank = NULL, dim = NULL, data = NULL, datalength; int i, length; hdbValue v; rank = GetHipadabaNode(self->pDes->parNode,"rank"); assert(rank != NULL); dim = GetHipadabaNode(self->pDes->parNode,"dim"); assert(dim != NULL); data = GetHipadabaNode(self->pDes->parNode,"data"); assert(data != NULL); datalength = GetHipadabaNode(self->pDes->parNode,"datalength"); assert(datalength != NULL); length = dim->value.v.intArray[0]; for(i = 1; i < dim->value.arrayLength; i++){ length *= dim->value.v.intArray[i]; } /* printf("initArray called with length %d\n", length);*/ v = MakeHdbInt(length); UpdateHipadabaPar(datalength, v, NULL); v = makeHdbValue(HIPINTVARAR, length); if(v.v.intArray == NULL){ return 0; } for(i = 0; i < length; i++){ v.v.intArray[i] = value; } UpdateHipadabaPar(data,v,NULL); ReleaseHdbValue(&v); return 1; } /*-------------------------------------------------------------------------*/ static hdbCallbackReturn HMDimCallback(pHdb currentNode, void *data, pHdbMessage message) { pHdbDataMessage update = NULL; if((update = GetHdbUpdateMessage(message)) != NULL){ copyHdbValue(update->v, ¤tNode->value); initArray((pCounter)data, 0); } return hdbContinue; } /*--------------------------------------------------------------------------*/ static int ResetCmd(pSICSOBJ ccmd, SConnection * pCon, Hdb * cmdNode, Hdb * par[], int nPar) { if(nPar < 1){ SCWrite(pCon, "ERROR: need a parameter to set", eError); return 0; } if(!initArray((pCounter) ccmd, par[0]->value.v.intValue )){ SCWrite(pCon,"ERROR: out of memory initializing HM", eError); return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int NoTimeBinCmd(pSICSOBJ ccmd, SConnection * pCon, Hdb * cmdNode, Hdb * par[], int nPar) { pHdb timeNode = NULL; timeNode = GetHipadabaNode(ccmd->objectNode,"time_binning"); if(timeNode == NULL){ SCWrite(pCon,"ERROR: HM has no time binning",eError); return 0; } SCPrintf(pCon,eValue,"%s.totimebin = %d", ccmd->objectNode->name, timeNode->value.arrayLength); return 1; } /*--------------------------------------------------------------------------*/ static int TimebinsCmd(pSICSOBJ ccmd, SConnection * pCon, Hdb * cmdNode, Hdb * par[], int nPar) { pHdb timeNode = NULL; pDynString data= NULL; timeNode = GetHipadabaNode(ccmd->objectNode,"time_binning"); if(timeNode == NULL){ SCWrite(pCon,"ERROR: HM has no time binning",eError); return 0; } data = formatValue(timeNode->value,timeNode); if(data != NULL){ SCPrintf(pCon,eValue,"%s.timebins = %s", ccmd->objectNode->name, GetCharArray(data)); DeleteDynString(data); } else { SCWrite(pCon,"ERROR: out of memory formatting timebins", eError); return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int GenbinCmd(pSICSOBJ ccmd, SConnection * pCon, Hdb * cmdNode, Hdb * par[], int nPar) { double start, step; int np, i; pHdb tof = NULL, dim = NULL; hdbValue v; if(nPar < 3){ SCWrite(pCon, "ERROR: need start step n parameters to gengin", eError); return 0; } start = par[0]->value.v.doubleValue; step = par[1]->value.v.doubleValue; np = par[2]->value.v.intValue; tof = GetHipadabaNode(ccmd->pDes->parNode,"time_binning"); assert(tof != NULL); dim = GetHipadabaNode(ccmd->pDes->parNode,"dim"); assert(dim != NULL); v = makeHdbValue(HIPFLOATVARAR,np ); if(v.v.floatArray == NULL){ SCWrite(pCon,"ERROR: out of memory in genbin", eError); return 0; } for(i = 0; i < np; i++){ v.v.floatArray[i] = start + i*step; } UpdateHipadabaPar(tof,v,pCon); ReleaseHdbValue(&v); GetHipadabaPar(dim,&v, pCon); v.v.intArray[v.arrayLength-1] = np; UpdateHipadabaPar(dim,v,pCon); return 1; } /*--------------------------------------------------------------------------*/ static int ConfigureCmd(pSICSOBJ ccmd, SConnection * pCon, Hdb * cmdNode, Hdb * par[], int nPar) { pHdb dimNode = NULL; if(nPar < 1) { SCWrite(pCon,"ERROR: need a parameter to read", eError); return 0; } dimNode = GetHipadabaNode(ccmd->objectNode,"dim"); assert(dimNode != NULL); if(strcmp(par[0]->value.v.text,"dim0") == 0){ SCPrintf(pCon,eValue,"%s.dim0 = %d", ccmd->objectNode->name, dimNode->value.v.intArray[0]); } else if(strcmp(par[0]->value.v.text,"dim1") == 0){ SCPrintf(pCon,eValue,"%s.dim1 = %d", ccmd->objectNode->name, dimNode->value.v.intArray[1]); } else { SCPrintf(pCon,eError,"ERROR: subcommand %s to configure not found", par[0]->value.v.text); return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int SumCmd(pSICSOBJ ccmd, SConnection * pCon, Hdb * cmdNode, Hdb * par[], int nPar) { pHdb dimNode = NULL, dataNode = NULL; int xstart, xend, ystart, yend, i; long lSum = 0; dimNode = GetHipadabaNode(ccmd->objectNode,"dim"); dataNode = GetHipadabaNode(ccmd->objectNode,"data"); assert(dimNode != NULL && dataNode != NULL); switch(dimNode->value.arrayLength){ case 1: if(nPar < 2) { SCWrite(pCon,"ERROR: need start and end for summing 1D data",eError); return 0; } xstart = par[0]->value.v.intValue; xend = par[1]->value.v.intValue; if(xstart < 0){ xstart = 0; } if(xend > dataNode->value.arrayLength){ xend = dataNode->value.arrayLength; } for(i = xstart; i < xend; i++){ lSum += dataNode->value.v.intArray[i]; } SCPrintf(pCon,eValue,"%s.sum = %ld", ccmd->objectNode->name, lSum); break; case 2: if(nPar < 4) { SCWrite(pCon,"ERROR: need start and end in x and y for summing 2D data",eError); return 0; } xstart = par[0]->value.v.intValue; xend = par[1]->value.v.intValue; if(xstart < 0){ xstart = 0; } if(xend > dimNode->value.v.intArray[0]){ xend = dimNode->value.v.intArray[0]; } ystart = par[2]->value.v.intValue; yend = par[3]->value.v.intValue; if(ystart < 0){ ystart = 0; } if(yend > dimNode->value.v.intArray[1]){ yend = dimNode->value.v.intArray[1]; } lSum = sumWindow(dataNode->value.v.intArray, xstart,xend,dimNode->value.v.intArray[0], ystart, yend, dimNode->value.v.intArray[1]); SCPrintf(pCon,eValue,"%s.sum = %ld", ccmd->objectNode->name, lSum); break; default: SCPrintf(pCon, eError, "ERROR: summing not supported for %d dimensional data", dimNode->value.arrayLength); return 0; } return 1; } /*-------------------------------------------------------------------------*/ static int TotalCmd(pSICSOBJ ccmd, SConnection * pCon, Hdb * cmdNode, Hdb * par[], int nPar) { pHdb dataNode = NULL; long lSum = 0; int i; dataNode = GetHipadabaNode(ccmd->objectNode,"data"); assert(dataNode != NULL); for(i = 0, lSum = 0; i < dataNode->value.arrayLength; i++){ lSum += dataNode->value.v.intArray[i]; } SCPrintf(pCon,eValue,"%s.total = %ld", ccmd->objectNode->name, lSum); return 1; } /*--------------------------------------------------------------------------*/ static int InitCmd(pSICSOBJ ccmd, SConnection * con, Hdb * cmdNode, Hdb * par[], int nPar) { return SecCtrInvokeFunction((pCounter)ccmd,con,CONFIG); } /*--------------------------------------------------------------------------*/ static int HMCtrTransferData(void *pData, SConnection *pCon) { pCounter self = (pCounter)pData; assert(self != NULL); pHdb node = NULL; hdbValue v; int status; node = GetHipadabaNode(self->pDes->parNode,"data"); assert(node != NULL); self->isUpToDate = 1; status = GetHipadabaPar(node,&v,pCon); ReleaseHdbValue(&v); return status; } /*------------------------------------------------------------------------- * automatically update the last entry of the dim variable when * setting time_binning --------------------------------------------------------------------------*/ static hdbCallbackReturn HMTOFCallback(pHdb currentNode, void *data, pHdbMessage message) { pHdbDataMessage update = NULL; hdbValue dim; pHdb dimNode = NULL; if((update = GetHdbUpdateMessage(message)) != NULL){ dimNode = GetHipadabaNode(currentNode->mama,"dim"); assert(dimNode != NULL); GetHipadabaPar(dimNode,&dim,NULL); dim.v.intArray[dim.arrayLength-1] = update->v->arrayLength; UpdateHipadabaPar(dimNode, dim, NULL); } return hdbContinue; } /*-------------------------------------------------------------------------- * Usage: * MakeSecHM name rank (tof) * -------------------------------------------------------------------------*/ int MakeSecHM(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pCounter pRes = NULL; int rank, status; pHdb node = NULL, child = NULL; if(argc < 3) { SCWrite(pCon,"ERROR: need at least a name and rank to create a HM", eError); return 0; } rank = atoi(argv[2]); pRes = CreateSecCounter(pCon,"HistMemSec", argv[1], 2); if(pRes == NULL){ return 0; } /* remove count and rename countnb to it */ node = GetHipadabaNode(pRes->pDes->parNode,"count"); DeleteHipadabaNode(node,NULL); node = GetHipadabaNode(pRes->pDes->parNode,"countnb"); strcpy(node->name,"count"); pRes->pCountInt->TransferData = HMCtrTransferData; node = pRes->objectNode; child = GetHipadabaNode(node,"values"); if(child!= NULL){ DeleteHipadabaNode(child,pCon); } child = MakeSICSHdbPar("rank", usMugger, MakeHdbInt(rank)); if (child == NULL) { return 0; } AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("dim", usMugger, makeHdbValue(HIPINTVARAR,rank)); if (child == NULL) { return 0; } AppendHipadabaCallback(child, MakeHipadabaCallback(HMDimCallback, pRes, NULL)); AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("datalength", usInternal, MakeHdbInt(100)); if (child == NULL) { return 0; } AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("data", usMugger, makeHdbValue(HIPINTVARAR,100)); if (child == NULL) { return 0; } AddHipadabaChild(node, child, NULL); child = AddSICSHdbPar(node,"set", usMugger, MakeSICSFunc(ResetCmd)); AddSICSHdbPar(child, "value", usUser, MakeHdbInt(0)); child = AddSICSHdbPar(node,"init", usMugger, MakeSICSFunc(InitCmd)); child = AddSICSHdbPar(node,"sum", usSpy, MakeSICSFunc(SumCmd)); AddSICSHdbPar(child, "xstart", usSpy, MakeHdbInt(0)); AddSICSHdbPar(child, "xend", usSpy, MakeHdbInt(0)); AddSICSHdbPar(child, "ystart", usSpy, MakeHdbInt(0)); AddSICSHdbPar(child, "yend", usSpy, MakeHdbInt(0)); child = AddSICSHdbPar(node,"total", usSpy, MakeSICSFunc(TotalCmd)); /* * test TOF option */ if(argc > 3){ if(strcmp(argv[3],"tof") == 0){ child = MakeSICSHdbPar("time_binning", usMugger, makeHdbValue(HIPFLOATVARAR,100)); if (child == NULL) { return 0; } AddHipadabaChild(node, child, NULL); AppendHipadabaCallback(child, MakeHipadabaCallback(HMTOFCallback, NULL, NULL)); child = AddSICSHdbPar(node,"genbin", usMugger, MakeSICSFunc(GenbinCmd)); AddSICSHdbPar(child, "start", usMugger, MakeHdbFloat(10.)); AddSICSHdbPar(child, "step", usMugger, MakeHdbFloat(10.)); AddSICSHdbPar(child, "np", usMugger, MakeHdbInt(10)); child = AddSICSHdbPar(node,"notimebin", usSpy, MakeSICSFunc(NoTimeBinCmd)); child = AddSICSHdbPar(node,"timebins", usSpy, MakeSICSFunc(TimebinsCmd)); } } status = AddCommand(pSics, argv[1], InterInvokeSICSOBJ, DeleteCounter, (void *) pRes); if (status != 1) { SCPrintf(pCon,eError, "ERROR: duplicate command %s not created", argv[1]); return 0; } return 1; } /*=========================================================================== This is a set of adapter functions which make the second gen HM look like a first generation one. This saves me from rewriting all the calculation codes based on the first gen HM !!!! BEWARE: In the functions below pHistMem should never be a pointer to a HistMem but rather a second generation HM which is a counter object !!!! ===============================================================================*/ const float *GetSecHistTimeBin(pHistMem self, int *iLength) { float *tb = NULL; pHdb tbNode = NULL; int i; pCounter pCter; assert(self->pDes->parNode != NULL); pCter = (pCounter)self; tbNode = GetHipadabaNode(self->pDes->parNode,"time_binning"); if(tbNode == NULL){ return NULL; } *iLength = tbNode->value.arrayLength; if(*iLength != pCter->tbLength){ if(pCter->timeBinning){ free(pCter->timeBinning); } pCter->timeBinning = malloc(*iLength*sizeof(float)); } for(i = 0; i < *iLength; i++){ pCter->timeBinning[i] = tbNode->value.v.floatArray[i]; } return (const float*)pCter->timeBinning; } /*---------------------------------------------------------------------------*/ HistInt *GetSecHistogramPointer(pHistMem self,SConnection *pCon) { pHdb dataNode = NULL; assert(self->pDes->parNode != NULL); dataNode = GetHipadabaNode(self->pDes->parNode,"data"); if(dataNode == NULL){ return NULL; } return (HistInt *)dataNode->value.v.intArray; } /*--------------------------------------------------------------------------*/ int GetSecHistogram(pHistMem self, SConnection *pCon, int i,int iStart, int iEnd, HistInt *lData, int iDataLen) { pHdb dataNode = NULL; assert(self->pDes->parNode != NULL); dataNode = GetHipadabaNode(self->pDes->parNode,"data"); if(dataNode == NULL){ return 0; } if(iEnd > dataNode->value.arrayLength){ iEnd = dataNode->value.arrayLength; } if ((iEnd - iStart) > iDataLen / sizeof(HistInt)) { SCWrite(pCon, "WARNING: truncating request to fit data space", eWarning); iEnd = (iDataLen / sizeof(HistInt)) - 1; } memcpy(lData,dataNode->value.v.intArray+iStart, (iEnd-iStart)*sizeof(int)); return 1; } /*-------------------------------------------------------------------------*/ void SecHistDirty(pHistMem self) { /* Nothing to do */ } /*-------------------------------------------------------------------------*/ int GetSecHistLength(pHistMem self) { pHdb dataNode = NULL; int i, length = 1; assert(self->pDes->parNode != NULL); dataNode = GetHipadabaNode(self->pDes->parNode,"dim"); if(dataNode == NULL){ return 0; } for(i = 0; i < dataNode->value.arrayLength; i++){ length *= dataNode->value.v.intArray[i]; } return length; }