/******************************************************************************* * * McStas, neutron ray-tracing package * Copyright (C) 1997-2017, All rights reserved * DTU Physics, Kgs. Lyngby, Denmark * Component: MCPL_output * * %I * Written by: Erik B Knudsen * Date: Mar 2016 * Origin: DTU Physics * * Detector-like component that writes neutron state parameters into an mcpl-format * binary, virtual-source neutron file. * * %D * Detector-like component that writes neutron state parameters into an mcpl-format * binary, virtual-source neutron file. * * MCPL is short for Monte Carlo Particle List, and is a new format for sharing events * between e.g. MCNP(X), Geant4 and McStas. * * When used with MPI, the component first outputs #MPI nodes individual MCPL files that * may be merged (the default). If, in addition, keep_mpi_unmerged is set, the constituent * parts of the merged mcpl-file are kept. * * N.b. Any file extension given will be replaced by .mcpl * * 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 neutron this must be packed into the 32 bits. * * These features are set this way to keep file sizes as manageable as possible. * * %BUGS * * %P * INPUT PARAMETERS * * filename: [str] Name of neutron file to write. Default is standard output [string]. If not given, a unique 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 McStas. * polarisationuse: [1] Enable storing the polarisation state of the neutron. * doubleprec: [1] Use double precision storage * userflag: [1] Extra variable to attach to each neutron. 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). * %E *******************************************************************************/ DEFINE COMPONENT MCPL_output DEFINITION PARAMETERS (polarisationuse=0, doubleprec=0, verbose=0, int userflag=0) SETTING PARAMETERS (string filename=0, string userflagcomment="", merge_mpi=1, keep_mpi_unmerged=0) OUTPUT PARAMETERS (outputfile,particle,Particle, userflagenabled) DEPENDENCY "-Wl,-rpath,CMD(mcpl-config --show libdir) -ICMD(mcpl-config --show includedir) -LCMD(mcpl-config --show libdir) -lmcpl" SHARE %{ #include #include int mcpl_file_exist (char *filename) { struct stat buffer; return (stat (filename, &buffer) == 0); } %} DECLARE %{ mcpl_outfile_t outputfile; mcpl_particle_t *particle,Particle; int userflagenabled; %} INITIALIZE %{ char extension[128]=""; char *myfilename,*stripext; /*strip extension from filename*/ if (stripext=strrchr(filename,'.')){ #if defined (USE_MPI) MPI_MASTER( fprintf(stdout, "WARNING: (%s): the \"%s\" file extension will be overwritten by \".mcpl\"\n",NAME_CURRENT_COMP,stripext); ); #else fprintf(stdout, "WARNING: (%s): the \"%s\" file extension will be overwritten by \".mcpl\"\n",NAME_CURRENT_COMP,stripext); #endif *stripext='\0'; } #if defined (USE_MPI) /* In case of MPI, simply redefine the filename used by each node */ if(keep_mpi_unmerged){ MPI_MASTER(fprintf(stdout, "INFO: (%s): You are keeping unmerged MCPL_output. %i files: %s_node_#i.mcpl.\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 standard extension*/ myfilename=mcfull_file(filename,extension); 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,mcinstrument_name); mcpl_hdr_set_srcname(outputfile,line); mcpl_enable_universal_pdgcode(outputfile,2112);/*all particles are neutrons*/ 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(mcinstrument_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); } } else { fprintf(stderr,"\nWarning (%s): Source instrument file (%s) not found, hence not embedded.\n", NAME_CURRENT_COMP, mcinstrument_source); } fclose(fp); int ii; char *clr,clbuf[CHAR_BUF_LENGTH]; if ( (clr=calloc(CHAR_BUF_LENGTH*(mcnumipar+1)+1,sizeof(char)))==NULL){ fprintf(stderr,"Error(%s): Memory allocation error.\n",NAME_CURRENT_COMP); exit(-1); } strncat(clr,mcinstrument_exe,CHAR_BUF_LENGTH); for (ii=0;iiposition[0]=x*100; particle->position[1]=y*100; particle->position[2]=z*100; if(polarisationuse){ particle->polarisation[0]=sx; particle->polarisation[1]=sy; particle->polarisation[2]=sz; } nrm =sqrt(vx*vx + vy*vy + vz*vz); /*ekin is in MeV*/ particle->ekin = VS2E*nrm*nrm/1e9; particle->direction[0] = vx/nrm; particle->direction[1] = vy/nrm; particle->direction[2] = vz/nrm; /*time in ms:*/ particle->time = t*1e3; /*weight in unspecified units:*/ particle->weight = p; /*if specified also add the userflags*/ if(userflagenabled){ particle->userflags = (uint32_t) userflag; } #if defined (USE_MPI) MPI_MASTER( #endif if (verbose==3 && mcrun_num<10) { printf("id=%llu\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]); } #if defined (USE_MPI) ); #endif mcpl_add_particle(outputfile,particle); SCATTER; %} SAVE %{ #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 %} FINALLY %{ #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; merge_outfilename=mcfull_file(filename,extension); mpi_node_files=(char **) calloc(mpi_node_count,sizeof(char *)); for (j=0;j