/****************************************************************** * * McStas, version 1.0, released October 26, 1998 * Maintained by Kristian Nielsen and Kim Lefmann, * Risoe National Laboratory, Roskilde, Denmark * * Component: Fermi Chopper * * %Identification * Written by: Andrew Garrett * Date: 26 Nov 1998 * Origin: KEK (Japan) * Version: 1.01 * Modified by: EF, Mar 08th, 2000 : corrected the 'max' pb * * Fermi Chopper with curved slits. * * %Description * Fermi Chopper with curved slits. All slits have the same radius * of curvature. * * Note: w and r_slit should have opposite signs. This routine * checks for this, and ensures the signs are opposite. Nu is * assumed to have the correct sign, and r_slit may be changed. * This component was previously called Curve_fe.comp. * * See also Additional note from Andrew Garrett [agarrett@ccbsf0.kek.jp]. * * %Parameters * Input Parameters: * * rad: Radius of the chopper (m) * nu: frequency (Hz) * delta: Phase angle (sec) * ymin: Lower y bound (m) * ymax: Upper y bound (m) * w: Width of an individual slit (m) * n: Number of slits (1) * r_slit: Radius of curvature of the slits (m) * * %End *******************************************************************/ DEFINE COMPONENT Fermi_Chopper DEFINITION PARAMETERS (rad, nu, delta, ymin, ymax, w, n, r_slit) SETTING PARAMETERS () OUTPUT PARAMETERS (omega, r_blade, x_width, nn, tdr) STATE PARAMETERS (x, y, z, vx, vy, vz, t, s1, s2, p) DECLARE %{ double omega, r_blade, x_width; int nn; double tdr; %} INITIALIZE %{ omega = 2*PI*nu; if (r_slit*omega > 0) r_blade = -r_slit; else r_blade = r_slit; x_width = n*w; nn = 0; tdr = 0; %} TRACE %{ double t0, t1, dt; double rcmid; /* length from chopper center in chopper frame */ double xcin, xcout, xcmid; /* x-coordinate of entry, exit, and */ /* middle points, in chopper frame */ double rin, rout, rmid; /* length from center of curvature */ /* in chopper frame */ /* Note: for r's, will actually calculate r^2 - r_slit^2 */ double vrin, vrout, vrmid; /* velocities are radial velocity */ /* from the center of curvature, */ /* in the chopper frame */ double dr, ttrans; double d1, d2; /* tempo vars for calculating max */ if (cylinder_intersect (&t0, &t1, x, y, z, vx, vy, vz, rad, ymax-ymin)) { if (t0 < 0) /*Neutron started inside cylinder */ ABSORB; dt = t1 - t0; /*total time of flight inside cylinder */ PROP_DT (t0); /*Brings neutron to entrance of cylinder */ /* Checks to see if neutron enters or leaves from top or bottom of */ /* cylinder. Check against 0.999rad^2 to avoid minor */ /* round-off error common to floating point arithmetic. */ if (x*x + z*z < 0.999*rad*rad || (x+vx*dt)*(x+vx*dt) + (z+vz*dt)*(z+vz*dt) < 0.999*rad*rad) ABSORB; t0 = t - delta; t1 = t0 + dt; /* Adjust t0 and t1 for offset, */ /* used in trig functions below */ xcin = x*cos(omega*t0) - z*sin(omega*t0); rin = rad*rad - 2.0*r_blade*xcin; /* Checks to see if the neutron entered the slit area */ if ( fabs(rin - x_width*x_width/4.0) > fabs(r_blade*x_width) ) ABSORB; xcout = (x+vx*dt)*cos(omega*t1) - (z+vz*dt)*sin(omega*t1); rout = rad*rad - 2.0*r_blade*xcout; /* Checks to see if the neutron exited the slit area */ if ( fabs(rout - x_width*x_width/4.0) > fabs(r_blade*x_width) ) ABSORB; dr = fabs( sqrt(r_blade*r_blade + rin) - sqrt(r_blade*r_blade + rout) ); /* If the neutron has changed its radius by more than a slit */ /* width, absorb it. */ if (dr > w) ABSORB; /* Calculates radial velocity on entrance and exit. Note: vr */ /* is off by a factor of rin (or rout), but only the sign is */ /* used, so this is not important. */ vrin = x*vx + z*vz - r_blade * ( (vx-omega*z)*cos(omega*t0) - (vz+omega*x)*sin(omega*t0) ); vrout = (x+vx*dt)*vx + (z+vz*dt)*vz - r_blade * ( ( vx-omega*(z+vz*dt) )*cos(omega*t1) - ( vz+omega*(x+vx*dt) )*sin(omega*t1) ); /* Check if there is a local extreme in r, in which case dr is */ /* greater than calculated above, and the new value must be found */ if (vrin * vrout < 0) { /* Will look for local extreme by adjusting t0 and t1. */ /* Note that t is the entry time, so t0+dt-t+delta will */ /* indicate the time in the cylinder, while t0+dt is */ /* the time the chopper has been rotating. */ do { dt = (t1-t0)/2; ttrans = t0 + dt - t + delta; vrmid = (x + vx*ttrans)*vx + (z + vz*ttrans)*vz - r_blade * ( (vx - omega*(z+vz*ttrans)) * cos(omega*(t0+dt)) - (vz + omega*(x+vx*ttrans)) * sin(omega*(t0+dt)) ); if (vrmid * vrin < 0) { t1 = t0 + dt; } else { t0 = t0 + dt; vrin = vrmid; } } while (fabs(vrmid) > 1e-12); /* Now calculate dr */ xcmid = ( x + vx*ttrans )*cos(omega*(t0+dt)) - ( z + vz*ttrans )*sin(omega*(t0+dt)); rcmid = (x + vx*ttrans)*(x + vx*ttrans) + (z + vz*ttrans)*(z + vz*ttrans); rmid = rcmid - 2*r_blade*xcmid; d1 = fabs (sqrt(r_blade*r_blade + rin) - sqrt(r_blade*r_blade + rmid)); d2 = fabs (sqrt(r_blade*r_blade + rout) - sqrt(r_blade*r_blade + rmid)); if (d1 > d2) dr = d1; else dr = d2; } /* Check if the neutron has moved more than 1 slit width. */ /* If so, absorb it, otherwise change its probability */ if (dr > w) { ABSORB; } else { nn ++; tdr += dr/w; p *= (1.0 - dr/w); } } else /* The neutron failed to even hit the chopper */ ABSORB; %} FINALLY %{ /* This is just to avoid a division by 0 error if no neutrons get */ /* through */ if (nn == 0) nn = 1; /* Prints out the number of neutrons that have passed through the */ /* chopper, and their average deviation as a fraction of the slit */ /* width */ printf ("Neutrons: %d, Deviation: %g\%\n", nn, 100.0*tdr/nn); %} MCDISPLAY %{ magnify("xy"); circle("xy", 0, 0, 0, rad); %} END