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