- First commit of the new UB based TAS calculation. A milestone has been
reached: it handles one test case correctly back and forth - Fixed oscillation code - Added a feature for switching off automatic updates in nxupdate Autoamtic updates cause problems when scanning...
This commit is contained in:
12
cell.c
12
cell.c
@ -17,7 +17,17 @@
|
||||
#define PI (3.1415926536) /* pi */
|
||||
#endif
|
||||
#define TWOPI (2*PI) /* 2*pi */
|
||||
|
||||
/*****************************************************************************
|
||||
* default value for a cell
|
||||
****************************************************************************/
|
||||
void defaultCell(plattice cell){
|
||||
cell->a = 1.;
|
||||
cell->b = 1.;
|
||||
cell->c = 1.;
|
||||
cell->alpha = 90.;
|
||||
cell->beta = 90.;
|
||||
cell->gamma = 90.;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* Transform direct lattice to reciprocal lattice.
|
||||
*******************************************************************************/
|
||||
|
5
cell.h
5
cell.h
@ -22,6 +22,11 @@
|
||||
double a,b,c;
|
||||
double alpha, beta, gamma;
|
||||
}lattice, *plattice;
|
||||
/**
|
||||
* defaultCell assigns defualt values to cell parameters
|
||||
* @param cell The lattice to assign default too
|
||||
*/
|
||||
void defaultCell(plattice cell);
|
||||
/**
|
||||
* conversion from a direct lattice to the recipcrocal one.
|
||||
* @param direct The input direct cell parameters.
|
||||
|
@ -657,7 +657,7 @@
|
||||
{
|
||||
self->pCountInt->TransferData(self,pCon);
|
||||
}
|
||||
if( (iNum < 0) || (iNum >= self->pDriv->iNoOfMonitors) )
|
||||
if( (iNum < 0) || (iNum > self->pDriv->iNoOfMonitors) )
|
||||
{
|
||||
return -1L;
|
||||
}
|
||||
|
5
lld.c
5
lld.c
@ -595,6 +595,11 @@ int LLDnodePtr2First( int List )
|
||||
|
||||
ListControl[ List ].current = ListControl[ List ].first->next ;
|
||||
|
||||
if(ListControl[List].first->next == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NULL != ListControl[ List ].first->next->next ;
|
||||
}
|
||||
|
||||
|
4
make_gen
4
make_gen
@ -20,9 +20,9 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
|
||||
tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \
|
||||
mesure.o uubuffer.o commandlog.o udpquieck.o fourtable.o\
|
||||
rmtrail.o help.o nxupdate.o confvirtualmot.o vector.o\
|
||||
simchop.o choco.o chadapter.o trim.o scaldate.o \
|
||||
simchop.o choco.o chadapter.o trim.o scaldate.o tasub.o\
|
||||
hklscan.o xytable.o exebuf.o exeman.o ubfour.o ubcalc.o\
|
||||
circular.o maximize.o sicscron.o scanvar.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 \
|
||||
hmcontrol.o userscan.o rs232controller.o lomax.o \
|
||||
|
32
nxupdate.c
32
nxupdate.c
@ -24,6 +24,10 @@ static int UpdateTask(void *pData){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(self->onOff == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
update when intervall reached or when end
|
||||
*/
|
||||
@ -48,6 +52,11 @@ static int CountCallback(int iEvent, void *pEventData, void *pUser){
|
||||
|
||||
self = (pNXupdate)pUser;
|
||||
pCon = (SConnection *)pEventData;
|
||||
|
||||
if(self->onOff == 0){
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(iEvent == COUNTSTART){
|
||||
assert(pCon);
|
||||
assert(self);
|
||||
@ -114,6 +123,9 @@ static void printUpdateList(SConnection *pCon, pNXupdate self, char *name){
|
||||
snprintf(pBueffel,255,"%s.updateIntervall = %d",name,
|
||||
self->updateIntervall);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
snprintf(pBueffel,255,"%s.onOff = %d",name,
|
||||
self->onOff);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int printUpdateParameters(SConnection *pCon, pNXupdate self,
|
||||
@ -139,6 +151,11 @@ static int printUpdateParameters(SConnection *pCon, pNXupdate self,
|
||||
self->updateIntervall);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else if(strcmp(param,"onoff") == 0){
|
||||
snprintf(pBueffel,255,"%s.onoff = %d",name,
|
||||
self->onOff);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBueffel,255,"ERROR: parameter %s not known", param);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
@ -182,6 +199,20 @@ static int configureUpdate(SConnection *pCon, pNXupdate self,
|
||||
self->updateIntervall = newUpdate;
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else if(strcmp(param,"onoff") == 0){
|
||||
if(Tcl_GetInt(InterpGetTcl(pServ->pSics),value,&newUpdate) != TCL_OK){
|
||||
snprintf(pBueffel,255,
|
||||
"ERROR: %s not an int, cannot set onoff", value);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
if(newUpdate >= 1){
|
||||
self->onOff = 1;
|
||||
} else {
|
||||
self->onOff = 0;
|
||||
}
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBueffel,255,"ERROR: parameter %s not known", param);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
@ -272,6 +303,7 @@ int UpdateFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
self->updateScript = strdup("UNDEFINED");
|
||||
self->linkScript = strdup("UNDEFINED");
|
||||
self->updateIntervall = 1200; /* 20 min */
|
||||
self->onOff = 1;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -20,6 +20,7 @@
|
||||
time_t nextUpdate;
|
||||
int iEnd;
|
||||
SConnection *pCon;
|
||||
int onOff;
|
||||
}NXupdate, *pNXupdate;
|
||||
|
||||
|
||||
|
@ -33,6 +33,7 @@ object:
|
||||
time_t nextUpdate;
|
||||
int iEnd;
|
||||
SConnection *pCon;
|
||||
int onOff;
|
||||
}NXupdate, *pNXupdate;
|
||||
@}
|
||||
The fields:
|
||||
@ -49,6 +50,7 @@ the NeXus file.
|
||||
\item[iEnd] A flag which becomes 1 when counting ends and makes the
|
||||
UpdateTask to stop.
|
||||
\item[pCon] The connection for which we are updating.
|
||||
\item[onOff] A switch to switch automatic updates on or off.
|
||||
\end{description}
|
||||
|
||||
This object has no public C interface. There is only ainterpreter
|
||||
|
4
ofac.c
4
ofac.c
@ -110,6 +110,7 @@
|
||||
#include "diffscan.h"
|
||||
#include "hklmot.h"
|
||||
#include "ubcalc.h"
|
||||
#include "tasub.h"
|
||||
/*----------------------- Server options creation -------------------------*/
|
||||
static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
@ -297,6 +298,8 @@
|
||||
HKLMotInstall,NULL,NULL);
|
||||
AddCommand(pInter,"MakeUBCalc",
|
||||
MakeUBCalc,NULL,NULL);
|
||||
AddCommand(pInter,"MakeTasUB",
|
||||
TasUBFactory,NULL,NULL);
|
||||
|
||||
|
||||
/*
|
||||
@ -360,6 +363,7 @@
|
||||
RemoveCommand(pSics,"MakeDiffScan");
|
||||
RemoveCommand(pSics,"MakeHKLMot");
|
||||
RemoveCommand(pSics,"MakeUBCalc");
|
||||
RemoveCommand(pSics,"MakeTasUB");
|
||||
|
||||
/*
|
||||
remove site specific installation commands
|
||||
|
96
oscillate.c
96
oscillate.c
@ -11,23 +11,52 @@
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "task.h"
|
||||
#include "commandlog.h"
|
||||
#include "oscillate.h"
|
||||
|
||||
#define ABS(x) (x < 0 ? -(x) : (x))
|
||||
|
||||
/*================== real work =========================================*/
|
||||
static void StopOscillation(pOscillator self){
|
||||
assert(self != NULL);
|
||||
if(self->taskID > 0){
|
||||
self->pMot->pDriver->Halt(self->pMot->pDriver);
|
||||
self->stopFlag = 1;
|
||||
MotorSetPar(self->pMot,self->pCon,"accesscode",(float)self->oldRights);
|
||||
self->taskID = -1;
|
||||
}
|
||||
MotorSetPar(self->pMot,self->pCon,"accesscode",usUser);
|
||||
if(self->debug > 0){
|
||||
WriteToCommandLog("oscillator>> ","Stopping");
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static float getNextPos(pOscillator self){
|
||||
float pos;
|
||||
if(self->nextTargetFlag == 1){
|
||||
pos = self->upperLimit;
|
||||
self->nextTargetFlag = 0;
|
||||
} else {
|
||||
pos = self->lowerLimit;
|
||||
self->nextTargetFlag = 1;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static float getCurrentTarget(pOscillator self){
|
||||
float pos;
|
||||
if(self->nextTargetFlag == 1){
|
||||
pos = self->lowerLimit;
|
||||
} else {
|
||||
pos = self->upperLimit;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int OscillationTask(void *data){
|
||||
pOscillator self = (pOscillator)data;
|
||||
int status, code, errStatus;
|
||||
char error[256];
|
||||
float pos;
|
||||
char error[256], message[132];
|
||||
float pos, curPos;
|
||||
|
||||
|
||||
assert(self);
|
||||
@ -40,39 +69,43 @@ static int OscillationTask(void *data){
|
||||
case HWFault:
|
||||
case HWPosFault:
|
||||
self->pMot->pDriver->GetError(self->pMot->pDriver,&code,error,255);
|
||||
SCWrite(self->pCon,error,eError);
|
||||
if(self->nextTargetFlag == 1){
|
||||
pos = self->lowerLimit;
|
||||
} else {
|
||||
pos = self->upperLimit;
|
||||
}
|
||||
WriteToCommandLog("oscillator>> ",error);
|
||||
pos = getCurrentTarget(self);
|
||||
errStatus = self->pMot->pDriver->TryAndFixIt(self->pMot->pDriver,code,pos);
|
||||
self->errorCount++;
|
||||
if(errStatus == MOTFAIL){
|
||||
/*
|
||||
try driving the other way on a serious error
|
||||
*/
|
||||
if(self->nextTargetFlag == 1){
|
||||
pos = self->upperLimit;
|
||||
self->nextTargetFlag = 0;
|
||||
} else {
|
||||
pos = self->lowerLimit;
|
||||
self->nextTargetFlag = 1;
|
||||
pos = getNextPos(self);
|
||||
status = MotorRun(self->pMot,self->pCon,pos);
|
||||
if(self->debug > 0){
|
||||
snprintf(message,131,"Started oscillation to %f, ret code = %d",
|
||||
pos,status);
|
||||
WriteToCommandLog("oscillator>>",message);
|
||||
}
|
||||
MotorRun(self->pMot,self->pCon,pos);
|
||||
}
|
||||
break;
|
||||
case HWWarn:
|
||||
MotorGetSoftPosition(self->pMot,self->pCon,&curPos);
|
||||
pos = getCurrentTarget(self);
|
||||
if(ABS(curPos - pos) < .5){
|
||||
status = MotorRun(self->pMot,self->pCon,getNextPos(self));
|
||||
}
|
||||
break;
|
||||
case HWBusy:
|
||||
break;
|
||||
case HWIdle:
|
||||
if(self->nextTargetFlag == 1){
|
||||
pos = self->upperLimit;
|
||||
self->nextTargetFlag = 0;
|
||||
} else {
|
||||
pos = self->lowerLimit;
|
||||
self->nextTargetFlag = 1;
|
||||
pos = getNextPos(self);
|
||||
status = MotorRun(self->pMot,self->pCon,pos);
|
||||
if(status == OKOK){
|
||||
self->pMot->pDrivInt->iErrorCount = 0;
|
||||
}
|
||||
if(self->debug > 0){
|
||||
snprintf(message,131,"Started oscillation to %f, ret code = %d",
|
||||
pos,status);
|
||||
WriteToCommandLog("oscillator>>",message);
|
||||
}
|
||||
MotorRun(self->pMot,self->pCon,pos);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -85,16 +118,16 @@ static int StartOscillation(pOscillator self, SConnection *pCon){
|
||||
assert(self);
|
||||
|
||||
if(self->taskID > 0){
|
||||
SCWrite(pCon,"ERROR: oscillation already running",eError);
|
||||
return 1;
|
||||
SCWrite(pCon,"WARNING: oscillation already running",eWarning);
|
||||
SCWrite(pCon,"WARNING: restarting .. ",eWarning);
|
||||
StopOscillation(self);
|
||||
SicsWait(2);
|
||||
}
|
||||
|
||||
MotorGetPar(self->pMot,"softlowerlim",&self->lowerLimit);
|
||||
self->lowerLimit += .5;
|
||||
MotorGetPar(self->pMot,"softupperlim",&self->upperLimit);
|
||||
self->upperLimit -= .5;
|
||||
MotorGetPar(self->pMot,"accesscode",&fval);
|
||||
self->oldRights = (int)fval;
|
||||
MotorSetPar(self->pMot,self->pCon,"accesscode",(float)usInternal);
|
||||
self->nextTargetFlag = 0;
|
||||
self->errorCount = 0;
|
||||
@ -221,6 +254,15 @@ int OscillatorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
"see commandlog for details");
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"debug") == 0) {
|
||||
if(argc >= 3){
|
||||
self->debug = atoi(argv[2]);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
snprintf(pBueffel,255,"%s.debug = %d", argv[0],self->debug);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"status") == 0) {
|
||||
if(self->taskID > 0){
|
||||
snprintf(pBueffel,255,"Oscillation running, %d errors so far, %s",
|
||||
|
@ -22,6 +22,7 @@ typedef struct {
|
||||
int stopFlag;
|
||||
SConnection *pCon;
|
||||
int errorCount;
|
||||
int debug;
|
||||
} Oscillator, *pOscillator;
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
@ -17,7 +17,6 @@ required:
|
||||
typedef struct {
|
||||
pObjectDescriptor pDes;
|
||||
pMotor pMot;
|
||||
int oldRights;
|
||||
float upperLimit;
|
||||
float lowerLimit;
|
||||
int nextTargetFlag;
|
||||
@ -25,14 +24,13 @@ typedef struct {
|
||||
int stopFlag;
|
||||
SConnection *pCon;
|
||||
int errorCount;
|
||||
int debug;
|
||||
} Oscillator, *pOscillator;
|
||||
@}
|
||||
The fields:
|
||||
\begin{description}
|
||||
\item[pDes] The SICS object descriptor.
|
||||
\item[pMot] The motor controlled through this module.
|
||||
\item[oldRights] The old user rights code for the motor. Must be saved
|
||||
in order to restore when stopping the oscillation.
|
||||
\item[upperLimit] The uper limit of the oscillation.
|
||||
\item[lowerLimit] the lower limits of the oscillation.
|
||||
\item[nextTargetFlag] A flag which decides which limit is the next one
|
||||
@ -41,6 +39,7 @@ to drive to.
|
||||
\item[stopFlag] A flag to signal the control task to stop.
|
||||
\item[pCon] A dummy connection object to use for writing. Is
|
||||
configured to write to log files.
|
||||
\item[debug] A debug flag causing more messages to be printed.
|
||||
\end{description}
|
||||
|
||||
The interface to this module is just the interpreter interface. The
|
||||
|
937
tasub.c
Normal file
937
tasub.c
Normal file
@ -0,0 +1,937 @@
|
||||
/*----------------------------------------------------------------------
|
||||
SICS interface to the triple axis spectrometer calculation
|
||||
module.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, April-May 2005
|
||||
----------------------------------------------------------------------*/
|
||||
#include <assert.h>
|
||||
#include "sics.h"
|
||||
#include "lld.h"
|
||||
#include "tasub.h"
|
||||
/*------------------- motor indexes in motor data structure ---------*/
|
||||
#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
|
||||
/*----------------- data structure management code -------------------*/
|
||||
static void saveCrystal(char *objName, char *name, pmaCrystal crystal,
|
||||
FILE *fd){
|
||||
fprintf(fd,"%s %s dd %f\n",objName, name, crystal->dd);
|
||||
fprintf(fd,"%s %s hb1 %f\n",objName, name, crystal->HB1);
|
||||
fprintf(fd,"%s %s hb2 %f\n",objName, name, crystal->HB2);
|
||||
fprintf(fd,"%s %s vb1 %f\n",objName, name, crystal->VB1);
|
||||
fprintf(fd,"%s %s vb2 %f\n",objName, name, crystal->VB2);
|
||||
fprintf(fd,"%s %s ss %d\n",objName, name, crystal->ss);
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void saveReflections(ptasUB self, char *name, FILE *fd){
|
||||
tasReflection r;
|
||||
int status;
|
||||
|
||||
status = LLDnodePtr2First(self->reflectionList);
|
||||
fprintf(fd,"%s clear\n",name);
|
||||
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));
|
||||
status = LLDnodePtr2Next(self->reflectionList);
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int tasUBSave(void *pData, char *name, FILE *fd){
|
||||
ptasUB self = (ptasUB)pData;
|
||||
|
||||
if(self == NULL){
|
||||
return 0;
|
||||
}
|
||||
fprintf(fd,"#---- tasUB module %s\n", name);
|
||||
saveCrystal(name,"mono",&self->machine.monochromator,fd);
|
||||
saveCrystal(name,"ana",&self->machine.analyzer,fd);
|
||||
fprintf(fd,"%s cell %f %f %f %f %f %f\n", name, self->cell.a,
|
||||
self->cell.b, self->cell.c, self->cell.alpha,
|
||||
self->cell.beta, self->cell.gamma);
|
||||
saveReflections(self,name,fd);
|
||||
if(self->tasMode == KICONST){
|
||||
fprintf(fd,"%s const ki\n",name);
|
||||
} else {
|
||||
fprintf(fd,"%s const kf\n",name);
|
||||
}
|
||||
fprintf(fd,"%s ss %d\n", name,self->machine.ss_sample);
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void defaultMonochromator(pmaCrystal mono){
|
||||
mono->dd = 3.35;
|
||||
mono->ss = 1;
|
||||
mono->HB1 = 1.;
|
||||
mono->HB2 = 1.;
|
||||
mono->VB1 = 1.;
|
||||
mono->VB2 = 1.;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static ptasUB MakeTasUB(){
|
||||
ptasUB pNew = NULL;
|
||||
|
||||
pNew = (ptasUB)malloc(sizeof(tasUB));
|
||||
if(pNew == NULL){
|
||||
return NULL;
|
||||
}
|
||||
memset(pNew,0,sizeof(tasUB));
|
||||
|
||||
pNew->pDes = CreateDescriptor("TAS-UB");
|
||||
pNew->machine.UB = mat_creat(3,3,UNIT_MATRIX);
|
||||
pNew->machine.planeNormal = mat_creat(3,1,ZERO_MATRIX);
|
||||
pNew->reflectionList = LLDcreate(sizeof(tasReflection));
|
||||
if(!pNew->pDes || !pNew->machine.UB || pNew->reflectionList < 0 ||
|
||||
pNew->machine.planeNormal == NULL){
|
||||
free(pNew);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pNew->pDes->SaveStatus = tasUBSave;
|
||||
pNew->machine.ss_sample = 1;
|
||||
defaultMonochromator(&pNew->machine.monochromator);
|
||||
defaultMonochromator(&pNew->machine.analyzer);
|
||||
defaultCell(&pNew->cell);
|
||||
pNew->tasMode = KICONST;
|
||||
pNew->targetEn = .0;
|
||||
pNew->actualEn = .0;
|
||||
pNew->mustRecalculate = 1;
|
||||
|
||||
return pNew;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static void KillTasUB(void *pData){
|
||||
ptasUB self = (ptasUB)pData;
|
||||
|
||||
if(self == NULL){
|
||||
return;
|
||||
}
|
||||
LLDdelete(self->reflectionList);
|
||||
if(self->pDes != NULL){
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
if(self->machine.UB != NULL){
|
||||
mat_free(self->machine.UB);
|
||||
}
|
||||
if(self->machine.planeNormal != NULL){
|
||||
mat_free(self->machine.planeNormal);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*===================== computation section =========================*/
|
||||
static int readTASAngles(ptasUB self, SConnection *pCon,
|
||||
ptasAngles ang){
|
||||
int status;
|
||||
float val;
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
/*==================== interpreter interface section =================*/
|
||||
static int testMotor(ptasUB pNew, SConnection *pCon, char *name, int idx){
|
||||
char pBueffel[132];
|
||||
|
||||
if(pNew->motors[idx] == NULL){
|
||||
snprintf(pBueffel,131,"ERROR: required motor %s NOT found",name);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
int TasUBFactory(SConnection *pCon,SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
ptasUB pNew = NULL;
|
||||
int status = 0;
|
||||
|
||||
if(argc < 2) {
|
||||
SCWrite(pCon,"ERROR: need name to install tasUB",eError);
|
||||
return 0;
|
||||
}
|
||||
pNew = MakeTasUB();
|
||||
if(pNew == NULL){
|
||||
SCWrite(pCon,"ERROR: out of memory creating tasUB",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
assign motors
|
||||
*/
|
||||
pNew->motors[0] = FindMotor(pSics,"a1");
|
||||
pNew->motors[1] = FindMotor(pSics,"a2");
|
||||
pNew->motors[2] = FindMotor(pSics,"mcv");
|
||||
pNew->motors[3] = FindMotor(pSics,"mch");
|
||||
pNew->motors[4] = FindMotor(pSics,"a3");
|
||||
pNew->motors[5] = FindMotor(pSics,"a4");
|
||||
pNew->motors[6] = FindMotor(pSics,"sgu");
|
||||
pNew->motors[7] = FindMotor(pSics,"sgl");
|
||||
pNew->motors[8] = FindMotor(pSics,"a5");
|
||||
pNew->motors[9] = FindMotor(pSics,"a6");
|
||||
pNew->motors[10] = FindMotor(pSics,"acv");
|
||||
pNew->motors[11] = FindMotor(pSics,"ach");
|
||||
|
||||
/*
|
||||
curvature motors may be missing, anything else is a serious problem
|
||||
*/
|
||||
status += testMotor(pNew, pCon,"a1",A1);
|
||||
status += testMotor(pNew, pCon,"a2",A2);
|
||||
status += testMotor(pNew, pCon,"a3",A3);
|
||||
status += testMotor(pNew, pCon,"a4",A4);
|
||||
status += testMotor(pNew, pCon,"sgu",SGU);
|
||||
status += testMotor(pNew, pCon,"sgl",SGL);
|
||||
status += testMotor(pNew, pCon,"a5",A5);
|
||||
status += testMotor(pNew, pCon,"a6",A6);
|
||||
if(status != 8){
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = AddCommand(pSics,argv[1],
|
||||
TasUBWrapper,
|
||||
KillTasUB,
|
||||
pNew);
|
||||
if(status != 1){
|
||||
SCWrite(pCon,"ERROR: duplicate tasUB command not created",eError);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
TODO: install all the virtual motors
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int setCrystalParameters(pmaCrystal crystal, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
int status;
|
||||
double d;
|
||||
char pBueffel[132];
|
||||
|
||||
status = Tcl_GetDouble(InterpGetTcl(pServ->pSics),argv[3],&d);
|
||||
if(status != TCL_OK){
|
||||
snprintf(pBueffel,131,"ERROR: failed to convert %s to number",
|
||||
argv[3]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
strtolower(argv[2]);
|
||||
if(strcmp(argv[2],"dd") == 0){
|
||||
crystal->dd = d;
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"ss") == 0){
|
||||
if(d > .0){
|
||||
crystal->ss = 1;
|
||||
} else {
|
||||
crystal->ss = -1;
|
||||
}
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"hb1") == 0){
|
||||
crystal->HB1 = d;
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"hb2") == 0){
|
||||
crystal->HB2 = d;
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"vb1") == 0){
|
||||
crystal->VB1 = d;
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"vb2") == 0){
|
||||
crystal->VB2 = d;
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBueffel,131,"ERROR: crystal parameter %s not known",
|
||||
argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int getCrystalParameters(pmaCrystal crystal, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
char pBueffel[132];
|
||||
|
||||
strtolower(argv[2]);
|
||||
if(strcmp(argv[2],"dd") == 0){
|
||||
snprintf(pBueffel,131,"%s.%s.dd = %f",argv[0],argv[1],crystal->dd);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"hb1") == 0){
|
||||
snprintf(pBueffel,131,"%s.%s.hb1 = %f",argv[0],argv[1],crystal->HB1);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"hb2") == 0){
|
||||
snprintf(pBueffel,131,"%s.%s.hb2 = %f",argv[0],argv[1],crystal->HB2);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"vb1") == 0){
|
||||
snprintf(pBueffel,131,"%s.%s.vb1 = %f",argv[0],argv[1],crystal->VB1);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"vb2") == 0){
|
||||
snprintf(pBueffel,131,"%s.%s.vb2 = %f",argv[0],argv[1],crystal->VB1);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}else if(strcmp(argv[2],"ss") == 0){
|
||||
snprintf(pBueffel,131,"%s.%s.ss = %d",argv[0],argv[1],crystal->ss);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}else {
|
||||
snprintf(pBueffel,131,"ERROR: crystal parameter %s not known",
|
||||
argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static int handleCrystalCommands(pmaCrystal crystal, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
char pBueffel[132];
|
||||
|
||||
if(argc < 3){
|
||||
snprintf(pBueffel,131,"ERROR: insufficent number of arguments to %s %s",
|
||||
argv[0],argv[1]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
if(argc > 3) {
|
||||
return setCrystalParameters(crystal,pCon,argc,argv);
|
||||
} else {
|
||||
return getCrystalParameters(crystal,pCon,argc,argv);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int tasReadCell(SConnection *pCon, ptasUB self, int argc, char *argv[]){
|
||||
int status;
|
||||
Tcl_Interp *pTcl = InterpGetTcl(pServ->pSics);
|
||||
char pBueffel[256];
|
||||
|
||||
if(argc < 8){
|
||||
SCWrite(pCon,"ERROR: insufficient number of arguments to tasub cell",
|
||||
eError);
|
||||
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]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetDouble(pTcl,argv[3],&self->cell.b);
|
||||
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(pTcl,argv[4],&self->cell.c);
|
||||
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(pTcl,argv[5],&self->cell.alpha);
|
||||
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(pTcl,argv[6],&self->cell.beta);
|
||||
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(pTcl,argv[7],&self->cell.gamma);
|
||||
if(status != TCL_OK){
|
||||
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
SCparChange(pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static void tasListCell(SConnection *pCon, char *name, lattice direct){
|
||||
char pBueffel[255];
|
||||
|
||||
snprintf(pBueffel,255,"%s.cell = %f %f %f %f %f %f",
|
||||
name,direct.a, direct.b,direct.c,
|
||||
direct.alpha,direct.beta,direct.gamma);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void clearReflections(ptasUB self){
|
||||
int status;
|
||||
|
||||
status = LLDnodePtr2First(self->reflectionList);
|
||||
while(status != 0){
|
||||
LLDnodeDelete(self->reflectionList);
|
||||
status = LLDnodePtr2Next(self->reflectionList);
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void listReflections(ptasUB self, SConnection *pCon){
|
||||
tasReflection r;
|
||||
int status;
|
||||
int count = 0;
|
||||
char line[256];
|
||||
Tcl_DString list;
|
||||
|
||||
Tcl_DStringInit(&list);
|
||||
snprintf(line,255,
|
||||
" NO QH QK QL A3 A4 SGU SGL KI KF\n");
|
||||
Tcl_DStringAppend(&list,line,-1);
|
||||
status = LLDnodePtr2First(self->reflectionList);
|
||||
while(status == 1){
|
||||
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);
|
||||
Tcl_DStringAppend(&list,line,-1);
|
||||
status = LLDnodePtr2Next(self->reflectionList);
|
||||
}
|
||||
if(count == 0){
|
||||
SCWrite(pCon,"Reflection list is empty",eValue);
|
||||
} else {
|
||||
SCWrite(pCon,Tcl_DStringValue(&list),eValue);
|
||||
}
|
||||
Tcl_DStringFree(&list);
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int addReflection(ptasUB self, SicsInterp *pSics,
|
||||
SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
tasReflection r;
|
||||
int status;
|
||||
char pBueffel[256];
|
||||
tasAngles angles;
|
||||
Tcl_DString list;
|
||||
|
||||
if(argc < 5){
|
||||
SCWrite(pCon,"ERROR: need at least miller indices to add reflection",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&r.h);
|
||||
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);
|
||||
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);
|
||||
if(status != TCL_OK){
|
||||
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(argc >= 11){
|
||||
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[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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
} else {
|
||||
if(argc > 5){
|
||||
SCWrite(pCon,
|
||||
"WARNING: not all angles given on command line, using positions instead",
|
||||
eWarning);
|
||||
}
|
||||
status = readTASAngles(self,pCon,&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);
|
||||
}
|
||||
LLDnodeAppend(self->reflectionList,&r);
|
||||
Tcl_DStringInit(&list);
|
||||
snprintf(pBueffel,255,
|
||||
" QH QK QL A3 A4 SGU SGL KI KF\n");
|
||||
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);
|
||||
Tcl_DStringAppend(&list,pBueffel,-1);
|
||||
SCWrite(pCon,Tcl_DStringValue(&list),eValue);
|
||||
Tcl_DStringFree(&list);
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int findReflection(int list, int idx, ptasReflection r){
|
||||
int count = 0;
|
||||
int status;
|
||||
|
||||
status = LLDnodePtr2First(list);
|
||||
while(status == 1){
|
||||
if(count == idx){
|
||||
LLDnodeDataTo(list,r);
|
||||
return 1;
|
||||
}
|
||||
status = LLDnodePtr2Next(list);
|
||||
count++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void listUB(MATRIX UB, SConnection *pCon){
|
||||
Tcl_DString list;
|
||||
char pBueffel[255];
|
||||
int i;
|
||||
|
||||
|
||||
Tcl_DStringInit(&list);
|
||||
if(UB == NULL){
|
||||
Tcl_DStringAppend(&list,"NO UB",-1);
|
||||
} else {
|
||||
Tcl_DStringAppend(&list,"UB = ", -1);
|
||||
snprintf(pBueffel,255,"%f %f %f\n", UB[0][0],
|
||||
UB[0][1],UB[0][2]);
|
||||
Tcl_DStringAppend(&list,pBueffel,-1);
|
||||
for(i = 1; i < 3; i++){
|
||||
snprintf(pBueffel,255," %f %f %f\n", UB[i][0],
|
||||
UB[i][1],UB[i][2]);
|
||||
Tcl_DStringAppend(&list,pBueffel,-1);
|
||||
}
|
||||
}
|
||||
SCWrite(pCon,Tcl_DStringValue(&list),eValue);
|
||||
Tcl_DStringFree(&list);
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static void printReflectionDiagnostik(ptasUB self, SConnection *pCon,
|
||||
tasReflection r){
|
||||
tasReflection r2;
|
||||
Tcl_DString list;
|
||||
char line[256];
|
||||
tasQEPosition qe;
|
||||
tasAngles angles;
|
||||
|
||||
Tcl_DStringInit(&list);
|
||||
snprintf(line,255,
|
||||
"METHOD QH QK QL A3 A4 SGU SGL KI KF\n");
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
Tcl_DStringAppend(&list,line,-1);
|
||||
angles.a3 = r.a3;
|
||||
angles.sample_two_theta = r.two_theta;
|
||||
angles.sgu = r.sgu;
|
||||
angles.sgl = r.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);
|
||||
Tcl_DStringAppend(&list,line,-1);
|
||||
SCWrite(pCon,Tcl_DStringValue(&list),eValue);
|
||||
Tcl_DStringFree(&list);
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void listDiagnostik(ptasUB self, SConnection *pCon){
|
||||
tasReflection r;
|
||||
int status;
|
||||
|
||||
status = LLDnodePtr2First(self->reflectionList);
|
||||
while(status == 1){
|
||||
LLDnodeDataTo(self->reflectionList,&r);
|
||||
printReflectionDiagnostik(self,pCon,r);
|
||||
status = LLDnodePtr2Next(self->reflectionList);
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics,
|
||||
int argc, char *argv[]){
|
||||
int idx, status;
|
||||
tasReflection r1, r2;
|
||||
char pBueffel[256];
|
||||
MATRIX UB = NULL;
|
||||
|
||||
if(argc < 4){
|
||||
SCWrite(pCon,
|
||||
"ERROR: not enough arguments for UB calculation, need index of two reflections",
|
||||
eError);
|
||||
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]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
status = findReflection(self->reflectionList, idx-1,&r1);
|
||||
if(status != 1){
|
||||
snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetInt(InterpGetTcl(pSics),argv[3],&idx);
|
||||
if(status != TCL_OK){
|
||||
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
status = findReflection(self->reflectionList, idx-1,&r2);
|
||||
if(status != 1){
|
||||
snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UB = calcTasUBFromTwoReflections(self->cell,r1,r2,&status);
|
||||
if(UB == NULL){
|
||||
switch(status){
|
||||
case UBNOMEMORY:
|
||||
SCWrite(pCon,"ERROR: out of memory calculating UB matrix",eError);
|
||||
break;
|
||||
case REC_NO_VOLUME:
|
||||
SCWrite(pCon,"ERROR: bad cell constants, no volume",eError);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(self->machine.UB != NULL){
|
||||
mat_free(self->machine.UB);
|
||||
}
|
||||
if(self->machine.planeNormal != NULL){
|
||||
mat_free(self->machine.planeNormal);
|
||||
}
|
||||
self->machine.UB = UB;
|
||||
self->machine.planeNormal = calcPlaneNormal(r1,r2);
|
||||
listUB(UB,pCon);
|
||||
listDiagnostik(self,pCon);
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static int calcRefAngles(ptasUB self, SConnection *pCon,
|
||||
SicsInterp *pSics,
|
||||
int argc, char *argv[]){
|
||||
tasQEPosition q;
|
||||
tasAngles angles;
|
||||
char pBueffel[256];
|
||||
int status;
|
||||
|
||||
if(argc < 7){
|
||||
SCWrite(pCon,"ERROR: need Qh, Qk, Ql, EI, EF for calculation",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&q.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],&q.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],&q.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],&q.ki);
|
||||
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],&q.kf);
|
||||
if(status != TCL_OK){
|
||||
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
q.ki = energyToK(q.ki);
|
||||
q.kf = energyToK(q.kf);
|
||||
|
||||
status = calcAllTasAngles(&self->machine,q,&angles);
|
||||
switch(status){
|
||||
case ENERGYTOBIG:
|
||||
SCWrite(pCon,"ERROR: energy to big",eError);
|
||||
return 0;
|
||||
break;
|
||||
case UBNOMEMORY:
|
||||
SCWrite(pCon,"ERROR: Out of memory calculating angles",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,
|
||||
angles.a3, angles.sample_two_theta,
|
||||
angles.sgl, angles.sgu,
|
||||
angles.analyzer.theta,angles.analyzer.two_theta);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
ptasUB self = NULL;
|
||||
char pBueffel[131];
|
||||
int status, newSS;
|
||||
|
||||
self = (ptasUB)pData;
|
||||
assert(self != NULL);
|
||||
|
||||
if(argc < 2){
|
||||
SCWrite(pCon,"ERROR: insufficient arguments to tasUB",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strtolower(argv[1]);
|
||||
if(strcmp(argv[1],"mono") == 0){
|
||||
return handleCrystalCommands(&self->machine.monochromator,pCon,argc,argv);
|
||||
} else if(strcmp(argv[1],"ana") == 0){
|
||||
return handleCrystalCommands(&self->machine.analyzer,pCon,argc,argv);
|
||||
}else if(strcmp(argv[1],"cell") == 0){
|
||||
if(argc > 2){
|
||||
return tasReadCell(pCon,self,argc,argv);
|
||||
} else {
|
||||
tasListCell(pCon,argv[0],self->cell);
|
||||
return 1;
|
||||
}
|
||||
} else if(strcmp(argv[1],"clear") == 0){
|
||||
clearReflections(self);
|
||||
clearReflections(self);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"listref") == 0){
|
||||
listReflections(self,pCon);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"addref") == 0){
|
||||
return addReflection(self,pSics,pCon,argc,argv);
|
||||
} else if(strcmp(argv[1],"listub") == 0){
|
||||
listUB(self->machine.UB,pCon);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"makeub") == 0){
|
||||
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],"const") == 0){
|
||||
if(argc > 2){
|
||||
strtolower(argv[2]);
|
||||
if(!SCMatchRights(pCon,usUser)){
|
||||
return 0;
|
||||
}
|
||||
if(strcmp(argv[2],"ki") == 0){
|
||||
self->tasMode = KICONST;
|
||||
} else if(strcmp(argv[2],"kf") == 0){
|
||||
self->tasMode = KFCONST;
|
||||
} else {
|
||||
SCWrite(pCon,"ERROR: unknown triple axis mode, accepted are ki, kf",eError);
|
||||
return 0;
|
||||
}
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
if(self->tasMode == KICONST){
|
||||
snprintf(pBueffel,131,"%s.const = ki",argv[0]);
|
||||
} else {
|
||||
snprintf(pBueffel,131,"%s.const = kf",argv[0]);
|
||||
}
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
} else if(strcmp(argv[1],"ss") == 0){
|
||||
if(argc > 2){
|
||||
strtolower(argv[2]);
|
||||
if(!SCMatchRights(pCon,usUser)){
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&newSS);
|
||||
if(status != TCL_OK){
|
||||
SCWrite(pCon,"ERROR: failed to convert argument to number",eError);
|
||||
return 0;
|
||||
}
|
||||
if(newSS != 1 && newSS != -1){
|
||||
SCWrite(pCon,"ERROR: invalid value for scattering sense, only 1, -1 allowed",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
self->machine.ss_sample = newSS;
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBueffel,131,"%s.ss = %d",argv[0],self->machine.ss_sample);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
snprintf(pBueffel,131,"ERROR: subcommand %s to %s not defined",argv[1],
|
||||
argv[0]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
64
tasub.h
Normal file
64
tasub.h
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
SICS interface to the triple axis spectrometer calculation
|
||||
module.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, April-May 2005
|
||||
----------------------------------------------------------------------*/
|
||||
#ifndef TASUB
|
||||
#define TASUB
|
||||
#include <stdio.h>
|
||||
#include "tasublib.h"
|
||||
#include "cell.h"
|
||||
#include "motor.h"
|
||||
|
||||
/*------------------- defines for tasMode -----------------------------------*/
|
||||
#define KICONST 1
|
||||
#define KFCONST 2
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
typedef struct{
|
||||
pObjectDescriptor pDes;
|
||||
tasMachine machine;
|
||||
int reflectionList;
|
||||
lattice cell;
|
||||
tasQEPosition target;
|
||||
tasQEPosition current;
|
||||
int tasMode;
|
||||
double targetEn, actualEn;
|
||||
int mustRecalculate;
|
||||
int mustDrive;
|
||||
pMotor motors[12];
|
||||
}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;
|
||||
pIDrivable pDriv;
|
||||
ptasUB math;
|
||||
int code;
|
||||
}tasMot, *ptasMot;
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
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
|
116
tasub.w
Normal file
116
tasub.w
Normal file
@ -0,0 +1,116 @@
|
||||
\subsection{Triple Axis Spectrometer UB Matrix Calculations}
|
||||
This module handles the calculations typical for a triple axis spectrometer.
|
||||
This is the calculation in Q energy space. The algorithm useid is based on
|
||||
a UB matrix calculus as described by Mark Lumsden. This uses the goniometer
|
||||
tilt angles, sgu and sgl, to position the reflection. For more information,
|
||||
see the pdf file holding M. Lumsden's text. The actual calculation has been
|
||||
put into a library, tasublib.h and tasublib.c. This describes the interface to
|
||||
the SICS interpreter. This module caters for:
|
||||
\begin{itemize}
|
||||
\item UB matrix calculations
|
||||
\item Angle calculations
|
||||
\item The triple axis modes and logic
|
||||
\item Introduces the QE variables as virtual motors into SICS
|
||||
\end{itemize}
|
||||
|
||||
|
||||
A data structure:
|
||||
@d tasubdat @{
|
||||
/*------------------- defines for tasMode -----------------------------------*/
|
||||
#define KICONST 1
|
||||
#define KFCONST 2
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
typedef struct{
|
||||
pObjectDescriptor pDes;
|
||||
tasMachine machine;
|
||||
int reflectionList;
|
||||
lattice cell;
|
||||
tasQEPosition target;
|
||||
tasQEPosition current;
|
||||
int tasMode;
|
||||
double targetEn, actualEn;
|
||||
int mustRecalculate;
|
||||
int mustDrive;
|
||||
pMotor motors[12];
|
||||
}tasUB, *ptasUB;
|
||||
@}
|
||||
\begin{description}
|
||||
\item[pDes] The traditional object descriptor
|
||||
\item[machine] The machine parameters: monochromator d spacing, scattering sense,
|
||||
UB and the like.
|
||||
\item[reflectionList] A list of reflections.
|
||||
\item[cell] The cell constants.
|
||||
\item[target] The Q energy target position
|
||||
\item[current] The actual Q energy position as calculated from angles.
|
||||
\item[tasMode] The mode: constant KI or constant KF
|
||||
\item[ptargetEn] The target energy transfer.
|
||||
\item[actualEn] The actual energy transfer as calcluated from angles.
|
||||
\item[mustRecalculate] A flag indicatin that the current Q energy psoition has to be
|
||||
recalculated.
|
||||
\item[mustDrive] A flag indicating that one of the values has changed and that we need
|
||||
to drive motors to get in sync again.
|
||||
\item[motors] The TAS motors: A1, A2, MCV (vertical curvature), MCH (horizontal curvature),
|
||||
A3, A4, SGU, SGL, A5, A6, ACV, ACH. The curvature motors may be NULL at
|
||||
runtime.
|
||||
\end{description}
|
||||
|
||||
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;
|
||||
pIDrivable pDriv;
|
||||
ptasUB math;
|
||||
int code;
|
||||
}tasMot, *ptasMot;
|
||||
@}
|
||||
\begin{description}
|
||||
\item[pDes] The traditional SICS object descriptor.
|
||||
\item[pDriv] The drivable interface.
|
||||
\item[math] The tasUB module which does the hard work.
|
||||
\item[code] The type code: one of the defines from EI to QM given above.
|
||||
\end{description}
|
||||
|
||||
In terms of an interface, there is only the interpreter interface, and of
|
||||
course the virtual motors within SICS:
|
||||
@d tasubint @{
|
||||
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[]);
|
||||
|
||||
@}
|
||||
|
||||
@o tasub.h @{
|
||||
/*----------------------------------------------------------------------
|
||||
SICS interface to the triple axis spectrometer calculation
|
||||
module.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, April-May 2005
|
||||
----------------------------------------------------------------------*/
|
||||
#ifndef TASUB
|
||||
#define TASUB
|
||||
#include <stdio.h>
|
||||
#include "tasublib.h"
|
||||
#include "cell.h"
|
||||
#include "motor.h"
|
||||
@<tasubdat@>
|
||||
@<tasubmotdat@>
|
||||
/*--------------------------------------------------------------------*/
|
||||
@<tasubint@>
|
||||
#endif
|
||||
@}
|
491
tasublib.c
Normal file
491
tasublib.c
Normal file
@ -0,0 +1,491 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, April 2005
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "trigd.h"
|
||||
#include "vector.h"
|
||||
#include "tasublib.h"
|
||||
|
||||
#define ABS(x) (x < 0 ? -(x) : (x))
|
||||
#define PI 3.141592653589793
|
||||
#define ECONST 2.072
|
||||
#define DEGREE_RAD (PI/180.0) /* Radians per degree */
|
||||
/*============== monochromator/analyzer stuff =========================*/
|
||||
double energyToK(double energy){
|
||||
double K;
|
||||
|
||||
K = sqrt(energy/ECONST);
|
||||
return K;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
double KtoEnergy(double k){
|
||||
double energy;
|
||||
|
||||
energy = ECONST*k*k;
|
||||
return energy;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
int maCalcAngles(maCrystal data, pmaAngles angles, double k){
|
||||
double fd;
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*==================== reciprocal space ==============================*/
|
||||
static MATRIX tasReflectionToHC(tasReflection 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);
|
||||
|
||||
hc = mat_mul(B,h);
|
||||
killVector(h);
|
||||
return hc;
|
||||
}
|
||||
/*------------------------------------------------------------------
|
||||
a quadrant dependent tangens
|
||||
------------------------------------------------------------------*/
|
||||
static double rtan(double y, double x){
|
||||
double val;
|
||||
|
||||
if( (x == 0.) && (y == 0.) ) {
|
||||
return .0;
|
||||
}
|
||||
if( x == 0.) {
|
||||
if(y < 0.){
|
||||
return -PI/2.;
|
||||
} else {
|
||||
return PI/2.;
|
||||
}
|
||||
}
|
||||
if(ABS(y) < ABS(x)) {
|
||||
val = atan(ABS(y/x));
|
||||
if(x < 0.) {
|
||||
val = PI - val;
|
||||
}
|
||||
if(y < 0.){
|
||||
val = -val;
|
||||
}
|
||||
return val;
|
||||
} else {
|
||||
val = PI/2. - atan(ABS(x/y));
|
||||
if(x < 0.) {
|
||||
val = PI - val;
|
||||
}
|
||||
if( y < 0.) {
|
||||
val = - val;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
/*---------------------------------------------------------------*/
|
||||
static double calcTheta(double ki, double kf, double two_theta){
|
||||
/**
|
||||
* |ki| - |kf|cos(two_theta)
|
||||
* tan(theta) = --------------------------
|
||||
* |kf|sin(two_theta)
|
||||
*/
|
||||
return rtan(ABS(ki) - ABS(kf)*Cosd(two_theta),
|
||||
ABS(kf)*Sind(two_theta))/DEGREE_RAD;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static MATRIX uFromAngles(double om, double sgu, double sgl){
|
||||
MATRIX u;
|
||||
|
||||
u = makeVector();
|
||||
if(u == NULL){
|
||||
return NULL;
|
||||
}
|
||||
vectorSet(u,0,-Cosd(sgl)*Cosd(om));
|
||||
vectorSet(u,1,Cosd(sgu)*Sind(om) - Sind(sgu)*Sind(sgl)*Cosd(om));
|
||||
vectorSet(u,2,-Sind(sgu)*Sind(om) - Cosd(sgu)*Sind(sgl)*Cosd(om));
|
||||
|
||||
return u;
|
||||
}
|
||||
/*---------------------------------------------------------------*/
|
||||
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);
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2){
|
||||
MATRIX u1 = NULL, u2 = NULL, planeNormal = NULL;
|
||||
|
||||
u1 = calcTasUVectorFromAngles(r1);
|
||||
u2 = calcTasUVectorFromAngles(r2);
|
||||
if(u1 != NULL && u2 != NULL){
|
||||
return vectorCrossProduct(u1,u2);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1,
|
||||
tasReflection r2, int *errorCode){
|
||||
MATRIX B, HT, UT, U, UB, HTT ;
|
||||
MATRIX u1, u2, h1, h2, planeNormal;
|
||||
double ud[3];
|
||||
int status;
|
||||
|
||||
*errorCode = 1;
|
||||
|
||||
/*
|
||||
calculate the B matrix and the HT matrix
|
||||
*/
|
||||
B = mat_creat(3,3,ZERO_MATRIX);
|
||||
status = calculateBMatrix(cell,B);
|
||||
if(status < 0){
|
||||
*errorCode = status;
|
||||
return NULL;
|
||||
}
|
||||
h1 = tasReflectionToHC(r1,B);
|
||||
h2 = tasReflectionToHC(r2,B);
|
||||
if(h1 == NULL || h2 == NULL){
|
||||
*errorCode = UBNOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
HT = matFromTwoVectors(h1,h2);
|
||||
if(HT == NULL){
|
||||
*errorCode = UBNOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
calculate U vectors and UT matrix
|
||||
*/
|
||||
u1 = calcTasUVectorFromAngles(r1);
|
||||
u2 = calcTasUVectorFromAngles(r2);
|
||||
if(u1 == NULL || u2 == NULL){
|
||||
*errorCode = UBNOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
UT = matFromTwoVectors(u1,u2);
|
||||
if(UT == NULL){
|
||||
*errorCode = UBNOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
debugging output
|
||||
printf("B-matrix\n");
|
||||
mat_dump(B);
|
||||
printf("HT-matrix\n");
|
||||
mat_dump(HT);
|
||||
printf("UT-matrix\n");
|
||||
mat_dump(UT);
|
||||
*/
|
||||
|
||||
/*
|
||||
UT = U * HT
|
||||
*/
|
||||
HTT = mat_tran(HT);
|
||||
if(HTT == NULL){
|
||||
*errorCode = UBNOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
U = mat_mul(UT,HTT);
|
||||
if(U == NULL){
|
||||
*errorCode = UBNOMEMORY;
|
||||
return NULL;
|
||||
}
|
||||
UB = mat_mul(U,B);
|
||||
if(UB == NULL){
|
||||
*errorCode = UBNOMEMORY;
|
||||
}
|
||||
|
||||
/*
|
||||
clean up
|
||||
*/
|
||||
killVector(h1);
|
||||
killVector(h2);
|
||||
mat_free(HT);
|
||||
mat_free(HTT);
|
||||
|
||||
killVector(u1);
|
||||
killVector(u2);
|
||||
mat_free(UT);
|
||||
|
||||
mat_free(U);
|
||||
mat_free(B);
|
||||
|
||||
return UB;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
static MATRIX buildTVMatrix(MATRIX U1V, MATRIX U2V){
|
||||
MATRIX T, T3V;
|
||||
int i;
|
||||
|
||||
T3V = vectorCrossProduct(U1V,U2V);
|
||||
if(T3V == NULL){
|
||||
return NULL;
|
||||
}
|
||||
T = mat_creat(3,3,ZERO_MATRIX);
|
||||
if(T == NULL){
|
||||
killVector(T3V);
|
||||
return NULL;
|
||||
}
|
||||
for(i = 0; i < 3; i++){
|
||||
T[i][0] = U1V[i][0];
|
||||
T[i][1] = U2V[i][0];
|
||||
T[i][2] = T3V[i][0];
|
||||
}
|
||||
killVector(T3V);
|
||||
return T;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
static MATRIX tasReflectionToQC(ptasReflection 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);
|
||||
QC = mat_mul(UB,Q);
|
||||
killVector(Q);
|
||||
return QC;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal,
|
||||
ptasReflection r){
|
||||
MATRIX U3V, U1V, U2V, TV, TVINV;
|
||||
|
||||
U3V = planeNormal;
|
||||
|
||||
U1V = tasReflectionToQC(r,UB);
|
||||
if(U1V == NULL){
|
||||
return NULL;
|
||||
}
|
||||
normalizeVector(U1V);
|
||||
|
||||
U2V = vectorCrossProduct(U3V,U1V);
|
||||
if(U2V == NULL){
|
||||
killVector(U1V);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TV = buildTVMatrix(U1V,U2V);
|
||||
if(TV == NULL){
|
||||
killVector(U1V);
|
||||
killVector(U2V);
|
||||
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);
|
||||
|
||||
return TVINV;
|
||||
}
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int ss, ptasReflection r){
|
||||
MATRIX R, QC;
|
||||
double om, q, theta, cos2t, tmp;
|
||||
|
||||
R = buildRMatrix(UB, planeNormal, r);
|
||||
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 {
|
||||
return BADRMATRIX;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
QC = tasReflectionToQC(r,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));
|
||||
if(cos2t > 1.){
|
||||
return TRIANGLENOTCLOSED;
|
||||
}
|
||||
r->two_theta = ss*Acosd(cos2t);
|
||||
|
||||
theta = calcTheta(r->ki, r->kf,r->two_theta);
|
||||
|
||||
r->a3 = om + theta;
|
||||
|
||||
killVector(QC);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
int calcTasQH(MATRIX UB, ptasReflection r){
|
||||
MATRIX UBINV = NULL, QV = NULL, Q = NULL;
|
||||
double q;
|
||||
int i;
|
||||
|
||||
UBINV = mat_inv(UB);
|
||||
QV = calcTasUVectorFromAngles(*r);
|
||||
if(UBINV == NULL || QV == NULL){
|
||||
return UBNOMEMORY;
|
||||
}
|
||||
/*
|
||||
normalize the QV vector to be the length of the Q vector
|
||||
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 /= 2. * PI;
|
||||
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];
|
||||
|
||||
killVector(QV);
|
||||
killVector(Q);
|
||||
mat_free(UBINV);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
int calcAllTasAngles(ptasMachine machine, tasQEPosition qe,
|
||||
ptasAngles angles){
|
||||
int status;
|
||||
tasReflection r;
|
||||
|
||||
status = maCalcAngles(machine->monochromator,&angles->monochromator,
|
||||
qe.ki);
|
||||
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);
|
||||
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);
|
||||
if(status != 1){
|
||||
return status;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int calcTasQEPosition(ptasMachine machine, tasAngles angles,
|
||||
ptasQEPosition qe){
|
||||
int status, retVal = 1;
|
||||
tasReflection r;
|
||||
double k;
|
||||
|
||||
status = maCalcK(machine->monochromator,angles.monochromator,&k);
|
||||
if(status != 1){
|
||||
if(status != BADSYNC){
|
||||
retVal = BADSYNC;
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
qe->ki = k;
|
||||
|
||||
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);
|
||||
if(status != 1){
|
||||
return status;
|
||||
}
|
||||
qe->qh = r.h;
|
||||
qe->qk = r.k;
|
||||
qe->ql = r.l;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
154
tasublib.h
Normal file
154
tasublib.h
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, April 2005
|
||||
*/
|
||||
#ifndef TASUBLIB
|
||||
#define TASUBLIB
|
||||
#include "cell.h"
|
||||
#include "matrix/matrix.h"
|
||||
/*================= error codes =====================================*/
|
||||
#define ENERGYTOBIG -700
|
||||
#define BADSYNC -701 /* mono/analyzer out of sync: 2*theta != two_theta*/
|
||||
#define UBNOMEMORY -702
|
||||
#define TRIANGLENOTCLOSED -703
|
||||
#define BADRMATRIX -704
|
||||
/*================= Monochromator/Analyzer stuff =====================*/
|
||||
/**
|
||||
* convert an energy in meV to Ki, Kf type values
|
||||
* @param input energy
|
||||
* @return Ki, or Kf
|
||||
*/
|
||||
double energyToK(double energy);
|
||||
/**
|
||||
* convert from Ki, Kf to energy in meV
|
||||
* @param input K value
|
||||
* @return output energy in meV
|
||||
*/
|
||||
double KtoEnergy(double k);
|
||||
/*----------------------------------------------------------------------*/
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* data structure for the angles of a mono/ana calculation
|
||||
*/
|
||||
typedef struct{
|
||||
double theta;
|
||||
double two_theta;
|
||||
double horizontal_curvature;
|
||||
double vertical_curvature;
|
||||
}maAngles, *pmaAngles;
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/**
|
||||
* calculate the angles for the wavelength or K value k
|
||||
* @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.
|
||||
*/
|
||||
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);
|
||||
/*======================= 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
|
||||
* @param r1 The first reflection
|
||||
* @param r2 The second reflection
|
||||
* @param erroroCode An error code which gives more details
|
||||
* when an error occurs.
|
||||
* @return a UB matix on sucess, or NULL on failure. Then errorCode
|
||||
* can be inspected what caused the problem.
|
||||
*/
|
||||
MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1,
|
||||
tasReflection r2, int *errorCode);
|
||||
/**
|
||||
* calcluate the normal to the plane describe by the two reflections r1, r2
|
||||
* @param r1 first reflection
|
||||
* @param r2 second reflection
|
||||
* @return a plane normal on success, NULL else
|
||||
*/
|
||||
MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2);
|
||||
/**
|
||||
* calculate the angles for r. R's h, k, l, ki, kf must be set, the angles
|
||||
* will be updated.
|
||||
* @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
|
||||
* @return 1 on success, a negative error code when errors are encountered
|
||||
*/
|
||||
int calcTasQAngles(MATRIX UB, MATRIX planeNormal,
|
||||
int ss, ptasReflection r);
|
||||
/**
|
||||
* 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.
|
||||
* @return 1 on success, a negative error code on failures.
|
||||
*/
|
||||
int calcTasQH(MATRIX UB, ptasReflection r);
|
||||
/*======================== 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
|
||||
* @param qe Input QE position
|
||||
* @param angles output angles.
|
||||
* @return 1 on success, a negative error code in case of problems
|
||||
*/
|
||||
int calcAllTasAngles(ptasMachine machine, tasQEPosition qe,
|
||||
ptasAngles angles);
|
||||
/**
|
||||
* calculate the current position of the spectrometer in Q-E space from
|
||||
* angles.
|
||||
* @param machine The machine parameters
|
||||
* @param angles The input angles
|
||||
* @param qe The output Q-E position
|
||||
* @return 1 on success, a negative error code on errors.
|
||||
*/
|
||||
int calcTasQEPosition(ptasMachine machine, tasAngles angles,
|
||||
ptasQEPosition qe);
|
||||
#endif
|
Reference in New Issue
Block a user