File: Collimator_radial.comp

package info (click to toggle)
mccode 3.5.19%2Bds5-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,113,256 kB
  • sloc: ansic: 40,697; python: 25,137; yacc: 8,438; sh: 5,405; javascript: 4,596; lex: 1,632; cpp: 742; perl: 296; lisp: 273; makefile: 226; fortran: 132
file content (309 lines) | stat: -rw-r--r-- 11,568 bytes parent folder | download
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2002, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Collimator_radial
*
* %I
* Written by: Emmanuel Farhi <farhi@ill.fr>
* Date: July 2005
* Origin: ILL
*
* A radial Soller collimator.
*
* %D
* Radial Soller collimator with rectangular opening and specified length.
* The collimator is made of many rectangular channels stacked radially.
* Each channel is a set of transmitting layers (nslit), separated by an absorbing
* material (infinitely thin), the whole stuff is inside an absorbing housing.
*
* When specifying the number of channels (nchan), each channel has a total
* entrance width=radius*fabs(theta_max-theta_min)/nchan, but only the central
* portion 'xwidth' accepts neutrons. When xwidth=0, it is set to the full
* apperture so that all neutrons enter the channels (all walls are infinitely thin).
*
* When using zero as the number of channels (nchan), the collimator is continuous,
* whithout shadowing effect.
*
* The component should be positioned at the radius center.
* The component can be made oscillating (usual on diffractometers and TOF
* machines) with the 'roc' parameter.
* The neutron beam outside the collimator angular area is transmitted unaffected.
*
* When used as a focusing collimator, the focusing parameter should be set to 1.
*
* An example of a instrument that uses this collimator can be found in the SALSA instrument,
* in the example folder
*
* Example:
*   Channelled radial collimator with shadow parts
*     Collimator_radial(xwidth=0.015, yheight=.3, length=.35, divergence=40,transmission=1, theta_min=5, theta_max=165, nchan=128, radius=0.9)
*   A continuous radial collimator
*     Collimator_radial(yheight=.3, length=.35, divergence=40,transmission=1, theta_min=5, theta_max=165, radius=0.9)
*
* %P
* INPUT PARAMETERS:
*
* xwidth: [m]               Soller  window width, filled with nslit slits. Use 0 value for continuous collimator.
* yheight: [m]              Collimator height. If  yheight_inner is specified, then this is the outer cylinders height
* length: [m]               Length/Distance between inner and outer slits.
* divergence: [min of arc]  Divergence angle. May also be specified with the nslit parameter. A zero value unactivates component.
* theta_min: [deg]          Minimum Theta angle for the radial setting.
* theta_max: [deg]          Maximum Theta angle for the radial setting.
* nchan: [1]                Number of Soller channels in the theta range. Use 0 value for continuous collimator.
* radius: [m]               Radius of the collimator (to entry window).
*
* Optional parameters
* transmission: [1]         Maximum transmission of Soller (0<=t<=1).
* nslit: [1]                Number of blades composing each Soller. Overrides the divergence parameter.
* roc: [deg]                Amplitude of oscillation of collimator. 0=fixed.
* verbose:     []          Gives additional information.
* approx:      []          Use Soller triangular transmission approximation.
* focusing: [1]             When set allows you to use the collimators for focusing, rather than dispersing.
* yheight_inner [1]         Defines the inner height of the collimator
*
* %E
*******************************************************************************/
DEFINE COMPONENT Collimator_radial

SETTING PARAMETERS (xwidth=0, yheight=.3, length=.35,
divergence=0,transmission=1,
theta_min=5, theta_max=165, nchan=0, radius=1.3, nslit=0,
roc=0, verbose=0, approx=0, focusing = 0, yheight_inner = 0)

DECLARE
%{
double width_of_slit;
double width_of_Soller;
double slit_theta;
%}

INITIALIZE
%{
width_of_slit=0;
width_of_Soller=0;
slit_theta=0;

if (radius <= 0)
    exit(printf("Collimator_radial: %s: incorrect radius=%g\n", NAME_CURRENT_COMP, radius));
  if (length <= 0)
    exit(printf("Collimator_radial: %s: invalid collimator length=%g\n", NAME_CURRENT_COMP, length));
  if (transmission <= 0 || transmission >1)
    exit(printf("Collimator_radial: %s: invalid transmission=%g\n", NAME_CURRENT_COMP, transmission));

  theta_max *= DEG2RAD;
  theta_min *= DEG2RAD;
  roc       *= DEG2RAD;
  divergence*= MIN2RAD;

  if (xwidth && !nchan)
    nchan  = ceil(radius*fabs(theta_max-theta_min)/xwidth);
  else if (!xwidth && nchan)
    xwidth = radius*fabs(theta_max-theta_min)/nchan;

  /* determine total width [m] of Soller channels, containing nslit in xwidth */
  if (nchan) {
		  width_of_Soller = radius*fabs(theta_max-theta_min)/nchan;
  }
  else       width_of_Soller = 0;

  if (!nchan || !xwidth || xwidth > width_of_Soller)
    nchan=xwidth=width_of_Soller=0; /* continuous collimator */

  /* determine width [m] of slits */
  if (divergence) {
    width_of_slit = length*tan(divergence);
    if (xwidth)           /* Soller */
      nslit = ceil(xwidth/width_of_slit);
    else if (!nchan)      /* continuous collimator */
      nslit = ceil(radius*fabs(theta_max-theta_min)/width_of_slit);
  } else {
    if (!nchan && nslit)  /* continuous collimator */
      width_of_slit = radius*fabs(theta_max-theta_min)/nslit;
    else if (nchan && nslit)  /* Soller */
      width_of_slit = xwidth/nslit;
    divergence = atan2(width_of_slit,length);
  }

  if (nslit <= 0)
    printf("Collimator_radial: %s: number of channels must be positive nslit=%g.\n"
                "WARNING            Specify alternatively divergence, xwidth and nchan.\n",
                NAME_CURRENT_COMP, nslit);

  if (verbose && nslit && width_of_slit) {
    printf("Collimator_radial: %s: divergence %g [min] %s"
           ". Total opening [%g:%g] [deg]\n",
           NAME_CURRENT_COMP, divergence*RAD2MIN,
           (roc ? "oscillating" : ""),
           theta_min*RAD2DEG, theta_max*RAD2DEG);
    if (approx)
      printf("    Using triangular approximation model");
    else if (!nchan)
      printf("    Using continuous model");
    else
      printf("    Using %i Soller channels of width %g [cm]",
        (int)nchan, width_of_Soller*100);

    printf(" with %i slits of width %g [mm] pitch %g [deg].\n",
      (int)nslit, width_of_slit*1000, atan2(width_of_slit, radius)*RAD2DEG);
  }
  if (!yheight_inner) yheight_inner = yheight;

%}

TRACE
%{
  double intersect=0;
  double t0, t1, t2, t3;

  if (width_of_slit && nslit) {
    /* determine intersection with inner and outer cylinders */
    intersect=cylinder_intersect(&t0,&t3,x,y,z,vx,vy,vz,radius,yheight_inner);
    if (!intersect) ABSORB;
    else if (t3 > t0 && !focusing) t0 = t3;
	
    intersect=cylinder_intersect(&t1,&t2,x,y,z,vx,vy,vz,radius+length,yheight);
    if (!intersect) ABSORB;
    else if (t2 > t1 && !focusing) t1 = t2;
	
    /* propagate/determine neutron position at ingoing cylinder */
    if ((t0 > 0 && t1 > t0 && !focusing) || (t1 > 0 && t0 > t1 && focusing)) {
      double input_chan=0;
      double input_theta=0, output_theta=0;
      double roc_theta=0;
      double input_slit=0,  output_slit=0;
      if (!focusing)  PROP_DT(t0);
      if (focusing) PROP_DT(t1);

      /* apply ROC oscillation with a linear random distribution */
      if (roc) roc_theta = roc*randpm1()/2; else roc_theta=0;

      /* angle on the initial relevant cylinder */
      input_theta = atan2(x, z) + roc_theta;

      /* check if we are within min/max collimator input bounds */
      if (input_theta >= theta_min && input_theta <= theta_max) {
        SCATTER;
        /* input Soller channel index */
        if (width_of_Soller) {
          input_chan = radius*(input_theta-theta_min)/width_of_Soller;
          input_chan = input_chan-floor(input_chan); /* position within Soller [0:1] */

          /* check if we hit an absorbing housing (between Sollers): ABSORB
           *   total Soller aperture is width_of_Soller,
           *   containg a slit pack  of aperture xwidth
           */
          if (input_chan < (1-xwidth/width_of_Soller)/2
           || input_chan > (1+xwidth/width_of_Soller)/2) ABSORB;
        }

        /* determine input slit index */
        input_slit = floor(input_theta*radius/width_of_slit);

      } else /* neutron missed collimator input range */
        input_theta=4*PI;

      /* propagate to next cylinder */
  
      if (!focusing) PROP_DT(t1-t0);
      if (focusing) PROP_DT(t0-t1);

      /* angle on the outgoing cylinder */
      output_theta = atan2(x, z) + roc_theta;

      /* check if we are within min/max collimator output bounds */
      if (output_theta >= theta_min && output_theta <= theta_max) {
        /* check if we come from sides:   ABSORB */
        if (input_theta > 2*PI) ABSORB; /* input_theta=4*PI when missed input */

        if (approx) {
          double phi=atan2(x, z)-atan2(vx, vz); /* difference between positional slit angle and velocity */
          if (fabs(phi) > divergence)
            ABSORB; /* get outside transmission */
          else
            p *= (1.0 - phi/divergence);
        } else {
          /* check if we have changed slit: ABSORB */
          /* slits are considered radial so that their output size is:
             width_of_slit*(radius+length)/radius and it turns out this the same exp as for input
           */
          output_slit = floor(output_theta*radius/width_of_slit);
          if (input_slit != output_slit) ABSORB;
        }
        SCATTER;
        p *= transmission;

      }
	  else if (focusing) ABSORB;
	  /* else neutron missed collimator output range*/
	  
    } /* else did not encounter collimator cylinders */
  } /* if nslit */

%}

MCDISPLAY
%{
  double Soller_theta;
  double height_inner = yheight/2;
  double height_outer = yheight_inner/2;
  double theta1, theta2;
  double x_in_l,  z_in_l,  x_in_r,  z_in_r;
  double x_out_l, z_out_l, x_out_r, z_out_r;
  int i;

  /* display collimator radial geometry:
     in order to avoid too many lines, we shown main housing and channels
     but no slit */

  if (!nchan || nchan > 20)     nchan=20;
  if (nchan > 64)               nchan=64;
  Soller_theta=fabs(theta_max-theta_min)/nchan; /* angular width of Soller */

  /* draw all channels, which also show housing */
  
  for (i = 0; i < nchan; i++) {

    theta1 = i*Soller_theta+theta_min;
    theta2 = theta1+Soller_theta;

    z_in_l = radius*cos(theta1);
    x_in_l = radius*sin(theta1);
    z_in_r = radius*cos(theta2);
    x_in_r = radius*sin(theta2);

    z_out_l = (radius+length)*cos(theta1);
    x_out_l = (radius+length)*sin(theta1);
    z_out_r = (radius+length)*cos(theta2);
    x_out_r = (radius+length)*sin(theta2);
    /* left side */
    multiline(6,
      x_in_l, -height_outer, z_in_l,
      x_in_l,  height_outer, z_in_l,
      x_out_l, height_inner, z_out_l,
      x_out_l,-height_inner, z_out_l,
      x_in_l, -height_outer, z_in_l,
      x_in_r, -height_outer, z_in_r);
   /* left -> right lines */
   line(x_in_l,   height_outer, z_in_l,  x_in_r,  height_outer, z_in_r);
   line(x_out_l,  height_inner, z_out_l, x_out_r, height_inner, z_out_r);
   line(x_out_l, -height_inner, z_out_l, x_out_r,-height_inner, z_out_r);
  }
  /* remaining bits */
  theta1 = nchan*Soller_theta+theta_min;
  z_in_l = radius*cos(theta1);
  x_in_l = radius*sin(theta1);
  z_out_l = (radius+length)*cos(theta1);
  x_out_l = (radius+length)*sin(theta1);
  multiline(5,
      x_in_l, -height_outer, z_in_l,
      x_in_l,  height_outer, z_in_l,
      x_out_l, height_inner, z_out_l,
      x_out_l,-height_inner, z_out_l,
      x_in_l, -height_outer, z_in_l);
%}

END