1/*******************************************************************************
2*
3*  McStas, neutron ray-tracing package
4*  Copyright(C) 2007 Risoe National Laboratory.
5*
6* %I
7* Written by: Mads Bertelsen
8* Date: 20.08.15
9* Origin: Svanevej 19
10*
11* A sample component to separate geometry and phsysics
12*
13* %D
14* Part of the Union components, a set of components that work together and thus
15*  sperates geometry and physics within McStas.
16* The use of this component requires other components to be used.
17*
18* 1) One specifies a number of processes using process components
19* 2) These are gathered into material definitions using Union_make_material
20* 3) Geometries are placed using Union_box/cylinder/sphere, assigned a material
21* 4) A Union_master component placed after all of the above
22*
23* Only in step 4 will any simulation happen, and per default all geometries
24*  defined before this master, but after the previous will be simulated here.
25*
26* There is a dedicated manual available for the Union_components
27*
28* This logger logs a 2D projection of the scattering vector, q in the lab frame.
29*
30* A logger will log something for scattering events happening to certain volumes,
31*  which are specified in the target_geometry string. By leaving it blank, all
32*  geometries are logged, even the ones not defined at this point in the
33*  instrument file. If a list og target_geometries is selected, one can further
34*  narrow the events logged by providing a list of process names in target_process
35*  which need to correspond with names of defined Union_process components.
36*
37* To use the logger_conditional_extend function, set it to some integer value n
38*  and make and extend section to the master component that runs the geometry.
39* In this extend function, logger_conditional_extend[n] is 1 if the conditional
40*  stack evaluated to true, 0 if not. This way one can check what rays is logged
41*  using regular McStas monitors. Only works if a conditional is applied to this
42*  logger.
43*
44* %P
45* INPUT PARAMETERS:
46* Q_direction_1: [string]    Q direction for first axis ("x", "y" or "z")
47* Q1_max: [1]                histogram boundery, max q value for first axis
48* Q1_min: [1]                histogram boundery, min q value for first axis
49* n1: [1]                    number of bins for first axis
50* Q_direction_2: [string]    Q direction for second axis ("x", "y" or "z")
51* Q2_max: [1]                histogram boundery, max q value for second axis
52* Q2_min: [1]                histogram boundery, min q value for second axis
53* n2: [1]                    number of bins for second axis
54* target_geometry: [string]  Comma seperated list of geometry names that will be logged, leave empty for all volumes (even not defined yet)
55* target_process: [string]   Comma seperated names of physical processes, if volumes are selected, one can select Union_process names
56* order_total: [1]           Only log rays that scatter for the n'th time, 0 for all orders
57* order_volume: [1]          Only log rays that scatter for the n'th time in the same geometry
58* order_volume_process [1] Only log rays that scatter for the n'th time in the same geometry, uwsing the same process
59* logger_conditional_extend_index [1] If a conditional is used with this logger, the result of each conditional calculation can be made available in extend as a array called "logger_conditional_extend", and one would then acces logger_conditional_extend[n] if logger_conditional_extend_index is set to n
60*
61* OUTPUT PARAMETERS:
62*
63* GLOBAL PARAMETERS:
64*
65* %L
66*
67* %E
68******************************************************************************/
69
70DEFINE COMPONENT Union_logger_2DQ
71DEFINITION PARAMETERS (n1=90, n2=90)
72SETTING PARAMETERS(string target_geometry="NULL",string target_process="NULL",Q1_min=-5,Q1_max=5,Q2_min=-5,Q2_max=5,string Q_direction_1="x", string Q_direction_2="z",string filename="NULL", order_total=0,order_volume=0,order_volume_process=0,logger_conditional_extend_index=-1)
73OUTPUT PARAMETERS (loop_index,accepted_processes,accepted_volumes,logger_list_element,this_logger,this_storage,loggers_on_target_volume,target_volume,logger_conditional_extend_index)
74
75/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */
76
77SHARE
78%{
79#ifndef Union
80#define Union $Revision: 0.8 $
81
82#include "Union_functions.c"
83#include "Union_initialization.c"
84
85#endif
86
87struct temp_2DQ_data_element_struct {
88int index_1;
89int index_2;
90double weight;
91};
92
93struct temp_2DQ_data_struct {
94int num_elements;
95int allocated_elements;
96struct temp_2DQ_data_element_struct *elements;
97};
98
99struct a_2DQ_storage_struct {
100struct Detector_2D_struct Detector_2D;
101struct temp_2DQ_data_struct temp_2DQ_data;
102int dim_1_choice;
103int dim_2_choice;
104int order;
105int order_in_this_volume;
106int order_process_in_this_volume;
107};
108
109// record_to_temp
110// Would be nice if x y z, k_new and k_old were all coords
111void record_to_temp_2DQ(Coords *position, double *k_new, double *k_old, double p, double p_old, double time, int scattered_in_this_volume, int scattered_in_this_volume_by_this_process, int total_number_of_scattering_events, struct logger_struct *logger, struct logger_with_data_struct *logger_with_data_array) {
112
113  struct a_2DQ_storage_struct *storage;
114  storage = logger->data_union.p_2DQ_storage;
115
116  int add_point = 1;
117
118  if (storage->order != 0) {
119    if (storage->order - 1 == total_number_of_scattering_events)
120      add_point = 1;
121    else
122      add_point = 0;
123  }
124
125  if (storage->order_in_this_volume != 0) {
126    if (storage->order_in_this_volume - 1 == scattered_in_this_volume)
127      add_point = 1;
128    else
129      add_point = 0;
130  }
131
132  if (storage->order_process_in_this_volume != 0) {
133    if (storage->order_process_in_this_volume - 1 == scattered_in_this_volume_by_this_process)
134      add_point = 1;
135    else
136      add_point = 0;
137  }
138
139  if (add_point == 1) {
140
141    double q1,q2;
142
143    // dim_1_choice = 0 for x, 1 for y, 2 for z. Done in initialize from input. "x" "y" "z".
144    q1 = k_old[storage->dim_1_choice] - k_new[storage->dim_1_choice];
145    q2 = k_old[storage->dim_2_choice] - k_new[storage->dim_2_choice];
146
147    int i,j;
148
149    // Find bin in histogram
150    if (q1>storage->Detector_2D.D1min && q1<storage->Detector_2D.D1max && q2>storage->Detector_2D.D2min && q2<storage->Detector_2D.D2max) {
151      i = floor((q1 - storage->Detector_2D.D1min)*storage->Detector_2D.bins_1/(storage->Detector_2D.D1max - storage->Detector_2D.D1min));
152      j = floor((q2 - storage->Detector_2D.D2min)*storage->Detector_2D.bins_2/(storage->Detector_2D.D2max - storage->Detector_2D.D2min));
153
154      // Save bin in histogram to temp (may need to allocate more memory)
155      int index;
156      //printf("number of data points used: %d space allocated for %d data points. \n",storage->temp_2DQ_data.num_elements,storage->temp_2DQ_data.allocated_elements);
157
158      if (storage->temp_2DQ_data.num_elements < storage->temp_2DQ_data.allocated_elements) {
159        storage->temp_2DQ_data.elements[storage->temp_2DQ_data.num_elements].index_1 = i;
160        storage->temp_2DQ_data.elements[storage->temp_2DQ_data.num_elements].index_2 = j;
161        storage->temp_2DQ_data.elements[storage->temp_2DQ_data.num_elements++].weight = p;
162      } else {
163        // No more space, need to allocate a larger buffer for this logger. Wish I had generics.
164
165        // copy current data to temp
166        struct temp_2DQ_data_struct temporary_storage;
167        temporary_storage.num_elements = storage->temp_2DQ_data.num_elements;
168        temporary_storage.elements = malloc(temporary_storage.num_elements*sizeof(struct temp_2DQ_data_element_struct));
169
170        for (index=0;index<storage->temp_2DQ_data.num_elements;index++) {
171          temporary_storage.elements[index].index_1 = storage->temp_2DQ_data.elements[index].index_1;
172          temporary_storage.elements[index].index_2 = storage->temp_2DQ_data.elements[index].index_2;
173          temporary_storage.elements[index].weight = storage->temp_2DQ_data.elements[index].weight;
174        }
175
176        // free current data
177        free(storage->temp_2DQ_data.elements);
178
179        // allocate larger array (10 larger)
180        storage->temp_2DQ_data.allocated_elements = 10 + storage->temp_2DQ_data.num_elements;
181        storage->temp_2DQ_data.elements = malloc(storage->temp_2DQ_data.allocated_elements*sizeof(struct temp_2DQ_data_element_struct));
182
183        // copy back from temp
184        for (index=0;index<storage->temp_2DQ_data.num_elements;index++) {
185          storage->temp_2DQ_data.elements[index].index_1 = temporary_storage.elements[index].index_1;
186          storage->temp_2DQ_data.elements[index].index_2 = temporary_storage.elements[index].index_2;
187          storage->temp_2DQ_data.elements[index].weight = temporary_storage.elements[index].weight;
188        }
189
190        // free temporary data
191        free(temporary_storage.elements);
192
193        // add new data point
194        storage->temp_2DQ_data.elements[storage->temp_2DQ_data.num_elements].index_1 = i;
195        storage->temp_2DQ_data.elements[storage->temp_2DQ_data.num_elements].index_2 = j;
196        storage->temp_2DQ_data.elements[storage->temp_2DQ_data.num_elements++].weight = p;
197      }
198
199      // If this is the first time this ray is being recorded in this logger, add it to the list of loggers that write to temp and may get it moved to perm
200      if (storage->temp_2DQ_data.num_elements == 1)
201        add_to_logger_with_data(logger_with_data_array,logger);
202    }
203  }
204
205}
206
207// clear_temp
208void clear_temp_2DQ(union logger_data_union *data_union) {
209  data_union->p_2DQ_storage->temp_2DQ_data.num_elements = 0;
210}
211
212// record_to_perm
213void record_to_perm_2DQ(Coords *position, double *k_new, double *k_old, double p, double p_old, double time, int scattered_in_this_volume, int scattered_in_this_volume_by_this_process, int total_number_of_scattering_events, struct logger_struct *logger, struct logger_with_data_struct *logger_with_data_array) {
214
215  //printf("In record to permanent \n");
216  struct a_2DQ_storage_struct *storage;
217  storage = logger->data_union.p_2DQ_storage;
218
219  int add_point = 1;
220
221  if (storage->order != 0) {
222    if (storage->order - 1 == total_number_of_scattering_events)
223      add_point = 1;
224    else
225      add_point = 0;
226  }
227
228  if (storage->order_in_this_volume != 0) {
229    if (storage->order_in_this_volume - 1 == scattered_in_this_volume)
230      add_point = 1;
231    else
232      add_point = 0;
233  }
234
235  if (storage->order_process_in_this_volume != 0) {
236    if (storage->order_process_in_this_volume - 1 == scattered_in_this_volume_by_this_process)
237      add_point = 1;
238    else
239      add_point = 0;
240  }
241
242  if (add_point == 1) {
243    //printf("storage was set \n");
244    double q1,q2;
245
246    // dim_1_choice = 0 for x, 1 for y, 2 for z. Done in initialize from input "x" "y" "z".
247    q1 = k_old[storage->dim_1_choice] - k_new[storage->dim_1_choice];
248    q2 = k_old[storage->dim_2_choice] - k_new[storage->dim_2_choice];
249
250    int i,j;
251
252    // Find bin in histogram
253    if (q1>storage->Detector_2D.D1min && q1<storage->Detector_2D.D1max && q2>storage->Detector_2D.D2min && q2<storage->Detector_2D.D2max) {
254
255      i = floor((q1 - storage->Detector_2D.D1min)*(double)storage->Detector_2D.bins_1/(storage->Detector_2D.D1max - storage->Detector_2D.D1min));
256      j = floor((q2 - storage->Detector_2D.D2min)*(double)storage->Detector_2D.bins_2/(storage->Detector_2D.D2max - storage->Detector_2D.D2min));
257
258      //printf("Added to statistics for monitor [%d] [%d] \n",i,j);
259      //printf("indicies found\n");
260
261      storage->Detector_2D.Array_N[i][j]++;
262      storage->Detector_2D.Array_p[i][j] += p;
263      storage->Detector_2D.Array_p2[i][j] += p*p;
264
265    }
266  }
267
268}
269
270// write_temp_to_perm
271void write_temp_to_perm_2DQ(union logger_data_union *data_union) {
272
273  struct a_2DQ_storage_struct *storage;
274  storage = data_union->p_2DQ_storage;
275
276  int index;
277  // Add all data points to the historgram, they are saved as index / weight combinations
278  for (index=0;index<storage->temp_2DQ_data.num_elements;index++) {
279    storage->Detector_2D.Array_N[storage->temp_2DQ_data.elements[index].index_1][storage->temp_2DQ_data.elements[index].index_2]++;
280
281    storage->Detector_2D.Array_p[storage->temp_2DQ_data.elements[index].index_1][storage->temp_2DQ_data.elements[index].index_2] += storage->temp_2DQ_data.elements[index].weight;
282
283    storage->Detector_2D.Array_p2[storage->temp_2DQ_data.elements[index].index_1][storage->temp_2DQ_data.elements[index].index_2] += storage->temp_2DQ_data.elements[index].weight*storage->temp_2DQ_data.elements[index].weight;
284  }
285  clear_temp_2DQ(data_union);
286}
287
288// Only need to define linking function for loggers once.
289#ifndef UNION_LOGGER
290#define UNION_LOGGER Dummy
291// Linking function for loggers, finds the indicies of the specified geometries on the global_geometry_list
292void manual_linking_function_logger_volumes(char *input_string, struct pointer_to_global_geometry_list *global_geometry_list, struct pointer_to_1d_int_list *accepted_volumes, char *component_name) {
293    // Need to check a input_string of text for an occurance of name. If it is in the inputstring, yes return 1, otherwise 0.
294   char *token;
295   int loop_index;
296   char local_string[512];
297
298   strcpy(local_string,input_string);
299   // get the first token
300   token = strtok(local_string,",");
301
302   // walk through other tokens
303   while( token != NULL )
304   {
305      //printf( " %s\n", token );
306      for (loop_index=0;loop_index<global_geometry_list->num_elements;loop_index++) {
307        if (strcmp(token,global_geometry_list->elements[loop_index].name) == 0) {
308          add_element_to_int_list(accepted_volumes,loop_index);
309          break;
310        }
311
312        if (loop_index == global_geometry_list->num_elements - 1) {
313          // All possible geometry names have been looked through, and the break was not executed.
314          // Alert the user to this problem by showing the geometry name that was not found and the currently available geometires
315            printf("\n");
316            printf("ERROR: The target_geometry string \"%s\" in Union logger component \"%s\" had an entry that did not match a specified geometry. \n",input_string,component_name);
317            printf("       The unrecoignized geometry name was: \"%s\" \n",token);
318            printf("       The geometries available at this point (need to be defined before the logger): \n");
319            for (loop_index=0;loop_index<global_geometry_list->num_elements;loop_index++)
320              printf("         %s\n",global_geometry_list->elements[loop_index].name);
321            exit(1);
322        }
323      }
324
325      // Updates the token
326      token = strtok(NULL,",");
327   }
328}
329
330void manual_linking_function_logger_processes(char *input_string, struct physics_struct *p_physics, struct pointer_to_1d_int_list *accepted_processes, char *component_name, char *Volume_name) {
331    // Need to check a input_string of text for an occurance of name. If it is in the inputstring, yes return 1, otherwise 0.
332   char *token;
333   int loop_index;
334   char local_string[256];
335
336   strcpy(local_string,input_string);
337   // get the first token
338   token = strtok(local_string,",");
339
340   // walk through other tokens
341   while( token != NULL )
342   {
343      //printf( " %s\n", token );
344      for (loop_index=0;loop_index<p_physics->number_of_processes;loop_index++) {
345        if (strcmp(token,p_physics->p_scattering_array[loop_index].name) == 0) {
346          add_element_to_int_list(accepted_processes,loop_index);
347          break;
348        }
349
350        if (loop_index == p_physics->number_of_processes - 1) {
351          // All possible process names have been looked through, and the break was not executed.
352          // Alert the user to this problem by showing the process name that was not found and the currently available processes
353            printf("\n");
354            printf("ERROR: The target process string \"%s\" in Union logger \"%s\" had an entry that did not match a specified process in assosiated volume \"%s\". \n",input_string,component_name,Volume_name);
355            printf("       The unrecoignized process name was: \"%s\" \n",token);
356            printf("       The processes defined in material \"%s\" of which  Volume \"%s\" is made: \n",p_physics->name,Volume_name);
357            for (loop_index=0;loop_index<p_physics->number_of_processes;loop_index++)
358              printf("         %s\n",p_physics->p_scattering_array[loop_index].name);
359            exit(1);
360        }
361      }
362
363      // Updates the token
364      token = strtok(NULL,",");
365   }
366}
367#endif
368
369double** allocate2Ddouble(int count_x, int count_y) {
370    // This function is needed to dynamically declare an array
371    //  that has continous data as a static array would have,
372    //  as that is the format expected by DETECTOR_OUT_2D.
373    int i;
374
375    // allocate space for actual data
376    double *data = malloc(sizeof(double) * count_x * count_y);
377
378    // create array or pointers to first elem in each 2D row
379    double **ptr_array = malloc(sizeof(double*) * count_x);
380    for (i = 0; i < count_x; i++) {
381        ptr_array[i] = data + (i*count_y);
382    }
383    return ptr_array;
384}
385
386void free2Ddouble(double** ptr_array) {
387    if (!ptr_array) return;
388    if (ptr_array[0]) free(ptr_array[0]);
389    free(ptr_array);
390}
391
392%}
393
394DECLARE
395%{
396// From make material
397// Needed for transport to the main component
398//struct global_material_element_struct global_material_element;
399//struct physics_struct this_material;
400
401int loop_index,l1,l2;
402int process_index;
403int found_process;
404int specified_processes;
405char local_string[256];
406
407// Reused for logger
408struct pointer_to_1d_int_list accepted_processes = {0,NULL};
409
410struct global_logger_element_struct logger_list_element;
411
412struct pointer_to_1d_int_list accepted_volumes = {0,NULL};
413
414struct logger_struct this_logger;
415struct a_2DQ_storage_struct this_storage;
416
417struct loggers_struct *loggers_on_target_volume;
418struct Volume_struct *target_volume;
419
420char temp_string[2];
421
422%}
423
424INITIALIZE
425%{
426
427
428  // Initialize storage from input
429  if (Q1_min >= Q1_max) {
430    printf("ERROR, Union logger \"%s\" had Q1_min >= Q1_max.\n",NAME_CURRENT_COMP);
431    exit(1);
432  }
433  this_storage.Detector_2D.D1min = Q1_min;
434  this_storage.Detector_2D.D1max = Q1_max;
435
436  if (Q2_min >= Q2_max) {
437    printf("ERROR, Union logger \"%s\" had Q2_min >= Q2_max.\n",NAME_CURRENT_COMP);
438    exit(1);
439  }
440  this_storage.Detector_2D.D2min = Q2_min;
441  this_storage.Detector_2D.D2max = Q2_max;
442
443  if (n1 <= 0) {
444    printf("ERROR, Union logger \"%s\" had n1 <= 0.\n",NAME_CURRENT_COMP);
445    exit(1);
446  }
447  this_storage.Detector_2D.bins_1 = n1;
448
449  if (n2 <= 0) {
450    printf("ERROR, Union logger \"%s\" had n2 <= 0.\n",NAME_CURRENT_COMP);
451    exit(1);
452  }
453  this_storage.Detector_2D.bins_2 = n2;
454
455  //printf("past input sanitation \n");
456
457  // Remember to take special care when deallocating this array, use free2Ddouble
458  this_storage.Detector_2D.Array_N = allocate2Ddouble(n1,n2); // Here the n1 double is cast to an int
459  this_storage.Detector_2D.Array_p = allocate2Ddouble(n1,n2);
460  this_storage.Detector_2D.Array_p2 = allocate2Ddouble(n1,n2);
461
462  for (l1=0;l1<n1;l1++) { //n1 is technically a double, but this works fine
463    for (l2=0;l2<n2;l2++) {
464      this_storage.Detector_2D.Array_N[l1][l2] = 0;
465      this_storage.Detector_2D.Array_p[l1][l2] = 0;
466      this_storage.Detector_2D.Array_p2[l1][l2] = 0;
467    }
468  }
469
470  //printf("past 2D pointer assignment \n");
471
472  // Input sanitation for filename apparently done in 2D_detector_out
473
474  if (strcmp(Q_direction_1,"x") == 0 || strcmp(Q_direction_1,"X") == 0) {
475      this_storage.dim_1_choice = 0;
476      sprintf(this_storage.Detector_2D.string_axis_1,"Q_x [A^-1]");
477      sprintf(this_storage.Detector_2D.title_string,"2D Q Union logger in plane x");
478  } else if (strcmp(Q_direction_1,"y") == 0 || strcmp(Q_direction_1,"Y") == 0) {
479      this_storage.dim_1_choice = 1;
480      sprintf(this_storage.Detector_2D.string_axis_1,"Q_y [A^-1]");
481      sprintf(this_storage.Detector_2D.title_string,"2D Q Union logger in plane y");
482  } else if (strcmp(Q_direction_1,"z") == 0 || strcmp(Q_direction_1,"Z") == 0) {
483      this_storage.dim_1_choice = 2;
484      sprintf(this_storage.Detector_2D.string_axis_1,"Q_z [A^-1]");
485      sprintf(this_storage.Detector_2D.title_string,"2D Q Union logger in plane z");
486  } else {
487      printf("ERROR, Union logger 2DQ named \"%s\" has an invalid Q_direction_1 string, it should be \"x\",\"y\" or \"z\".\n",NAME_CURRENT_COMP);
488      exit(1);
489  }
490
491  if (strcmp(Q_direction_2,"x") == 0 || strcmp(Q_direction_2,"X") == 0) {
492      this_storage.dim_2_choice = 0;
493      sprintf(this_storage.Detector_2D.string_axis_2,"Q_x [A^-1]");
494      sprintf(temp_string,"x");
495  } else if (strcmp(Q_direction_2,"y") == 0 || strcmp(Q_direction_2,"Y") == 0) {
496      this_storage.dim_2_choice = 1;
497      sprintf(this_storage.Detector_2D.string_axis_2,"Q_y [A^-1]");
498      sprintf(temp_string,"y");
499  } else if (strcmp(Q_direction_2,"z") == 0 || strcmp(Q_direction_2,"Z") == 0) {
500      this_storage.dim_2_choice = 2;
501      sprintf(this_storage.Detector_2D.string_axis_2,"Q_z [A^-1]");
502      sprintf(temp_string,"z");
503  } else {
504      printf("ERROR, Union logger 2DQ named \"%s\" has an invalid Q_direction_2 string, it should be \"x\",\"y\" or \"z\".\n",NAME_CURRENT_COMP);
505      exit(1);
506  }
507
508  strcat(this_storage.Detector_2D.title_string,temp_string); // Connects the title string started in Q_direction_1 part with the ending in Q_direction_2 part
509
510  sprintf(this_storage.Detector_2D.Filename,filename);
511
512
513  this_storage.order = order_total;
514  this_storage.order_in_this_volume = order_volume;
515  this_storage.order_process_in_this_volume = order_volume_process;
516  this_storage.temp_2DQ_data.num_elements=0;
517  this_storage.temp_2DQ_data.allocated_elements = 10;
518  this_storage.temp_2DQ_data.elements = malloc(this_storage.temp_2DQ_data.allocated_elements*sizeof(struct temp_2DQ_data_element_struct));
519
520  //printf("past direction choices sanitation \n");
521
522  // Book keeping
523  this_logger.logger_extend_index = logger_conditional_extend_index;
524  this_logger.function_pointers.active_record_function = &record_to_perm_2DQ;  // Assume no conditional
525  this_logger.function_pointers.inactive_record_function = &record_to_temp_2DQ; // If an assume is present, these two pointers are switched
526  this_logger.function_pointers.temp_to_perm = &write_temp_to_perm_2DQ;
527  this_logger.function_pointers.clear_temp = &clear_temp_2DQ;
528  // Initializing for conditional
529  this_logger.conditional_list.num_elements = 0;
530
531  //this_logger.function_pointers.perm_to_disk = &write_perm_to_disk_2DQ; //Obsolete
532
533  //printf("past this_logger function assignment \n");
534
535  this_logger.data_union.p_2DQ_storage = &this_storage;
536
537  sprintf(this_logger.name,NAME_CURRENT_COMP);
538
539  //printf("past this_logger assignment \n");
540
541  sprintf(logger_list_element.name,NAME_CURRENT_COMP);
542  logger_list_element.component_index = INDEX_CURRENT_COMP;
543  logger_list_element.logger = &this_logger;
544
545  //printf("past logger_list_element assignment \n");
546
547  // In order to run the logger at the right times, pointers to this logger is stored in each volume it logs,
548  //  and additionally for each avaiable process. If a process is not logged, the pointer is simply not stored.
549
550  // Need to find the volumes for which the processes should have a reference to this logger
551  if (target_geometry && strlen(target_geometry) && strcmp(target_geometry,"NULL") && strcmp(target_geometry, "0")) {
552    // Certain volumes were selected, find the indicies in the global_geometry_list
553    manual_linking_function_logger_volumes(target_geometry, &global_geometry_list, &accepted_volumes, NAME_CURRENT_COMP);
554    // Add this logger to the global_specific_volumes_logger_list (so that conditionals can affect it)
555    add_element_to_logger_list(&global_specific_volumes_logger_list,logger_list_element);
556
557    for (loop_index=0;loop_index<accepted_volumes.num_elements;loop_index++) {
558      target_volume = global_geometry_list.elements[accepted_volumes.elements[loop_index]].Volume;
559      // Add an element to its logger list
560      add_initialized_logger_in_volume(&target_volume->loggers,target_volume->p_physics->number_of_processes);
561
562      if (target_process && strlen(target_process) && strcmp(target_process,"NULL") && strcmp(target_process, "0")) {
563        // Unused process pointers should point to NULL
564        for (process_index=0;process_index<target_volume->p_physics->number_of_processes;process_index++) {
565          target_volume->loggers.p_logger_volume[target_volume->loggers.num_elements-1].p_logger_process[process_index]=NULL;
566        }
567        // A target_process was set, find it within the volume structure (can be many processes)
568        manual_linking_function_logger_processes(target_process, target_volume->p_physics, &accepted_processes, NAME_CURRENT_COMP,target_volume->name);
569        for (process_index=0;process_index<accepted_processes.num_elements;process_index++) {
570          // Add pointer to this logger for all the accepted processes in this newly added loggers element
571          target_volume->loggers.p_logger_volume[target_volume->loggers.num_elements-1].p_logger_process[accepted_processes.elements[process_index]]=&this_logger;
572        }
573      } else {
574        // No target_process was set, attatch the logger to all processes
575        for (process_index=0;process_index<target_volume->p_physics->number_of_processes;process_index++) {
576          target_volume->loggers.p_logger_volume[target_volume->loggers.num_elements-1].p_logger_process[process_index]=&this_logger;
577        }
578      }
579    }
580  } else {
581    // Send to global_all_volumes_logger_list
582    // Here there is no system for selecting processes as well
583    add_element_to_logger_list(&global_all_volume_logger_list,logger_list_element);
584  }
585
586
587 %}
588
589TRACE
590%{
591%}
592
593SAVE
594%{
595// Write to disk
596DETECTOR_OUT_2D(
597 this_storage.Detector_2D.title_string,
598 this_storage.Detector_2D.string_axis_1,
599 this_storage.Detector_2D.string_axis_2,
600 this_storage.Detector_2D.D1min, this_storage.Detector_2D.D1max,
601 this_storage.Detector_2D.D2min, this_storage.Detector_2D.D2max,
602 this_storage.Detector_2D.bins_1, this_storage.Detector_2D.bins_2,
603 *this_storage.Detector_2D.Array_N, *this_storage.Detector_2D.Array_p, *this_storage.Detector_2D.Array_p2,
604 this_storage.Detector_2D.Filename);
605
606%}
607
608FINALLY
609%{
610// Remember to clean up allocated lists
611if (this_storage.temp_2DQ_data.allocated_elements>0) free(this_storage.temp_2DQ_data.elements);
612
613free2Ddouble(this_storage.Detector_2D.Array_N);
614free2Ddouble(this_storage.Detector_2D.Array_p);
615free2Ddouble(this_storage.Detector_2D.Array_p2);
616
617if (accepted_processes.num_elements > 0) free(accepted_processes.elements);
618if (accepted_volumes.num_elements > 0) free(accepted_volumes.elements);
619
620%}
621
622END
623
624