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 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
|
/*******************************************************************************
*
* McStas, neutron ray-tracing package
* Copyright 1997-2003, All rights reserved
* Risoe National Laboratory, Roskilde, Denmark
* Institut Laue Langevin, Grenoble, France
*
* Component: SANS_spheres2
*
* %I
* Written by: P. Willendrup, derived from H. Frielinghaus SANS_benchmark2
* Date: 16.12.2019
* Origin: DTU
*
* %D
* Sample for Small Angle Neutron Scattering - hard spheres in thin solution, mono disperse.
*
* For the scattering simulation a high fraction of neutron paths is directed to the scattering (exact fraction is sc_aim).
* The remaining paths are used for the transmitted beams. The absolute intensities are treated accordingly, and the p-parameter is set accordingly.
*
* For the scattering probability, the integral of the scattering function between Q = 0.0001 and 1.0 AA-1 is calculated.
* This is used in terms of transmisson, and of course for the scattering probability.
* In this way, multiple scattering processes could be treated as well.
*
* The typical SANS range was considered to be between 0.0001 and 1.0 AA-1.
* This means that the scattered neutrons are equally distributed in this range on logarithmic Q-scales.
*
* Example: SANS_spheres2(xwidth=0.01, yheight=0.01, zthick=0.001, model=1.0, dsdw_inc=0.02, sc_aim=0.97, sans_aim=0.95, R-150)
*
* %P
*
* INPUT PARAMETERS
*
* xwidth: [m] Width of sample volume
* yheight: [m] Height of sample volume
* zthick: [m] Thickness of sample volume
* R: [AA] Radius of dilute, monodisperse spheres
* phi: [1] Volume-ratio of the spheres wrt. solution
* drho: [cm^-2] Scattering length density
* dsdw_inc: [cm^-1] The incoherent background from the overall sample, should read ca. 1.0 for water, 0.5 for half D2O, half H2O, and ca. 0.02 for D2O
* sc_aim: [1] The fraction of neutron paths used to represent the scattered neutrons (including everything: incoherent and coherent). rest is transmission.
* sans_aim: [1] The fraction of neutron paths used to represent the scattered neutrons in the sans-range (up to 1.0AA-1). rest is incoherent with Q>1AA-1.
* singlesp: [1] Switches between multiple scattering (parameter zero 0.0) and single scattering (parameter 1.0). The sc_aim directs a fraction of paths to the first scattering process accordingly. The no. of paths for the second scattering process is derived from the real probability. Up to 10 scattering processes are considered.
* Qmind: [AA^-1] Lower limit of "SANS" scattering
* Qmaxd: [AA^-1] Upper limit of "SANS" scattering
*
* %Link
*
* %E
*******************************************************************************/
DEFINE COMPONENT SANS_spheres2
SETTING PARAMETERS (xwidth=0.01, yheight=0.01, zthick=0.001, dsdw_inc=0.02, sc_aim=0.97, sans_aim=0.95, R=150, phi=1e-3, drho=6e10, int singlesp=1, Qmind = 0.0001, Qmaxd = 2.1544346900319)
SHARE
%{
#pragma acc routine seq
double Min(double A, double B) {
if (A<B) return A; else return B;
};
#pragma acc routine seq
double Max(double A, double B) {
if (A>B) return A; else return B;
};
#pragma acc routine seq
int IMin(int A, int B) {
if (A<B) return A; else return B;
};
#pragma acc routine seq
int IMax(int A, int B) {
if (A>B) return A; else return B;
};
#pragma acc routine seq
double dSigdW(double Q, double R, double phi, double drho) {
double out;
double G;
double qR;
qR = Q*R;
G = (drho*drho*phi*4e-24*PI*R*R*R/3.0); /* 4 is from sphere volume, 1e-24 is AA^3->cm^3 */
/* Note that for very small q, we should rather do a Taylor expansion here.
- See H. Frielinghaus mail to PW, WGB from Dec. 18th 2019 */
out = 3.0*(sin(qR)-qR*cos(qR))/(qR*qR*qR);
out *= G * out;
return out;
}
%}
DECLARE
%{
DArray1d Idsdw;
double Qminl;
double Qmaxl;
double l10; /* logarithms of Qmind, Qmaxd and constant ln(10) */
double p0;
%}
INITIALIZE
%{
if (!xwidth || !yheight || !zthick)
{
exit(fprintf(stderr,"%s: sample has no volume (zero dimensions)\n", NAME_CURRENT_COMP));
}
int iii,kkk;
Qminl = log10(Qmind);
Qmaxl = log10(Qmaxd);
l10 = log(10.00);
double q,Isq;
double qmin,qmax,step;
int istp;
istp = floor((Qmaxl-Qminl)*300.0+0.5);
Idsdw = create_darr1d(31);
/* By integration, calculate the coherent scattering cross-section for the relevant wavelength range */
for (iii=1;iii<=30;iii++) { /* wavelength in AA, up to 30 */
Idsdw[iii] = 0.0;
Isq = 0.0;
qmin = 0.0;
step = (log10(Min(Qmaxd,4.0*PI/iii))-Qminl)/istp;
for (kkk=0;kkk<=istp;kkk++) {
qmax = pow(10.0,Qminl+kkk*step);
q = 0.5*(qmin+qmax);
Isq += dSigdW(q,R,phi,drho)*q*(qmax-qmin);
qmin = qmax;
};
Idsdw[iii]= Isq;
};
%}
TRACE
%{
double v,k0,lambda;
int Ilam,Ilam2;
double qmax,qmaxl,Ymax,Xmax,thmax;
/* Wavelength-dependent cross-section variables for cross-section terms */
double Scoh, Sinc1, Sinc2, Stot;
double rcut,fcut;
double Q, Xsc, theta;
int iscatt;
char intersect;
double t0, t1, dt, phiROT;
double axis_x, axis_y, axis_z;
double tmp_vx, tmp_vy, tmp_vz, vout_x, vout_y, vout_z;
/* Initial neutron weight saved for later */
p0=p;
/* Number of scatterings in sample - limit at 10 below */
iscatt = 0;
v = sqrt(vx*vx + vy*vy + vz*vz);
k0 = v / K2V;
lambda = 2.0*PI / k0;
Ilam = IMax(floor(lambda),1);
Ilam2 = IMin(Ilam+1,30);
/* Coherent "SANS" scattering - in 3 intervals, asymptotic values at the low and high WL end */
if (lambda<=1.0) Scoh = 200.0*PI*Idsdw[1] / (k0*k0);
else {
if (lambda>=30.0) Scoh = 200.0*PI*Idsdw[30] / (k0*k0);
else Scoh = 200.0*PI*((Ilam2-lambda)*Idsdw[Ilam]+(lambda-Ilam)*Idsdw[Ilam2]) / (k0*k0);
};
/* Scattering triangle consideration, limit to lowes of
either Qmind or double initial k0 value */
qmax = Min(Qmaxd,2.0*k0);
qmaxl = log10(qmax);
Ymax = 0.25*qmax*qmax/(k0*k0);
/* Maximal relative scale between q and k0 */
if (Ymax>=0.9999) Ymax=1.0; /* if rounding errors occurr, this will help to avoid problems */
Xmax = 1.0 - 2.0*Ymax;
/* Maximal scattering angle for SANS signal */
thmax = acos(Xmax);
/* Inchoherent "forward" scattering */
Sinc1 = 100.0*PI*( qmax*qmax/(k0*k0)) * fabs(dsdw_inc);
/* non-directional incoherent scattering */
Sinc2 = 100.0*PI*(4.0-qmax*qmax/(k0*k0)) * fabs(dsdw_inc);
/* - that result in the total scattering cross-section */
Stot = Sinc1 + Sinc2 + Scoh;
/* Check for intersections with sample */
intersect = box_intersect(&t0, &t1, x, y, z, vx, vy, vz, xwidth, yheight, zthick);
/* Are we hitting and does cross-section have finite value? */
if (intersect && Stot>0.0) {
/* Kill neutron if it already entered sample volume */
if(t0<0.0) ABSORB;
/* Using total XS, check if we should scatter coherently here or transmit. Partition statistics accordingly. */
rcut = exp(-Stot*(t1-t0)*v);
/* Sample scattering position logarithmically */
if (1.0-rcut > sc_aim) {
dt = -1.0/(v*Stot)*log(rand01());
} else {
if (rand01()<=sc_aim) {
dt = -1.0/(v*Stot)*log(1.0-(1.0-rcut)*rand01());
p *= (1.0-rcut)/sc_aim;
}
else {
/* Transmit this guy */
dt = -1.0/(v*Stot)*log(rcut*rand01());
dt = 1e33; /* run out of sample ... */
p *= rcut/(1.0-sc_aim);
};
};
/* Based on time-logic, define if we should treat the neutron or not */
if (t0+dt<=t1) {
PROP_DT(t0+dt);
SCATTER;
iscatt = 1;
/* Partition statistics according to "SANS" vs. incoherent scattering */
fcut = Max(Ymax,sans_aim);
/* Scatter SANS or not */
if (rand01()<=fcut) {
/* Pick a random Q in the SANS regime - logarithmic sampling */
Q = pow(10.0,Qminl+(qmaxl-Qminl)*rand01());
double dsdw;
dsdw=dSigdW(Q,R,phi,drho);
p *= 200.0*PI*Q*Q/(k0*k0)*(qmaxl-Qminl)*l10*(dsdw+fabs(dsdw_inc))/(Stot*fcut);
Xsc = 1.0 - 0.5*(Q*Q/(k0*k0));
/* Scattering angle */
theta = 2.0 * asin(0.5*Q/k0);
} else {
/* Random Q for the incoherent case */
Xsc = -1.0 + (Xmax+1.0)*rand01();
p *= (1.0-Ymax)/(1.0-fcut);
/* Scattering angle */
theta = acos(Xsc);
}
/* Azimuthal-symmetrical angle */
phiROT = 2.0*PI*rand01();
/* vector product between \vec{v} and vertical */
vec_prod(axis_x, axis_y, axis_z, vx, vy, vz, 0, 1, 0);
/* apply the two rotations from above */
rotate(tmp_vx, tmp_vy, tmp_vz, vx, vy, vz, theta, axis_x, axis_y, axis_z);
rotate(vout_x, vout_y, vout_z, tmp_vx, tmp_vy, tmp_vz, phiROT, vx, vy, vz);
vx = vout_x;
vy = vout_y;
vz = vout_z;
/* Check if we should do multiple scattering (still) */
while (iscatt<10 && singlesp==0) {
/* re-intersect component geometry */
intersect = box_intersect(&t0, &t1, x, y, z, vx, vy, vz, xwidth, yheight, zthick);
if (!intersect) ABSORB;
/* Logarithmic sampling in time according to Xsect */
dt = -1.0/(v*Stot)*log(rand01());
/* Still inside the sample? */
if (dt<=t1) {
/* Propagate and scatter */
PROP_DT(dt);
SCATTER;
iscatt++;
/* Apply the same weighting and logic scheme as for single-scattering above */
fcut = Max(Ymax,sans_aim);
if (rand01()<=fcut) {
Q = pow(10.0,Qminl+(qmaxl-Qminl)*rand01());
double dsdw;
dsdw=dSigdW(Q,R,phi,drho);
p *= 200.0*PI*Q*Q/(k0*k0)*(qmaxl-Qminl)*l10*(dsdw+fabs(dsdw_inc))/(Stot*fcut);
Xsc = 1.0 - 0.5*(Q*Q/(k0*k0));
theta = 2.0 * asin(0.5*Q/k0);
}
else {
Xsc = -1.0 + (Xmax+1.0)*rand01();
p *= (1.0-Ymax)/(1.0-fcut);
theta = acos(Xsc);
};
phiROT = 2.0*PI*rand01();
vec_prod(axis_x, axis_y, axis_z, vx, vy, vz, 0, 1, 0);
rotate(tmp_vx, tmp_vy, tmp_vz, vx, vy, vz, theta, axis_x, axis_y, axis_z);
rotate(vout_x, vout_y, vout_z, tmp_vx, tmp_vy, tmp_vz, phiROT, vx, vy, vz);
vx = vout_x;
vy = vout_y;
vz = vout_z;
}
else break; /* Not in the sample any longer */
};
/* Final propagation to last "edge" of the sample box */
intersect = box_intersect(&t0, &t1, x, y, z, vx, vy, vz, xwidth, yheight, zthick);
if (!intersect) ABSORB;
PROP_DT(t1);
} else {
PROP_DT(t1); /* Time dt was long enough that we already passed the sample */
};
};
%}
MCDISPLAY
%{
double radius = 0;
double h = 0;
{
double xmin = -0.5*xwidth;
double xmax = 0.5*xwidth;
double ymin = -0.5*yheight;
double ymax = 0.5*yheight;
double zmin = -0.5*zthick;
double zmax = 0.5*zthick;
multiline(5, xmin, ymin, zmin,
xmax, ymin, zmin,
xmax, ymax, zmin,
xmin, ymax, zmin,
xmin, ymin, zmin);
multiline(5, xmin, ymin, zmax,
xmax, ymin, zmax,
xmax, ymax, zmax,
xmin, ymax, zmax,
xmin, ymin, zmax);
line(xmin, ymin, zmin, xmin, ymin, zmax);
line(xmax, ymin, zmin, xmax, ymin, zmax);
line(xmin, ymax, zmin, xmin, ymax, zmax);
line(xmax, ymax, zmin, xmax, ymax, zmax);
}
%}
END
|