diff --git a/docs/source/io_formats/materials.rst b/docs/source/io_formats/materials.rst index 7875eb330d..322b9c9994 100644 --- a/docs/source/io_formats/materials.rst +++ b/docs/source/io_formats/materials.rst @@ -50,6 +50,12 @@ Each ``material`` element can have the following attributes or sub-elements: *Default*: "" + :depletable: + Boolean value indicating whether the material is depletable. + + :volume: + Volume of the material in cm^3. + :temperature: An element with no attributes which is used to set the default temperature of the material in Kelvin. diff --git a/include/openmc.h b/include/openmc.h index 1f919d7c61..898be784e6 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -56,9 +56,11 @@ extern "C" { int openmc_material_add_nuclide(int32_t index, const char name[], double density); int openmc_material_get_densities(int32_t index, int** nuclides, double** densities, int* n); int openmc_material_get_id(int32_t index, int32_t* id); + int openmc_material_get_volume(int32_t index, double* volume); int openmc_material_set_density(int32_t index, double density); int openmc_material_set_densities(int32_t index, int n, const char** name, const double* density); int openmc_material_set_id(int32_t index, int32_t id); + int openmc_material_set_volume(int32_t index, double volume); int openmc_material_filter_get_bins(int32_t index, int32_t** bins, int32_t* n); int openmc_material_filter_set_bins(int32_t index, int32_t n, const int32_t* bins); int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh); diff --git a/openmc/material.py b/openmc/material.py index dac2fe14af..bd31fbd23a 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -284,6 +284,8 @@ class Material(IDManagerMixin): # Create the Material material = cls(mat_id, name) material.depletable = bool(group.attrs['depletable']) + if 'volume' in group.attrs: + material.volume = group.attrs['volume'] # Read the names of the S(a,b) tables for this Material and add them if 'sab_names' in group: @@ -833,6 +835,9 @@ class Material(IDManagerMixin): if self._depletable: element.set("depletable", "true") + if self._volume: + element.set("volume", str(self._volume)) + # Create temperature XML subelement if self.temperature is not None: subelement = ET.SubElement(element, "temperature") diff --git a/src/cell.cpp b/src/cell.cpp index d26fa84147..fb364cfdfb 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -493,7 +493,7 @@ openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n) *n = 1; } } else { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } return 0; @@ -517,7 +517,7 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, //TODO: off-by-one c.material.push_back(i_mat - 1); } else { - strcpy(openmc_err_msg, "Index in materials array is out of bounds."); + set_errmsg("Index in materials array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } } @@ -528,7 +528,7 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, c.type = FILL_LATTICE; } } else { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } return 0; diff --git a/src/error.h b/src/error.h index 356dfd8010..7d015d6143 100644 --- a/src/error.h +++ b/src/error.h @@ -5,6 +5,7 @@ #include #include +#include "openmc.h" namespace openmc { @@ -14,20 +15,38 @@ extern "C" void warning_from_c(const char* message, int message_len); extern "C" void write_message_from_c(const char* message, int message_len, int level); -inline -void fatal_error(const char *message) +inline void +set_errmsg(const char* message) { - fatal_error_from_c(message, strlen(message)); + std::strcpy(openmc_err_msg, message); +} + +inline void +set_errmsg(const std::string& message) +{ + std::strcpy(openmc_err_msg, message.c_str()); +} + +inline void +set_errmsg(const std::stringstream& message) +{ + std::strcpy(openmc_err_msg, message.str().c_str()); } inline -void fatal_error(const std::string &message) +void fatal_error(const char* message) +{ + fatal_error_from_c(message, std::strlen(message)); +} + +inline +void fatal_error(const std::string& message) { fatal_error_from_c(message.c_str(), message.length()); } inline -void fatal_error(const std::stringstream &message) +void fatal_error(const std::stringstream& message) { fatal_error(message.str()); } @@ -47,7 +66,7 @@ void warning(const std::stringstream& message) inline void write_message(const char* message, int level) { - write_message_from_c(message, strlen(message), level); + write_message_from_c(message, std::strlen(message), level); } inline diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 23472e21af..ca86ae2ae1 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1534,9 +1534,7 @@ contains ! Check if material is depletable if (check_for_node(node_mat, "depletable")) then - call get_node_value(node_mat, "depletable", temp_str) - if (to_lower(temp_str) == "true" .or. temp_str == "1") & - mat % depletable = .true. + call get_node_value(node_mat, "depletable", mat % depletable) end if ! Copy material name diff --git a/src/material.cpp b/src/material.cpp index c9ef47f074..409908e673 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -20,13 +20,17 @@ std::unordered_map material_map; // Material implementation //============================================================================== -Material::Material(pugi::xml_node material_node) +Material::Material(pugi::xml_node node) { - if (check_for_node(material_node, "id")) { - id = std::stoi(get_node_value(material_node, "id")); + if (check_for_node(node, "id")) { + id = std::stoi(get_node_value(node, "id")); } else { fatal_error("Must specify id of material in materials XML file."); } + + if (check_for_node(node, "volume")) { + volume_ = std::stod(get_node_value(node, "volume")); + } } //============================================================================== @@ -56,6 +60,48 @@ read_materials(pugi::xml_node* node) } } +//============================================================================== +// C API +//============================================================================== + +extern "C" int +openmc_material_get_volume(int32_t index, double* volume) +{ + if (index >= 1 && index <= global_materials.size()) { + Material* m = global_materials[index - 1]; + if (m->volume_ >= 0.0) { + *volume = m->volume_; + return 0; + } else { + std::stringstream msg; + msg << "Volume for material with ID=" << m->id << " not set."; + set_errmsg(msg); + return OPENMC_E_UNASSIGNED; + } + } else { + set_errmsg("Index in materials array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + +extern "C" int +openmc_material_set_volume(int32_t index, double volume) +{ + if (index >= 1 && index <= global_materials.size()) { + Material* m = global_materials[index - 1]; + if (volume >= 0.0) { + m->volume_ = volume; + return 0; + } else { + set_errmsg("Volume must be non-negative"); + return OPENMC_E_INVALID_ARGUMENT; + } + } else { + set_errmsg("Index in materials array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + //============================================================================== // Fortran compatibility functions //============================================================================== diff --git a/src/material.h b/src/material.h index 0a9a099a44..c6337f1e25 100644 --- a/src/material.h +++ b/src/material.h @@ -25,6 +25,7 @@ class Material { public: int32_t id; //!< Unique ID + double volume_ {-1.0}; //!< Volume in [cm^3] Material() {}; diff --git a/src/material_header.F90 b/src/material_header.F90 index a9de08ec4c..33195497cb 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -24,6 +24,7 @@ module material_header public :: openmc_material_add_nuclide public :: openmc_material_get_id public :: openmc_material_get_densities + public :: openmc_material_get_volume public :: openmc_material_set_density public :: openmc_material_set_densities public :: openmc_material_set_id @@ -51,9 +52,16 @@ module material_header end subroutine material_set_id_c subroutine extend_materials_c(n) bind(C) - import C_INT32_t + import C_INT32_T integer(C_INT32_T), intent(in), value :: n end subroutine extend_materials_c + + function openmc_material_get_volume(index, volume) result(err) bind(C) + import C_INT32_T, C_DOUBLE, C_INT + integer(C_INT32_T), value :: index + real(C_DOUBLE), intent(out) :: volume + integer(C_INT) :: err + end function openmc_material_get_volume end interface !=============================================================================== diff --git a/src/relaxng/materials.rnc b/src/relaxng/materials.rnc index c7e0fbf863..d2a84418ea 100644 --- a/src/relaxng/materials.rnc +++ b/src/relaxng/materials.rnc @@ -1,10 +1,14 @@ element materials { element material { (element id { xsd:int } | attribute id { xsd:int }) & - (element name { xsd:string { maxLength="52" } } | - attribute name { xsd:string { maxLength="52" } })? & - element temperature { xsd:double }? & + (element name { xsd:string } | attribute name { xsd:string })? & + + (element depletable { xsd:boolean } | attribute depletable { xsd:boolean })? & + + (element volume { xsd:double } | attribute volume { xsd:double })? & + + (element temperature { xsd:double } | attribute temperature { xsd:double })? & element density { (element value { xsd:double } | attribute value { xsd:double })? & diff --git a/src/relaxng/materials.rng b/src/relaxng/materials.rng index 342260be8e..90d6ec5c6e 100644 --- a/src/relaxng/materials.rng +++ b/src/relaxng/materials.rng @@ -15,21 +15,42 @@ - - 52 - + - - 52 - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/summary.F90 b/src/summary.F90 index 13bc426637..ddc64f707b 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -5,7 +5,7 @@ module summary use error, only: write_message use geometry_header use hdf5_interface - use material_header, only: Material, n_materials + use material_header, only: Material, n_materials, openmc_material_get_volume use mesh_header, only: RegularMesh use message_passing use mgxs_interface @@ -315,8 +315,10 @@ contains integer :: j integer :: k integer :: n + integer :: err character(20), allocatable :: nuc_names(:) character(20), allocatable :: macro_names(:) + real(8) :: volume real(8), allocatable :: nuc_densities(:) integer :: num_nuclides integer :: num_macros @@ -341,6 +343,11 @@ contains call write_attribute(material_group, "depletable", 0) end if + err = openmc_material_get_volume(i, volume) + if (err == 0 .and. volume > ZERO) then + call write_attribute(material_group, "volume", volume) + end if + ! Write name for this material call write_dataset(material_group, "name", m % name)