/******************************************************************************* * * McStas, neutron ray-tracing package * Copyright 1997-2002, All rights reserved * Risoe National Laboratory, Roskilde, Denmark * Institut Laue Langevin, Grenoble, France * * Component: Monochromator_curved * * %I * * Written by: Emmanuel Farhi, Kim, Lefmann, Peter Link * Date: Aug. 24th 2001 * Version: $Revision: 1.19 $ * Origin: ILL * Release: McStas 1.6 * Modified by: EF, Aug. 24th 2001: From Mosaic_anisotropic and Mon_2foc * Modified by: EF, Feb 13th 2002: Read reflectivity table * Modified by: EF, Oct 24th 2002: Read transmission table * * Double bent multiple crystal slabs with anisotropic gaussian mosaic. * * %Description * Double bent infinitely thin mosaic crystal, useful as a monochromator or * analyzer. which uses a small-mosaicity approximation and taking into account * higher order scattering. The mosaic is anisotropic gaussian, with different * FWHMs in the Y and Z directions. The scattering vector is perpendicular to the * surface. For an unrotated monochromator component, the crystal plane lies in * the y-z plane (ie. parallel to the beam). The component works in reflection, but * also transmits the non-diffracted beam. Reflectivity and transmission files may * be used. The slabs are positioned in the vertical plane (not on a * cylinder/sphere), and are rotated according to the curvature radius. * When curvatures are set to 0, the monochromator is flat. * The curvatures approximation for parallel beam focusing to distance L, with * monochromator rotation angle A1 are: * RV = 2*L*sin(DEG2RAD*A1); * RH = 2*L/sin(DEG2RAD*A1); * * When you rotate the component by A1 = asin(Q/2/Ki)*RAD2DEG, do not forget to * rotate the following components by A2=2*A1 (for 1st order) ! * * Example: Monochromator_curved(zwidth=0.01, yheight=0.01, gap=0.0005, * NH=11, NV=11, mosaich=30.0, mosaicv=30.0, r0=0.7, Q=1.8734) * * Example values for lattice parameters * PG 002 DM=3.355 AA (Highly Oriented Pyrolytic Graphite) * PG 004 DM=1.607 AA * Heusler 111 DM=3.362 AA (Cu2MnAl) * CoFe DM=1.771 AA (Co0.92Fe0.08) * Ge 311 DM=1.714 AA * Si 111 DM=3.135 AA * Cu 111 DM=2.087 AA * Cu 002 DM=1.807 AA * Cu 220 DM=1.278 AA * Cu 111 DM=2.095 AA * * %Parameters * INPUT PARAMETERS: * * zwidth: horizontal width of an individual slab (m) * yheight: vertical height of an individual slab (m) * gap: typical gap between adjacent slabs (m) * NH: number of slabs horizontal (columns) * NV: number of slabs vertical (rows) * mosaich: Horisontal mosaic FWHM (arc minutes) * mosaicv: Vertical mosaic FWHM (arc minutes) * r0: Maximum reflectivity. O unactivates component (1) * Q: Scattering vector (AA-1) * RV: radius of vertical focussing. flat for 0 (m) * RH: radius of horizontal focussing. flat for 0 (m) * * optional parameters * DM: monochromator d-spacing instead of Q=2*pi/DM (Angstrom) * mosaic: sets mosaich=mosaicv (arc minutes) * width: total width of monochromator (m) * height: total height of monochromator (m) * verbose: verbosity level (0/1) * reflect: reflectivity file name of text file as 2 columns [k, R] [str] * transmit:transmission file name of text file as 2 columns [k, T] [str] * * OUTPUT PARAMETERS: * col: column index for last hit blade (1:NH) * row: row index for last hit blade (1:NV) * * %Link * Additional note from Peter Link. * %L * Obsolete Mosaic_anisotropic by Kristian Nielsen * %L * Contributed Monochromator_2foc by Peter Link * * %End *******************************************************************************/ DEFINE COMPONENT Monochromator_curved DEFINITION PARAMETERS (reflect=0, transmit=0) SETTING PARAMETERS (zwidth=0.01, yheight=0.01, gap=0.0005, NH=11, NV=11, mosaich=30.0, mosaicv=30.0, r0=0.7, t0=0.3,Q=1.8734, RV=0, RH=0, DM=0, mosaic=0, width=0, height=0, verbose=0) OUTPUT PARAMETERS (mos_rms_y, mos_rms_z, mos_rms_max, mono_Q,SlabWidth,SlabHeight,rTable, tTable, row, col) STATE PARAMETERS (x,y,z,vx,vy,vz,t,s1,s2,p) SHARE %{ #ifndef GAUSS /* Define these arrays only once for all instances. */ /* Values for Gauss quadrature. Taken from Brice Carnahan, H. A. Luther and James O Wilkes, "Applied numerical methods", Wiley, 1969, page 103. This reference is available from the Copenhagen UB2 library */ double Gauss_X[] = {-0.987992518020485, -0.937273392400706, -0.848206583410427, -0.724417731360170, -0.570972172608539, -0.394151347077563, -0.201194093997435, 0, 0.201194093997435, 0.394151347077563, 0.570972172608539, 0.724417731360170, 0.848206583410427, 0.937273392400706, 0.987992518020485}; double Gauss_W[] = {0.030753241996117, 0.070366047488108, 0.107159220467172, 0.139570677926154, 0.166269205816994, 0.186161000115562, 0.198431485327111, 0.202578241925561, 0.198431485327111, 0.186161000115562, 0.166269205816994, 0.139570677926154, 0.107159220467172, 0.070366047488108, 0.030753241996117}; #define GAUSS(x,mean,rms) \ (exp(-((x)-(mean))*((x)-(mean))/(2*(rms)*(rms)))/(sqrt(2*PI)*(rms))) #endif %include "read_table-lib" %} DECLARE %{ double mos_rms_y; /* root-mean-square of mosaic, in radians */ double mos_rms_z; double mos_rms_max; double mono_Q; double SlabWidth, SlabHeight; t_Table rTable, tTable; double row,col; %} INITIALIZE %{ if (mosaic != 0) { mos_rms_y = MIN2RAD*mosaic/sqrt(8*log(2)); mos_rms_z = mos_rms_y; } else { mos_rms_y = MIN2RAD*mosaich/sqrt(8*log(2)); mos_rms_z = MIN2RAD*mosaicv/sqrt(8*log(2)); } mos_rms_max = mos_rms_y > mos_rms_z ? mos_rms_y : mos_rms_z; mono_Q = Q; if (DM != 0) mono_Q = 2*PI/DM; if (mono_Q <= 0) { fprintf(stderr,"Monochromator_curved: %s: Error scattering vector Q = 0\n", NAME_CURRENT_COMP); exit(-1); } if (r0 < 0) { fprintf(stderr,"Monochromator_curved: %s: Error reflectivity r0 is negative\n", NAME_CURRENT_COMP); exit(-1); } if (r0 == 0) { fprintf(stderr,"Monochromator_curved: %s: Reflectivity r0 is null. Ingnoring component.\n", NAME_CURRENT_COMP); } if (NH*NV == 0) { fprintf(stderr,"Monochromator_curved: %s: no slabs ??? (NH or NV=0)\n", NAME_CURRENT_COMP); exit(-1); } if (verbose && r0) { printf("Monochromator_curved: component %s Q=%.3g Angs-1 (DM=%.4g Angs)\n", NAME_CURRENT_COMP, mono_Q, 2*PI/mono_Q); if (NH*NV == 1) printf(" flat.\n"); else { if (NH > 1) { printf(" horizontal: %i blades", (int)NH); if (RH != 0) printf(" focusing with RH=%.3g [m]", RH); printf("\n"); } if (NV > 1) { printf(" vertical: %i blades", (int)NV); if (RV != 0) printf(" focusing with RV=%.3g [m]", RV); printf("\n"); } } } if (reflect != NULL && r0) { if (verbose) fprintf(stdout, "Monochromator_curved : %s : Reflectivity data (k, R)\n", NAME_CURRENT_COMP); Table_Read(&rTable, reflect, 1); /* read 1st block data from file into rTable */ Table_Rebin(&rTable); /* rebin as evenly, increasing array */ if (rTable.rows < 2) Table_Free(&rTable); Table_Info(rTable); } else rTable.data = NULL; if (transmit != NULL) { if (verbose) fprintf(stdout, "Monochromator_curved : %s : Transmission data (k, T)\n", NAME_CURRENT_COMP); Table_Read(&tTable, transmit, 1); /* read 1st block data from file into rTable */ Table_Rebin(&tTable); /* rebin as evenly, increasing array */ if (tTable.rows < 2) Table_Free(&tTable); Table_Info(tTable); } else tTable.data = NULL; if (width == 0) SlabWidth = zwidth; else SlabWidth = (width+gap)/NH - gap; if (height == 0) SlabHeight = yheight; else SlabHeight = (height+gap)/NV - gap; %} TRACE %{ double dt; if(vx != 0.0 && (dt = -x/vx) >= 0.0 && r0) { /* Moving towards crystal? */ double zmin,zmax, ymin,ymax, zp,yp, y1,z1,t1; y1 = y + vy*dt; /* Propagate to crystal plane */ z1 = z + vz*dt; t1 = t + dt; zmax = ((NH*(SlabWidth+gap))-gap)/2; zmin = -zmax; ymax = ((NV*(SlabHeight+gap))-gap)/2; ymin = -ymax; zp = fmod ( (z1-zmin),(SlabWidth+gap) ); yp = fmod ( (y1-ymin),(SlabHeight+gap) ); /* hit a slab or a gap ? */ if (z1>zmin && z1ymin && y1 2*k/mono_Q) order--; if(order > 0) /* Bragg scattering possible? */ { double q0, q0x, theta, delta, p_reflect, tmp, my_r0; q0 = order*mono_Q; q0x = ratio < 0 ? -q0 : q0; theta = asin(q0/(2*k)); /* Actual bragg angle */ /* Make MC choice: reflect or transmit? */ delta = asin(fabs(kux)) - theta; if (rTable.data != NULL) { my_r0 = r0*Table_Value(rTable, k, 1); /* 2nd column */ } else my_r0 = r0; if (my_r0 >= 1) { if (verbose) fprintf(stdout, "Warning: Monochromator_curved : lowered reflectivity from %f to 1 (k=%f)\n", my_r0, k); my_r0=0.999; } if (my_r0 < 0) { if (verbose) fprintf(stdout, "Warning: Monochromator_curved : raised reflectivity from %f to 0 (k=%f)\n", my_r0, k); my_r0=0; } p_reflect = fabs(my_r0)*exp(-kiz*kiz/(kiy*kiy + kiz*kiz)*(delta*delta)/ (2*mos_rms_y*mos_rms_y))* exp(-kiy*kiy/(kiy*kiy + kiz*kiz)*(delta*delta)/ (2*mos_rms_z*mos_rms_z)); tmp = rand01(); if(tmp <= p_reflect) { /* Reflect */ double bx,by,bz,ax,ay,az,phi; double cos_2theta,k_sin_2theta,cos_phi,sin_phi,kfx,kfy,kfz,q_x,q_y,q_z; double total,c1x,c1y,c1z,width,mos_sample; int i; cos_2theta = cos(2*theta); k_sin_2theta = k*sin(2*theta); /* Get unit normal to plane containing ki and most probable kf */ vec_prod(bx, by, bz, kix, kiy, kiz, q0x, 0, 0); NORM(bx,by,bz); bx *= k_sin_2theta; by *= k_sin_2theta; bz *= k_sin_2theta; /* Get unit vector normal to ki and b */ vec_prod(ax, ay, az, bx, by, bz, kux, kuy, kuz); /* Compute the total scattering probability at this ki */ total = 0; /* Choose width of Gaussian distribution to sample the angle * phi on the Debye-Scherrer cone for the scattered neutron. * The radius of the Debye-Scherrer cone is smaller by a * factor 1/cos(theta) than the radius of the (partial) sphere * describing the possible orientations of Q due to mosaicity, so we * start with a width 1/cos(theta) greater than the largest of * the two mosaics. */ mos_sample = mos_rms_max/cos(theta); c1x = kix*(cos_2theta-1); c1y = kiy*(cos_2theta-1); c1z = kiz*(cos_2theta-1); /* Loop, repeatedly reducing the sample width until it is small * enough to avoid sampling scattering directions with * ridiculously low scattering probability. * Use a cut-off at 5 times the gauss width for considering * scattering probability as well as for integration limits * when integrating the sampled distribution below. */ for(;;) { width = 5*mos_sample; cos_phi = cos(width); sin_phi = sin(width); q_x = c1x + cos_phi*ax + sin_phi*bx; q_y = (c1y + cos_phi*ay + sin_phi*by)/mos_rms_z; q_z = (c1z + cos_phi*az + sin_phi*bz)/mos_rms_y; /* Stop when we get near a factor of 25=5^2. */ if(q_z*q_z + q_y*q_y < (25/(2.0/3.0))*(q_x*q_x)) break; mos_sample *= (2.0/3.0); } /* Now integrate the chosen sampling distribution, using a * cut-off at five times sigma. */ for(i = 0; i < (sizeof(Gauss_X)/sizeof(double)); i++) { phi = width*Gauss_X[i]; cos_phi = cos(phi); sin_phi = sin(phi); q_x = c1x + cos_phi*ax + sin_phi*bx; q_y = c1y + cos_phi*ay + sin_phi*by; q_z = c1z + cos_phi*az + sin_phi*bz; p_reflect = GAUSS((q_z/q_x),0,mos_rms_y)* GAUSS((q_y/q_x),0,mos_rms_z); total += Gauss_W[i]*p_reflect; } total *= width; /* Choose point on Debye-Scherrer cone. Sample from a Gaussian of * width 1/cos(theta) greater than the mosaic and correct for any * error by adjusting the neutron weight later. */ phi = mos_sample*randnorm(); /* Compute final wave vector kf and scattering vector q = ki - kf */ cos_phi = cos(phi); sin_phi = sin(phi); q_x = c1x + cos_phi*ax + sin_phi*bx; q_y = c1y + cos_phi*ay + sin_phi*by; q_z = c1z + cos_phi*az + sin_phi*bz; p_reflect = GAUSS((q_z/q_x),0,mos_rms_y)* GAUSS((q_y/q_x),0,mos_rms_z); x = 0.0; y = y1; z = z1; t = t1; vxp = K2V*(kix+q_x); vyp = K2V*(kiy+q_y); vzp = K2V*(kiz+q_z); p *= p_reflect/(total*GAUSS(phi,0,mos_sample)); /* rotate v coords back */ vx = vxp*csb*csa-vyp*snb*csa+vzp*sna; vy = vxp*snb +vyp*csb; vz = -vxp*csb*sna+vyp*snb*sna+vzp*csa; SCATTER; } /* End MC choice to reflect or transmit neutron (if tmp= 1) { if (verbose) fprintf(stdout, "Warning: Monochromator_curved : lowered transmission from %f to 1 (k=%f)\n", my_t0, k); my_t0=0.999; } if (my_t0 > 0) p*= my_t0; else ABSORB; } } /* End intersect the crystal (if z1) */ } /* End neutron moving towards crystal (if vx)*/ %} FINALLY %{ Table_Free(&rTable); Table_Free(&tTable); %} MCDISPLAY %{ int ih; magnify("xy"); for(ih = 0; ih < NH; ih++) { int iv; for(iv = 0; iv < NV; iv++) { double zmin,zmax,ymin,ymax; double xt, xt1, yt, yt1; zmin = (SlabWidth+gap)*(ih-NH/2.0)+gap/2; zmax = zmin+SlabWidth; ymin = (SlabHeight+gap)*(iv-NV/2.0)+gap/2; ymax = ymin+SlabHeight; if (RH) xt = -(zmax*zmax - zmin*zmin)/RH/2; else xt = 0; if (RV) yt = -(ymax*ymax - ymin*ymin)/RV/2; else yt = 0; multiline(5, xt+yt, (double)ymin, (double)zmin, xt-yt, (double)ymax, (double)zmin, -xt-yt, (double)ymax, (double)zmax, -xt+yt, (double)ymin, (double)zmax, xt+yt, (double)ymin, (double)zmin); } } %} END