1693 lines
45 KiB
C
1693 lines
45 KiB
C
/*-------------------------------------------------------------------------
|
|
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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <tcl.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#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;
|
|
}
|
|
}
|
|
}
|