
- Changed floor() to round() in sanslirebin - Some changes to accomodate the new run/drive behaviour - Added the the sps bipa command
805 lines
23 KiB
C
805 lines
23 KiB
C
/*--------------------------------------------------------------------------
|
|
This is one implementation file for the TASMAD simulation module for
|
|
SICS. The requirement is to make SICS look as much as TASMAD as
|
|
possible. This includes:
|
|
- TASMAD is variable driven
|
|
- Sometimes variables are accessed in storage order.
|
|
- A complicated calculation has to be done for getting the instruments
|
|
settings right. The appropriate F77 routine from TASMAD will be
|
|
reused.
|
|
- The scan logic is different.
|
|
- Output of ILL-formatted data files is required.
|
|
|
|
This file implements a couple of utility functions mainly for parsing
|
|
and second for interfacing to the F77 routines for calculating the
|
|
TAS settings..
|
|
|
|
Mark Koennecke, November 2000
|
|
|
|
Polarisation support added.
|
|
|
|
Mark Koennecke, April 2002
|
|
---------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <fortify.h>
|
|
#include <sics.h>
|
|
#include <sicsvar.h>
|
|
#include <counter.h>
|
|
#include <motor.h>
|
|
#include <scan.h>
|
|
#include "tas.h"
|
|
#include "tasu.h"
|
|
|
|
|
|
/*-----------------------------------------------------------------------
|
|
isTASMotor finds out if the given string is a TAS motor and returns its
|
|
index in the motor list if this the case. Else -1 is returned.
|
|
-------------------------------------------------------------------------*/
|
|
int isTASMotor(char *val)
|
|
{
|
|
int iPtr;
|
|
|
|
iPtr = 0;
|
|
while (tasMotorOrder[iPtr] != NULL) {
|
|
if (strcmp(val, tasMotorOrder[iPtr]) == 0) {
|
|
return iPtr;
|
|
} else {
|
|
iPtr++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
return number if val is a current variable, else -1
|
|
never used - and wrong (the number 18) M.Z. june 07
|
|
-----------------------------------------------------------------------*/
|
|
int isTASCurrent(char *val)
|
|
{
|
|
int test;
|
|
test = isTASMotor(val);
|
|
if (test < 0) {
|
|
return test;
|
|
}
|
|
if (test > 18) {
|
|
return test;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
isTASVar finds out if the given string is a TAS variable and returns its
|
|
index if this is the case. Else -1 will be returned.
|
|
--------------------------------------------------------------------------*/
|
|
int isTASVar(char *val)
|
|
{
|
|
int iPtr;
|
|
|
|
iPtr = 0;
|
|
while (tasVariableOrder[iPtr] != NULL) {
|
|
if (strcmp(val, tasVariableOrder[iPtr]) == 0) {
|
|
return iPtr;
|
|
} else {
|
|
iPtr++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
isTASEnergy finds out if a variable is a TAS energy variable. This would
|
|
require a TAS calculation to take place. If the test is positive then the
|
|
index of the Variable is returned, else -1 is returned.
|
|
-------------------------------------------------------------------------*/
|
|
int isTASEnergy(char *val)
|
|
{
|
|
int iPtr;
|
|
|
|
for (iPtr = EMIN; iPtr <= EMAX; iPtr++) {
|
|
if (strcmp(val, tasVariableOrder[iPtr]) == 0) {
|
|
return iPtr - EMIN;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
prepare2Parse removes all unnecessary delimiters from the parse string.
|
|
These are: ' =
|
|
----------------------------------------------------------------------*/
|
|
void prepare2Parse(char *line)
|
|
{
|
|
int i, iLang;
|
|
|
|
iLang = strlen(line);
|
|
for (i = 0; i < iLang; i++) {
|
|
if (line[i] == ',' || line[i] == '=') {
|
|
line[i] = ' ';
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
int tasNumeric(char *pText)
|
|
{
|
|
int i, ii, iGood;
|
|
static char pNum[13] = { "1234567890.+-" };
|
|
|
|
for (i = 0; i < strlen(pText); i++) {
|
|
for (ii = 0; ii < 13; ii++) {
|
|
iGood = 0;
|
|
if (pText[i] == pNum[ii]) {
|
|
iGood = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!iGood) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
print calculation errors.
|
|
*/
|
|
static int printError(int ier, SConnection * pCon)
|
|
{
|
|
/*
|
|
error messages taken from erreso
|
|
*/
|
|
switch (ier) {
|
|
case 1:
|
|
SCWrite(pCon, "ERROR: Bad lattice parameters(AS,BS,CS)", eError);
|
|
return 0;
|
|
break;
|
|
case 2:
|
|
SCWrite(pCon, "ERROR: Bad cell angles", eError);
|
|
return 0;
|
|
break;
|
|
case 3:
|
|
SCWrite(pCon, "ERROR: Bad scattering plane ", eError);
|
|
return 0;
|
|
break;
|
|
case 4:
|
|
SCWrite(pCon, "ERROR: Bad lattice or lattice plane", eError);
|
|
return 0;
|
|
break;
|
|
case 5:
|
|
SCWrite(pCon, "ERROR: Check Lattice and Scattering Plane", eError);
|
|
return 0;
|
|
break;
|
|
case 6:
|
|
SCWrite(pCon, "ERROR: Q not in scattering plane", eError);
|
|
return 0;
|
|
break;
|
|
break;
|
|
case 7:
|
|
SCWrite(pCon, "ERROR: Q-modulus to small", eError);
|
|
return 0;
|
|
break;
|
|
case 8:
|
|
case 12:
|
|
SCWrite(pCon, "ERROR: KI,KF,Q triangle cannot close", eError);
|
|
return 0;
|
|
break;
|
|
case 9:
|
|
SCWrite(pCon, "ERROR: KI or K, check d-spacings", eError);
|
|
return 0;
|
|
break;
|
|
case 10:
|
|
SCWrite(pCon, "ERROR: KI or KF cannot be obtained", eError);
|
|
return 0;
|
|
break;
|
|
case 11:
|
|
SCWrite(pCon, "ERROR: KI or KF to small", eError);
|
|
return 0;
|
|
break;
|
|
default:
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------
|
|
getSRO reads the SRO motor. This motor is for the rotation of the
|
|
magnet. The value has to be subtracted from the helm value during
|
|
calculations
|
|
-----------------------------------------------------------------------*/
|
|
int getSRO(SConnection * pCon, float *sroVal)
|
|
{
|
|
pMotor pMot = NULL;
|
|
int status;
|
|
|
|
pMot = FindMotor(pServ->pSics, "sro");
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: internal: motor sro not found!", eError);
|
|
return 0;
|
|
}
|
|
status = MotorGetSoftPosition(pMot, pCon, sroVal);
|
|
if (status != 1) {
|
|
SCWrite(pCon, "ERROR: failed to read motor sro", eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
TASCalc does the triple axis spectrometer calculations. This function is
|
|
invoked whenever energy or Q needs to be driven. The parameters:
|
|
- self a pointer to a TASdata structure holding information about all
|
|
necessary parameters.
|
|
- pCon a SConnection object needed for reporting errors.
|
|
- tasMask a mask with 0,1 indicating which variable is driven. IT IS
|
|
ASSUMED THAT THE APPROPRIATE VARIABLE HAS ALREADY BEEN SET IN THE
|
|
INTERPRETER BEFORE TASCalc IS CALLED. This is because for convenience
|
|
this functions collects the values from the interpreter.
|
|
- motorTargets will hold the new targets for the relevant motors
|
|
(A1-A6 plus some magnet related) when the call finished happily.
|
|
- motorMask will hold 1's for each motor to drive, 0 for each motor
|
|
not affected.
|
|
|
|
This version uses the TASMAD calculation routines. These have been
|
|
translated from F77 to C with f2c (f2c -A crysconv.f , tacov.f). The C is
|
|
not maintainable, always edit the F77 sources in case of need and
|
|
retranslate. This scheme requires the definitions going before TASCalc. The
|
|
advantage of using f2c is that we get less portability problems with
|
|
different calling conventions for C anf F77 on different platforms.
|
|
-----------------------------------------------------------------------*/
|
|
#include "f2c.h"
|
|
extern int setrlp_(real * sam, integer * ier);
|
|
|
|
extern int t_conv__(real * ei, real * aki, real * ef, real * akf, real *
|
|
qhkl, real * en, real * hx, real * hy, real * hz,
|
|
integer * if1, integer * if2, logical * ldk,
|
|
logical * ldh, logical * ldf, logical * lpa, real * dm,
|
|
real * da, real * helm, real * f1h, real * f1v,
|
|
real * f2h, real * f2v, real * f, integer * ifx,
|
|
integer * iss, integer * ism, integer * isa,
|
|
real * t_a__, real * t_rm__, real * t_alm__,
|
|
real * t_ra__, real * qm, logical * ldra,
|
|
logical * ldr_rm__, logical * ldr_alm__,
|
|
logical * ldr_ra__, real * p_ih__, real * c_ih__,
|
|
doublereal * a4, integer * ier);
|
|
|
|
extern int inicurve_(integer * midx, real * mrx1, real * mrx2, integer
|
|
* aidx, real * arx1, real * arx2, real * mmin,
|
|
real * mmax, real * amin, real * amax);
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
int TASCalc(pTASdata self, SConnection * pCon,
|
|
unsigned char tasMask[MAXEVAR],
|
|
float motorTargets[20], unsigned char motorMask[20])
|
|
{
|
|
/* for setrlp */
|
|
real sam[13];
|
|
integer ier;
|
|
/* for t_conv */
|
|
real ei, aki, ef, akf, qhkl[3], en, hx, hy, hz, dm, da, helm, f1h, f1v,
|
|
f2h, f2v, f, angles[6], tRM, tRA, tALM, qm, currents[8], helmconv[4];
|
|
doublereal a4;
|
|
integer if1, if2, ifx, iss, ism, isa;
|
|
logical ldk[8], ldh, ldf, lpa, ldra[6], l_RM, l_RA, l_ALM;
|
|
/* for inicurve */
|
|
real mrx1, mrx2, arx1, arx2, mmin, mmax, amin, amax;
|
|
integer im, ia;
|
|
pMotor pMot;
|
|
float fVal, fSRO;
|
|
/* else */
|
|
int i;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
/*
|
|
The first thing we need to do is to set up the orientation matrix
|
|
from the sample parameters.
|
|
*/
|
|
sam[0] = (real) self->tasPar[AS]->fVal;
|
|
sam[1] = (real) self->tasPar[BS]->fVal;
|
|
sam[2] = (real) self->tasPar[CS]->fVal;
|
|
sam[3] = (real) self->tasPar[AA]->fVal;
|
|
sam[4] = (real) self->tasPar[BB]->fVal;
|
|
sam[5] = (real) self->tasPar[CC]->fVal;
|
|
sam[6] = (real) self->tasPar[AX]->fVal;
|
|
sam[7] = (real) self->tasPar[AY]->fVal;
|
|
sam[8] = (real) self->tasPar[AZ]->fVal;
|
|
sam[9] = (real) self->tasPar[BX]->fVal;
|
|
sam[10] = (real) self->tasPar[BY]->fVal;
|
|
sam[11] = (real) self->tasPar[BZ]->fVal;
|
|
setrlp_(sam, &ier);
|
|
switch (ier) {
|
|
case 1:
|
|
SCWrite(pCon, "ERROR: error on lattice parameters", eError);
|
|
return 0;
|
|
break;
|
|
case 2:
|
|
SCWrite(pCon, "ERROR: error on lattice angles", eError);
|
|
return 0;
|
|
break;
|
|
case 3:
|
|
SCWrite(pCon, "ERROR: error on vectors A1, A2", eError);
|
|
return 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
now we need to set the parameters for mono/analyzer
|
|
curvature calculations.
|
|
*/
|
|
mrx1 = (real) self->tasPar[MRX1]->fVal;
|
|
mrx2 = (real) self->tasPar[MRX2]->fVal;
|
|
arx1 = (real) self->tasPar[ARX1]->fVal;
|
|
arx2 = (real) self->tasPar[ARX2]->fVal;
|
|
im = 7;
|
|
ia = 9;
|
|
pMot = FindMotor(pServ->pSics, "MCV");
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: cannot find monochromator curvature motor",
|
|
eError);
|
|
return 0;
|
|
}
|
|
MotorGetPar(pMot, "softupperlim", &fVal);
|
|
mmax = (real) fVal;
|
|
MotorGetPar(pMot, "softlowerlim", &fVal);
|
|
mmin = (real) fVal;
|
|
pMot = FindMotor(pServ->pSics, "ACH");
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: cannot find analyzer curvature motor", eError);
|
|
return 0;
|
|
}
|
|
MotorGetPar(pMot, "softupperlim", &fVal);
|
|
amax = (real) fVal;
|
|
MotorGetPar(pMot, "softlowerlim", &fVal);
|
|
amin = (real) fVal;
|
|
inicurve_(&im, &mrx1, &mrx2, &ia, &arx1, &arx2, &mmin, &mmax,
|
|
&amin, &amax);
|
|
|
|
/*
|
|
This done, we painstackingly initialize the tons of parameters required
|
|
by the t_conv
|
|
*/
|
|
ei = (real) self->tasPar[TEI]->fVal;
|
|
aki = (real) self->tasPar[TKI]->fVal;
|
|
ef = (real) self->tasPar[TEF]->fVal;
|
|
akf = (real) self->tasPar[TKF]->fVal;
|
|
qhkl[0] = (real) self->tasPar[TQH]->fVal;
|
|
qhkl[1] = (real) self->tasPar[TQK]->fVal;
|
|
qhkl[2] = (real) self->tasPar[TQL]->fVal;
|
|
en = (real) self->tasPar[TEN]->fVal;
|
|
hx = (real) self->tasPar[THX]->fVal;
|
|
hy = (real) self->tasPar[THY]->fVal;
|
|
hz = (real) self->tasPar[THZ]->fVal;
|
|
f = (real) 2.072; /* energy unit meV */
|
|
if1 = (integer) self->tasPar[F1]->iVal;
|
|
if2 = (integer) self->tasPar[F2]->iVal;
|
|
for (i = 0; i < 8; i++) {
|
|
ldk[i] = (logical) tasMask[i];
|
|
}
|
|
if (if1 > 0 || if2 > 0) {
|
|
ldf = 1;
|
|
} else {
|
|
ldf = 0;
|
|
}
|
|
if (tasMask[9] || tasMask[10] || tasMask[11]) {
|
|
ldh = 1;
|
|
} else {
|
|
ldh = 0;
|
|
}
|
|
|
|
if (self->tasPar[LPA]->iVal > 0)
|
|
lpa = (logical) 1;
|
|
else
|
|
lpa = (logical) 0;
|
|
|
|
dm = (real) self->tasPar[DM]->fVal;
|
|
da = (real) self->tasPar[DA]->fVal;
|
|
qm = (real) self->tasPar[QM]->fVal;
|
|
helm = (real) self->tasPar[HELM]->fVal;
|
|
f1h = (real) self->tasPar[IF1H]->fVal;
|
|
f1v = (real) self->tasPar[IF1V]->fVal;
|
|
f2h = (real) self->tasPar[IF2H]->fVal;
|
|
f2v = (real) self->tasPar[IF2V]->fVal;
|
|
ifx = (integer) self->tasPar[FX]->iVal;
|
|
iss = (integer) self->tasPar[SS]->iVal;
|
|
ism = (integer) self->tasPar[SM]->iVal;
|
|
isa = (integer) self->tasPar[SA]->iVal;
|
|
|
|
/*
|
|
initialize the magnet currents.
|
|
*/
|
|
for (i = 0; i < 4; i++) {
|
|
helmconv[i] = .0;
|
|
currents[i] = readDrivable(tasMotorOrder[CURMOT + i], pCon);
|
|
currents[i + 4] = readDrivable(tasMotorOrder[CURMOT + i + 4], pCon);
|
|
}
|
|
readConversionFactors(self, helmconv);
|
|
|
|
/*
|
|
warning if energy fixed
|
|
*/
|
|
if (ifx == 0) {
|
|
SCWrite(pCon, "WARNING: energy fixed", eWarning);
|
|
}
|
|
|
|
/*
|
|
read a4 in order to make magnet calculations work
|
|
*/
|
|
a4 = .0;
|
|
a4 = readDrivable(tasMotorOrder[A4MOT], pCon);
|
|
|
|
/*
|
|
initalise the motorMasks to 0.
|
|
*/
|
|
for (i = 0; i < 20; i++) {
|
|
motorMask[i] = 0;
|
|
}
|
|
for (i = 0; i < 6; i++) {
|
|
ldra[i] = 0;
|
|
}
|
|
l_RA = l_RM = l_ALM = ier = 0;
|
|
|
|
/* now we can call */
|
|
t_conv__(&ei, &aki, &ef, &akf,
|
|
qhkl, &en, &hx, &hy, &hz, &if1,
|
|
&if2, ldk, &ldh, &ldf, &lpa, &dm,
|
|
&da, &helm, &f1h, &f1v, &f2h, &f2v,
|
|
&f, &ifx, &iss, &ism, &isa,
|
|
angles, &tRM, &tALM, &tRA, &qm, ldra,
|
|
&l_RM, &l_ALM, &l_RA, currents, helmconv, &a4, &ier);
|
|
|
|
if (ier != 0) {
|
|
printError(ier, pCon);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
now we have to put those things back which interest us, including
|
|
updating the variables which may have accidentally been set.
|
|
*/
|
|
for (i = 0; i < 6; i++) {
|
|
motorTargets[i] = angles[i];
|
|
motorMask[i] = ldra[i];
|
|
}
|
|
/*
|
|
these additional motors are the curvature motors
|
|
*/
|
|
motorMask[6] = l_RM;
|
|
motorTargets[6] = tRM;
|
|
motorMask[8] = l_RA;
|
|
motorTargets[8] = tRA;
|
|
for (i = 0; i < 8; i++) {
|
|
motorTargets[9 + i] = currents[i];
|
|
}
|
|
if (ldh) {
|
|
/* currents must be driven */
|
|
for (i = 0; i < 3; i++) {
|
|
motorMask[13 + i] = 1;
|
|
}
|
|
}
|
|
if (ldf) {
|
|
/* currents must be driven */
|
|
for (i = 0; i < 4; i++) {
|
|
motorMask[9 + i] = 1;
|
|
}
|
|
}
|
|
|
|
self->tasPar[TEI]->fVal = (float) ei;
|
|
self->tasPar[TKI]->fVal = (float) aki;
|
|
self->tasPar[TEF]->fVal = (float) ef;
|
|
self->tasPar[TKF]->fVal = (float) akf;
|
|
self->tasPar[TEN]->fVal = (float) en;
|
|
self->tasPar[QM]->fVal = (float) qm;
|
|
self->tasPar[TQM]->fVal = (float) qm;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
TASStart starts the motors calculated by TASCalc
|
|
---------------------------------------------------------------------------*/
|
|
int TASStart(pTASdata self, SConnection * pCon, SicsInterp * pSics,
|
|
float motorTargets[20], unsigned char motorMask[20])
|
|
{
|
|
int status, i;
|
|
char pBueffel[80];
|
|
|
|
/*
|
|
do the A1-A6 motors first
|
|
*/
|
|
for (i = 0; i < 6; i++) {
|
|
if (motorMask[i] != 0) {
|
|
status = StartMotor(pServ->pExecutor, pSics, pCon,
|
|
tasMotorOrder[i], RUNDRIVE, motorTargets[i]);
|
|
}
|
|
}
|
|
/*
|
|
start the monochromator and analyzer curvature motors
|
|
*/
|
|
if (motorMask[6]) {
|
|
status = StartMotor(pServ->pExecutor, pSics, pCon,
|
|
"MCV", RUNDRIVE, motorTargets[6]);
|
|
if (status == 0) {
|
|
/* the error will have been reported but must be ignored */
|
|
SCSetInterrupt(pCon, eContinue);
|
|
return 0;
|
|
}
|
|
}
|
|
if (motorMask[8]) {
|
|
status = StartMotor(pServ->pExecutor, pSics, pCon,
|
|
"ACH", RUNDRIVE, motorTargets[8]);
|
|
if (status == 0) {
|
|
/* the error will have been reported but must be ignored */
|
|
SCSetInterrupt(pCon, eContinue);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
start magnet currents.
|
|
*/
|
|
for (i = 0; i < 8; i++) {
|
|
if (motorMask[9 + i] == 1) {
|
|
startCurrent(tasMotorOrder[CURMOT + i], pCon, motorTargets[9 + i]);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*------------------ from t_update.f converted to t_update.c -----------*/
|
|
extern int t_update__(real * p_a__, real * p_ih__, real * c_ih__,
|
|
logical * lpa, real * dm, real * da, integer * isa,
|
|
real * helm, real * f1h, real * f1v, real * f2h,
|
|
real * f2v, real * f, real * ei, real * aki,
|
|
real * ef, real * akf, real * qhkl, real * en,
|
|
real * hx, real * hy, real * hz, integer * if1,
|
|
integer * if2, real * qm, integer * ier);
|
|
/*---------------------------------------------------------------------------
|
|
TASUpdate calculates the Q/E variables back from the motors A1-A6 and
|
|
then proceeds to update the energy variables. It also checks if the
|
|
analyzer monochromator motors match up i.e tth = 2*om.
|
|
----------------------------------------------------------------------------*/
|
|
int TASUpdate(pTASdata self, SConnection * pCon)
|
|
{
|
|
real sam[16], amot[6], helmCurrent[8], convH[4], dm, da, helm, f1h, f1v;
|
|
real f, ei, aki, ef, akf, qhkl[3], en, hx, hy, hz, qm, f2v, f2h;
|
|
logical lpa;
|
|
integer isa, if1, if2, ier, ifx;
|
|
pMotor pMot;
|
|
char pBueffel[132];
|
|
float fMot, diff, fSRO;
|
|
int i, status;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
/*
|
|
The first thing we need to do is to set up the orientation matrix
|
|
from the sample parameters.
|
|
*/
|
|
sam[0] = (real) self->tasPar[AS]->fVal;
|
|
sam[1] = (real) self->tasPar[BS]->fVal;
|
|
sam[2] = (real) self->tasPar[CS]->fVal;
|
|
sam[3] = (real) self->tasPar[AA]->fVal;
|
|
sam[4] = (real) self->tasPar[BB]->fVal;
|
|
sam[5] = (real) self->tasPar[CC]->fVal;
|
|
sam[6] = (real) self->tasPar[AX]->fVal;
|
|
sam[7] = (real) self->tasPar[AY]->fVal;
|
|
sam[8] = (real) self->tasPar[AZ]->fVal;
|
|
sam[9] = (real) self->tasPar[BX]->fVal;
|
|
sam[10] = (real) self->tasPar[BY]->fVal;
|
|
sam[11] = (real) self->tasPar[BZ]->fVal;
|
|
setrlp_(sam, &ier);
|
|
switch (ier) {
|
|
case 1:
|
|
SCWrite(pCon, "ERROR: error on lattice parameters", eError);
|
|
return 0;
|
|
break;
|
|
case 2:
|
|
SCWrite(pCon, "ERROR: error on lattice angles", eError);
|
|
return 0;
|
|
break;
|
|
case 3:
|
|
SCWrite(pCon, "ERROR: error on vectors A1, A2", eError);
|
|
return 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
correct helmholtz angle for SRO rotation
|
|
*/
|
|
if (getSRO(pCon, &fSRO)) {
|
|
fSRO = self->oldSRO - fSRO;
|
|
fSRO = self->tasPar[HELM]->fVal - fSRO;
|
|
if (fSRO > 360) {
|
|
fSRO -= 360.;
|
|
}
|
|
if (fSRO < -360) {
|
|
fSRO += 360.;
|
|
}
|
|
getSRO(pCon, &self->oldSRO);
|
|
self->tasPar[HELM]->fVal = fSRO;
|
|
}
|
|
|
|
/*
|
|
get the motor angles A1-A6
|
|
*/
|
|
for (i = 0; i < 6; i++) {
|
|
pMot = FindMotor(pServ->pSics, tasMotorOrder[i]);
|
|
if (!pMot) {
|
|
sprintf(pBueffel, "ERROR: internal: motor %s NOT found",
|
|
tasMotorOrder[i]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
status = MotorGetSoftPosition(pMot, pCon, &fMot);
|
|
if (status != 1) {
|
|
sprintf(pBueffel, "ERROR: failed to read motor %s",
|
|
tasMotorOrder[i]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
amot[i] = fMot;
|
|
}
|
|
|
|
/*
|
|
read magnet currents.
|
|
*/
|
|
for (i = 0; i < 4; i++) {
|
|
convH[i] = .0;
|
|
helmCurrent[i] = readDrivable(tasMotorOrder[CURMOT + i], pCon);
|
|
helmCurrent[4 + i] = readDrivable(tasMotorOrder[CURMOT + i + 4], pCon);
|
|
}
|
|
readConversionFactors(self, convH);
|
|
|
|
/*
|
|
collect all the other machine parameters needed for a call to
|
|
t_update
|
|
*/
|
|
if (self->tasPar[LPA]->iVal > 0)
|
|
lpa = (logical) 1;
|
|
else
|
|
lpa = (logical) 0;
|
|
|
|
da = (real) self->tasPar[DA]->fVal;
|
|
dm = (real) self->tasPar[DM]->fVal;
|
|
isa = (integer) self->tasPar[SA]->iVal;
|
|
helm = (real) self->tasPar[HELM]->fVal;
|
|
f1h = (real) self->tasPar[IF1H]->fVal;
|
|
f1v = (real) self->tasPar[IF1V]->fVal;
|
|
f2h = (real) self->tasPar[IF2H]->fVal;
|
|
f2v = (real) self->tasPar[IF2V]->fVal;
|
|
f = (real) 2.072; /* energy unit meV */
|
|
|
|
ifx = (integer) self->tasPar[FX]->iVal;
|
|
|
|
/*
|
|
now call t_update to do the calculation
|
|
*/
|
|
ier = 0;
|
|
en = ef = ei = .0;
|
|
t_update__(amot, helmCurrent, convH, &lpa, &dm, &da, &isa, &helm,
|
|
&f1h, &f1v, &f2h, &f2v, &f, &ei, &aki, &ef, &akf,
|
|
qhkl, &en, &hx, &hy, &hz, &if1, &if2, &qm, &ier);
|
|
/*
|
|
!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
t_update's function ex_up must be edited manually after conversion
|
|
to c by f2c. The reason is a different definition of the abs function.
|
|
The line:
|
|
arg = (d__1 = *dx * sin(*ax2 / 114.59155902616465, abs(d__1));
|
|
|
|
has to be changed to:
|
|
arg = *dx * sin(*ax2 / 114.59155902616465);
|
|
if(arg < .0)
|
|
arg = -arg;
|
|
|
|
!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!! */
|
|
|
|
if (ier != 0) {
|
|
printError(ier, pCon);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
update all the energy variables
|
|
*/
|
|
self->tasPar[EI]->fVal = ei;
|
|
self->tasPar[KI]->fVal = aki;
|
|
self->tasPar[EF]->fVal = ef;
|
|
self->tasPar[KF]->fVal = akf;
|
|
self->tasPar[QH]->fVal = qhkl[0];
|
|
self->tasPar[QK]->fVal = qhkl[1];
|
|
self->tasPar[QL]->fVal = qhkl[2];
|
|
/*
|
|
self->tasPar[EN]->fVal = en;
|
|
*/
|
|
self->tasPar[EN]->fVal = ei - ef;
|
|
self->tasPar[HX]->fVal = hx;
|
|
self->tasPar[HY]->fVal = hy;
|
|
self->tasPar[HZ]->fVal = hz;
|
|
self->tasPar[QM]->fVal = qm;
|
|
self->tasPar[HX]->fVal = hx;
|
|
self->tasPar[HY]->fVal = hy;
|
|
self->tasPar[HZ]->fVal = hz;
|
|
SCparChange(pCon);
|
|
|
|
/*
|
|
now check the analyzer or monochromator angles
|
|
*/
|
|
if (ifx == 1) {
|
|
diff = amot[1] / 2 - amot[0];
|
|
if (diff < .0)
|
|
diff = -diff;
|
|
if (diff > .1) {
|
|
sprintf(pBueffel, "WARNING: A2 = %f is not half of A1 = %f",
|
|
amot[1], amot[0]);
|
|
SCWrite(pCon, pBueffel, eWarning);
|
|
}
|
|
} else if (ifx == 2) {
|
|
diff = amot[5] / 2 - amot[4];
|
|
if (diff < .0)
|
|
diff = -diff;
|
|
if (diff > .1) {
|
|
sprintf(pBueffel, "WARNING: A6 = %f is not half of A5 = %f",
|
|
amot[5], amot[4]);
|
|
SCWrite(pCon, pBueffel, eWarning);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
readDrivable tries to read the value of one of the magnet currents.
|
|
All errors are ignored because most of the time currents will not be
|
|
present in the system.
|
|
-----------------------------------------------------------------------*/
|
|
float readDrivable(char *val, SConnection * pCon)
|
|
{
|
|
pIDrivable pDriv;
|
|
CommandList *pCom;
|
|
pDummy pDum;
|
|
pMotor pMot = NULL;
|
|
float fVal;
|
|
|
|
/*
|
|
else: read general drivable
|
|
*/
|
|
pCom = FindCommand(pServ->pSics, val);
|
|
if (pCom != NULL) {
|
|
pDriv = GetDrivableInterface(pCom->pData);
|
|
if (pDriv != NULL) {
|
|
return pDriv->GetValue(pCom->pData, pCon);
|
|
}
|
|
}
|
|
return -999.99;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
startCurrent starts driving a current to a new value
|
|
All errors are ignored because most of the time currents will not be
|
|
present in the system.
|
|
-----------------------------------------------------------------------*/
|
|
void startCurrent(char *val, SConnection * pCon, float fVal)
|
|
{
|
|
StartMotor(pServ->pExecutor, pServ->pSics, pCon, val, RUNDRIVE,fVal);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
readConversionFactors updates the array given as a parameter with the
|
|
values of the Gauss->Ampere conversion factors
|
|
-------------------------------------------------------------------------*/
|
|
void readConversionFactors(pTASdata self, float convH[4])
|
|
{
|
|
convH[0] = self->tasPar[HCONV1]->fVal;
|
|
convH[1] = self->tasPar[HCONV2]->fVal;
|
|
convH[2] = self->tasPar[HCONV3]->fVal;
|
|
convH[3] = self->tasPar[HCONV4]->fVal;
|
|
}
|