diff --git a/HEN_HOUSE/egs++/Makefile b/HEN_HOUSE/egs++/Makefile index 0e6e55e5b..1be6e3872 100644 --- a/HEN_HOUSE/egs++/Makefile +++ b/HEN_HOUSE/egs++/Makefile @@ -62,7 +62,7 @@ shape_libs = egs_circle egs_ellipse egs_extended_shape egs_gaussian_shape \ egs_line_shape egs_polygon_shape egs_rectangle egs_shape_collection \ egs_voxelized_shape -aobject_libs = egs_track_scoring egs_dose_scoring egs_radiative_splitting +aobject_libs = egs_track_scoring egs_dose_scoring egs_radiative_splitting egs_phsp_scoring all_libs = $(geometry_libs) $(source_libs) $(shape_libs) $(aobject_libs) lib_objects = $(addprefix $(DSO1), $(addsuffix .$(obje), $(all_libs))) diff --git a/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/Makefile b/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/Makefile new file mode 100644 index 000000000..04eedc2e3 --- /dev/null +++ b/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/Makefile @@ -0,0 +1,53 @@ + +############################################################################### +# +# EGSnrc egs++ makefile to build phase space scoring object +# Copyright (C) 2015 National Research Council Canada +# +# This file is part of EGSnrc. +# +# EGSnrc is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with EGSnrc. If not, see . +# +############################################################################### +# +# Author: Blake Walters, 2018 +# +# Contributors: +# +############################################################################### + + +include $(EGS_CONFIG) +include $(SPEC_DIR)egspp.spec +include $(SPEC_DIR)egspp_$(my_machine).conf + +DEFS = $(DEF1) -DBUILD_PHSP_SCORING_DLL + +library = egs_phsp_scoring +lib_files = egs_phsp_scoring +my_deps = $(common_ausgab_deps) +extra_dep = $(addprefix $(DSOLIBS), $(my_deps)) + +include $(SPEC_DIR)egspp_libs.spec + +INC2 = -I$(IEGS2) -I..$(DSEP).. -I$(HEN_HOUSE)iaea_phsp + +#this has been redefined to include iaea_phsp libraries +link2_libs = egspp iaea_phsp + +$(make_depend) + +test: + @echo "common_h2: $(common_h2)" + @echo "extra_dep: $(extra_dep)" diff --git a/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/egs_phsp_scoring.cpp b/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/egs_phsp_scoring.cpp new file mode 100644 index 000000000..79059f4ee --- /dev/null +++ b/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/egs_phsp_scoring.cpp @@ -0,0 +1,700 @@ +/* +############################################################################### +# +# EGSnrc egs++ phase space scoring object +# Copyright (C) 2015 National Research Council Canada +# +# This file is part of EGSnrc. +# +# EGSnrc is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with EGSnrc. If not, see . +# +############################################################################### +# +# Author: Blake Walters, 2018 +# +# Contributors: +# +############################################################################### +*/ + + +/*! \file egs_phsp_scoring.cpp + * \brief A phase space scoring ausgab object: implementation + * \BW + */ + +#include +#include +#include +#include + +#include "egs_phsp_scoring.h" +#include "egs_input.h" +#include "egs_functions.h" +#include "iaea_phsp.h" + +EGS_PhspScoring::EGS_PhspScoring(const string &Name, + EGS_ObjectFactory *f) : + EGS_AusgabObject(Name,f), phsp_index(0), store_max(1000), phsp_file(0), + count(0), countg(0), emin(1.e30), emax(-1.e30), first_flush(true), is_restart(false) { + otype = "EGS_PhspScoring"; +} + +EGS_PhspScoring::~EGS_PhspScoring() { +} + +void EGS_PhspScoring::setApplication(EGS_Application *App) { + EGS_AusgabObject::setApplication(App); + if (!app) { + return; + } + + char buf[512];//useful character buffer + //set up the stack of particles to output to the phase space file + //1000 particles at a time + p_stack = new Particle[store_max]; + + description = "\n*******************************************\n"; + description += "Phase Space Scoring Object ("; + description += name; + description += ")\n"; + description += "*******************************************\n"; + if (score_type==0) { + description += "\n Will output phase space for particles crossing surfaces of geometry:\n"; + description += phsp_geom->getName(); + description += "\n Particles scored on: "; + if (scoredir == 0) { + description += "entering and exiting phase space geometry"; + } + else if (scoredir == 1) { + description += "entering phase space geometry"; + } + else if (scoredir == 2) { + description += "exiting phase space geometry"; + } + } + else if (score_type==1) { + description += "\n Will output phase space for the following exit/entry region pairs:\n"; + description += " Exit regions:\n"; + for (int i=0; igetnRegions(); + for (int ir=0; ir tolist; + for (int i=0; igetAppDir(); + } + if (oformat==0) { + description += "\n Data will be output in EGSnrc format.\n"; + if (app->getNparallel()>0) { + sprintf(buf,"%s_w%d.egsphsp1",getObjectName().c_str(),app->getIparallel()); + } + else { + sprintf(buf,"%s.egsphsp1",getObjectName().c_str()); + } + phsp_fname=egsJoinPath(phspoutdir,buf); + description += "\n Phase space file name:\n"; + description += phsp_fname; + } + else if (oformat==1) { + description += "\n Data will be output in IAEA format.\n"; + if (app->getNparallel()>0) { + sprintf(buf,"%s_w%d.1",getObjectName().c_str(),app->getIparallel()); + } + else { + sprintf(buf,"%s.1",getObjectName().c_str()); + } + phsp_fname=egsJoinPath(phspoutdir,buf); + + //need to add a null terminator + len = phsp_fname.length(); + phsp_fname_char = new char[len+1]; + phsp_fname.copy(phsp_fname_char,len,0); + phsp_fname_char[len]='\0'; //null terminator on string + + //iaea particle charge + iaea_q_type[0]=2; //e- + iaea_q_type[1]=1; //photon + iaea_q_type[2]=3; //e+ + + iaea_id = 1; + + //set up extra float and extra long array indices + latch_ind = 2;//type of latch as defined by iaea + iaea_n_extra_long=1; //only store latch + iaea_i_latch=0; // position of latch in array + if (score_mu) { + iaea_n_extra_float=1; + mu_ind = 0; //set type to generic float + iaea_i_mu=0; //position of mu in array + } + else { + iaea_n_extra_float=0; //no extra floats + } + + description += "\n Phase space file names:\n"; + description += " Header file: " + phsp_fname + ".IAEAheader\n"; + description += " Data file: " + phsp_fname + ".IAEAphsp"; + string xyzname[3] = {"X", "Y", "Z"}; + for (int i=0; i<3; i++) { + if (xyz_is_const[i]) { + ostringstream xyz; + xyz << xyzscore[i]; + description += "\n Data scored at constant " + xyzname[i] + " = " + xyz.str() + " cm"; + } + } + } + description += "\n Particles scored: "; + if (ocharge == 0) { + description += "all"; + } + else if (ocharge == 1) { + description += "photons"; + } + else if (ocharge == 2) { + description += "charged"; + } + if (oformat ==1 && score_mu) { + description += "\n mu will be scored (if available)"; + } + if (oformat ==0 && score_mc) { + description += "\n will score multiple crossers (and descendents)"; + } +} + +//final buffer flush and then close file +//we want to output some data about particles scored +//may ultimately want to allow the user to define scoring zones for output +void EGS_PhspScoring::reportResults() { + flushBuffer(); + if (oformat == 1) { //iaea + int iaea_iostat; + iaea_destroy_source(&iaea_id,&iaea_iostat); + if (iaea_iostat<0) { + egsFatal("\n EGS_PhspScoring: Error closing phase space file.\n"); + } + } + else if (oformat == 0) { + phsp_file.close(); + } + egsInformation("\n======================================================\n"); + egsInformation("Phase Space Scoring Object(%s)\n",name.c_str()); + egsInformation("======================================================\n"); + if (oformat==1) { + egsInformation("\n IAEA format phase space output:\n"); + egsInformation(" Header file: %s.IAEAheader\n",phsp_fname.c_str()); + egsInformation(" Data file: %s.IAEAphsp\n",phsp_fname.c_str()); + } + else if (oformat == 0) { + egsInformation("\n EGSnrc format phase space output:\n"); + egsInformation(" Data file: %s\n",phsp_fname.c_str()); + } + float emintmp; + if (count == countg) { + emintmp = 0.0; + } + else { + emintmp = emin; + } + egsInformation("Summary of scored data:\n"); + egsInformation("=> total no. of particles = %lld \n", count); + egsInformation("=> no. of photons = %lld \n", countg); + egsInformation("=> max. k.e. of all particles = %g MeV\n",emax); + egsInformation("=> min. k.e. of charged particles = %g MeV\n",emintmp); + egsInformation("=> no. of primary histories represented = %lld\n",last_case); + egsInformation("\n======================================================\n"); +} + +//store 1000 particles at a time in p_stack +//if we're at 1000, actually write the particles to the file and update +//the header info +//also, keep track of phase space file counters, min., max. energy +void EGS_PhspScoring::storeParticle(EGS_I64 ncase) { + + //if user requested mu scoring, check if mu is available + if (score_mu && app->getMU() < 0) { + egsWarning("\nEGS_PhspScoring: User requested mu scoring, but mu is inavailable with this source.\n"); + egsWarning("Turning off mu scoring.\n"); + score_mu=false; + } + + //counters, min. and max. k.e. + EGS_Float prm = app->getRM(); + count++; + if (app->top_p.q==0) { + countg++; + } + if (app->top_p.E-abs(app->top_p.q)*prm > emax) { + emax = app->top_p.E-abs(app->top_p.q)*prm; + } + if (app->top_p.q != 0 && app->top_p.E - prm < emin) { + emin = app->top_p.E - prm; + } + + //store particle data in p_stack + //set -ve energy marker if this is a new primary hist. + double E = app->top_p.E; + if (ncase != last_case) { + E = -E; + last_case = ncase; + } + p_stack[phsp_index].E = E; + p_stack[phsp_index].wt = app->top_p.wt; + p_stack[phsp_index].x = app->top_p.x.x; + p_stack[phsp_index].y = app->top_p.x.y; + p_stack[phsp_index].z = app->top_p.x.z; + p_stack[phsp_index].u = app->top_p.u.x; + p_stack[phsp_index].v = app->top_p.u.y; + p_stack[phsp_index].w = app->top_p.u.z; + p_stack[phsp_index].q = app->top_p.q; + if (score_mu) { + p_stack[phsp_index].mu = app->getMU(); + } + p_stack[phsp_index++].latch = app->top_p.latch; + + if (phsp_index > store_max - 1) { + //write store_max particles to the file and reset phsp_index counter + flushBuffer(); + } +} + +//open the phase space file for writing/appending data +void EGS_PhspScoring::openPhspFile() const { +//the file has already been named at this point + if (oformat==0) { //EGSnrc format + if (is_restart) { + phsp_file.open(phsp_fname.c_str(),ios::binary|ios::out|ios::in); + if (!(phsp_file)) + egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s for appending.\n", + phsp_fname.c_str()); + //check that total no. of particles in header = total no. read from .egsdat file + unsigned int count4; + phsp_file.seekg(5,ios::beg); + phsp_file.read((char *) &count4, sizeof(unsigned int)); + if (count4 != countprev) { + egsFatal("\nEGS_PhspScoring: Particle no. mismatch between %s and .egsdat file.\n",phsp_fname.c_str()); + } + //go to the end of the file + phsp_file.seekp(0,ios::end); + if (phsp_file.tellp() != 28 + countprev*sizeof(egs_phsp_write_struct)) { + egsFatal("\nEGS_PhspScoring: File size mismatch in %s and .egsdat file.\n",phsp_fname.c_str()); + } + } + else { + phsp_file.open(phsp_fname.c_str(),ios::binary|ios::out); + if (!(phsp_file)) + egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s for writing.\n", + phsp_fname.c_str()); + //always MODE0 files--i.e. no ZLAST + phsp_file.write("MODE0",5); + //leave space for/skip over the rest of the header + phsp_file.seekp(28,ios::beg); + } + } + else if (oformat == 1) { //IAEA format + int rwmode; + int iaea_iostat; + iaea_id = 1; //numerical index indicating this is the 1st file associated with this object scored + //hard coded to 1 + if (is_restart) { + int rwmode = 3; + iaea_new_source(&iaea_id,phsp_fname_char,&rwmode,&iaea_iostat,len); + if (iaea_iostat < 0) { + egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s.IAEAphsp for appending.\n",phsp_fname.c_str()); + } + //check for consistency with total no. of scored particles as read from .egsdat file + EGS_I64 nparticle; + int type = -1; + int iaea_iostat; + iaea_get_max_particles(&iaea_id,&type,&nparticle); + if (nparticle != countprev) { + egsFatal("\nEGS_PhspScoring: Particle no. mismatch between %s.IAEAphsp and .egsdat file.\n",phsp_fname.c_str()); + } + iaea_check_file_size_byte_order(&iaea_id,&iaea_iostat); + if (iaea_iostat != 0) { + egsFatal("\nEGS_PhspScoring: Byte order/file size mismatch in %s.IAEAphsp.\n",phsp_fname.c_str()); + } + } + else { + int rwmode = 2; + iaea_new_source(&iaea_id,phsp_fname_char,&rwmode,&iaea_iostat,len); + if (iaea_iostat < 0) { + egsFatal("\nEGS_PhspScoring: Failed to open phase space file %s.IAEAphsp for writing.\n",phsp_fname.c_str()); + } + } + + + //set up constant variables + for (int i=0; i<3; i++) { + if (xyz_is_const[i]) { + int index = i; + float constval = xyzscore[i]; + iaea_set_constant_variable(&iaea_id,&index,&constval); + } + } + //set up extra floats and int indices and types + //need to store below in _tmp variables because this is a const function + int latch_ind_tmp = latch_ind; + int iaea_n_extra_long_tmp=iaea_n_extra_long; + int iaea_i_latch_tmp=iaea_i_latch; + int mu_ind_tmp = mu_ind; + int iaea_i_mu_tmp = iaea_i_mu; + int iaea_n_extra_float_tmp=iaea_n_extra_float; + + iaea_set_extra_numbers(&iaea_id,&iaea_n_extra_float_tmp,&iaea_n_extra_long_tmp); + iaea_set_type_extralong_variable(&iaea_id,&iaea_i_latch_tmp,&latch_ind_tmp); + if (score_mu) { + iaea_set_type_extrafloat_variable(&iaea_id,&iaea_i_mu_tmp,&mu_ind_tmp); + } + } +} + +//write phsp_index particles to phase space file +//update header and reset phsp_index +int EGS_PhspScoring::flushBuffer() const { + + if (first_flush) { + openPhspFile(); //here's where we open the phase space file + } + //awkward logic because we do not know if this is a restart + //until after initialization + first_flush = false; + + if (oformat == 1) { //iaea format + for (int j=0; j from_reg, to_reg; + int stype = 0; //default is to use scoring geom + int phspouttype; + int ptype; + int sdir; + int imuscore = 0; + float xyzconst[3]; + bool xyzisconst[3] = {false, false, false}; + string gname; + string outdir; + int err01 = input->getInput("phase space geometry",gname); + if (err01) { + stype = 1; + } + else { + phspgeom = EGS_BaseGeometry::getGeometry(gname); + if (!phspgeom) { + egsWarning("\nEGS_PhspScoring: %s does not name an existing geometry.\n" + "Will assume you want to use exit/entry region pairs.\n",gname.c_str()); + stype = 1; + } + else { + if (input->getInput("score particles on", str) < 0) { + egsInformation("EGS_PhspScoring: No input for scoring direction.\n"); + egsInformation("Will score on entry and exit from phase space geometry.\n"); + sdir = 0; + } + else { + //get scoring direction + vector allowed_sdir; + allowed_sdir.push_back("entry and exit"); + allowed_sdir.push_back("entry"); + allowed_sdir.push_back("exit"); + sdir = input->getInput("score particles on",allowed_sdir,-1); + if (sdir < 0) { + egsFatal("\nEGS_PhspScoring: Invalid scoring direction.\n"); + } + } + } + } + if (stype==1) { + // user wants to use exit/entry region pairs + int err05 = input->getInput("from regions",from_reg); + int err06 = input->getInput("to regions",to_reg); + if (err05 || err06) { + egsFatal("\nEGS_PhspScoring: Missing/incorrect input for scoring method\n" + "(scoring geometry or pairs of exit/entry regions)\n"); + } + else { + //run some checks on exit/entry region pairs + vector::iterator p,p1; + if (from_reg.size() > to_reg.size()) { + p = from_reg.begin(); + egsWarning("\nEGS_PhspScoring: Mismatch in no. of exit/entry regions.\n" + "Will only score for matched pairs.\n"); + p += to_reg.size(); + from_reg.erase(p,p+from_reg.size()-to_reg.size()); + } + else if (to_reg.size() > from_reg.size()) { + p = to_reg.begin(); + egsWarning("\nEGS_PhspScoring: Mismatch in no. of exit/entry regions.\n" + "Will only score for matched pairs.\n"); + p += from_reg.size(); + to_reg.erase(p,p+to_reg.size()-from_reg.size()); + } + //now go through and look for exit region = entry region + int i=0; + while (igetInput("output format", str) < 0) { + egsInformation("EGS_PhspScoring: No input for output format type. Will default to EGSnrc.\n"); + phspouttype = 0; + } + else { + vector allowed_oformat; + allowed_oformat.push_back("EGSnrc"); + allowed_oformat.push_back("IAEA"); + phspouttype = input->getInput("output format", allowed_oformat, -1); + if (phspouttype < 0) { + egsFatal("\nEGS_PhspScoring: Invalid output format.\n"); + } + //see if the user wants to specify constant X/Y/Z for IAEA format + if (phspouttype == 1) { + int err02 = input->getInput("constant X",xyzconst[0]); + int err03 = input->getInput("constant Y",xyzconst[1]); + int err04 = input->getInput("constant Z",xyzconst[2]); + if (!err02) { + xyzisconst[0] = true; + } + if (!err03) { + xyzisconst[1] = true; + } + if (!err04) { + xyzisconst[2] = true; + } + //see if user wants to score mu (if available) + //default is not to score + if (!input->getInput("score mu", str)) { + vector allowed_muscore; + allowed_muscore.push_back("no"); + allowed_muscore.push_back("yes"); + imuscore = input->getInput("score mu",allowed_muscore,-1); + if (imuscore < 0) { + egsWarning("\nEGS_PhspScoring: Invalid input for mu scoring. Will not score mu.\n"); + imuscore = 0; + } + } + } + } + if (phspouttype == 0) { + //see if user wants to score multiple crossers + if (!input->getInput("score multiple crossers", str)) { + vector allowed_scoremc; + allowed_scoremc.push_back("no"); + allowed_scoremc.push_back("yes"); + iscoremc = input->getInput("score multiple crossers",allowed_scoremc,-1); + if (iscoremc < 0) { + egsWarning("\nEGS_PhspScoring: Invalid input for score multiple crossers. Will not score.\n"); + iscoremc = 0; + } + } + } + if (input->getInput("output directory",outdir) < 0) { + outdir=""; + } + if (input->getInput("particle type", str) < 0) { + egsInformation("EGS_PhspScoring: No input for particle type. Will score all.\n"); + ptype = 0; + } + else { + //get particle type + vector allowed_ptype; + allowed_ptype.push_back("all"); + allowed_ptype.push_back("photons"); + allowed_ptype.push_back("charged"); + ptype = input->getInput("particle type",allowed_ptype,-1); + if (ptype < 0) { + egsFatal("\nEGS_PhspScoring: Invalid particle type.\n"); + } + } + + //================================================= + + /* Setup phsp scoring object with input parameters */ + EGS_PhspScoring *result = new EGS_PhspScoring("",f); + result->setName(input); + if (stype==0) { + result->setGeom(phspgeom); + } + else if (stype==1) { + result->setEntryExitReg(from_reg,to_reg); + } + result->setOType(phspouttype); + result->setXYZconst(xyzisconst,xyzconst); + result->setOutDir(outdir); + result->setParticleType(ptype); + result->setScoreDir(sdir); + result->setMuScore(imuscore); + result->setScoreMC(iscoremc); + return result; + } +} diff --git a/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/egs_phsp_scoring.h b/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/egs_phsp_scoring.h new file mode 100644 index 000000000..c6966f88a --- /dev/null +++ b/HEN_HOUSE/egs++/ausgab_objects/egs_phsp_scoring/egs_phsp_scoring.h @@ -0,0 +1,551 @@ +/* +############################################################################### +# +# EGSnrc egs++ phase space scoring object headers +# Copyright (C) 2015 National Research Council Canada +# +# This file is part of EGSnrc. +# +# EGSnrc is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with EGSnrc. If not, see . +# +############################################################################### +# +# Author: Blake Walters, 2018 +# +# Contributors: +# +############################################################################### +*/ + + +/*! \file egs_phsp_scoring.h + * \brief A phase space scoring ausgab object + * \BW + */ + +#ifndef EGS_PHSP_SCORING_ +#define EGS_PHSP_SCORING_ + +#include "egs_ausgab_object.h" +#include "egs_application.h" +#include "egs_scoring.h" +#include "egs_base_geometry.h" + +#ifdef WIN32 + + #ifdef BUILD_PHSP_SCORING_DLL + #define EGS_PHSP_SCORING_EXPORT __declspec(dllexport) + #else + #define EGS_PHSP_SCORING_EXPORT __declspec(dllimport) + #endif + #define EGS_PHSP_SCORING_LOCAL + +#else + + #ifdef HAVE_VISIBILITY + #define EGS_PHSP_SCORING_EXPORT __attribute__ ((visibility ("default"))) + #define EGS_PHSP_SCORING_LOCAL __attribute__ ((visibility ("hidden"))) + #else + #define EGS_PHSP_SCORING_EXPORT + #define EGS_PHSP_SCORING_LOCAL + #endif + +#endif + +/*! \brief A phase space scoring object: header + +\ingroup AusgabObjects + +This ausgab object generates phase space data for particles using one of two methods: +1. Scores particles exiting and/or entering all surfaces of a predefined geometry. + The geometry can be a component of the simulation geometry or coincident with a surface + in the simulation geometry. +2. Scores particles on exiting one user-specified region and entering another. + The user can specify multiple exit/entry region pairs. + +Phase space data can be scored in one of 2 possible formats: + +EGSnrc format: E,x,y,u,v,wt,latch +IAEA format: iq,E,[x],[y],[z],u,v,wt,latch,[mu] + +Note that in IAEA format, the user has the option of specifying a fixed x, y, and/or z coordinate +of the scoring plane/line/point, in which case the fixed coordinates shall not be scored for each +particle but will be specified in the header (.IAEAheader) file. Also, in this format, the +user has the option of scoring the synchronization parameter, mu, passed from the source. + +Can be used in any C++ user code by entering the proper input block in +the ausgab object definition block. + +\verbatim +:start ausgab object definition: + :start ausgab object: + library = egs_phsp_scoring + name = some_name + output format = EGSnrc or IAEA + constant X = X value (cm) at which all particles are scored (IAEA format only) + constant Y = Y value (cm) at which all particles are scored (IAEA format only) + constant Z = Z value (cm) at which all particles are scored (IAEA format only) + particle type = all, photons, or charged + score mu = yes or no [default] (IAEA format only) + score multiple crossers = no (default) or yes (EGSnrc format only) + output directory = name of output directory + + and one of two methods of scoring particles: + + Method 1: score particles on entry to/exit from a predefined geometry + phase space geometry = name of previously defined geometry + score particles on = entry, exit, entry and exit [default] + + Method 2: score particles on exiting one region and entering another + from regions = list of exit region numbers + to regions = list of entry region numbers + + :stop ausgab object: +:stop ausgab object definition: +\endverbatim + +Phase space data is output to the file some_name.egsphsp1 (EGSnrc format) +or some_name.1.IAEAphsp and some_name.1.IAEAheader (IAEA format) +Note that if the user specifies constant X/Y/Z, then particles are all assumed to be scored at the +same X/Y/Z with this(ese) values output to .IAEAheader instead of being output for each particle +to the .IAEAphsp file. + +Particles of the type indicated by the "particle type" input are scored. If this input +is omitted, then all particles are scored. + +In IAEA-format phase space files, the user can opt to score the synchronization parameter, mu. +This option will automatically be turned off if the parameter is not available from the +source. Currently, this parameter can only be passed from egs_beam_source (only if the accelerator +includes synchronized CMs), iaea_phsp_source (if scored using a BEAMnrc simulation with +synchronized CMs or scored using this ausgab object with mu scoring turned on) and +egs_dynamic_source (always available). + +The default is to not score multiple crossers (and their descendents) and, indeed, this +is, by definition, the protocol for IAEA format phase space files. However, if the user is scoring +data in EGSnrc format, then they have the option to include multiple crossers and their +descendents. Note that the marker for a particle having been scored is to set bit 31 of the +particle's latch high. Thus, the marker is associated with the particle, not the scoring +object. This has implications if the user wishes to have multiple phase space scoring +objects in one run: a particle scored by one phase space scoring object will not subsequently +be scored by another, unless the user has set "score multiple crossers = yes" in the +latter. + +If "output directory" is omitted or left blank then the output directory defaults to the +application directory (i.e. $EGS_HOME/appname). + +When using a phase space scoring geometry, particles can be scored on entering the phase space geometry, +exiting the geometry, or both (the default). Be aware of how the "inside" and "outside" of the geometry +are defined when using this option. + +When using pairs of exit/entry regions, the number of regions specified by the "to regions" input +must equal that of the "from regions" input. If the exit region number is equal to the entry +region number, then the pair is deleted prior to the run. + +A note on parallel runs: +If a phase space file is being written during a parallel run, then each job, i, outputs its phase +space data to some_name_wi.[egsphsp1][.1.IAEAheader/phsp]. Thus, the naming scheme is the same as +that for other output files from a parallel run. These phase space files are not added automatically +when the results of a parallel run are combined. The user must either use the addphsp tool or +program their own concatenation routine. + +Example: +The following example input illustrates the two phase space scoring methods. In both +cases, phase space is scored in planes perpendicular to the axis of a water/air cylinder. +\verbatim +:start geometry definition: + :start geometry: + library = egs_planes + type = EGS_Zplanes + positions = 21.0 + name = scoreplane + :stop geometry: + + :start geometry: + library = egs_planes + type = EGS_Zplanes + positions = 0.0 10.0 21.0 + name = cutplane + :stop geometry: + + :start geometry: + library = egs_cylinders + type = EGS_ZCylinders + name = cylinders + radii = 1.0 5.0 15.0 + midpoint = 0 + :start media input: + media = H2O521ICRU AIR521ICRU + set medium = 0 0 + set medium = 1 1 + set medium = 2 0 + :stop media input: + :stop geometry: + + :start geometry: + name = maingeom + library = egs_cdgeometry + base geometry = cutplane + set geometry = 0 cylinders + set geometry = 1 cylinders + :stop geometry: + + simulation geometry = maingeom + :stop geometry definition: + + :start ausgab object definition: + :start ausgab object: + library = egs_phsp_scoring + name = test + from regions = 0 2 + to regions = 3 5 + output format = IAEA + constant Z = 10.0 + particle type = all + score mu = no + :stop ausgab object: + + :start ausgab object: + library = egs_phsp_scoring + name = test2 + phase space geometry = scoreplane + output format = EGSnrc + particle type = all + score particles on = entry + score multiple crossers = yes + :stop ausgab object: +:stop ausgab object definition: +\endverbatim +The first ausgab object, "test," uses scoring method 2 (exit/entry region pairs) to +score phase space data, in IAEA format, for all particles crossing a plane perpendicular +to the cylinder and at the mid-point of the cylinder (Z=10 cm). Data will be scored +for particles within the innermost cylinder (exit/entry regions 0/3) and within the outermost +annulus (exit/entry regions 2/5). Note that the constant Z value of the scoring plane is input, +so data will be in 2D format. Also note that IAEA format, by convention, does not score multiple +crossers. The output will be to test.1.IAEAheader (header file) and test.1.IAEAphsp (phase space data). + +The second ausgab object, "test2," uses scoring method 1 (predefined scoring geometry) to +score phase space data, in EGSnrc format, for all particles crossing a single plane coincident with +the bottom (Z=21 cm) of the cylinder. The scoring plane is given by the geometry, "scoreplane," +which defines a single plane perpendicular to Z at Z=21 cm. Recall that a single plane defines +a single region on the +ve normal side of the plane. In this example, a particle is considered "outside" +scoreplane if Z < 21.0 and inside if Z > 21.0 and, thus, scoring particles on "entry" will collect +data for all particles leaving out the bottom of the cylinder. In this case, however, the specification +of scoring direction is moot, since particles leaving the bottom of the cylinder are effectively leaving +the simulation geometry. Note that the option to score multiple crossers has been turned on. Otherwise, +particles previously scored in "test" would not be scored by "test2." Phase space data will be output +to test2.egsphsp1. +*/ + +class EGS_PHSP_SCORING_EXPORT EGS_PhspScoring : public EGS_AusgabObject { + +public: + + EGS_PhspScoring(const string &Name="", EGS_ObjectFactory *f = 0); + + ~EGS_PhspScoring(); + + int processEvent(EGS_Application::AusgabCall iarg) { + //only score if particle has correct charge + if (ocharge==0 || 1+abs(app->top_p.q)==ocharge) { + EGS_Vector x = app->top_p.x; + int ir = app->top_p.ir; + int latch = app->top_p.latch; + //only score if: 1) it has not been scored before or + //2) we are scoring multiple crossers (EGSnrc format only) + if (!(latch & bsmc()) || (oformat==0 && score_mc)) { + if (score_type==0) { //using scoring geometry + if (iarg == 0) { + phsp_before = phsp_geom->isInside(x); + } + + if (iarg == 5) { + phsp_after = phsp_geom->isInside(x); + if (phsp_after != phsp_before) { + if (scoredir == 0 || (scoredir == 1 && phsp_after) || + (scoredir == 2 && phsp_before)) { + storeParticle(current_case); + } + //set bit 31 to flag this as having been scored + latch = (latch | bsmc()); + app->setLatch(latch); + return 0; + } + } + } + else if (score_type==1) { //pairs of exit/entry regions + if (iarg == 0) { + ir_before = ir; + } + + if (iarg == 5) { + ir_after = ir; + if (from_to[ir_before].size()>0 && ir_before != ir_after) { + for (int i=0; i< from_to[ir_before].size(); i++) { + if (ir_after == from_to[ir_before][i]) { + storeParticle(current_case); + latch = (latch | bsmc()); + app->setLatch(latch); + return 0; + } + } + } + } + } + } + } + return 0; + }; + + int processEvent(EGS_Application::AusgabCall iarg, int ir) { + //same as above, we don't need the region no. + if (ocharge==0 || 1+abs(app->top_p.q)==ocharge) { + EGS_Vector x = app->top_p.x; + int latch = app->top_p.latch; + //only score if: 1) it has not been scored before or + //2) we are scoring multiple crossers (EGSnrc format only) + if (!(latch & bsmc()) || (oformat==0 && score_mc)) { + if (score_type==0) { //using scoring geometry + if (iarg == 0) { + phsp_before = phsp_geom->isInside(x); + } + + if (iarg == 5) { + phsp_after = phsp_geom->isInside(x); + if (phsp_after != phsp_before) { + if (scoredir == 0 || (scoredir == 1 && phsp_after) || + (scoredir == 2 && phsp_before)) { + storeParticle(current_case); + } + //set bit 31 to flag this as having been scored + latch = (latch | bsmc()); + app->setLatch(latch); + return 0; + } + } + } + else if (score_type==1) { //pairs of exit/entry regions + if (iarg == 0) { + ir_before = ir; + } + + if (iarg == 5) { + ir_after = ir; + if (from_to[ir_before].size()>0 && ir_before != ir_after) { + for (int i=0; i< from_to[ir_before].size(); i++) { + if (ir_after == from_to[ir_before][i]) { + storeParticle(current_case); + latch = (latch | bsmc()); + app->setLatch(latch); + return 0; + } + } + } + } + } + } + } + return 0; + }; + + bool needsCall(EGS_Application::AusgabCall iarg) const { + if (iarg == 0 || iarg == 5) { + return true; + } + else { + return false; + } + }; + + //below gets called from startNewShower if current_case != last_case + //don't update last_case yet + void setCurrentCase(EGS_I64 ncase) { + current_case=ncase; + }; + + void setGeom(EGS_BaseGeometry *phspgeom) { + score_type=0; + phsp_geom = phspgeom; + } + + void setEntryExitReg(const vector from_reg, const vector to_reg) { + score_type=1; + fromreg=from_reg; + toreg=to_reg; + } + + void setOType(const int phspouttype) { + oformat = phspouttype; + } + + //set output directory + void setOutDir(const string outdir) { + phspoutdir = outdir; + } + + void setParticleType(const int ptype) { + ocharge = ptype; + } + + void setScoreDir(const int sdir) { + scoredir = sdir; + } + + void setMuScore(const int imuscore) { + if (imuscore == 1) { + score_mu = true; + } + else { + score_mu = false; + } + } + + void setScoreMC(const int iscoremc) { + if (iscoremc==1) { + score_mc = true; + } + else { + score_mc = false; + } + } + + //method below pertains only to IAEA format + //set array element 0/1/2 of xyz_is_constant equal to true + //if scoring at a constant X/Y/Z value and store the + //constant value in element 0/1/2 of array xyzscore + void setXYZconst(bool xyzisconst[3], float xyzconst[3]) { + for (int i=0; i<3; i++) { + xyz_is_const[i] = xyzisconst[i]; + xyzscore[i]=xyzconst[i]; + } + } + + void storeParticle(EGS_I64 ncase); + + int flushBuffer() const; + + void openPhspFile() const; + + void setApplication(EGS_Application *App); + + void reportResults(); + + bool storeState(ostream &data) const; + bool setState(istream &data); + bool addState(istream &data); + +protected: + + struct Particle { + int q, latch; + EGS_Float E, x, y, z, u, v, w, wt, mu; + }; + + //functions, struct and variables used to write EGSnrc format phsp files + static unsigned int bclr() { + return ~((1 << 30) | (1 << 29)); + } + static unsigned int bsqe() { + return (1 << 30); + } + static unsigned int bsqp() { + return (1 << 29); + } + struct egs_phsp_write_struct { + int latch; + float E; + float x,y; + float u,v; + float wt; + egs_phsp_write_struct() {}; + egs_phsp_write_struct(const Particle &p) { + latch = (p.latch & bclr()); + if (p.q == -1) { + latch = (latch | bsqe()); + } + else if (p.q == 1) { + latch = (latch | bsqp()); + } + E = p.E; + x = p.x; + y = p.y; + u = p.u; + v = p.v; + wt = p.w >= 0 ? p.wt : -p.wt; + }; + }; + mutable fstream phsp_file; //output file -- mutable so we can write to it during storeState + EGS_I64 count; //total no. of particles in file + EGS_I64 countg; //no. of photons in file + float emax; //max. k.e. of particles in phsp file + float emin; //min. k.e. of charged particles in file + bool score_mc; //set to true to score multiple crossers and their descendents + + //variables specific to IAEA format + mutable int iaea_id; //file id--mutable so we can write to it during storeState + int latch_ind; //IAEA id for latch variable (set to 2) + int mu_ind; //IAEA id for mu--no ID for now so set to generic float (0) + int iaea_n_extra_float, iaea_n_extra_long; //no. of extra floats, ints + int iaea_i_latch, iaea_i_mu; //indices of indicated variables in arrays + int iaea_q_type[3]; //easy conversion from q to iaea type + bool xyz_is_const[3]; //set to true if scoring at constant X/Y/Z + float xyzscore[3]; //constant X/Y/Z scoring values + int len; //length of name + char *phsp_fname_char; //need file name in char format + bool score_mu; //set to true if scoring mu + float pmu; //mu value associated with particle + + //back to variables common to EGSnrc and IAEA formats + + Particle *p_stack; //the stored particle stack + + //below used to set bit 31 to denote the particle has been scored + static unsigned int bsmc() { + return (1 << 31); + } + + int store_max; //max. no. of particles to store in p_stack + mutable int phsp_index; //index in p_stack array -- mutable so we can change it in storeState + mutable bool first_flush; //first time writing to file in this run -- mutable so we can change it in storeState + + bool is_restart; //true if this is a restart + EGS_I64 countprev; //no. of particles written to file before restart + + EGS_I64 last_case; //last primary history scored + EGS_I64 current_case; //current primary history + + int oformat; //0 for EGSnrc format, 1 for IAEA format + + int ocharge; //particle type for output: 0--all; 1--photons; 2--charged particles + + string phsp_fname; //name of phase space file + + string phspoutdir; //output directory + + int score_type; //0 if scoring on exiting/entering a phase space geometry + //1 if using pairs of exit/entry regions + + //for method 1: scoring using predefined geometry + EGS_BaseGeometry *phsp_geom; //geometry on entrance to/exit from which phase space data is scored + int scoredir; //scoring direction: 0--on entry and exit; 1--on entry; 2--on exit + bool phsp_before; //true if inside scoring geometry before step + bool phsp_after; //true if inside scoring geometry after step + + //for method 2: scoring using exit/entry region pairs + vector fromreg; //array of exit regions + vector toreg; //array of entry regions + vector > from_to; //from a given global exit region, an array of possible entry regions + int ir_before, ir_after; //reg. no. before and after step +}; + +#endif diff --git a/HEN_HOUSE/egs++/egs_advanced_application.cpp b/HEN_HOUSE/egs++/egs_advanced_application.cpp index f73280b2b..78d729af8 100644 --- a/HEN_HOUSE/egs++/egs_advanced_application.cpp +++ b/HEN_HOUSE/egs++/egs_advanced_application.cpp @@ -1198,6 +1198,14 @@ void EGS_AdvancedApplication::setRadiativeSplitting(const EGS_Float &nsplit) { the_egsvr->nbr_split = nsplit; } +//************************************************************ +// Utility function for ausgab phase space scoring objects +//************************************************************ +void EGS_AdvancedApplication::setLatch(int latch) { + int np = the_stack->np-1; + the_stack->latch[np] = latch; +} + extern __extc__ void egsHowfar() { CHECK_GET_APPLICATION(app,"egsHowfar()"); int np = the_stack->np-1; diff --git a/HEN_HOUSE/egs++/egs_advanced_application.h b/HEN_HOUSE/egs++/egs_advanced_application.h index ea95e1acf..b627ef340 100644 --- a/HEN_HOUSE/egs++/egs_advanced_application.h +++ b/HEN_HOUSE/egs++/egs_advanced_application.h @@ -211,6 +211,12 @@ class APP_EXPORT EGS_AdvancedApplication : public EGS_Application { void setEdep(EGS_Float edep); EGS_Float getEcut(); EGS_Float getPcut(); + + //************************************************************ + // Utility function for ausgab phase space scoring objects + //************************************************************ + void setLatch(int latch); + /* Needed by some sources */ EGS_Float getRM(); /* Turn ON/OFF radiative splitting */ diff --git a/HEN_HOUSE/egs++/egs_application.h b/HEN_HOUSE/egs++/egs_application.h index 5e8f52cab..527513719 100644 --- a/HEN_HOUSE/egs++/egs_application.h +++ b/HEN_HOUSE/egs++/egs_application.h @@ -674,6 +674,18 @@ class EGS_EXPORT EGS_Application { geometry->getLabelRegions(str, regs); } + /*! \brief Returns the value of the \a mu synchronization parameter + + The parameter, \a mu, is a random number on \a [0,1) associated with each + primary history and is retrieved from \a source. It can be used to + synchronize geometric parameters throughout a simulation. If \a mu is + not available in \a source (i.e., the \a getMu function has not been + reimplemented in \a source), then this returns -1. + */ + EGS_Float getMU() { + return source->getMu(); + } + /*! \brief User scoring function for accumulation of results and VRT implementation This function first calls the processEvent() method of the ausgab objects @@ -1116,6 +1128,12 @@ class EGS_EXPORT EGS_Application { return -1.0; }; virtual void setRadiativeSplitting(const EGS_Float &nsplit) {}; + + //************************************************************ + // Utility function for ausgab phase space scoring objects + //************************************************************ + virtual void setLatch(int latch) {}; + }; #define APP_MAIN(app_name) \ diff --git a/HEN_HOUSE/iaea_phsp/iaea_header.cpp b/HEN_HOUSE/iaea_phsp/iaea_header.cpp index 1181623b4..c06c49558 100644 --- a/HEN_HOUSE/iaea_phsp/iaea_header.cpp +++ b/HEN_HOUSE/iaea_phsp/iaea_header.cpp @@ -687,11 +687,11 @@ int iaea_header_type::check_byte_order() // printf("\n \t %x %x %x %x", pf[0],pf[1],pf[2],pf[3]); if(pf[0] == 0 && pf[3] != 0) { - printf("\nByte order: INTEL / ALPHA,LINUX -> LITLE_ENDIAN \n"); + //printf("\nByte order: INTEL / ALPHA,LINUX -> LITLE_ENDIAN \n"); return(LITTLE_ENDIAN); }else if(pf[0] != 0 && pf[3] == 0) { - printf("\nByte order: OTHER (SGI,SUN-SOLARIS) -> BIG_ENDIAN \n "); + //printf("\nByte order: OTHER (SGI,SUN-SOLARIS) -> BIG_ENDIAN \n "); return(BIG_ENDIAN); } else