File: MCPL_output.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 (463 lines) | stat: -rw-r--r-- 15,490 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
/*******************************************************************************
*
* McXtrace, x-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: MCPL_output
*
* %Identification
* Written by: Erik B Knudsen 
* Date: Aug 2016
* Origin: DTU Physics
*
* Detector-like component that writes photon state parameters into an mcpl-format binary, virtual-source photon file.
*
* %Description
* Detector-like component that writes photon state parameters into an mcpl-format 
* binary, virtual-source photon file.
*
* MCPL is short for Monte Carlo Particle List, and is a new format for sharing events
* between e.g. MCNP(X), Geant4, and McXtrace.
*
* When used with MPI, the component will output #MPI nodes individual MCPL files that
* can be merged using the mcpltool.
*
* MCPL_output allows a few flags to tweak the output files:
* 1. If use_polarisation is unset (default) the polarisation vector will not be stored (saving space)
* 2. If doubleprec is unset (default) data will be stored as 32 bit floating points, effectively cutting the output file size in half.
* 3. Extra information may be attached to each ray in the form of a userflag, a user-defined variable wich is packed into 32 bits. If
* the user variable does not fit in 32 bits the value will be truncated and likely garbage. If more than one variable is to be attached to
* each photon this must be packed into the 32 bits.
*
* These features are set this way to keep file sizes as manageable as possible.
*
* Example: MCPL_output( filename="voutput", verbose=1, userflag="flag", userflagcomment="Photon Id", merge_mpi=1)
*
* %Parameters
* INPUT PARAMETERS
*
* filename: [str]         Name of neutron file to write. If not given, the component name will be used.
* verbose:         [1]   If 1) Print summary information for created MCPL file. 2) Also print summary of first 10 particles information stored in the MCPL file. >2) Also print information for first 10 particles as they are being stored by McXtrace.
* polarisationuse: [1]   Enable storing the polarization state of the photon.
* doubleprec:      [1]   Use double precision storage.
* userflag:        [1]   Extra variable to attach to each photon. The value of this variable will be packed into a 32 bit integer.
* userflagcomment: [str] String variable to describe the userflag. If this string is empty (the default) no userflags will be stored.
* merge_mpi:       [1]   Flag to indicate if output should be merged in case of MPI.
* keep_mpi_unmerged: [1] Flag to indicate if original unmerged mcpl-files should be kept (or deleted).
* buffermax: [1]         Maximal number of events to save ( <= MAXINT), GPU/OpenACC only.
* %End
*******************************************************************************/

DEFINE COMPONENT MCPL_output

SETTING PARAMETERS (int polarisationuse=0, int doubleprec=0, int verbose=0, string userflag="",
  string filename=0, string userflagcomment="", merge_mpi=1, keep_mpi_unmerged=0, buffermax=0)

DEPENDENCY "-Wl,-rpath,CMD(mcpl-config --show libdir) -LCMD(mcpl-config --show libdir) -lmcpl -ICMD(mcpl-config --show includedir)"

SHARE
%{
#include <mcpl.h>
#include <sys/stat.h>
  int mcpl_file_exist (char *filename)
  {
    struct stat   buffer;
    return (stat (filename, &buffer) == 0);
  }
%}

DECLARE
%{
    mcpl_outfile_t outputfile;
    mcpl_particle_t *particle;
    mcpl_particle_t Particle;
    int userflagenabled;
    DArray1d X;
    DArray1d Y;
    DArray1d Z;
    DArray1d KX;
    DArray1d KY;
    DArray1d KZ;
    DArray1d EX;
    DArray1d EY;
    DArray1d EZ;
    DArray1d T;
    DArray1d PHI;
    DArray1d P;
    DArray1d U;
    int captured;
    char finalfile[CHAR_BUF_LENGTH];
%}

INITIALIZE
%{
    char extension[128]="";
    char *myfilename;
    
    // Use instance name for base output if no input was given
    if (!strcmp(filename,"\0")) sprintf(filename,"%s",NAME_CURRENT_COMP);

#if defined (USE_MPI)
  /* In case of MPI, simply redefine the filename used by each node */
    MPI_MASTER(fprintf(stdout, "INFO (%s): You are using MCPL_output with MPI, hence you will get %i filenames %s_node_#i as output.\n",NAME_CURRENT_COMP,mpi_node_count,filename); );
    sprintf(extension,"node_%i.mcpl",mpi_node_rank);
#else
    sprintf(extension,"mcpl");
#endif
    /*add output dir (if applicable) to the output filename and add extension if */
    // Append the extension to the filename
    //  -- do not use mcfull_file for this since it can not handle absolute filenames with a '.' in them
    char * actual_filename = (char *) calloc(strlen(filename)+strlen(extension)+2, sizeof(char));
    strcpy(actual_filename, filename);
    strcat(actual_filename, ".");
    strcat(actual_filename, extension);

    // still use mcfull_file in case the filename does not include path information
    myfilename = mcfull_file(actual_filename, NULL);

    // release the memory now that we have the full filename
    if (actual_filename) free(actual_filename);

    char line[256];
    outputfile = mcpl_create_outfile(myfilename);
    /*reset filename to be whatever mcpl actually calls it. It may have added .mcpl*/
    snprintf(myfilename,strlen(myfilename)+5,"%s",mcpl_outfile_filename(outputfile));

    snprintf(line,255,"%s %s %s",MCCODE_NAME,MCCODE_VERSION,instrument_name);
    mcpl_hdr_set_srcname(outputfile,line);
    mcpl_enable_universal_pdgcode(outputfile,22);/*all particles are photons*/
    snprintf(line,255,"Output by COMPONENT: %s",NAME_CURRENT_COMP);
    mcpl_hdr_add_comment(outputfile,line);

    /*also add the instrument file and the command line as blobs*/
    FILE *fp;
    if( (fp=fopen(instrument_source,"rb"))!=NULL){
        unsigned char *buffer;
        int size,status;
        /*find the file size by seeking to end, "tell" the position, and then go back again*/
        fseek(fp, 0L, SEEK_END);
        size = ftell(fp); // get current file pointer
        fseek(fp, 0L, SEEK_SET); // seek back to beginning of file
        if ( size && (buffer=malloc(size))!=NULL){
            if (size!=(fread(buffer,1,size,fp))){
	      fprintf(stderr,"\nWarning (%s): Source instrument file not read cleanly\n", NAME_CURRENT_COMP);
            }
            mcpl_hdr_add_data(outputfile, "mccode_instr_file", size, buffer);
            free(buffer);
        }
	fclose(fp);
    } else {
      fprintf(stderr,"\nWarning (%s): Source instrument file (%s) not found, hence not embedded.\n", NAME_CURRENT_COMP, instrument_source);
    }


    int ii;
    char clr[2048],*clrp;
    clrp=clr;
    clrp+=snprintf(clrp,2048,"%s",instrument_exe);
    char Parameters[CHAR_BUF_LENGTH];
    for (ii=0;ii<numipar;ii++){
        (*mcinputtypes[mcinputtable[ii].type].printer)(Parameters, mcinputtable[ii].par);
        clrp+=snprintf(clrp,2048-(clrp-clr)," %s=%s",mcinputtable[ii].name, Parameters);
    }
    *(clrp)='\0';
    mcpl_hdr_add_data(outputfile, "mccode_cmd_line" , strlen(clr), clr);

    if (polarisationuse) {
        mcpl_enable_polarisation(outputfile);
    }
    if (doubleprec){
        mcpl_enable_doubleprec(outputfile);
    }

#if defined (USE_MPI)
  MPI_MASTER(
#endif

    if (verbose==1) {
    printf("MCPL_output verbose mode: after generating the mcpl-file a summary will be printed.\n");
    }

#if defined (USE_MPI)
	    );
#endif

  /*Add comments on what the orientation and position of this component is.*/
  /*Include the instrument file itself as a binary blob in the mcpl file*/

  userflagenabled=0;
  /*Have the option of including a user-flag like they do at Loki.*/
  if (strlen(userflagcomment)!=0){
      mcpl_enable_userflags(outputfile);
      userflagenabled=1;
      /*Don't add the comment if it's empty*/
      if(userflagcomment && strlen(userflagcomment)){
          snprintf(line,255,"userflags: %s",userflagcomment);
          mcpl_hdr_add_comment(outputfile,line);
      }
  }
   if (myfilename){
       MPI_MASTER(
         sprintf(finalfile,myfilename);
       );
       free(myfilename);
   }
#ifndef OPENACC
  /*pointer to the single particle storage area*/
  particle=&Particle;
#else
    if(!buffermax){
      buffermax= mcget_ncount();
    }
    X = create_darr1d(buffermax);
    X = create_darr1d(buffermax);
    Y = create_darr1d(buffermax);
    Z = create_darr1d(buffermax);
    KX = create_darr1d(buffermax);
    KY = create_darr1d(buffermax);
    KZ = create_darr1d(buffermax);
    EX = create_darr1d(buffermax);
    EY = create_darr1d(buffermax);
    EZ = create_darr1d(buffermax);
    T = create_darr1d(buffermax);
    PHI = create_darr1d(buffermax);
    P = create_darr1d(buffermax);
    if (userflagenabled) {
      U = create_darr1d(buffermax);
    }
    captured=0;
#endif
%}

TRACE
%{
  double uvar;
  int fail;
#ifdef OPENACC
  int cap;
#pragma acc atomic capture
  {
    cap=captured++;
  }

  //  unsigned long long i=_particle->_uid;// % GPU_INNERLOOP;
  if (cap < ceil(buffermax)) {
    X[cap]=x;
    Y[cap]=y;
    Z[cap]=z;
    KX[cap]=kx;
    KY[cap]=ky;
    KZ[cap]=kz;
    EX[cap]=Ex;
    EY[cap]=Ey;
    EZ[cap]=Ez;
    T[cap]=t;
    PHI[cap]=phi;
    P[cap]=p;
    if(userflagenabled) {
      uvar = particle_getvar(_particle,userflag,&fail); if(fail) uvar=0;
      U[cap] = uvar;
    }
    SCATTER;
  }

#else
    double nrm;
    /*positions are in cm*/
    particle->position[0]=x*100;
    particle->position[1]=y*100;
    particle->position[2]=z*100;

    if(polarisationuse){
        particle->polarisation[0]=Ex;
        particle->polarisation[1]=Ey;
        particle->polarisation[2]=Ez;
    }

    nrm =sqrt(kx*kx + ky*ky + kz*kz);
    /*ekin is in MeV, in McXtrace we use keV*/
    particle->ekin = K2E*nrm*1e-3;
    particle->direction[0] = kx/nrm;
    particle->direction[1] = ky/nrm;
    particle->direction[2] = kz/nrm;
    /*time in ms:*/
    particle->time = t*1e3;
    /*weight in unspecified units:*/
    particle->weight = p;
    /*if specified also add the userflags*/
    if(userflagenabled){
        uvar = particle_getvar(_particle,userflag,&fail); if(fail) uvar=0;
        particle->userflags = (uint32_t) uvar;
    }

#if defined (USE_MPI)
  MPI_MASTER(
#endif
    if (verbose==3 && mcrun_num<10) {
      printf("id=%ld\tpdg=22\tekin=%g MeV\tx=%g cm\ty=%g cm\tz=%g cm\tux=%g\tuy=%g\tuz=%g\tt=%g ms\tweight=%g\tpolx=%g\tpoly=%g\tpolz=%g\n",
	     mcrun_num, particle->ekin, particle->position[0], particle->position[1], particle->position[2],
	     particle->direction[0], particle->direction[1], particle->direction[2], particle->time, particle->weight,
	     particle->polarisation[0], particle->polarisation[1], particle->polarisation[2]);
    }
#if defined (USE_MPI)
  );
#endif


    mcpl_add_particle(outputfile,particle);

    SCATTER;
#endif
%}

SAVE
%{
#ifdef OPENACC
  double nrm;
  unsigned long long i;
  if (captured > ceil(buffermax)) {
     fprintf(stderr,"MCPL_output captured %g particles which is more than the buffersize (%g)!\n",(double)captured,buffermax);
  }
  for (i=0;i<captured;i++) {
    if (P[i]>0) {
      /*positions are in cm*/
      Particle.position[0]=X[i]*100;
      Particle.position[1]=Y[i]*100;
      Particle.position[2]=Z[i]*100;

      if(polarisationuse){
	Particle.polarisation[0]=EX[i];
	Particle.polarisation[1]=EY[i];
	Particle.polarisation[2]=EZ[i];
      }

      nrm =sqrt(KX[i]*KX[i] + KY[i]*KY[i] + KZ[i]*KZ[i]);
      /*ekin is in MeV in McXtrace keV*/
      Particle.ekin = K2E*nrm*1e-3;
      Particle.direction[0] = KX[i]/nrm;
      Particle.direction[1] = KY[i]/nrm;
      Particle.direction[2] = KZ[i]/nrm;
      /*time in ms:*/
      Particle.time = T[i]*1e3;
      /*weight in unspecified units:*/
      Particle.weight = P[i];
      /*if specified also add the userflags*/
      if(userflagenabled){
	Particle.userflags = (uint32_t) U[i];
      }

      if (verbose==3 && mcrun_num<10) {
	printf("id=%ld\tpdg=2112\tekin=%g MeV\tx=%g cm\ty=%g cm\tz=%g cm\tux=%g\tuy=%g\tuz=%g\tt=%g ms\tweight=%g\tpolx=%g\tpoly=%g\tpolz=%g\n",
	       mcrun_num, Particle.ekin, Particle.position[0], Particle.position[1], Particle.position[2],
	       Particle.direction[0], Particle.direction[1], Particle.direction[2], Particle.time, Particle.weight,
	       Particle.polarisation[0], Particle.polarisation[1], Particle.polarisation[2]);
      }

      mcpl_add_particle(outputfile,&Particle);
    }
  }
#endif
%}

FINALLY
%{
#ifdef USE_MPI
  if (merge_mpi && mpi_node_count > 1) {
    mcpl_close_outfile(outputfile);
  } else {
    mcpl_closeandgzip_outfile(outputfile);
  }
#else
  mcpl_closeandgzip_outfile(outputfile);
#endif
#ifdef USE_MPI
 MPI_Barrier(MPI_COMM_WORLD);
 MPI_MASTER(
     /* Only attempt merge if requested and meaningful */
     if (merge_mpi && mpi_node_count > 1) {
        char **mpi_node_files;
        char *merge_outfilename;
        char extension[128]="mcpl";
        int j;
        mcpl_outfile_t merge_outfile;

        char * real_filename = (char *) calloc(strlen(filename) + strlen(extension) + 2, sizeof(char));
        strcpy(real_filename, filename);
        strcat(real_filename, ".");
        strcat(real_filename, extension);

        merge_outfilename = mcfull_file(real_filename, NULL);

        mpi_node_files=(char **) calloc(mpi_node_count,sizeof(char *));
        sprintf(extension,"node_%i.mcpl", mpi_node_count);
        char * temp_name = (char *) calloc(strlen(filename) + strlen(extension) + 2, sizeof(char));
        for (j=0;j<mpi_node_count;j++){
            sprintf(temp_name, "%s.node_%i.mcpl", filename, j);
            mpi_node_files[j] = mcfull_file(temp_name, NULL);
        }
        if (temp_name) free(temp_name);

        /*now do the merge through the call to mcpl_merge_files*/
        merge_outfile = mcpl_merge_files(merge_outfilename,mpi_node_count,(const char **) mpi_node_files);
        mcpl_closeandgzip_outfile(merge_outfile);

        /*remove the original unmerged files if wanted*/
        if(!keep_mpi_unmerged){
            int status=0;
            for (j=0;j<mpi_node_count;j++){
                status+=remove(mpi_node_files[j]);
            }
            if (status){
                fprintf(stderr,"Warning (%s): Could not remove one or more unmerged files.\n",NAME_CURRENT_COMP);
            }
        }

        /*free the string storage*/
	sprintf(finalfile,merge_outfilename);
        free(merge_outfilename);
        for (j=0;j<mpi_node_count;j++){
            free(mpi_node_files[j]);
        }
        free(mpi_node_files);
    }
  );
#endif
  if(verbose) {
    MPI_MASTER(
      /* check if we need to add .gz suffix */
      if (!mcpl_file_exist(finalfile)) {
	char *finalfilegz=malloc(CHAR_BUF_LENGTH*sizeof(char));
	sprintf(finalfilegz,"%s.gz",finalfile);
	sprintf(finalfile,"%s",finalfilegz);
	free(finalfilegz);
      }
      /* Recheck for file existance */
      if (mcpl_file_exist(finalfile)) {
	printf("\n\nMCPL output summary from %s\n",finalfile);
	mcpl_dump(finalfile, 0, 0, 10);
      } else {
	printf("\n\nWarning, did not localize expected output file for stat summary!\n");
      }
    );
  }
%}

MCDISPLAY
%{
    double t,dt;
    int i;
    multiline(5, 0.2,0.2,0.0, -0.2,0.2,0.0, -0.2,-0.2,0.0, 0.2,-0.2,0.0, 0.2,0.2,0.0);
    /*M*/
    multiline(5,-0.085,-0.085,0.0, -0.085,0.085,0.0, -0.045,-0.085,0.0, -0.005,0.085,0.0, -0.005,-0.085,0.0);
    /*O*/
    dt=2*M_PI/32;
    t=0;
    for (i=0;i<32;i++){
        line(0.04*cos(t)+0.045,0.08*sin(t),0, 0.04*cos(t+dt)+0.045,0.08*sin(t+dt),0);
        t+=dt;
    }
%}

END