- Fixed a few problems with hklscan
- Added transfer of zipped data to conman.c, histogram memory software in order to support the TRICS status display. - Upgraded TRICS data file writing. - First installment of triple axis spectrometer support: initialization of data structures and an implementation of the MAD dr(ive) command.
This commit is contained in:
470
tasutil.c
Normal file
470
tasutil.c
Normal file
@@ -0,0 +1,470 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
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 "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;
|
||||
}
|
||||
else
|
||||
{
|
||||
iPtr++;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
/*
|
||||
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[9])
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user