- First working version of the triple axis UB matrix code
This commit is contained in:
@ -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.
|
||||
<DT>dataset reopen filename
|
||||
<DT>dataset reopen 001/trics2005n000051
|
||||
<DD>Reopens an already existing file set for appending. Only the file root
|
||||
without directory info or endings needs to be given.
|
||||
<DT>dataset close
|
||||
@ -93,6 +94,9 @@ This object knows about the following parameters:
|
||||
max count in scan - 2* min count in scan.
|
||||
<dt>fastscan
|
||||
<dd>0 or 1: switches fastscan mode.
|
||||
<dt>psimode
|
||||
<dd>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.
|
||||
<dt>psd
|
||||
<dd>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:
|
||||
</p>
|
||||
<p>
|
||||
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:
|
||||
<dl>
|
||||
<dt>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:
|
||||
<dl>
|
||||
<dt>dataset bi
|
||||
<dd>switches into bissectiong mode. This is the default.
|
||||
<dd>switches into bissecting mode. This is the default.
|
||||
<dt>dataset nb
|
||||
<dd>switches into normal beam mode.
|
||||
</dl>
|
||||
|
2
hklmot.c
2
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;
|
||||
|
2
make_gen
2
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) \
|
||||
|
1
mesure.c
1
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;
|
||||
|
2
scan.c
2
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
415
sicsstat.tcl
415
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
|
||||
|
115
stdscan.c
115
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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
644
tasdrive.c
Normal file
644
tasdrive.c
Normal file
@ -0,0 +1,644 @@
|
||||
/*---------------------------------------------------------------------
|
||||
SICS interface to the triple axis drivable motors.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, May 2005
|
||||
--------------------------------------------------------------------*/
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
17
tasdrive.h
Normal file
17
tasdrive.h
Normal file
@ -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
|
418
tasub.c
418
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 {
|
||||
|
15
tasub.h
15
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
|
||||
|
35
tasub.w
35
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,
|
||||
/*--------------------------------------------------------------------*/
|
||||
@<tasubint@>
|
||||
#endif
|
||||
@}
|
||||
@}
|
||||
@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
|
||||
@}
|
||||
|
335
tasublib.c
335
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 <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
187
tasublib.h
187
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
|
||||
|
Reference in New Issue
Block a user