/******************************************************************************* * * McStas, neutron ray-tracing package * Copyright 1997-2002, All rights reserved * Risoe National Laboratory, Roskilde, Denmark * Institut Laue Langevin, Grenoble, France * * Component: TOFRes_sample * * %I * Modified from Res_sample, written by: Kristian Nielsen * Date: 1999 * Written by: KL, 10 October 2004 * Origin: Risoe * * Sample for TOF resolution function calculation. * * %D * An inelastic sample with completely uniform scattering in both solid angle * and energy. This sample is used together with the TOFRes_monitor component * and (optionally) the mcresplot front-end to compute the resolution * function of all time-of-flight instruments. * The method of time focusing is used to optimize the simulations. * * The shape of the sample is either a hollow cylinder or a rectangular box. The * hollow cylinder shape is specified with an inner and outer radius. * The box is specified with dimensions xwidth, yheight, zdepth. * * The scattered neutrons will have directions towards a given target and * detector arrival time in an interval of time_width centered on time_bin. * * The target area is default disk shaped, but may also be rectangular * if specified focus_xw and focus_yh * or focus_aw and focus_ah, respectively in meters and degrees. * The target itself is either situated according to given coordinates (x,y,z), * or setting the relative target_index of the component to focus at * (next is +1). This target position will be set to its AT position. * When targeting to centered components, such as spheres or cylinders, * define an Arm component where to focus at. * * Example: TOFRes_sample(thickness=0.001, radius=0.01, yheight=0.04, focus_xw=0.025, focus_yh=0.025, time_bin=3e4, time_width=200, target_x=0, target_y=0, target_z=1) * * %P * INPUT PARAMETERS: * * thickness: [m] Thickness of hollow cylinder in (x,z) plane * radius: [m] Outer radius of hollow cylinder * yheight: [m] vert. dimension of sample, as a height * focus_r: [m] Radius of sphere containing target * target_index: [1] relative index of component to focus at, e.g. next is +1 * time_bin: [us] position of time bin * time_width: [us] width of time bin * f: [1] Adaptive time-shortening factor * * Optional parameters * xwidth: [m] horiz. dimension of sample, as a width * zdepth: [m] depth of sample * focus_xw: [m] horiz. dimension of a rectangular area * focus_yh: [m] vert. dimension of a rectangular area * focus_aw: [deg] horiz. angular dimension of a rectangular area * focus_ah: [deg] vert. angular dimension of a rectangular area * target_x: [] * target_y: [m] position of target to focus at * target_z: [] * %E *******************************************************************************/ DEFINE COMPONENT TOFRes_sample DEFINITION PARAMETERS () SETTING PARAMETERS (thickness=0,radius=0.01,yheight=0.05,focus_r=0.05, time_bin=20000, time_width=10, f=50, target_x=0, target_y=0, target_z=.5, focus_xw=0, focus_yh=0, focus_aw=0, focus_ah=0, xwidth=0, zdepth=0, int target_index=0) /* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */ SHARE %{ struct Res_sample_struct { char isrect; /* true when7 sample is a box */ double distance; /* when non zero, gives rect target distance */ double aw,ah; /* rectangular angular dimensions */ double xw,yh; /* rectangular metrical dimensions */ double tx,ty,tz; /* target coords */ }; %} /* Needed for resolution calculation */ USERVARS %{ double res_pi; double res_ki_x; double res_ki_y; double res_ki_z; double res_kf_x; double res_kf_y; double res_kf_z; double res_rx; double res_ry; double res_rz; %} DECLARE %{ struct Res_sample_struct res_struct; char res_pi_var[20]; char res_ki_x_var[20]; char res_ki_y_var[20]; char res_ki_z_var[20]; char res_kf_x_var[20]; char res_kf_y_var[20]; char res_kf_z_var[20]; char res_rx_var[20]; char res_ry_var[20]; char res_rz_var[20]; int compindex; %} INITIALIZE %{ if (!radius || !yheight) { if (!xwidth || !yheight || !zdepth) { exit(fprintf(stderr,"TOFRes_sample: %s: box-shaped sample has no volume (zero dimensions)\n", NAME_CURRENT_COMP)); } else { res_struct.isrect=1; } } else { res_struct.isrect=0; if (thickness && thickness >= radius) { exit(fprintf(stderr,"TOFRes_sample: %s: Hollow cylinder sample has no volume (zero dimensions)\n", NAME_CURRENT_COMP)); } } /* now compute target coords if a component index is supplied */ if (target_index) { Coords ToTarget; ToTarget = coords_sub(POS_A_COMP_INDEX(INDEX_CURRENT_COMP+target_index),POS_A_CURRENT_COMP); ToTarget = rot_apply(ROT_A_CURRENT_COMP, ToTarget); coords_get(ToTarget, &res_struct.tx, &res_struct.ty, &res_struct.tz); } else { res_struct.tx = target_x; res_struct.ty = target_y; res_struct.tz = target_z; } res_struct.distance=sqrt(res_struct.tx*res_struct.tx +res_struct.ty*res_struct.ty+res_struct.tz*res_struct.tz); /* different ways of setting rectangular area */ res_struct.aw = res_struct.ah = 0; if (focus_xw) { res_struct.xw = focus_xw; } if (focus_yh) { res_struct.yh = focus_yh; } if (focus_aw) { res_struct.aw = DEG2RAD*focus_aw; } if (focus_ah) { res_struct.ah = DEG2RAD*focus_ah; } /* Initialize uservar strings */ sprintf(res_pi_var,"res_pi_%i",_comp->_index); sprintf(res_ki_x_var,"res_ki_x_%i",_comp->_index); sprintf(res_ki_y_var,"res_ki_y_%i",_comp->_index); sprintf(res_ki_z_var,"res_ki_z_%i",_comp->_index); sprintf(res_kf_x_var,"res_kf_x_%i",_comp->_index); sprintf(res_kf_y_var,"res_kf_y_%i",_comp->_index); sprintf(res_kf_z_var,"res_kf_z_%i",_comp->_index); sprintf(res_rx_var,"res_rx_%i",_comp->_index); sprintf(res_ry_var,"res_ry_%i",_comp->_index); sprintf(res_rz_var,"res_rz_%i",_comp->_index); compindex=_comp->_index; %} TRACE %{ double t0, t3; /* Entry/exit time for outer cylinder */ double t1, t2; /* Entry/exit time for inner cylinder */ double v; /* Neutron velocity */ double E; double l_full; /* Flight path length for non-scattered neutron */ double flight_time; /* Calculated time-of-flight from source to target (detector) */ double dt0, dt1, dt2, dt; /* Flight times through sample */ double solid_angle=0; /* Solid angle of target as seen from scattering point */ double aim_x, aim_y, aim_z, aim_length; /* Position of target relative to scattering point */ double scat_factor; /* Simple cross-section model */ int intersect=0; double kix,kiy,kiz; double kfx,kfy,kfz; if(res_struct.isrect) intersect = box_intersect(&t0, &t3, x, y, z, vx, vy, vz, xwidth, yheight, zdepth); else intersect = cylinder_intersect(&t0, &t3, x, y, z, vx, vy, vz, radius, yheight); if(intersect) { if(t0 < 0) ABSORB; if(res_struct.isrect) { t1 = t2 = t3; scat_factor = 2*zdepth; } /* box sample */ else { /* Cylindrical sample */ /* Neutron enters at t=t0. */ /* If cylinder hollow does not exist or is NOT intersected */ if(thickness==0 || !cylinder_intersect(&t1, &t2, x, y, z, vx, vy, vz, radius-thickness, yheight)) { t1 = t2 = t3; } else { ABSORB; } scat_factor = 2*(radius-thickness); } dt0 = t1-t0; /* Time in sample, ingoing */ dt1 = t2-t1; /* Time in hole */ dt2 = t3-t2; /* Time in sample, outgoing */ v = sqrt(vx*vx + vy*vy + vz*vz); l_full = v * (dt0 + dt2); /* Length of full path through sample */ p *= l_full/scat_factor; /* Scattering probability */ dt = rand01()*(dt0+dt2); /* Time of scattering (relative to t0) */ if (dt > dt0) dt += dt1; PROP_DT(dt+t0); /* Point of scattering */ /* Store initial neutron state. */ if(p == 0) ABSORB; kix=V2K*vx; kiy=V2K*vy; kiz=V2K*vz; particle_setvar_void(_particle, res_pi_var, &p); particle_setvar_void(_particle, res_ki_x_var, &(kix)); particle_setvar_void(_particle, res_ki_y_var, &(kiy)); particle_setvar_void(_particle, res_ki_z_var, &(kiz)); particle_setvar_void(_particle, res_rx_var, &x); particle_setvar_void(_particle, res_ry_var, &y); particle_setvar_void(_particle, res_rz_var, &z); aim_x = res_struct.tx-x; /* Vector pointing at target (anal./det.) */ aim_y = res_struct.ty-y; aim_z = res_struct.tz-z; aim_length = sqrt(aim_x*aim_x+aim_y*aim_y+aim_z*aim_z); if(res_struct.aw && res_struct.ah) { randvec_target_rect_angular(&vx, &vy, &vz, &solid_angle, aim_x, aim_y, aim_z, res_struct.aw, res_struct.ah, ROT_A_CURRENT_COMP); } else if(res_struct.xw && res_struct.yh) { randvec_target_rect(&vx, &vy, &vz, &solid_angle, aim_x, aim_y, aim_z, res_struct.xw, res_struct.yh, ROT_A_CURRENT_COMP); } else { randvec_target_circle(&vx, &vy, &vz, &solid_angle, aim_x, aim_y, aim_z, focus_r); } NORM(vx, vy, vz); flight_time = -t + 1e-6*(time_bin + time_width * randpm1()); /* Correct for too large or negative flight_times, based on user-defined f */ for (; flight_time<0; flight_time += 1/f); for (; flight_time>1/f; flight_time -= 1/f); v = aim_length / flight_time; /* !! Remember later to correct for Jacobian in MC choice, t to V !! */ vx *= v; vy *= v; vz *= v; SCATTER; /* Store final neutron state. */ kfx=V2K*vx; kfy=V2K*vy; kfz=V2K*vz; particle_setvar_void(_particle, res_kf_x_var, &(kfx)); particle_setvar_void(_particle, res_kf_y_var, &(kfy)); particle_setvar_void(_particle, res_kf_z_var, &(kfz)); } %} MCDISPLAY %{ if(res_struct.isrect) { /* Flat sample. */ double xmin = -0.5*xwidth; double xmax = 0.5*xwidth; double ymin = -0.5*yheight; double ymax = 0.5*yheight; double len = zdepth/2; multiline(5, xmin, ymin, -len, xmax, ymin, -len, xmax, ymax, -len, xmin, ymax, -len, xmin, ymin, -len); multiline(5, xmin, ymin, len, xmax, ymin, len, xmax, ymax, len, xmin, ymax, len, xmin, ymin, len); line(xmin, ymin, -len, xmin, ymin, len); line(xmax, ymin, -len, xmax, ymin, len); line(xmin, ymax, -len, xmin, ymax, len); line(xmax, ymax, -len, xmax, ymax, len); } else { double radius_i = thickness ? radius-thickness : 0; circle("xz", 0, yheight/2.0, 0, radius_i); circle("xz", 0, yheight/2.0, 0, radius); circle("xz", 0, -yheight/2.0, 0, radius_i); circle("xz", 0, -yheight/2.0, 0, radius); line(-radius_i, -yheight/2.0, 0, -radius_i, +yheight/2.0, 0); line(+radius_i, -yheight/2.0, 0, +radius_i, +yheight/2.0, 0); line(0, -yheight/2.0, -radius_i, 0, +yheight/2.0, -radius_i); line(0, -yheight/2.0, +radius_i, 0, +yheight/2.0, +radius_i); line(-radius, -yheight/2.0, 0, -radius, +yheight/2.0, 0); line(+radius, -yheight/2.0, 0, +radius, +yheight/2.0, 0); line(0, -yheight/2.0, -radius, 0, +yheight/2.0, -radius); line(0, -yheight/2.0, +radius, 0, +yheight/2.0, +radius); } %} END