
the capture command in that it not put resluts into the Tcl interpreter. This broke scriptcontext scripts in complicated situations. - Resolved some issues with the TAS calculation and negative scattering sense. - Fixed a bug which did not reset the state to idle after checking reachability in confvirtualmot.c SKIPPED: psi/autowin.c psi/eigera2.c psi/jvlprot.c psi/makefile_linux psi/sinqhttpopt.c psi/tasscan.c
285 lines
7.3 KiB
C
285 lines
7.3 KiB
C
/**
|
|
* This is an implementation of the polymorphic single crystal calculation module
|
|
* for the triple axis mode. In this mode the tilt angles of a standard sample
|
|
* cradle are used to orient the sample. The math behind this has been decribed by
|
|
* Mark Lumsden in his paper.
|
|
*
|
|
* copyright: see file COPYRIGHT
|
|
*
|
|
* Mark Koennecke, November 2008
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <sics.h>
|
|
#include "singlediff.h"
|
|
#include "motor.h"
|
|
#include "singlex.h"
|
|
#include "motorlist.h"
|
|
#include "lld.h"
|
|
#include "tasublib.h"
|
|
#include "fourlib.h"
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int calculateTASSettings(pSingleDiff self,
|
|
double *hkl, double *settings)
|
|
{
|
|
tasQEPosition qe;
|
|
tasAngles angles;
|
|
double e, *normal;
|
|
int status;
|
|
MATRIX mn;
|
|
char error[132];
|
|
float fHard;
|
|
|
|
e = 9.045 / self->lambda;
|
|
e = e * e;
|
|
qe.ki = energyToK(e);
|
|
qe.kf = energyToK(e);
|
|
qe.qh = hkl[0];
|
|
qe.qk = hkl[1];
|
|
qe.ql = hkl[2];
|
|
|
|
normal = SXGetPlanenormal();
|
|
if (normal == NULL) {
|
|
return 0;
|
|
}
|
|
mn = vectorToMatrix(normal);
|
|
if (mn == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
status = calcTasQAngles(self->UB, mn, 1,0, qe, &angles);
|
|
if (status < 0) {
|
|
status = 0;
|
|
} else {
|
|
status = 1;
|
|
}
|
|
settings[0] = angles.sample_two_theta;
|
|
settings[1] = angles.a3;
|
|
settings[2] = angles.sgu;
|
|
settings[3] = angles.sgl;
|
|
if (!MotorCheckBoundary(SXGetMotor(Omega), (float) settings[0], &fHard,
|
|
error, 132)) {
|
|
status = 0;
|
|
}
|
|
if (!MotorCheckBoundary
|
|
(SXGetMotor(TwoTheta), (float) settings[1], &fHard, error, 132)) {
|
|
status = 0;
|
|
}
|
|
if (!MotorCheckBoundary(SXGetMotor(Sgu), (float) settings[2], &fHard,
|
|
error, 132)) {
|
|
status = 0;
|
|
}
|
|
if (!MotorCheckBoundary(SXGetMotor(Sgl), (float) settings[3], &fHard,
|
|
error, 132)) {
|
|
status = 0;
|
|
}
|
|
free(normal);
|
|
mat_free(mn);
|
|
return status;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
static int settingsToTasList(struct __SingleDiff *self, double *settings)
|
|
{
|
|
|
|
setNewMotorTarget(self->motList, (char *) SXGetMotorName(Omega),
|
|
(float) settings[0]);
|
|
setNewMotorTarget(self->motList, (char *) SXGetMotorName(TwoTheta),
|
|
(float) settings[1]);
|
|
setNewMotorTarget(self->motList, (char *) SXGetMotorName(Sgu),
|
|
(float) settings[2]);
|
|
setNewMotorTarget(self->motList, (char *) SXGetMotorName(Sgl),
|
|
(float) settings[3]);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
static int hklFromTasAngles(struct __SingleDiff *self, double *hkl)
|
|
{
|
|
pIDrivable pDriv;
|
|
double e, stt, om, sgu, sgl;
|
|
tasQEPosition qe;
|
|
tasAngles angles;
|
|
int status = 1;
|
|
|
|
e = 9.045 / self->lambda;
|
|
e = e * e;
|
|
qe.ki = energyToK(e);
|
|
qe.kf = energyToK(e);
|
|
|
|
pDriv = makeMotListInterface();
|
|
pDriv->GetValue(&self->motList, pServ->dummyCon);
|
|
|
|
stt = getListMotorPosition(self->motList,
|
|
(char *) SXGetMotorName(TwoTheta));
|
|
om = getListMotorPosition(self->motList, (char *) SXGetMotorName(Omega));
|
|
sgu = getListMotorPosition(self->motList, (char *) SXGetMotorName(Sgu));
|
|
sgl = getListMotorPosition(self->motList, (char *) SXGetMotorName(Sgl));
|
|
|
|
angles.a3 = om;
|
|
angles.sample_two_theta = stt;
|
|
angles.sgu = sgu;
|
|
angles.sgl = sgl;
|
|
|
|
status = calcTasQH(self->UB, angles, &qe);
|
|
if (status < 0) {
|
|
status = 0;
|
|
}
|
|
hkl[0] = qe.qh;
|
|
hkl[1] = qe.qk;
|
|
hkl[2] = qe.ql;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int hklFromTasAnglesGiven(struct __SingleDiff *self,
|
|
double *settings, double *hkl)
|
|
{
|
|
double e;
|
|
tasQEPosition qe;
|
|
tasAngles angles;
|
|
int status = 1;
|
|
|
|
e = 9.045 / self->lambda;
|
|
e = e * e;
|
|
qe.ki = energyToK(e);
|
|
qe.kf = energyToK(e);
|
|
|
|
angles.a3 = settings[0];
|
|
angles.sample_two_theta = settings[1];
|
|
angles.sgu = settings[2];
|
|
angles.sgl = settings[3];
|
|
|
|
status = calcTasQH(self->UB, angles, &qe);
|
|
if (status < 0) {
|
|
status = 0;
|
|
}
|
|
hkl[0] = qe.qh;
|
|
hkl[1] = qe.qk;
|
|
hkl[2] = qe.ql;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
static int getTasReflection(char *id, tasReflection * r)
|
|
{
|
|
pSICSOBJ refList;
|
|
double hkl[3], angles[4];
|
|
double lambda, e;
|
|
|
|
lambda = SXGetLambda();
|
|
e = 9.045 / lambda;
|
|
e = e * e;
|
|
|
|
refList = SXGetReflectionList();
|
|
if (!GetRefIndexID(refList, id, hkl)) {
|
|
return 0;
|
|
} else {
|
|
r->qe.qh = hkl[0];
|
|
r->qe.qk = hkl[1];
|
|
r->qe.ql = hkl[2];
|
|
r->qe.ki = energyToK(e);
|
|
r->qe.kf = energyToK(e);
|
|
GetRefAnglesID(refList, id, angles);
|
|
r->angles.a3 = angles[0];
|
|
r->angles.sample_two_theta = angles[1];
|
|
r->angles.sgu = angles[2];
|
|
r->angles.sgl = angles[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
MATRIX calcTasUBFromTwo(pSingleDiff self,
|
|
char *refid1, char *refid2, int *err)
|
|
{
|
|
MATRIX ub = NULL, pl = NULL;
|
|
tasReflection r1, r2;
|
|
lattice direct;
|
|
double p[3];
|
|
|
|
direct.a = self->cell[0];
|
|
direct.b = self->cell[1];
|
|
direct.c = self->cell[2];
|
|
direct.alpha = self->cell[3];
|
|
direct.beta = self->cell[4];
|
|
direct.gamma = self->cell[5];
|
|
|
|
if (!getTasReflection(refid1, &r1)) {
|
|
*err = REFERR;
|
|
return NULL;
|
|
}
|
|
if (!getTasReflection(refid2, &r2)) {
|
|
*err = REFERR;
|
|
return NULL;
|
|
}
|
|
|
|
ub = calcTasUBFromTwoReflections(direct, r1, r2, err);
|
|
pl = calcPlaneNormal(r1, r2);
|
|
if (pl != NULL) {
|
|
matrixToVector(pl, p);
|
|
SXSetPlanenormal(p);
|
|
mat_free(pl);
|
|
}
|
|
return ub;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
MATRIX calcTasUBFromThree(pSingleDiff self,
|
|
char *refid1, char *refid2, char *refid3,
|
|
int *err)
|
|
{
|
|
/*
|
|
* not implemented yet
|
|
* There is also a problem: if I have three reflections, which
|
|
* defines the plane normal? This also does not make much sense anyway:
|
|
* we usually will not have a reflection out of plane: thus the three
|
|
* will be coplanar and the results may not be useful at all!
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
static int calcTasZ1(pSingleDiff self, char *refid, double z1[3])
|
|
{
|
|
tasReflection r1;
|
|
MATRIX u = NULL;
|
|
|
|
if (!getTasReflection(refid, &r1)) {
|
|
return 0;
|
|
}
|
|
u = calcTasUVectorFromAngles(r1);
|
|
if (u == NULL) {
|
|
return 0;
|
|
} else {
|
|
matrixToVector(u, z1);
|
|
mat_free(u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
void initializeSingleTas(pSingleDiff diff)
|
|
{
|
|
|
|
if (diff->motList >= 0) {
|
|
LLDdelete(diff->motList);
|
|
}
|
|
diff->motList = LLDcreate(sizeof(MotControl));
|
|
addMotorToList(diff->motList, (char *) SXGetMotorName(TwoTheta), .0);
|
|
addMotorToList(diff->motList, (char *) SXGetMotorName(Omega), .0);
|
|
addMotorToList(diff->motList, (char *) SXGetMotorName(Sgu), .0);
|
|
addMotorToList(diff->motList, (char *) SXGetMotorName(Sgl), .0);
|
|
|
|
diff->calculateSettings = calculateTASSettings;
|
|
diff->settingsToList = settingsToTasList;
|
|
diff->hklFromAngles = hklFromTasAngles;
|
|
diff->hklFromAnglesGiven = hklFromTasAnglesGiven;
|
|
diff->calcUBFromTwo = calcTasUBFromTwo;
|
|
diff->calcUBFromThree = calcTasUBFromThree;
|
|
diff->calcZ1 = calcTasZ1;
|
|
}
|