Files
sics/tasutil.c
cvs 876396bb7e - Added triple axis scan command.
- Introduced simulation mode to simdriv and simcter, i.e they never fail and
  finish at once.
- Started defining MAD compatibility commands in Tcl
- Fixed a bug in FOCUS_src which caused it to leak sockets.
- Introduced setsockopt SO_REUSEADDR to all new sockets in sinqhm in order
  to loose the next sinqhm error.
2000-12-05 09:05:03 +00:00

479 lines
13 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
---------------------------------------------------------------------------*/
#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;
}
/*--------------------------------------------------------------------------
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;
}
/*----------------------------------------------------------------------
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[EI]->fVal;
aki = (real)self->tasPar[KI]->fVal;
ef = (real)self->tasPar[EF]->fVal;
akf = (real)self->tasPar[KF]->fVal;
qhkl[0] = (real)self->tasPar[QH]->fVal;
qhkl[1] = (real)self->tasPar[QK]->fVal;
qhkl[2] = (real)self->tasPar[QL]->fVal;
en = (real)self->tasPar[EN]->fVal;
hx = (real)self->tasPar[HX]->fVal;
hy = (real)self->tasPar[HY]->fVal;
hz = (real)self->tasPar[HZ]->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];
}
ldh = (logical)tasMask[8];
ldf = (logical)tasMask[9];
if(self->tasPar[LPA]->iVal > 0)
lpa = (logical)1;
dm = (real)self->tasPar[DM]->fVal;
da = (real)self->tasPar[DM]->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 helmholts currents. This needs work when
polarisation anlaysis is really supported.
*/
for(i = 0; i < 4; i++)
{
helmconv[i] = .0;
currents[i] = .0;
currents[i+4] = .0;
}
/*
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 = 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);
/*
error messages taken from erreso
*/
switch(ier)
{
case 1:
SCWrite(pCon,"ERROR: Bad lattice parameters",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: Q not in scattering plane",eError);
return 0;
break;
case 6:
SCWrite(pCon,"ERROR: Q modulus to small",eError);
return 0;
break;
case 7:
case 12:
SCWrite(pCon,"ERROR: KI, KF, Q triangle cannot close ",eError);
return 0;
break;
case 8:
SCWrite(pCon,"ERROR: in KI, KF, check d-spacings",eError);
return 0;
break;
case 9:
SCWrite(pCon,"ERROR: KI or KF cannot be obtained",eError);
return 0;
break;
case 10:
SCWrite(pCon,"ERROR: KI or KF to small",eError);
return 0;
break;
case 11:
SCWrite(pCon,"ERROR: KI or KF cannot be obtained",eError);
return 0;
break;
default:
break;
}
/*
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];
}
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];
}
for(i = 0; i < 4; i++)
{
motorTargets[17+i] = helmconv[i];
}
self->tasPar[EI]->fVal = (float)ei;
self->tasPar[KI]->fVal = (float)aki;
self->tasPar[EF]->fVal = (float)ef;
self->tasPar[KF]->fVal = (float)akf;
self->tasPar[EN]->fVal = (float)en;
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 */
return 0;
}
}
}
/*
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 */
return 0;
}
}
if(motorMask[8])
{
status = StartMotor(pServ->pExecutor,pSics,pCon,
"ACH", motorTargets[8]);
if(status == 0)
{
/* the error will have been reported */
return 0;
}
}
/*
missing: set the magnet currents. In order to do this, I need more
info about the magnets involved and how to address them.
*/
return 1;
}