/*********************************************************************** * * McStas, version 1.2 released February 2000 * Maintained by Kristian Nielsen and Kim Lefmann, * Risoe National Laboratory, Roskilde, Denmark * * %IDENTIFICATION * * Author: Thomas C Hansen * Date: 07 March 2000 * Version: $Revision: 1.12 $ * Origin: ILL (Dif/D20) * Modified by: EF, 2004. Obsoleted as it is not stable/working * * Curved linear 1D MSGC PSD * * %DESCRIPTION * * A curved linear 1D PSD monitor using a cylindrical projection. This detector type is commonly * used in constant wavelength neutron powder diffraction, based either on multiwire- (MWGC) or * microstrip- (MSGC) gaschamber technology. This implementation is mainly pushed by the MSGC * realisation (D20) of such a PSD, as done on D20 at ILL. So some kind of 'polygonality' effect * resulting from the polygonal arrangement of MSGC plates will be considered in the near future * by an approximation of the electron avalanche trace in the electrical field. * OBSOLETE: rather use monitors/Monitor_nD with options="... banana ..." * * %PARAMETERS * * INPUT PARAMETERS: * * radius: (m) Radius of detector at center of MSGC plate (=radius in PSD_entry + gap) (1.471) * height: (m) Height of detector (=height in PSD_entry) (0.15) * nd: (1) Number of cells (=nd in PSD_entry) (1536) * pitch: (deg) angular pitch (=pitch in PSD_entry) (0.1) * gap: (m) gaschamber detection gap (0.053) * filename: (string) Name of file in which to store the detector image (NULL) * sign: (1) Chirality of 1st diffractometer axis=sign[takeoff of d20adapt.instr] (-1) * tt0: (deg) Angular position of 1st PSD cell (=tt0 in PSD_entry) (0) * pdet: (bar) Pressure of 3He detection gas (1.2) * pT_trace: (m) Average effective length of proton/tritium trace (0.005) * period: (1) Number of detection cells per MSGC plate (=period in PSD_entry) (32) * cellwidth: (m) Width of one detection cell on a MSGC plate (0.002568) * * OUTPUT PARAMETERS: * * PSD_N: (*1) Array of neutron counts * PSD_p: (*1.0) Array of neutron weight counts * PSD_p2: (*1.0) Array of second moments * alpha: (rad) Angle covered by one MSGC plate * R1: (m) PSD radius at MSGC edge * * %LINKS * Source code of d20adapt.instr, where this component is used * %LINKS * Source code of PSD_entry.comp, a corresponding entry window * * %END * ***********************************************************************/ DEFINE COMPONENT PSD_curved DEFINITION PARAMETERS ( radius, height, nd, pitch, gap, filename, sign, tt0, pdet, pT_trace, period, cellwidth) SETTING PARAMETERS () OUTPUT PARAMETERS (PSD_N, PSD_p, PSD_p2, alpha, R1) STATE PARAMETERS (x,y,z,vx,vy,vz,t,s1,s2,p) DECLARE %{ int PSD_N[3601]; double PSD_p[3601]; double PSD_p2[3601]; double alpha, R1; %} INITIALIZE %{ int i; alpha=period*pitch/360.0*PI; R1=radius/cos(alpha); for (i=0; i 0 */) { /*if(t0 < 0) t0 = t1;*/ if(t0 < t1) t0 = t1; /*PROP_DT(t0);*/ x+=vx*t0; y+=vy*t0; z+=vz*t0; t+=t0; SCATTER; /* incomming neutron */ /* if ((double)sign*twotheta/PI*180. < tt0-pitch) ABSORB; */ /* if ((double)sign*twotheta/PI*180. > tt0+(nd+1)*pitch) ABSORB; */ /* Polygonality effect in MSGC PSD - the detection gap is not really constant ... */ /* Where would the n hit, if the outer radius is where the plates are closest to the entry */ cylinder_intersect(&t2, &t3, x, y, z, vx, vy, vz, radius, height); if(t2 < 0) t2 = t3; x0=x+t3*vx; z0=z+t3*vz; twotheta0 = -atan2(x0,z0); i0 = floor(0.5+((double)sign*twotheta0/PI*180.0-tt0)/pitch); plate0=i0/period; /* printf("\nplate: %d, cell %d, twotheta %lf\n",plate0,i0,twotheta0/PI*180.0); */ /* Where would the n hit, if the outer radius is where two plates join */ cylinder_intersect(&t2, &t3, x, y, z, vx, vy, vz, R1, height); if(t2 < 0) t2 = t3; x1=x+t3*vx; z1=z+t3*vz; twotheta1 = -atan2(x1,z1); i1 = floor(0.5+((double)sign*twotheta1/PI*180.0-tt0)/pitch); plate1=i1/period; /* printf("plate: %d, cell %d, twotheta %lf\n",plate1,i1,twotheta1/PI*180.0); */ /* We try now to get the radius R2 where the n hits the plate */ twotheta=(tt0-pitch/2.0+(plate0+0.5)*period*pitch)*PI/180.0; /* printf("twotheta of plate %d: %lf\n",plate0,twotheta*180.0/PI); */ zp0=cos(twotheta-alpha)*R1; xp0=sin(twotheta-alpha)*R1; zp1=cos(twotheta+alpha)*R1; xp1=sin(twotheta+alpha)*R1; xx = (z0-(z1 -z0 )/(x1 -x0 )*x0) - (zp0-(zp1-zp0)/(xp1-xp0)*xp0); xx/= (zp1-zp0)/(xp1-xp0) - (z1 -z0 )/(x1 -x0 ); zz = (z0-(z1 -z0 )/(x1 -x0 )*x0) + (z1 -z0 )/(x1 -x0 ) * xx ; /* printf("mt=%lf;bt=%lf \n",(z1 -z0 )/(x1 -x0 ),(z0 -(z1 -z0 )/(x1 -x0 )*x0 )); printf("mp=%lf;bp=%lf \n",(zp1-zp0)/(xp1-xp0),(zp0-(zp1-zp0)/(xp1-xp0)*xp0)); printf("xx[0]=%lf;zz[0]=%lf\n",xx,zz); */ R2=sqrt(xx*xx+zz*zz); /* printf("R0=%lf;R1=%lf;R2=%lf\n",radius,R1,R2); printf("neutron hits plate %d (radius %lf < %lf < %lf) %lf %lf\n",plate0,radius,R2,R1,sqrt(x0*x0+z0*z0),sqrt(x1*x1+z1*z1)); printf("twotheta = %lf to %lf\n",twotheta0/PI*180.0,twotheta1/PI*180.0); printf("plate %d (%lf,%lf) to (%lf,%lf)\n",plate0,xp0,zp0,xp1,zp1); printf("n hits between (%lf,%lf) and (%lf,%lf)\n",x0,z0,x1,z1); printf("%lf of plate \n",b); */ if (plate1 != plate0) { twotheta=(tt0-pitch/2.0+(plate1+1)*period*pitch)*PI/180.0; zp0=cos(twotheta-alpha)*R1; xp0=sin(twotheta-alpha)*R1; zp1=cos(twotheta+alpha)*R1; xp1=sin(twotheta+alpha)*R1; xx = (z0-(z1 -z0 )/(x1 -x0 )*x0) - (zp0-(zp1-zp0)/(xp1-xp0)*xp0); xx/= (zp1-zp0)/(xp1-xp0) - (z1 -z0 )/(x1 -x0 ); zz = (z0-(z1 -z0 )/(x1 -x0 )*x0) + (z1 -z0 )/(x1 -x0 ) * xx ; tmp=sqrt(xx*xx+zz*zz); if (tmp R1) { /* printf("neutron hits plate %d or %d (radius %lf < %lf < %lf)\n",plate0,plate1,radius,R2,R1); printf("##############################################################\n"); */ R2=R1; } /* Now we got the virtual outer radius R2 which is in between 'radius' and 'R1' */ cylinder_intersect(&t2, &t3, x, y, z, vx, vy, vz, R2, height); if(t2 < 0) t2 = t3; /* The following thing is not working as exspected to trace the trajectory of a neutron through the detection gap PROP_DT(t2); SCATTER; PROP_DT(-t2); SCATTER; */ x+=vx*t2; y+=vy*t2; z+=vz*t2; SCATTER; x-=vx*t2; y-=vy*t2; z-=vz*t2; SCATTER; v = sqrt(vx*vx + vy*vy + vz*vz); l_full = v * (t3); /* Length of full path through sample */ /* printf("Trajectory in gap %lfmm (%lf microsecs), ",l_full*1000,t3*1000000); */ eff=1.0-exp(-0.07417*pdet*l_full*100.0*VL/v); /* VL = 1e10*HBAR*2*PI/MNEUTRON; */ dt = (t3) * -log(rand01()*(eff)+1.0-eff);/* + t0*/ /* printf("efficiency %lf percent, capture after %lfmm\n",eff*100,dt*v*1000); */ PROP_DT(dt); SCATTER; /* Point of capture */ l = v*dt; /* Penetration in detector */ p_detection=p*eff; p*=1-eff; /* a not detected (=captured) neutron may continue the flightpath!) */ /* Now, 2Theta for the place, where the neutron should have been detected ... */ twotheta = -atan2(x,z); /* target vector b from neutron to PSD (in plane: y=0) */ bx= sin(twotheta)*radius-x; by= 0.0; bz= cos(twotheta)*radius-z; /* axis a perpendicular to neutron vector v */ vec_prod(ax,ay,az, vx,vy,vz, bx,by,bz); /* MC choice of angle component psi in a circle */ psi =2*PI*rand01(); /* rotation in circle of neutron vector v around axis a (in plane) -> temporary trace vector t */ rotate (tx,ty,tz, vx,vy,vz, psi, ax,ay,az); /* MC choice of second angle component in a sphere */ theta=acos(randpm1()); /* rotation in sphere of temporary trace vector t (out of plane) -> output pT trace vector o */ rotate (ox,oy,oz, tx,ty,tz, theta, vx,vy,vz); /* vx=ox;vy=oy;vz=oz; - NOT the neutron changes it's direction but the pT trace o */ NORM(ox,oy,oz); /* neutron is virtually detected at about a quarter of the total p/T trace length from capture */ ox*=pT_trace/4.0; oy*=pT_trace/4.0; oz*=pT_trace/4.0; x+=ox;y+=oy;z+=oz; /* SHOW the part of pT trace leading to the point of virtual neutron capture detcted by the cas chamber PSD */ SCATTER; /* NOW 2Theta and phi is calculated for the gravicenter of electron avalanche */ twotheta = -atan2(x,z); phi = asin(y/radius); /* i = floor(0.5+(nx-1)*( (double)sign*twotheta/(2*PI) - tt0/360.)); */ i = floor(0.5+((double)sign*twotheta/PI*180.0-tt0)/pitch); if ((i=0)) { PSD_N [i] ++; PSD_p [i] += p_detection; PSD_p2[i] += p_detection*p_detection; } else { ABSORB; } } else { ABSORB; } /* Yes, indeed, ABSORB IS a good idea for non-detected neutrons, as they do not interest anymore, and to use Check_adapt afterwards! */ %} FINALLY %{ int i; double total=0.0,histories=0.0; char string[40]; for (i=0;i