770 lines
22 KiB
C
770 lines
22 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
|
|
-----------------------------------------------------------------------*/
|
|
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.
|
|
-------------------------------------------------------------------------*/
|
|
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:
|
|
break;
|
|
}
|
|
}
|
|
/*----------------------------------------------------------------------
|
|
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__, 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[10],
|
|
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];
|
|
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;
|
|
/* 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] = readCurrent(tasMotorOrder[CURMOT+i],pCon);
|
|
currents[i+4] = readCurrent(tasMotorOrder[CURMOT + i + 4],pCon);
|
|
}
|
|
readConversionFactors(self,helmconv);
|
|
|
|
/*
|
|
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,
|
|
&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 < 4; 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;
|
|
|
|
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], motorTargets[i]);
|
|
if(status == 0)
|
|
{
|
|
/* the error will have been reported and must be ignored */
|
|
SCSetInterrupt(pCon,eContinue);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
start the monochromator and analyzer curvature motors
|
|
*/
|
|
if(motorMask[6])
|
|
{
|
|
status = StartMotor(pServ->pExecutor,pSics,pCon,
|
|
"MCV", motorTargets[6]);
|
|
if(status == 0)
|
|
{
|
|
/* the error will have been reported but must be ignored*/
|
|
SCSetInterrupt(pCon,eContinue);
|
|
}
|
|
}
|
|
if(motorMask[8])
|
|
{
|
|
status = StartMotor(pServ->pExecutor,pSics,pCon,
|
|
"ACH", 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;
|
|
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;
|
|
}
|
|
|
|
/*
|
|
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] = readCurrent(tasMotorOrder[CURMOT+i],pCon);
|
|
helmCurrent[4+i] = readCurrent(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;
|
|
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[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;
|
|
|
|
/*
|
|
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;
|
|
}
|
|
/*-----------------------------------------------------------------------
|
|
readCurrent 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 readCurrent(char *val, SConnection *pCon){
|
|
pIDrivable pDriv;
|
|
CommandList *pCom;
|
|
pDummy pDum;
|
|
|
|
pCom = FindCommand(pServ->pSics,val);
|
|
if(pCom != NULL){
|
|
pDriv = GetDrivableInterface(pCom->pData);
|
|
if(pDriv != NULL){
|
|
return pDriv->GetValue(pCom->pData,pCon);
|
|
}
|
|
}
|
|
return .0;
|
|
}
|
|
/*-----------------------------------------------------------------------
|
|
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,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;
|
|
}
|