Skip to content
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8b1b8dc
add properties file path to settings
gonuke Feb 16, 2026
8713fe9
add flags to indicate which properties to read from properties file
gonuke Feb 18, 2026
76c258e
Add new XML reading method to check existence of file path
gonuke Feb 18, 2026
0a7636b
add flags for which properties to read from file
gonuke Feb 18, 2026
9942d78
read properties file after other initialization
gonuke Feb 18, 2026
886c641
propagate boolean for property reads into C API and related python calls
gonuke Feb 18, 2026
fd1594a
propagate read properties flags to cells
gonuke Feb 19, 2026
5852ec0
propagate read properties flags to material
gonuke Feb 19, 2026
a9b3f28
add new booleans to header
gonuke Feb 19, 2026
1b78b84
apply clang formatting
gonuke Feb 19, 2026
cc10db6
fix formatting
gonuke Feb 20, 2026
cf9a27e
manually fix clang-format inconsistency
gonuke Feb 20, 2026
4f796fb
fix string to char* conversion
gonuke Feb 20, 2026
6a862b6
declare new XML reader
gonuke Feb 20, 2026
cfcbfc2
add missing semi-colon and guess at formatting
gonuke Feb 20, 2026
fb22bba
add default value to signature
gonuke Feb 20, 2026
9a20d6e
clang-format-15
gonuke Feb 20, 2026
015df87
add file_utils to xml_interface
gonuke Feb 20, 2026
d8c92fd
back away from new XML reader for valid file paths
gonuke Feb 21, 2026
99ca76f
Improve documentation
gonuke Feb 21, 2026
a86f00e
switch to C++ error handling
gonuke Feb 21, 2026
5474147
cleanup lib call tests
gonuke Feb 22, 2026
902e749
add temporary file for testing
gonuke Feb 22, 2026
a62b545
don't convert back to string in test
gonuke Feb 22, 2026
c7a8090
Don't generate file, but do test against Path
gonuke Feb 22, 2026
ebbdc1a
abbreviate names
gonuke Feb 23, 2026
6355305
update documentation
gonuke Feb 23, 2026
19abae7
cleanup comments and error messages
gonuke Feb 23, 2026
1726602
simplify early exit logic
gonuke Feb 23, 2026
0e9eea3
style update
gonuke Feb 23, 2026
41317cf
read the properties in the right place
gonuke Mar 4, 2026
cde42e1
unwind fine-grained import booleans
gonuke Mar 5, 2026
17aa7ef
Adding manual test for properties load via settings
pshriwise Mar 8, 2026
86ec40c
Abandoning the test fixture as it adds complexity
pshriwise Mar 8, 2026
14df979
Altering TemporarySession intracomm handling for cleaner testing
pshriwise Mar 8, 2026
bcea94f
Test code cleanup
pshriwise Mar 8, 2026
6ad63cd
Merge pull request #1 from pshriwise/properties_in_settings
gonuke Mar 8, 2026
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
25 changes: 25 additions & 0 deletions docs/source/io_formats/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,31 @@ generator during generation of colors in plots.

*Default*: 1


.. _properties_file:

--------------------------------------
``<properties_file>`` Element
--------------------------------------

The ``properties_file`` element indicates whether temperatures and densities
from a properties file should override the properties present in the XML file. It contains
the following parameters:

:filepath:
The path to the properties file

:temperatures:
Boolean to indicate whether or not to read cell temperatures from the properties file.

*Default*: True

:densities:
Boolean to indicate whether or not to read cell and material densities from the properties file.

*Default*: True


---------------------
``<ptables>`` Element
---------------------
Expand Down
3 changes: 2 additions & 1 deletion include/openmc/capi.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,8 @@ 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);
int openmc_properties_import(
const char* filename, bool read_temperatures, bool read_densities);

// Error codes
extern int OPENMC_E_UNASSIGNED;
Expand Down
5 changes: 4 additions & 1 deletion include/openmc/cell.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,10 @@ class Cell {

//! Import physical properties from HDF5
//! \param[in] group HDF5 group to write to
void import_properties_hdf5(hid_t group);
//! \param[in] read_temperatures whether to read temperatures
//! \param[in] read_densities whether to read densities
void import_properties_hdf5(
hid_t group, bool read_temperatures, bool read_densities);

//! Get the BoundingBox for this cell.
virtual BoundingBox bounding_box() const = 0;
Expand Down
2 changes: 1 addition & 1 deletion include/openmc/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class Material {

//! Import physical properties from HDF5
//! \param[in] group HDF5 group to read from
void import_properties_hdf5(hid_t group);
void import_properties_hdf5(hid_t group, bool read_densities);

//! Add nuclide to the material
//
Expand Down
6 changes: 6 additions & 0 deletions include/openmc/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ extern bool weight_window_checkpoint_collision; //!< enable weight window check
//!< upon collision?
extern bool write_all_tracks; //!< write track files for every particle?
extern bool write_initial_source; //!< write out initial source file?
extern bool read_temperatures; //!< read cell temperatures from
//!< properties file?
extern bool read_densities; //!< read cell/material densities
//!< from properties file?

// Paths to various files
extern std::string path_cross_sections; //!< path to cross_sections.xml
Expand All @@ -114,6 +118,8 @@ extern std::string path_sourcepoint; //!< path to a source file
extern std::string path_statepoint; //!< path to a statepoint file
extern std::string weight_windows_file; //!< Location of weight window file to
//!< load on simulation initialization
extern std::string properties_file; //!< Location of properties file to
//!< load on simulation initialization

// This is required because the c_str() may not be the first thing in
// std::string. Sometimes it is, but it seems libc++ may not be like that
Expand Down
4 changes: 2 additions & 2 deletions openmc/lib/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class _SourceSite(Structure):
_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.argtypes = [c_char_p, c_bool, c_bool]
_dll.openmc_properties_import.restype = c_int
_dll.openmc_properties_import.errcheck = _error_handler
_dll.openmc_run.restype = c_int
Expand Down Expand Up @@ -304,7 +304,7 @@ def import_properties(filename):
openmc.lib.export_properties

"""
_dll.openmc_properties_import(filename.encode())
_dll.openmc_properties_import(filename.encode(), True, True)


def init(args=None, intracomm=None, output=True):
Expand Down
74 changes: 74 additions & 0 deletions openmc/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ class Settings:
Initial seed for randomly generated plot colors.
ptables : bool
Determine whether probability tables are used.
properties_file : Pathlike
Location of the properties file to load cell temperatures/densities
and materials
read_temperatures : bool
Whether to read cell temperatures from the properties file
read_densities : bool
Whether to read densities from the properties file
random_ray : dict
Options for configuring the random ray solver. Acceptable keys are:

Expand Down Expand Up @@ -392,6 +399,9 @@ def __init__(self, **kwargs):
self._photon_transport = None
self._plot_seed = None
self._ptables = None
self._properties_file = None
self._read_temperatures = None
self._read_densities = None
self._uniform_source_sampling = None
self._seed = None
self._stride = None
Expand Down Expand Up @@ -1018,6 +1028,40 @@ def temperature(self, temperature: dict):

self._temperature = temperature

@property
def properties_file(self) -> PathLike | None:
return self._properties_file

@properties_file.setter
def properties_file(self, value: PathLike | None):
if value is None:
self._properties_file = None
else:
cv.check_type('properties file', value, PathLike)
self._properties_file = input_path(value)
self.read_temperatures = True
self.read_densities = True

@property
def read_temperatures(self) -> bool:
return self._read_temperatures

@read_temperatures.setter
def read_temperatures(self, read_temperatures : bool):
cv.check_type('read temperatures from properties ',
read_temperatures, bool)
self._read_temperatures = read_temperatures

@property
def read_densities(self) -> bool:
return self._read_densities

@read_densities.setter
def read_densities(self, read_densities : bool):
cv.check_type('read temperatures from properties ',
read_densities, bool)
self._read_densities = read_densities

@property
def trace(self) -> Iterable:
return self._trace
Expand Down Expand Up @@ -1708,6 +1752,25 @@ def _create_temperature_subelements(self, root):
else:
element.text = str(value)

def _create_properties_file_element(self, root):
if ((self.read_densities or
self.read_temperatures) and
self.properties_file is None):
# build warning that no properties file is specified
msg = ('Flag to read densities or temperatures was set without providing '
'a properties file.')
warnings.warn(msg)

if self.properties_file is not None:
element = ET.Element("properties")
subelement = ET.SubElement(element, "filepath")
subelement.text = str(self.properties_file)
subelement = ET.SubElement(element, "temperatures")
subelement.text = str(self.read_temperatures).lower()
subelement = ET.SubElement(element, "densities")
subelement.text = str(self.read_densities).lower()
root.append(element)

def _create_trace_subelement(self, root):
if self._trace is not None:
element = ET.SubElement(root, "trace")
Expand Down Expand Up @@ -2205,6 +2268,15 @@ def _temperature_from_xml_element(self, root):
if text is not None:
self.temperature['multipole'] = text in ('true', '1')

def _properties_file_from_xml_element(self, root):
elem = root.find('properties')
if elem is not None:
self.properties_file = get_text(elem, 'filepath')
text = get_text(elem, 'temperatures')
self.read_temperatures = text in ('true', '1')
text = get_text(elem, 'densities')
self.read_densities = text in ('true', '1')

def _trace_from_xml_element(self, root):
text = get_elem_list(root, "trace", int)
if text is not None:
Expand Down Expand Up @@ -2440,6 +2512,7 @@ def to_xml_element(self, mesh_memo=None):
self._create_ifp_n_generation_subelement(element)
self._create_tabular_legendre_subelements(element)
self._create_temperature_subelements(element)
self._create_properties_file_element(element)
self._create_trace_subelement(element)
self._create_track_subelement(element)
self._create_ufs_mesh_subelement(element, mesh_memo)
Expand Down Expand Up @@ -2554,6 +2627,7 @@ def from_xml_element(cls, elem, meshes=None):
settings._ifp_n_generation_from_xml_element(elem)
settings._tabular_legendre_from_xml_element(elem)
settings._temperature_from_xml_element(elem)
settings._properties_file_from_xml_element(elem)
settings._trace_from_xml_element(elem)
settings._track_from_xml_element(elem)
settings._ufs_mesh_from_xml_element(elem, meshes)
Expand Down
65 changes: 35 additions & 30 deletions src/cell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,45 +234,50 @@ void Cell::export_properties_hdf5(hid_t group) const
close_group(cell_group);
}

void Cell::import_properties_hdf5(hid_t group)
void Cell::import_properties_hdf5(
hid_t group, bool read_temperatures, bool read_densities)
{
auto cell_group = open_group(group, fmt::format("cell {}", id_));

// Read temperatures from file
vector<double> temps;
read_dataset(cell_group, "temperature", temps);
if (read_temperatures) {
// Read temperatures from file
vector<double> 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()) {
fatal_error(fmt::format(
"Number of temperatures for cell {} doesn't match number of instances",
id_));
}
// Ensure number of temperatures makes sense
auto n_temps = temps.size();
if (n_temps > 1 && n_temps != n_instances()) {
fatal_error(fmt::format(
"Number of temperatures for cell {} doesn't match number of instances",
id_));
}

// Modify temperatures for the cell
sqrtkT_.clear();
sqrtkT_.resize(temps.size());
for (int64_t i = 0; i < temps.size(); ++i) {
this->set_temperature(temps[i], i);
// Modify temperatures for the cell
sqrtkT_.clear();
sqrtkT_.resize(temps.size());
for (int64_t i = 0; i < temps.size(); ++i) {
this->set_temperature(temps[i], i);
}
}

// Read densities
if (object_exists(cell_group, "density")) {
vector<double> density;
read_dataset(cell_group, "density", density);
if (read_densities) {
// Read densities
if (object_exists(cell_group, "density")) {
vector<double> density;
read_dataset(cell_group, "density", density);

// Ensure number of densities makes sense
auto n_density = density.size();
if (n_density > 1 && n_density != n_instances()) {
fatal_error(fmt::format("Number of densities for cell {} "
"doesn't match number of instances",
id_));
}
// Ensure number of densities makes sense
auto n_density = density.size();
if (n_density > 1 && n_density != n_instances()) {
fatal_error(fmt::format("Number of densities for cell {} "
"doesn't match number of instances",
id_));
}

// Set densities.
for (int32_t i = 0; i < n_density; ++i) {
this->set_density(density[i], i);
// Set densities.
for (int32_t i = 0; i < n_density; ++i) {
this->set_density(density[i], i);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/finalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ int openmc_finalize()
settings::temperature_multipole = false;
settings::temperature_range = {0.0, 0.0};
settings::temperature_tolerance = 10.0;
settings::properties_file.clear();
settings::trigger_on = false;
settings::trigger_predict = false;
settings::trigger_batch_interval = 1;
Expand Down
5 changes: 5 additions & 0 deletions src/initialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,11 @@ void read_separate_xml_files()
read_plots_xml();

finalize_variance_reduction();

if (!settings::properties_file.empty()) {
openmc_properties_import(settings::properties_file.c_str(),
settings::read_temperatures, settings::read_densities);
}
}

void initial_output()
Expand Down
5 changes: 4 additions & 1 deletion src/material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1138,8 +1138,11 @@ void Material::export_properties_hdf5(hid_t group) const
close_group(material_group);
}

void Material::import_properties_hdf5(hid_t group)
void Material::import_properties_hdf5(hid_t group, bool read_densities)
{
if (!read_densities)
return;

hid_t material_group = open_group(group, "material " + std::to_string(id_));
double density;
read_attribute(material_group, "atom_density", density);
Expand Down
16 changes: 16 additions & 0 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ bool weight_window_checkpoint_surface {false};
bool weight_window_checkpoint_collision {true};
bool write_all_tracks {false};
bool write_initial_source {false};
bool read_temperatures {true};
bool read_densities {true};

std::string path_cross_sections;
std::string path_input;
Expand All @@ -96,6 +98,7 @@ std::string path_sourcepoint;
std::string path_statepoint;
const char* path_statepoint_c {path_statepoint.c_str()};
std::string weight_windows_file;
std::string properties_file;

int32_t n_inactive {0};
int32_t max_lost_particles {10};
Expand Down Expand Up @@ -733,6 +736,19 @@ void read_settings_xml(pugi::xml_node root)
}
}

// read properties from file
if (check_for_node(root, "properties")) {
// Get pointer to properties node
xml_node node_props = root.child("properties");

properties_file = get_node_value(node_props, "filepath");
if (!file_exists(properties_file)) {
fatal_error(fmt::format("File '{}' does not exist.", properties_file));
}
read_temperatures = get_node_value_bool(node_props, "temperatures");
read_densities = get_node_value_bool(node_props, "densities");
}

// Particle trace
if (check_for_node(root, "trace")) {
auto temp = get_node_array<int64_t>(root, "trace");
Expand Down
Loading
Loading