/*------------------------------------------------------------------------- M E S U R E An object for doing four circle diffractometer measurements with a single counter. copyright: see copyright.h Mark Koennecke, April 1998 heavily reworked: Mark Koennecke, February-March 2005 ---------------------------------------------------------------------------*/ #include #include #include #include #include #include "fortify.h" #include "sics.h" #include "motor.h" #include "o2t.h" #include "scan.h" #include "scan.i" #include "stdscan.h" #include "danu.h" #include "integrate.h" #include "hkl.h" #include "matrix/matrix.h" #include "hkl.i" #include "sicsvar.h" #include "evcontroller.h" #include "mesure.h" #include "nxscript.h" #include "fourtable.h" #include "lld.h" #include "stdscan.h" #include "exeman.h" extern void SNXFormatTime(char *pBueffel, int iLen); extern float nintf(float f); #define ANGERR 0.2 /* #define MESSDEBUG 1 define MESSDEBUG for simulated peaks. This helps in debugging this code and the initial data correction code */ extern void SNXFormatTime(char *pBueffel, int iLen); /* nxutil.c */ /*------------------- the data structure -----------------------------------*/ typedef struct __Mesure { pObjectDescriptor pDes; /* standard object descriptor */ pICallBack pCall; /* callback interface for automatic notification */ pScanData pScanner; /* scan object to use for scans */ pHKL pCryst; /* hkl object for crystallographic calc and reflection driving */ pMotor pOmega; /* motor for omega scans */ pMotor p2Theta; /* motor for 2 theta scans*/ char *pCOmega; /* name of omega motor */ char *pC2Theta; /* name of 2 theta motor */ char *pFileRoot; /* where to write files */ pDataNumber pDanu; /* where to get data file number */ FILE *fRefl; /* reflection profile file */ FILE *fHKL; /* integrated intensity file */ int iLogFile; /* log file num at connection */ SConnection *pCon; /* log file owning connection */ char *pCurrentFile; /* current file root */ char headerTemplate[512]; int iCount; /* count of reflection */ int CountMode; /* timer or preset */ int np; /* number of scan points */ float fPreset; /* counting preset */ float fStep; /* omega step widths */ long *lCounts; /* array to store counting values */ float fPosition[4]; /* the real positions after driving */ int iCompact; /* true if compact scan ouput. */ int weak; /* weak flag: remeasure weak reflections */ long weakThreshold; /* threshold when a peak is so weak that is has to remeasured */ int fastScan; /* flag for using fastscans for scanning reflections */ int psiMode; /* 1 for psi scan mode, 0 else */ int psd; /* a flag for making 2D detector scans */ int stepTable; /* mapping of two theta ranges to step width and variable to scan */ } Mesure; /*-------------------------------------------------------------------------*/ static int SaveMesure(void *pData, char *name, FILE *fd) { pMesure self = (pMesure)pData; fprintf(fd,"#Four Circle Dataset Module %s\n",name); if(self->CountMode == eTimer) { fprintf(fd,"%s countmode timer\n",name); } else { fprintf(fd,"%s countmode monitor\n",name); } fprintf(fd,"%s np %d\n", name, self->np); fprintf(fd,"%s preset %f\n", name, self->fPreset); fprintf(fd,"%s step %f\n", name, self->fStep); fprintf(fd,"%s weakthreshold %ld\n", name, self->weakThreshold); fprintf(fd,"%s compact %d\n", name, self->iCompact); fprintf(fd,"%s psd %d\n", name, self->psd); fprintf(fd,"%s weak %d\n", name, self->weak); fprintf(fd,"%s fastscan %d\n", name, self->fastScan); SaveFourCircleTable(self->stepTable,name,fd); return 1; } /*-------------------------------------------------------------------------*/ static void ListMesure(pMesure self, char *name, SConnection *pCon) { Tcl_DString list; char pBuffer[132]; Tcl_DStringInit(&list); if(self->CountMode == eTimer) { snprintf(pBuffer,131,"%s.countmode timer\n",name); } else { snprintf(pBuffer,131,"%s.countmode monitor\n",name); } Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.np %d\n", name, self->np); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.preset %f\n", name, self->fPreset); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.step %f\n", name, self->fStep); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.weakthreshold %ld\n", name, self->weakThreshold); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.compact %d\n", name, self->iCompact); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.psd %d\n", name, self->psd); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.weak %d\n", name, self->weak); Tcl_DStringAppend(&list,pBuffer,-1); snprintf(pBuffer,131,"%s.fastscan %d\n", name, self->fastScan); Tcl_DStringAppend(&list,pBuffer,-1); SCWrite(pCon,Tcl_DStringValue(&list),eValue); Tcl_DStringFree(&list); } /*--------------------------------------------------------------------------*/ pMesure CreateMesure(pHKL pCryst, pScanData pScanner, pMotor pOmega, char *pOm, pMotor p2Theta, char *p2t, char *pFileRoot, pDataNumber pDanu, char *hdTemplate) { pMesure pNew = NULL; assert(pCryst); assert(pScanner); assert(pOmega); assert(pFileRoot); assert(pDanu); /* allocate space............. */ pNew = (pMesure)malloc(sizeof(Mesure)); if(!pNew) { return NULL; } memset(pNew,0,sizeof(Mesure)); pNew->pDes = CreateDescriptor("Mesure"); pNew->pDes->SaveStatus = SaveMesure; pNew->pCall = CreateCallBackInterface(); if( !pNew->pDes || !pNew->pCall) { free(pNew); return NULL; } /* asssign defaults */ pNew->pScanner = pScanner; pNew->pCryst = pCryst; pNew->pOmega = pOmega; pNew->p2Theta = p2Theta; pNew->pCOmega = strdup(pOm); pNew->pC2Theta = strdup(p2t); pNew->pFileRoot = strdup(pFileRoot); pNew->pDanu = pDanu; pNew->iCount = 0; pNew->CountMode = 0; pNew->np = 50; pNew->fStep = 0.05; pNew->fPreset = 2; pNew->iCompact = 1; pNew->psd = 0; pNew->weak = 0; pNew->weakThreshold = 99999; pNew->fastScan = 0; pNew->psiMode = 0; #ifdef MESSDEBUG pNew->lCounts = (long *)malloc(90*sizeof(long)); #endif pNew->lCounts = (long *)malloc(50*sizeof(long)); pNew->stepTable = MakeFourCircleTable(); strncpy(pNew->headerTemplate,hdTemplate,511); return pNew; } /*------------------------------------------------------------------------*/ void DeleteMesure(void *pData) { pMesure self = NULL; self = (pMesure)pData; if(!pData) { return; } if(self->pDes) DeleteDescriptor(self->pDes); if(self->pCall) DeleteCallBackInterface(self->pCall); if(self->pFileRoot) free(self->pFileRoot); if(self->pCOmega) free(self->pCOmega); if(self->fRefl) MesureClose(self); if(self->lCounts) free(self->lCounts); DeleteFourCircleTable(self->stepTable); free(self); } /*------------------------------------------------------------------------*/ int MesureFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { pMesure pNew = NULL; pHKL pCryst = NULL; pScanData pScan = NULL; CommandList *pCom = NULL; pMotor pMot = NULL, pMot2 = NULL; pDataNumber pDanu = NULL; pSicsO2T pO2T = NULL; char pBueffel[512]; pDummy pDum = NULL; int iRet; assert(pCon); assert(pSics); /* check no of parameters inicom name hkl scan omega root danu */ if(argc < 9) { SCWrite(pCon, "ERROR: Insufficient number of parameters to MesureFactory",eError); return 0; } /* work parameters one by one, first hkl */ pCom = FindCommand(pSics,argv[2]); if(pCom) { pDum = (pDummy)pCom->pData; if(pDum) { if(strcmp(pDum->pDescriptor->name,"4-Circle-Calculus") == 0) { pCryst = (pHKL)pCom->pData; } } } if(!pCryst) { sprintf(pBueffel,"ERROR: %s is no four circle calculus object",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } /* scanner */ pCom = FindCommand(pSics,argv[3]); if(pCom) { pDum = (pDummy)pCom->pData; if(pDum) { if(strcmp(pDum->pDescriptor->name,"ScanObject") == 0) { pScan = (pScanData)pCom->pData; } } } if(!pScan) { sprintf(pBueffel,"ERROR: %s is no scan object",argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } /* omega */ pMot = FindMotor(pSics,argv[4]); if(!pMot) { sprintf(pBueffel,"ERROR: %s is no motor object ",argv[4]); SCWrite(pCon,pBueffel,eError); return 0; } /* 2 theta */ pMot2 = FindMotor(pSics,argv[5]); if(!pMot2) { sprintf(pBueffel,"ERROR: %s is no motor object ",argv[5]); SCWrite(pCon,pBueffel,eError); return 0; } /* Data Number */ pCom = FindCommand(pSics,argv[7]); if(pCom) { pDum = (pDummy)pCom->pData; if(pDum) { if(strcmp(pDum->pDescriptor->name,"DataNumber") == 0) { pDanu = (pDataNumber)pCom->pData; } } } if(!pDanu) { sprintf(pBueffel,"ERROR: %s is no DataNumber object",argv[7]); SCWrite(pCon,pBueffel,eError); return 0; } /* finally create the thing */ pNew = CreateMesure(pCryst,pScan,pMot,argv[4], pMot2, argv[5], argv[6],pDanu,argv[8]); if(!pNew) { SCWrite(pCon,"ERROR: no memory in MesureFactory",eError); return 0; } /* add the new command */ iRet = AddCommand(pSics,argv[1],MesureAction,DeleteMesure,pNew); if(!iRet) { sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]); SCWrite(pCon,pBueffel,eError); return 0; } return 1; } /*------------------------------------------------------------------------ This implements the compact scan output for TRICS scans */ static int CompactScanData(pScanData self, int iPoint) { pVarEntry pVar = NULL; void *pDings; int i, iRet, status; float fVal; char pStatus[512], pItem[20]; char pHead[512]; CountEntry sCount; char *pAns = NULL, *pPtr = NULL ; Tcl_Interp *pTcl; assert(self); assert(self->pCon); /* loop over all scan variables */ status = 1; memset(pHead,0,512*sizeof(char)); memset(pStatus,0,512*sizeof(char)); memset(pItem,0,20*sizeof(char)); for(i = 0; i < self->iScanVar; i++) { DynarGet(self->pScanVar,i,&pDings); pVar = (pVarEntry)pDings; if(pVar) { fVal = pVar->pInter->GetValue(pVar->pObject,self->pCon); AppendScanVar(pVar,fVal); sprintf(pItem,"%-10.10s",pVar->Name); strcat(pHead,pItem); sprintf(pItem,"%-10.3f",fVal); strcat(pStatus,pItem); } } /* store counter data */ /* monitors */ for(i = 1; i < 10; i++) { sCount.Monitors[i-1] = GetMonitor((pCounter)self->pCounterData,i, self->pCon); } if( self->iChannel != 0 && self->iChannel != -10 ) { sCount.Monitors[self->iChannel - 1] = GetCounts((pCounter)self->pCounterData, self->pCon); } if(self->iChannel == 0) { sCount.lCount = GetCounts((pCounter)self->pCounterData,self->pCon); } else { sCount.lCount = GetMonitor((pCounter)self->pCounterData, self->iChannel, self->pCon); } /* stow away */ DynarReplace(self->pCounts,self->iCounts,&sCount,sizeof(CountEntry)); self->iCounts++; return 1; } /*------------------------------------------------------------------------*/ static int getMesureNP(pMesure self, double twoTheta) { int np; np = GetFourCircleScanNP(self->stepTable,twoTheta); if(np < -800){ np = self->np; } return np; } /*------------------------------------------------------------------------- This is slightly tricky: the crystallography module has a scan tolerance. This is supposed to be automatically set. In order to do so, I need the step width which in turn is dependent on two theta. Therefore I calculate two times: the first time with a scan tolerance of 0 to get two theta, the second time with the scan tolerance ste to a decent value to get the real thing. ---------------------------------------------------------------------------*/ static int MesureCalculateSettings(pMesure self, float fHKL[3], float fSet[4], float fPsi, SConnection *pCon) { int status, np; float step, tolerance, fHard; char *scanvar = NULL; char buffer[256]; SetHKLScanTolerance(self->pCryst,.0); status = CalculateSettings(self->pCryst,fHKL,fPsi,0,fSet,pCon); if(!status) { return status; } step = GetFourCircleStep(self->stepTable, fSet[0]); if(step < -900.){ step = self->fStep; } np = getMesureNP(self,(double)fSet[0]); tolerance = (step * (float)np)/2. + .2; SetHKLScanTolerance(self->pCryst,tolerance); status = CalculateSettings(self->pCryst,fHKL,fPsi,0,fSet,pCon); if(status != 1){ return status; } scanvar = GetFourCircleScanVar(self->stepTable,fSet[0]); if(scanvar != NULL && strcmp(scanvar,"om") != 0){ tolerance *= 2.; strcpy(buffer,"ERROR: 2theta limit problem:"); if(!MotorCheckBoundary(self->p2Theta,fSet[0]-tolerance,&fHard, buffer,256-strlen(buffer))){ SCWrite(pCon,buffer,eWarning); return 0; } if(!MotorCheckBoundary(self->p2Theta,fSet[0]+tolerance,&fHard, buffer,256-strlen(buffer))){ SCWrite(pCon,buffer,eWarning); return 0; } } return status; } /*--------------------------------------------------------------------------*/ int MesureReflection(pMesure self, float fHKL[3], float fPsi, SConnection *pCon) { int iRet; float fSet[4]; assert(self); iRet = MesureCalculateSettings(self,fHKL,fSet,fPsi,pCon); if(!iRet) { return iRet; } return MesureGenReflection(self,fHKL,fSet,pCon); } /*-----------------------------------------------------------------------*/ static int DriveToReflection(pMesure self, float fSet[4], SConnection *pCon) { int iRet, i; float fDelta; char pBueffel[132]; iRet = DriveSettings(self->pCryst,fSet,pCon); if(!iRet) { return iRet; } /* store achieved position for reporting */ iRet = GetCurrentPosition(self->pCryst,pCon,self->fPosition); if(iRet != 1) { return iRet; } /* check if we are really there. */ for(i = 0; i < 4; i++) { fDelta = fSet[i] - self->fPosition[i]; if(fDelta < 0.) fDelta = -fDelta; if(fDelta > ANGERR) { snprintf(pBueffel,131, "ERROR: angle %d positioned badly, aborting Reflection", i); SCWrite(pCon,pBueffel,eError); return 0; } } return 1; } /*----------------------------------------------------------------------- test if this scan has to be remeasured because it is weak ------------------------------------------------------------------------*/ int weakScan(pMesure self, double twoTheta) { int i, np; long low = 99999, high = -99999; /* the scan is always OK if we do not test for weak conditions or we are in psd mode */ if(self->weak == 0 || self->psd == 1){ return 0; } np = getMesureNP(self,twoTheta); GetScanCounts(self->pScanner,self->lCounts,np); for(i = 0; i < np; i++) { if(self->lCounts[i] < low) { low = self->lCounts[i]; } if(self->lCounts[i] > high) { high = self->lCounts[i]; } } /* I am using the weakest point here as a rough estimate of the background */ if(high - 2 * low > self->weakThreshold) { return 0; } else { return 1; } } /*-----------------------------------------------------------------------*/ static int PerformPSDScan(pMesure self, char *scanVar, float fStart, float step, int np, float two_theta) { int status; char pCommand[1024]; char countMode[20]; Tcl_Interp *pTcl; float fPreset; /* PSD scans are done by calling the routine Tcl procedure tricsscan with the appropriate parameters. tricsscan does only omega scans! */ if(self->CountMode == eTimer) { strcpy(countMode,"timer"); } else { strcpy(countMode,"monitor"); } fPreset = GetFourCirclePreset(self->stepTable,(double)two_theta); if(fPreset < .0){ fPreset = self->fPreset; } snprintf(pCommand,1023,"tricsscan %f %f %d %s %f", fStart, step, np, countMode,fPreset); pTcl = InterpGetTcl(pServ->pSics); status = Tcl_Eval(pTcl,pCommand); if(status != TCL_OK) { return 0; } else { return 1; } } /*------------------------------------------------------------------------*/ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) { float fStart, stepWidth, fPreset; int iRet, np; char pBueffel[132]; char *scanVar = NULL; /* calculate scan start */ iRet = MotorGetSoftPosition(self->pOmega,pCon,&fStart); if(!iRet) { return iRet; } scanVar = GetFourCircleScanVar(self->stepTable,(double)twoTheta); if(strcmp(scanVar,"NOT FOUND") == 0) { free(scanVar); scanVar = strdup(self->pCOmega); stepWidth = self->fStep; } else { stepWidth = GetFourCircleStep(self->stepTable,(double)twoTheta); } np = getMesureNP(self,(double)twoTheta); if(stepWidth != self->fStep) { snprintf(pBueffel,130,"Using stepwidth %f, %d points",stepWidth,np); SCWrite(pCon,pBueffel,eWarning); } fStart -= (np/2)*stepWidth; /* special case: psd mode */ if(self->psd == 1) { iRet = PerformPSDScan(self,scanVar,fStart, stepWidth, np,twoTheta); free(scanVar); return iRet; } /* below is the code for a single counter scan. TODO: (maybe) make this clearer and separate this into another subroutine Set the scan up */ ClearScanVar(self->pScanner); AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega, fStart, stepWidth); snprintf(pBueffel,131,"Scanning om from %f with step %f", fStart, stepWidth); SCWrite(pCon,pBueffel,eValue); /* Oksana does not want o2t scans to be tightly coupled, this is why we cannot use the normal o2t scan variable. Instead we calculate new limits and steps for 2 theta and use it as a second scan variable */ if(strstr(scanVar,"o2t") != NULL){ iRet = MotorGetSoftPosition(self->p2Theta,pCon,&fStart); if(!iRet) { return iRet; } stepWidth *= 2.; fStart -= (np/2.)*stepWidth; AddScanVar(self->pScanner, pServ->pSics,pCon,self->pC2Theta, fStart, stepWidth); snprintf(pBueffel,131,"Scanning 2theta from %f with step %f", fStart, stepWidth); SCWrite(pCon,pBueffel,eValue); } /* as np can change, we have to reallocate enough space */ if(self->lCounts != NULL){ free(self->lCounts); self->lCounts = (long *)malloc(np*sizeof(long)); if(self->lCounts == NULL){ SCWrite(pCon,"ERROR: out of memory for scan scan data",eError); SCSetInterrupt(pCon,eAbortScan); return 0; } memset(self->lCounts,0,np*sizeof(long)); } /* * determine preset */ fPreset = GetFourCirclePreset(self->stepTable,(double)twoTheta); if(fPreset < .0){ fPreset = self->fPreset; } /* do the scan */ free(scanVar); if(self->iCompact) { self->pScanner->CollectScanData = CompactScanData; } if(self->fastScan >= 1) { self->pScanner->ScanDrive = ScanFastDrive; } iRet = SilentScan(self->pScanner,np,self->CountMode, fPreset,pServ->pSics,pCon); if(weakScan(self,twoTheta)) { /* look for interrupts before restarting scan */ if(iRet == 0) { if(SCGetInterrupt(pCon) >= eAbortBatch) { return 0; } else { SCSetInterrupt(pCon,eContinue); } } /* redo scan with preset * 5 */ SCWrite(pCon,"Remeasuring weak reflection",eWarning); iRet = SilentScan(self->pScanner,np,self->CountMode, fPreset*5.,pServ->pSics,pCon); } ResetScanFunctions(self->pScanner); return iRet; } /*------------------------------------------------------------------------*/ int MesureGenReflection(pMesure self, float fHKL[3], float fSet[4], SConnection *pCon) { int iRet, i; char pBueffel[132]; assert(self); iRet = DriveToReflection(self,fSet,pCon); if(!iRet) { return iRet; } iRet = ScanReflection(self,fSet[0],pCon); return iRet; } /*--------------------------------------------------------------------------*/ int MesureStart(pMesure self, SConnection *pCon) { char pFilename[512], pRoot[512]; char pBueffel[1024]; char pBuff[132]; int iYear, iNum, iTaus; float fVal, fUB[9]; pSicsVariable pVar = NULL; char *pFile = NULL, *pPtr; float zero, pos; pMotor pMot = NULL; FILE *temp = NULL; assert(self); assert(pCon); /* close open files if so */ if(self->fRefl != NULL) { MesureClose(self); } /* create filename root */ pFile = makeFilename(pServ->pSics,pCon); if(!pFile) { return 0; } pPtr = strrchr(pFile,(int)'.'); pPtr++; *pPtr = '\0'; self->pCurrentFile = strdup(pFile); free(pFile); strncpy(pRoot,self->pCurrentFile,511); /* do the logfile */ strcpy(pFilename,pRoot); strcat(pFilename,"log"); self->iLogFile = SCAddLogFile(pCon,pFilename); self->pCon = pCon; /* we do not need reflection files when doing a PSD scan */ if(self->psd == 1) { sprintf(pBueffel,"Logging to %s.log", pRoot); SCWrite(pCon,pBueffel,eValue); return 1; } /* open the reflection file */ sprintf(pBueffel,"Writing to %s.log, .ccl, .rfl",pRoot); SCWrite(pCon,pBueffel,eValue); strcpy(pFilename,pRoot); strcat(pFilename,"ccl"); self->fRefl = fopen(pFilename,"w"); if(!self->fRefl) { sprintf(pBueffel,"ERROR: SERIOUS TROUBLE: cannot open %s!", pFilename); SCWrite(pCon,pBueffel,eError); SCSetInterrupt(pCon,eAbortBatch); return 0; } temp = fopen(self->headerTemplate,"r"); if(temp == NULL) { SCWrite(pCon,"ERROR: failed to open header template",eError); } if(temp != NULL && self->fRefl != NULL) { WriteTemplate(self->fRefl, temp, pFilename, NULL, pCon, pServ->pSics); fclose(temp); } /* open hkl-data file */ strcpy(pFilename,pRoot); strcat(pFilename,"rfl"); self->fHKL = fopen(pFilename,"w"); if(!self->fHKL) { sprintf(pBueffel,"ERROR: SERIOUS TROUBLE: cannot open %s!", pFilename); SCWrite(pCon,pBueffel,eError); SCSetInterrupt(pCon,eAbortBatch); return 0; } fputs(pFilename,self->fHKL); fputs("\n",self->fHKL); /* write some header data */ SNXFormatTime(pBueffel,1024); fprintf(self->fHKL,"filetime = %s\n",pBueffel); GetLambda(self->pCryst,&fVal); fprintf(self->fHKL,"lambda = %f Angstroem\n",fVal); GetUB(self->pCryst,fUB); fprintf(self->fHKL, "UB = %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f %7.6f\n", fUB[0], fUB[1],fUB[2],fUB[3],fUB[4],fUB[5],fUB[6],fUB[7],fUB[8]); /* write sample & user info */ strcpy(pBueffel,"CCL, Instr=TRICS, "); pVar = FindVariable(pServ->pSics,"sample"); if(pVar) { fprintf(self->fHKL,"sample = %s\n",pVar->text); sprintf(pBuff,"sample = %s, ",pVar->text); strcat(pBueffel,pBuff); } pVar = FindVariable(pServ->pSics,"user"); if(pVar) { fprintf(self->fHKL,"user = %s \n",pVar->text); sprintf(pBuff,"user = %s",pVar->text); strcat(pBueffel,pBuff); } return 1; } /*---------------------------------------------------------------------------*/ int MesureReopen(pMesure self, char *fileroot, SConnection *pCon) { char pBueffel[1024]; char pFile[512]; assert(self); assert(fileroot); assert(pCon); /* close pending files */ if(self->fRefl != NULL) { MesureClose(self); } /* log file */ strcpy(pFile,self->pFileRoot); strcat(pFile,"/"); strcat(pFile,fileroot); strcat(pFile,".log"); self->iLogFile = SCAddLogFile(pCon,pFile); self->pCon = pCon; /* No reopening of reflection files in psd mode */ if(self->psd == 1) { return 1; } /* check if this is possible */ strcpy(pFile,self->pFileRoot); strcat(pFile,"/"); strcat(pFile,fileroot); strcat(pFile,".col"); self->fRefl = fopen(pFile,"r"); if(!self->fRefl) { sprintf(pBueffel,"ERROR: there is no such measurement at %s",fileroot); SCWrite(pCon,pBueffel,eError); return 0; } fclose(self->fRefl); /* well seems to exist, open for append */ self->fRefl = fopen(pFile,"a"); /* rfl file */ strcpy(pFile,self->pFileRoot); strcat(pFile,"/"); strcat(pFile,fileroot); self->pCurrentFile = strdup(pFile); strcat(pFile,".rfl"); self->fHKL = fopen(pFile,"a"); return 1; } /*------------------------------------------------------------------------*/ int MesureClose(pMesure self) { assert(self); SCDelLogFile(self->pCon,self->iLogFile); if(self->psd == 1) { self->pCon = NULL; self->iLogFile = -1; if(self->pCurrentFile) free(self->pCurrentFile); return 1; } if(self->fRefl) { fclose(self->fRefl); self->fRefl = NULL; } if(self->fHKL) { fclose(self->fHKL); self->fHKL = NULL; } self->pCon = NULL; self->iLogFile = -1; if(self->pCurrentFile) free(self->pCurrentFile); return 1; } /*---------------------------------------------------------------------------*/ static double getProtonAverage(pMesure self){ int np, i; long *lData = NULL, lSum = 0; np = GetScanNP(self->pScanner); lData = (long *)malloc((np+1)*sizeof(long)); if(lData == NULL || np == 0){ return 0.; } memset(lData,0,(np+1)*sizeof(long)); GetScanMonitor(self->pScanner,2,lData, np); for(i = 0; i < np; i++){ lSum += lData[i]; } return (double)lSum/(double)np; } /*---------------------------------------------------------------------------*/ static int WriteReflection(pMesure self, float fHKL[3],SConnection *pCon) { float fSum, fSigma, fSet[4], fTemp, fPreset, fStep; double prot; static float fMax = 10.; int iRet, i,ii, iLF, iNP; char pBueffel[512], pNum[10], pTime[132]; pEVControl pEva = NULL; pDummy pPtr = NULL; pIDrivable pDriv = NULL; assert(self); assert(pCon); memset(pTime,0,132*sizeof(char)); #ifdef MESSDEBUG self->np = 90; fMax += 10; SimScan(self->pScanner,14.,0.5,fMax); if(fMax > 1000) { fMax = 10.; } #endif /* no writing in PSD mode */ if(self->psd == 1) { return 1; } /* get necessary data */ fSum = 0.; fSigma = 0.; iRet = ScanIntegrate(self->pScanner,&fSum, &fSigma); if(iRet != 1) { switch(iRet) { case INTEGLEFT: sprintf(pBueffel, "WARNING: integration failed --> no left side to: %f %f %f", fHKL[0], fHKL[1],fHKL[2]); break; case INTEGRIGHT: sprintf(pBueffel, "WARNING: integration failed -->no right side to: %f %f %f", fHKL[0], fHKL[1],fHKL[2]); break; case INTEGNOPEAK: sprintf(pBueffel, "WARNING: integration failed -->no peak found: %f %f %f", fHKL[0], fHKL[1],fHKL[2]); break; case INTEGFUNNYBACK: sprintf(pBueffel, "WARNING: integration problem, asymmetric background: %f %f %f", fHKL[0], fHKL[1],fHKL[2]); break; } SCWrite(pCon,pBueffel,eWarning); } iNP = GetScanNP(self->pScanner); GetScanCounts(self->pScanner,self->lCounts,iNP); /* write it */ if(self->fRefl) { fprintf(self->fRefl,"%4d %7.3f %7.3f %7.3f %7.2f %7.2f %7.2f %7.2f %7.0f %7.2f\n", self->iCount, fHKL[0],fHKL[1],fHKL[2], self->fPosition[0], self->fPosition[1], self->fPosition[2],self->fPosition[3], fSum,fSigma); } if(self->fHKL) { fprintf(self->fHKL,"%5d %6.2f %6.2f %6.2f %7.2f %7.2f %7.2f %7.2f %7.0f %7.2f\n", self->iCount, fHKL[0],fHKL[1],fHKL[2], self->fPosition[0], self->fPosition[1], self->fPosition[2],self->fPosition[3], fSum,fSigma); } sprintf(pBueffel,"%5d %6.2f %6.2f %6.2f %7.2f %7.2f %7.2f %7.2f %7.0f %7.2f\n", self->iCount, fHKL[0],fHKL[1],fHKL[2], self->fPosition[0], self->fPosition[1], self->fPosition[2],self->fPosition[3], fSum,fSigma); SCWrite(pCon,pBueffel,eStatus); /* get temperature */ fTemp = -777.77; pEva = (pEVControl)FindCommandData(pServ->pSics,"temperature", "Environment Controller"); if(pEva == NULL) { pPtr = (pDummy)FindCommandData(pServ->pSics,"temperature", "RemObject"); if(pPtr != NULL) { pDriv = pPtr->pDescriptor->GetInterface(pPtr,DRIVEID); if(pDriv != NULL) { fTemp = pDriv->GetValue(pPtr,pCon); } } } else { iRet = EVCGetPos(pEva, pCon,&fTemp); } /* write profile */ if(self->fRefl) { /* collect data */ SNXFormatTime(pBueffel,512); GetScanVarStep(self->pScanner,0,&fStep); fPreset = GetScanPreset(self->pScanner); prot = getProtonAverage(self); fprintf(self->fRefl,"%3d %7.4f %9.0f %7.3f %12f %s\n",iNP,fStep, fPreset,fTemp,prot, pBueffel); for(i = 0; i < iNP; i++) { for(ii = 0; ii < 10 && i < iNP; ii++) { fprintf(self->fRefl," %7ld",self->lCounts[i]); iLF = 1; i++; } fprintf(self->fRefl,"\n"); i--; iLF = 0; } if(iLF) { fprintf(self->fRefl,"\n"); } fflush(self->fRefl); } /* write data if compact output */ if(self->iCompact == 1) { strcpy(pTime,pBueffel); sprintf(pBueffel,"%3d%8.4f%10.0f%8.3f %s\n",iNP,fStep, fPreset,fTemp,pTime); SCWrite(pCon,pBueffel,eValue); pBueffel[0] = '\0'; for(i = 0; i < iNP; i++) { for(ii = 0; ii < 10 && i < iNP; ii++) { sprintf(pNum," %6ld",self->lCounts[i]); strcat(pBueffel,pNum); iLF = 1; i++; } SCWrite(pCon,pBueffel,eValue); pBueffel[0] = '\0'; i--; iLF = 0; } if(iLF) { SCWrite(pCon,pBueffel,eValue); } } return 1; } /*---------------------------------------------------------------------*/ static FILE *openListFile(char *pName){ FILE *fd = NULL; pDynString filename = NULL; filename = findBatchFile(pServ->pSics,pName); if(filename != NULL){ fd = fopen(GetCharArray(filename),"r"); DeleteDynString(filename); } else { fd = fopen(pName,"r"); } return fd; } /*------------------------------------------------------------------------*/ int MesureFile(pMesure self, char *pFile, int iSkip, SConnection *pCon) { FILE *fd = NULL; char pBueffel[512], pTime[132], pError[256]; int i, iRet; float fHKL[3], fPsi = .0; assert(self); assert(pCon); /* well before doing a thing, open the list file */ fd = openListFile(pFile); if(!fd) { sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile); SCWrite(pCon,pBueffel,eError); return 0; } /* check that files are open, if not open */ if(self->fRefl == NULL) { MesureStart(self,pCon); } /* make a mark */ SNXFormatTime(pTime,131); sprintf(pBueffel,"Starting at list %s at %s",pFile,pTime); SCWrite(pCon,pBueffel,eStatus); /* skippy! */ for(i = 0; i < iSkip; i++) { fgets(pBueffel,510,fd); } self->iCount = iSkip; if(self->psiMode > 0){ SCWrite(pCon,"WARNING: measuring in psi mode",eWarning); } /* loop through space and measure! */ while(fgets(pBueffel,510,fd) != NULL) { for(i = 0; i < 3;i++) fHKL[i] = 0.; if(self->psiMode > 0){ iRet = sscanf(pBueffel,"%f%f%f%f", &fHKL[0],&fHKL[1],&fHKL[2],&fPsi); if(iRet != 4){ snprintf(pError,255,"WARNING: skipping bad line %s",pBueffel); SCWrite(pCon,pError,eWarning); continue; } } else { iRet = sscanf(pBueffel,"%f%f%f",&fHKL[0],&fHKL[1],&fHKL[2]); if(iRet != 3){ snprintf(pError,255,"WARNING: skipping bad line %s",pBueffel); SCWrite(pCon,pError,eWarning); continue; } } self->iCount++; iRet = MesureReflection(self,fHKL,fPsi,pCon); if(iRet == 0) { if(SCGetInterrupt(pCon) >= eAbortBatch) { return 0; } else { SCSetInterrupt(pCon,eContinue); continue; } } WriteReflection(self,fHKL,pCon); } /* we are done */ SNXFormatTime(pTime,131); sprintf(pBueffel,"Finishing list %s at %s",pFile,pTime); SCWrite(pCon,pBueffel,eStatus); fclose(fd); return 1; } /*------------------------------------------------------------------------*/ int TestFile(pMesure self, char *pFile, SConnection *pCon) { FILE *fd = NULL; char pBueffel[512], pError[256]; int i, iRet; float fHKL[3], fSet[4], fPsi = .0; int count = 0, good = 0; assert(self); assert(pCon); /* well before doing a thing, open the list file */ fd = openListFile(pFile); if(!fd) { sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile); SCWrite(pCon,pBueffel,eError); return 0; } if(self->psiMode > 0){ SCWrite(pCon,"WARNING: measuring in psi mode",eWarning); } /* loop through space and test! */ while(fgets(pBueffel,510,fd) != NULL) { for(i = 0; i < 3;i++) fHKL[i] = 0.; if(self->psiMode > 0){ iRet = sscanf(pBueffel,"%f%f%f%f", &fHKL[0],&fHKL[1],&fHKL[2],&fPsi); if(iRet != 4){ snprintf(pError,255,"WARNING: skipping bad line %s",pBueffel); SCWrite(pCon,pError,eWarning); continue; } } else { iRet = sscanf(pBueffel,"%f%f%f",&fHKL[0],&fHKL[1],&fHKL[2]); if(iRet != 3){ snprintf(pError,255,"WARNING: skipping bad line %s",pBueffel); SCWrite(pCon,pError,eWarning); continue; } } count++; iRet = MesureCalculateSettings(self,fHKL,fSet,fPsi,pCon); if(iRet == 1) { good++; } } fclose(fd); snprintf(pBueffel,511,"Of %d reflections on file, %d are good and %d are rotten", count,good,count-good); SCWrite(pCon,pBueffel,eValue); return 1; } /*------------------------------------------------------------------------*/ int MesureGenFile(pMesure self, char *pFile, int iSkip, SConnection *pCon) { FILE *fd = NULL; char pBueffel[512], pTime[132]; int i, iRet, iH, iK, iL; float fHKL[3], fSet[4]; char pDum[4]; assert(self); assert(pCon); /* well before doing a thing, open the list file */ fd = openListFile(pFile); if(!fd) { sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile); SCWrite(pCon,pBueffel,eError); return 0; } /* check that files are open, if not open */ if(self->fRefl == NULL) { MesureStart(self,pCon); } /* make a mark */ SNXFormatTime(pTime,131); sprintf(pBueffel,"Starting at list %s at %s",pFile,pTime); SCWrite(pCon,pBueffel,eStatus); /* skippy! */ for(i = 0; i < iSkip; i++) { fgets(pBueffel,510,fd); } self->iCount = iSkip; /* loop through space and measure! */ while(fgets(pBueffel,510,fd) != NULL) { for(i = 0; i < 3;i++) fHKL[i] = 0.; for(i = 0; i < 4;i++) fSet[i] = 0.; iRet = sscanf(pBueffel,"%4d%4d%4d%s%f%f%f%f", &iH,&iK,&iL,pDum, &fSet[0], &fSet[1],&fSet[2],&fSet[3]); fHKL[0] = (float)iH; fHKL[1] = (float)iK; fHKL[2] = (float)iL; self->iCount++; iRet = MesureGenReflection(self,fHKL,fSet,pCon); if(iRet == 0) { if(SCGetInterrupt(pCon) >= eAbortBatch) { return 0; } else { SCSetInterrupt(pCon,eContinue); continue; } } WriteReflection(self,fHKL,pCon); } /* we are done */ SNXFormatTime(pTime,131); sprintf(pBueffel,"Finishing list %s at %s",pFile,pTime); SCWrite(pCon,pBueffel,eStatus); fclose(fd); return 1; } /*--------------------------------------------------------------------------*/ int MesureSetPar(pMesure self, char *name, float fVal) { if(strcmp(name,"np") == 0) { #ifndef MESSDEBUG self->np = (int)fVal; if(self->lCounts) free(self->lCounts); self->lCounts = (long *)malloc(self->np*sizeof(long)); if(!self->lCounts) { return 0; } #else #endif return 1; } else if(strcmp(name,"step") == 0) { self->fStep = fVal; return 1; } else if(strcmp(name,"weakthreshold") == 0) { self->weakThreshold = (long)nintf(fVal); return 1; } else if(strcmp(name,"preset") == 0) { self->fPreset = fVal; return 1; } else if(strcmp(name,"countmode") == 0) { if(fVal < 0.05) { self->CountMode = eTimer; } else { self->CountMode = ePreset; } return 1; } else if(strcmp(name,"compact") == 0) { if(fVal >= 1.) { self->iCompact = 1; } else { self->iCompact = 0; } return 1; } else if(strcmp(name,"psd") == 0) { if(fVal >= 1.) { self->psd = 1; } else { self->psd = 0; } return 1; } else if(strcmp(name,"weak") == 0) { if(fVal >= 1.) { self->weak = 1; } else { self->weak = 0; } return 1; } else if(strcmp(name,"fastscan") == 0) { if(fVal >= 1.) { self->fastScan = 1; } else { self->fastScan = 0; } return 1; } else if(strcmp(name,"psimode") == 0) { if(fVal >= 1.) { self->psiMode = 1; } else { self->psiMode = 0; } return 1; } else { return 0; } } /*-------------------------------------------------------------------------*/ int MesureGetPar(pMesure self, char *name, float *fVal) { if(strcmp(name,"np") == 0) { *fVal = self->np; return 1; } else if(strcmp(name,"step") == 0) { *fVal = self->fStep; return 1; } else if(strcmp(name,"weakthreshold") == 0) { *fVal = (float)self->weakThreshold; return 1; } else if(strcmp(name,"preset") == 0) { *fVal = self->fPreset; return 1; } else if(strcmp(name,"countmode") == 0) { if(self->CountMode == eTimer) { *fVal = 0.; } else { *fVal = 1.0; } return 1; } else if(strcmp(name,"compact") == 0) { *fVal = self->iCompact; return 1; } else if(strcmp(name,"psd") == 0) { *fVal = self->psd; return 1; } else if(strcmp(name,"fastscan") == 0) { *fVal = (float)self->fastScan; return 1; } else if(strcmp(name,"weak") == 0) { *fVal = (float)self->weak; return 1; } else if(strcmp(name,"psimode") == 0) { *fVal = self->psiMode; return 1; } else { return 0; } } /*---------------------------------------------------------------------------*/ int MesureAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { int iRet, iSkip, err; char pBueffel[1024]; pMesure self = NULL; double d; float fVal, fHKL[3], start, end, step; self = (pMesure)pData; assert(self); assert(pCon); if(argc < 2) { sprintf(pBueffel,"ERROR: Insufficient arguments to %s",argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } /* catch table processing commands */ iRet = HandleFourCircleCommands(&self->stepTable,pCon,argc,argv,&err); if(iRet == 1) { return err; } strtolower(argv[1]); /*------ start */ if(strcmp(argv[1],"open") == 0) { if(!SCMatchRights(pCon,usUser)) { return 0; } iRet = MesureStart(self,pCon); if(iRet) { SCSendOK(pCon); } return iRet; } /*----------- list*/ else if(strcmp(argv[1],"list") == 0) { ListMesure(self,argv[0],pCon); return 1; } /*------ file */ else if(strcmp(argv[1],"file") == 0) { sprintf(pBueffel,"Currently writing to: %s",self->pCurrentFile); SCWrite(pCon,pBueffel,eValue); return 1; } /*------ nb */ else if(strcmp(argv[1],"nb") == 0) { if(!SCMatchRights(pCon,usUser)) { return 0; } iRet = SetNOR(self->pCryst,1); if(!iRet) { SCWrite(pCon, "ERROR: nu motor not configured at hkl, cannot do normal beam", eError); return 0; } SCSendOK(pCon); return 1; } /*------ bi */ else if(strcmp(argv[1],"bi") == 0) { if(!SCMatchRights(pCon,usUser)) { return 0; } iRet = SetNOR(self->pCryst,0); SCSendOK(pCon); return 1; } /*--------- close */ else if(strcmp(argv[1],"close") == 0) { if(!SCMatchRights(pCon,usUser)) { return 0; } MesureClose(self); return 1; } /*-------- reopen */ else if(strcmp(argv[1],"reopen") == 0) { if(!SCMatchRights(pCon,usUser)) { return 0; } if(argc < 3) { SCWrite(pCon,"ERROR: expected filename as parameter for reopen",eError); return 0; } iRet = MesureReopen(self,argv[2],pCon); if(iRet) { SCSendOK(pCon); } return iRet; } /*------- measure */ else if(strcmp(argv[1],"measure") == 0) { iSkip = 0; if(!SCMatchRights(pCon,usUser)) { return 0; } if(argc < 3) { SCWrite(pCon,"ERROR: expected list file name as parameter for measure ",eError); return 0; } if(argc >= 4) { iRet = Tcl_GetInt(pSics->pTcl,argv[3],&iSkip); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer, got %s",argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } } iRet = MesureFile(self,argv[2],iSkip,pCon); if(iRet) { SCSendOK(pCon); } return iRet; } /*------- calc */ else if(strcmp(argv[1],"calc") == 0) { if(argc < 3) { SCWrite(pCon,"ERROR: expected list file name as parameter for measure ",eError); return 0; } iRet = TestFile(self,argv[2],pCon); return iRet; } /*------- genlist */ else if(strcmp(argv[1],"genlist") == 0) { iSkip = 0; if(!SCMatchRights(pCon,usUser)) { return 0; } if(argc < 3) { SCWrite(pCon,"ERROR: expected list file name as parameter for measure ",eError); return 0; } if(argc >= 4) { iRet = Tcl_GetInt(pSics->pTcl,argv[3],&iSkip); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer, got %s",argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } } iRet = MesureGenFile(self,argv[2],iSkip,pCon); if(iRet) { SCSendOK(pCon); } return iRet; } /* ------ writereflection*/ else if(strcmp(argv[1],"writereflection") == 0) { GetCurrentHKL(self->pCryst,fHKL); WriteReflection(self,fHKL,pCon); SCSendOK(pCon); return 1; } /* ------ count mode */ else if(strcmp(argv[1],"countmode") == 0) { if(argc > 2) /* set case */ { /* check rights */ if(!SCMatchRights(pCon,usUser)) { SCWrite(pCon,"ERROR: You are not aurhorised to do this!",eError); return 0; } if(strcmp(argv[2],"timer") == 0) { fVal = 0.; } else if(strcmp(argv[2],"monitor") == 0) { fVal = 1.; } else { SCWrite(pCon,"ERROR: Invalid parameter for countmode",eError); return 0; } MesureSetPar(self,"countmode",fVal); SCSendOK(pCon); return 1; } else /* get case */ { MesureGetPar(self,"countmode",&fVal); if(fVal < 0.05) { sprintf(pBueffel,"%s.countmode = timer",argv[0]); } else { sprintf(pBueffel,"%s.countmode = monitor", argv[0]); } SCWrite(pCon,pBueffel,eValue); return 1; } } /*------ can be other pars */ else { if(argc > 2) /* set case */ { /* check rights */ if(!SCMatchRights(pCon,usUser)) { SCWrite(pCon,"ERROR: You are not aurhorised to do this!",eError); return 0; } iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&d); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected numeric value for %s but got %s", argv[1],argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } fVal = (float)d; iRet = MesureSetPar(self,argv[1],fVal); if(iRet) { SCSendOK(pCon); return 1; } else { sprintf(pBueffel,"ERROR: parameter %s not known",argv[1]); SCWrite(pCon,pBueffel,eError); return 0; } } else /* get case */ { iRet = MesureGetPar(self,argv[1],&fVal); if(!iRet) { sprintf(pBueffel,"ERROR: parameter %s not known",argv[1]); SCWrite(pCon,pBueffel,eError); return 0; } sprintf(pBueffel,"%s.%s = %f",argv[0],argv[1],fVal); SCWrite(pCon,pBueffel,eValue); return 1; } } }