From 9553f2908a9d5b4a929ff6fed93a4c252deb1d3d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 1 Jul 2019 22:08:42 -0500 Subject: [PATCH] Improvements in Tally interfaces --- include/openmc/capi.h | 4 +- include/openmc/tallies/tally.h | 16 +++- openmc/capi/filter.py | 1 + openmc/capi/tally.py | 6 +- src/tallies/filter.cpp | 28 ++++--- src/tallies/tally.cpp | 136 +++++++++++++++++++++------------ 6 files changed, 124 insertions(+), 67 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index afca455ddf..fba6538188 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -95,7 +95,7 @@ extern "C" { int openmc_tally_get_active(int32_t index, bool* active); int openmc_tally_get_estimator(int32_t index, int* estimator); int openmc_tally_get_id(int32_t index, int32_t* id); - int openmc_tally_get_filters(int32_t index, const int32_t** indices, int* n); + int openmc_tally_get_filters(int32_t index, const int32_t** indices, size_t* n); int openmc_tally_get_n_realizations(int32_t index, int32_t* n); int openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n); int openmc_tally_get_scores(int32_t index, int** scores, int* n); @@ -104,7 +104,7 @@ extern "C" { int openmc_tally_results(int32_t index, double** ptr, size_t shape_[3]); int openmc_tally_set_active(int32_t index, bool active); int openmc_tally_set_estimator(int32_t index, const char* estimator); - int openmc_tally_set_filters(int32_t index, int n, const int32_t* indices); + int openmc_tally_set_filters(int32_t index, size_t n, const int32_t* indices); int openmc_tally_set_id(int32_t index, int32_t id); int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides); int openmc_tally_set_scores(int32_t index, int n, const char** scores); diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index 969c064e75..be7666d5ca 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -2,8 +2,10 @@ #define OPENMC_TALLIES_TALLY_H #include "openmc/constants.h" +#include "openmc/tallies/filter.h" #include "openmc/tallies/trigger.h" +#include #include "pugixml.hpp" #include "xtensor/xfixed.hpp" #include "xtensor/xtensor.hpp" @@ -21,16 +23,22 @@ namespace openmc { class Tally { public: - Tally(); + explicit Tally(int32_t id); + + static Tally* create(int32_t id = -1); void init_from_xml(pugi::xml_node node); + void set_id(int32_t id); + void set_scores(pugi::xml_node node); - void set_scores(std::vector scores); + void set_scores(const std::vector& scores); void set_nuclides(pugi::xml_node node); + void set_nuclides(const std::vector& nuclides); + //---------------------------------------------------------------------------- // Methods for getting and setting filter/stride data. @@ -38,7 +46,7 @@ public: int32_t filters(int i) const {return filters_[i];} - void set_filters(const int32_t filter_indices[], int n); + void set_filters(gsl::span filters); int32_t strides(int i) const {return strides_[i];} @@ -112,6 +120,8 @@ private: std::vector strides_; int32_t n_filter_bins_ {0}; + + gsl::index index_; }; //============================================================================== diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 404cd3898e..bda3c3178f 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -94,6 +94,7 @@ _dll.openmc_zernike_filter_set_order.restype = c_int _dll.openmc_zernike_filter_set_order.errcheck = _error_handler _dll.tally_filters_size.restype = c_size_t + class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 9529a31f21..88c14e4494 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -36,7 +36,7 @@ _dll.openmc_tally_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_id.restype = c_int _dll.openmc_tally_get_id.errcheck = _error_handler _dll.openmc_tally_get_filters.argtypes = [ - c_int32, POINTER(POINTER(c_int32)), POINTER(c_int)] + c_int32, POINTER(POINTER(c_int32)), POINTER(c_size_t)] _dll.openmc_tally_get_filters.restype = c_int _dll.openmc_tally_get_filters.errcheck = _error_handler _dll.openmc_tally_get_n_realizations.argtypes = [c_int32, POINTER(c_int32)] @@ -63,7 +63,7 @@ _dll.openmc_tally_results.errcheck = _error_handler _dll.openmc_tally_set_active.argtypes = [c_int32, c_bool] _dll.openmc_tally_set_active.restype = c_int _dll.openmc_tally_set_active.errcheck = _error_handler -_dll.openmc_tally_set_filters.argtypes = [c_int32, c_int, POINTER(c_int32)] +_dll.openmc_tally_set_filters.argtypes = [c_int32, c_size_t, POINTER(c_int32)] _dll.openmc_tally_set_filters.restype = c_int _dll.openmc_tally_set_filters.errcheck = _error_handler _dll.openmc_tally_set_estimator.argtypes = [c_int32, c_char_p] @@ -249,7 +249,7 @@ class Tally(_FortranObjectWithID): @property def filters(self): filt_idx = POINTER(c_int32)() - n = c_int() + n = c_size_t() _dll.openmc_tally_get_filters(self._index, filt_idx, n) return [_get_filter(filt_idx[i]) for i in range(n.value)] diff --git a/src/tallies/filter.cpp b/src/tallies/filter.cpp index 36a36044ab..0b792da1bf 100644 --- a/src/tallies/filter.cpp +++ b/src/tallies/filter.cpp @@ -143,13 +143,27 @@ Filter* Filter::create(const std::string& type, int32_t id) void Filter::set_id(int32_t id) { - Expects(id >= 0); + Expects(id >= -1); + + // Clear entry in filter map if an ID was already assigned before + if (id_ != -1) { + model::filter_map.erase(id_); + id_ = -1; + } + + // Make sure no other filter has same ID if (model::filter_map.find(id) != model::filter_map.end()) { throw std::runtime_error{"Two filters have the same ID: " + std::to_string(id)}; } - // Clear entry in filter map if an ID was already assigned before - if (id_ != -1) model::filter_map.erase(id_); + // If no ID specified, auto-assign next ID in sequence + if (id == -1) { + id = 0; + for (const auto& f : model::tally_filters) { + id = std::max(id, f->id_); + } + ++id; + } // Update ID and entry in filter map id_ = id; @@ -183,13 +197,7 @@ openmc_filter_set_id(int32_t index, int32_t id) { if (int err = verify_filter(index)) return err; - if (model::filter_map.find(id) != model::filter_map.end()) { - set_errmsg("Two filters have the same ID: " + std::to_string(id)); - return OPENMC_E_INVALID_ID; - } - - model::tally_filters[index]->id_ = id; - model::filter_map[id] = index; + model::tally_filters[index]->set_id(id); return 0; } diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index a4cb041694..05004ad96f 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -240,9 +240,18 @@ score_str_to_int(std::string score_str) // Tally object implementation //============================================================================== -Tally::Tally() +Tally::Tally(int32_t id) + : index_{model::tallies.size()} { - this->set_filters(nullptr, 0); + this->set_id(id); + this->set_filters({}); +} + +Tally* +Tally::create(int32_t id) +{ + model::tallies.push_back(std::make_unique(id)); + return model::tallies.back().get(); } void @@ -252,25 +261,55 @@ Tally::init_from_xml(pugi::xml_node node) } void -Tally::set_filters(const int32_t filter_indices[], int n) +Tally::set_id(int32_t id) +{ + Expects(id >= -1); + + // Clear entry in tally map if an ID was already assigned before + if (id_ != -1) { + model::tally_map.erase(id_); + id_ = -1; + } + + // Make sure no other tally has the same ID + if (model::tally_map.find(id) != model::tally_map.end()) { + throw std::runtime_error{"Two tallies have the same ID: " + std::to_string(id)}; + } + + // If no ID specified, auto-assign next ID in sequence + if (id == -1) { + id = 0; + for (const auto& t : model::tallies) { + id = std::max(id, t->id_); + } + ++id; + } + + // Update ID and entry in tally map + id_ = id; + model::tally_map[id] = index_; +} + +void +Tally::set_filters(gsl::span filters) { // Clear old data. filters_.clear(); strides_.clear(); // Copy in the given filter indices. - filters_.assign(filter_indices, filter_indices + n); + auto n = filters.size(); + filters_.reserve(n); for (int i = 0; i < n; ++i) { - auto i_filt = filters_[i]; - if (i_filt < 0 || i_filt >= model::tally_filters.size()) - throw std::out_of_range("Index in tally filter array out of bounds."); + // Add index to vector of filters + auto& f {filters[i]}; + filters_.push_back(model::filter_map.at(f->id_)); // Keep track of indices for special filters. - const auto* filt = model::tally_filters[i_filt].get(); - if (dynamic_cast(filt)) { + if (dynamic_cast(f)) { energyout_filter_ = i; - } else if (dynamic_cast(filt)) { + } else if (dynamic_cast(f)) { delayedgroup_filter_ = i; } } @@ -298,7 +337,7 @@ Tally::set_scores(pugi::xml_node node) } void -Tally::set_scores(std::vector scores) +Tally::set_scores(const std::vector& scores) { // Reset state and prepare for the new scores. scores_.clear(); @@ -450,17 +489,25 @@ Tally::set_nuclides(pugi::xml_node node) // The user provided specifics nuclides. Parse it as an array with either // "total" or a nuclide name like "U-235" in each position. auto words = get_node_array(node, "nuclides"); - for (auto word : words) { - if (word == "total") { - nuclides_.push_back(-1); - } else { - auto search = data::nuclide_map.find(word); - if (search == data::nuclide_map.end()) - fatal_error("Could not find the nuclide " + word - + " specified in tally " + std::to_string(id_) - + " in any material"); - nuclides_.push_back(search->second); - } + this->set_nuclides(words); + } +} + +void +Tally::set_nuclides(const std::vector& nuclides) +{ + nuclides_.clear(); + + for (const auto& nuc : nuclides) { + if (nuc == "total") { + nuclides_.push_back(-1); + } else { + auto search = data::nuclide_map.find(nuc); + if (search == data::nuclide_map.end()) + fatal_error("Could not find the nuclide " + nuc + + " specified in tally " + std::to_string(id_) + + " in any material"); + nuclides_.push_back(search->second); } } } @@ -628,22 +675,14 @@ void read_tallies_xml() } for (auto node_tal : root.children("tally")) { - model::tallies.push_back(std::make_unique()); - - auto& t {model::tallies.back()}; - t->init_from_xml(node_tal); - // Copy and set tally id if (!check_for_node(node_tal, "id")) { fatal_error("Must specify id for tally in tally XML file."); } - t->id_ = std::stoi(get_node_value(node_tal, "id")); - model::tally_map[t->id_] = model::tallies.size() - 1; + int32_t id = std::stoi(get_node_value(node_tal, "id")); - // Copy tally name - if (check_for_node(node_tal, "name")) { - t->name_ = get_node_value(node_tal, "name"); - } + auto t = Tally::create(id); + t->init_from_xml(node_tal); // ======================================================================= // READ DATA FOR FILTERS @@ -665,7 +704,7 @@ void read_tallies_xml() // Allocate and store filter user ids if (!filters.empty()) { - std::vector filter_indices; + std::vector filter_ptrs; for (int filter_id : filters) { // Determine if filter ID is valid auto it = model::filter_map.find(filter_id); @@ -675,11 +714,11 @@ void read_tallies_xml() } // Store the index of the filter - filter_indices.push_back(it->second); + filter_ptrs.push_back(model::tally_filters[it->second].get()); } // Set the filters - t->set_filters(filter_indices.data(), filter_indices.size()); + t->set_filters(filter_ptrs); } // Check for the presence of certain filter types @@ -1028,7 +1067,7 @@ openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end) if (index_start) *index_start = model::tallies.size(); if (index_end) *index_end = model::tallies.size() + n - 1; for (int i = 0; i < n; ++i) { - model::tallies.push_back(std::make_unique()); + model::tallies.push_back(std::make_unique(-1)); } return 0; } @@ -1112,14 +1151,7 @@ openmc_tally_set_id(int32_t index, int32_t id) return OPENMC_E_OUT_OF_BOUNDS; } - if (model::tally_map.find(id) != model::tally_map.end()) { - set_errmsg("Two or more tallies use the same unique ID: " - + std::to_string(id)); - return OPENMC_E_INVALID_ID; - } - - model::tallies[index]->id_ = id; - model::tally_map[id] = index; + model::tallies[index]->set_id(id); return 0; } @@ -1259,7 +1291,7 @@ openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides) } extern "C" int -openmc_tally_get_filters(int32_t index, const int32_t** indices, int* n) +openmc_tally_get_filters(int32_t index, const int32_t** indices, size_t* n) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1272,7 +1304,7 @@ openmc_tally_get_filters(int32_t index, const int32_t** indices, int* n) } extern "C" int -openmc_tally_set_filters(int32_t index, int n, const int32_t* indices) +openmc_tally_set_filters(int32_t index, size_t n, const int32_t* indices) { // Make sure the index fits in the array bounds. if (index < 0 || index >= model::tallies.size()) { @@ -1282,9 +1314,15 @@ openmc_tally_set_filters(int32_t index, int n, const int32_t* indices) // Set the filters. try { - model::tallies[index]->set_filters(indices, n); + // Convert indices to filter pointers + std::vector filters; + for (gsl::index i = 0; i < n; ++i) { + int32_t i_filt = indices[i]; + filters.push_back(model::tally_filters.at(i_filt).get()); + } + model::tallies[index]->set_filters(filters); } catch (const std::out_of_range& ex) { - set_errmsg(ex.what()); + set_errmsg("Index in tally filter array out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; }