/*------------------------------------------------------------------------- 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, eLog); /* 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, eLog); } /* 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", eLog); 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"); /* TODO 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"); /* TODO: 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); /* TODO * 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, eLog); /* 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, eLog); /* 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, eLog); 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, eLog); /* 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, eLog); 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; } } }