File: Monitor_nD.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 (638 lines) | stat: -rw-r--r-- 26,722 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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2002, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Monitor_nD
*
* %Identification
* Written by: <a href="mailto:farhi@ill.fr">Emmanuel Farhi</a>
* Date: 14th Feb 2000.
* Origin: <a href="http://www.ill.fr">ILL</a>
* Release: McStas 1.6
* Version: $Revision$
* Modified by: EF, 29th Feb 2000 : added more options, monitor shape, theta, phi
* Modified by: EF, 01st Feb 2001 : PreMonitor for correlation studies (0.13.6)
* Modified by: EF, 5th  Apr 2001 : use global functions (0.14) compile faster
* Modified by: EF, 23th Jul 2001 : log of signal, init arrays to 0, box (0.15)
* Modified by: EF, 04th Sep 2001 : log/abs of variables (0.16)
* Modified by: EF, 24th Oct 2001 : capture flux  [p*lambda/1.7985] (0.16.3)
* Modified by: EF, 27th Aug 2002 : monitor a variable in place of I (0.16.5)
* Modified by: EF, 25th Oct 2002 : banana, and auto for each variable (0.16.5)
*
* This component is a general Monitor that can output 0/1/2D signals
* (Intensity or signal vs. [something] and vs. [something] ...)
*
* %Description
* This component is a general Monitor that can output 0/1/2D signals
* It can produce many 1D signals (one for any variable specified in
* option list), or a single 2D output (two variables correlation).
* Also, an additional 'list' of neutron events can be produced.
* By default, monitor is square (in x/y plane). A disk shape is also possible
* The 'cylinder' and 'banana' option will change that for a banana shape
* The 'sphere' option simulates spherical detector. The 'box' is a box.
* The cylinder, sphere and banana should be centered on the scattering point.
* The monitored flux may be per monitor unit area, and weighted by
* a lambda/lambda(2200m/s) factor to obtain standard integrated capture flux.
* In normal configuration, the Monitor_nD measures the current parameters
* of the neutron that is beeing detected. But a PreMonitor_nD component can
* be used in order to study correlations between a neutron being detected in
* a Monitor_nD place, and given parameters that are monitored elsewhere
* (at <b>PreMonitor_nD</b>).
* The monitor can also act as a 3He gas detector, taking into account the
* detection efficiency.
*
* The 'bins' and 'limits' modifiers are to be used after each variable,
* and 'auto','log' and 'abs' come before it. (eg: auto abs log hdiv bins=10
* limits=[-5 5]) When placed after all variables,  these two latter modifiers
* apply to the signal (e.g. intensity). Unknown keywords are ignored.
* If no limits are specified for a given observable, reasonable defaults will be
* applied. Note that these implicit limits are <b>even</b> applied in list mode. 
*
* <b>Implicit limits for typical variables:</b>
* (consult monitor_nd-lib.c if you don't find your variable here)
* x, y, z: Derived from detection-object geometry
* k: [0 10] Angs-1
* v: [0 1e6] m/s
* t: [0 1] s
* p: [0 FLT_MAX] in intensity-units
* vx, vy: [-1000 1000] m/s
* vz: [0 10000] m/s
* kx, ky: [-1 1] Angs-1
* kz: [-10 10] Angs-1
* energy, omega: [0 100] meV
* lambda,wavelength: [0 100] Angs
* sx, sy, sz: [-1 1] in polarisation-units
* angle: [-50 50] deg
* divergence, vdiv, hdiv, xdiv, ydiv: [-5 5] deg
* longitude, lattitude: [-180 180] deg
* neutron: [0 simulaton_ncount]
* id, pixel id: [0 FLT_MAX]
* uservars u1,u2,u3: [-1e10 1e10]
*
* In the case of multiple components at the same position, the 'parallel'
* keyword must be used in each instance instead of defining a GROUP.
*
* <b>Possible options are</b>
* Variables to record:
*     kx ky kz k wavevector [Angs-1] Wavevector on x,y,z and norm
*     vx vy vz v            [m/s]    Velocity on x,y,z and norm
*     x y z radius          [m]      Distance, Position and norm
*     xy, yz, xz            [m]      Radial position in xy, yz and xz plane
*     kxy kyz kxz           [Angs-1] Radial wavevector in xy, yz and xz plane
*     vxy vyz vxz           [m/s]    Radial velocity in xy, yz and xz plane
*     t time                [s]      Time of Flight
*     energy omega          [meV]    energy of neutron
*     lambda wavelength     [Angs]   wavelength of neutron
*     sx sy sz              [1]      Spin
*     vdiv ydiv dy          [deg]    vertical divergence (y)
*     hdiv divergence xdiv  [deg]    horizontal divergence (x)
*     angle                 [deg]    divergence from <z> direction
*     theta longitude       [deg]    longitude (x/z) for sphere and cylinder
*     phi   lattitude       [deg]    lattitude (y/z) for sphere and cylinder
*
*     user user1            will monitor the [Mon_Name]_Vars.UserVariable{1|2|3}
*     user2 user3           to be assigned in an other component (see below)
*
*     p intensity flux      [n/s  or  n/cm^2/s]
*     ncounts n neutron     [1]      neutron ID, i.e current event index
*     pixel id              [1]      pixelID in histogram made of preceeding vars, e.g. 'theta y'. To set an offset PixelID use the 'min=value' keyword. Sets event mode.
*
* <b>Other options keywords are:</b>
*     abs                       Will monitor the abs of the following variable or of the signal (if used after all variables)
*     auto                      Automatically set detector limits for one/all
*     all  {limits|bins|auto}   To set all limits or bins values or auto mode
*     binary {float|double}     with 'source' option, saves in compact files
*     bins=[bins=20]            Number of bins in the detector along dimension
*     borders                   To also count off-limits neutrons (X < min or X > max)
*     capture                   weight by lambda/lambda(2200m/s) capture flux
*     file=string               Detector image file name. default is component name, plus date and variable extension.
*     incoming                  Monitor incoming beam in non flat det
*     limits=[min max]          Lower/Upper limits for axes (see up for the variable unit)
*     list=[counts=1000] or all For a long file of neutron characteristics with [counts] or all events
*     log                       Will monitor the log of the following variable or of the signal (if used after all variables)
*     min=[min_value]           Same as limits, but only sets the min or max
*     max=[max_value]
*     multiple                  Create multiple independant 1D monitors files
*     no or not                 Revert next option
*     outgoing                  Monitor outgoing beam (default)
*     parallel                  Use this option when the next component is at the same position (parallel components)
*     per cm2                   Intensity will be per cm^2 (detector area). Displays beam section.
*     per steradian             Displays beam solid angle in steradian
*     premonitor                Will monitor neutron parameters stored previously with <b>PreMonitor_nD</b>.
*     signal=[var]              Will monitor [var] instead of usual intensity
*     slit or absorb            Absorb neutrons that are out detector
*     source                    The monitor will save neutron states
*     unactivate                To unactivate detector (0D detector)
*     verbose                   To display additional informations
*     3He_pressure=[3 in bars]  The 3He gas pressure in detector. 3He_pressure=0 is perfect detector (default)
*
* Detector shape options (specified as xwidth,yheight,zdepth or x/y/z/min/max)
*     box                       Box of size xwidth, yheight, zdepth.
*     cylinder                  To get a cylindrical monitor (diameter is xwidth or set radius, height is yheight).
*     banana                    Same as cylinder, without top/bottom, on restricted angular area; use theta variable with limits to define arc. (diameter is xwidth or set radius, height is yheight).
*     disk                      Disk flat xy monitor. diameter is xwidth.
*     sphere                    To get a spherical monitor (e.g. a 4PI) (diameter is xwidth or set radius).
*     square                    Square flat xy monitor (xwidth, yheight).
*     previous                  The monitor uses PREVIOUS component as detector surface. Or use 'geometry' parameter to specify any PLY/OFF geometry file.
*
* <b>EXAMPLES:</b>
* <ul>
* <li>MyMon = Monitor_nD(xwidth = 0.1, yheight = 0.1, zdepth = 0,
* &emsp;&emsp;options = "intensity per cm2 angle,limits=[-5 5] bins=10,with
* &emsp;&emsp;borders, file = mon1");
*                  will monitor neutron angle from [z] axis, between -5
*                  and 5 degrees, in 10 bins, into "mon1.A" output 1D file
*
*  <li> options = "sphere theta phi outgoing"  
*       for a sphere PSD detector (out beam)  and saves into file "MyMon_[Date_ID].th_ph"
*
*  <li> options = "banana, theta limits=[10,130], bins=120, y" 
*       a theta/height banana detector
*
*  <li> options = "angle radius all auto" 
*       is a 2D monitor with automatic limits
*
*  <li> options = "list=1000 kx ky kz energy" 
*       records 1000 neutron event in a file
*
*  <li> options = "multiple kx ky kz, auto abs log t, and list all neutrons"
*        makes 4 output 1D files and produces a complete list for all neutrons
*        and monitor log(abs(tof)) within automatic limits (for t)
*
*  <li> options = "theta y, sphere, pixel min=100"
*        a 4pi detector which outputs an event list with pixelID from the actual
*        detector surface, starting from index 100.
*
* </ul>
* To dynamically define a number of bins, or limits:
*   Use in DECLARE:    char op[256];
*   Use in INITIALIZE: sprintf(op, "lambda limits=[%g %g], bins=%i", lmin, lmax, lbin);
*   Use in TRACE:      Monitor_nD(... options=op ...)
*
* <b>How to monitor any instrument/component variable into a Monitor_nD</b>
* Suppose you want to monitor a variable 'age' which you assign somwhere in
* the instrument:
*      COMPONENT MyMonitor = Monitor_nD(
*       xwidth = 0.1, yheight = 0.1,
*       user1="age", username1="Age of the Captain [years]",
*       options="user1, auto")
*      AT ...
*
* See also the example in <a href="PreMonitor_nD.html">PreMonitor_nD</a> to
* monitor neutron parameters cross-correlations.
*
* %BUGS
* The 'auto' option for guessing optimal variable bounds should NOT be used with MPI
* as each process may use different limits.
*
* %Parameters
* INPUT PARAMETERS:
*
* xwidth: [m]            Width of detector.
* yheight: [m]           Height of detector.
* zdepth: [m]            Thickness of detector (z).
* radius: [m]            Radius of sphere/banana shape monitor
* options: [str]         String that specifies the configuration of the monitor. The general syntax is "[x] options..." (see <b>Descr.</b>).
*
* Optional input parameters (override xwidth yheight zdepth):
* xmin: [m]              Lower x bound of opening
* xmax: [m]              Upper x bound of opening
* ymin: [m]              Lower y bound of opening
* ymax: [m]              Upper y bound of opening
* zmin: [m]              Lower z bound of opening
* zmax: [m]              Upper z bound of opening
* filename: [str]        Output file name (overrides file=XX option).
* bins: [1]              Number of bins to force for all variables. Use 'bins' keyword in 'options' for heterogeneous bins
* min: [u]               Minimum range value to force for all variables. Use 'min' or 'limits' keyword in 'options' for other limits
* max: [u]               Maximum range value to force for all variables. Use 'max' or 'limits' keyword in 'options' for other limits
* user1: [str]           Variable name of USERVAR to be monitored by user1.
* user2: [str]           Variable name of USERVAR to be monitored by user2.
* user3: [str]           Variable name of USERVAR to be monitored by user3.
* username1: [str]       Name assigned to User1
* username2: [str]       Name assigned to User2
* username3: [str]       Name assigned to User3
* restore_neutron: [0|1] If set, the monitor does not influence the neutron state. Equivalent to setting the 'parallel' option.
* geometry: [str]        Name of an OFF file to specify a complex geometry detector
* nowritefile: [1]      If set, monitor will skip writing to disk
*
* CALCULATED PARAMETERS:
*
* DEFS: [struct]         structure containing Monitor_nD Defines
* Vars: [struct]         structure containing Monitor_nD variables
*
* %Link
* <a href="PreMonitor_nD.html">PreMonitor_nD</a>
*
* %End
******************************************************************************/
DEFINE COMPONENT Monitor_nD

SETTING PARAMETERS (
  string user1="", string user2="", string user3="",
  xwidth=0, yheight=0, zdepth=0,
  xmin=0, xmax=0, ymin=0, ymax=0, zmin=0, zmax=0,
  int bins=0, min=-1e40, max=1e40, int restore_neutron=0, radius=0,
  string options="NULL", string filename="NULL",string geometry="NULL", int nowritefile=0,
  string username1="NULL", string username2="NULL", string username3="NULL"
)
/* these are protected C variables */

/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */

SHARE
%{
  %include "monitor_nd-lib"
  %include "read_table-lib"
  %include "interoff-lib"
%}

DECLARE
%{
  MonitornD_Defines_type DEFS;
  MonitornD_Variables_type Vars;
  MCDETECTOR detector;
  off_struct offdata;
%}

INITIALIZE
%{
  char tmp[CHAR_BUF_LENGTH];
  strcpy(Vars.compcurname, NAME_CURRENT_COMP);
  if (options != NULL)
    strncpy(Vars.option, options, CHAR_BUF_LENGTH);
  else {
    strcpy(Vars.option, "x y");
    printf("Monitor_nD: %s has no option specified. Setting to PSD ('x y') monitor.\n", NAME_CURRENT_COMP);
  }
  Vars.compcurpos = POS_A_CURRENT_COMP;

  if (strstr(Vars.option, "source"))
    strcat(Vars.option, " list, x y z vx vy vz t sx sy sz ");

  if (bins) { sprintf(tmp, " all bins=%ld ", (long)bins); strcat(Vars.option, tmp); }
  if (min > -FLT_MAX && max < FLT_MAX) { sprintf(tmp, " all limits=[%g %g]", min, max); strcat(Vars.option, tmp); }
  else if (min > -FLT_MAX) { sprintf(tmp, " all min=%g", min); strcat(Vars.option, tmp); }
  else if (max <  FLT_MAX) { sprintf(tmp, " all max=%g", max); strcat(Vars.option, tmp); }

  /* transfer, "zero", and check username- and user variable strings to Vars struct*/
  strncpy(Vars.UserName1,
    username1 && strlen(username1) && strcmp(username1, "0") && strcmp(username1, "NULL") ?
    username1 : "", 128);
  strncpy(Vars.UserName2,
    username2 && strlen(username2) && strcmp(username2, "0") && strcmp(username2, "NULL") ?
    username2 : "", 128);
  strncpy(Vars.UserName3,
    username3 && strlen(username3) && strcmp(username3, "0") && strcmp(username3, "NULL") ?
    username3 : "", 128);
  if(user1 && strlen(user1) && strcmp(user1, "0") && strcmp(user1, "NULL")){
    strncpy(Vars.UserVariable1,user1,128);
    int fail;_class_particle testparticle;
    particle_getvar(&testparticle,Vars.UserVariable1,&fail);
    if(fail){
      fprintf(stderr,"Warning (%s): user1=%s is unknown. The signal will not be resolved - this is likely not what you intended.\n",NAME_CURRENT_COMP,user1);
    }
  }
  if(user2 && strlen(user2) && strcmp(user2, "0") && strcmp(user2, "NULL")){
    strncpy(Vars.UserVariable2,user2,128);
    int fail;_class_particle testparticle;
    particle_getvar(&testparticle,Vars.UserVariable2,&fail);
    if(fail){
      fprintf(stderr,"Warning (%s): user2=%s is unknown. The signal will not be resolved - this is likely not what you intended.\n",NAME_CURRENT_COMP,user2);
    }
  }
  if(user3 && strlen(user3) && strcmp(user3, "0") && strcmp(user3, "NULL")){
    strncpy(Vars.UserVariable3,user3,128);
    int fail;_class_particle testparticle;
    particle_getvar(&testparticle,Vars.UserVariable3,&fail);
    if(fail){
      fprintf(stderr,"Warning (%s): user3=%s is unknown. The signal will not be resolved - this is likely not what you intended.\n",NAME_CURRENT_COMP,user3);
    }
  }
 
  /*sanitize parameters set for curved shapes*/
  if(strstr(Vars.option,"cylinder") || strstr(Vars.option,"banana") || strstr(Vars.option,"sphere")){
    /*this _is_ an explicit curved shape. Should have a radius. Inherit from xwidth or zdepth (diameters), x has precedence.*/
    if (!radius){
      if(xwidth){
	radius=xwidth/2.0;
      }else{
	radius=zdepth/2.0;
      }
    }else{
      xwidth=2*radius;
    }
    if(!yheight){
      /*if not set - use the diameter as height for the curved object. This will likely only happen for spheres*/
      yheight=2*radius;
    }
  }else if (radius) {
    /*radius is set - this must be a curved shape. Infer shape from yheight, and set remaining values
     (xwidth etc. They are used inside monitor_nd-lib.*/
    xwidth = zdepth = 2*radius;
    if (yheight){
      /*a height is given (and no shape explitly set - assume cylinder*/
      strcat(Vars.option, " banana");
    }else {
      strcat(Vars.option, " sphere");
      yheight=2*radius;
    }
  }

  int offflag=0;
  if (geometry && strlen(geometry) && strcmp(geometry,"0") && strcmp(geometry, "NULL")) {
    #ifndef USE_OFF
    fprintf(stderr,"Error: You are attempting to use an OFF geometry without -DUSE_OFF. You will need to recompile with that define set!\n");
    exit(-1);
    #else
    if (!off_init(  geometry, xwidth, yheight, zdepth, 1, &offdata )) {
      printf("Monitor_nD: %s could not initiate the OFF geometry %s. \n"
             "            Defaulting to normal Monitor dimensions.\n",
             NAME_CURRENT_COMP, geometry);
      strcpy(geometry, "");
    } else {
      offflag=1;
    }
    #endif
  }

  if (!radius && !xwidth && !yheight && !zdepth && !xmin && !xmax && !ymin && !ymax &&
    !strstr(Vars.option, "previous") && (!geometry || !strlen(geometry)))
    exit(printf("Monitor_nD: %s has no dimension specified. Aborting (radius, xwidth, yheight, zdepth, previous, geometry).\n", NAME_CURRENT_COMP));

  Monitor_nD_Init(&DEFS, &Vars, xwidth, yheight, zdepth, xmin,xmax,ymin,ymax,zmin,zmax,offflag);

  if (Vars.Flag_OFF) {
    offdata.mantidflag=Vars.Flag_mantid;
    offdata.mantidoffset=Vars.Coord_Min[Vars.Coord_Number-1];
  }


  if (filename && strlen(filename) && strcmp(filename,"NULL") && strcmp(filename,"0"))
    strncpy(Vars.Mon_File, filename, 128);

  /* check if user given filename with ext will be used more than once */
  if ( ((Vars.Flag_Multiple && Vars.Coord_Number > 1) || Vars.Flag_List) && strchr(Vars.Mon_File,'.') )
  { char *XY; XY = strrchr(Vars.Mon_File,'.'); *XY='_'; }

  if (restore_neutron) Vars.Flag_parallel=1;
  detector.m = 0;

#ifdef USE_MPI
MPI_MASTER(
  if (strstr(Vars.option, "auto") && mpi_node_count > 1)
    printf("Monitor_nD: %s is using automatic limits option 'auto' together with MPI.\n"
           "WARNING     this may create incorrect distributions (but integrated flux will be right).\n", NAME_CURRENT_COMP);
);
#else
#ifdef OPENACC
  if (strstr(Vars.option, "auto"))
    printf("Monitor_nD: %s is requesting automatic limits option 'auto' together with OpenACC.\n"
           "WARNING     this feature is NOT supported using OpenACC and has been disabled!\n", NAME_CURRENT_COMP);
#endif
#endif

%}

TRACE
%{
  double  transmit_he3=1.0;
  double  multiplier_capture=1.0;
  double  t0 = 0;
  double  t1 = 0;
  int     pp;
  int     intersect   = 0;
  char    Flag_Restore = 0;

  #ifdef OPENACC
  #ifdef USE_OFF
  off_struct thread_offdata = offdata;
  #endif
  #else
  #define thread_offdata offdata
  #endif
  
  /* this is done automatically
    STORE_NEUTRON(INDEX_CURRENT_COMP, x, y, z, vx, vy, vz, t, sx, sy, sz, p);
  */
  #ifdef USE_OFF
  if (geometry && strlen(geometry) && strcmp(geometry,"0") && strcmp(geometry, "NULL"))
  {
    /* determine intersections with object */
    intersect = off_intersect_all(&t0, &t1, NULL, NULL,
				  x,y,z, vx, vy, vz, 0, 0, 0, &thread_offdata );
    if (Vars.Flag_mantid) {
      if(intersect) {
        Vars.OFF_polyidx=thread_offdata.nextintersect;
      } else {
        Vars.OFF_polyidx=-1;
      }
    }
  }
  else
  #endif
    if ( (abs(Vars.Flag_Shape) == DEFS.SHAPE_SQUARE)
            || (abs(Vars.Flag_Shape) == DEFS.SHAPE_DISK) ) /* square xy or disk xy */
  {
    // propagate to xy plane and find intersection
    // make sure the event is recoverable afterwards
    t0 = t;
    ALLOW_BACKPROP;
    PROP_Z0;
    if ( (t>=t0) && (z==0.0) ) // forward propagation to xy plane was successful
    {
      if (abs(Vars.Flag_Shape) == DEFS.SHAPE_SQUARE)
      {
        // square xy
        intersect = (x>=Vars.mxmin && x<=Vars.mxmax && y>=Vars.mymin && y<=Vars.mymax);
      }
      else
      {
        // disk xy
        intersect = (SQR(x) + SQR(y)) <= SQR(Vars.Sphere_Radius);
      }
    }
    else
    {
      intersect=0;
    }
  }
  else if (abs(Vars.Flag_Shape) == DEFS.SHAPE_SPHERE) /* sphere */
  {
    intersect = sphere_intersect(&t0, &t1, x, y, z, vx, vy, vz, Vars.Sphere_Radius);
  /*      intersect = (intersect && t0 > 0); */
  }
  else if ((abs(Vars.Flag_Shape) == DEFS.SHAPE_CYLIND) || (abs(Vars.Flag_Shape) == DEFS.SHAPE_BANANA)) /* cylinder */
  {
    intersect = cylinder_intersect(&t0, &t1, x, y, z, vx, vy, vz, Vars.Sphere_Radius, Vars.Cylinder_Height);
  }
  else if (abs(Vars.Flag_Shape) == DEFS.SHAPE_BOX) /* box */
  {
    intersect = box_intersect(&t0, &t1, x, y, z, vx, vy, vz,
                              fabs(Vars.mxmax-Vars.mxmin), fabs(Vars.mymax-Vars.mymin), fabs(Vars.mzmax-Vars.mzmin));
  }
  else if (abs(Vars.Flag_Shape) == DEFS.SHAPE_PREVIOUS) /* previous comp */
  { intersect = 1; }

  if (intersect)
  {
    if ((abs(Vars.Flag_Shape) == DEFS.SHAPE_SPHERE) || (abs(Vars.Flag_Shape) == DEFS.SHAPE_CYLIND)
     || (abs(Vars.Flag_Shape) == DEFS.SHAPE_BOX) || (abs(Vars.Flag_Shape) == DEFS.SHAPE_BANANA)
     || (geometry && strlen(geometry) && strcmp(geometry,"0") && strcmp(geometry, "NULL")) )
    {
      /* check if we have to remove the top/bottom with BANANA shape */
        if (abs(Vars.Flag_Shape) == DEFS.SHAPE_BANANA) {
            if (intersect == 1) { // Entered and left through sides
                if (t0 < 0 && t1 > 0) {
                    t0 = t;  /* neutron was already inside ! */
                }
                if (t1 < 0 && t0 > 0) { /* neutron exit before entering !! */
                    t1 = t;
                }
                /* t0 is now time of incoming intersection with the detection area */
                if ((Vars.Flag_Shape < 0) && (t1 > 0)) {
                    PROP_DT(t1); /* t1 outgoing beam */
                } else {
                    PROP_DT(t0); /* t0 incoming beam */
                }
            } else if (intersect == 3 || intersect == 5) { // Entered from top or bottom, left through side
                if ((Vars.Flag_Shape < 0) && (t1 > 0)) {
                    PROP_DT(t1); /* t1 outgoing beam */
                } else {
                    intersect=0;
                    Flag_Restore=1;
                }
            } else if (intersect == 9 || intersect == 17) { // Entered through side, left from top or bottom
                if ((Vars.Flag_Shape < 0) && (t1 > 0)) {
                    intersect=0;
                    Flag_Restore=1;
                } else {
                    PROP_DT(t0); /* t0 incoming beam */
                }
            } else if (intersect == 13 || intersect == 19) { // Went through top/bottom on entry and exit
                intersect=0;
                Flag_Restore=1;
            } else {
                printf("Cylinder_intersect returned unexpected value %i\n", intersect);
            }
        } else {
            // All other shapes than the BANANA 
            if (t0 < 0 && t1 > 0)
              t0 = t;  /* neutron was already inside ! */
            if (t1 < 0 && t0 > 0) /* neutron exit before entering !! */
              t1 = t;
            /* t0 is now time of incoming intersection with the detection area */
            if ((Vars.Flag_Shape < 0) && (t1 > 0))
              PROP_DT(t1); /* t1 outgoing beam */
            else
              PROP_DT(t0); /* t0 incoming beam */
        }
      
      /* Final test if we are on lid / bottom of banana/sphere */
      if (abs(Vars.Flag_Shape) == DEFS.SHAPE_BANANA || abs(Vars.Flag_Shape) == DEFS.SHAPE_SPHERE) {
        if (Vars.Cylinder_Height && fabs(y) >= Vars.Cylinder_Height/2 - FLT_EPSILON) {
          intersect=0;
          Flag_Restore=1;
        }
      }
    }
  }

  if (intersect)
  {
    /* Now get the data to monitor: current or keep from PreMonitor */
/*    if (Vars.Flag_UsePreMonitor != 1)*/
/*    {*/
/*      Vars.cp  = p;*/
/*      Vars.cx  = x;*/
/*      Vars.cvx = vx;*/
/*      Vars.csx = sx;*/
/*      Vars.cy  = y;*/
/*      Vars.cvy = vy;*/
/*      Vars.csy = sy;*/
/*      Vars.cz  = z;*/
/*      Vars.cvz = vz;*/
/*      Vars.csz = sz;*/
/*      Vars.ct  = t;*/
/*    }*/

    if ((Vars.He3_pressure > 0) && (t1 != t0) && ((abs(Vars.Flag_Shape) == DEFS.SHAPE_SPHERE) || (abs(Vars.Flag_Shape) == DEFS.SHAPE_CYLIND) || (abs(Vars.Flag_Shape) == DEFS.SHAPE_BOX)))
    {
      transmit_he3 = exp(-7.417*Vars.He3_pressure*fabs(t1-t0)*2*PI*K2V);
      /* will monitor the absorbed part */
      p = p * (1-transmit_he3);
    }

    if (Vars.Flag_capture)
    {
      multiplier_capture = V2K*sqrt(vx*vx+vy*vy+vz*vz);
      if (multiplier_capture != 0) multiplier_capture = 2*PI/multiplier_capture; /* lambda. lambda(2200 m/2) = 1.7985 Angs  */
      p = p * multiplier_capture/1.7985;
    }

    pp = Monitor_nD_Trace(&DEFS, &Vars, _particle);
    if (pp==0.0)
    {
      ABSORB;
    }
    else if(pp==1)
    {
      SCATTER;
    }

    /*set weight to undetected part if capture and/or he3_pressure*/
    if (Vars.He3_pressure > 0){
      /* after monitor, only remains 1-p_detect */
      p = p * transmit_he3/(1.0-transmit_he3);
    }

    if (Vars.Flag_capture){
      p = p / multiplier_capture*1.7985;
    }

    if (Vars.Flag_parallel) /* back to neutron state before detection */
      Flag_Restore = 1;
  } /* end if intersection */
  else {
    if (Vars.Flag_Absorb && !Vars.Flag_parallel)
    {
      // restore neutron ray before absorbing for correct mcdisplay
      RESTORE_NEUTRON(INDEX_CURRENT_COMP, x, y, z, vx, vy, vz, t, sx, sy, sz, p);
      ABSORB;
    }
    else Flag_Restore = 1;  /* no intersection, back to previous state */
  }

  if (Flag_Restore)
  {
    RESTORE_NEUTRON(INDEX_CURRENT_COMP, x, y, z, vx, vy, vz, t, sx, sy, sz, p);
  }
%}

SAVE
%{
if (!nowritefile) {
  /* save results, but do not free pointers */
  detector = Monitor_nD_Save(&DEFS, &Vars);
}
%}

FINALLY
%{
  /* free pointers */
  Monitor_nD_Finally(&DEFS, &Vars);
%}

MCDISPLAY
%{
  if (geometry && strlen(geometry) && strcmp(geometry,"0") && strcmp(geometry, "NULL"))
  {
    off_display(offdata);
  } else {
    Monitor_nD_McDisplay(&DEFS, &Vars);
  }
%}

END