mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 05:35:49 -04:00
Modified the C API to support setting material temperatures and to support setting the event based flag. Fixed failing MPI test.
This commit is contained in:
parent
20c8043c1c
commit
e8081207d7
11 changed files with 100 additions and 67 deletions
|
|
@ -88,6 +88,7 @@ int openmc_material_set_densities(
|
|||
int openmc_material_set_id(int32_t index, int32_t id);
|
||||
int openmc_material_get_name(int32_t index, const char** name);
|
||||
int openmc_material_set_name(int32_t index, const char* name);
|
||||
int openmc_material_set_temperature(int32_t index, double temperature);
|
||||
int openmc_material_set_volume(int32_t index, double volume);
|
||||
int openmc_material_filter_get_bins(
|
||||
int32_t index, const int32_t** bins, size_t* n);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,10 @@ public:
|
|||
double density_; //!< Total atom density in [atom/b-cm]
|
||||
double density_gpcc_; //!< Total atom density in [g/cm^3]
|
||||
double volume_ {-1.0}; //!< Volume in [cm^3]
|
||||
|
||||
double temperature_ {-1}; //!< Default temperature for material
|
||||
//!< A negative indicates no default
|
||||
//!< temperature was specified.
|
||||
bool fissionable_ {
|
||||
false}; //!< Does this material contain fissionable nuclides
|
||||
bool depletable_ {false}; //!< Is the material depletable?
|
||||
|
|
@ -195,10 +199,6 @@ private:
|
|||
// Private data members
|
||||
gsl::index index_;
|
||||
|
||||
//! \brief Default temperature for cells containing this material.
|
||||
//!
|
||||
//! A negative value indicates no default temperature was specified.
|
||||
double temperature_ {-1};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ extern "C" bool cmfd_run; //!< is a CMFD run?
|
|||
extern bool
|
||||
delayed_photon_scaling; //!< Scale fission photon yield to include delayed
|
||||
extern "C" bool entropy_on; //!< calculate Shannon entropy?
|
||||
extern bool event_based; //!< use event-based mode (instead of history-based)
|
||||
extern "C" bool event_based; //!< use event-based mode (instead of history-based)
|
||||
extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular?
|
||||
extern bool material_cell_offsets; //!< create material cells offsets?
|
||||
extern "C" bool output_summary; //!< write summary.h5?
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import openmc
|
|||
|
||||
def process_CLI_arguments(volume=False, geometry_debug=False, particles=None,
|
||||
plot=False, restart_file=None, threads=None,
|
||||
tracks=False, event_based=False,
|
||||
openmc_exec='openmc', mpi_args=None):
|
||||
tracks=False, event_based=None, openmc_exec='openmc',
|
||||
mpi_args=None):
|
||||
"""Run an OpenMC simulation.
|
||||
|
||||
Parameters
|
||||
|
|
@ -30,8 +30,9 @@ def process_CLI_arguments(volume=False, geometry_debug=False, particles=None,
|
|||
:envvar:`OMP_NUM_THREADS` environment variable).
|
||||
tracks : bool, optional
|
||||
Write tracks for all particles. Defaults to False.
|
||||
event_based : bool, optional
|
||||
Turns on event-based parallelism, instead of default history-based
|
||||
event_based : None or bool, optional
|
||||
Turns on event-based parallelism if True. If None, the value in
|
||||
the Settings will be used.
|
||||
openmc_exec : str, optional
|
||||
Path to OpenMC executable. Defaults to 'openmc'.
|
||||
mpi_args : list of str, optional
|
||||
|
|
@ -61,8 +62,9 @@ def process_CLI_arguments(volume=False, geometry_debug=False, particles=None,
|
|||
if geometry_debug:
|
||||
args.append('-g')
|
||||
|
||||
if event_based:
|
||||
args.append('-e')
|
||||
if event_based is not None:
|
||||
if event_based:
|
||||
args.append('-e')
|
||||
|
||||
if isinstance(restart_file, str):
|
||||
args += ['-r', restart_file]
|
||||
|
|
@ -70,6 +72,9 @@ def process_CLI_arguments(volume=False, geometry_debug=False, particles=None,
|
|||
if tracks:
|
||||
args.append('-t')
|
||||
|
||||
if plot:
|
||||
args.append('-p')
|
||||
|
||||
if mpi_args is not None:
|
||||
args = mpi_args + args
|
||||
|
||||
|
|
|
|||
|
|
@ -61,4 +61,6 @@ from .math import *
|
|||
from .plot import *
|
||||
|
||||
# Flag to denote whether or not openmc.lib.init has been called
|
||||
# TODO: Establish and use a flag in the C++ code to represent the status of the
|
||||
# openmc_init and openmc_finalize methods
|
||||
is_initialized = False
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ _dll.openmc_material_get_name.errcheck = _error_handler
|
|||
_dll.openmc_material_set_name.argtypes = [c_int32, c_char_p]
|
||||
_dll.openmc_material_set_name.restype = c_int
|
||||
_dll.openmc_material_set_name.errcheck = _error_handler
|
||||
_dll.openmc_material_set_temperature.argtypes = [c_int32, c_double]
|
||||
_dll.openmc_material_set_temperature.restype = c_int
|
||||
_dll.openmc_material_set_temperature.errcheck = _error_handler
|
||||
_dll.openmc_material_set_volume.argtypes = [c_int32, c_double]
|
||||
_dll.openmc_material_set_volume.restype = c_int
|
||||
_dll.openmc_material_set_volume.errcheck = _error_handler
|
||||
|
|
@ -165,6 +168,10 @@ class Material(_FortranObjectWithID):
|
|||
return None
|
||||
return volume.value
|
||||
|
||||
@temperature.setter
|
||||
def temperature(self, temperature):
|
||||
_dll.openmc_material_set_temperature(self._index, temperature)
|
||||
|
||||
@volume.setter
|
||||
def volume(self, volume):
|
||||
_dll.openmc_material_set_volume(self._index, volume)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class _Settings:
|
|||
restart_run = _DLLGlobal(c_bool, 'restart_run')
|
||||
run_CE = _DLLGlobal(c_bool, 'run_CE')
|
||||
verbosity = _DLLGlobal(c_int, 'verbosity')
|
||||
event_based = _DLLGlobal(c_bool, 'event_based')
|
||||
|
||||
@property
|
||||
def run_mode(self):
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class Model:
|
|||
"""
|
||||
|
||||
def __init__(self, geometry=None, materials=None, settings=None,
|
||||
tallies=None, plots=None, intracomm=None):
|
||||
tallies=None, plots=None):
|
||||
self.geometry = openmc.Geometry()
|
||||
self.materials = openmc.Materials()
|
||||
self.settings = openmc.Settings()
|
||||
|
|
@ -145,8 +145,6 @@ class Model:
|
|||
|
||||
@property
|
||||
def is_initialized(self):
|
||||
# TODO: Replace openmc.lib.is_initialized with a direct ctypes access
|
||||
# to simulation::initialized
|
||||
return openmc.lib.is_initialized
|
||||
|
||||
@geometry.setter
|
||||
|
|
@ -222,7 +220,7 @@ class Model:
|
|||
return cls(geometry, materials, settings)
|
||||
|
||||
def init_lib(self, threads=None, geometry_debug=False, restart_file=None,
|
||||
tracks=False, output=True, event_based=False):
|
||||
tracks=False, output=True, event_based=None):
|
||||
"""Initializes the model in memory via the C API
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
|
@ -243,8 +241,9 @@ class Model:
|
|||
Write tracks for all particles. Defaults to False.
|
||||
output : bool
|
||||
Capture OpenMC output from standard out
|
||||
event_based : bool, optional
|
||||
Turns on event-based parallelism, instead of default history-based
|
||||
event_based : None or bool, optional
|
||||
Turns on event-based parallelism if True. If None, the value in
|
||||
the Settings will be used.
|
||||
"""
|
||||
|
||||
# TODO: right now the only way to set most of the above parameters via
|
||||
|
|
@ -456,7 +455,7 @@ class Model:
|
|||
|
||||
def run(self, particles=None, threads=None, geometry_debug=False,
|
||||
restart_file=None, tracks=False, output=True, cwd='.',
|
||||
openmc_exec='openmc', mpi_args=None, event_based=False):
|
||||
openmc_exec='openmc', mpi_args=None, event_based=None):
|
||||
"""Runs OpenMC. If the C API has been initialized, then the C API is
|
||||
used, otherwise, this method creates the XML files and runs OpenMC via
|
||||
a system call. In both cases this method returns the path to the last
|
||||
|
|
@ -494,8 +493,9 @@ class Model:
|
|||
mpi_args : list of str, optional
|
||||
MPI execute command and any additional MPI arguments to pass,
|
||||
e.g. ['mpiexec', '-n', '8'].
|
||||
event_based : bool, optional
|
||||
Turns on event-based parallelism, instead of default history-based
|
||||
event_based : None or bool, optional
|
||||
Turns on event-based parallelism if True. If None, the value in
|
||||
the Settings will be used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -523,21 +523,21 @@ class Model:
|
|||
msg = f"{arg_name} must be set via Model.is_initialized(...)"
|
||||
raise ValueError(msg)
|
||||
|
||||
init_particles = openmc.lib.settings.particles
|
||||
if particles is not None:
|
||||
init_particles = openmc.lib.settings.particles
|
||||
if isinstance(particles, Integral) and particles > 0:
|
||||
openmc.lib.settings.particles = particles
|
||||
|
||||
# Event-based can be set at init-time or on a case-basis.
|
||||
# Handle the argument here.
|
||||
# TODO This will be dealt with in a future change to the C API
|
||||
init_event_based = openmc.lib.settings.event_based
|
||||
if event_based is not None:
|
||||
openmc.lib.settings.event_based = event_based
|
||||
|
||||
# Then run using the C API
|
||||
openmc.lib.run(output)
|
||||
|
||||
# Reset changes for the openmc.run kwargs handling
|
||||
if particles is not None:
|
||||
openmc.lib.settings.particles = init_particles
|
||||
openmc.lib.settings.particles = init_particles
|
||||
openmc.lib.settings.event_based = init_event_based
|
||||
|
||||
else:
|
||||
# Then run via the command line
|
||||
|
|
@ -697,10 +697,7 @@ class Model:
|
|||
if obj_type == 'cell' and attrib_name == 'volume':
|
||||
raise NotImplementedError(
|
||||
'Setting a Cell volume is not supported!')
|
||||
# Same with setting temperatures, TODO: update C API for this
|
||||
if obj_type == 'material' and attrib_name == 'temperature':
|
||||
raise NotImplementedError(
|
||||
'Setting a Material temperature is not yet supported!')
|
||||
|
||||
# And some items just dont make sense
|
||||
if obj_type == 'cell' and attrib_name == 'density':
|
||||
raise ValueError('Cannot set a Cell density!')
|
||||
|
|
@ -751,10 +748,10 @@ class Model:
|
|||
# Next lets keep what is in C API memory up to date as well
|
||||
if self.is_initialized:
|
||||
lib_obj = obj_by_id[id_]
|
||||
if attrib_name == 'temperature':
|
||||
lib_obj.set_temperature(value)
|
||||
elif attrib_name == 'density':
|
||||
if attrib_name == 'density':
|
||||
lib_obj.set_density(value, density_units)
|
||||
elif attrib_name == 'temperature' and obj_type == 'cell':
|
||||
lib_obj.set_temperature(value)
|
||||
else:
|
||||
setattr(lib_obj, attrib_name, value)
|
||||
|
||||
|
|
@ -800,7 +797,8 @@ class Model:
|
|||
|
||||
"""
|
||||
|
||||
self._change_py_lib_attribs(names_or_ids, vector, 'cell', 'translation')
|
||||
self._change_py_lib_attribs(names_or_ids, vector, 'cell',
|
||||
'translation')
|
||||
|
||||
def update_densities(self, names_or_ids, density, density_units='atom/b-cm'):
|
||||
"""Update the density of a given set of materials to a new value
|
||||
|
|
@ -822,8 +820,8 @@ class Model:
|
|||
|
||||
"""
|
||||
|
||||
self._change_py_lib_attribs(names_or_ids, density, 'material', 'density',
|
||||
density_units)
|
||||
self._change_py_lib_attribs(names_or_ids, density, 'material',
|
||||
'density', density_units)
|
||||
|
||||
def update_cell_temperatures(self, names_or_ids, temperature):
|
||||
"""Update the temperature of a set of cells to the given value
|
||||
|
|
@ -844,7 +842,7 @@ class Model:
|
|||
"""
|
||||
|
||||
self._change_py_lib_attribs(names_or_ids, temperature, 'cell',
|
||||
'temperature')
|
||||
'temperature')
|
||||
|
||||
def update_material_temperatures(self, names_or_ids, temperature):
|
||||
"""Update the temperature of a set of materials to the given value
|
||||
|
|
@ -865,7 +863,7 @@ class Model:
|
|||
"""
|
||||
|
||||
self._change_py_lib_attribs(names_or_ids, temperature, 'material',
|
||||
'temperature')
|
||||
'temperature')
|
||||
|
||||
def update_material_volumes(self, names_or_ids, volume):
|
||||
"""Update the volume of a set of materials to the given value
|
||||
|
|
|
|||
|
|
@ -1480,6 +1480,18 @@ extern "C" int openmc_material_set_name(int32_t index, const char* name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int openmc_material_set_temperature(int32_t index, double temperature)
|
||||
{
|
||||
if (index >= 0 && index < model::materials.size()) {
|
||||
auto& m {model::materials[index]};
|
||||
m->temperature_ = temperature;
|
||||
return 0;
|
||||
} 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 >= 0 && index < model::materials.size()) {
|
||||
|
|
|
|||
|
|
@ -207,6 +207,11 @@ def test_material(lib_init):
|
|||
m.name = "Not hot borated water"
|
||||
assert m.name == "Not hot borated water"
|
||||
|
||||
assert m.temperature == 293.6
|
||||
m.temperature = 400.
|
||||
assert m.temperature == 400.
|
||||
m.temperature == 293.6
|
||||
|
||||
|
||||
def test_properties_density(lib_init):
|
||||
m = openmc.lib.materials[1]
|
||||
|
|
@ -263,6 +268,7 @@ def test_settings(lib_init):
|
|||
assert settings.generations_per_batch == 1
|
||||
assert settings.particles == 100
|
||||
assert settings.seed == 1
|
||||
assert settings.event_based is False
|
||||
settings.seed = 11
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ from pathlib import Path
|
|||
from shutil import which
|
||||
import openmc
|
||||
import openmc.lib
|
||||
from openmc.mpi import DummyCommunicator
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
|
|
@ -128,12 +127,14 @@ def test_init(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
assert test_model._cells_by_id == {}
|
||||
assert test_model._cells_by_name == {}
|
||||
assert test_model.is_initialized is False
|
||||
assert isinstance(test_model.intracomm, DummyCommunicator)
|
||||
assert hasattr(test_model.intracomm, 'rank')
|
||||
|
||||
# Now check proper init of an actual model. Assume no interference between
|
||||
# parameters and so we can apply them all at once instead of testing one
|
||||
# parameter initialization at a time
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
if mpi_intracomm is not None:
|
||||
test_model.intracomm = mpi_intracomm
|
||||
assert test_model.geometry is geom
|
||||
assert test_model.materials is mats
|
||||
assert test_model.settings is settings
|
||||
|
|
@ -154,17 +155,10 @@ def test_init(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
'': [geom.root_universe.cells[3], geom.root_universe.cells[4]],
|
||||
'inf fuel': [geom.root_universe.cells[2].fill.cells[1]]}
|
||||
assert test_model.is_initialized is False
|
||||
if mpi_intracomm is None:
|
||||
assert isinstance(test_model.intracomm, DummyCommunicator)
|
||||
else:
|
||||
assert test_model.intracomm == mpi_intracomm
|
||||
|
||||
# Finally test the parameter type checking by passing bad types and
|
||||
# obtaining the right exception types
|
||||
if mpi_intracomm is not None:
|
||||
def_params = [geom, mats, settings, tals, plots, mpi_intracomm]
|
||||
else:
|
||||
def_params = [geom, mats, settings, tals, plots]
|
||||
def_params = [geom, mats, settings, tals, plots]
|
||||
for i in range(len(def_params)):
|
||||
args = def_params.copy()
|
||||
# Try an integer, as that is a bad type for all arguments
|
||||
|
|
@ -223,13 +217,14 @@ def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
|||
test_model.geometry.root_universe.cells[4]],
|
||||
'inf fuel': [test_model.geometry.root_universe.cells[2].fill.cells[1]]}
|
||||
assert test_model.is_initialized is False
|
||||
assert isinstance(test_model.intracomm, DummyCommunicator)
|
||||
|
||||
|
||||
def test_init_finalize_lib(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
# We are going to init and then make sure data is loaded
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
if mpi_intracomm is not None:
|
||||
test_model.intracomm = mpi_intracomm
|
||||
test_model.init_lib(output=False)
|
||||
|
||||
# First check that the API is advertised as initialized
|
||||
|
|
@ -257,6 +252,8 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
# Create PWR pin cell model and write XML files
|
||||
openmc.reset_auto_ids()
|
||||
model = openmc.examples.pwr_pin_cell()
|
||||
if mpi_intracomm is not None:
|
||||
model.intracomm = mpi_intracomm
|
||||
model.init_lib(output=False)
|
||||
|
||||
# Change fuel temperature and density and export properties
|
||||
|
|
@ -296,7 +293,9 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
|
||||
def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
if mpi_intracomm is not None:
|
||||
test_model.intracomm = mpi_intracomm
|
||||
|
||||
# This case will run by getting the k-eff and tallies for command-line and
|
||||
# C API execution modes and ensuring they give the same result.
|
||||
|
|
@ -334,7 +333,9 @@ def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
|
||||
def test_plots(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
if mpi_intracomm is not None:
|
||||
test_model.intracomm = mpi_intracomm
|
||||
|
||||
# This test cannot check the correctness of the plot, but it can
|
||||
# check that a plot was made and that the expected ppm and png files are
|
||||
|
|
@ -367,7 +368,9 @@ def test_plots(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
|
||||
def test_py_lib_attributes(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
if mpi_intracomm is not None:
|
||||
test_model.intracomm = mpi_intracomm
|
||||
|
||||
test_model.init_lib(output=False)
|
||||
|
||||
|
|
@ -439,19 +442,13 @@ def test_py_lib_attributes(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
|
||||
# Now lets do the material temperature updates.
|
||||
# Check initial conditions
|
||||
with pytest.raises(NotImplementedError):
|
||||
test_model.update_material_temperatures(['UO2'], 600.)
|
||||
# TODO: When C API material.set_temperature is implemented, uncomment below
|
||||
# assert abs(openmc.lib.materials[1].temperature - 293.6) < 1e-13
|
||||
# # The temperature on the material will be None because its just the
|
||||
# # default assert test_model.materials[0].temperature is None
|
||||
# # Change the temperature
|
||||
# test_model.update_material_temperatures(['UO2'], 600.)
|
||||
# assert abs(openmc.lib.materials[1].temperature - 600.) < 1e-13
|
||||
# assert abs(test_model.materials[0].temperature - 600.) < 1e-13
|
||||
assert abs(openmc.lib.materials[1].temperature - 293.6) < 1e-13
|
||||
# Change the temperature
|
||||
test_model.update_material_temperatures(['UO2'], 600.)
|
||||
assert abs(openmc.lib.materials[1].temperature - 600.) < 1e-13
|
||||
assert abs(test_model.materials[0].temperature - 600.) < 1e-13
|
||||
|
||||
# And finally material volume
|
||||
# import pdb; pdb.set_trace()
|
||||
assert abs(openmc.lib.materials[1].volume - 0.4831931368640985) < 1e-13
|
||||
# The temperature on the material will be None because its just the default
|
||||
assert abs(test_model.materials[0].volume - 0.4831931368640985) < 1e-13
|
||||
|
|
@ -468,7 +465,9 @@ def test_deplete(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
pin_model_attributes
|
||||
with open('test_chain.xml', 'w') as f:
|
||||
f.write(chain_file_xml)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
if mpi_intracomm is not None:
|
||||
test_model.intracomm = mpi_intracomm
|
||||
|
||||
initial_mat = mats[0].clone()
|
||||
initial_u = initial_mat.get_nuclide_atom_densities()['U235'][1]
|
||||
|
|
@ -518,7 +517,9 @@ def test_deplete(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
def test_calc_volumes(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
if mpi_intracomm is not None:
|
||||
test_model.intracomm = mpi_intracomm
|
||||
|
||||
# With no vol calcs, it should fail
|
||||
with pytest.raises(ValueError):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue