- 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:
koennecke
2005-04-22 14:07:06 +00:00
parent 288c65e0bb
commit 6387994017
17 changed files with 1897 additions and 34 deletions

12
cell.c
View File

@ -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
View File

@ -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.

View File

@ -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
View File

@ -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 ;
}

View File

@ -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 \

View File

@ -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;
/*

View File

@ -20,6 +20,7 @@
time_t nextUpdate;
int iEnd;
SConnection *pCon;
int onOff;
}NXupdate, *pNXupdate;

View File

@ -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
View File

@ -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

View File

@ -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",

View File

@ -22,6 +22,7 @@ typedef struct {
int stopFlag;
SConnection *pCon;
int errorCount;
int debug;
} Oscillator, *pOscillator;
/*---------------------------------------------------------------------*/

View File

@ -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
View 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
View 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
View 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
View 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
View 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