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
|
/******************************************************************
*
* McStas, version 3.1,
*
*
*
* Component: Fermi_chop2a
*
* %Identification
* Written by: Garrett Granroth
* Date: 6 Feb 2005
* Origin: SNS Oak Ridge,TN
*
* %D
* Models an SNS Fermic Chopper, used in the SNS_ARCS instrument model.
*
* %Parameters
* nput Parameters:
*
* len: [m] slit package length
* w: [m] slit package width
* nu: [Hz] frequency
* delta: [sec] time from edge of chopper to center Phase angle
* tc: [sec] time when desired neutron is at the center of the chopper
* ymin: [m] Lower y bound
* ymax: [m] Upper y bound
* nchan: [1] number of channels in chopper
* bw: [m] blade width
* blader: [m] blade radius
*
*
* %End
*******************************************************************/
DEFINE COMPONENT Fermi_chop2a
SETTING PARAMETERS (len, w, nu, delta, tc, ymin, ymax, nchan, bw, blader)
SHARE
%{
#ifndef FERMI_CHOP_DEFS
#define FERMI_CHOP_DEFS
/* routine to calculate acos in proper quadrant range = 0 to 2PI*/
#pragma acc routine
double acos0_2pi(double x,double y)
{
if (y>0.0){
return acos(x);
}
return 2.0*PI-acos(x);
}
/*routine to calculate x and y positions of a neutron in a fermi chopper */
#pragma acc routine
void neutxypos(double *x, double *y, double phi, double inrad, double* c)
{
*x=c[0]+inrad*cos(phi);
*y=c[1]+inrad*sin(phi);
}
/* routine to calculate the origin of a circle that describes the neutron path through the chopper */
#pragma acc routine
void calccenter(double* c, double* zr, double* xr){
double denom, A,B,C,D,a,b;
denom=2*(-zr[0]*xr[2] +zr[0]*xr[1]+ zr[1]*xr[2]+xr[0]*zr[2]-xr[0]*zr[1] - xr[1]*zr[2]);
A=xr[1]-xr[2];B=xr[0]-xr[1];C=zr[2]-zr[1];D=zr[1]-zr[0];
a=zr[0]*zr[0]-zr[1]*zr[1]+xr[0]*xr[0]-xr[1]*xr[1];
b=zr[2]*zr[2]-zr[1]*zr[1]+xr[2]*xr[2]-xr[1]*xr[1];
c[0]=1.0/denom*(A*a+B*b);
c[1]=1.0/denom*(C*a+D*b);
}
#endif
/* function that describes the shape of the blades */
#pragma acc routine
double blades(double zin,double rin,double off){
if (rin!=0.0)
return rin*(1-cos(asin(zin/fabs(rin))))+off;
else
return 0;
}
/* function to calculate which channel the neturon is in and to check if it is in a blade
* or outside the slit package
* return 0 if neutron does not transmit return 1 with channel number if neutron will pass*/
#pragma acc routine
int checkabsorb(double phi,int *chan_num, double inrad,double inw, double insw,
double inbw, double blader, double off, double* c){
double xtmp,neuzr,neuxr;
neutxypos(&neuzr,&neuxr,phi,inrad,c);
// printf("xr:%g zr:%g phi: %g r: %g c[0]: %g c[1]: %g\n",neuxr,neuzr,phi,inrad,c[0],c[1]);
if (fabs(neuxr)>inw/2.0) // check if neutron x position is outside of slit package
return 0;
xtmp=neuxr+inw/2.0; // move origin to side of slit package
*chan_num=ceil((xtmp-blades(neuzr,blader,off))/(inbw+insw)); //calculate channel number
//check if neutron is in blade
if (xtmp >*chan_num*(inbw+insw)+blades(neuzr,blader,off))
return 0;
return 1;
}
%}
DECLARE
%{
double omega;
double off;
double splen;
double rad;
double sw;
double tw;
%}
INITIALIZE
%{
splen=len/2.0;
omega=2.0*PI*nu;
off=blader*(1-cos(asin(splen/fabs(blader))));// the additional width needed to accomodate the curvature of the blade
tw=(w+2.0*off); //the total width needed to contain the slit package
rad=sqrt(tw*tw/4.0+splen*splen); //radius of cylinder containing slit package.
sw=(w-bw)/nchan-bw;
printf("sw: %g rad: %g\n",sw,rad);
%}
TRACE
%{
double t0,t1,dphi,dt2,tneuzr,tneuxr,nrad;
double phivec[200],tpt[3],xpt[3],ypt[3],zpt[3],zr[3],xr[3],yr[3],theta[3],c[2];
int chan_num,chan_num0,idx1,idx3;
if (cylinder_intersect (&t0, &t1, x, y, z, vx, vy, vz, rad, ymax-ymin)){
if (t0 < 0) /*Neutron started inside cylinder */
ABSORB;
dt2=t1-t0;
PROP_DT(t0); /*propagate neutron to edge of chopper*/
/*calculate neutron position and velocity in chopper frame
calculate 3 points in the instrument frame and put them into the
chopper frame inorder to determine the radius and center of a circle
that describes the path of the neutron in the chopper frame. */
tpt[1]=t;
tpt[2]=t+dt2;
tpt[0]=t+dt2/2.0;
//set local 0 in time as tc and calculate angle of rotation for each point
for(idx3=0;idx3<3;idx3++){
theta[idx3]=(tpt[idx3]-tc)*omega;
}
zpt[1]=-sqrt(rad*rad-x*x); xpt[1]=x; ypt[1]=y; /* point where neutron intersects chopper */
zpt[2]=zpt[1]+vz*(dt2); xpt[2]=xpt[1]+vx*(dt2); ypt[2]=ypt[1]+vy*(dt2); /* point where neutron leaves the chopper */
xpt[0]=xpt[1]+vx*(dt2/2.0); ypt[0]=ypt[1]+vy*(dt2/2.0); zpt[0]=zpt[1]+vz*(dt2/2.0); /*point half way between in time */
/* do the rotation */
for(idx3=0;idx3<3;idx3++){
rotate(xr[idx3],yr[idx3],zr[idx3],xpt[idx3],ypt[idx3],zpt[idx3],theta[idx3],0,1,0);
}
calccenter(c,zr,xr); /* calculate the center */
nrad=sqrt((zr[0]-c[0])*(zr[0]-c[0])+(xr[0]-c[1])*(xr[0]-c[1])); /*calculate the radius of curvature for the neutron path */
/* calculate points along path of neutron through cylinder quit on absorption
* or transmit neutron if 200 points are calculated
* calculate phi for first and last points */
phivec[0]=acos0_2pi((zr[1]-c[0])/nrad,xr[1]-c[1]);phivec[1]=acos0_2pi((zr[2]-c[0])/nrad,xr[2]-c[1]);
neutxypos(&tneuzr,&tneuxr,phivec[0],nrad,c);
/* reset phi[0] and phi[1] to match the length of the slit package rather than cylinder radius*/
if(tneuzr<-splen){
phivec[0]=acos0_2pi((-c[0]-splen)/nrad,-c[1]);
}
neutxypos(&tneuzr,&tneuxr,phivec[1],nrad,c);
if(tneuzr>splen){
phivec[1]=acos0_2pi((-c[0]+splen/2.0)/nrad,-c[1]);
}
dphi=phivec[1]-phivec[0]; /* initial dphi */
idx1=2;
phivec[idx1]=phivec[0]+dphi/2.0; /* calculate center point */
if (!checkabsorb(phivec[idx1],&chan_num,nrad,tw,sw,bw,blader,off,c))
ABSORB;
chan_num0=chan_num;
while (idx1<129){
dphi=phivec[1]-phivec[idx1];
idx1++;
phivec[idx1]=phivec[0]+dphi/2.0;
if (!checkabsorb(phivec[idx1],&chan_num,nrad,tw,sw,bw,blader,off,c))
ABSORB;
if ((chan_num!=chan_num0) || (chan_num>nchan))
ABSORB;
/* If the current dphi is positive calculate points until a point is beyond phivec[1]
Check to see if the point is absorbed after each new point is generated stop if more than 129 iterations are performed
*/
if (dphi>0){
while ((phivec[idx1]<phivec[1])&&(idx1<129)){
/* printf("phivec[%i]: %g dphi: %g phivec[1]: %g\n", idx1,phivec[idx1],dphi,phivec[1]);*/
idx1++;
phivec[idx1]=phivec[idx1-1]+dphi;
if (!checkabsorb(phivec[idx1],&chan_num,nrad,tw,sw,bw,blader,off,c))
ABSORB;
// printf("chan_num0: %i chan_num: %i\n",chan_num0,chan_num);
if ((chan_num!=chan_num0) || (chan_num>nchan))
ABSORB;
}
if (phivec[idx1]>=phivec[1]) idx1--; //remove the point that is beyond phivec[1]
}
/* If the current dphi is negative calculate points until a point is beyond phivec[1]
Check to see if the point is absorbed after each new point is generated stop if more than 129 iterations are performed
*/
else if (dphi<0){
while ((phivec[idx1]>phivec[1])&&(idx1<129)){
/* printf("phivec[%i]: %g\n", idx1,phivec[idx1]);*/
idx1++;
phivec[idx1]=phivec[idx1-1]+dphi;
if (!checkabsorb(phivec[idx1],&chan_num,nrad,tw,sw,bw,blader,off,c))
ABSORB;
// printf("chan_num0: %i chan_num: %i\n",chan_num0,chan_num);
if ((chan_num!=chan_num0) || (chan_num>nchan))
ABSORB;
}
if (phivec[idx1]<=phivec[1]) idx1--; //remove the point that is beyond phivec[1]
}
else
ABSORB; /* dphi =0? */
}
}
else /* The neutron failed to even hit the chopper */
ABSORB;
%}
MCDISPLAY
%{
double zstep,x1,x2,x3,x4,z1,z2;
int idx, idx2;
line(tw/2.0,ymin,splen,tw/2.0,ymax,splen);
line(tw/2.0,ymin,-splen,tw/2.0,ymax,-splen);
line(-tw/2.0,ymin,splen,-tw/2.0,ymax,splen);
line(-tw/2.0,ymin,-splen,-tw/2.0,ymax,-splen);
line(tw/2.0,ymax,splen,tw/2.0,ymax,-splen);
line(-tw/2.0,ymax,splen,-tw/2.0,ymax,-splen);
line(tw/2.0,ymin,splen,tw/2.0,ymin,-splen);
line(-tw/2.0,ymin,splen,-tw/2.0,ymin,-splen);
circle("zx",0,ymin,0,rad);
circle("zx",0,ymax,0,rad);
zstep=2.0*splen/10.0;
for(idx=0;idx<nchan+1;idx++){
for(idx2=0;idx2<10;idx2++){
z1=idx2*zstep-splen;
z2=(idx2+1)*zstep-splen;
x1=blades(z1,blader,off)+idx*(sw+bw)-tw/2.0;
x2=blades(z2,blader,off)+idx*(sw+bw)-tw/2.0;
x3=x1+bw;
x4=x2+bw;
line(x1,ymin,z1,x2,ymin,z2);
line(x1,ymax,z1,x2,ymax,z2);
line(x3,ymin,z1,x4,ymin,z2);
line(x3,ymax,z1,x4,ymax,z2);
if(idx2==0){
line(x1,ymin,z1,x1,ymax,z1);
line(x3,ymin,z1,x3,ymax,z1);
line(x1,ymin,z1,x3,ymin,z1);
line(x1,ymax,z1,x3,ymax,z1);
}
if(idx2==9){
line(x2,ymin,z2,x2,ymax,z2);
line(x4,ymin,z2,x4,ymax,z2);
line(x2,ymin,z2,x4,ymin,z2);
line(x2,ymax,z2,x4,ymax,z2);
}
}
}
%}
END
|