/*******************************************************************************
*
* McStas, neutron ray-tracing package
* Copyright (C) 1997-2011, All rights reserved
* Risoe National Laboratory, Roskilde, Denmark
* Institut Laue Langevin, Grenoble, France
*
* Instrument: Template TAS instrument
*
* %Identification
* Written by: Emmanuel Farhi
* Date: 2006
* Origin: ILL (France)
* Release: McStas 1.12cb
* Version: $Revision: 1.6 $
* %INSTRUMENT_SITE: Templates
*
* Template RESCAL type triple-axis machine (TAS)
*
* %Description
* This instrument is a simple model of triple-axis spectrometer.
* It is directly illuminated by the moderator,
* and has flat monochromator and analyzer. Sample is a vanadium cylinder.
* Default geometry is from IN20@ILL.
*
* Si 111 DM=3.135 AA
* PG 002 DM=3.355 AA (Highly Oriented Pyrolytic Graphite)
* Ge 311 DM=1.714 AA
*
* IN22 configuration:
* KI=3.84, QM=1.0, EN=0.0, verbose=1,
* WM=0.15, HM=0.12, NHM=1, NVM=9, RMV=-1,
* WA=0.20, HA=0.10, NHA=11, NVA=3, RAV=-1, RAH=-1,
* SM=-1, SS=1, SA=-1,
* L1=10.0, L2=1.7, L3=1.0, L4=0.8
*
* Example: mcrun templateTAS.instr EN=0.5 QM=1
* Example: mcrun templateTAS.instr A1=20.6
*
* %Parameters
* INPUT PARAMETERS:
* KI: Incoming neutron wavevector [Angs-1]
* KF: Outgoing neutron wavevector [Angs-1]
* EI: Incoming neutron energy [meV]
* EF: Outgoing neutron energy [meV]
* QH: Measurement QH position in crystal [rlu]
* QK: Measurement QK position in crystal [rlu]
* QL: Measurement QL position in crystal [rlu]
* EN: Energy transfert in crystal [meV]
* QM: Wavevector transfert in crystal [Angs-1]
* KFIX: Fixed KI or KF value for Rescal compatibility [Angs-1]
* FX: Fixed KI or KF type for Rescal compatibility [1:KI,2:KF]
* L1: Source-Monochromator distance [m]
* L2: Monochromator-Sample distance [m]
* L3: Sample-Analyzer distance [m]
* L4: Analyzer-detector distance [m]
* SM: Scattering sense of beam from Monochromator [1:left, -1:right]
* SS: Scattering sense of beam from Sample [1:left, -1:right]
* SA: Scattering sense of beam from Analyzer [1:left, -1:right]
* DM: Monochromator d-spacing [Angs]
* DA: Analyzer d-spacing [Angs]
* RMV: Monochromator vertical curvature, 0 for flat, -1 for automatic setting [m]
* RMH: Monochromator horizontal curvature, 0 for flat, -1 for automatic setting [m]
* RAV: Analyzer vertical curvature, 0 for flat, -1 for automatic setting [m]
* RAH: Analyzer horizontal curvature, 0 for flat, -1 for automatic setting [m]
* ETAM: Monochromator mosaic [arc min]
* ETAA: Analyzer mosaic [arc min]
* ALF1: Horizontal collimation from Source to Monochromator [arc min]
* ALF2: Horizontal collimation from Monochromator to Sample A[arc min]
* ALF3: Horizontal collimation from Sample to Analyzer [arc min]
* ALF4: Horizontal collimation from Analyzer to Detector [arc min]
* BET1: Vertical collimation from Source to Monochromator [arc min]
* BET2: Vertical collimation from Monochromator to Sample A[arc min]
* BET3: Vertical collimation from Sample to Analyzer [arc min]
* BET4: Vertical collimation from Analyzer to Detector [arc min]
* AS: Sample lattice parameter A [Angs]
* BS: Sample lattice parameter B [Angs]
* CS: Sample lattice parameter C [Angs]
* AA: Angle between lattice vectors B,C [deg]
* BB: Angle between lattice vectors C,A [deg]
* CC: Angle between lattice vectors A,B [deg]
* AX: First reciprocal lattice vector in scattering plane, X [rlu]
* AY: First reciprocal lattice vector in scattering plane, Y [rlu]
* AZ: First reciprocal lattice vector in scattering plane, Z [rlu]
* BX: Second reciprocal lattice vector in scattering plane, X [rlu]
* BY: Second reciprocal lattice vector in scattering plane, Y [rlu]
* BZ: Second reciprocal lattice vector in scattering plane, Z [rlu]
* A1: Monohromator rotation angle [deg]
* A2: Monohromator take-off angle [deg]
* A3: Sample rotation angle [deg]
* A4: Sample take-off angle [deg]
* A5: Analyzer rotation angle [deg]
* A6: Analyzer take-off angle [deg]
* verbose: print TAS configuration. 0 to be quiet [1]
*
* %Link
* Rescal for Matlab at http://www.ill.fr/tas/matlab
* %Link
* Restrax at http://omega.ujf.cas.cz/restrax/
* %End
*******************************************************************************/
DEFINE INSTRUMENT templateTAS(
KI=2.662, KF=0, EI=0, EF=0,
QH=0, QK=0, QL=0,
EN=0, QM=0, KFIX=0, FX=0,
L1=9, L2=2.1, L3=1.5, L4=0.7,
SM=1, SS=-1, SA=1,
DM=3.3539, DA=3.3539,
RMV=0, RMH=0, RAV=0, RAH=0,
ETAM=30, ETAA=30,
ALF1=60, ALF2=60, ALF3=60, ALF4=60,
BET1=120, BET2=120, BET3=120, BET4=120,
AS=6.28, BS=6.28, CS=6.28,
AA=90, BB=90, CC=90,
AX=1, AY=0, AZ=0,
BX=0, BY=1, BZ=0,
verbose=1,
A1=0,A2=0,A3=0,A4=0,A5=0,A6=0
)
DECLARE
%{
struct sample_struct {
double as, bs, cs;
double aa, bb, cc;
double ax, ay, az;
double bx, by, bz;
} sample;
struct machine_hkl_struct {
double dm, da;
double l1, l2, l3, l4;
double sm, ss, sa;
double etam, etaa, kfix, fx;
double alf1, alf2, alf3, alf4;
double bet1, bet2, bet3, bet4;
double ki, kf, ei, ef;
double qh, qk, ql, en;
} machine_hkl;
struct machine_real_struct {
double a1,a2,a3,a4,a5,a6;
double rmh, rmv, rah, rav;
double qm, qs, qt[3];
char message[256];
} machine_real;
struct machine_real_struct qhkl2angles(
struct sample_struct sample,
struct machine_hkl_struct machine_hkl,
struct machine_real_struct machine_real) {
/* code from TASMAD/t_rlp.F:SETRLP */
double qhkl[3];
double alpha[3];
double a[3];
double aspv[3][2];
double cosa[3], sina[3];
double cosb[3], sinb[3];
double b[3], c[3], s[4][4];
double vv[3][3], bb[3][3];
double arg, cc;
int i,j,k,l,m,n;
char liquid_case=1;
/* transfert parameters to local arrays */
qhkl[0] = machine_hkl.qh; /* HKL target */
qhkl[1] = machine_hkl.qk;
qhkl[2] = machine_hkl.ql;
alpha[0] = sample.aa; /* cell angles */
alpha[1] = sample.bb;
alpha[2] = sample.cc;
a[0] = sample.as; /* cell parameters */
a[1] = sample.bs;
a[2] = sample.cs;
aspv[0][0]= sample.ax; /* cell axis A */
aspv[1][0]= sample.ay;
aspv[2][0]= sample.az;
aspv[0][1]= sample.bx; /* cell axis B */
aspv[1][1]= sample.by;
aspv[2][1]= sample.bz;
/* default return values */
strcpy(machine_real.message, "");
machine_real.a3 = machine_real.a4 = 0;
machine_real.a1 = machine_real.a5 = 0;
/* if using HKL positioning in crystal (QM = 0) */
if (machine_real.qm <= 0) {
liquid_case = 0;
/* compute reciprocal cell */
for (i=0; i< 3; i++)
if (a[i] <=0) sprintf(machine_real.message, "Lattice parameters a[%i]=%g", i, a[i]);
else {
a[i] /= 2*PI;
alpha[i]*= DEG2RAD;
cosa[i] = cos(alpha[i]);
sina[i] = sin(alpha[i]);
}
cc = cosa[0]*cosa[0]+cosa[1]*cosa[1]+cosa[2]*cosa[2]; /* nprm */
cc = 1 + 2*cosa[0]*cosa[1]*cosa[2] - cc;
if (cc <= 0) sprintf(machine_real.message, "Lattice angles (AA,BB,CC) cc=%g", cc);
else cc = sqrt(cc);
if (strlen(machine_real.message)) return machine_real;
/* compute bb */
j=1; k=2;
for (i=0; i<3; i++) {
b[i] = sina[i]/(a[i]*cc);
cosb[i] = (cosa[j]*cosa[k] - cosa[i])/(sina[j]*sina[k]);
sinb[i] = sqrt(1 - cosb[i]*cosb[i]);
j=k; k=i;
}
bb[0][0] = b[0];
bb[1][0] = 0;
bb[2][0] = 0;
bb[0][1] = b[1]*cosb[2];
bb[1][1] = b[1]*sinb[2];
bb[2][1] = 0;
bb[0][2] = b[2]*cosb[1];
bb[1][2] =-b[2]*sinb[1]*cosa[0];
bb[2][2] = 1/a[2];
/* compute vv */
for (k=0; k< 3; k++)
for (i=0; i< 3; i++) vv[k][i] = 0;
for (k=0; k< 2; k++)
for (i=0; i< 3; i++)
for (j=0; j< 3; j++)
vv[k][i] += bb[i][j]*aspv[j][k];
for (m=2; m>=1; m--)
for (n=0; n<3; n++) {
i = (int)fmod(m+1,3); j= (int)fmod(m+2,3);
k = (int)fmod(n+1,3); l= (int)fmod(n+2,3);
vv[m][n]=vv[i][k]*vv[j][l]-vv[i][l]*vv[j][k];
}
for (i=0; i< 3; i++) { /* compute norm(vv) */
c[i]=0;
for (j=0; j< 3; j++)
c[i] += vv[i][j]*vv[i][j];
if (c[i]>0) c[i] = sqrt(c[i]);
else {
sprintf(machine_real.message, "Vectors A and B, c[%i]=%g", i, c[i]);
return machine_real;
}
}
for (i=0; i< 3; i++) /* normalize vv */
for (j=0; j< 3; j++)
vv[j][i] /= c[j];
for (i=0; i< 3; i++) /* compute S */
for (j=0; j< 3; j++) {
s[i][j] = 0;
for (k=0; k< 3; k++)
s[i][j] += vv[i][k]*bb[k][j];
}
s[3][3]=1;
for (i=0; i< 3; i++) s[3][i]=s[i][3]=0;
/* compute q modulus and transverse component */
machine_real.qs = 0;
for (i=0; i< 3; i++) {
machine_real.qt[i] = 0;
for (j=0; j< 3; j++) machine_real.qt[i] += qhkl[j]*s[i][j];
machine_real.qs += machine_real.qt[i]*machine_real.qt[i];
}
if (machine_real.qs > 0) machine_real.qm = sqrt(machine_real.qs);
else sprintf(machine_real.message, "Q modulus too small QM^2=%g", machine_real.qs);
} else {
machine_real.qs = machine_real.qm*machine_real.qm;
}
/* end if qm <= 0 ********************************************* */
/* positioning of monochromator and analyser */
arg = PI/machine_hkl.dm/machine_hkl.ki;
if (fabs(arg > 1))
sprintf(machine_real.message, "Monochromator can not reach this KI. arg=%g", arg);
else {
if (machine_hkl.dm <= 0 || machine_hkl.ki <= 0)
strcpy(machine_real.message, "Monochromator DM=0 or KI=0.");
else
machine_real.a1 = asin(arg)*RAD2DEG;
machine_real.a1 *= machine_hkl.sm;
}
machine_real.a2=2*machine_real.a1;
arg = PI/machine_hkl.da/machine_hkl.kf;
if (fabs(arg > 1))
sprintf(machine_real.message, "Analyzer can not reach this KF. arg=%g",arg);
else {
if (machine_hkl.da <= 0 || machine_hkl.kf <= 0)
strcpy(machine_real.message, "Analyzer DA=0 or KF=0.");
else
machine_real.a5 = asin(arg)*RAD2DEG;
machine_real.a5 *= machine_hkl.sa;
}
machine_real.a6=2*machine_real.a5;
if (strlen(machine_real.message)) return machine_real;
/* code from TASMAD/t_conv.F:SAM_CASE */
arg = (machine_hkl.ki*machine_hkl.ki + machine_hkl.kf*machine_hkl.kf - machine_real.qs)
/ (2*machine_hkl.ki*machine_hkl.kf);
if (fabs(arg) < 1)
machine_real.a4 = RAD2DEG*acos(arg);
else
sprintf(machine_real.message, "Q modulus too big. Can not close triangle. arg=%g", arg);
machine_real.a4 *= machine_hkl.ss;
if (!liquid_case) { /* compute a3 in crystals */
machine_real.a3 =
-atan2(machine_real.qt[1],machine_real.qt[0])
-acos( (machine_hkl.kf*machine_hkl.kf-machine_real.qs-machine_hkl.ki*machine_hkl.ki)
/(-2*machine_real.qm*machine_hkl.ki) );
machine_real.a3 *= RAD2DEG*(machine_real.a4 > 0 ? 1 : -1 );
}
return machine_real;
}
%}
/* end of DECLARE */
INITIALIZE
%{
double Vi, Vf;
char anglemode = 0;
if (KFIX && FX) {
if (FX == 1) KI = KFIX;
else if (FX == 2) KF = KFIX;
}
/* determine neutron energy from input */
if (KI && !EI) {
Vi = K2V*fabs(KI);
EI = VS2E*Vi*Vi;
}
if (KF && !EF) {
Vf = K2V*fabs(KF);
EF = VS2E*Vf*Vf;
}
machine_real.a1 = A1;
machine_real.a2 = A2;
machine_real.a3 = A3;
machine_real.a4 = A4;
machine_real.a5 = A5;
machine_real.a6 = A6;
if (A1 || A2 || A3 || A4 || A5 || A6) anglemode=1;
if (!anglemode) {
if (!EI && !EF)
exit(fprintf(stderr,
"%s: ERROR: neutron beam energy is not defined (EI, EF, KI, KF)\n",
NAME_CURRENT_COMP));
/* energy conservation */
if (EI)
EF = EI - EN;
else if (EF)
EI = EF + EN;
/* determine remaining neutron energies */
if (!KI && EI) {
Vi = SE2V*sqrt(EI);
KI = V2K*Vi;
}
if (!KF && EF) {
Vf = SE2V*sqrt(EF);
KF = V2K*Vf;
}
if (!QM && !QH && !QK && !QL)
exit(fprintf(stderr,
"%s: ERROR: No Q trasnfert defined (QM, QH, QK, QL)\n",
NAME_CURRENT_COMP));
}
/* transfert sample parameters */
sample.aa = AA;
sample.bb = BB;
sample.cc = CC;
sample.as = AS;
sample.bs = BS;
sample.cs = CS;
sample.ax = AX;
sample.ay = AY;
sample.az = AZ;
sample.bx = BX;
sample.by = BY;
sample.bz = BZ;
/* transfert target parameters */
machine_hkl.ki = KI;
machine_hkl.kf = KF;
machine_hkl.ei = EI;
machine_hkl.ef = EF;
machine_hkl.qh = QH;
machine_hkl.qk = QK;
machine_hkl.ql = QL;
machine_hkl.en = EN;
machine_real.qm = QM;
if (verbose) {
printf("%s: Detailed TAS configuration\n", NAME_CURRENT_COMP);
printf("* Incoming beam: EI=%.4g [meV] KI=%.4g [Angs-1] Vi=%g [m/s]\n", EI, KI, Vi);
printf("* Outgoing beam: EF=%.4g [meV] KF=%.4g [Angs-1] Vf=%g [m/s]\n", EF, KF, Vf);
}
/* transfert machine parameters */
machine_hkl.l1 = L1;
machine_hkl.l2 = L2;
machine_hkl.l3 = L3;
machine_hkl.l4 = L4;
machine_hkl.sm = SM;
machine_hkl.ss = SS;
machine_hkl.sa = SA;
machine_hkl.dm = DM;
machine_hkl.da = DA;
machine_real.rmv= RMV;
machine_real.rmh= RMH;
machine_real.rav= RAV;
machine_real.rah= RAH;
machine_hkl.etam= ETAM;
machine_hkl.etaa= ETAA;
machine_hkl.alf1= ALF1;
machine_hkl.alf2= ALF2;
machine_hkl.alf3= ALF3;
machine_hkl.alf4= ALF4;
machine_hkl.bet1= BET1;
machine_hkl.bet2= BET2;
machine_hkl.bet3= BET3;
machine_hkl.bet4= BET4;
/* geometry tests w/r to collimator lengths */
if (machine_hkl.l1 <= 1)
exit(fprintf(stderr, "%s: ERROR: L1 too short. Min=1\n", NAME_CURRENT_COMP));
if (machine_hkl.l2 <= 0.35)
exit(fprintf(stderr, "%s: ERROR: L2 too short. Min=0.35\n", NAME_CURRENT_COMP));
if (machine_hkl.l3 <= 0.40)
exit(fprintf(stderr, "%s: ERROR: L3 too short. Min=0.40\n", NAME_CURRENT_COMP));
if (machine_hkl.l4 <= 0.24)
exit(fprintf(stderr, "%s: ERROR: L4 too short. Min=0.24\n", NAME_CURRENT_COMP));
if (!anglemode) {
machine_real = qhkl2angles(sample, machine_hkl, machine_real);
if (strlen(machine_real.message))
exit(fprintf(stderr, "%s: ERROR: %s [qhkl2angles]\n",
NAME_CURRENT_COMP, machine_real.message));
}
/* compute optimal curvatures */
double L;
L = 1/(1/L1+1/L2);
if (RMV < 0) machine_real.rmv = fabs(2*L*sin(DEG2RAD*machine_real.a1));
if (RMH < 0) machine_real.rmh = fabs(2*L/sin(DEG2RAD*machine_real.a1));
L = 1/(1/L3+1/L4);
if (RAV < 0) machine_real.rav = fabs(2*L*sin(DEG2RAD*machine_real.a5));
if (RAH < 0) machine_real.rah = fabs(2*L/sin(DEG2RAD*machine_real.a5));
if (verbose) {
printf("* Transfert: EN=%g [meV] QM=%g [Angs-1]\n", EN, machine_real.qm);
printf("Angles: A1=%.4g A2=%.4g A3=%.4g A4=%.4g A5=%.4g A6=%.4g [deg]\n",
machine_real.a1, machine_real.a2,
machine_real.a3, machine_real.a4,
machine_real.a5, machine_real.a6);
printf("Monochromator: DM=%.4g [Angs] RMH=%.4g [m] RMV=%.4g [m] %s\n",
machine_hkl.dm, machine_real.rmh, machine_real.rmv,
(!machine_real.rmh && !machine_real.rmv ? "flat" : "curved"));
printf("Analyzer: DA=%.4g [Angs] RAH=%.4g [m] RAV=%.4g [m] %s\n",
machine_hkl.da, machine_real.rah, machine_real.rav,
(!machine_real.rah && !machine_real.rav ? "flat" : "curved"));
}
%}
/* end of INITIALIZE */
TRACE
/* Source description */
INSTRUMENT COMPONENT Origin=Progress_bar()
AT (0,0,0) ABSOLUTE
/* a flat constant source */
INSTRUMENT COMPONENT Source = Source_gen(
radius = 0.10,
dist = machine_hkl.l1,
xw = 0.1, yh = 0.08,
E0 = machine_hkl.ei,
dE = machine_hkl.ei*0.03)
AT (0,0,0) ABSOLUTE
INSTRUMENT COMPONENT SC1 = Collimator_linear(
xmin =-0.08/2, ymin =-0.11/2,
xmax = 0.08/2, ymax = 0.11/2,
len = machine_hkl.l1 > 6.34 ? 5.34 : machine_hkl.l1/2,
divergence=ALF1,
divergenceV=BET1)
WHEN (ALF1 && BET1)
AT (0, 0, (machine_hkl.l1-5.34)/2) ABSOLUTE
INSTRUMENT COMPONENT Guide_out=Arm()
AT (0, 0, machine_hkl.l1) ABSOLUTE
COMPONENT Mono_Cradle = Arm()
AT (0, 0, 0) RELATIVE PREVIOUS
SPLIT COMPONENT PG1Xtal = Monochromator_curved(
width = 0.10,
height = 0.12,
NH=1, NV=9,
RV=machine_real.rmv, RH=machine_real.rmh,
DM=machine_hkl.dm, mosaich = machine_hkl.etam, mosaicv = machine_hkl.etam,
r0 = (fabs(machine_hkl.dm-3.355) < 0.2 ? 1: 0.7),
reflect=(fabs(machine_hkl.dm-3.355) < 0.2 ? "HOPG.rfl" : ""))
AT (0, 0, 0) RELATIVE Mono_Cradle
ROTATED (0, machine_real.a1, 0) RELATIVE Mono_Cradle
/* on mono, pointing towards sample */
COMPONENT Mono_Out = Arm()
AT (0,0,0) RELATIVE Mono_Cradle
ROTATED (0, machine_real.a2, 0) RELATIVE Mono_Cradle
COMPONENT SC2 = Collimator_linear(
xmin =-0.04/2, ymin =-0.07/2,
xmax = 0.04/2, ymax = 0.07/2,
len = 0.35,
divergence=ALF2,
divergenceV=BET2)
AT (0, 0, (machine_hkl.l2-0.35)/2) RELATIVE Mono_Out
COMPONENT Sample_Cradle = Arm()
AT (0, 0, machine_hkl.l2) RELATIVE Mono_Out
ROTATED (0, machine_real.a3, 0) RELATIVE Mono_Out
SPLIT COMPONENT Sample = V_sample(
radius_i = 0.0, radius_o = 0.0064, h = 0.0254,
focus_xw = 0.06, focus_yh=0.12, pack = 1,
target_index=2)
AT (0,0,0) RELATIVE Sample_Cradle
COMPONENT Sample_Out = Arm() /* this is the sample-ana axis */
AT (0,0,0) RELATIVE Sample_Cradle
ROTATED (0, machine_real.a4, 0) RELATIVE Mono_Out
COMPONENT SC3 =Collimator_linear(
xmin =-0.06/2, ymin =-0.12/2,
xmax = 0.06/2, ymax = 0.12/2,
len = 0.40,
divergence=ALF3,
divergenceV=BET3)
AT (0, 0, (machine_hkl.l3-0.40)/2) RELATIVE Sample_Out
COMPONENT Ana_Cradle = Arm()
AT (0, 0, machine_hkl.l3) RELATIVE Sample_Out
ROTATED (0, machine_real.a5, 0) RELATIVE Sample_Out
SPLIT COMPONENT PG2Xtal = Monochromator_curved(
width = 0.10,
height = 0.12,
NH=1, NV=9,
RV=machine_real.rav, RH=machine_real.rah,
mosaich = machine_hkl.etaa, mosaicv = machine_hkl.etaa,
r0 = 0.7, DM=machine_hkl.da)
AT (0, 0, 0) RELATIVE Ana_Cradle
COMPONENT Ana_Out = Arm() /* this is the sample-ana axis */
AT (0,0,0) RELATIVE Ana_Cradle
ROTATED (0, machine_real.a6, 0) RELATIVE Sample_Out
COMPONENT SC4 =Collimator_linear(
xmin =-0.06/2, ymin =-0.12/2,
xmax = 0.06/2, ymax = 0.12/2,
len = 0.24,
divergence=ALF4,
divergenceV=BET4)
AT (0, 0, (machine_hkl.l4-0.24)/2) RELATIVE Ana_Out
/* vertical 3He Detector */
COMPONENT He3H = PSD_monitor(
xmin = -0.025400, xmax = 0.025400,
ymin = -0.042850, ymax = 0.042850,
nx=20, ny=20, filename="He3H.psd")
AT (0, 0, machine_hkl.l4) RELATIVE Ana_Out
END