-
Notifications
You must be signed in to change notification settings - Fork 525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pulse height tally #1881
Pulse height tally #1881
Changes from all commits
974dd9e
f826f19
60dbd36
fd00996
bfc0941
7b1269b
9d8f244
16c1bdd
03785e0
5f2ef89
a3236d7
7328a4a
9e66d14
a78a374
de24a93
137f829
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,8 @@ extern const RegularMesh* ufs_mesh; | |
extern vector<double> k_generation; | ||
extern vector<int64_t> work_index; | ||
|
||
extern std::vector<double> bins_pht; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You shouldn't make these extern declarations twice. It appears you should only have them in simulation.h. If you need them in settings.cpp, you should include simulation.h there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that's part of the problem: my implementation doesn't yet work properly with OpenMC's tally functions. I think I need to work on how the tally output is determined in the end from the pht_storage array. Then we don't need to define |
||
extern int cell_pht; | ||
} // namespace simulation | ||
|
||
//============================================================================== | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
#include "openmc/message_passing.h" | ||
#include "openmc/mgxs_interface.h" | ||
#include "openmc/nuclide.h" | ||
#include "openmc/particle_data.h" | ||
#include "openmc/photon.h" | ||
#include "openmc/physics.h" | ||
#include "openmc/physics_mg.h" | ||
|
@@ -85,6 +86,7 @@ void Particle::create_secondary( | |
void Particle::from_source(const SourceSite* src) | ||
{ | ||
// Reset some attributes | ||
|
||
clear(); | ||
surface() = 0; | ||
cell_born() = C_NONE; | ||
|
@@ -286,6 +288,11 @@ void Particle::event_collide() | |
} | ||
} | ||
|
||
// TODO: The assumption behind the modelling of the pulse-height tally is that | ||
// particles lose energy only in collisions, for a more comprehensive modeling | ||
// of charged particles this has to be changed. | ||
if (type() == ParticleType::photon){energy_delivered_in_cell();} // score the pht only for photons | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to this logic, secondary photons that start with an energy less than the threshold will still be scored in this function but their initial energy does not get scored in
|
||
|
||
// Reset banked weight during collision | ||
n_bank() = 0; | ||
n_bank_second() = 0; | ||
|
@@ -315,7 +322,6 @@ void Particle::event_collide() | |
coord(j + 1).u = coord(j).u; | ||
} | ||
} | ||
|
||
// Score flux derivative accumulators for differential tallies. | ||
if (!model::active_tallies.empty()) | ||
score_collision_derivative(*this); | ||
|
@@ -350,6 +356,9 @@ void Particle::event_revive_from_secondary() | |
secondary_bank().pop_back(); | ||
n_event() = 0; | ||
|
||
// remove energy of created secondary particles from pht value | ||
remove_energy_of_secondary(); | ||
|
||
// Enter new particle in particle track file | ||
if (write_track()) | ||
add_particle_track(*this); | ||
|
@@ -389,6 +398,41 @@ void Particle::event_death() | |
int64_t offset = id() - 1 - simulation::work_index[mpi::rank]; | ||
simulation::progeny_per_particle[offset] = n_progeny(); | ||
} | ||
killed_particle_energy_delivered(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indent |
||
} | ||
|
||
void Particle::energy_delivered_in_cell() | ||
{ | ||
// Adds the energy the particle loses during the collision. | ||
pht_storage()[coord(n_coord() - 1).cell] += E_last() - E(); | ||
} | ||
|
||
void Particle::killed_particle_energy_delivered() | ||
{ | ||
// Adds the energy of killed particles. | ||
pht_storage()[coord(n_coord() - 1).cell] += E(); | ||
} | ||
|
||
void Particle::remove_energy_of_secondary() | ||
{ | ||
|
||
// determine where the particle was born | ||
if (coord(n_coord() - 1).cell == C_NONE) { | ||
if (!exhaustive_find_cell(*this)) { | ||
mark_as_lost( | ||
"Could not find the cell containing particle " + std::to_string(id())); | ||
return; | ||
} | ||
|
||
// Set birth cell attribute | ||
if (cell_born() == C_NONE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you have to do this here? I think you are probably calling this function a bit early somewhere if you are making yourself responsible for setting the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you are right, this fixed a bug for me. When I remove that, I get an error message. I think I need to set this attribute because I need it some lines below when I do pht_storage()[cell_born()] -= E(); In this line, we subtract the energy of all particles created in reactions from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I replaced coord(0).cell to make the tally work on multiple leveled universes coord(n_coord() - 1).cell There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cfichtlscherer, upon further inspection I think this logic can be simplified a bit since the code will only enter this block if a new source particle from the secondary bank is populated:
|
||
cell_born() = coord(n_coord() - 1).cell; | ||
} | ||
|
||
// settings::energy_cutoff[1] is the cutoff energy of photons | ||
// Remove the energy of created secondary particles from the pht_storage array | ||
if (type() == ParticleType::photon) | ||
pht_storage()[cell_born()] -= E(); | ||
} | ||
|
||
void Particle::cross_surface() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,7 +64,6 @@ void collision(Particle& p) | |
sample_positron_reaction(p); | ||
break; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Undo this line |
||
// Kill particle if energy falls below cutoff | ||
int type = static_cast<int>(p.type()); | ||
if (p.E() < settings::energy_cutoff[type]) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ | |
#include "openmc/tallies/derivative.h" | ||
#include "openmc/tallies/filter.h" | ||
#include "openmc/tallies/tally.h" | ||
#include "openmc/tallies/tally_scoring.h" | ||
#include "openmc/tallies/trigger.h" | ||
#include "openmc/timer.h" | ||
#include "openmc/track_output.h" | ||
|
@@ -289,6 +290,9 @@ const RegularMesh* ufs_mesh {nullptr}; | |
vector<double> k_generation; | ||
vector<int64_t> work_index; | ||
|
||
std::vector<double> bins_pht; | ||
int cell_pht; | ||
|
||
} // namespace simulation | ||
|
||
//============================================================================== | ||
|
@@ -709,8 +713,15 @@ void transport_history_based_single_particle(Particle& p) | |
p.event_collide(); | ||
} | ||
p.event_revive_from_secondary(); | ||
if (!p.alive()) | ||
if (!p.alive()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not the right place to do the scoring. It should probably be in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had the problem here that we can do the scoring only after the particle and all its progeny have been simulated. That's why I put it in this unusual place. I don't know exactly how we can put this in |
||
for (auto i_tally = 0; i_tally < model::tallies.size(); ++i_tally) { | ||
const auto& tally {*model::tallies[i_tally]}; | ||
if (tally.scores_[0] == -17) { | ||
score_pht_tally(p); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This loop could be optimized by storing the PHT id as
|
||
break; | ||
} | ||
} | ||
p.event_death(); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
#include "openmc/capi.h" | ||
#include "openmc/cell.h" | ||
#include "openmc/error.h" | ||
#include "openmc/simulation.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Undo this |
||
#include "openmc/xml_interface.h" | ||
|
||
namespace openmc { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
#include "openmc/mgxs_interface.h" | ||
#include "openmc/search.h" | ||
#include "openmc/settings.h" | ||
#include "openmc/simulation.h" | ||
#include "openmc/xml_interface.h" | ||
|
||
namespace openmc { | ||
|
@@ -18,6 +19,7 @@ namespace openmc { | |
void EnergyFilter::from_xml(pugi::xml_node node) | ||
{ | ||
auto bins = get_node_array<double>(node, "bins"); | ||
simulation::bins_pht = bins; //! store them as a global variable for the pht | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not a good design. If you have multiple energy filters in your problem, each of them will be trying to modify global state. it wont' work if anyone tries to tally any other energy-dependent quantities. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I will also revise this part completely and think about how to pass the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree with @gridley. I'd encourage you to think about the user interface for this feature a bit since that will influence how data is stored on the C++ side. For example, would the following be appropriate? ph_tally = openmc.Tally()
ph_tally.filters = [openmc.CellFilter(...), openmc.EnergyFilter(...)]
ph_tally.scores = ['pulse-height'] It may be the case that pulse-height tallies are different enough that they deserve their own class, in which case it might look something like: ph_tally = openmc.PulseHeightTally()
ph_tally.filters = [openmc.CellFilter(...), openmc.EnergyFilter(...)] I'm not sure offhand whether this latter idea is necessary. We may have to think a bit more carefully about the overall design of different tally types. |
||
this->set_bins(bins); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,10 @@ | |
#include "openmc/tallies/filter_surface.h" | ||
#include "openmc/xml_interface.h" | ||
|
||
#ifdef _OPENMP | ||
#include <omp.h> | ||
#endif | ||
|
||
#include "xtensor/xadapt.hpp" | ||
#include "xtensor/xbuilder.hpp" // for empty_like | ||
#include "xtensor/xview.hpp" | ||
|
@@ -253,6 +257,17 @@ Tally::Tally(pugi::xml_node node) | |
} | ||
} | ||
|
||
// Currently the pulse-height tally is only working in a selected type of | ||
// settings Here these settings are checked again | ||
bool exists = std::find(std::begin(scores_), std::end(scores_), | ||
TallyScore::SCORE_PULSE_HEIGHT) != std::end(scores_); | ||
if (exists && scores_.size() > 1) { | ||
fatal_error("Error: The Pulse-Height Tally can currently not be used in combination with other tallys."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By this logic, this checks whether more than one score is defined for a single pulse height tally, so the error message should be "The Pulse Height Tally cannot currently be used with multiple scores" |
||
} | ||
if (exists && !settings::photon_transport) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add checks to make sure each filter is of type cell or energy, are there any other filters that might be relevant? In that case, I also think there should be a check to make sure there is at least one energy and cell filter defined in the tally. One design choice would also be to enforce exactly one cell filter and one energy filter for this tally type, and users can define multiple pulse height tallies if there are multiple detectors in the system |
||
fatal_error("Error: The Pulse-Height Tally works only with photon transport True."); | ||
} | ||
Comment on lines
+267
to
+269
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How difficult will it be to extend this capability to neutrons? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have thought about how useful this feature would be. To simulate neutron detectors, I think the absorption tally is enough. Are there other applications? Would users be interested in this? I could imagine that fission makes the whole thing more complicated. But if you like, we can work on it. Maybe in an update when we have implemented the tally for photons? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There may be users interested in this, but thinking about it a bit, it does seem that it will be a little more complicated for a number of reasons so perhaps we should defer for now. Note that checking |
||
|
||
// If settings.xml trigger is turned on, create tally triggers | ||
if (settings::trigger_on) { | ||
this->init_triggers(node); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
cmake_minimum_required(VERSION 3.3 FATAL_ERROR) | ||
project(openmc_cpp_driver CXX) | ||
add_executable(cpp_driver driver.cpp) | ||
find_package(OpenMC REQUIRED HINTS /home/cpf/openmc/build) | ||
target_link_libraries(cpp_driver OpenMC::libopenmc) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<geometry> | ||
<cell id="1" material="1" name="detector" region="-1 2 -3" universe="1" /> | ||
<cell id="2" material="2" name="surrounding" region="~(-1 2 -3) -4" universe="1" /> | ||
<cell fill="1" id="3" name="root cell" region="-4" universe="2" /> | ||
<surface coeffs="0 0 2.54" id="1" name="cylinder" type="z-cylinder" /> | ||
<surface coeffs="0" id="2" name="bottom" type="z-plane" /> | ||
<surface coeffs="5" id="3" name="top" type="z-plane" /> | ||
<surface boundary="vacuum" coeffs="0 0 0 10" id="4" name="outer sphere" type="sphere" /> | ||
</geometry> | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<materials> | ||
<material id="1" name="sodium iodide detector material"> | ||
<density units="g/cc" value="3.67" /> | ||
<nuclide ao="1.0" name="Na23" /> | ||
<nuclide ao="1.0" name="I127" /> | ||
</material> | ||
<material id="2" name="air"> | ||
<density units="g/cc" value="0.001225" /> | ||
<nuclide ao="3.985348" name="N14" /> | ||
<nuclide ao="0.014652" name="N15" /> | ||
<nuclide ao="1" name="O16" /> | ||
</material> | ||
</materials> | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<settings> | ||
<run_mode>fixed source</run_mode> | ||
<particles>1000</particles> | ||
<batches>1</batches> | ||
<inactive>0</inactive> | ||
<source particle="photon" strength="1.0"> | ||
<space type="point"> | ||
<parameters>0.0 0.0 -1.0</parameters> | ||
</space> | ||
<angle reference_uvw="0.0 0.0 1.0" type="monodirectional" /> | ||
<energy type="discrete"> | ||
<parameters>662000.0 1.0</parameters> | ||
</energy> | ||
</source> | ||
<photon_transport>true</photon_transport> | ||
<seed>1</seed> | ||
</settings> | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<tallies> | ||
<filter id="1" type="cell"> | ||
<bins>1</bins> | ||
</filter> | ||
<filter id="2" type="energy"> | ||
<bins>0.0 20000.0 40000.0 60000.0 80000.0 100000.0 120000.0 140000.0 160000.0 180000.0 200000.0 220000.0 240000.0 260000.0 280000.0 300000.0 320000.0 340000.0 360000.0 380000.0 400000.0 420000.0 440000.0 460000.0 480000.0 500000.0 520000.0 540000.0 560000.0 580000.0 600000.0 620000.0 640000.0 660000.0 680000.0 700000.0 720000.0 740000.0 760000.0 780000.0 800000.0 820000.0 840000.0 860000.0 880000.0 900000.0 920000.0 940000.0 960000.0 980000.0 1000000.0</bins> | ||
</filter> | ||
<tally id="1" name="pulse-height tally"> | ||
<filters>1 2</filters> | ||
<scores>pulse-height</scores> | ||
</tally> | ||
</tallies> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where exactly is cell_pht initialized?