diff --git a/doc/user/mesure.htm b/doc/user/mesure.htm index 6fe973f9..1d34c4c6 100644 --- a/doc/user/mesure.htm +++ b/doc/user/mesure.htm @@ -53,6 +53,7 @@ of the measurement. parameter iSkip determines the number of lines to skip in the file. This feature allows to continue measurement on not fully processed files.
dataset reopen filename +
dataset reopen 001/trics2005n000051
Reopens an already existing file set for appending. Only the file root without directory info or endings needs to be given.
dataset close @@ -93,6 +94,9 @@ This object knows about the following parameters: max count in scan - 2* min count in scan.
fastscan
0 or 1: switches fastscan mode. +
psimode +
0 or 1: switches psi scanning mode. Please note that suitable HKL input files for this mode + must contain four numbers: H, K, L and psi.
psd
0 or 1: switches on PSD mode for measuring with the area detector. Currently this is mapped to doing a tricsscan with the scan parameters as evaluted from the two theta range table. The @@ -102,7 +106,7 @@ This object knows about the following parameters:

Then there are command which allow to configure the table of two theta ranges and - scan parameters. All table rleated commands start with: dataset table. The following + scan parameters. All table related commands start with: dataset table. The following commands are supported:

dataset table list @@ -126,7 +130,7 @@ dataset supports two geometries: the first is the usual bisecting geometry. The This is accounted for by two switches:
dataset bi -
switches into bissectiong mode. This is the default. +
switches into bissecting mode. This is the default.
dataset nb
switches into normal beam mode.
diff --git a/hklmot.c b/hklmot.c index 85be94c1..aeece55f 100644 --- a/hklmot.c +++ b/hklmot.c @@ -49,7 +49,7 @@ static int HKLHalt(void *pData){ static int HKLCheckLimits(void *self, float fVal, char *error, int errLen){ /* There is no meaningful implementation here. This gets called when starting the motor. - At that stage not all other values may be known. If the calculation failes, this will die + At that stage not all other values may be known. If the calculation fails, this will die at status check time. */ return 1; diff --git a/make_gen b/make_gen index ea966a99..25c12e67 100644 --- a/make_gen +++ b/make_gen @@ -24,7 +24,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ hklscan.o xytable.o exebuf.o exeman.o ubfour.o ubcalc.o\ circular.o maximize.o sicscron.o scanvar.o tasublib.o\ d_sign.o d_mod.o tcldrivable.o stdscan.o diffscan.o\ - synchronize.o definealias.o oscillate.o \ + synchronize.o definealias.o oscillate.o tasdrive.o\ hmcontrol.o userscan.o rs232controller.o lomax.o \ fourlib.o motreg.o motreglist.o anticollider.o \ s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \ diff --git a/mesure.c b/mesure.c index 1ff4b413..86e03313 100644 --- a/mesure.c +++ b/mesure.c @@ -846,7 +846,6 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon) self->fRefl = fopen(pFile,"r"); if(!self->fRefl) { - fclose(self->fRefl); sprintf(pBueffel,"ERROR: there is no such measurement at %s",fileroot); SCWrite(pCon,pBueffel,eError); return 0; diff --git a/scan.c b/scan.c index 07562243..be6c1561 100644 --- a/scan.c +++ b/scan.c @@ -729,7 +729,7 @@ CountEntry CollectCounterData(pScanData self) self->fPreset = fPreset; /* do some preprocessing */ - iRet = PrepareScan(self); + iRet = SilentPrepare(self); if(!iRet) { self->WriteHeader = HeaderFunc; diff --git a/servlog.c b/servlog.c index 5bb33b06..8c03e171 100644 --- a/servlog.c +++ b/servlog.c @@ -285,7 +285,13 @@ } sprintf(pFile,"%s%1d.log",pFile, iFile); fLogFile = fopen(pFile,"w"); - assert(fLogFile); + if(!fLogFile) + { + printf("ERROR: cannot open logfile %s for writing\n", + pFile); + fLogFile = NULL; + return; + } iLineCount = 0; } diff --git a/sicsstat.tcl b/sicsstat.tcl index 0b6ab7c4..38b3e2f7 100644 --- a/sicsstat.tcl +++ b/sicsstat.tcl @@ -1,193 +1,230 @@ -banana CountMode timer -banana preset 10.000000 -# Counter counter -counter SetPreset 10.000000 -counter SetMode Timer -# Motor tilt -tilt sign 1.000000 -tilt SoftZero 0.000000 -tilt SoftLowerLim -403.623993 -tilt SoftUpperLim 396.376007 -tilt Fixed -1.000000 -tilt InterruptMode 0.000000 -tilt AccessCode 2.000000 -# Motor chi -chi sign 1.000000 -chi SoftZero 0.000000 -chi SoftLowerLim -20.000000 -chi SoftUpperLim 20.000000 -chi Fixed -1.000000 -chi InterruptMode 0.000000 -chi AccessCode 2.000000 -# Motor ome -ome sign 1.000000 -ome SoftZero 0.000000 -ome SoftLowerLim -180.000000 -ome SoftUpperLim 180.000000 -ome Fixed -1.000000 -ome InterruptMode 0.000000 -ome AccessCode 2.000000 -# Motor atz -atz sign 1.000000 -atz SoftZero 0.000000 -atz SoftLowerLim -3900.000000 -atz SoftUpperLim 0.000000 -atz Fixed -1.000000 -atz InterruptMode 0.000000 -atz AccessCode 2.000000 -# Motor az1 -az1 sign 1.000000 -az1 SoftZero 0.000000 -az1 SoftLowerLim -3900.000000 -az1 SoftUpperLim 0.000000 -az1 Fixed -1.000000 -az1 InterruptMode 0.000000 -az1 AccessCode 2.000000 -# Motor dv -dv sign 1.000000 -dv SoftZero 0.000000 -dv SoftLowerLim -14000.000000 -dv SoftUpperLim 25000.000000 -dv Fixed -1.000000 -dv InterruptMode 0.000000 -dv AccessCode 2.000000 -# Motor dh -dh sign 1.000000 -dh SoftZero 0.000000 -dh SoftLowerLim -14000.000000 -dh SoftUpperLim 16000.000000 -dh Fixed -1.000000 -dh InterruptMode 0.000000 -dh AccessCode 2.000000 -# Motor dz -dz sign 1.000000 -dz SoftZero 0.000000 -dz SoftLowerLim 1.050000 -dz SoftUpperLim 6.000000 -dz Fixed -1.000000 -dz InterruptMode 0.000000 -dz AccessCode 2.000000 -# Motor sy -sy sign 1.000000 -sy SoftZero 0.000000 -sy SoftLowerLim -10000.000000 -sy SoftUpperLim 10000.000000 -sy Fixed -1.000000 -sy InterruptMode 0.000000 -sy AccessCode 2.000000 -# Motor sx -sx sign 1.000000 -sx SoftZero 0.000000 -sx SoftLowerLim -10000.000000 -sx SoftUpperLim 10000.000000 -sx Fixed -1.000000 -sx InterruptMode 0.000000 -sx AccessCode 2.000000 -# Motor sz -sz sign 1.000000 -sz SoftZero 0.000000 -sz SoftLowerLim -10000.000000 -sz SoftUpperLim 10000.000000 -sz Fixed -1.000000 -sz InterruptMode 0.000000 -sz AccessCode 2.000000 -# Motor om -om sign 1.000000 -om SoftZero 0.000000 -om SoftLowerLim -10000.000000 -om SoftUpperLim 10000.000000 -om Fixed -1.000000 -om InterruptMode 0.000000 -om AccessCode 2.000000 -# Motor tl -tl sign 1.000000 -tl SoftZero 0.000000 -tl SoftLowerLim -10000.000000 -tl SoftUpperLim 10000.000000 -tl Fixed -1.000000 -tl InterruptMode 0.000000 -tl AccessCode 2.000000 -# Motor tu -tu sign 1.000000 -tu SoftZero 0.000000 -tu SoftLowerLim -10000.000000 -tu SoftUpperLim 10000.000000 -tu Fixed -1.000000 -tu InterruptMode 0.000000 -tu AccessCode 2.000000 -# Motor gl -gl sign 1.000000 -gl SoftZero 0.000000 -gl SoftLowerLim -10000.000000 -gl SoftUpperLim 10000.000000 -gl Fixed -1.000000 -gl InterruptMode 0.000000 -gl AccessCode 2.000000 -# Motor gu -gu sign 1.000000 -gu SoftZero 0.000000 -gu SoftLowerLim -10000.000000 -gu SoftUpperLim 10000.000000 -gu Fixed -1.000000 -gu InterruptMode 0.000000 -gu AccessCode 2.000000 -# Motor sc -sc sign 1.000000 -sc SoftZero 0.000000 -sc SoftLowerLim -2000.000000 -sc SoftUpperLim 70000.000000 -sc Fixed -1.000000 -sc InterruptMode 0.000000 -sc AccessCode 2.000000 -# Motor stz -stz sign 1.000000 -stz SoftZero 0.000000 -stz SoftLowerLim 6500.000000 -stz SoftUpperLim 20000.000000 -stz Fixed -1.000000 -stz InterruptMode 0.000000 -stz AccessCode 2.000000 -# Motor stx -stx sign 1.000000 -stx SoftZero 0.000000 -stx SoftLowerLim -16000.000000 -stx SoftUpperLim 16000.000000 -stx Fixed -1.000000 -stx InterruptMode 0.000000 -stx AccessCode 2.000000 -# Motor sr -sr sign 1.000000 -sr SoftZero 0.000000 -sr SoftLowerLim -10000.000000 -sr SoftUpperLim 10000.000000 -sr Fixed -1.000000 -sr InterruptMode 0.000000 -sr AccessCode 2.000000 -sampletable UNKNOWN -sampletable setAccess 2 -starttime 2003-02-13 13:52:54 -starttime setAccess 2 -batchroot /afs/psi.ch/user/k/koennecke/src/sics -batchroot setAccess 2 -sample Wurstbroetchen -sample setAccess 2 -adress UNKNOWN -adress setAccess 2 -phone UNKNOWN -phone setAccess 2 -fax UNKNOWN -fax setAccess 2 -email UNKNOWN -email setAccess 2 -samplename KohlSulfid -samplename setAccess 2 -comment UNKNOWN -comment setAccess 2 -environment UNKNOWN -environment setAccess 2 -subtitle UNKNOWN -subtitle setAccess 2 +exe batchpath ./ +exe syspath ./ +#---- tasUB module tasub +tasub mono dd 3.350000 +tasub mono hb1 1.000000 +tasub mono hb2 1.000000 +tasub mono vb1 1.000000 +tasub mono vb2 1.000000 +tasub mono ss 1 +tasub ana dd 3.350000 +tasub ana hb1 1.000000 +tasub ana hb2 1.000000 +tasub ana vb1 1.000000 +tasub ana vb2 1.000000 +tasub ana ss 1 +tasub cell 1.000000 1.000000 1.000000 90.000000 90.000000 90.000000 +tasub clear +tasub const ki +tasub ss 1 + tasub setub 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 + tasub setnormal 0.000000 0.000000 0.000000 +tasub settarget 0.000000 0.000000 0.000000 0.000000 0.000000 +tasub update +scaninfo 0,Unknown,1.0,.1 +scaninfo setAccess 0 +polfile UNKNOWN +polfile setAccess 2 +local UNKNOWN +local setAccess 2 +output UNKNOWN +output setAccess 2 +lastcommand UNKNOWN +lastcommand setAccess 2 user Albert von Villigen user setAccess 2 title UNKNOWN title setAccess 2 +# Counter counter +counter SetPreset 10.000000 +counter SetMode Timer +# Motor agl +agl sign 1.000000 +agl SoftZero 0.000000 +agl SoftLowerLim -10.000000 +agl SoftUpperLim 10.000000 +agl Fixed -1.000000 +agl InterruptMode 0.000000 +agl precision 0.010000 +agl AccessCode 2.000000 +agl movecount 10.000000 +# Motor sgu +sgu sign 1.000000 +sgu SoftZero 0.000000 +sgu SoftLowerLim -16.000000 +sgu SoftUpperLim 16.000000 +sgu Fixed -1.000000 +sgu InterruptMode 0.000000 +sgu precision 0.010000 +sgu AccessCode 2.000000 +sgu movecount 10.000000 +# Motor sgl +sgl sign 1.000000 +sgl SoftZero 0.000000 +sgl SoftLowerLim -16.000000 +sgl SoftUpperLim 16.000000 +sgl Fixed -1.000000 +sgl InterruptMode 0.000000 +sgl precision 0.010000 +sgl AccessCode 2.000000 +sgl movecount 10.000000 +# Motor mgl +mgl sign 1.000000 +mgl SoftZero 0.000000 +mgl SoftLowerLim -10.000000 +mgl SoftUpperLim 10.000000 +mgl Fixed -1.000000 +mgl InterruptMode 0.000000 +mgl precision 0.010000 +mgl AccessCode 2.000000 +mgl movecount 10.000000 +# Motor atu +atu sign 1.000000 +atu SoftZero 0.000000 +atu SoftLowerLim -17.000000 +atu SoftUpperLim 16.879999 +atu Fixed -1.000000 +atu InterruptMode 0.000000 +atu precision 0.010000 +atu AccessCode 2.000000 +atu movecount 10.000000 +# Motor atl +atl sign 1.000000 +atl SoftZero 0.000000 +atl SoftLowerLim -17.000000 +atl SoftUpperLim 17.000000 +atl Fixed -1.000000 +atl InterruptMode 0.000000 +atl precision 0.010000 +atl AccessCode 2.000000 +atl movecount 10.000000 +# Motor stu +stu sign 1.000000 +stu SoftZero 0.000000 +stu SoftLowerLim -30.000000 +stu SoftUpperLim 30.000000 +stu Fixed -1.000000 +stu InterruptMode 0.000000 +stu precision 0.010000 +stu AccessCode 2.000000 +stu movecount 10.000000 +# Motor stl +stl sign 1.000000 +stl SoftZero 0.000000 +stl SoftLowerLim -30.000000 +stl SoftUpperLim 30.000000 +stl Fixed -1.000000 +stl InterruptMode 0.000000 +stl precision 0.010000 +stl AccessCode 2.000000 +stl movecount 10.000000 +# Motor mtu +mtu sign 1.000000 +mtu SoftZero 0.000000 +mtu SoftLowerLim -17.000000 +mtu SoftUpperLim 17.000000 +mtu Fixed -1.000000 +mtu InterruptMode 0.000000 +mtu precision 0.010000 +mtu AccessCode 2.000000 +mtu movecount 10.000000 +# Motor mtl +mtl sign 1.000000 +mtl SoftZero 0.000000 +mtl SoftLowerLim -17.000000 +mtl SoftUpperLim 17.000000 +mtl Fixed -1.000000 +mtl InterruptMode 0.000000 +mtl precision 0.010000 +mtl AccessCode 2.000000 +mtl movecount 10.000000 +# Motor ach +ach sign 1.000000 +ach SoftZero 0.000000 +ach SoftLowerLim -0.500000 +ach SoftUpperLim 11.500000 +ach Fixed -1.000000 +ach InterruptMode 0.000000 +ach precision 0.010000 +ach AccessCode 2.000000 +ach movecount 10.000000 +# Motor sro +sro sign 1.000000 +sro SoftZero 0.000000 +sro SoftLowerLim 0.000000 +sro SoftUpperLim 351.000000 +sro Fixed -1.000000 +sro InterruptMode 0.000000 +sro precision 0.010000 +sro AccessCode 2.000000 +sro movecount 10.000000 +# Motor mcv +mcv sign 1.000000 +mcv SoftZero 0.000000 +mcv SoftLowerLim -9.000000 +mcv SoftUpperLim 124.000000 +mcv Fixed -1.000000 +mcv InterruptMode 0.000000 +mcv precision 0.010000 +mcv AccessCode 2.000000 +mcv movecount 10.000000 +# Motor a6 +a6 sign 1.000000 +a6 SoftZero 0.000000 +a6 SoftLowerLim -116.000000 +a6 SoftUpperLim 166.000000 +a6 Fixed -1.000000 +a6 InterruptMode 0.000000 +a6 precision 0.010000 +a6 AccessCode 2.000000 +a6 movecount 10.000000 +# Motor a5 +a5 sign 1.000000 +a5 SoftZero 0.000000 +a5 SoftLowerLim -200.000000 +a5 SoftUpperLim 200.000000 +a5 Fixed -1.000000 +a5 InterruptMode 0.000000 +a5 precision 0.010000 +a5 AccessCode 2.000000 +a5 movecount 10.000000 +# Motor a4 +a4 sign 1.000000 +a4 SoftZero 0.000000 +a4 SoftLowerLim -135.100006 +a4 SoftUpperLim 123.400002 +a4 Fixed -1.000000 +a4 InterruptMode 0.000000 +a4 precision 0.010000 +a4 AccessCode 2.000000 +a4 movecount 10.000000 +# Motor a3 +a3 sign 1.000000 +a3 SoftZero 0.000000 +a3 SoftLowerLim -177.300003 +a3 SoftUpperLim 177.300003 +a3 Fixed -1.000000 +a3 InterruptMode 0.000000 +a3 precision 0.010000 +a3 AccessCode 2.000000 +a3 movecount 10.000000 +# Motor a2 +a2 sign 1.000000 +a2 SoftZero 0.000000 +a2 SoftLowerLim -129.100006 +a2 SoftUpperLim -22.000000 +a2 Fixed -1.000000 +a2 InterruptMode 0.000000 +a2 precision 0.010000 +a2 AccessCode 2.000000 +a2 movecount 10.000000 +# Motor a1 +a1 sign 1.000000 +a1 SoftZero 0.000000 +a1 SoftLowerLim -87.000000 +a1 SoftUpperLim 6.100000 +a1 Fixed -1.000000 +a1 InterruptMode 0.000000 +a1 precision 0.010000 +a1 AccessCode 2.000000 +a1 movecount 10.000000 diff --git a/stdscan.c b/stdscan.c index 1be616a0..ed0824ce 100644 --- a/stdscan.c +++ b/stdscan.c @@ -368,6 +368,28 @@ static char *fixExtension(char *filename) self->fd = NULL; return 1; } +/*------------------------------------------------------------------------*/ +static int prepareDataFile(pScanData self){ + char *pPtr = NULL; + char pBueffel[512]; + + /* allocate a new data file */ + pPtr = ScanMakeFileName(self->pSics,self->pCon); + if(!pPtr) + { + SCWrite(self->pCon, + "ERROR: cannot allocate new data filename, Scan aborted", + eError); + self->pCon = NULL; + self->pSics = NULL; + return 0; + } + snprintf(pBueffel,511,"Writing data file: %s ...",pPtr); + SCWrite(self->pCon,pBueffel,eWarning); + strcpy(self->pFile,pPtr); + free(pPtr); + return 1; +} /*--------------------------------------------------------------------------*/ int PrepareScan(pScanData self) { @@ -377,7 +399,6 @@ static char *fixExtension(char *filename) float fVal; char pBueffel[512]; char pMessage[1024]; - char *pPtr = NULL; assert(self); assert(self->iNP > 0); @@ -426,25 +447,72 @@ static char *fixExtension(char *filename) SetCounterPreset((pCounter)self->pCounterData, self->fPreset); self->iCounts = 0; - /* allocate a new data file */ - pPtr = ScanMakeFileName(self->pSics,self->pCon); - if(!pPtr) - { - SCWrite(self->pCon, - "ERROR: cannot allocate new data filename, Scan aborted", - eError); - self->pCon = NULL; - self->pSics = NULL; - return 0; + if(!prepareDataFile(self)){ + return 0; } - snprintf(pBueffel,511,"Writing data file: %s ...",pPtr); - SCWrite(self->pCon,pBueffel,eWarning); - strcpy(self->pFile,pPtr); - free(pPtr); return 1; } /*--------------------------------------------------------------------------*/ + int SilentPrepare(pScanData self) + { + pVarEntry pVar = NULL; + void *pDings; + int i, iRet; + float fVal; + char pBueffel[512]; + char pMessage[1024]; + + assert(self); + assert(self->iNP > 0); + assert(self->pCon); + + /* check boundaries of scan variables and allocate storage */ + for(i = 0; i < self->iScanVar; i++) + { + DynarGet(self->pScanVar,i,&pDings); + pVar = (pVarEntry)pDings; + if(pVar) + { + /* start value */ + fVal = ScanVarStart(pVar); + iRet = pVar->pInter->CheckLimits(pVar->pObject, + fVal,pBueffel,511); + if(!iRet) + { + sprintf(pMessage,"ERROR: %s, scan aborted",pBueffel); + SCWrite(self->pCon,pBueffel,eError); + return 0; + } + /* end value */ + fVal = pVar->fStart + (self->iNP - 1) * ScanVarStep(pVar); + iRet = pVar->pInter->CheckLimits(pVar->pObject, + fVal,pBueffel,511); + if(!iRet) + { + sprintf(pMessage,"ERROR: %s, scan aborted",pBueffel); + SCWrite(self->pCon,pBueffel,eError); + return 0; + } + InitScanVar(pVar); + } + else + { + SCWrite(self->pCon, + "WARNING: Internal error, no scan variable, I try to continue", + eWarning); + } + pVar = NULL; + } /* end for */ + + /* configure counter */ + SetCounterMode((pCounter)self->pCounterData,self->iMode); + SetCounterPreset((pCounter)self->pCounterData, self->fPreset); + self->iCounts = 0; + + return 1; + } +/*--------------------------------------------------------------------------*/ int NonCheckPrepare(pScanData self) { pVarEntry pVar = NULL; @@ -453,7 +521,6 @@ static char *fixExtension(char *filename) float fVal; char pBueffel[512]; char pMessage[1024]; - char *pPtr = NULL; assert(self); assert(self->iNP > 0); @@ -484,21 +551,9 @@ static char *fixExtension(char *filename) SetCounterPreset((pCounter)self->pCounterData, self->fPreset); self->iCounts = 0; - /* allocate a new data file */ - pPtr = ScanMakeFileName(self->pSics,self->pCon); - if(!pPtr) - { - SCWrite(self->pCon, - "ERROR: cannot allocate new data filename, Scan aborted", - eError); - self->pCon = NULL; - self->pSics = NULL; - return 0; + if(!prepareDataFile(self)){ + return 0; } - snprintf(pBueffel,511,"Writing data file: %s ...",pPtr); - SCWrite(self->pCon,pBueffel,eWarning); - strcpy(self->pFile,pPtr); - free(pPtr); return 1; } diff --git a/stdscan.h b/stdscan.h index f348dac6..2a95fa6d 100644 --- a/stdscan.h +++ b/stdscan.h @@ -33,6 +33,10 @@ /** * second version of PrepareScan which does not check scan limits */ + int SilentPrepare(pScanData self); + /** + * third version of PrepareScan which does not create data files but checks + */ int NonCheckPrepare(pScanData self); /** * ScanDrive handles driving to the scan point iPoint. diff --git a/tasdrive.c b/tasdrive.c new file mode 100644 index 00000000..fc702a44 --- /dev/null +++ b/tasdrive.c @@ -0,0 +1,644 @@ +/*--------------------------------------------------------------------- + SICS interface to the triple axis drivable motors. + + copyright: see file COPYRIGHT + + Mark Koennecke, May 2005 +--------------------------------------------------------------------*/ +#include +#include "sics.h" +#include "tasdrive.h" + +#define ABS(x) (x < 0 ? -(x) : (x)) + +#define MOTPREC .01 +/*------------------- motor indexes in motor data structure --------- + WARNING: have to match tasub.c !!!!! +--------------------------------------------------------------------*/ +#define A1 0 +#define A2 1 +#define MCV 2 +#define MCH 3 +#define A3 4 +#define A4 5 +#define SGU 6 +#define SGL 7 +#define A5 8 +#define A6 9 +#define ACV 10 +#define ACH 11 + +/*============== Drivable Interface functions =====================*/ +static int TASSetValue(void *pData, SConnection *pCon, + float value){ + ptasMot self = (ptasMot)pData; + assert(self); + + setTasPar(&self->math->target,self->math->tasMode,self->code,value); + self->math->mustDrive = 1; + return OKOK; +} +/*----------------------------------------------------------------*/ +static int readTASMotAngles(ptasUB self, SConnection *pCon, + ptasAngles ang){ + int status; + float val, theta; + + /* + Monochromator + */ + status = MotorGetSoftPosition(self->motors[A1],pCon,&val); + if(status == 0){ + return status; + } + theta = val; + status = MotorGetSoftPosition(self->motors[A2],pCon,&val); + if(status == 0){ + return status; + } + ang->monochromator_two_theta = val; + if(ABS(val/2. - theta) > .1){ + SCWrite(pCon,"WARNING: theta monochromator not half of two theta",eWarning); + } + + /* + Analyzer + */ + status = MotorGetSoftPosition(self->motors[A5],pCon,&val); + if(status == 0){ + return status; + } + theta = val; + status = MotorGetSoftPosition(self->motors[A6],pCon,&val); + if(status == 0){ + return status; + } + ang->analyzer_two_theta = val; + if(ABS(val/2. - theta) > .1){ + SCWrite(pCon,"WARNING: theta analyzer not half of two theta",eWarning); + } + + + /* + crystal + */ + status = MotorGetSoftPosition(self->motors[A3],pCon,&val); + if(status == 0){ + return status; + } + ang->a3 = val; + status = MotorGetSoftPosition(self->motors[A4],pCon,&val); + if(status == 0){ + return status; + } + ang->sample_two_theta = val; + status = MotorGetSoftPosition(self->motors[SGU],pCon,&val); + if(status == 0){ + return status; + } + ang->sgu = val; + status = MotorGetSoftPosition(self->motors[SGL],pCon,&val); + if(status == 0){ + return status; + } + ang->sgl = val; + return 1; +} +/*-------------------------------------------------------------*/ +static float TASGetValue(void *pData, SConnection *pCon){ + ptasMot self = (ptasMot)pData; + int status; + tasAngles angles; + double val; + + assert(self); + + if(self->math->mustRecalculate == 1) { + status = readTASMotAngles(self->math, pCon, &angles); + if(status != 1){ + return -999.99; + } + status = calcTasQEPosition(&self->math->machine, angles, &self->math->current); + if(status < 0){ + SCWrite(pCon,"ERROR: out of memory calculating Q-E variables",eError); + return -999.99; + } + self->math->mustRecalculate = 0; + } + val = getTasPar(self->math->current,self->code); + return (float)val; +} +/*-----------------------------------------------------------------*/ +static float TASQMGetValue(void *pData, SConnection *pCon){ + ptasMot self = (ptasMot)pData; + int status; + tasAngles angles; + double val; + + assert(self); + + if(self->math->mustRecalculate == 1) { + status = readTASMotAngles(self->math, pCon, &angles); + if(status != 1){ + return -999.99; + } + status = calcTasPowderPosition(&self->math->machine, angles, &self->math->current); + if(status < 0){ + SCWrite(pCon,"ERROR: out of memory calculating Q-E variables",eError); + return -999.99; + } + self->math->mustRecalculate = 0; + } + val = getTasPar(self->math->current,self->code); + return (float)val; +} +/*---------------------------------------------------------------------------------*/ +static int TASCheckLimits(void *pData, float fVal, char *error, int iErrLen){ + /* + There is no meaningful implementation here. This gets called when starting the motor. + At that stage not all other values may be known. If the calculation fails, + this will die at status check time. + */ + return 1; +} +/*---------------------------------------------------------------------------------*/ +static int TASHalt(void *pData){ + ptasMot self = (ptasMot)pData; + int i; + + assert(self); + for(i = 0; i < 12; i++){ + if(self->math->motors[i] != NULL){ + self->math->motors[i]->pDrivInt->Halt(self->math->motors[i]); + } + } + return 1; +} +/*---------------------------------------------------------------------------*/ +static int startMotors(ptasMot self, tasAngles angles, + SConnection *pCon){ + float val; + double curve; + int status; + + /* + monochromator + */ + val = self->math->motors[A1]->pDrivInt->GetValue(self->math->motors[A1],pCon); + if(ABS(val - angles.monochromator_two_theta/2.) > MOTPREC){ + status = self->math->motors[A1]->pDrivInt->SetValue(self->math->motors[A1], + pCon, + angles.monochromator_two_theta/2.); + if(status != OKOK){ + return status; + } + } + val = self->math->motors[A2]->pDrivInt->GetValue(self->math->motors[A2],pCon); + if(ABS(val - angles.monochromator_two_theta) > MOTPREC){ + status = self->math->motors[A2]->pDrivInt->SetValue(self->math->motors[A2], + pCon, + angles.monochromator_two_theta); + if(status != OKOK){ + return status; + } + } + if(self->math->motors[MCV] != NULL){ + curve = maCalcVerticalCurvature(self->math->machine.monochromator, + angles.monochromator_two_theta); + val = self->math->motors[MCV]->pDrivInt->GetValue(self->math->motors[MCV],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[MCV]->pDrivInt->SetValue(self->math->motors[MCV], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + if(self->math->motors[MCH] != NULL){ + curve = maCalcHorizontalCurvature(self->math->machine.monochromator, + angles.monochromator_two_theta); + val = self->math->motors[MCH]->pDrivInt->GetValue(self->math->motors[MCH],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[MCH]->pDrivInt->SetValue(self->math->motors[MCH], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + + /* + analyzer + */ + val = self->math->motors[A5]->pDrivInt->GetValue(self->math->motors[A5],pCon); + if(ABS(val - angles.analyzer_two_theta/2.) > MOTPREC){ + status = self->math->motors[A5]->pDrivInt->SetValue(self->math->motors[A5], + pCon, + angles.analyzer_two_theta/2.); + if(status != OKOK){ + return status; + } + } + val = self->math->motors[A6]->pDrivInt->GetValue(self->math->motors[A6],pCon); + if(ABS(val - angles.analyzer_two_theta) > MOTPREC){ + status = self->math->motors[A6]->pDrivInt->SetValue(self->math->motors[A6], + pCon, + angles.analyzer_two_theta); + if(status != OKOK){ + return status; + } + } + if(self->math->motors[ACV] != NULL){ + curve = maCalcVerticalCurvature(self->math->machine.analyzer, + angles.analyzer_two_theta); + val = self->math->motors[ACV]->pDrivInt->GetValue(self->math->motors[ACV],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[ACV]->pDrivInt->SetValue(self->math->motors[ACV], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + if(self->math->motors[ACH] != NULL){ + curve = maCalcHorizontalCurvature(self->math->machine.analyzer, + angles.analyzer_two_theta); + val = self->math->motors[ACH]->pDrivInt->GetValue(self->math->motors[ACH],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[ACH]->pDrivInt->SetValue(self->math->motors[ACH], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + + /* + crystal + */ + val = self->math->motors[A3]->pDrivInt->GetValue(self->math->motors[A3],pCon); + if(ABS(val - angles.a3) > MOTPREC){ + status = self->math->motors[A3]->pDrivInt->SetValue(self->math->motors[A3], + pCon, + angles.a3); + if(status != OKOK){ + return status; + } + } + val = self->math->motors[A4]->pDrivInt->GetValue(self->math->motors[A4],pCon); + if(ABS(val - angles.sample_two_theta) > MOTPREC){ + status = self->math->motors[A4]->pDrivInt->SetValue(self->math->motors[A4], + pCon, + angles.sample_two_theta); + if(status != OKOK){ + return status; + } + } + val = self->math->motors[SGL]->pDrivInt->GetValue(self->math->motors[SGL],pCon); + if(ABS(val - angles.sgl) > MOTPREC){ + status = self->math->motors[SGL]->pDrivInt->SetValue(self->math->motors[SGL], + pCon, + angles.sgl); + if(status != OKOK){ + return status; + } + } + val = self->math->motors[SGU]->pDrivInt->GetValue(self->math->motors[SGU],pCon); + if(ABS(val - angles.sgu) > MOTPREC){ + status = self->math->motors[SGU]->pDrivInt->SetValue(self->math->motors[SGU], + pCon, + angles.sgu); + if(status != OKOK){ + return status; + } + } + self->math->mustDrive = 0; + return OKOK; +} +/*-----------------------------------------------------------------------------*/ +static int calculateAndDrive(ptasMot self, SConnection *pCon){ + tasAngles angles; + int status; + + status = calcAllTasAngles(&self->math->machine, self->math->target, + &angles); + switch(status){ + case ENERGYTOBIG: + SCWrite(pCon,"ERROR: desired energy to big",eError); + return HWFault; + break; + + case UBNOMEMORY: + SCWrite(pCon,"ERROR: out of memory calculating angles",eError); + return HWFault; + break; + case BADRMATRIX: + SCWrite(pCon,"ERROR: bad crystallographic parameters or bad UB",eError); + return HWFault; + break; + case TRIANGLENOTCLOSED: + SCWrite(pCon,"ERROR: cannot close scattering triangle",eError); + return HWFault; + break; + default: + return startMotors(self,angles,pCon); + } + return HWFault; +} +/*-----------------------------------------------------------------------------*/ +static int checkMotors(ptasMot self, SConnection *pCon){ + int i, status; + + self->math->mustRecalculate = 1; + for(i = 0; i < 12; i++){ + if(self->math->motors[i] != NULL){ + status = self->math->motors[i]->pDrivInt->CheckStatus(self->math->motors[i],pCon); + if(status != HWIdle && status != OKOK){ + return status; + } + } + } + return HWIdle; +} +/*------------------------------------------------------------------------------*/ +static int TASGetStatus(void *pData, SConnection *pCon){ + ptasMot self = (ptasMot)pData; + int status; + assert(self); + + if(self->math->mustDrive == 1){ + status = calculateAndDrive(self,pCon); + if(status != OKOK){ + return HWFault; + } else { + return HWBusy; + } + } else { + return checkMotors(self, pCon); + } +} +/*---------------------------------------------------------------------------*/ +static int startQMMotors(ptasMot self, tasAngles angles, + SConnection *pCon){ + float val; + double curve; + int status; + + /* + monochromator + */ + val = self->math->motors[A1]->pDrivInt->GetValue(self->math->motors[A1],pCon); + if(ABS(val - angles.monochromator_two_theta/2.) > MOTPREC){ + status = self->math->motors[A1]->pDrivInt->SetValue(self->math->motors[A1], + pCon, + angles.monochromator_two_theta/2.); + if(status != OKOK){ + return status; + } + } + val = self->math->motors[A2]->pDrivInt->GetValue(self->math->motors[A2],pCon); + if(ABS(val - angles.monochromator_two_theta) > MOTPREC){ + status = self->math->motors[A2]->pDrivInt->SetValue(self->math->motors[A2], + pCon, + angles.monochromator_two_theta); + if(status != OKOK){ + return status; + } + } + if(self->math->motors[MCV] != NULL){ + curve = maCalcVerticalCurvature(self->math->machine.monochromator, + angles.monochromator_two_theta); + val = self->math->motors[MCV]->pDrivInt->GetValue(self->math->motors[MCV],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[MCV]->pDrivInt->SetValue(self->math->motors[MCV], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + if(self->math->motors[MCH] != NULL){ + curve = maCalcHorizontalCurvature(self->math->machine.monochromator, + angles.monochromator_two_theta); + val = self->math->motors[MCH]->pDrivInt->GetValue(self->math->motors[MCH],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[MCH]->pDrivInt->SetValue(self->math->motors[MCH], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + + /* + analyzer + */ + val = self->math->motors[A5]->pDrivInt->GetValue(self->math->motors[A5],pCon); + if(ABS(val - angles.analyzer_two_theta/2.) > MOTPREC){ + status = self->math->motors[A5]->pDrivInt->SetValue(self->math->motors[A5], + pCon, + angles.analyzer_two_theta/2.); + if(status != OKOK){ + return status; + } + } + val = self->math->motors[A6]->pDrivInt->GetValue(self->math->motors[A6],pCon); + if(ABS(val - angles.analyzer_two_theta) > MOTPREC){ + status = self->math->motors[A6]->pDrivInt->SetValue(self->math->motors[A6], + pCon, + angles.analyzer_two_theta); + if(status != OKOK){ + return status; + } + } + if(self->math->motors[ACV] != NULL){ + curve = maCalcVerticalCurvature(self->math->machine.analyzer, + angles.analyzer_two_theta); + val = self->math->motors[ACV]->pDrivInt->GetValue(self->math->motors[ACV],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[ACV]->pDrivInt->SetValue(self->math->motors[ACV], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + if(self->math->motors[ACH] != NULL){ + curve = maCalcHorizontalCurvature(self->math->machine.analyzer, + angles.analyzer_two_theta); + val = self->math->motors[ACH]->pDrivInt->GetValue(self->math->motors[ACH],pCon); + if(ABS(val - curve) > MOTPREC){ + status = self->math->motors[ACH]->pDrivInt->SetValue(self->math->motors[ACH], + pCon, + curve); + if(status != OKOK){ + return status; + } + } + } + + /* + crystal + */ + val = self->math->motors[A4]->pDrivInt->GetValue(self->math->motors[A4],pCon); + if(ABS(val - angles.sample_two_theta) > MOTPREC){ + status = self->math->motors[A4]->pDrivInt->SetValue(self->math->motors[A4], + pCon, + angles.sample_two_theta); + if(status != OKOK){ + return status; + } + } + + self->math->mustDrive = 0; + return OKOK; +} +/*-----------------------------------------------------------------------------*/ +static int calculateQMAndDrive(ptasMot self, SConnection *pCon){ + tasAngles angles; + int status; + + status = calcTasPowderAngles(&self->math->machine, self->math->target, + &angles); + switch(status){ + case ENERGYTOBIG: + SCWrite(pCon,"ERROR: desired energy to big",eError); + return HWFault; + break; + case TRIANGLENOTCLOSED: + SCWrite(pCon,"ERROR: cannot close scattering triangle",eError); + return HWFault; + break; + default: + return startQMMotors(self,angles,pCon); + } + return HWFault; +} +/*------------------------------------------------------------------------------*/ +static int TASQMGetStatus(void *pData, SConnection *pCon){ + ptasMot self = (ptasMot)pData; + int status; + assert(self); + + if(self->math->mustDrive == 1){ + status = calculateQMAndDrive(self,pCon); + if(status != OKOK){ + return HWFault; + } else { + return HWBusy; + } + } else { + return checkMotors(self, pCon); + } +} +/*================== Life and Death =========================================*/ +static void KillTasMot(void *pData){ + ptasMot self = (ptasMot)pData; + if(self == NULL){ + return; + } + + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + self->pDes == NULL; + } + if(self->pDriv != NULL){ + free(self->pDriv); + self->pDriv = NULL; + } + free(self); +} +/*---------------------------------------------------------------------------*/ +static void *GetTasInterface(void *pData, int interfaceID){ + ptasMot self = (ptasMot)pData; + + if(self != NULL && interfaceID == DRIVEID){ + return self->pDriv; + } else { + return NULL; + } +} +/*-------------------------------------------------------------------------*/ +int InstallTasMotor(SicsInterp *pSics, ptasUB self, int tasVar, char *name){ + ptasMot pNew = NULL; + + pNew = (ptasMot)malloc(sizeof(tasMot)); + if(!pNew){ + return 0; + } + memset(pNew,0,sizeof(tasMot)); + pNew->pDes = CreateDescriptor("TasMot"); + pNew->pDriv = CreateDrivableInterface(); + if(!pNew->pDes || !pNew->pDriv) { + free(pNew); + return 0; + } + pNew->pDes->GetInterface = GetTasInterface; + pNew->pDriv->Halt = TASHalt; + pNew->pDriv->CheckLimits = TASCheckLimits; + pNew->pDriv->SetValue = TASSetValue; + pNew->pDriv->CheckStatus = TASGetStatus; + pNew->pDriv->GetValue = TASGetValue; + pNew->math = self; + pNew->code = tasVar; + + return AddCommand(pSics,name, TasMot, KillTasMot,pNew); + +} +/*-------------------------------------------------------------------------*/ +int InstallTasQMMotor(SicsInterp *pSics, ptasUB self){ + ptasMot pNew = NULL; + + pNew = (ptasMot)malloc(sizeof(tasMot)); + if(!pNew){ + return 0; + } + memset(pNew,0,sizeof(tasMot)); + pNew->pDes = CreateDescriptor("TasMot"); + pNew->pDriv = CreateDrivableInterface(); + if(!pNew->pDes || !pNew->pDriv) { + free(pNew); + return 0; + } + pNew->pDes->GetInterface = GetTasInterface; + pNew->pDriv->Halt = TASHalt; + pNew->pDriv->CheckLimits = TASCheckLimits; + pNew->pDriv->SetValue = TASSetValue; + pNew->pDriv->CheckStatus = TASQMGetStatus; + pNew->pDriv->GetValue = TASQMGetValue; + pNew->math = self; + pNew->code = QM; + + return AddCommand(pSics,"qm", TasMot, KillTasMot,pNew); +} +/*------------------------------------------------------------------------*/ +int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + ptasMot self = (ptasMot)pData; + float value; + char pBueffel[132]; + + if(argc > 1){ + strtolower(argv[1]); + if(strcmp(argv[1],"target") == 0){ + snprintf(pBueffel,131,"%s.target = %f", + argv[0], getTasPar(self->math->target,self->code)); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + SCWrite(pCon,"ERROR: tasmot does not understand this subcommand",eError); + return 0; + } + } + value = self->pDriv->GetValue(self,pCon); + snprintf(pBueffel,131,"%s = %f", argv[0], value); + SCWrite(pCon,pBueffel,eValue); + return 1; +} diff --git a/tasdrive.h b/tasdrive.h new file mode 100644 index 00000000..c6c061ca --- /dev/null +++ b/tasdrive.h @@ -0,0 +1,17 @@ + +/*--------------------------------------------------------------------- + SICS interface to the triple axis drivable motors. + + copyright: see file COPYRIGHT + + Mark Koennecke, May 2005 +--------------------------------------------------------------------*/ +#ifndef TASDRIV +#define TASDRIV +#include "tasub.h" + +int InstallTasMotor(SicsInterp *pSics, ptasUB self, int tasVar, char *name); +int InstallTasQMMotor(SicsInterp *pSics, ptasUB self); +int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData, + int argc, char *argv[]); +#endif diff --git a/tasub.c b/tasub.c index 2cc3cb18..58f62284 100644 --- a/tasub.c +++ b/tasub.c @@ -10,6 +10,7 @@ #include "sics.h" #include "lld.h" #include "tasub.h" +#include "tasdrive.h" /*------------------- motor indexes in motor data structure ---------*/ #define A1 0 #define A2 1 @@ -43,8 +44,9 @@ static void saveReflections(ptasUB self, char *name, FILE *fd){ while(status == 1){ LLDnodeDataTo(self->reflectionList,&r); fprintf(fd,"%s addref %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", - name, r.h, r.k, r.l, r.a3, r.two_theta, r.sgu, r.sgl, - KtoEnergy(r.ki), KtoEnergy(r.kf)); + name, r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta, + r.angles.sgu, r.angles.sgl, + KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf)); status = LLDnodePtr2Next(self->reflectionList); } } @@ -68,6 +70,20 @@ static int tasUBSave(void *pData, char *name, FILE *fd){ fprintf(fd,"%s const kf\n",name); } fprintf(fd,"%s ss %d\n", name,self->machine.ss_sample); + fprintf(fd," %s setub %f %f %f %f %f %f %f %f %f\n", + name, + self->machine.UB[0][0], self->machine.UB[0][1], self->machine.UB[0][2], + self->machine.UB[1][0], self->machine.UB[1][1], self->machine.UB[1][2], + self->machine.UB[2][0], self->machine.UB[2][1], self->machine.UB[2][2]); + fprintf(fd," %s setnormal %f %f %f\n", + name, + self->machine.planeNormal[0][0], self->machine.planeNormal[1][0], + self->machine.planeNormal[2][0]); + fprintf(fd,"%s settarget %f %f %f %f %f %f\n", + name, + self->target.qh, self->target.qk, self->target.ql, self->target.qm, + self->target.ki, self->target.kf); + fprintf(fd,"%s update\n", name); return 1; } /*------------------------------------------------------------------*/ @@ -108,7 +124,7 @@ static ptasUB MakeTasUB(){ pNew->targetEn = .0; pNew->actualEn = .0; pNew->mustRecalculate = 1; - + return pNew; } /*-------------------------------------------------------------------*/ @@ -139,58 +155,20 @@ static int readTASAngles(ptasUB self, SConnection *pCon, /* Monochromator */ - status = MotorGetSoftPosition(self->motors[A1],pCon,&val); - if(status == 0){ - return status; - } - ang->monochromator.theta = val; status = MotorGetSoftPosition(self->motors[A2],pCon,&val); if(status == 0){ return status; } - ang->monochromator.two_theta = val; - if(self->motors[MCV] != NULL){ - status = MotorGetSoftPosition(self->motors[MCV],pCon,&val); - if(status == 0){ - return status; - } - ang->monochromator.vertical_curvature = val; - } - if(self->motors[MCH] != NULL){ - status = MotorGetSoftPosition(self->motors[MCH],pCon,&val); - if(status == 0){ - return status; - } - ang->monochromator.horizontal_curvature = val; - } + ang->monochromator_two_theta = val; /* Analyzer */ - status = MotorGetSoftPosition(self->motors[A5],pCon,&val); - if(status == 0){ - return status; - } - ang->analyzer.theta = val; status = MotorGetSoftPosition(self->motors[A6],pCon,&val); if(status == 0){ return status; } - ang->analyzer.two_theta = val; - if(self->motors[ACV] != NULL){ - status = MotorGetSoftPosition(self->motors[ACV],pCon,&val); - if(status == 0){ - return status; - } - ang->analyzer.vertical_curvature = val; - } - if(self->motors[ACH] != NULL){ - status = MotorGetSoftPosition(self->motors[ACH],pCon,&val); - if(status == 0){ - return status; - } - ang->analyzer.horizontal_curvature = val; - } + ang->analyzer_two_theta = val; /* crystal @@ -233,7 +211,12 @@ static int testMotor(ptasUB pNew, SConnection *pCon, char *name, int idx){ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData, int argc, char *argv[]){ ptasUB pNew = NULL; - int status = 0; + int status = 0, i; + char pBueffel[132]; + char names[][3] = {"ei","ki", + "qh","qk","ql", + "ef","kf", + "en"}; if(argc < 2) { SCWrite(pCon,"ERROR: need name to install tasUB",eError); @@ -284,9 +267,23 @@ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: duplicate tasUB command not created",eError); return 0; } + /* - TODO: install all the virtual motors + install virtual motors */ + for(i = 0; i < 8; i++){ + status = InstallTasMotor(pSics,pNew,i+1,names[i]); + if(status != 1){ + snprintf(pBueffel,131,"ERROR: failed to create TAS motor %s", names[i]); + SCWrite(pCon,pBueffel,eError); + } + } + status = InstallTasQMMotor(pSics,pNew); + if(status != 1){ + snprintf(pBueffel,131,"ERROR: failed to create TAS motor qm"); + SCWrite(pCon,pBueffel,eError); + } + return 1; } /*-----------------------------------------------------------------*/ @@ -304,6 +301,10 @@ static int setCrystalParameters(pmaCrystal crystal, SConnection *pCon, return 1; } + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + strtolower(argv[2]); if(strcmp(argv[2],"dd") == 0){ crystal->dd = d; @@ -411,6 +412,11 @@ static int tasReadCell(SConnection *pCon, ptasUB self, int argc, char *argv[]){ eError); return 0; } + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + status = Tcl_GetDouble(pTcl,argv[2],&self->cell.a); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); @@ -487,7 +493,8 @@ static void listReflections(ptasUB self, SConnection *pCon){ count++; LLDnodeDataTo(self->reflectionList,&r); snprintf(line,255,"%3d %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", - count, r.h, r.k, r.l, r.a3, r.two_theta, r.sgu, r.sgl, r.ki, r.kf); + count, r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta, + r.angles.sgu, r.angles.sgl, r.qe.ki, r.qe.kf); Tcl_DStringAppend(&list,line,-1); status = LLDnodePtr2Next(self->reflectionList); } @@ -513,19 +520,24 @@ static int addReflection(ptasUB self, SicsInterp *pSics, eError); return 0; } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&r.h); + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&r.qe.qh); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&r.k); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&r.qe.qk); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&r.l); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&r.qe.ql); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]); SCWrite(pCon,pBueffel,eError); @@ -533,66 +545,56 @@ static int addReflection(ptasUB self, SicsInterp *pSics, } if(argc >= 11){ - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&r.a3); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&r.angles.a3); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]); SCWrite(pCon,pBueffel,eError); return 0; } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&r.a3); - if(status != TCL_OK){ - snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]); - SCWrite(pCon,pBueffel,eError); - return 0; - } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&r.two_theta); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&r.angles.sample_two_theta); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]); SCWrite(pCon,pBueffel,eError); return 0; } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&r.sgu); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&r.angles.sgu); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]); SCWrite(pCon,pBueffel,eError); return 0; } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[8],&r.sgl); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[8],&r.angles.sgl); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[8]); SCWrite(pCon,pBueffel,eError); return 0; } - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[9],&r.ki); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[9],&r.qe.ki); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[9]); SCWrite(pCon,pBueffel,eError); return 0; } - r.ki = energyToK(r.ki); - status = Tcl_GetDouble(InterpGetTcl(pSics),argv[10],&r.kf); + r.qe.ki = energyToK(r.qe.ki); + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[10],&r.qe.kf); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[10]); SCWrite(pCon,pBueffel,eError); return 0; } - r.kf = energyToK(r.kf); + r.qe.kf = energyToK(r.qe.kf); } else { if(argc > 5){ SCWrite(pCon, "WARNING: not all angles given on command line, using positions instead", eWarning); } - status = readTASAngles(self,pCon,&angles); + status = readTASAngles(self,pCon,&r.angles); if(status != 1){ return status; } - r.a3 = angles.a3; - r.two_theta = angles.sample_two_theta; - r.sgu = angles.sgu; - r.sgl = angles.sgl; - maCalcK(self->machine.monochromator,angles.monochromator,&r.ki); - maCalcK(self->machine.analyzer,angles.analyzer,&r.kf); + r.qe.ki = maCalcK(self->machine.monochromator,angles.monochromator_two_theta); + r.qe.kf = maCalcK(self->machine.analyzer,angles.analyzer_two_theta); } LLDnodeAppend(self->reflectionList,&r); Tcl_DStringInit(&list); @@ -601,10 +603,12 @@ static int addReflection(ptasUB self, SicsInterp *pSics, Tcl_DStringAppend(&list,pBueffel,-1); snprintf(pBueffel,255, " %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", - r.h, r.k, r.l, r.a3, r.two_theta, r.sgu, r.sgl, r.ki, r.kf); + r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta, + r.angles.sgu, r.angles.sgl, r.qe.ki, r.qe.kf); Tcl_DStringAppend(&list,pBueffel,-1); SCWrite(pCon,Tcl_DStringValue(&list),eValue); Tcl_DStringFree(&list); + SCparChange(pCon); return 1; } /*-----------------------------------------------------------------*/ @@ -662,28 +666,30 @@ static void printReflectionDiagnostik(ptasUB self, SConnection *pCon, Tcl_DStringAppend(&list,line,-1); snprintf(line,255, "INPUT %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", - r.h, r.k, r.l, r.a3, r.two_theta, r.sgu, r.sgl, r.ki, r.kf); + r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, + r.angles.sample_two_theta, r.angles.sgu, r.angles.sgl, r.qe.ki, r.qe.kf); Tcl_DStringAppend(&list,line,-1); - qe.ki = r.ki; - qe.kf = r.kf; - qe.qk = r.h; - qe.qk = r.k; - qe.ql = r.l; + qe.ki = r.qe.ki; + qe.kf = r.qe.kf; + qe.qh = r.qe.qh; + qe.qk = r.qe.qk; + qe.ql = r.qe.ql; calcAllTasAngles(&self->machine,qe,&angles); snprintf(line,255, "QE->ANG %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", - r.h, r.k, r.l, angles.a3, angles.sample_two_theta, - angles.sgu, angles.sgl, r.ki, r.kf); + r.qe.qh, r.qe.qk, r.qe.ql, + angles.a3, angles.sample_two_theta, + angles.sgu, angles.sgl, r.qe.ki, r.qe.kf); Tcl_DStringAppend(&list,line,-1); - angles.a3 = r.a3; - angles.sample_two_theta = r.two_theta; - angles.sgu = r.sgu; - angles.sgl = r.sgl; + angles.a3 = r.angles.a3; + angles.sample_two_theta = r.angles.sample_two_theta; + angles.sgu = r.angles.sgu; + angles.sgl = r.angles.sgl; calcTasQEPosition(&self->machine,angles,&qe); snprintf(line,255, "ANG->QE %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", - qe.qh, qe.qk, qe.ql, r.a3, r.two_theta, - r.sgu, r.sgl, qe.ki, qe.kf); + qe.qh, qe.qk, qe.ql, angles.a3, angles.sample_two_theta, + angles.sgu, angles.sgl, qe.ki, qe.kf); Tcl_DStringAppend(&list,line,-1); SCWrite(pCon,Tcl_DStringValue(&list),eValue); Tcl_DStringFree(&list); @@ -714,6 +720,11 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics, eError); return 0; } + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&idx); if(status != TCL_OK){ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); @@ -761,6 +772,7 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics, self->machine.planeNormal = calcPlaneNormal(r1,r2); listUB(UB,pCon); listDiagnostik(self,pCon); + SCparChange(pCon); return 1; } /*------------------------------------------------------------------*/ @@ -820,19 +832,240 @@ static int calcRefAngles(ptasUB self, SConnection *pCon, SCWrite(pCon,"ERROR: Out of memory calculating angles",eError); return 0; break; + case BADRMATRIX: + SCWrite(pCon,"ERROR: bad crystallographic parameters or bad UB",eError); + return 0; + break; case TRIANGLENOTCLOSED: SCWrite(pCon,"ERROR: scattering triangle not closed",eError); return 0; break; } - snprintf(pBueffel,255," %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f", - angles.monochromator.theta, angles.monochromator.two_theta, + snprintf(pBueffel,255," %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f", + angles.monochromator_two_theta, angles.a3, angles.sample_two_theta, angles.sgl, angles.sgu, - angles.analyzer.theta,angles.analyzer.two_theta); + angles.analyzer_two_theta); SCWrite(pCon,pBueffel,eValue); return 1; } +/*------------------------------------------------------------------*/ +static int setUB(SConnection *pCon, SicsInterp *pSics, ptasUB self, + int argc, char *argv[]){ + double value; + char pBueffel[256]; + int status; + + if(argc < 11){ + SCWrite(pCon,"ERROR: not enough arguments for setting UB", + eError); + return 0; + } + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[0][0] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[0][1] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[0][2] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[1][0] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[1][1] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[1][2] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[8],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[8]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[2][0] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[9],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[9]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[2][1] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[10],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[10]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.UB[2][2] = value; + SCSendOK(pCon); + SCparChange(pCon); + + return 1; +} +/*------------------------------------------------------------------*/ +static int setNormal(SConnection *pCon, SicsInterp *pSics, ptasUB self, + int argc, char *argv[]){ + double value; + char pBueffel[256]; + int status; + + if(argc < 5){ + SCWrite(pCon,"ERROR: not enough arguments for setting plane normal", + eError); + return 0; + } + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.planeNormal[0][0] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.planeNormal[1][0] = value; + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&value); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->machine.planeNormal[2][0] = value; + SCSendOK(pCon); + SCparChange(pCon); + + return 1; +} +/*------------------------------------------------------------------*/ +static int setTarget(SConnection *pCon, SicsInterp *pSics, ptasUB self, + int argc, char *argv[]){ + double value; + char pBueffel[256]; + int status; + + if(argc < 8){ + SCWrite(pCon,"ERROR: not enough arguments for setting qe target", + eError); + return 0; + } + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&self->target.qh); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&self->target.qk); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&self->target.ql); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&self->target.qm); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&self->target.ki); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&self->target.kf); + if(status != TCL_OK){ + snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + + SCSendOK(pCon); + + return 1; +} +/*------------------------------------------------------------------*/ +static int tasUpdate(SConnection *pCon, ptasUB self){ + int status; + tasAngles angles; + + status = readTASAngles(self,pCon,&angles); + if(status != 1){ + return status; + } + status = calcTasQEPosition(&self->machine, angles, &self->current); + if(status < 0){ + SCWrite(pCon,"ERROR: out of memory calculating Q-E variables",eError); + return 0; + } + self->mustRecalculate = 0; + SCSendOK(pCon); + return 1; +} /*-------------------------------------------------------------------*/ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, int argc, char *argv[]){ @@ -877,6 +1110,14 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, return calcUB(self,pCon,pSics,argc,argv); } else if(strcmp(argv[1],"calcref") == 0){ return calcRefAngles(self,pCon,pSics,argc,argv); + } else if(strcmp(argv[1],"setub") == 0){ + return setUB(pCon,pSics,self,argc,argv); + } else if(strcmp(argv[1],"setnormal") == 0){ + return setNormal(pCon,pSics,self,argc,argv); + } else if(strcmp(argv[1],"settarget") == 0){ + return setTarget(pCon,pSics,self,argc,argv); + } else if(strcmp(argv[1],"update") == 0){ + return tasUpdate(pCon,self); } else if(strcmp(argv[1],"const") == 0){ if(argc > 2){ strtolower(argv[2]); @@ -919,6 +1160,7 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, return 0; } self->machine.ss_sample = newSS; + tasUpdate(pCon,self); SCSendOK(pCon); return 1; } else { diff --git a/tasub.h b/tasub.h index fb86cbfc..8086b0f0 100644 --- a/tasub.h +++ b/tasub.h @@ -15,9 +15,6 @@ #include "motor.h" /*------------------- defines for tasMode -----------------------------------*/ -#define KICONST 1 -#define KFCONST 2 -/*-----------------------------------------------------------------------------*/ typedef struct{ pObjectDescriptor pDes; tasMachine machine; @@ -33,16 +30,6 @@ }tasUB, *ptasUB; -/*----------------------- defines for virtual motors -----------------------------*/ -#define EI 1 -#define KI 2 -#define QH 3 -#define QK 4 -#define QL 5 -#define EF 6 -#define KF 7 -#define EN 8 -#define QM 9 /*--------------------- the tas virtual motor data structure ---------------------*/ typedef struct { pObjectDescriptor pDes; @@ -57,8 +44,6 @@ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData, int argc, char *argv[]); int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, int argc, char *argv[]); -int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData, - int argc, char *argv[]); #endif diff --git a/tasub.w b/tasub.w index f6be124c..04de0974 100644 --- a/tasub.w +++ b/tasub.w @@ -17,9 +17,6 @@ This module handles the calculations typical for a triple axis spectrometer. A data structure: @d tasubdat @{ /*------------------- defines for tasMode -----------------------------------*/ -#define KICONST 1 -#define KFCONST 2 -/*-----------------------------------------------------------------------------*/ typedef struct{ pObjectDescriptor pDes; tasMachine machine; @@ -56,16 +53,6 @@ A data structure: For the virtual motors, there must be a data structure, too: @d tasubmotdat @{ -/*----------------------- defines for virtual motors -----------------------------*/ -#define EI 1 -#define KI 2 -#define QH 3 -#define QK 4 -#define QL 5 -#define EF 6 -#define KF 7 -#define EN 8 -#define QM 9 /*--------------------- the tas virtual motor data structure ---------------------*/ typedef struct { pObjectDescriptor pDes; @@ -88,8 +75,6 @@ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData, int argc, char *argv[]); int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, int argc, char *argv[]); -int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData, - int argc, char *argv[]); @} @@ -113,4 +98,22 @@ int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData, /*--------------------------------------------------------------------*/ @ #endif -@} \ No newline at end of file +@} +@o tasdrive.h @{ +/*--------------------------------------------------------------------- + SICS interface to the triple axis drivable motors. + + copyright: see file COPYRIGHT + + Mark Koennecke, May 2005 +--------------------------------------------------------------------*/ +#ifndef TASDRIV +#define TASDRIV +#include "tasub.h" + +int InstallTasMotor(SicsInterp *pSics, ptasUB self, int tasVar, char *name); +int InstallTasQMMotor(SicsInterp *pSics, ptasUB self); +int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData, + int argc, char *argv[]); +#endif +@} diff --git a/tasublib.c b/tasublib.c index f9bb67ea..ab36e988 100644 --- a/tasublib.c +++ b/tasublib.c @@ -1,13 +1,15 @@ /** * This is a library of functions and data structures for performing * triple axis spectrometer angle calculations using the UB-matrix - * formalism as described by Mark Lumsden. + * formalism as described by Mark Lumsden, to appear in Acta Cryst. * * copyright: see file COPYRIGHT * * Mark Koennecke, April 2005 */ #include +#include +#include #include "trigd.h" #include "vector.h" #include "tasublib.h" @@ -30,42 +32,53 @@ double KtoEnergy(double k){ energy = ECONST*k*k; return energy; } +/*-------------------------------------------------------------------*/ +static double calcCurvature(double B1, double B2, double theta){ + return B1 + B2/Sind(ABS(theta)); +} /*--------------------------------------------------------------------*/ -int maCalcAngles(maCrystal data, pmaAngles angles, double k){ - double fd; +int maCalcTwoTheta(maCrystal data, double k, double *two_theta){ + double fd, theta; /* fd = k/(2.*data.dd); */ fd = PI/(data.dd*k); if(fd > 1.0) { return ENERGYTOBIG; } - angles->theta = Asind(fd)*data.ss; - angles->two_theta = 2.*angles->theta; - angles->horizontal_curvature = data.HB1 + data.HB2/Sind(angles->theta); - angles->vertical_curvature = data.VB1 + data.VB2/Sind(angles->theta); + theta = Asind(fd)*data.ss; + *two_theta = 2.*theta; return 1; } /*--------------------------------------------------------------------*/ -int maCalcK(maCrystal data, maAngles angles, double *k){ - - *k = ABS(data.dd * Sind(angles.two_theta/2)); - *k = PI / *k; - if(ABS(angles.two_theta/2. - angles.theta) > .1) { - return BADSYNC; +double maCalcVerticalCurvature(maCrystal data, double two_theta){ + return calcCurvature(data.VB1,data.VB2, two_theta/2.); +} +/*-------------------------------------------------------------------*/ +double maCalcHorizontalCurvature(maCrystal data, double two_theta){ + return calcCurvature(data.HB1,data.HB2, two_theta/2.); +} +/*--------------------------------------------------------------------*/ +double maCalcK(maCrystal data, double two_theta){ + double k; + k = ABS(data.dd * Sind(two_theta/2)); + if(ABS(k) > .001){ + k = PI / k; + } else { + k = .0; } - return 1; + return k; } /*==================== reciprocal space ==============================*/ -static MATRIX tasReflectionToHC(tasReflection r, MATRIX B){ +static MATRIX tasReflectionToHC(tasQEPosition r, MATRIX B){ MATRIX h = NULL, hc = NULL; h = makeVector(); if(h == NULL){ return NULL; } - vectorSet(h,0,r.h); - vectorSet(h,1,r.k); - vectorSet(h,2,r.l); + vectorSet(h,0,r.qh); + vectorSet(h,1,r.qk); + vectorSet(h,2,r.ql); hc = mat_mul(B,h); killVector(h); @@ -135,9 +148,9 @@ static MATRIX uFromAngles(double om, double sgu, double sgl){ static MATRIX calcTasUVectorFromAngles(tasReflection r){ double theta, om; - theta = calcTheta(r.ki,r.kf,r.two_theta); - om = r.a3 - theta; - return uFromAngles(om,r.sgu, r.sgl); + theta = calcTheta(r.qe.ki,r.qe.kf,r.angles.sample_two_theta); + om = r.angles.a3 - theta; + return uFromAngles(om,r.angles.sgu, r.angles.sgl); } /*-------------------------------------------------------------------*/ MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2){ @@ -170,8 +183,8 @@ MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1, *errorCode = status; return NULL; } - h1 = tasReflectionToHC(r1,B); - h2 = tasReflectionToHC(r2,B); + h1 = tasReflectionToHC(r1.qe,B); + h2 = tasReflectionToHC(r2.qe,B); if(h1 == NULL || h2 == NULL){ *errorCode = UBNOMEMORY; return NULL; @@ -265,34 +278,33 @@ static MATRIX buildTVMatrix(MATRIX U1V, MATRIX U2V){ return T; } /*-----------------------------------------------------------------------------*/ -static MATRIX tasReflectionToQC(ptasReflection r, MATRIX UB){ +static MATRIX tasReflectionToQC(tasQEPosition r, MATRIX UB){ MATRIX Q, QC; Q = makeVector(); if(Q == NULL){ return NULL; } - vectorSet(Q,0,r->h); - vectorSet(Q,1,r->k); - vectorSet(Q,2,r->l); + vectorSet(Q,0,r.qh); + vectorSet(Q,1,r.qk); + vectorSet(Q,2,r.ql); QC = mat_mul(UB,Q); killVector(Q); return QC; } /*----------------------------------------------------------------------------*/ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal, - ptasReflection r){ - MATRIX U3V, U1V, U2V, TV, TVINV; + tasQEPosition qe){ + MATRIX U1V, U2V, TV, TVINV, M; - U3V = planeNormal; - U1V = tasReflectionToQC(r,UB); + U1V = tasReflectionToQC(qe,UB); if(U1V == NULL){ return NULL; } normalizeVector(U1V); - U2V = vectorCrossProduct(U3V,U1V); + U2V = vectorCrossProduct(planeNormal,U1V); if(U2V == NULL){ killVector(U1V); return NULL; @@ -305,73 +317,69 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal, return NULL; } TVINV = mat_inv(TV); - if(TVINV == NULL){ - killVector(U1V); - killVector(U2V); - mat_free(TV); - return NULL; - } - + killVector(U1V); killVector(U2V); - mat_free(TVINV); - + mat_free(TV); return TVINV; } /*-------------------------------------------------------------------------------*/ -int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int ss, ptasReflection r){ +int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int ss, tasQEPosition qe, + ptasAngles angles){ MATRIX R, QC; - double om, q, theta, cos2t, tmp; + double om, q, theta, cos2t, tmp, sq; - R = buildRMatrix(UB, planeNormal, r); + R = buildRMatrix(UB, planeNormal, qe); if(R == NULL){ return UBNOMEMORY; } - om = Acosd(R[0][0]/sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0])); - r->sgl = Acosd(sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0])); - r->sgu = Asind(R[2][1]/sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0])); - - /* - r->sgl = Asind(-R[2][0]); - tmp = sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]); - if(tmp > .001){ - r->sgu = Acosd(R[2][2]/tmp); - } else { + sq = sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]); + if(ABS(sq) < .00001){ return BADRMATRIX; } - */ - - - QC = tasReflectionToQC(r,UB); + om = Acosd(R[0][0]/sq); + om -= 180.; + angles->sgl = Acosd(sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0])); + sq = sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]); + if(ABS(sq) < .00001){ + return BADRMATRIX; + } + angles->sgu = Asind(R[2][1]/sq); + + QC = tasReflectionToQC(qe,UB); if(QC == NULL){ return UBNOMEMORY; } q = vectorLength(QC); q = 2.*PI*vectorLength(QC); - cos2t = (r->ki*r->ki + r->kf*r->kf - q*q)/(2. * ABS(r->ki) * ABS(r->kf)); + cos2t = (qe.ki*qe.ki + qe.kf*qe.kf - q*q)/(2. * ABS(qe.ki) * ABS(qe.kf)); if(cos2t > 1.){ return TRIANGLENOTCLOSED; } - r->two_theta = ss*Acosd(cos2t); + angles->sample_two_theta = ss*Acosd(cos2t); - theta = calcTheta(r->ki, r->kf,r->two_theta); + theta = calcTheta(qe.ki, qe.kf,angles->sample_two_theta); - r->a3 = om + theta; + angles->a3 = om + theta; killVector(QC); + mat_free(R); return 1; } /*------------------------------------------------------------------------*/ -int calcTasQH(MATRIX UB, ptasReflection r){ +int calcTasQH(MATRIX UB, tasAngles angles, ptasQEPosition qe){ MATRIX UBINV = NULL, QV = NULL, Q = NULL; double q; + tasReflection r; int i; UBINV = mat_inv(UB); - QV = calcTasUVectorFromAngles(*r); + r.angles = angles; + r.qe = *qe; + QV = calcTasUVectorFromAngles(r); if(UBINV == NULL || QV == NULL){ return UBNOMEMORY; } @@ -380,26 +388,23 @@ int calcTasQH(MATRIX UB, ptasReflection r){ Thereby take into account the physicists magic fudge 2PI factor */ - q = sqrt(r->ki*r->ki + r->kf*r->kf - 2.*r->ki*r->kf*Cosd(r->two_theta)); + q = sqrt(qe->ki*qe->ki + qe->kf*qe->kf - 2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta)); q /= 2. * PI; + qe->qm = q; + for(i = 0; i < 3; i++){ QV[i][0] *= q; } - /* - mat_dump(UB); - mat_dump(UBINV); - mat_dump(QV); - */ Q = mat_mul(UBINV,QV); if(Q == NULL){ mat_free(UBINV); killVector(QV); return UBNOMEMORY; } - r->h = Q[0][0]; - r->k = Q[1][0]; - r->l = Q[2][0]; + qe->qh = Q[0][0]; + qe->qk = Q[1][0]; + qe->ql = Q[2][0]; killVector(QV); killVector(Q); @@ -413,29 +418,20 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe, int status; tasReflection r; - status = maCalcAngles(machine->monochromator,&angles->monochromator, - qe.ki); + status = maCalcTwoTheta(machine->monochromator,qe.ki, + &angles->monochromator_two_theta); if(status != 1){ return status; } - r.h = qe.qh; - r.k = qe.qk; - r.l = qe.ql; - r.ki = qe.ki; - r.kf = qe.kf; status = calcTasQAngles(machine->UB, machine->planeNormal, - machine->ss_sample, &r); + machine->ss_sample, qe,angles); if(status != 1){ return status; } - angles->a3 = r.a3; - angles->sample_two_theta = r.two_theta; - angles->sgu = r.sgu; - angles->sgl = r.sgl; - status = maCalcAngles(machine->analyzer,&angles->analyzer, - qe.kf); + status = maCalcTwoTheta(machine->analyzer,qe.kf,& + angles->analyzer_two_theta); if(status != 1){ return status; } @@ -445,47 +441,140 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe, /*----------------------------------------------------------------------*/ int calcTasQEPosition(ptasMachine machine, tasAngles angles, ptasQEPosition qe){ - int status, retVal = 1; - tasReflection r; - double k; + int status; - status = maCalcK(machine->monochromator,angles.monochromator,&k); - if(status != 1){ - if(status != BADSYNC){ - retVal = BADSYNC; - } else { - return status; - } - } - qe->ki = k; + qe->ki = maCalcK(machine->monochromator,angles.monochromator_two_theta); + qe->kf = maCalcK(machine->analyzer,angles.analyzer_two_theta); - status = maCalcK(machine->analyzer,angles.analyzer,&k); - if(status != 1){ - if(status != BADSYNC){ - retVal = BADSYNC; - } else { - return status; - } - } - qe->kf = k; - - - r.sgu = angles.sgu; - r.sgl = angles.sgl; - r.a3 = angles.a3; - r.two_theta = angles.sample_two_theta; - r.ki = qe->ki; - r.kf = qe->kf; - status = calcTasQH(machine->UB,&r); + status = calcTasQH(machine->UB,angles,qe); if(status != 1){ return status; } - qe->qh = r.h; - qe->qk = r.k; - qe->ql = r.l; - - return retVal; + return 1; } - +/*================== POWDER Implementation ===========================*/ +int calcTasPowderAngles(ptasMachine machine, tasQEPosition qe, + ptasAngles angles){ + double cos2t; + int status; + tasReflection r; + + status = maCalcTwoTheta(machine->monochromator,qe.ki, + &angles->monochromator_two_theta); + if(status != 1){ + return status; + } + + cos2t = (qe.ki*qe.ki + qe.kf*qe.kf - qe.qm*qe.qm)/(2. * ABS(qe.ki) * ABS(qe.kf)); + if(cos2t > 1.){ + return TRIANGLENOTCLOSED; + } + angles->sample_two_theta = machine->ss_sample*Acosd(cos2t); + + + status = maCalcTwoTheta(machine->analyzer,qe.kf,& + angles->analyzer_two_theta); + if(status != 1){ + return status; + } + + return 1; +} +/*---------------------------------------------------------------------*/ +int calcTasPowderPosition(ptasMachine machine, tasAngles angles, + ptasQEPosition qe){ + + int status; + + qe->ki = maCalcK(machine->monochromator,angles.monochromator_two_theta); + qe->kf = maCalcK(machine->analyzer,angles.analyzer_two_theta); + + qe->qm = sqrt(qe->ki*qe->ki + qe->kf*qe->kf - + 2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta)); + + return 1; +} +/*====================== Logic implementation =========================*/ +void setTasPar(ptasQEPosition qe, int tasMode, int tasVar, double value){ + double et; + + assert(tasMode == KICONST || tasMode == KFCONST); + + switch(tasVar){ + case KF: + qe->kf = value; + break; + case EF: + qe->kf = energyToK(value); + break; + case KI: + qe->ki = value; + break; + case EI: + qe->ki = energyToK(value); + break; + case QH: + qe->qh = value; + break; + case QK: + qe->qk = value; + break; + case QL: + qe->ql = value; + break; + case EN: + if(tasMode == KICONST){ + et = KtoEnergy(qe->ki) - value; + qe->kf = energyToK(et); + } else if(tasMode == KFCONST){ + et = KtoEnergy(qe->kf) + value; + qe->ki = energyToK(et); + } else { + assert(0); + } + break; + case QM: + qe->qm = value; + break; + default: + assert(0); + break; + } +} +/*-------------------------------------------------------------------------*/ +double getTasPar(tasQEPosition qe, int tasVar){ + switch(tasVar){ + case EI: + return KtoEnergy(qe.ki); + break; + case KI: + return qe.ki; + break; + case EF: + return KtoEnergy(qe.kf); + break; + case KF: + return qe.kf; + break; + case QH: + return qe.qh; + break; + case QK: + return qe.qk; + break; + case QL: + return qe.ql; + break; + case EN: + return KtoEnergy(qe.ki) - KtoEnergy(qe.kf); + break; + case QM: + return qe.qm; + break; + default: + assert(0); + } +} + diff --git a/tasublib.h b/tasublib.h index c900af25..8a4ab20c 100644 --- a/tasublib.h +++ b/tasublib.h @@ -17,6 +17,64 @@ #define UBNOMEMORY -702 #define TRIANGLENOTCLOSED -703 #define BADRMATRIX -704 +/*========================== defines for tasMode ====================*/ +#define KICONST 1 +#define KFCONST 2 +/*=========================== TAS Variables =========================*/ +#define EI 1 +#define KI 2 +#define QH 3 +#define QK 4 +#define QL 5 +#define EF 6 +#define KF 7 +#define EN 8 +#define QM 9 +/*=========================== data structures =======================*/ +/** + * data structure describing a monochromator or analyzer crystal + */ +typedef struct { + double dd; /* lattice spacing */ + int ss; /* scattering sense */ + double HB1, HB2; /* horizontal curvature parameters */ + double VB1, VB2; /* vertical curvature parameters */ +} maCrystal, *pmaCrystal; +/** + * the machine parameters of a triple axis spectrometer + */ +typedef struct { + maCrystal monochromator, analyzer; + MATRIX UB; + MATRIX planeNormal; + int ss_sample; /* scattering sense sample */ +}tasMachine, *ptasMachine; +/** + * a position in Q - Energy space + */ +typedef struct { + double ki, kf; + double qh,qk,ql; + double qm; +}tasQEPosition, *ptasQEPosition; +/** + * A triple axis angle position + */ +typedef struct { + double monochromator_two_theta; + double a3; + double sample_two_theta; + double sgl; + double sgu; + double analyzer_two_theta; +}tasAngles, *ptasAngles; +/** + * a full triple axis reflection + */ +typedef struct { + tasQEPosition qe; + tasAngles angles; +}tasReflection, *ptasReflection; /*================= Monochromator/Analyzer stuff =====================*/ /** * convert an energy in meV to Ki, Kf type values @@ -32,46 +90,35 @@ double energyToK(double energy); double KtoEnergy(double k); /*----------------------------------------------------------------------*/ /** - * data structure describing a monochromator or analyzer crystal + * calculate two_theta for k + * @param data The crystals parameter + * @param k The input K value to calculate + * @param two_theta The resulting two_theta + * @return 1 on success, a negative error code on failure */ -typedef struct { - double dd; /* lattice spacing */ - int ss; /* scattering sense */ - double HB1, HB2; /* horizontal curvature parameters */ - double VB1, VB2; /* vertical curvature parameters */ -} maCrystal, *pmaCrystal; +int maCalcTwoTheta(maCrystal data, double k, double *two_theta); /** - * data structure for the angles of a mono/ana calculation + * calculate the value for the vertical curvature + * @param data The input crystal parameters + * @param two_theta The tow theta value for which to calculate the curvature. + * @return A new value for the curvature. */ -typedef struct{ - double theta; - double two_theta; - double horizontal_curvature; - double vertical_curvature; -}maAngles, *pmaAngles; -/*-----------------------------------------------------------------------*/ +double maCalcVerticalCurvature(maCrystal data, double two_theta); /** - * calculate the angles for the wavelength or K value k + * calculate the value for the horizontal curvature + * @param data The input crystal parameters + * @param two_theta The tow theta value for which to calculate the curvature. + * @return A new value for the curvature. + */ +double maCalcHorizontalCurvature(maCrystal data, double two_theta); +/** + * calculate the value of the K vector from the angle * @param data The crystals constants - * @param angles output angles - * @param k The wavelength or k value to calculate - * @return 1 on success, a negative error code on failure. + * @param two_theta The two theta read from the motor + * @return The k value calculated from two_theta and the parameters. */ -int maCalcAngles(maCrystal data, pmaAngles angles, double k); -/** - * calculate the value of the K vector from angles - * @param data The crystals constants - * @param angles The current angles - * @param k The output K vector - * @return 1 on success, a negative error code on failure. - */ -int maCalcK(maCrystal data, maAngles angles, double *k); +double maCalcK(maCrystal data, double two_theta); /*======================= reciprocal space =============================*/ -typedef struct { - double h,k,l; - double a3, two_theta, sgu, sgl; - double ki, kf; -}tasReflection, *ptasReflection; /** * calculate a UB from two reflections and the cell. * @param cell The lattice constant of the crystal @@ -97,41 +144,22 @@ MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2); * @param UB The UB matrix to use * @param planeNormal The normal to the scattering plane to use * @param ss The scattering sense at the sample - * @param r The input/output reflection + * @param qe The desired Q Energy position + * @param angles The resulting angles. * @return 1 on success, a negative error code when errors are encountered */ int calcTasQAngles(MATRIX UB, MATRIX planeNormal, - int ss, ptasReflection r); + int ss, tasQEPosition qe, + ptasAngles angles); /** * calculate QH, QK, QL from the angles given * @param UB The UB matrix to use - * @param r The reflection to proecess. The angles and ki, kf have to be set - * to appropriate values before this can work properly. + * @param angles The angles as read from the motors + * @param qe The resulting Q Energy positions * @return 1 on success, a negative error code on failures. */ -int calcTasQH(MATRIX UB, ptasReflection r); +int calcTasQH(MATRIX UB, tasAngles angles, ptasQEPosition qe); /*======================== pulling it together.. =======================*/ -typedef struct { - maCrystal monochromator, analyzer; - MATRIX UB; - MATRIX planeNormal; - int ss_sample; /* scattering sense sample */ - tasReflection r; -}tasMachine, *ptasMachine; -/*---------------------------------------------------------------------*/ -typedef struct { - maAngles monochromator; - double a3; - double sample_two_theta; - double sgl; - double sgu; - maAngles analyzer; -}tasAngles, *ptasAngles; -/*-------------------------------------------------------------------*/ -typedef struct { - double ki, kf; - double qh,qk,ql; -}tasQEPosition, *ptasQEPosition; /** * calculate all the tas target angles for a position in Q-Energy space. * @param machine The machine description @@ -151,4 +179,45 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe, */ int calcTasQEPosition(ptasMachine machine, tasAngles angles, ptasQEPosition qe); +/*======================== POWDER MODE ================================= + Powder mode is driving only QM, A3, SGGU, SGL will not be touched, + only energy and sample two theta will be driven. +========================================================================*/ +/** + * calculate the angles for a specified energy and qm position (in qe). + * @param machine The machine constants of the spectrometer + * @param qe The energy, qm position desired. + * @param angles The angles for this qe position. Please ignore a3, sgu, sgl + * @return 1 on success, a negative error code else + */ +int calcTasPowderAngles(ptasMachine machine, tasQEPosition qe, + ptasAngles angles); +/** + * calculate the current energy qm position from angles. + * @param machine The spectrometer parameters. + * @param angles The angles as read from the motors + * @param qe The resulting qe position + * @return 1 on success, a negative error code on errors + */ +int calcTasPowderPosition(ptasMachine machine, tasAngles angles, + ptasQEPosition qe); +/*======================= TAS Logic =====================================*/ +/** + * set triple axis parameters, thereby taking the tasMode into account + * @param qe The Q Energy variable set to update + * @param tasMode The triple axis mode to apply + * @param tasVar The TAS variable to handle. This MUST be one of the + * defines at the top of this file. + * @param value The value to set for tasPar + */ +void setTasPar(ptasQEPosition qe, int tasMode, int tasVar, double value); +/** + * calculates the value of a TAS parameter from qe. + * @param qe The Q Energy psoition to extract data from + * @parm tasVar The TAS variable to extract. This MUST be one of the + * defines given at the top of this file. + * @return The value of the TAS variable. + */ +double getTasPar(tasQEPosition qe, int tasVar); + #endif