1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
/*******************************************************************************
* McXtrace, X-ray tracing package
* Copyright, All rights reserved
* Risoe National Laboratory, Roskilde, Denmark
* Institut Laue Langevin, Grenoble, France
*
* Component: SANSQMonitor
*
* %I
* Written by: Søren Kynde (kynde@nbi.dk)
* Rewritten by: Martin Cramer Pedersen (mcpe@nbi.dk)
* Date: October 17, 2012
* Origin: KU-Science
*
* A circular detector measuring the radial average of intensity as a function
* of the momentum transform in the sample.
*
* %D
* A simple component simulating the scattering from a box-shaped, thin solution
* of monodisperse, spherical particles.
*
* %P
* RadiusDetector: [m] Radius of the detector (in the xy-plane).
* DistanceFromSample: [m] Distance from the sample to this component.
* LambdaMin: [AA] Max sensitivity in lambda - used to compute the highest possible value of momentum transfer, q.
* NumberOfBins: [] Number of bins in the r (and q).
* RFilename: [] File used for storing I(r).
* qFilename: [] File used for storing I(q).
* Lambda0: [] If lambda is given, the momentum transfers of all rays are computed from this value. Otherwise, instrumental effects are neglected.
* restore_neutron: [] If set to 1, the component restores the original neutron.
*
* %E
*******************************************************************************/
DEFINE COMPONENT SANSQMonitor
SETTING PARAMETERS (NumberOfBins = 100,
string RFilename = "RDetector", string qFilename = "QDetector",
RadiusDetector, DistanceFromSample, LambdaMin = 1.0, Lambda0 = 0.0, restore_neutron = 0)
DECLARE
%{
// Declarations
double TwoThetaMax;
double qMax;
DArray1d Nofq;
DArray1d Iofq;
DArray1d IofqSquared;
DArray1d NofR;
DArray1d IofR;
DArray1d IofRSquared;
%}
INITIALIZE
%{
// Declarations
int i;
Nofq = create_darr1d(NumberOfBins);
Iofq = create_darr1d(NumberOfBins);
IofqSquared = create_darr1d(NumberOfBins);
NofR = create_darr1d(NumberOfBins);
IofR = create_darr1d(NumberOfBins);
IofRSquared = create_darr1d(NumberOfBins);
// Initializations
for (i = 0; i < NumberOfBins; ++i) {
Nofq[i] = 0.0;
Iofq[i] = 0.0;
IofqSquared[i] = 0.0;
}
TwoThetaMax = atan(RadiusDetector / DistanceFromSample);
qMax = 4 * PI * sin(TwoThetaMax / 2.0) / LambdaMin;
%}
TRACE
%{
// Declarations
int i;
double TwoTheta;
double Lambda;
double R;
double RLow;
double RHigh;
double q;
double qLow;
double qHigh;
double TwoThetaLow;
double TwoThetaHigh;
double AreaOfSlice;
PROP_Z0;
// Computation of R
R = sqrt(pow(x, 2) + pow(y, 2));
// Computation of q
if (Lambda0 <= 0.0) {
Lambda = 2.0 * PI / (V2K * sqrt(pow(vx, 2) + pow(vy, 2) + pow(vz, 2)));
} else {
Lambda = Lambda0;
}
TwoTheta = atan(R / DistanceFromSample);
q = 4.0 * PI * sin(TwoTheta / 2.0) / Lambda;
// Put neutron in the correct r-bin
if (R < RadiusDetector) {
i = floor(NumberOfBins * R / RadiusDetector);
RLow = RadiusDetector / NumberOfBins * i;
RHigh = RadiusDetector / NumberOfBins * (i + 1);
TwoThetaLow = atan(RLow / DistanceFromSample);
TwoThetaHigh = atan(RHigh / DistanceFromSample);
AreaOfSlice = fabs((cos(2.0 * TwoThetaLow) - cos(2.0 * TwoThetaHigh)) * 2.0 * PI);
#pragma acc atomic
NofR[i] = NofR[i] + 1;
double p_A=p/AreaOfSlice;
#pragma acc atomic
IofR[i] = IofR[i] + p_A;
double p2_A2= p*p/(AreaOfSlice*AreaOfSlice);
#pragma acc atomic
IofRSquared[i] = IofRSquared[i] + p2_A2;
}
// Put neutron in the correct q-bin
if (q < qMax) {
i = floor(NumberOfBins * q / qMax);
qLow = qMax / NumberOfBins * i;
qHigh = qMax / NumberOfBins * (i + 1);
TwoThetaLow = asin(qLow * Lambda / (4.0 * PI));
TwoThetaHigh = asin(qHigh * Lambda / (4.0 * PI));
AreaOfSlice = fabs((cos(2.0 * TwoThetaLow) - cos(2.0 * TwoThetaHigh)) * 2.0 * PI);
#pragma acc atomic
Nofq[i] = Nofq[i] + 1;
double p_A=p/AreaOfSlice;
#pragma acc atomic
Iofq[i] = Iofq[i] + p_A;
double p2_A2= p*p/(AreaOfSlice*AreaOfSlice);
#pragma acc atomic
IofqSquared[i] = IofqSquared[i] + p2_A2;
SCATTER;
}
// Restore neutron if requested
if (restore_neutron) {
// RESTORE_NEUTRON(INDEX_CURRENT_COMP, x, y, z, vx, vy, vz, t, sx, sy, sz, p);
}
%}
SAVE
%{
// Output I(r)
DETECTOR_OUT_1D(
"QMonitor - Radially averaged distribution",
"Radius [m]",
"I(r)",
"r",
0.0,
RadiusDetector,
NumberOfBins,
&NofR[0],
&IofR[0],
&IofRSquared[0],
RFilename
);
// Output I(q)
DETECTOR_OUT_1D(
"QMonitor - Distribution in q (Radially averaged)",
"q [1 / AA]",
"I(q)",
"q",
0.0,
qMax,
NumberOfBins,
&Nofq[0],
&Iofq[0],
&IofqSquared[0],
qFilename
);
%}
FINALLY
%{
destroy_darr1d(Nofq);
destroy_darr1d(Iofq);
destroy_darr1d(IofqSquared);
destroy_darr1d(NofR);
destroy_darr1d(IofR);
destroy_darr1d(IofRSquared);
%}
MCDISPLAY
%{
circle("xy", 0, 0, 0, RadiusDetector);
%}
END
|