- First working version of the triple axis UB matrix code

This commit is contained in:
koennecke
2005-05-13 07:40:57 +00:00
parent d0a535faa3
commit 6145b513f8
16 changed files with 1681 additions and 527 deletions

View File

@ -53,6 +53,7 @@ of the measurement.
parameter iSkip determines the number of lines to skip in the file. This parameter iSkip determines the number of lines to skip in the file. This
feature allows to continue measurement on not fully processed files. feature allows to continue measurement on not fully processed files.
<DT>dataset reopen filename <DT>dataset reopen filename
<DT>dataset reopen 001/trics2005n000051
<DD>Reopens an already existing file set for appending. Only the file root <DD>Reopens an already existing file set for appending. Only the file root
without directory info or endings needs to be given. without directory info or endings needs to be given.
<DT>dataset close <DT>dataset close
@ -93,6 +94,9 @@ This object knows about the following parameters:
max count in scan - 2* min count in scan. max count in scan - 2* min count in scan.
<dt>fastscan <dt>fastscan
<dd>0 or 1: switches fastscan mode. <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 <dt>psd
<dd>0 or 1: switches on PSD mode for measuring with the area detector. Currently this is mapped <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 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>
<p> <p>
Then there are command which allow to configure the table of two theta ranges and 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: commands are supported:
<dl> <dl>
<dt>dataset table list <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: This is accounted for by two switches:
<dl> <dl>
<dt>dataset bi <dt>dataset bi
<dd>switches into bissectiong mode. This is the default. <dd>switches into bissecting mode. This is the default.
<dt>dataset nb <dt>dataset nb
<dd>switches into normal beam mode. <dd>switches into normal beam mode.
</dl> </dl>

View File

@ -49,7 +49,7 @@ static int HKLHalt(void *pData){
static int HKLCheckLimits(void *self, float fVal, char *error, int errLen){ static int HKLCheckLimits(void *self, float fVal, char *error, int errLen){
/* /*
There is no meaningful implementation here. This gets called when starting the motor. 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. at status check time.
*/ */
return 1; return 1;

View File

@ -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\ hklscan.o xytable.o exebuf.o exeman.o ubfour.o ubcalc.o\
circular.o maximize.o sicscron.o scanvar.o tasublib.o\ circular.o maximize.o sicscron.o scanvar.o tasublib.o\
d_sign.o d_mod.o tcldrivable.o stdscan.o diffscan.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 \ hmcontrol.o userscan.o rs232controller.o lomax.o \
fourlib.o motreg.o motreglist.o anticollider.o \ fourlib.o motreg.o motreglist.o anticollider.o \
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \ s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \

View File

@ -846,7 +846,6 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
self->fRefl = fopen(pFile,"r"); self->fRefl = fopen(pFile,"r");
if(!self->fRefl) if(!self->fRefl)
{ {
fclose(self->fRefl);
sprintf(pBueffel,"ERROR: there is no such measurement at %s",fileroot); sprintf(pBueffel,"ERROR: there is no such measurement at %s",fileroot);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; return 0;

2
scan.c
View File

@ -729,7 +729,7 @@ CountEntry CollectCounterData(pScanData self)
self->fPreset = fPreset; self->fPreset = fPreset;
/* do some preprocessing */ /* do some preprocessing */
iRet = PrepareScan(self); iRet = SilentPrepare(self);
if(!iRet) if(!iRet)
{ {
self->WriteHeader = HeaderFunc; self->WriteHeader = HeaderFunc;

View File

@ -285,7 +285,13 @@
} }
sprintf(pFile,"%s%1d.log",pFile, iFile); sprintf(pFile,"%s%1d.log",pFile, iFile);
fLogFile = fopen(pFile,"w"); fLogFile = fopen(pFile,"w");
assert(fLogFile); if(!fLogFile)
{
printf("ERROR: cannot open logfile %s for writing\n",
pFile);
fLogFile = NULL;
return;
}
iLineCount = 0; iLineCount = 0;
} }

View File

@ -1,193 +1,230 @@
banana CountMode timer exe batchpath ./
banana preset 10.000000 exe syspath ./
# Counter counter #---- tasUB module tasub
counter SetPreset 10.000000 tasub mono dd 3.350000
counter SetMode Timer tasub mono hb1 1.000000
# Motor tilt tasub mono hb2 1.000000
tilt sign 1.000000 tasub mono vb1 1.000000
tilt SoftZero 0.000000 tasub mono vb2 1.000000
tilt SoftLowerLim -403.623993 tasub mono ss 1
tilt SoftUpperLim 396.376007 tasub ana dd 3.350000
tilt Fixed -1.000000 tasub ana hb1 1.000000
tilt InterruptMode 0.000000 tasub ana hb2 1.000000
tilt AccessCode 2.000000 tasub ana vb1 1.000000
# Motor chi tasub ana vb2 1.000000
chi sign 1.000000 tasub ana ss 1
chi SoftZero 0.000000 tasub cell 1.000000 1.000000 1.000000 90.000000 90.000000 90.000000
chi SoftLowerLim -20.000000 tasub clear
chi SoftUpperLim 20.000000 tasub const ki
chi Fixed -1.000000 tasub ss 1
chi InterruptMode 0.000000 tasub setub 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000
chi AccessCode 2.000000 tasub setnormal 0.000000 0.000000 0.000000
# Motor ome tasub settarget 0.000000 0.000000 0.000000 0.000000 0.000000
ome sign 1.000000 tasub update
ome SoftZero 0.000000 scaninfo 0,Unknown,1.0,.1
ome SoftLowerLim -180.000000 scaninfo setAccess 0
ome SoftUpperLim 180.000000 polfile UNKNOWN
ome Fixed -1.000000 polfile setAccess 2
ome InterruptMode 0.000000 local UNKNOWN
ome AccessCode 2.000000 local setAccess 2
# Motor atz output UNKNOWN
atz sign 1.000000 output setAccess 2
atz SoftZero 0.000000 lastcommand UNKNOWN
atz SoftLowerLim -3900.000000 lastcommand setAccess 2
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
user Albert von Villigen user Albert von Villigen
user setAccess 2 user setAccess 2
title UNKNOWN title UNKNOWN
title setAccess 2 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

111
stdscan.c
View File

@ -368,6 +368,28 @@ static char *fixExtension(char *filename)
self->fd = NULL; self->fd = NULL;
return 1; 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) int PrepareScan(pScanData self)
{ {
@ -377,7 +399,6 @@ static char *fixExtension(char *filename)
float fVal; float fVal;
char pBueffel[512]; char pBueffel[512];
char pMessage[1024]; char pMessage[1024];
char *pPtr = NULL;
assert(self); assert(self);
assert(self->iNP > 0); assert(self->iNP > 0);
@ -426,21 +447,68 @@ static char *fixExtension(char *filename)
SetCounterPreset((pCounter)self->pCounterData, self->fPreset); SetCounterPreset((pCounter)self->pCounterData, self->fPreset);
self->iCounts = 0; self->iCounts = 0;
/* allocate a new data file */ if(!prepareDataFile(self)){
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; return 0;
} }
snprintf(pBueffel,511,"Writing data file: %s ...",pPtr);
SCWrite(self->pCon,pBueffel,eWarning); return 1;
strcpy(self->pFile,pPtr); }
free(pPtr); /*--------------------------------------------------------------------------*/
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; return 1;
} }
@ -453,7 +521,6 @@ static char *fixExtension(char *filename)
float fVal; float fVal;
char pBueffel[512]; char pBueffel[512];
char pMessage[1024]; char pMessage[1024];
char *pPtr = NULL;
assert(self); assert(self);
assert(self->iNP > 0); assert(self->iNP > 0);
@ -484,21 +551,9 @@ static char *fixExtension(char *filename)
SetCounterPreset((pCounter)self->pCounterData, self->fPreset); SetCounterPreset((pCounter)self->pCounterData, self->fPreset);
self->iCounts = 0; self->iCounts = 0;
/* allocate a new data file */ if(!prepareDataFile(self)){
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; return 0;
} }
snprintf(pBueffel,511,"Writing data file: %s ...",pPtr);
SCWrite(self->pCon,pBueffel,eWarning);
strcpy(self->pFile,pPtr);
free(pPtr);
return 1; return 1;
} }

View File

@ -33,6 +33,10 @@
/** /**
* second version of PrepareScan which does not check scan limits * 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); int NonCheckPrepare(pScanData self);
/** /**
* ScanDrive handles driving to the scan point iPoint. * ScanDrive handles driving to the scan point iPoint.

644
tasdrive.c Normal file
View 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
View 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

416
tasub.c
View File

@ -10,6 +10,7 @@
#include "sics.h" #include "sics.h"
#include "lld.h" #include "lld.h"
#include "tasub.h" #include "tasub.h"
#include "tasdrive.h"
/*------------------- motor indexes in motor data structure ---------*/ /*------------------- motor indexes in motor data structure ---------*/
#define A1 0 #define A1 0
#define A2 1 #define A2 1
@ -43,8 +44,9 @@ static void saveReflections(ptasUB self, char *name, FILE *fd){
while(status == 1){ while(status == 1){
LLDnodeDataTo(self->reflectionList,&r); 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", 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, name, r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta,
KtoEnergy(r.ki), KtoEnergy(r.kf)); r.angles.sgu, r.angles.sgl,
KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf));
status = LLDnodePtr2Next(self->reflectionList); 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 const kf\n",name);
} }
fprintf(fd,"%s ss %d\n", name,self->machine.ss_sample); 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; return 1;
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
@ -139,58 +155,20 @@ static int readTASAngles(ptasUB self, SConnection *pCon,
/* /*
Monochromator Monochromator
*/ */
status = MotorGetSoftPosition(self->motors[A1],pCon,&val);
if(status == 0){
return status;
}
ang->monochromator.theta = val;
status = MotorGetSoftPosition(self->motors[A2],pCon,&val); status = MotorGetSoftPosition(self->motors[A2],pCon,&val);
if(status == 0){ if(status == 0){
return status; return status;
} }
ang->monochromator.two_theta = val; 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;
}
/* /*
Analyzer Analyzer
*/ */
status = MotorGetSoftPosition(self->motors[A5],pCon,&val);
if(status == 0){
return status;
}
ang->analyzer.theta = val;
status = MotorGetSoftPosition(self->motors[A6],pCon,&val); status = MotorGetSoftPosition(self->motors[A6],pCon,&val);
if(status == 0){ if(status == 0){
return status; return status;
} }
ang->analyzer.two_theta = val; 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;
}
/* /*
crystal 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 TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]){ int argc, char *argv[]){
ptasUB pNew = NULL; 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) { if(argc < 2) {
SCWrite(pCon,"ERROR: need name to install tasUB",eError); 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); SCWrite(pCon,"ERROR: duplicate tasUB command not created",eError);
return 0; 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; return 1;
} }
/*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/
@ -304,6 +301,10 @@ static int setCrystalParameters(pmaCrystal crystal, SConnection *pCon,
return 1; return 1;
} }
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
strtolower(argv[2]); strtolower(argv[2]);
if(strcmp(argv[2],"dd") == 0){ if(strcmp(argv[2],"dd") == 0){
crystal->dd = d; crystal->dd = d;
@ -411,6 +412,11 @@ static int tasReadCell(SConnection *pCon, ptasUB self, int argc, char *argv[]){
eError); eError);
return 0; return 0;
} }
if(!SCMatchRights(pCon,usUser)){
return 0;
}
status = Tcl_GetDouble(pTcl,argv[2],&self->cell.a); status = Tcl_GetDouble(pTcl,argv[2],&self->cell.a);
if(status != TCL_OK){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]);
@ -487,7 +493,8 @@ static void listReflections(ptasUB self, SConnection *pCon){
count++; count++;
LLDnodeDataTo(self->reflectionList,&r); 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", 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); Tcl_DStringAppend(&list,line,-1);
status = LLDnodePtr2Next(self->reflectionList); status = LLDnodePtr2Next(self->reflectionList);
} }
@ -513,19 +520,24 @@ static int addReflection(ptasUB self, SicsInterp *pSics,
eError); eError);
return 0; 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){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; 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){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; 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){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
@ -533,66 +545,56 @@ static int addReflection(ptasUB self, SicsInterp *pSics,
} }
if(argc >= 11){ 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){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; return 0;
} }
status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&r.a3); 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[5]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&r.two_theta);
if(status != TCL_OK){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; 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){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; 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){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[8]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[8]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; 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){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[9]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[9]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; return 0;
} }
r.ki = energyToK(r.ki); r.qe.ki = energyToK(r.qe.ki);
status = Tcl_GetDouble(InterpGetTcl(pSics),argv[10],&r.kf); status = Tcl_GetDouble(InterpGetTcl(pSics),argv[10],&r.qe.kf);
if(status != TCL_OK){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[10]); snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[10]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; return 0;
} }
r.kf = energyToK(r.kf); r.qe.kf = energyToK(r.qe.kf);
} else { } else {
if(argc > 5){ if(argc > 5){
SCWrite(pCon, SCWrite(pCon,
"WARNING: not all angles given on command line, using positions instead", "WARNING: not all angles given on command line, using positions instead",
eWarning); eWarning);
} }
status = readTASAngles(self,pCon,&angles); status = readTASAngles(self,pCon,&r.angles);
if(status != 1){ if(status != 1){
return status; return status;
} }
r.a3 = angles.a3; r.qe.ki = maCalcK(self->machine.monochromator,angles.monochromator_two_theta);
r.two_theta = angles.sample_two_theta; r.qe.kf = maCalcK(self->machine.analyzer,angles.analyzer_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);
} }
LLDnodeAppend(self->reflectionList,&r); LLDnodeAppend(self->reflectionList,&r);
Tcl_DStringInit(&list); Tcl_DStringInit(&list);
@ -601,10 +603,12 @@ static int addReflection(ptasUB self, SicsInterp *pSics,
Tcl_DStringAppend(&list,pBueffel,-1); Tcl_DStringAppend(&list,pBueffel,-1);
snprintf(pBueffel,255, snprintf(pBueffel,255,
" %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", " %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); Tcl_DStringAppend(&list,pBueffel,-1);
SCWrite(pCon,Tcl_DStringValue(&list),eValue); SCWrite(pCon,Tcl_DStringValue(&list),eValue);
Tcl_DStringFree(&list); Tcl_DStringFree(&list);
SCparChange(pCon);
return 1; return 1;
} }
/*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/
@ -662,28 +666,30 @@ static void printReflectionDiagnostik(ptasUB self, SConnection *pCon,
Tcl_DStringAppend(&list,line,-1); Tcl_DStringAppend(&list,line,-1);
snprintf(line,255, snprintf(line,255,
"INPUT %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", "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); Tcl_DStringAppend(&list,line,-1);
qe.ki = r.ki; qe.ki = r.qe.ki;
qe.kf = r.kf; qe.kf = r.qe.kf;
qe.qk = r.h; qe.qh = r.qe.qh;
qe.qk = r.k; qe.qk = r.qe.qk;
qe.ql = r.l; qe.ql = r.qe.ql;
calcAllTasAngles(&self->machine,qe,&angles); calcAllTasAngles(&self->machine,qe,&angles);
snprintf(line,255, snprintf(line,255,
"QE->ANG %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", "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, r.qe.qh, r.qe.qk, r.qe.ql,
angles.sgu, angles.sgl, r.ki, r.kf); angles.a3, angles.sample_two_theta,
angles.sgu, angles.sgl, r.qe.ki, r.qe.kf);
Tcl_DStringAppend(&list,line,-1); Tcl_DStringAppend(&list,line,-1);
angles.a3 = r.a3; angles.a3 = r.angles.a3;
angles.sample_two_theta = r.two_theta; angles.sample_two_theta = r.angles.sample_two_theta;
angles.sgu = r.sgu; angles.sgu = r.angles.sgu;
angles.sgl = r.sgl; angles.sgl = r.angles.sgl;
calcTasQEPosition(&self->machine,angles,&qe); calcTasQEPosition(&self->machine,angles,&qe);
snprintf(line,255, snprintf(line,255,
"ANG->QE %6.2f %6.2f %6.2f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n", "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, qe.qh, qe.qk, qe.ql, angles.a3, angles.sample_two_theta,
r.sgu, r.sgl, qe.ki, qe.kf); angles.sgu, angles.sgl, qe.ki, qe.kf);
Tcl_DStringAppend(&list,line,-1); Tcl_DStringAppend(&list,line,-1);
SCWrite(pCon,Tcl_DStringValue(&list),eValue); SCWrite(pCon,Tcl_DStringValue(&list),eValue);
Tcl_DStringFree(&list); Tcl_DStringFree(&list);
@ -714,6 +720,11 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics,
eError); eError);
return 0; return 0;
} }
if(!SCMatchRights(pCon,usUser)){
return 0;
}
status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&idx); status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&idx);
if(status != TCL_OK){ if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]); 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); self->machine.planeNormal = calcPlaneNormal(r1,r2);
listUB(UB,pCon); listUB(UB,pCon);
listDiagnostik(self,pCon); listDiagnostik(self,pCon);
SCparChange(pCon);
return 1; return 1;
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
@ -820,19 +832,240 @@ static int calcRefAngles(ptasUB self, SConnection *pCon,
SCWrite(pCon,"ERROR: Out of memory calculating angles",eError); SCWrite(pCon,"ERROR: Out of memory calculating angles",eError);
return 0; return 0;
break; break;
case BADRMATRIX:
SCWrite(pCon,"ERROR: bad crystallographic parameters or bad UB",eError);
return 0;
break;
case TRIANGLENOTCLOSED: case TRIANGLENOTCLOSED:
SCWrite(pCon,"ERROR: scattering triangle not closed",eError); SCWrite(pCon,"ERROR: scattering triangle not closed",eError);
return 0; return 0;
break; break;
} }
snprintf(pBueffel,255," %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f", snprintf(pBueffel,255," %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f",
angles.monochromator.theta, angles.monochromator.two_theta, angles.monochromator_two_theta,
angles.a3, angles.sample_two_theta, angles.a3, angles.sample_two_theta,
angles.sgl, angles.sgu, angles.sgl, angles.sgu,
angles.analyzer.theta,angles.analyzer.two_theta); angles.analyzer_two_theta);
SCWrite(pCon,pBueffel,eValue); SCWrite(pCon,pBueffel,eValue);
return 1; 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 TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]){ int argc, char *argv[]){
@ -877,6 +1110,14 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
return calcUB(self,pCon,pSics,argc,argv); return calcUB(self,pCon,pSics,argc,argv);
} else if(strcmp(argv[1],"calcref") == 0){ } else if(strcmp(argv[1],"calcref") == 0){
return calcRefAngles(self,pCon,pSics,argc,argv); 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){ } else if(strcmp(argv[1],"const") == 0){
if(argc > 2){ if(argc > 2){
strtolower(argv[2]); strtolower(argv[2]);
@ -919,6 +1160,7 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
return 0; return 0;
} }
self->machine.ss_sample = newSS; self->machine.ss_sample = newSS;
tasUpdate(pCon,self);
SCSendOK(pCon); SCSendOK(pCon);
return 1; return 1;
} else { } else {

15
tasub.h
View File

@ -15,9 +15,6 @@
#include "motor.h" #include "motor.h"
/*------------------- defines for tasMode -----------------------------------*/ /*------------------- defines for tasMode -----------------------------------*/
#define KICONST 1
#define KFCONST 2
/*-----------------------------------------------------------------------------*/
typedef struct{ typedef struct{
pObjectDescriptor pDes; pObjectDescriptor pDes;
tasMachine machine; tasMachine machine;
@ -33,16 +30,6 @@
}tasUB, *ptasUB; }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 ---------------------*/ /*--------------------- the tas virtual motor data structure ---------------------*/
typedef struct { typedef struct {
pObjectDescriptor pDes; pObjectDescriptor pDes;
@ -57,8 +44,6 @@ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif #endif

33
tasub.w
View File

@ -17,9 +17,6 @@ This module handles the calculations typical for a triple axis spectrometer.
A data structure: A data structure:
@d tasubdat @{ @d tasubdat @{
/*------------------- defines for tasMode -----------------------------------*/ /*------------------- defines for tasMode -----------------------------------*/
#define KICONST 1
#define KFCONST 2
/*-----------------------------------------------------------------------------*/
typedef struct{ typedef struct{
pObjectDescriptor pDes; pObjectDescriptor pDes;
tasMachine machine; tasMachine machine;
@ -56,16 +53,6 @@ A data structure:
For the virtual motors, there must be a data structure, too: For the virtual motors, there must be a data structure, too:
@d tasubmotdat @{ @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 ---------------------*/ /*--------------------- the tas virtual motor data structure ---------------------*/
typedef struct { typedef struct {
pObjectDescriptor pDes; pObjectDescriptor pDes;
@ -88,8 +75,6 @@ int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@} @}
@ -114,3 +99,21 @@ int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData,
@<tasubint@> @<tasubint@>
#endif #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
@}

View File

@ -1,13 +1,15 @@
/** /**
* This is a library of functions and data structures for performing * This is a library of functions and data structures for performing
* triple axis spectrometer angle calculations using the UB-matrix * 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 * copyright: see file COPYRIGHT
* *
* Mark Koennecke, April 2005 * Mark Koennecke, April 2005
*/ */
#include <math.h> #include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "trigd.h" #include "trigd.h"
#include "vector.h" #include "vector.h"
#include "tasublib.h" #include "tasublib.h"
@ -30,42 +32,53 @@ double KtoEnergy(double k){
energy = ECONST*k*k; energy = ECONST*k*k;
return energy; 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){ int maCalcTwoTheta(maCrystal data, double k, double *two_theta){
double fd; double fd, theta;
/* fd = k/(2.*data.dd); */ /* fd = k/(2.*data.dd); */
fd = PI/(data.dd*k); fd = PI/(data.dd*k);
if(fd > 1.0) { if(fd > 1.0) {
return ENERGYTOBIG; return ENERGYTOBIG;
} }
angles->theta = Asind(fd)*data.ss; theta = Asind(fd)*data.ss;
angles->two_theta = 2.*angles->theta; *two_theta = 2.*theta;
angles->horizontal_curvature = data.HB1 + data.HB2/Sind(angles->theta);
angles->vertical_curvature = data.VB1 + data.VB2/Sind(angles->theta);
return 1; return 1;
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
int maCalcK(maCrystal data, maAngles angles, double *k){ double maCalcVerticalCurvature(maCrystal data, double two_theta){
return calcCurvature(data.VB1,data.VB2, two_theta/2.);
*k = ABS(data.dd * Sind(angles.two_theta/2));
*k = PI / *k;
if(ABS(angles.two_theta/2. - angles.theta) > .1) {
return BADSYNC;
} }
return 1; /*-------------------------------------------------------------------*/
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 k;
} }
/*==================== reciprocal space ==============================*/ /*==================== reciprocal space ==============================*/
static MATRIX tasReflectionToHC(tasReflection r, MATRIX B){ static MATRIX tasReflectionToHC(tasQEPosition r, MATRIX B){
MATRIX h = NULL, hc = NULL; MATRIX h = NULL, hc = NULL;
h = makeVector(); h = makeVector();
if(h == NULL){ if(h == NULL){
return NULL; return NULL;
} }
vectorSet(h,0,r.h); vectorSet(h,0,r.qh);
vectorSet(h,1,r.k); vectorSet(h,1,r.qk);
vectorSet(h,2,r.l); vectorSet(h,2,r.ql);
hc = mat_mul(B,h); hc = mat_mul(B,h);
killVector(h); killVector(h);
@ -135,9 +148,9 @@ static MATRIX uFromAngles(double om, double sgu, double sgl){
static MATRIX calcTasUVectorFromAngles(tasReflection r){ static MATRIX calcTasUVectorFromAngles(tasReflection r){
double theta, om; double theta, om;
theta = calcTheta(r.ki,r.kf,r.two_theta); theta = calcTheta(r.qe.ki,r.qe.kf,r.angles.sample_two_theta);
om = r.a3 - theta; om = r.angles.a3 - theta;
return uFromAngles(om,r.sgu, r.sgl); return uFromAngles(om,r.angles.sgu, r.angles.sgl);
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2){ MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2){
@ -170,8 +183,8 @@ MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1,
*errorCode = status; *errorCode = status;
return NULL; return NULL;
} }
h1 = tasReflectionToHC(r1,B); h1 = tasReflectionToHC(r1.qe,B);
h2 = tasReflectionToHC(r2,B); h2 = tasReflectionToHC(r2.qe,B);
if(h1 == NULL || h2 == NULL){ if(h1 == NULL || h2 == NULL){
*errorCode = UBNOMEMORY; *errorCode = UBNOMEMORY;
return NULL; return NULL;
@ -265,34 +278,33 @@ static MATRIX buildTVMatrix(MATRIX U1V, MATRIX U2V){
return T; return T;
} }
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
static MATRIX tasReflectionToQC(ptasReflection r, MATRIX UB){ static MATRIX tasReflectionToQC(tasQEPosition r, MATRIX UB){
MATRIX Q, QC; MATRIX Q, QC;
Q = makeVector(); Q = makeVector();
if(Q == NULL){ if(Q == NULL){
return NULL; return NULL;
} }
vectorSet(Q,0,r->h); vectorSet(Q,0,r.qh);
vectorSet(Q,1,r->k); vectorSet(Q,1,r.qk);
vectorSet(Q,2,r->l); vectorSet(Q,2,r.ql);
QC = mat_mul(UB,Q); QC = mat_mul(UB,Q);
killVector(Q); killVector(Q);
return QC; return QC;
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal, static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal,
ptasReflection r){ tasQEPosition qe){
MATRIX U3V, U1V, U2V, TV, TVINV; MATRIX U1V, U2V, TV, TVINV, M;
U3V = planeNormal;
U1V = tasReflectionToQC(r,UB); U1V = tasReflectionToQC(qe,UB);
if(U1V == NULL){ if(U1V == NULL){
return NULL; return NULL;
} }
normalizeVector(U1V); normalizeVector(U1V);
U2V = vectorCrossProduct(U3V,U1V); U2V = vectorCrossProduct(planeNormal,U1V);
if(U2V == NULL){ if(U2V == NULL){
killVector(U1V); killVector(U1V);
return NULL; return NULL;
@ -305,73 +317,69 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal,
return NULL; return NULL;
} }
TVINV = mat_inv(TV); TVINV = mat_inv(TV);
if(TVINV == NULL){
killVector(U1V); killVector(U1V);
killVector(U2V); killVector(U2V);
mat_free(TV); mat_free(TV);
return NULL;
}
killVector(U1V);
killVector(U2V);
mat_free(TVINV);
return TVINV; 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; 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){ if(R == NULL){
return UBNOMEMORY; return UBNOMEMORY;
} }
om = Acosd(R[0][0]/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]);
r->sgl = Acosd(sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0])); if(ABS(sq) < .00001){
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 {
return BADRMATRIX; return BADRMATRIX;
} }
*/ 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);
QC = tasReflectionToQC(r,UB);
if(QC == NULL){ if(QC == NULL){
return UBNOMEMORY; return UBNOMEMORY;
} }
q = vectorLength(QC); q = vectorLength(QC);
q = 2.*PI*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.){ if(cos2t > 1.){
return TRIANGLENOTCLOSED; 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); killVector(QC);
mat_free(R);
return 1; return 1;
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
int calcTasQH(MATRIX UB, ptasReflection r){ int calcTasQH(MATRIX UB, tasAngles angles, ptasQEPosition qe){
MATRIX UBINV = NULL, QV = NULL, Q = NULL; MATRIX UBINV = NULL, QV = NULL, Q = NULL;
double q; double q;
tasReflection r;
int i; int i;
UBINV = mat_inv(UB); UBINV = mat_inv(UB);
QV = calcTasUVectorFromAngles(*r); r.angles = angles;
r.qe = *qe;
QV = calcTasUVectorFromAngles(r);
if(UBINV == NULL || QV == NULL){ if(UBINV == NULL || QV == NULL){
return UBNOMEMORY; return UBNOMEMORY;
} }
@ -380,26 +388,23 @@ int calcTasQH(MATRIX UB, ptasReflection r){
Thereby take into account the physicists magic fudge Thereby take into account the physicists magic fudge
2PI factor 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; q /= 2. * PI;
qe->qm = q;
for(i = 0; i < 3; i++){ for(i = 0; i < 3; i++){
QV[i][0] *= q; QV[i][0] *= q;
} }
/*
mat_dump(UB);
mat_dump(UBINV);
mat_dump(QV);
*/
Q = mat_mul(UBINV,QV); Q = mat_mul(UBINV,QV);
if(Q == NULL){ if(Q == NULL){
mat_free(UBINV); mat_free(UBINV);
killVector(QV); killVector(QV);
return UBNOMEMORY; return UBNOMEMORY;
} }
r->h = Q[0][0]; qe->qh = Q[0][0];
r->k = Q[1][0]; qe->qk = Q[1][0];
r->l = Q[2][0]; qe->ql = Q[2][0];
killVector(QV); killVector(QV);
killVector(Q); killVector(Q);
@ -413,29 +418,20 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe,
int status; int status;
tasReflection r; tasReflection r;
status = maCalcAngles(machine->monochromator,&angles->monochromator, status = maCalcTwoTheta(machine->monochromator,qe.ki,
qe.ki); &angles->monochromator_two_theta);
if(status != 1){ if(status != 1){
return status; 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, status = calcTasQAngles(machine->UB, machine->planeNormal,
machine->ss_sample, &r); machine->ss_sample, qe,angles);
if(status != 1){ if(status != 1){
return status; 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, status = maCalcTwoTheta(machine->analyzer,qe.kf,&
qe.kf); angles->analyzer_two_theta);
if(status != 1){ if(status != 1){
return status; return status;
} }
@ -445,47 +441,140 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe,
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
int calcTasQEPosition(ptasMachine machine, tasAngles angles, int calcTasQEPosition(ptasMachine machine, tasAngles angles,
ptasQEPosition qe){ ptasQEPosition qe){
int status, retVal = 1; int status;
qe->ki = maCalcK(machine->monochromator,angles.monochromator_two_theta);
qe->kf = maCalcK(machine->analyzer,angles.analyzer_two_theta);
status = calcTasQH(machine->UB,angles,qe);
if(status != 1){
return status;
}
return 1;
}
/*================== POWDER Implementation ===========================*/
int calcTasPowderAngles(ptasMachine machine, tasQEPosition qe,
ptasAngles angles){
double cos2t;
int status;
tasReflection r; tasReflection r;
double k;
status = maCalcK(machine->monochromator,angles.monochromator,&k); status = maCalcTwoTheta(machine->monochromator,qe.ki,
&angles->monochromator_two_theta);
if(status != 1){ if(status != 1){
if(status != BADSYNC){ return status;
retVal = BADSYNC; }
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 { } else {
return status; assert(0);
}
break;
case QM:
qe->qm = value;
break;
default:
assert(0);
break;
} }
} }
qe->ki = k; /*-------------------------------------------------------------------------*/
double getTasPar(tasQEPosition qe, int tasVar){
status = maCalcK(machine->analyzer,angles.analyzer,&k); switch(tasVar){
if(status != 1){ case EI:
if(status != BADSYNC){ return KtoEnergy(qe.ki);
retVal = BADSYNC; break;
} else { case KI:
return status; 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);
} }
} }
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);
if(status != 1){
return status;
}
qe->qh = r.h;
qe->qk = r.k;
qe->ql = r.l;
return retVal;
}

View File

@ -17,6 +17,64 @@
#define UBNOMEMORY -702 #define UBNOMEMORY -702
#define TRIANGLENOTCLOSED -703 #define TRIANGLENOTCLOSED -703
#define BADRMATRIX -704 #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 =====================*/ /*================= Monochromator/Analyzer stuff =====================*/
/** /**
* convert an energy in meV to Ki, Kf type values * convert an energy in meV to Ki, Kf type values
@ -32,46 +90,35 @@ double energyToK(double energy);
double KtoEnergy(double k); 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 { int maCalcTwoTheta(maCrystal data, double k, double *two_theta);
double dd; /* lattice spacing */
int ss; /* scattering sense */
double HB1, HB2; /* horizontal curvature parameters */
double VB1, VB2; /* vertical curvature parameters */
} maCrystal, *pmaCrystal;
/** /**
* 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 maCalcVerticalCurvature(maCrystal data, double two_theta);
double theta;
double two_theta;
double horizontal_curvature;
double vertical_curvature;
}maAngles, *pmaAngles;
/*-----------------------------------------------------------------------*/
/** /**
* 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 data The crystals constants
* @param angles output angles * @param two_theta The two theta read from the motor
* @param k The wavelength or k value to calculate * @return The k value calculated from two_theta and the parameters.
* @return 1 on success, a negative error code on failure.
*/ */
int maCalcAngles(maCrystal data, pmaAngles angles, double k); double maCalcK(maCrystal data, double two_theta);
/**
* 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);
/*======================= reciprocal space =============================*/ /*======================= 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. * calculate a UB from two reflections and the cell.
* @param cell The lattice constant of the crystal * @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 UB The UB matrix to use
* @param planeNormal The normal to the scattering plane to use * @param planeNormal The normal to the scattering plane to use
* @param ss The scattering sense at the sample * @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 * @return 1 on success, a negative error code when errors are encountered
*/ */
int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int calcTasQAngles(MATRIX UB, MATRIX planeNormal,
int ss, ptasReflection r); int ss, tasQEPosition qe,
ptasAngles angles);
/** /**
* calculate QH, QK, QL from the angles given * calculate QH, QK, QL from the angles given
* @param UB The UB matrix to use * @param UB The UB matrix to use
* @param r The reflection to proecess. The angles and ki, kf have to be set * @param angles The angles as read from the motors
* to appropriate values before this can work properly. * @param qe The resulting Q Energy positions
* @return 1 on success, a negative error code on failures. * @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.. =======================*/ /*======================== 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. * calculate all the tas target angles for a position in Q-Energy space.
* @param machine The machine description * @param machine The machine description
@ -151,4 +179,45 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe,
*/ */
int calcTasQEPosition(ptasMachine machine, tasAngles angles, int calcTasQEPosition(ptasMachine machine, tasAngles angles,
ptasQEPosition qe); 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 #endif