398 lines
10 KiB
C
398 lines
10 KiB
C
/*-----------------------------------------------------------------------
|
|
This is a data handling class for histogram memory data.
|
|
For more information see hmdata.tex.
|
|
|
|
copyright: see file COPYRIGHT
|
|
|
|
Mark Koennecke, January 2003
|
|
-------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include "fortify.h"
|
|
#include "hmdata.h"
|
|
#include "HistMem.h"
|
|
#include "HistMem.i"
|
|
#include "HistDriv.i"
|
|
#include "countdriv.h"
|
|
/*----------------------------------------------------------------------*/
|
|
pHMdata makeHMData(void) {
|
|
pHMdata self = NULL;
|
|
|
|
self = (pHMdata)malloc(sizeof(HMdata));
|
|
if(self == NULL){
|
|
return NULL;
|
|
}
|
|
memset(self,0,sizeof(HMdata));
|
|
self->nTimeChan = 1;
|
|
self->updateFlag = 1;
|
|
|
|
return self;
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
void killHMData(pHMdata self){
|
|
if(self->localBuffer != NULL){
|
|
free(self->localBuffer);
|
|
}
|
|
free(self);
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
void clearHMData(pHMdata self){
|
|
long size;
|
|
int i;
|
|
size = 1;
|
|
for(i = 0; i < self->rank; i++){
|
|
size *= self->iDim[i];
|
|
}
|
|
if(self->tofMode){
|
|
size *= self->nTimeChan;
|
|
}
|
|
memset(self->localBuffer,0,size*sizeof(HistInt));
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int resizeBuffer(pHMdata self){
|
|
long size;
|
|
int i;
|
|
|
|
size = 1;
|
|
for(i = 0; i < self->rank; i++){
|
|
size *= self->iDim[i];
|
|
}
|
|
if(self->tofMode){
|
|
size *= self->nTimeChan;
|
|
}
|
|
if(self->localBuffer != NULL){
|
|
free(self->localBuffer);
|
|
self->localBuffer = NULL;
|
|
}
|
|
self->localBuffer = (HistInt *)malloc(size*sizeof(HistInt));
|
|
if(!self->localBuffer){
|
|
return 0;
|
|
}
|
|
memset(self->localBuffer,0,size*sizeof(HistInt));
|
|
self->updateFlag = 1;
|
|
return 1;
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
int configureHMdata(pHMdata self, pStringDict pOpt,
|
|
SConnection *pCon){
|
|
int status, i;
|
|
float fVal;
|
|
char pValue[80];
|
|
|
|
if(self->nTimeChan > 2) {
|
|
self->tofMode = 1;
|
|
} else {
|
|
self->tofMode = 0;
|
|
}
|
|
status = StringDictGetAsNumber(pOpt,"rank",&fVal);
|
|
if(!status){
|
|
SCWrite(pCon,"ERROR: critical configuration problem: no rank found",
|
|
eError);
|
|
return 0;
|
|
}
|
|
self->rank = (int)rint(fVal);
|
|
|
|
for(i = 0; i < self->rank; i++){
|
|
sprintf(pValue,"dim%1.1d",i);
|
|
status = StringDictGetAsNumber(pOpt,pValue,&fVal);
|
|
if(!status){
|
|
sprintf(pValue,"ERROR dimension %d not found!!", i);
|
|
return 0;
|
|
}
|
|
self->iDim[i] = (int)rint(fVal);
|
|
}
|
|
|
|
status = StringDictGetAsNumber(pOpt,"update",&fVal);
|
|
if(!status){
|
|
self->updateIntervall = 0; /* no buffering */
|
|
} else {
|
|
self->updateIntervall = (int)rint(fVal);
|
|
}
|
|
|
|
/*
|
|
invalidate buffer
|
|
*/
|
|
if(self->localBuffer != NULL){
|
|
free(self->localBuffer);
|
|
self->localBuffer = NULL;
|
|
}
|
|
|
|
/*
|
|
note: remove update request in histmem.c
|
|
*/
|
|
if(self->updateIntervall > 0){
|
|
/*
|
|
we do buffer
|
|
*/
|
|
status = resizeBuffer(self);
|
|
if(!status){
|
|
SCWrite(pCon,"ERROR: failed to resize buffer",eError);
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
int genTimeBinning(pHMdata self, float start, float step, int noSteps){
|
|
int i;
|
|
|
|
if(noSteps >= MAXCHAN){
|
|
return 0;
|
|
}
|
|
for(i = 0; i < noSteps; i++){
|
|
self->timeBinning[i] = start + i*step;
|
|
}
|
|
self->tofMode = 1;
|
|
self->nTimeChan = noSteps;
|
|
return resizeBuffer(self);
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
int setTimeBin(pHMdata self, int index, float value){
|
|
if(index >= 0 && index < MAXCHAN){
|
|
self->timeBinning[index] = value;
|
|
} else {
|
|
return 0;
|
|
}
|
|
self->tofMode = 1;
|
|
if(index > self->nTimeChan){
|
|
self->nTimeChan = index;
|
|
return resizeBuffer(self);
|
|
}
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------*/
|
|
int isInTOFMode(pHMdata self){
|
|
return self->tofMode;
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
int getNoOfTimebins(pHMdata self){
|
|
return self->nTimeChan;
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
float *getTimeBinning(pHMdata self){
|
|
return self->timeBinning;
|
|
}
|
|
/*-------------------------------------------------------------------*/
|
|
void clearTimeBinning(pHMdata self){
|
|
self->nTimeChan = 1;
|
|
self->tofMode = 0;
|
|
resizeBuffer(self);
|
|
}
|
|
/*--------------------------------------------------------------------*/
|
|
void getHMDataDim(pHMdata self, int iDim[MAXDIM], int *rank){
|
|
memcpy(iDim,self->iDim,self->rank*sizeof(int));
|
|
*rank = self->rank;
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
long getHMDataLength(pHMdata self){
|
|
long length = 1;
|
|
int i;
|
|
for(i = 0; i < self->rank; i++){
|
|
length *= self->iDim[i];
|
|
}
|
|
if(self->tofMode){
|
|
length *= self->nTimeChan;
|
|
}
|
|
return length;
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
void updateHMData(pHMdata self){
|
|
self->updateFlag = 1;
|
|
}
|
|
/*--------------------------------------------------------------------
|
|
The idea here is that upper level code sets the updateFlag through
|
|
updateHMData (above) whenever the HM changes (counts). If this flag is set
|
|
the next call to get getHMDataHistogram will read a new copy from the HM.
|
|
After reading nextUpdate is set to time + updateIntervall. In order to
|
|
prevent clients hammering the HM nextUpdate is checked as well.
|
|
updateIntervall can be set to a reasonable time intervall between updates in seconds. If updateIntervall is 0, a direct read is always perfomed.
|
|
If this system needs to be bypassed altogether (because there is no memory
|
|
to buffer all HM) use GetHistogramDirect (histogram.c) instead which acts
|
|
on the driver level.
|
|
--------------------------------------------------------------------------*/
|
|
static int mustUpdate(pHMdata self){
|
|
if(self->updateFlag == 1 && time(NULL) >= self->nextUpdate){
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
static int updateHMbuffer(pHistMem hist, int bank, SConnection *pCon){
|
|
int status, iErr, i;
|
|
char pError[80], pBueffel[256];
|
|
pHMdata self = hist->pDriv->data;
|
|
|
|
assert(self);
|
|
|
|
for(i = 0; i < 3; i++){
|
|
status = hist->pDriv->GetHistogram(hist->pDriv,pCon,
|
|
bank,0,getHMDataLength(self),
|
|
self->localBuffer);
|
|
if(status == OKOK){
|
|
self->nextUpdate = time(NULL) + self->updateIntervall;
|
|
self->updateFlag = 0;
|
|
break;
|
|
} else{
|
|
status = hist->pDriv->GetError(hist->pDriv,&iErr,pError,79);
|
|
sprintf(pBueffel,"ERROR: %s ",pError);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
status = hist->pDriv->TryAndFixIt(hist->pDriv,iErr);
|
|
if(status == COTERM) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if(status == OKOK){
|
|
return 1;
|
|
} else {
|
|
return HWFault;
|
|
}
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
int getHMDataHistogram(pHistMem hist, SConnection *pCon,
|
|
int bank, int start, int length,
|
|
HistInt *lData){
|
|
int status;
|
|
pHMdata self = hist->pDriv->data;
|
|
HistInt *lStart;
|
|
|
|
assert(self);
|
|
|
|
if(self->localBuffer == NULL){
|
|
resizeBuffer(self);
|
|
}
|
|
|
|
/*
|
|
update buffer if necessary
|
|
*/
|
|
if(mustUpdate(self)){
|
|
status = updateHMbuffer(hist,bank,pCon);
|
|
if(status != OKOK){
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/*
|
|
copy buffered data to lData
|
|
*/
|
|
lStart = self->localBuffer + start;
|
|
if(start + length > getHMDataLength(self)){
|
|
length = getHMDataLength(self) - start - 1;
|
|
}
|
|
memcpy(lData,lStart,length*sizeof(HistInt));
|
|
return 1;
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
HistInt *getHMDataBufferPointer(pHistMem hist,SConnection *pCon){
|
|
int status;
|
|
pHMdata self = hist->pDriv->data;
|
|
|
|
assert(self);
|
|
|
|
if(self->localBuffer == NULL){
|
|
resizeBuffer(self);
|
|
}
|
|
/*
|
|
update buffer if necessary
|
|
*/
|
|
if(mustUpdate(self)){
|
|
status = updateHMbuffer(hist,0,pCon);
|
|
if(status != OKOK){
|
|
return NULL;
|
|
}
|
|
}
|
|
return self->localBuffer;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static long SumRow(HistInt *iData, int iDataLength, int iStart, int iEnd){
|
|
int i;
|
|
long lSum;
|
|
|
|
if(iEnd > iDataLength){
|
|
return -1;
|
|
}
|
|
|
|
lSum = 0;
|
|
for(i = iStart; i < iEnd; i++){
|
|
lSum += iData[i];
|
|
}
|
|
return lSum;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
long sumHMDataRectangle(pHistMem hist, SConnection *pCon,
|
|
int iStart[MAXDIM], int iEnd[MAXDIM]) {
|
|
HistInt *iData;
|
|
pHMdata self = hist->pDriv->data;
|
|
int i, iHistLength, status, iIndex;
|
|
char pBueffel[256];
|
|
unsigned long lSum, lRowSum;
|
|
|
|
assert(self);
|
|
|
|
/*
|
|
error checking
|
|
*/
|
|
for(i = 0; i < self->rank; i++){
|
|
if( (iStart[i] < 0) || (iStart[i] > self->iDim[i]) ) {
|
|
sprintf(pBueffel,"ERROR: %d is out of data dimension range",
|
|
iStart[i]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return -1;
|
|
}
|
|
if( (iEnd[i] < 0) || (iEnd[i] > self->iDim[i]) ){
|
|
sprintf(pBueffel,"ERROR: %d is out of data dimension range",
|
|
iEnd[i]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if(self->localBuffer == NULL){
|
|
resizeBuffer(self);
|
|
}
|
|
|
|
/*
|
|
get an update of the HM if necessary
|
|
*/
|
|
if(mustUpdate(self)){
|
|
status = updateHMbuffer(hist,0,pCon);
|
|
if(status != OKOK){
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
iHistLength = getHMDataLength(self);
|
|
/* actually sum */
|
|
switch(self->rank)
|
|
{
|
|
case 1:
|
|
lSum = SumRow(self->localBuffer, iHistLength,
|
|
iStart[0], iEnd[0]);
|
|
break;
|
|
case 2:
|
|
lSum = 0;
|
|
for(i = iStart[0]; i < iEnd[0]; i++){
|
|
iIndex = i*self->iDim[1];
|
|
lRowSum = SumRow(self->localBuffer,iHistLength,
|
|
iIndex+iStart[1], iIndex+iEnd[1]);
|
|
lSum += lRowSum;
|
|
}
|
|
break;
|
|
default:
|
|
sprintf(pBueffel,
|
|
"ERROR: summing in %d dimensions not yet implemented",
|
|
self->rank);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return -1;
|
|
break;
|
|
}
|
|
if(lSum < 0){
|
|
lSum = -lSum;
|
|
}
|
|
return lSum;
|
|
}
|