/*-------------------------------------------------------------------------- P O L T E R W R I T E Polterwrite is an object for writing POLTI data files. copyright: see copyright.h Uwe Filges, November 2001 ----------------------------------------------------------------------------*/ #include #include #include #include #include #undef VOID #include "sics.h" #include "event.h" #include "counter.h" #include "HistMem.h" #include "nxdict.h" #include "nxutil.h" #include "motor.h" #include "sicsvar.h" #include "polterwrite.h" /* diaphragm1 - chopper */ #define DIA1DIST 8000 /* histogram memory name */ #define HM "hm" #define DETRADIUS 3000 typedef struct { pObjectDescriptor pDes; pHistMem pHist; int iNew; time_t tUpdate; int iInterval; int iEnd; SConnection *pCon; char *dictfile; char *pFile; }Polterdi, *pPolterdi; /* ------------------- forward declaration of task function --------------*/ static int PoldiTask(void *pData); static void PoldiUpdate(pPolterdi self, SConnection *pCon); /*------------------ The Countstart Callback Function ----------------------*/ static int Countstartcallback(int iEvent, void *pEventData, void *pUser) { pPolterdi self = NULL; if(iEvent == COUNTSTART) { self = (pPolterdi)pUser; assert(self); self->iNew = 1; self->iEnd = 0; self->tUpdate = time(NULL); self->pCon = (SConnection *)pEventData; TaskRegister(pServ->pTasker,PoldiTask,NULL,NULL,self,1); return 1; } return 1; } /*------------------ The Countend Callback Function ----------------------*/ static int Countendcallback(int iEvent, void *pEventData, void *pUser) { pPolterdi self = NULL; if(iEvent == COUNTEND) { self = (pPolterdi)pUser; assert(self); self->tUpdate = time(NULL); self->iEnd = 1; PoldiUpdate(self,self->pCon); return 1; } return 1; } /*-----------------------------------------------------------------------*/ static void SNError(void *pData, char *text) { SConnection *pCon; assert(pData); pCon = (SConnection *)pData; SCWrite(pCon,text,eError); } /*-------------------------------------------------------------------*/ static void writePolterdiGlobal(NXhandle hfil, NXdict hdict, SConnection *pCon){ char pBueffel[512]; SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"etitle","title"); SNXFormatTime(pBueffel,511); NXDputalias(hfil,hdict,"estart",pBueffel); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"iname","instrument"); sprintf(pBueffel,"%d",strlen("SINQ, PSI, Switzerland")); NXDupdate(hdict,"strdim",pBueffel); NXDputalias(hfil,hdict,"sname","SINQ, PSI, Switzerland"); sprintf(pBueffel,"%d",strlen("continous spallation source")); NXDupdate(hdict,"strdim",pBueffel); NXDputalias(hfil,hdict,"stype","continous spallation source"); NXDupdate(hdict,"strdim","132"); } /*-------------------------------------------------------------------*/ static void writeChopper(NXhandle hfil, NXdict hdict, SConnection *pCon){ SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"cname","choppername"); SNXSPutDrivable(pServ->pSics,pCon,hfil,hdict,"chopperspeed","crot"); } /*-------------------------------------------------------------------*/ static void writeDiaphragm1(NXhandle hfil, NXdict hdict, SConnection *pCon){ float dist; SNXSPutMotor(pServ->pSics,pCon,hfil,hdict,"dia1x","d1hl"); SNXSPutMotorNull(pServ->pSics,pCon,hfil,hdict,"dia1x0","d1hl"); SNXSPutMotor(pServ->pSics,pCon,hfil,hdict,"dia1y","d1hr"); SNXSPutMotorNull(pServ->pSics,pCon,hfil,hdict,"dia1y0","d1hr"); dist = (float)DIA1DIST; NXDputalias(hfil,hdict,"dia1dist",&dist); } /*------------------------------------------------------------------*/ static void writeDiaphragm2(NXhandle hfil, NXdict hdict, SConnection *pCon){ SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2x_plus", "d2hl"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2xplus0", "d2hl"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2x_minus", "d2hr"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2xminus0", "d2hr"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2z_plus", "d2vu"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2zplus0", "d2vu"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "dia2z_minus", "d2vl"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "dia2zminus0", "d2vl"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"dia2dist","dia1_dia2"); } /*--------------------------------------------------------------------*/ static void writeSample(NXhandle hfil, NXdict hdict, SConnection *pCon) { SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"sdist","dia2_sample"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"chopperdist","chopper_sample"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"saname","sample"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"senvir","environment"); /* SNXSPutEVVar(hfil,hdict,"temperature",pCon,"stemp","stddev"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "srsu", "rsu"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "srsu0", "rsu"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "srsl", "rsl"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "srsl0", "rsl"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "srsa", "rsa"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "srsa0", "rsa"); */ SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sshu", "shu"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "sshu0", "shu"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sshl", "shl"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "sshl0", "shl"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssgu", "sgu"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssgu0", "sgu"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssgl", "sgl"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssgl0", "sgl"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssv", "sv"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssv0", "sv"); SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "ssa", "sa"); SNXSPutMotorNull(pServ->pSics, pCon, hfil, hdict, "ssa0", "sa"); } /*--------------------------------------------------------------------*/ static int PoldiStart(pPolterdi self, SConnection *pCon) { char pBueffel[256]; NXhandle hfil = NULL; NXdict hdict= NULL; int status; const float *fTime = NULL; CounterMode eMode; float *fTime2 = NULL,fTheta0[801],fTheta[801], fVal; pSicsVariable pVar = NULL; float det_radius, det_size, x0det, y0det, twothet; float pi, alpha1, alphasamp, sms, phidetav, phim; float phi2det, val1, val2, nodet,scancheck; int iLength, i, nzell; pMotor sa; HistInt *lData = NULL; long lVal; /* create filename */ self->pFile = SNXMakeFileName(pServ->pSics,pCon); if(!self->pFile) { SCWrite(pCon,"ERROR: Extra severe: failed to create data file name", eError); return 0; } /* create a Nexus file */ NXopen(self->pFile,NXACC_CREATE,&hfil); if(!hfil) { SCWrite(pCon,"ERROR: cannot create data file ",eError); return 0; } /* tell Uwe User what we are doing */ pVar = NULL; pVar = FindVariable(pServ->pSics,"scancheck"); if(pVar) { VarGetFloat(pVar, &scancheck); } else { SCWrite(pCon,"ERROR: Command not found!",eError); return; } if (scancheck == 0) { sprintf(pBueffel,"Writing %s ......",self->pFile); SCWrite(pCon,pBueffel,eWarning); } /* write globals */ SNXSPutGlobals(hfil,self->pFile,"POLDI",pCon); /* open nxdict */ status = NXDinitfromfile(self->dictfile,&hdict); if(status != NX_OK) { sprintf(pBueffel,"ERROR: failed to open dictionary file %s", self->dictfile); SCWrite(pCon,pBueffel,eError); SCWrite(pCon,"ERROR: Aborting data file writing",eError); SCWrite(pCon,"ERROR: This is a SERIOUS problem!",eError); SCWrite(pCon,"ERROR: DATA NOT WRITTEN",eError); NXclose(&hfil); return 0; } writePolterdiGlobal(hfil,hdict,pCon); writeChopper(hfil,hdict,pCon); writeDiaphragm1(hfil,hdict,pCon); writeDiaphragm2(hfil,hdict,pCon); writeSample(hfil,hdict,pCon); /* write time binning */ fTime = GetHistTimeBin(self->pHist,&iLength); fTime2 = (float *)malloc(iLength*sizeof(float)); if(fTime2) { for(i = 0;i < iLength; i++) { fTime2[i] = fTime[i]/2.; } sprintf(pBueffel,"%d",iLength); NXDupdate(hdict,"timebin",pBueffel); NXDputalias(hfil,hdict,"dtime",fTime2); free(fTime2); } else { SCWrite(pCon,"ERROR: out of memory while writing time binning",eError); } /* theta calculation */ det_radius = (float)DETRADIUS; pVar = FindVariable(pServ->pSics,"det_size"); if(pVar) { VarGetFloat(pVar,&det_size); } else { SCWrite(pCon,"ERROR: Command not found!",eError); return; } pVar = NULL; pVar = FindVariable(pServ->pSics,"nodet"); if(pVar) { VarGetFloat(pVar,&nodet); } else { SCWrite(pCon,"ERROR: Command not found!",eError); return; } pVar = NULL; nzell = (int)nodet; pVar = FindVariable(pServ->pSics,"x0_det"); if(pVar) { VarGetFloat(pVar,&x0det); } else { SCWrite(pCon,"ERROR: Command not found!",eError); return; } pVar = NULL; pVar = FindVariable(pServ->pSics,"y0_det"); if(pVar) { VarGetFloat(pVar, &y0det); } else { SCWrite(pCon,"ERROR: Command not found!",eError); return; } pVar = NULL; pVar = FindVariable(pServ->pSics,"twotheta"); if(pVar) { VarGetFloat(pVar, &twothet); } else { SCWrite(pCon,"ERROR: Command not found!",eError); return; } pi = 3.1415926536; /* transformation to radient */ twothet = twothet*pi/180; if (x0det < 0) { alpha1 = atan(y0det/x0det); } if (x0det > 0) { alpha1 = pi + atan(y0det/x0det); } alphasamp=pi + alpha1 - twothet; sms = sqrt(x0det*x0det + y0det*y0det); phidetav = pi - alphasamp - asin(sms/det_radius*sin(alphasamp)) + alpha1; phim = atan(y0det/x0det); if (phim < 0) { phim = pi + phim; } for(i = 0; i <= nzell; i++) { phi2det = phidetav+(i-0.5*(nzell-1.0))*det_size/(det_radius); val1 = det_radius*sin(phi2det) - sms*sin(phim); val2 = det_radius*cos(phi2det) - sms*cos(phim); fTheta0[i] = atan(val1/val2); if (fTheta0[i] < 0) { fTheta0[i] = pi + fTheta0[i]; } /* transformation to degree */ fTheta0[i] = fTheta0[i]*180/pi; } for (i=0;i<=nzell;i++) { fTheta[i]=fTheta0[nzell-i]; } NXDputalias(hfil,hdict,"dtheta",fTheta); NXDputalias(hfil,hdict,"detector_radius",&det_radius); NXDputalias(hfil,hdict,"cell_size",&det_size); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"ddist","detectordist"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"sangle","scatt_angle"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"detx0","x0_det"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"dety0","y0_det"); SNXSPutVariable(pServ->pSics,pCon,hfil,hdict,"theta","twotheta"); /* write Histogram */ lData = GetHistogramPointer(self->pHist,pCon); if(lData) { NXDputalias(hfil,hdict,"dcounts",lData); } else { SCWrite(pCon,"ERROR: failed to get histogram data",eError); } /* write counting data */ fVal = GetHistCountTime(self->pHist,pCon); NXDputalias(hfil,hdict,"cntime",&fVal); lVal = GetHistMonitor(self->pHist,1,pCon); NXDputalias(hfil,hdict,"cnmon1",&lVal); eMode = GetHistCountMode(self->pHist); if(eMode == eTimer) { strcpy(pBueffel,"timer"); } else { strcpy(pBueffel,"monitor"); } NXDputalias(hfil,hdict,"cnmode",pBueffel); fVal = GetHistPreset(self->pHist); NXDputalias(hfil,hdict,"cnpreset",&fVal); /* close everything */ NXclose(&hfil); NXDclose(hdict,NULL); self->iNew = 0; } /*---------------------------------------------------------------------------*/ static void PoldiUpdate(pPolterdi self, SConnection *pCon) { char pBueffel[256]; NXhandle hfil = NULL; NXdict hdict = NULL; int status; const float *fTime = NULL; CounterMode eMode; float *fTime2 = NULL, fTheta[801], fVal; pSicsVariable pVar = NULL; float det_radius, det_size, x0det, y0det, twothet; float pi, alpha1, alphasamp, sms, phidetav, phim; float phi2det, val1, val2, nodet, scancheck; int iLength, i, nzell; pMotor sa; HistInt *lData = NULL; long lVal; time_t zeit; /* open everything again */ status = NXopen(self->pFile,NXACC_RDWR,&hfil); if(status != NX_OK) { SCWrite(pCon,"ERROR: cannot reopen data file ",eError); return; } status = NXDinitfromfile(self->dictfile,&hdict); if(status != NX_OK) { sprintf(pBueffel,"ERROR: failed to open dictionary file %s", self->dictfile); SCWrite(pCon,pBueffel,eError); SCWrite(pCon,"ERROR: Aborting data file writing",eError); SCWrite(pCon,"ERROR: This is a SERIOUS problem!",eError); SCWrite(pCon,"ERROR: DATA NOT WRITTEN",eError); NXclose(&hfil); return; } /* tell the user that something is happening */ pVar = NULL; pVar = FindVariable(pServ->pSics,"scancheck"); if(pVar) { VarGetFloat(pVar, &scancheck); } else { SCWrite(pCon,"ERROR: Command not found!",eError); return; } if (scancheck == 0) { time(&zeit); sprintf(pBueffel,"Updating %s on %s ",self->pFile,asctime(localtime(&zeit))); SCWrite(pCon,pBueffel,eWarning); } /* write time binning */ fTime = GetHistTimeBin(self->pHist,&iLength); fTime2 = (float *)malloc(iLength*sizeof(float)); if(fTime2) { for(i = 0;i < iLength; i++) { fTime2[i] = fTime[i]/2.; } sprintf(pBueffel,"%d",iLength); NXDupdate(hdict,"timebin",pBueffel); NXDputalias(hfil,hdict,"dtime",fTime2); free(fTime2); } else { SCWrite(pCon,"ERROR: out of memory while writing time binning",eError); } /* write Histogram */ lData = GetHistogramPointer(self->pHist,pCon); if(lData) { NXDputalias(hfil,hdict,"dcounts",lData); } else { SCWrite(pCon,"ERROR: failed to get histogram data",eError); } /* write counting data */ fVal = GetHistCountTime(self->pHist,pCon); NXDputalias(hfil,hdict,"cntime",&fVal); lVal = GetHistMonitor(self->pHist,1,pCon); NXDputalias(hfil,hdict,"cnmon1",&lVal); lVal = GetHistMonitor(self->pHist,4,pCon); NXDputalias(hfil,hdict,"cnprot",&lVal); eMode = GetHistCountMode(self->pHist); if(eMode == eTimer) { strcpy(pBueffel,"timer"); } else { strcpy(pBueffel,"monitor"); } NXDputalias(hfil,hdict,"cnmode",pBueffel); fVal = GetHistPreset(self->pHist); NXDputalias(hfil,hdict,"cnpreset",&fVal); /* close everything */ NXclose(&hfil); NXDclose(hdict,NULL); } /*------------------------------------------------------------------------- FoLink sets all the links for the NXdata vGroup. Had to be separate because at least one update is necessary before this can be done. -------------------------------------------------------------------------*/ static void PoldiLink(pPolterdi self, SConnection *pCon) { NXhandle hfil = NULL; NXdict hdict = NULL; int status; char pBueffel[512]; /* open everything again */ NXopen(self->pFile,NXACC_RDWR,&hfil); if(!self->pFile) { SCWrite(pCon,"ERROR: cannot reopen data file ",eError); return; } status = NXDinitfromfile(self->dictfile,&hdict); if(status != NX_OK) { sprintf(pBueffel,"ERROR: failed to open dictionary file %s", self->dictfile); SCWrite(pCon,pBueffel,eError); SCWrite(pCon,"ERROR: Aborting data file writing",eError); SCWrite(pCon,"ERROR: This is a SERIOUS problem!",eError); SCWrite(pCon,"ERROR: DATA NOT WRITTEN",eError); NXclose(&hfil); return; } NXDaliaslink(hfil,hdict,"dana","dcounts"); NXDaliaslink(hfil,hdict,"dana","dtheta"); NXDaliaslink(hfil,hdict,"dana","dtime"); /* close everything */ NXclose(&hfil); NXDclose(hdict,NULL); } /*--------------------------------------------------------------------------- This is the task function for updating the data file any now and then automatically --------------------------------------------------------------------------*/ static int PoldiTask(void *pData) { pPolterdi self = NULL; int iWrite, iRet, ltask; self = (pPolterdi)pData; if(!self) return 0; /* figure out if we need to write */ iWrite = 0; iRet = 1; /* first case: update intervall */ if(time(NULL) >= self->tUpdate) { ltask = GetDevexecID(pServ->pExecutor); if (ltask > 0) { self->tUpdate = time(NULL) + self->iInterval; iWrite = 1; iRet = 1; } else { self->iEnd = 1; } } if(self->iEnd == 1) { self->tUpdate = 0; iWrite = 0; iRet = 0; } if(iWrite) { if(self->iNew) { PoldiStart(self,self->pCon); PoldiUpdate(self,self->pCon); PoldiLink(self,self->pCon); } else { PoldiUpdate(self,self->pCon); } } return iRet; } /*----------------------------------------------------------------------*/ static void KillPolterdi(void *pData){ pPolterdi self = (pPolterdi)pData; if(!self) return; if(self->pDes){ DeleteDescriptor(self->pDes); } if(self->pFile){ free(self->pFile); } if(self->dictfile){ free(self->dictfile); } free(self); } /*-----------------------------------------------------------------------*/ int PolterInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { pPolterdi pNew = NULL; pICallBack pCall = NULL; pDummy pDum; pHistMem pHist = NULL; /* configure fortify */ /* iFortifyScope = Fortify_EnterScope(); Fortify_CheckAllMemory(); */ if(argc < 2){ SCWrite(pCon,"ERROR: insufficient number of arguments to PolterInstall", eError); return 0; } pHist = (pHistMem)FindCommandData(pSics,HM,"HistMem"); if (!pHist) { SCWrite(pCon,"ERROR: Histogram memory NOT found",eError); return 0; } pNew = (pPolterdi)malloc(sizeof(Polterdi)); if(!pNew){ SCWrite(pCon,"ERROR: out of memory in PolterInstall", eError); return 0; } memset(pNew,0,sizeof(Polterdi)); pNew->pDes = CreateDescriptor("PoldiWrite"); pNew->pHist = pHist; pNew->dictfile = strdup(argv[1]); pNew->iInterval = 20*60; if(!pNew->pDes || !pNew->dictfile){ SCWrite(pCon,"ERROR: out of memory in PolterInstall", eError); return 0; } /* install callbacks */ pDum = (pDummy)pHist; pCall = (pICallBack)pDum->pDescriptor->GetInterface(pHist,CALLBACKINTERFACE); if(!pCall) { SCWrite(pCon, "ERROR: no callback interface found at your histogram memory", eError); KillPolterdi(pNew); return 0; } RegisterCallback(pCall,COUNTSTART,Countstartcallback,pNew,NULL); RegisterCallback(pCall,COUNTEND,Countendcallback,pNew,NULL); AddCommand(pSics,"storedata",PolterAction,KillPolterdi,pNew); return 1; } /*----------------------------------------------------------------------*/ int PolterAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { int iRet, iVal; pPolterdi self = NULL; char pBueffel[512]; if(argc < 2) { SCWrite(pCon,"ERROR: Insufficient number of arguments to StoreData", eError); return 0; } self = (pPolterdi)pData; assert(self); strtolower(argv[1]); if(strcmp(argv[1],"start") == 0) { PoldiStart(self,pCon); PoldiUpdate(self,pCon); PoldiLink(self,pCon); return 1; } else if(strcmp(argv[1],"update") == 0) { if((self->iNew) || (!self->pFile)) { PoldiStart(self,pCon); PoldiUpdate(self,pCon); PoldiLink(self,pCon); } else { PoldiUpdate(self,pCon); } return 1; } else if(strcmp(argv[1],"getfile") == 0) { sprintf(pBueffel,"StoreData.file = %s",self->pFile); SCWrite(pCon,pBueffel,eValue); return 1; } else if(strcmp(argv[1],"interval") == 0) { if(argc > 2) /* set value */ { if(!SCMatchRights(pCon,usUser)) { return 0; } iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iVal); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: cannot convert --> %s <-- to number ", argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } self->iInterval = iVal*60; /* go to seconds from minutes*/ SCSendOK(pCon); return 1; } else /* read the value */ { sprintf(pBueffel,"storedata.interval = %d",self->iInterval/60); SCWrite(pCon,pBueffel,eValue); return 1; } } SCWrite(pCon,"ERROR: subcommand to StoreData not recognized",eError); return 0; }