From 94fc050fec82b94ba98658baa2ae9512dd60c03e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Jun 2021 10:23:32 +0700 Subject: [PATCH 01/23] Add open_group that works with std::string --- include/openmc/hdf5_interface.h | 2 +- src/hdf5_interface.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index f601673041..ae91ce2ae9 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -51,7 +51,7 @@ inline hid_t create_group(hid_t parent_id, const std::stringstream& name) hid_t file_open(const std::string& filename, char mode, bool parallel=false); - +hid_t open_group(hid_t group_id, const std::string& name); void write_string(hid_t group_id, const char* name, const std::string& buffer, bool indep); diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 0f8db2dc5f..522c9c2625 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -225,6 +225,11 @@ file_open(const std::string& filename, char mode, bool parallel) return file_open(filename.c_str(), mode, parallel); } +hid_t open_group(hid_t group_id, const std::string& name) +{ + return open_group(group_id, name.c_str()); +} + void file_close(hid_t file_id) { H5Fclose(file_id); From 482848cadb5f96b0bc902204715c120556b8de06 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Jun 2021 10:23:05 +0700 Subject: [PATCH 02/23] Add openmc_properties_export/import to C API (incomplete) --- include/openmc/capi.h | 1 + include/openmc/cell.h | 8 ++++++ include/openmc/summary.h | 10 ++++++++ openmc/lib/cell.py | 18 ++++++++++++++ openmc/lib/core.py | 34 +++++++++++++++++++++++++- src/cell.cpp | 43 ++++++++++++++++++++++++++++++++ src/summary.cpp | 53 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 166 insertions(+), 1 deletion(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 2ca9fc430f..43c33dd91a 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -15,6 +15,7 @@ extern "C" { int openmc_cell_get_id(int32_t index, int32_t* id); int openmc_cell_get_temperature(int32_t index, const int32_t* instance, double* T); int openmc_cell_get_name(int32_t index, const char** name); + int openmc_cell_get_num_instances(int32_t index, int32_t* num_instances); int openmc_cell_set_name(int32_t index, const char* name); int openmc_cell_set_fill(int32_t index, int type, int32_t n, const int32_t* indices); int openmc_cell_set_id(int32_t index, int32_t id); diff --git a/include/openmc/cell.h b/include/openmc/cell.h index c7ba0ab137..6976a8ee2a 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -153,6 +153,14 @@ public: //! \return Map with cell indexes as keys and instances as values std::unordered_map> get_contained_cells() const; + //! Export physical properties to HDF5 + //! \param[in] group HDF5 group to read from + void export_properties_hdf5(hid_t group) const; + + //! Import physical properties from HDF5 + //! \param[in] group HDF5 group to write to + void import_properties_hdf5(hid_t group); + protected: void get_contained_cells_inner( std::unordered_map>& contained_cells, diff --git a/include/openmc/summary.h b/include/openmc/summary.h index ff2ab71a89..95fb0be167 100644 --- a/include/openmc/summary.h +++ b/include/openmc/summary.h @@ -11,6 +11,16 @@ void write_nuclides(hid_t file); void write_geometry(hid_t file); void write_materials(hid_t file); +//! Export physical properties for model +//! \param[in] filename Filename to write to +//! \return Error code +extern "C" int openmc_properties_export(const char* filename); + +//! Import physical properties for model +//! \param[in] filename Filename to read from +// \return Error code +extern "C" int openmc_properties_import(const char* filename); + } #endif // OPENMC_SUMMARY_H diff --git a/openmc/lib/cell.py b/openmc/lib/cell.py index c69d1e2a40..7fdc4542db 100644 --- a/openmc/lib/cell.py +++ b/openmc/lib/cell.py @@ -25,6 +25,9 @@ _dll.openmc_cell_get_fill.argtypes = [ c_int32, POINTER(c_int), POINTER(POINTER(c_int32)), POINTER(c_int32)] _dll.openmc_cell_get_fill.restype = c_int _dll.openmc_cell_get_fill.errcheck = _error_handler +_dll.openmc_cell_get_num_instances.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_cell_get_num_instances.restype = c_int +_dll.openmc_cell_get_num_instances.errcheck = _error_handler _dll.openmc_cell_get_temperature.argtypes = [ c_int32, POINTER(c_int32), POINTER(c_double)] _dll.openmc_cell_get_temperature.restype = c_int @@ -78,6 +81,14 @@ class Cell(_FortranObjectWithID): ---------- id : int ID of the cell + fill : openmc.lib.Material or list of openmc.lib.Material + Indicates what the region of space is filled with + name : str + Name of the cell + num_instances : int + Number of unique cell instances + bounding_box : 2-tuple of numpy.ndarray + Lower-left and upper-right coordinates of bounding box """ __instances = WeakValueDictionary() @@ -159,6 +170,12 @@ class Cell(_FortranObjectWithID): indices = (c_int32*1)(-1) _dll.openmc_cell_set_fill(self._index, 0, 1, indices) + @property + def num_instances(self): + n = c_int32() + _dll.openmc_cell_get_num_instances(self._index, n) + return n.value + def get_temperature(self, instance=None): """Get the temperature of a cell @@ -211,6 +228,7 @@ class Cell(_FortranObjectWithID): return llc, urc + class _CellMapping(Mapping): def __getitem__(self, key): index = c_int32() diff --git a/openmc/lib/core.py b/openmc/lib/core.py index e740e28699..4dd01ebda5 100644 --- a/openmc/lib/core.py +++ b/openmc/lib/core.py @@ -62,7 +62,13 @@ _dll.openmc_next_batch.argtypes = [POINTER(c_int)] _dll.openmc_next_batch.restype = c_int _dll.openmc_next_batch.errcheck = _error_handler _dll.openmc_plot_geometry.restype = c_int -_dll.openmc_plot_geometry.restype = _error_handler +_dll.openmc_plot_geometry.errcheck = _error_handler +_dll.openmc_properties_export.argtypes = [c_char_p] +_dll.openmc_properties_export.restype = c_int +_dll.openmc_properties_export.errcheck = _error_handler +_dll.openmc_properties_import.argtypes = [c_char_p] +_dll.openmc_properties_import.restype = c_int +_dll.openmc_properties_import.errcheck = _error_handler _dll.openmc_run.restype = c_int _dll.openmc_run.errcheck = _error_handler _dll.openmc_reset.restype = c_int @@ -307,6 +313,32 @@ def plot_geometry(): _dll.openmc_plot_geometry() +def properties_export(filename=None): + """Export physical properties. + + Parameters + ---------- + filename : str or None + Filename to export properties to (defaults to "properties.h5") + + """ + if filename is not None: + filename = c_char_p(filename.encode()) + _dll.openmc_properties_export(filename) + + +def properties_import(filename): + """Import physical properties. + + Parameters + ---------- + filename : str + Filename to import properties from + + """ + _dll.openmc_properties_import(filename.encode()) + + def reset(): """Reset tally results""" _dll.openmc_reset() diff --git a/src/cell.cpp b/src/cell.cpp index 6b88a67803..37550e9f50 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -282,6 +282,38 @@ Cell::set_temperature(double T, int32_t instance, bool set_contained) } } +void Cell::export_properties_hdf5(hid_t group) const +{ + // Create a group for this cell. + auto cell_group = create_group(group, fmt::format("cell {}", id_)); + + // Write temperature in [K] for one or more cell instances + vector temps; + for (auto sqrtkT_val : sqrtkT_) + temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); + write_dataset(cell_group, "temperature", temps); + + close_group(cell_group); +} + +void Cell::import_properties_hdf5(hid_t group) +{ + auto cell_group = open_group(group, fmt::format("cell {}", id_)); + + // Read temperatures from file + vector temps; + read_dataset(cell_group, "temperature", temps); + + // Modify temperatures for the cell + sqrtkT_.resize(0); + sqrtkT_.reserve(temps.size()); + for (auto T : temps) { + sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * T)); + } + + close_group(cell_group); +} + //============================================================================== // CSGCell implementation //============================================================================== @@ -1278,6 +1310,17 @@ openmc_cell_set_id(int32_t index, int32_t id) } } +extern "C" int +openmc_cell_get_num_instances(int32_t index, int32_t* num_instances) +{ + if (index < 0 || index >= model::cells.size()) { + set_errmsg("Index in cells array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *num_instances = model::cells[index]->n_instances_; + return 0; +} + //! Extend the cells array by n elements extern "C" int openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end) diff --git a/src/summary.cpp b/src/summary.cpp index 3d2c6816b4..730a53a50b 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -1,6 +1,9 @@ #include "openmc/summary.h" +#include + #include "openmc/cell.h" +#include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" #include "openmc/lattice.h" #include "openmc/material.h" @@ -133,4 +136,54 @@ void write_materials(hid_t file) close_group(materials_group); } +extern "C" int openmc_properties_export(const char* filename) +{ + // Set a default filename if none was passed + std::string name = filename ? filename : "properties.h5"; + + // Display output message + auto msg = fmt::format("Exporting properties to {}...", name); + write_message(msg, 5); + + // Create a new file using default properties. + hid_t file = file_open(name, 'w'); + + // Write cell properties + auto geom_group = create_group(file, "geometry"); + write_attribute(geom_group, "n_cells", model::cells.size()); + auto cells_group = create_group(geom_group, "cells"); + for (const auto& c : model::cells) c->export_properties_hdf5(cells_group); + close_group(cells_group); + close_group(geom_group); + + // Terminate access to the file. + file_close(file); + return 0; +} + +extern "C" int openmc_properties_import(const char* filename) +{ + // Display output message + auto msg = fmt::format("Importing properties from {}...", filename); + write_message(msg, 5); + + // Create a new file using default properties. + if (!file_exists(filename)) { + set_errmsg(fmt::format("File '{}' does not exist.", filename)); + return OPENMC_E_INVALID_ARGUMENT; + } + hid_t file = file_open(filename, 'r'); + + // Read cell properties + auto geom_group = open_group(file, "geometry"); + auto cells_group = open_group(geom_group, "cells"); + for (const auto& c : model::cells) c->import_properties_hdf5(cells_group); + close_group(cells_group); + close_group(geom_group); + + // Terminate access to the file. + file_close(file); + return 0; +} + } // namespace openmc From ef7b43d986de99e7a6c87d7079b904523ff36b63 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Jun 2021 11:39:22 +0700 Subject: [PATCH 03/23] Add material density to properties.h5 --- include/openmc/material.h | 8 ++++++++ src/material.cpp | 17 +++++++++++++++++ src/summary.cpp | 23 +++++++++++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/openmc/material.h b/include/openmc/material.h index 7e975a1bb6..f0d8103707 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -69,6 +69,14 @@ public: //! Write material data to HDF5 void to_hdf5(hid_t group) const; + //! Export physical properties to HDF5 + //! \param[in] group HDF5 group to write to + void export_properties_hdf5(hid_t group) const; + + //! Import physical properties from HDF5 + //! \param[in] group HDF5 group to read from + void import_properties_hdf5(hid_t group); + //! Add nuclide to the material // //! \param[in] nuclide Name of the nuclide diff --git a/src/material.cpp b/src/material.cpp index 59d2f954e4..c2240c99bb 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1053,6 +1053,23 @@ void Material::to_hdf5(hid_t group) const close_group(material_group); } +void Material::export_properties_hdf5(hid_t group) const +{ + hid_t material_group = create_group(group, "material " + std::to_string(id_)); + write_attribute(material_group, "atom_density", density_); + write_attribute(material_group, "mass_density", density_gpcc_); + close_group(material_group); +} + +void Material::import_properties_hdf5(hid_t group) +{ + hid_t material_group = open_group(group, "material " + std::to_string(id_)); + double density; + read_attribute(material_group, "atom_density", density); + this->set_density(density, "atom/b-cm"); + close_group(material_group); +} + void Material::add_nuclide(const std::string& name, double density) { // Check if nuclide is already in material diff --git a/src/summary.cpp b/src/summary.cpp index 730a53a50b..df69448847 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -152,10 +152,20 @@ extern "C" int openmc_properties_export(const char* filename) auto geom_group = create_group(file, "geometry"); write_attribute(geom_group, "n_cells", model::cells.size()); auto cells_group = create_group(geom_group, "cells"); - for (const auto& c : model::cells) c->export_properties_hdf5(cells_group); + for (const auto& c : model::cells) { + c->export_properties_hdf5(cells_group); + } close_group(cells_group); close_group(geom_group); + // Write material properties + hid_t materials_group = create_group(file, "materials"); + write_attribute(materials_group, "n_materials", model::materials.size()); + for (const auto& mat : model::materials) { + mat->export_properties_hdf5(materials_group); + } + close_group(materials_group); + // Terminate access to the file. file_close(file); return 0; @@ -177,10 +187,19 @@ extern "C" int openmc_properties_import(const char* filename) // Read cell properties auto geom_group = open_group(file, "geometry"); auto cells_group = open_group(geom_group, "cells"); - for (const auto& c : model::cells) c->import_properties_hdf5(cells_group); + for (const auto& c : model::cells) { + c->import_properties_hdf5(cells_group); + } close_group(cells_group); close_group(geom_group); + // Read material properties + auto materials_group = open_group(file, "materials"); + for (const auto& mat : model::materials) { + mat->import_properties_hdf5(materials_group); + } + close_group(materials_group); + // Terminate access to the file. file_close(file); return 0; From 7a4e32f7d51974e03c7c40fd9c6ca794f3e5f809 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Jun 2021 11:48:45 +0700 Subject: [PATCH 04/23] Add filetype and other metadata to properties.h5 --- include/openmc/constants.h | 1 + src/summary.cpp | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index aac3a52a83..2083f33b42 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -31,6 +31,7 @@ constexpr array VERSION_SUMMARY {6, 0}; constexpr array VERSION_VOLUME {1, 0}; constexpr array VERSION_VOXEL {2, 0}; constexpr array VERSION_MGXS_LIBRARY {1, 0}; +constexpr array VERSION_PROPERTIES {1, 0}; // ============================================================================ // ADJUSTABLE PARAMETERS diff --git a/src/summary.cpp b/src/summary.cpp index df69448847..29d37009b1 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -148,6 +148,17 @@ extern "C" int openmc_properties_export(const char* filename) // Create a new file using default properties. hid_t file = file_open(name, 'w'); + // Write metadata + write_attribute(file, "filetype", "properties"); + write_attribute(file, "version", VERSION_STATEPOINT); + write_attribute(file, "openmc_version", VERSION); +#ifdef GIT_SHA1 + write_attribute(file, "git_sha1", GIT_SHA1); +#endif + write_attribute(file, "date_and_time", time_stamp()); + write_attribute(file, "path", settings::path_input); + + // Write cell properties auto geom_group = create_group(file, "geometry"); write_attribute(geom_group, "n_cells", model::cells.size()); @@ -184,6 +195,14 @@ extern "C" int openmc_properties_import(const char* filename) } hid_t file = file_open(filename, 'r'); + // Ensure the filetype is correct + std::string filetype; + read_attribute(file, "filetype", filetype); + if (filetype != "properties") { + set_errmsg(fmt::format("File '{}' is not a properties file.", filename)); + return OPENMC_E_INVALID_ARGUMENT; + } + // Read cell properties auto geom_group = open_group(file, "geometry"); auto cells_group = open_group(geom_group, "cells"); From d6f483d36fbfb16a7912dcec302d6f062428b81d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Jun 2021 14:52:04 +0700 Subject: [PATCH 05/23] Make sure openmc_properties_export/import appear in global namespace --- include/openmc/capi.h | 26 ++++++++++++++++++-------- include/openmc/summary.h | 10 ---------- src/summary.cpp | 5 +++++ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 43c33dd91a..f08ec5c02f 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -145,13 +145,13 @@ extern "C" { //! \param[in] meshtyally_id id of CMFD Mesh Tally //! \param[in] cmfd_indices indices storing spatial and energy dimensions of CMFD problem //! \param[in] norm CMFD normalization factor - extern "C" void openmc_initialize_mesh_egrid(const int meshtally_id, const int* cmfd_indices, - const double norm); + void openmc_initialize_mesh_egrid(const int meshtally_id, const int* cmfd_indices, + const double norm); //! Sets the mesh and energy grid for CMFD reweight //! \param[in] feedback whether or not to run CMFD feedback //! \param[in] cmfd_src computed CMFD source - extern "C" void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src); + void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src); //! Sets the fixed variables that are used for CMFD linear solver //! \param[in] indptr CSR format index pointer array of loss matrix @@ -162,10 +162,10 @@ extern "C" { //! \param[in] spectral spectral radius of CMFD matrices and tolerances //! \param[in] map coremap for problem, storing accelerated regions //! \param[in] use_all_threads whether to use all threads when running CMFD solver - extern "C" void openmc_initialize_linsolver(const int* indptr, int len_indptr, - const int* indices, int n_elements, - int dim, double spectral, - const int* map, bool use_all_threads); + void openmc_initialize_linsolver(const int* indptr, int len_indptr, + const int* indices, int n_elements, + int dim, double spectral, + const int* map, bool use_all_threads); //! Runs a Gauss Seidel linear solver to solve CMFD matrix equations //! linear solver @@ -174,9 +174,19 @@ extern "C" { //! \param[out] x unknown vector //! \param[in] tol tolerance on final error //! \return number of inner iterations required to reach convergence - extern "C" int openmc_run_linsolver(const double* A_data, const double* b, + int openmc_run_linsolver(const double* A_data, const double* b, double* x, double tol); + //! Export physical properties for model + //! \param[in] filename Filename to write to + //! \return Error code + int openmc_properties_export(const char* filename); + + //! Import physical properties for model + //! \param[in] filename Filename to read from + // \return Error code + int openmc_properties_import(const char* filename); + // Error codes extern int OPENMC_E_UNASSIGNED; extern int OPENMC_E_ALLOCATE; diff --git a/include/openmc/summary.h b/include/openmc/summary.h index 95fb0be167..ff2ab71a89 100644 --- a/include/openmc/summary.h +++ b/include/openmc/summary.h @@ -11,16 +11,6 @@ void write_nuclides(hid_t file); void write_geometry(hid_t file); void write_materials(hid_t file); -//! Export physical properties for model -//! \param[in] filename Filename to write to -//! \return Error code -extern "C" int openmc_properties_export(const char* filename); - -//! Import physical properties for model -//! \param[in] filename Filename to read from -// \return Error code -extern "C" int openmc_properties_import(const char* filename); - } #endif // OPENMC_SUMMARY_H diff --git a/src/summary.cpp b/src/summary.cpp index 29d37009b1..c2276c063e 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -2,6 +2,7 @@ #include +#include "openmc/capi.h" #include "openmc/cell.h" #include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" @@ -136,6 +137,10 @@ void write_materials(hid_t file) close_group(materials_group); } +//============================================================================== +// C API +//============================================================================== + extern "C" int openmc_properties_export(const char* filename) { // Set a default filename if none was passed From 01b023b7ec7a4ad391afd293d514c1352d1292e3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 12:09:59 +0700 Subject: [PATCH 06/23] Include cell instance in id_map --- openmc/lib/plot.py | 2 +- src/plot.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openmc/lib/plot.py b/openmc/lib/plot.py index c51000e0de..b029d67570 100644 --- a/openmc/lib/plot.py +++ b/openmc/lib/plot.py @@ -232,7 +232,7 @@ def id_map(plot): OpenMC property ids with dtype int32 """ - img_data = np.zeros((plot.v_res, plot.h_res, 2), + img_data = np.zeros((plot.v_res, plot.h_res, 3), dtype=np.dtype('int32')) _dll.openmc_id_map(plot, img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/src/plot.cpp b/src/plot.cpp index 615701341e..3e55d1d5f9 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -36,7 +36,7 @@ constexpr int32_t NOT_FOUND {-2}; constexpr int32_t OVERLAP {-3}; IdData::IdData(size_t h_res, size_t v_res) - : data_({v_res, h_res, 2}, NOT_FOUND) + : data_({v_res, h_res, 3}, NOT_FOUND) { } void @@ -44,18 +44,20 @@ IdData::set_value(size_t y, size_t x, const Particle& p, int level) { // set cell data if (p.n_coord() <= level) { data_(y, x, 0) = NOT_FOUND; + data_(y, x, 1) = NOT_FOUND; } else { data_(y, x, 0) = model::cells.at(p.coord(level).cell)->id_; + data_(y, x, 1) = p.cell_instance(); } // set material data Cell* c = model::cells.at(p.coord(p.n_coord() - 1).cell).get(); if (p.material() == MATERIAL_VOID) { - data_(y, x, 1) = MATERIAL_VOID; + data_(y, x, 2) = MATERIAL_VOID; return; } else if (c->type_ == Fill::MATERIAL) { Material* m = model::materials.at(p.material()).get(); - data_(y, x, 1) = m->id_; + data_(y, x, 2) = m->id_; } } From 1a1a5a1cf47270e43999a152db7e3b3c47ecec74 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 14:17:31 +0700 Subject: [PATCH 07/23] Add documentation for properties file format --- docs/source/io_formats/index.rst | 1 + docs/source/io_formats/properties.rst | 36 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 docs/source/io_formats/properties.rst diff --git a/docs/source/io_formats/index.rst b/docs/source/io_formats/index.rst index 7ae22c0a33..8c89bd2a1d 100644 --- a/docs/source/io_formats/index.rst +++ b/docs/source/io_formats/index.rst @@ -45,6 +45,7 @@ Output Files statepoint source summary + properties depletion_results particle_restart track diff --git a/docs/source/io_formats/properties.rst b/docs/source/io_formats/properties.rst new file mode 100644 index 0000000000..5030e78f35 --- /dev/null +++ b/docs/source/io_formats/properties.rst @@ -0,0 +1,36 @@ +.. _io_properties: + +====================== +Properties File Format +====================== + +The current version of the properties file format is 1.0. + +**/** + +:Attributes: - **filetype** (*char[]*) -- String indicating the type of file. + - **version** (*int[2]*) -- Major and minor version of the + statepoint file format. + - **openmc_version** (*int[3]*) -- Major, minor, and release + version number for OpenMC. + - **git_sha1** (*char[40]*) -- Git commit SHA-1 hash. + - **date_and_time** (*char[]*) -- Date and time the summary was + written. + - **path** (*char[]*) -- Path to directory containing input files. + +**/geometry/** + +:Attributes: - **n_cells** (*int*) -- Number of cells in the problem. + +**/geometry/cells/cell /** + +:Datasets: - **temperature** (*double[]*) -- Temperature of the cell in [K]. + +**/materials/** + +:Attributes: - **n_materials** (*int*) -- Number of materials in the problem. + +**/materials/material /** + +:Attributes: - **atom_density** (*double*) -- Total density in [atom/b-cm]. + - **mass_density** (*double*) -- Total density in [g/cm^3]. From d135cc272136500eac6d9cef769754935cd4ee58 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 14:23:54 +0700 Subject: [PATCH 08/23] Add consistency checks on number of cells/materials --- src/summary.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/summary.cpp b/src/summary.cpp index c2276c063e..62f51c94de 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -208,8 +208,16 @@ extern "C" int openmc_properties_import(const char* filename) return OPENMC_E_INVALID_ARGUMENT; } - // Read cell properties + // Make sure number of cells matches auto geom_group = open_group(file, "geometry"); + int32_t n; + read_attribute(geom_group, "n_cells", n); + if (n != openmc::model::cells.size()) { + set_errmsg(fmt::format("Number of cells in {} doesn't match current model.", filename)); + return OPENMC_E_GEOMETRY; + } + + // Read cell properties auto cells_group = open_group(geom_group, "cells"); for (const auto& c : model::cells) { c->import_properties_hdf5(cells_group); @@ -217,8 +225,15 @@ extern "C" int openmc_properties_import(const char* filename) close_group(cells_group); close_group(geom_group); - // Read material properties + // Make sure number of cells matches auto materials_group = open_group(file, "materials"); + read_attribute(materials_group, "n_materials", n); + if (n != openmc::model::materials.size()) { + set_errmsg(fmt::format("Number of materials in {} doesn't match current model.", filename)); + return OPENMC_E_GEOMETRY; + } + + // Read material properties for (const auto& mat : model::materials) { mat->import_properties_hdf5(materials_group); } From 33f7d09f715e196d1afa1e065543be0e8352c6f4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 14:26:50 +0700 Subject: [PATCH 09/23] Use names import_properties and export_properties for Python API --- openmc/lib/core.py | 60 ++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/openmc/lib/core.py b/openmc/lib/core.py index 4dd01ebda5..0da24aab88 100644 --- a/openmc/lib/core.py +++ b/openmc/lib/core.py @@ -126,6 +126,24 @@ def current_batch(): return c_int.in_dll(_dll, 'current_batch').value +def export_properties(filename=None): + """Export physical properties. + + Parameters + ---------- + filename : str or None + Filename to export properties to (defaults to "properties.h5") + + See Also + -------- + openmc.lib.import_properties + + """ + if filename is not None: + filename = c_char_p(filename.encode()) + _dll.openmc_properties_export(filename) + + def finalize(): """Finalize simulation and free memory""" _dll.openmc_finalize() @@ -184,6 +202,22 @@ def hard_reset(): _dll.openmc_hard_reset() +def import_properties(filename): + """Import physical properties. + + Parameters + ---------- + filename : str + Filename to import properties from + + See Also + -------- + openmc.lib.export_properties + + """ + _dll.openmc_properties_import(filename.encode()) + + def init(args=None, intracomm=None): """Initialize OpenMC @@ -313,32 +347,6 @@ def plot_geometry(): _dll.openmc_plot_geometry() -def properties_export(filename=None): - """Export physical properties. - - Parameters - ---------- - filename : str or None - Filename to export properties to (defaults to "properties.h5") - - """ - if filename is not None: - filename = c_char_p(filename.encode()) - _dll.openmc_properties_export(filename) - - -def properties_import(filename): - """Import physical properties. - - Parameters - ---------- - filename : str - Filename to import properties from - - """ - _dll.openmc_properties_import(filename.encode()) - - def reset(): """Reset tally results""" _dll.openmc_reset() From b63030a04f3492d45fe88a11c926bf62ff6c9196 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 14:50:05 +0700 Subject: [PATCH 10/23] Add Model.import_properties method --- openmc/model/model.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/openmc/model/model.py b/openmc/model/model.py index 7d6acb281c..e7a56bb19a 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -2,6 +2,8 @@ from collections.abc import Iterable from pathlib import Path import time +import h5py + import openmc from openmc.checkvalue import check_type, check_value @@ -197,6 +199,38 @@ class Model: if self.plots: self.plots.export_to_xml(d) + def import_properties(self, filename): + """Import physical properties + + Parameters + ---------- + filename : str + Path to properties HDF5 file + + See Also + -------- + openmc.lib.export_properties + + """ + cells = self.geometry.get_all_cells() + materials = self.geometry.get_all_materials() + + with h5py.File(filename, 'r') as fh: + # Update temperatures for cells filled with materials + cells_group = fh['geometry/cells'] + for name, group in cells_group.items(): + cell_id = int(name.split()[1]) + cell = cells[cell_id] + if cell.fill_type in ('material', 'distribmat'): + cell.temperature = group['temperature'][()] + + # Update material densities + mats_group = fh['materials'] + for name, group in mats_group.items(): + mat_id = int(name.split()[1]) + atom_density = group.attrs['atom_density'] + materials[mat_id].set_density('atom/b-cm', atom_density) + def run(self, **kwargs): """Creates the XML files, runs OpenMC, and returns the path to the last statepoint file generated. From fd2637cb485eca0f23ee2bdea0ff880795aff26b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 14:56:38 +0700 Subject: [PATCH 11/23] Add Model.from_xml classmethod --- openmc/model/model.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/openmc/model/model.py b/openmc/model/model.py index e7a56bb19a..de80bfa3a1 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -126,6 +126,31 @@ class Model: for plot in plots: self._plots.append(plot) + @classmethod + def from_xml(cls, geometry='geometry.xml', materials='materials.xml', + settings='settings.xml'): + """Create model from existing XML files + + Parameters + ---------- + geometry : str + Path to geometry.xml file + materials : str + Path to materials.xml file + settings : str + Path to settings.xml file + + Returns + ------- + openmc.model.Model + Model created from XML files + + """ + materials = openmc.Materials.from_xml(materials) + geometry = openmc.Geometry.from_xml(geometry, materials) + settings = openmc.Settings.from_xml(settings) + return cls(geometry, materials, settings) + def deplete(self, timesteps, chain_file=None, method='cecm', fission_q=None, **kwargs): """Deplete model using specified timesteps/power From 87bd987ebb802200540c23cfccaba2c56a672ed5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 14:58:49 +0700 Subject: [PATCH 12/23] Make Model available in main openmc namespace --- openmc/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/__init__.py b/openmc/__init__.py index 50246cdd8a..8985099ba8 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -31,7 +31,7 @@ from openmc.search import * from openmc.polynomial import * from . import examples -# Import a few convencience functions that used to be here -from openmc.model import rectangular_prism, hexagonal_prism +# Import a few names from the model module +from openmc.model import rectangular_prism, hexagonal_prism, Model __version__ = '0.13.0-dev' From 8f26aeb47128e1b7707c47e8499e30e8f08115e2 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 15:02:32 +0700 Subject: [PATCH 13/23] Fix Model docstring --- openmc/model/model.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openmc/model/model.py b/openmc/model/model.py index de80bfa3a1..84650767af 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -13,11 +13,11 @@ class Model: This class can be used to store instances of :class:`openmc.Geometry`, :class:`openmc.Materials`, :class:`openmc.Settings`, - :class:`openmc.Tallies`, :class:`openmc.Plots`, and :class:`openmc.CMFD`, - thus making a complete model. The :meth:`Model.export_to_xml` method will - export XML files for all attributes that have been set. If the - :meth:`Model.materials` attribute is not set, it will attempt to create a - ``materials.xml`` file based on all materials appearing in the geometry. + :class:`openmc.Tallies`, and :class:`openmc.Plots`, thus making a complete + model. The :meth:`Model.export_to_xml` method will export XML files for all + attributes that have been set. If the :attr:`Model.materials` attribute is + not set, it will attempt to create a ``materials.xml`` file based on all + materials appearing in the geometry. Parameters ---------- From 51e1b5f41c4bd0e16afa083f505bdda4406b04b8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 15:14:00 +0700 Subject: [PATCH 14/23] Fix id_map test --- tests/unit_tests/test_lib.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 87d4843c77..9ed080a7bb 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -116,6 +116,7 @@ def test_cell(lib_init): cell.name = "Not fuel" assert cell.name == "Not fuel" + def test_cell_temperature(lib_init): cell = openmc.lib.cells[1] cell.set_temperature(100.0, 0) @@ -558,9 +559,9 @@ def test_load_nuclide(lib_init): def test_id_map(lib_init): - expected_ids = np.array([[(3, 3), (2, 2), (3, 3)], - [(2, 2), (1, 1), (2, 2)], - [(3, 3), (2, 2), (3, 3)]], dtype='int32') + expected_ids = np.array([[(3, 0, 3), (2, 0, 2), (3, 0, 3)], + [(2, 0, 2), (1, 0, 1), (2, 0, 2)], + [(3, 0, 3), (2, 0, 2), (3, 0, 3)]], dtype='int32') # create a plot object s = openmc.lib.plot._PlotBase() From 4449cc42f2e57935cac23e54d2e6baad17f0aa31 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 15:35:54 +0700 Subject: [PATCH 15/23] Make sure properties.h5 gets closed properly upon error --- src/summary.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/summary.cpp b/src/summary.cpp index 62f51c94de..64d9a63629 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -204,6 +204,7 @@ extern "C" int openmc_properties_import(const char* filename) std::string filetype; read_attribute(file, "filetype", filetype); if (filetype != "properties") { + file_close(file); set_errmsg(fmt::format("File '{}' is not a properties file.", filename)); return OPENMC_E_INVALID_ARGUMENT; } @@ -213,6 +214,8 @@ extern "C" int openmc_properties_import(const char* filename) int32_t n; read_attribute(geom_group, "n_cells", n); if (n != openmc::model::cells.size()) { + close_group(geom_group); + file_close(file); set_errmsg(fmt::format("Number of cells in {} doesn't match current model.", filename)); return OPENMC_E_GEOMETRY; } @@ -229,6 +232,8 @@ extern "C" int openmc_properties_import(const char* filename) auto materials_group = open_group(file, "materials"); read_attribute(materials_group, "n_materials", n); if (n != openmc::model::materials.size()) { + close_group(materials_group); + file_close(file); set_errmsg(fmt::format("Number of materials in {} doesn't match current model.", filename)); return OPENMC_E_GEOMETRY; } From 329dff20189a3e8ec960a2eb1421664a2428924a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 15:36:41 +0700 Subject: [PATCH 16/23] Add tests for export_properties and import_properties --- openmc/lib/material.py | 2 ++ tests/unit_tests/test_lib.py | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/openmc/lib/material.py b/openmc/lib/material.py index 6f80abb5e2..fa27c4678b 100644 --- a/openmc/lib/material.py +++ b/openmc/lib/material.py @@ -87,6 +87,8 @@ class Material(_FortranObjectWithID): ID of the material nuclides : list of str List of nuclides in the material + density : float + Density of the material in [g/cm^3] densities : numpy.ndarray Array of densities in atom/b-cm name : str diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 9ed080a7bb..3b6b02c393 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -115,6 +115,7 @@ def test_cell(lib_init): assert cell.name == "Fuel" cell.name = "Not fuel" assert cell.name == "Not fuel" + assert cell.num_instances == 1 def test_cell_temperature(lib_init): @@ -125,6 +126,21 @@ def test_cell_temperature(lib_init): assert cell.get_temperature() == pytest.approx(200.0) +def test_properties_temperature(lib_init): + # Cell temperature should be 200 from above test + cell = openmc.lib.cells[1] + assert cell.get_temperature() == pytest.approx(200.0) + + # Export properties and change temperature + openmc.lib.export_properties('properties.h5') + cell.set_temperature(300.0) + assert cell.get_temperature() == pytest.approx(300.0) + + # Import properties and check that temperature is restored + openmc.lib.import_properties('properties.h5') + assert cell.get_temperature() == pytest.approx(200.0) + + def test_new_cell(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Cell(1) @@ -133,6 +149,13 @@ def test_new_cell(lib_init): assert len(openmc.lib.cells) == 5 +def test_properties_fail_cell(lib_init): + # The number of cells was changed in the previous test, so the properties + # file is no longer valid + with pytest.raises(exc.GeometryError, match="Number of cells"): + openmc.lib.import_properties("properties.h5") + + def test_material_mapping(lib_init): mats = openmc.lib.materials assert isinstance(mats, Mapping) @@ -168,6 +191,21 @@ def test_material(lib_init): m.name = "Not hot borated water" assert m.name == "Not hot borated water" + +def test_properties_density(lib_init): + m = openmc.lib.materials[1] + orig_density = m.density + + # Export properties and change density + openmc.lib.export_properties('properties.h5') + m.set_density(orig_density*2, 'g/cm3') + assert m.density == pytest.approx(orig_density*2) + + # Import properties and check that density was restored + openmc.lib.import_properties('properties.h5') + assert m.density == pytest.approx(orig_density) + + def test_material_add_nuclide(lib_init): m = openmc.lib.materials[3] m.add_nuclide('Xe135', 1e-12) @@ -183,6 +221,13 @@ def test_new_material(lib_init): assert len(openmc.lib.materials) == 5 +def test_properties_fail_material(lib_init): + # The number of materials was changed in the previous test, so the properties + # file is no longer valid + with pytest.raises(exc.GeometryError, match="Number of materials"): + openmc.lib.import_properties("properties.h5") + + def test_nuclide_mapping(lib_init): nucs = openmc.lib.nuclides assert isinstance(nucs, Mapping) @@ -576,6 +621,7 @@ def test_id_map(lib_init): ids = openmc.lib.plot.id_map(s) assert np.array_equal(expected_ids, ids) + def test_property_map(lib_init): expected_properties = np.array( [[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)], From 6190ff8ff3b6d687b9e2485f787cec64fab26394 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 15:50:04 +0700 Subject: [PATCH 17/23] Add test for Model.import_properties --- tests/unit_tests/test_model.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/unit_tests/test_model.py diff --git a/tests/unit_tests/test_model.py b/tests/unit_tests/test_model.py new file mode 100644 index 0000000000..5ff3430eae --- /dev/null +++ b/tests/unit_tests/test_model.py @@ -0,0 +1,33 @@ +import pytest +import openmc +import openmc.lib + + +def test_import_properties(run_in_tmpdir, mpi_intracomm): + """Test importing properties on the Model class """ + + # Create PWR pin cell model and write XML files + model = openmc.examples.pwr_pin_cell() + model.export_to_xml() + + # Change fuel temperature and density and export properties + openmc.lib.init(intracomm=mpi_intracomm) + cell = openmc.lib.cells[1] + cell.set_temperature(600.0) + cell.fill.set_density(5.0, 'g/cm3') + openmc.lib.export_properties() + openmc.lib.finalize() + + # Import properties to existing model and re-export to new directory + model.import_properties("properties.h5") + model.export_to_xml("with_properties") + + # Load model with properties and confirm temperature/density has been changed + model_with_properties = openmc.Model.from_xml( + 'with_properties/geometry.xml', + 'with_properties/materials.xml', + 'with_properties/settings.xml' + ) + cell = model_with_properties.geometry.get_all_cells()[1] + assert cell.temperature == [600.0] + assert cell.fill.get_mass_density() == pytest.approx(5.0) From 803f17500c4e148b1b72b27f901bafc2676957db Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Jun 2021 17:05:10 +0700 Subject: [PATCH 18/23] Fix use of get_map within plot.cpp and failing properties test --- src/plot.cpp | 5 +++-- tests/unit_tests/test_model.py | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index 3e55d1d5f9..999cf3d294 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -157,7 +157,8 @@ void create_ppm(Plot const& pl) // assign colors for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { - auto id = ids.data_(y, x, pl.color_by_); + int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 2; + auto id = ids.data_(y, x, idx); // no setting needed if not found if (id == NOT_FOUND) { continue; } if (id == OVERLAP) { @@ -840,7 +841,7 @@ void create_voxel(Plot const& pl) IdData ids = pltbase.get_map(); // select only cell/material ID data and flip the y-axis - int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 1; + int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 2; xt::xtensor data_slice = xt::view(ids.data_, xt::all(), xt::all(), idx); xt::xtensor data_flipped = xt::flip(data_slice, 0); diff --git a/tests/unit_tests/test_model.py b/tests/unit_tests/test_model.py index 5ff3430eae..4b658d5ab0 100644 --- a/tests/unit_tests/test_model.py +++ b/tests/unit_tests/test_model.py @@ -7,6 +7,7 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm): """Test importing properties on the Model class """ # Create PWR pin cell model and write XML files + openmc.reset_auto_ids() model = openmc.examples.pwr_pin_cell() model.export_to_xml() From 876bd925a32c75a553a8b65c81b7debf21b59407 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 12 Jul 2021 06:58:04 -0500 Subject: [PATCH 19/23] Add check on num cells/materials for Model.import_properties --- openmc/model/model.py | 17 +++++++++++++++-- src/summary.cpp | 1 - 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/openmc/model/model.py b/openmc/model/model.py index 84650767af..ca33a96acd 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -241,16 +241,29 @@ class Model: materials = self.geometry.get_all_materials() with h5py.File(filename, 'r') as fh: - # Update temperatures for cells filled with materials cells_group = fh['geometry/cells'] + + # Make sure number of cells matches + n_cells = fh['geometry'].attrs['n_cells'] + if n_cells != len(cells): + raise ValueError("Number of cells in properties file doesn't " + "match current model.") + + # Update temperatures for cells filled with materials for name, group in cells_group.items(): cell_id = int(name.split()[1]) cell = cells[cell_id] if cell.fill_type in ('material', 'distribmat'): cell.temperature = group['temperature'][()] - # Update material densities + # Make sure number of materials matches mats_group = fh['materials'] + n_cells = mats_group.attrs['n_materials'] + if n_cells != len(materials): + raise ValueError("Number of materials in properties file doesn't " + "match current model.") + + # Update material densities for name, group in mats_group.items(): mat_id = int(name.split()[1]) atom_density = group.attrs['atom_density'] diff --git a/src/summary.cpp b/src/summary.cpp index 64d9a63629..4e6e876ad0 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -163,7 +163,6 @@ extern "C" int openmc_properties_export(const char* filename) write_attribute(file, "date_and_time", time_stamp()); write_attribute(file, "path", settings::path_input); - // Write cell properties auto geom_group = create_group(file, "geometry"); write_attribute(geom_group, "n_cells", model::cells.size()); From 4484fd69f5b51d5c3d90801d6ae129cc839b2de7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 12 Jul 2021 07:26:26 -0500 Subject: [PATCH 20/23] Add checks during Cell::import_properties_hdf5 --- src/cell.cpp | 15 +++++++++++---- src/summary.cpp | 9 +++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 37550e9f50..9686a1d1b2 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -304,11 +304,18 @@ void Cell::import_properties_hdf5(hid_t group) vector temps; read_dataset(cell_group, "temperature", temps); + // Ensure number of temperatures makes sense + auto n_temps = temps.size(); + if (n_temps > 1 && n_temps != n_instances_) { + throw std::runtime_error(fmt::format( + "Number of temperatures for cell {} doesn't match number of instances", id_)); + } + // Modify temperatures for the cell - sqrtkT_.resize(0); - sqrtkT_.reserve(temps.size()); - for (auto T : temps) { - sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * T)); + sqrtkT_.clear(); + sqrtkT_.resize(temps.size()); + for (gsl::index i = 0; i < temps.size(); ++i) { + this->set_temperature(temps[i], i); } close_group(cell_group); diff --git a/src/summary.cpp b/src/summary.cpp index 4e6e876ad0..0ef0056476 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -221,8 +221,13 @@ extern "C" int openmc_properties_import(const char* filename) // Read cell properties auto cells_group = open_group(geom_group, "cells"); - for (const auto& c : model::cells) { - c->import_properties_hdf5(cells_group); + try { + for (const auto& c : model::cells) { + c->import_properties_hdf5(cells_group); + } + } catch (const std::exception& e) { + set_errmsg(e.what()); + return OPENMC_E_UNASSIGNED; } close_group(cells_group); close_group(geom_group); From 024b1080fd778dd2a324a6522738e6d9b3888183 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 12 Jul 2021 07:28:21 -0500 Subject: [PATCH 21/23] Update id_map docstring --- openmc/lib/plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/lib/plot.py b/openmc/lib/plot.py index b029d67570..da42ea49e0 100644 --- a/openmc/lib/plot.py +++ b/openmc/lib/plot.py @@ -228,7 +228,7 @@ def id_map(plot): Returns ------- id_map : numpy.ndarray - A NumPy array with shape (vertical pixels, horizontal pixels, 2) of + A NumPy array with shape (vertical pixels, horizontal pixels, 3) of OpenMC property ids with dtype int32 """ From 731f2975bb8f840e0302def583ff582da7a7f29f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 13 Jul 2021 06:57:33 -0500 Subject: [PATCH 22/23] Replace lib.Material.density property with get_density method --- openmc/lib/material.py | 37 +++++++++++++++++++++++++----------- tests/unit_tests/test_lib.py | 15 ++++++++++----- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/openmc/lib/material.py b/openmc/lib/material.py index fa27c4678b..8af251c14a 100644 --- a/openmc/lib/material.py +++ b/openmc/lib/material.py @@ -87,8 +87,6 @@ class Material(_FortranObjectWithID): ID of the material nuclides : list of str List of nuclides in the material - density : float - Density of the material in [g/cm^3] densities : numpy.ndarray Array of densities in atom/b-cm name : str @@ -176,15 +174,6 @@ class Material(_FortranObjectWithID): return self._get_densities()[0] return nuclides - @property - def density(self): - density = c_double() - try: - _dll.openmc_material_get_density(self._index, density) - except OpenMCError: - return None - return density.value - @property def densities(self): return self._get_densities()[1] @@ -226,6 +215,32 @@ class Material(_FortranObjectWithID): """ _dll.openmc_material_add_nuclide(self._index, name.encode(), density) + def get_density(self, units='atom/b-cm'): + """Get density of a material. + + Parameters + ---------- + units : {'atom/b-cm', 'g/cm3'} + Units for density + + Returns + ------- + float + Density in requested units + + """ + if units == 'atom/b-cm': + return self.densities.sum() + elif units == 'g/cm3': + density = c_double() + try: + _dll.openmc_material_get_density(self._index, density) + except OpenMCError: + return None + return density.value + else: + raise ValueError("Units must be 'atom/b-cm' or 'g/cm3'") + def set_density(self, density, units='atom/b-cm'): """Set density of a material. diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 3b6b02c393..9a4fc8b9fd 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -1,4 +1,5 @@ from collections.abc import Mapping +from ctypes import ArgumentError import os import numpy as np @@ -186,7 +187,7 @@ def test_material(lib_init): assert sum(m.densities) == pytest.approx(rho) m.set_density(0.1, 'g/cm3') - assert m.density == pytest.approx(0.1) + assert m.get_density('g/cm3') == pytest.approx(0.1) assert m.name == "Hot borated water" m.name = "Not hot borated water" assert m.name == "Not hot borated water" @@ -194,16 +195,20 @@ def test_material(lib_init): def test_properties_density(lib_init): m = openmc.lib.materials[1] - orig_density = m.density + orig_density = m.get_density('atom/b-cm') + orig_density_gpcc = m.get_density('g/cm3') # Export properties and change density openmc.lib.export_properties('properties.h5') - m.set_density(orig_density*2, 'g/cm3') - assert m.density == pytest.approx(orig_density*2) + m.set_density(orig_density_gpcc*2, 'g/cm3') + assert m.get_density() == pytest.approx(orig_density*2) # Import properties and check that density was restored openmc.lib.import_properties('properties.h5') - assert m.density == pytest.approx(orig_density) + assert m.get_density() == pytest.approx(orig_density) + + with pytest.raises(ValueError): + m.get_density('🥏') def test_material_add_nuclide(lib_init): From ab80feb65ac4d82a50aa054a7c52281218570e53 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 14 Jul 2021 15:12:46 -0500 Subject: [PATCH 23/23] Get rid of try/except block for lib.Material.get_density --- openmc/lib/material.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openmc/lib/material.py b/openmc/lib/material.py index 8af251c14a..6770721ab6 100644 --- a/openmc/lib/material.py +++ b/openmc/lib/material.py @@ -233,10 +233,7 @@ class Material(_FortranObjectWithID): return self.densities.sum() elif units == 'g/cm3': density = c_double() - try: - _dll.openmc_material_get_density(self._index, density) - except OpenMCError: - return None + _dll.openmc_material_get_density(self._index, density) return density.value else: raise ValueError("Units must be 'atom/b-cm' or 'g/cm3'")