Skip to content
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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/custom_source/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
project(openmc_sources CXX)
add_library(source SHARED source_ring.cpp)
find_package(OpenMC REQUIRED)
find_package(OpenMC REQUIRED HINTS "/home/cpf/openmc/build/bin/openmc")
if (OpenMC_FOUND)
message(STATUS "Found OpenMC: ${OpenMC_DIR}")
endif()
Expand Down
3 changes: 2 additions & 1 deletion include/openmc/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ enum TallyScore {
SCORE_INVERSE_VELOCITY = -13, // flux-weighted inverse velocity
SCORE_FISS_Q_PROMPT = -14, // prompt fission Q-value
SCORE_FISS_Q_RECOV = -15, // recoverable fission Q-value
SCORE_DECAY_RATE = -16 // delayed neutron precursor decay rate
SCORE_DECAY_RATE = -16, // delayed neutron precursor decay rate
SCORE_PULSE_HEIGHT = -17 // pulse-height of photons in a cell
};

// Global tally parameters
Expand Down
10 changes: 10 additions & 0 deletions include/openmc/particle.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ class Particle : public ParticleData {
void event_revive_from_secondary();
void event_death();

//! needed for determining the value of the pulse-height tally
//
//! sums up the energy a photon looses after in a cell
void energy_delivered_in_cell();
//! adds the last energy of the particle if it dies.
void killed_particle_energy_delivered();
//! removes the energy from created secondary particles to avoid
//! double counting
void remove_energy_of_secondary();

//! Cross a surface and handle boundary conditions
void cross_surface();

Expand Down
3 changes: 3 additions & 0 deletions include/openmc/particle_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ class ParticleData {
// Secondary particle bank
vector<SourceSite> secondary_bank_;

std::vector<double> pht_storage_; // array for the pulse-height tally

int64_t current_work_; // current work index

vector<double> flux_derivs_; // for derivatives for this particle
Expand Down Expand Up @@ -435,6 +437,7 @@ class ParticleData {
SourceSite& secondary_bank(int i) { return secondary_bank_[i]; }
decltype(secondary_bank_)& secondary_bank() { return secondary_bank_; }
int64_t& current_work() { return current_work_; }
std::vector<double>& pht_storage() { return pht_storage_; }
const int64_t& current_work() const { return current_work_; }
double& flux_derivs(int i) { return flux_derivs_[i]; }
const double& flux_derivs(int i) const { return flux_derivs_[i]; }
Expand Down
2 changes: 2 additions & 0 deletions include/openmc/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ extern int trigger_batch_interval; //!< Batch interval for triggers
extern "C" int verbosity; //!< How verbose to make output
extern double weight_cutoff; //!< Weight cutoff for Russian roulette
extern double weight_survive; //!< Survival weight after Russian roulette
extern std::vector<double> bins_pht; //! Used for the pulse-height tally
extern int cell_pht; //! Used for the pulse-height tally
Copy link
Contributor

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?

} // namespace settings

//==============================================================================
Expand Down
2 changes: 2 additions & 0 deletions include/openmc/simulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

@cfichtlscherer cfichtlscherer Sep 21, 2021

Choose a reason for hiding this comment

The 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 external std::vector<double> bins_pht; nor external int cell_pht; here.
I think I was in too much of a hurry here overall and really wanted to create a reasonably running version.

extern int cell_pht;
} // namespace simulation

//==============================================================================
Expand Down
5 changes: 5 additions & 0 deletions include/openmc/tallies/tally_scoring.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ void score_tracklength_tally(Particle& p, double distance);
//! \param tallies A vector of tallies to score to
void score_surface_tally(Particle& p, const vector<int>& tallies);

//! Score the pulse-height tally
//
//! \param p The particle being tracked
void score_pht_tally(Particle& p);

} // namespace openmc

#endif // OPENMC_TALLIES_TALLY_SCORING_H
1 change: 1 addition & 0 deletions src/output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ const std::unordered_map<int, const char*> score_names = {
{SCORE_FISS_Q_PROMPT, "Prompt fission power"},
{SCORE_FISS_Q_RECOV, "Recoverable fission power"},
{SCORE_CURRENT, "Current"},
{SCORE_PULSE_HEIGHT, "pulse-height"},
};

//! Create an ASCII output file showing all tally results.
Expand Down
46 changes: 45 additions & 1 deletion src/particle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The 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 remove_energy_of_secondary. Is this correct? Should the condition instead be:

if (type() == ParticleType::photon && E_last() >  settings::energy_cutoff[1])
  energy_delivered_in_cell();


// Reset banked weight during collision
n_bank() = 0;
n_bank_second() = 0;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Copy link
Contributor

Choose a reason for hiding this comment

The 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)
Copy link
Contributor

Choose a reason for hiding this comment

The 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 cell_born() attribute. I am guessing that adding this fixed a bug for you at some point. I think we could probably remove this, but I'll have to look into it more to be sure.

Copy link
Contributor Author

@cfichtlscherer cfichtlscherer Sep 21, 2021

Choose a reason for hiding this comment

The 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 pht_storage again, because otherwise we would count energies twice.
However, we could put the cell_born() attribute in a different place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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

Copy link
Contributor

Choose a reason for hiding this comment

The 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:

void Particle::remove_energy_of_secondary()
{
  if (!exhaustive_find_cell(*this)) {
    mark_as_lost(
      "Could not find the cell containing particle " + std::to_string(id()));
    return;
  }

  // Set birth cell attribute
  cell_born() = coord(n_coord() - 1).cell;

  if (type() == ParticleType::photon && E() > settings::energy_cutoff[1])
  pht_storage()[cell_born()] -= E();
}

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()
Expand Down
2 changes: 2 additions & 0 deletions src/particle_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ ParticleData::ParticleData()
// Create microscopic cross section caches
neutron_xs_.resize(data::nuclides.size());
photon_xs_.resize(data::elements.size());

pht_storage_.resize(model::cells.size(), 0.0);
cfichtlscherer marked this conversation as resolved.
Show resolved Hide resolved
}

TrackState ParticleData::get_track_state() const
Expand Down
1 change: 0 additions & 1 deletion src/physics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ void collision(Particle& p)
sample_positron_reaction(p);
break;
}

Copy link
Contributor

Choose a reason for hiding this comment

The 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]) {
Expand Down
1 change: 1 addition & 0 deletions src/reaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ std::unordered_map<int, std::string> REACTION_NAME_MAP {
{SCORE_INVERSE_VELOCITY, "inverse-velocity"},
{SCORE_FISS_Q_PROMPT, "fission-q-prompt"},
{SCORE_FISS_Q_RECOV, "fission-q-recoverable"},
{SCORE_PULSE_HEIGHT, "pulse-height"},
// Normal ENDF-based reactions
{TOTAL_XS, "(n,total)"},
{ELASTIC, "(n,elastic)"},
Expand Down
13 changes: 12 additions & 1 deletion src/simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

//==============================================================================
Expand Down Expand Up @@ -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()) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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 p.event_collide(). It should be right near score_collision_tally in that function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 p.event_collide() right now, since when this method is called, it's not yet determined here whether the particle and its progeny have finished simulating. I don't know how we could put this information in here. Maybe I'm on the wrong track here.

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);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop could be optimized by storing the PHT id as pht_tally_id and having a boolean is_pht_simulation as global variables so that you aren't iterating through each tally in the system after each photon death

if (is_pht_simulation)
    score_pht_tally(pht_tally_id, p)

break;
}
}
p.event_death();
}
Expand Down
1 change: 1 addition & 0 deletions src/tallies/filter_cell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "openmc/capi.h"
#include "openmc/cell.h"
#include "openmc/error.h"
#include "openmc/simulation.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undo this

#include "openmc/xml_interface.h"

namespace openmc {
Expand Down
2 changes: 2 additions & 0 deletions src/tallies/filter_energy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 pht_storage of the particle to the tally and the filters.

Copy link
Contributor

Choose a reason for hiding this comment

The 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);
}

Expand Down
15 changes: 15 additions & 0 deletions src/tallies/tally.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.");
Copy link
Contributor

Choose a reason for hiding this comment

The 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) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How difficult will it be to extend this capability to neutrons?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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?

Copy link
Contributor

Choose a reason for hiding this comment

The 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 settings::photon_transport is actually not sufficient to determine that the simulation doesn't contain neutrons. settings::photon_transport is true when we run coupled neutron-photon simulations too. The most robust way would be to look through each external source distribution openmc::model::external_sources and see if it emits photons. However, I don't see a way to do that easily since we have different types of external sources (IndependentSource, FileSource, CustomSourceWrapper)... let me think more about how to handle that


// If settings.xml trigger is turned on, create tally triggers
if (settings::trigger_on) {
this->init_triggers(node);
Expand Down
23 changes: 23 additions & 0 deletions src/tallies/tally_scoring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "openmc/tallies/filter.h"
#include "openmc/tallies/filter_delayedgroup.h"
#include "openmc/tallies/filter_energy.h"
#include "openmc/xml_interface.h"

#include <string>

Expand Down Expand Up @@ -2468,4 +2469,26 @@ void score_surface_tally(Particle& p, const vector<int>& tallies)
match.bins_present_ = false;
}

void score_pht_tally(Particle& p)
{
for (auto i_tally : model::active_tracklength_tallies) {
auto& tally {*model::tallies[i_tally]};

auto filter_iter = FilterBinIter(tally, p);
auto score_index = 0;

auto score = p.pht_storage()[simulation::cell_pht];
//auto score = p.pht_storage()[7];
//auto score = p.pht_storage()[0];
// the -1 in the next line is for the index shift
auto scoring_it = std::upper_bound(simulation::bins_pht.begin(), simulation::bins_pht.end(), score) - simulation::bins_pht.begin() - 1;
#pragma omp atomic
tally.results_(scoring_it, score_index, TallyResult::VALUE) += 1;
}

// Reset all the filter matches for the next tally event.
for (auto& match : p.filter_matches())
match.bins_present_ = false;
}

} // namespace openmc
6 changes: 6 additions & 0 deletions tests/regression_tests/cpp_driver/CMakeLists.txt
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)
Empty file.
55 changes: 55 additions & 0 deletions tests/regression_tests/pulse_height_tally/inputs_true.dat
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>
Loading