mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 14:15:42 -04:00
Resolving comments from @paulromano and updating tests accordingly
This commit is contained in:
parent
d7bf830028
commit
dc80b799ac
8 changed files with 373 additions and 385 deletions
|
|
@ -583,40 +583,12 @@ class SILEQIIntegrator(SIIntegrator):
|
|||
return proc_time, [eos_conc, inter_conc], [res_bar]
|
||||
|
||||
|
||||
def integrator_factory(method):
|
||||
"""This method is a factor for the integrator sub-classes
|
||||
|
||||
Params
|
||||
------
|
||||
method : str
|
||||
The type of integrator method to use. Valid values are: 'cecm',
|
||||
'predictor', 'cf4', 'epc_rk4', 'si_celi', 'si_leqi', 'celi', and 'leqi'
|
||||
|
||||
Returns
|
||||
-------
|
||||
integrator : Integrator
|
||||
The type of integrator
|
||||
|
||||
"""
|
||||
|
||||
if method == 'cecm':
|
||||
integrator = CECMIntegrator
|
||||
elif method == 'predictor':
|
||||
integrator = PredictorIntegrator
|
||||
elif method == 'cf4':
|
||||
integrator = CF4Integrator
|
||||
elif method == 'epc_rk4':
|
||||
integrator = EPCRK4Integrator
|
||||
elif method == 'si_celi':
|
||||
integrator = SICELIIntegrator
|
||||
elif method == 'si_leqi':
|
||||
integrator = SILEQIIntegrator
|
||||
elif method == 'celi':
|
||||
integrator = CELIIntegrator
|
||||
elif method == 'leqi':
|
||||
integrator = LEQIIntegrator
|
||||
else:
|
||||
msg = "Invalid integrator method: {}!".format(method)
|
||||
raise ValueError(msg)
|
||||
|
||||
return integrator
|
||||
integrator_by_name = {
|
||||
'cecm': CECMIntegrator,
|
||||
'predictor': PredictorIntegrator,
|
||||
'cf4': CF4Integrator,
|
||||
'epc_rk4': EPCRK4Integrator,
|
||||
'si_celi': SICELIIntegrator,
|
||||
'si_leqi': SILEQIIntegrator,
|
||||
'celi': CELIIntegrator,
|
||||
'leqi': LEQIIntegrator}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ class Operator(TransportOperator):
|
|||
self.settings = settings
|
||||
self.geometry = geometry
|
||||
self.diff_burnable_mats = diff_burnable_mats
|
||||
self.cleanup_when_done = True
|
||||
self._cleanup_when_done = True
|
||||
|
||||
# Reduce the chain before we create more materials
|
||||
if reduce_chain:
|
||||
|
|
@ -537,7 +537,7 @@ class Operator(TransportOperator):
|
|||
|
||||
# Initialize OpenMC library
|
||||
comm.barrier()
|
||||
if not openmc.lib.LIB_INIT:
|
||||
if not openmc.lib.is_initialized:
|
||||
openmc.lib.init(intracomm=comm)
|
||||
|
||||
# Generate tallies in memory
|
||||
|
|
@ -556,7 +556,7 @@ class Operator(TransportOperator):
|
|||
|
||||
def finalize(self):
|
||||
"""Finalize a depletion simulation and release resources."""
|
||||
if self.cleanup_when_done:
|
||||
if self._cleanup_when_done:
|
||||
openmc.lib.finalize()
|
||||
|
||||
def _update_materials(self):
|
||||
|
|
|
|||
|
|
@ -1,23 +1,79 @@
|
|||
from collections.abc import Iterable
|
||||
from numbers import Integral
|
||||
import subprocess
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
import openmc
|
||||
|
||||
|
||||
@contextmanager
|
||||
def change_directory(working_dir):
|
||||
"""A context manager for executing in a provided working directory"""
|
||||
start_dir = Path().absolute()
|
||||
try:
|
||||
Path.mkdir(working_dir, exist_ok=True)
|
||||
os.chdir(working_dir)
|
||||
yield
|
||||
finally:
|
||||
os.chdir(start_dir)
|
||||
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):
|
||||
"""Run an OpenMC simulation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
volume : bool, optional
|
||||
Run in stochastic volume calculation mode. Defaults to False.
|
||||
geometry_debug : bool, optional
|
||||
Turn on geometry debugging during simulation. Defaults to False.
|
||||
particles : int, optional
|
||||
Number of particles to simulate per generation.
|
||||
plot : bool, optional
|
||||
Run in plotting mode. Defaults to False.
|
||||
restart_file : str, optional
|
||||
Path to restart file to use
|
||||
threads : int, optional
|
||||
Number of OpenMP threads. If OpenMC is compiled with OpenMP threading
|
||||
enabled, the default is implementation-dependent but is usually equal
|
||||
to the number of hardware threads available (or a value set by the
|
||||
: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
|
||||
openmc_exec : str, optional
|
||||
Path to OpenMC executable. Defaults to 'openmc'.
|
||||
mpi_args : list of str, optional
|
||||
MPI execute command and any additional MPI arguments to pass,
|
||||
e.g. ['mpiexec', '-n', '8'].
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Returns
|
||||
-------
|
||||
args : Iterable of str
|
||||
The runtime flags converted to CLI arguments of the OpenMC executable
|
||||
|
||||
"""
|
||||
|
||||
args = [openmc_exec]
|
||||
|
||||
if volume:
|
||||
args += ['--volume']
|
||||
|
||||
if isinstance(particles, Integral) and particles > 0:
|
||||
args += ['-n', str(particles)]
|
||||
|
||||
if isinstance(threads, Integral) and threads > 0:
|
||||
args += ['-s', str(threads)]
|
||||
|
||||
if geometry_debug:
|
||||
args.append('-g')
|
||||
|
||||
if event_based:
|
||||
args.append('-e')
|
||||
|
||||
if isinstance(restart_file, str):
|
||||
args += ['-r', restart_file]
|
||||
|
||||
if tracks:
|
||||
args.append('-t')
|
||||
|
||||
if mpi_args is not None:
|
||||
args = mpi_args + args
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def _run(args, output, cwd):
|
||||
|
|
@ -141,8 +197,8 @@ def calculate_volumes(threads=None, output=True, cwd='.',
|
|||
----------
|
||||
threads : int, optional
|
||||
Number of OpenMP threads. If OpenMC is compiled with OpenMP threading
|
||||
enabled, the default is implementation-dependent but is usually equal to
|
||||
the number of hardware threads available (or a value set by the
|
||||
enabled, the default is implementation-dependent but is usually equal
|
||||
to the number of hardware threads available (or a value set by the
|
||||
:envvar:`OMP_NUM_THREADS` environment variable).
|
||||
output : bool, optional
|
||||
Capture OpenMC output from standard out
|
||||
|
|
@ -165,12 +221,9 @@ def calculate_volumes(threads=None, output=True, cwd='.',
|
|||
openmc.VolumeCalculation
|
||||
|
||||
"""
|
||||
args = [openmc_exec, '--volume']
|
||||
|
||||
if isinstance(threads, Integral) and threads > 0:
|
||||
args += ['-s', str(threads)]
|
||||
if mpi_args is not None:
|
||||
args = mpi_args + args
|
||||
args = process_CLI_arguments(volume=True, threads=threads,
|
||||
openmc_exec=openmc_exec, mpi_args=mpi_args)
|
||||
|
||||
_run(args, output, cwd)
|
||||
|
||||
|
|
@ -186,8 +239,8 @@ def run(particles=None, threads=None, geometry_debug=False,
|
|||
Number of particles to simulate per generation.
|
||||
threads : int, optional
|
||||
Number of OpenMP threads. If OpenMC is compiled with OpenMP threading
|
||||
enabled, the default is implementation-dependent but is usually equal to
|
||||
the number of hardware threads available (or a value set by the
|
||||
enabled, the default is implementation-dependent but is usually equal
|
||||
to the number of hardware threads available (or a value set by the
|
||||
:envvar:`OMP_NUM_THREADS` environment variable).
|
||||
geometry_debug : bool, optional
|
||||
Turn on geometry debugging during simulation. Defaults to False.
|
||||
|
|
@ -216,27 +269,10 @@ def run(particles=None, threads=None, geometry_debug=False,
|
|||
If the `openmc` executable returns a non-zero status
|
||||
|
||||
"""
|
||||
args = [openmc_exec]
|
||||
|
||||
if isinstance(particles, Integral) and particles > 0:
|
||||
args += ['-n', str(particles)]
|
||||
|
||||
if isinstance(threads, Integral) and threads > 0:
|
||||
args += ['-s', str(threads)]
|
||||
|
||||
if geometry_debug:
|
||||
args.append('-g')
|
||||
|
||||
if event_based:
|
||||
args.append('-e')
|
||||
|
||||
if isinstance(restart_file, str):
|
||||
args += ['-r', restart_file]
|
||||
|
||||
if tracks:
|
||||
args.append('-t')
|
||||
|
||||
if mpi_args is not None:
|
||||
args = mpi_args + args
|
||||
args = process_CLI_arguments(
|
||||
volume=False, geometry_debug=geometry_debug, particles=particles,
|
||||
restart_file=restart_file, threads=threads, tracks=tracks,
|
||||
event_based=event_based, openmc_exec=openmc_exec, mpi_args=mpi_args)
|
||||
|
||||
_run(args, output, cwd)
|
||||
|
|
|
|||
|
|
@ -60,4 +60,5 @@ from .settings import settings
|
|||
from .math import *
|
||||
from .plot import *
|
||||
|
||||
LIB_INIT = False
|
||||
# Flag to denote whether or not openmc.lib.init has been called
|
||||
is_initialized = False
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ def export_properties(filename=None):
|
|||
def finalize():
|
||||
"""Finalize simulation and free memory"""
|
||||
_dll.openmc_finalize()
|
||||
openmc.lib.LIB_INIT = False
|
||||
openmc.lib.is_initialized = False
|
||||
|
||||
|
||||
def find_cell(xyz):
|
||||
|
|
@ -215,7 +215,7 @@ def import_properties(filename):
|
|||
See Also
|
||||
--------
|
||||
openmc.lib.export_properties
|
||||
mat
|
||||
|
||||
"""
|
||||
_dll.openmc_properties_import(filename.encode())
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ def init(args=None, intracomm=None):
|
|||
intracomm = c_void_p(address)
|
||||
|
||||
_dll.openmc_init(argc, argv, intracomm)
|
||||
openmc.lib.LIB_INIT = True
|
||||
openmc.lib.is_initialized = True
|
||||
|
||||
|
||||
def is_statepoint_batch():
|
||||
|
|
|
|||
|
|
@ -1,20 +1,30 @@
|
|||
from collections.abc import Iterable
|
||||
import operator
|
||||
import os
|
||||
from pathlib import Path
|
||||
from numbers import Integral
|
||||
import time
|
||||
import warnings
|
||||
import subprocess
|
||||
from contextlib import contextmanager
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
from openmc.checkvalue import check_type, check_value, check_iterable_type, \
|
||||
check_length
|
||||
import openmc.deplete as dep
|
||||
from openmc.data.library import DataLibrary
|
||||
from openmc.exceptions import DataError, InvalidIDError, SetupError
|
||||
from openmc.checkvalue import check_type, check_value
|
||||
from openmc.exceptions import InvalidIDError
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _change_directory(working_dir):
|
||||
"""A context manager for executing in a provided working directory"""
|
||||
start_dir = Path().cwd()
|
||||
Path.mkdir(working_dir, exist_ok=True)
|
||||
os.chdir(working_dir)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.chdir(start_dir)
|
||||
|
||||
|
||||
class Model:
|
||||
|
|
@ -28,6 +38,8 @@ class Model:
|
|||
not set, it will attempt to create a ``materials.xml`` file based on all
|
||||
materials appearing in the geometry.
|
||||
|
||||
.. versionchanged:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
geometry : openmc.Geometry, optional
|
||||
|
|
@ -40,14 +52,8 @@ class Model:
|
|||
Tallies information
|
||||
plots : openmc.Plots, optional
|
||||
Plot information
|
||||
chain_file : str or Path, optional
|
||||
Path to the depletion chain XML file. Defaults to the chain
|
||||
found under the ``depletion_chain`` in the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable if it exists. If a
|
||||
str is provided it will be converted to a Path object.
|
||||
fission_q : dict, optional
|
||||
Dictionary of nuclides and their fission Q values [eV].
|
||||
If not given, values will be pulled from the ``chain_file``.
|
||||
intracomm : mpi4py.MPI.Intracomm or None, optional
|
||||
MPI intracommunicator
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
|
@ -61,19 +67,13 @@ class Model:
|
|||
Tallies information
|
||||
plots : openmc.Plots
|
||||
Plot information
|
||||
chain_file : str or Path
|
||||
Path to the depletion chain XML file. Defaults to the chain
|
||||
found under the ``depletion_chain`` in the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable if it exists. If a
|
||||
str is provided it will be converted to a Path object.
|
||||
fission_q : dict
|
||||
Dictionary of nuclides and their fission Q values [eV].
|
||||
If not given, values will be pulled from the ``chain_file``.
|
||||
intracomm : mpi4py.MPI.Intracomm or None
|
||||
MPI intracommunicator
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, geometry=None, materials=None, settings=None,
|
||||
tallies=None, plots=None, chain_file=None, fission_q=None):
|
||||
tallies=None, plots=None, intracomm=None):
|
||||
self.geometry = openmc.Geometry()
|
||||
self.materials = openmc.Materials()
|
||||
self.settings = openmc.Settings()
|
||||
|
|
@ -91,18 +91,33 @@ class Model:
|
|||
if plots is not None:
|
||||
self.plots = plots
|
||||
|
||||
self.chain_file = chain_file
|
||||
self.fission_q = fission_q
|
||||
self.intracomm = intracomm
|
||||
|
||||
# Store dictionaries to the materials and cells by ID and names
|
||||
if materials is None:
|
||||
mats = self.geometry.get_all_materials().values()
|
||||
else:
|
||||
mats = self.materials
|
||||
self._materials_by_id = {mat.id: mat for mat in mats}
|
||||
self._materials_by_name = {mat.name: mat for mat in mats}
|
||||
cells = self.geometry.get_all_cells()
|
||||
# Get the ID maps
|
||||
self._materials_by_id = {mat.id: mat for mat in mats}
|
||||
self._cells_by_id = {cell.id: cell for cell in cells.values()}
|
||||
self._cells_by_name = {cell.name: cell for cell in cells.values()}
|
||||
|
||||
# Get the names maps, but since names are not unique, store a list for
|
||||
# each name key. In this way when the user requests a change by a name,
|
||||
# the change will be applied to all of the same name.
|
||||
self._cells_by_name = {}
|
||||
for cell in cells.values():
|
||||
if cell.name not in self._cells_by_name:
|
||||
self._cells_by_name[cell.name] = [cell]
|
||||
else:
|
||||
self._cells_by_name[cell.name].append(cell)
|
||||
self._materials_by_name = {}
|
||||
for mat in mats:
|
||||
if mat.name not in self._materials_by_name:
|
||||
self._materials_by_name[mat.name] = [mat]
|
||||
else:
|
||||
self._materials_by_name[mat.name].append(mat)
|
||||
|
||||
@property
|
||||
def geometry(self):
|
||||
|
|
@ -125,16 +140,14 @@ class Model:
|
|||
return self._plots
|
||||
|
||||
@property
|
||||
def chain_file(self):
|
||||
return self._chain_file
|
||||
def intracomm(self):
|
||||
return self._intracomm
|
||||
|
||||
@property
|
||||
def fission_q(self):
|
||||
return self._fission_q
|
||||
|
||||
@property
|
||||
def C_init(self):
|
||||
return openmc.lib.LIB_INIT
|
||||
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
|
||||
def geometry(self, geometry):
|
||||
|
|
@ -176,20 +189,20 @@ class Model:
|
|||
for plot in plots:
|
||||
self._plots.append(plot)
|
||||
|
||||
@chain_file.setter
|
||||
def chain_file(self, chain_file):
|
||||
check_type('chain_file', chain_file, (type(None), str, Path))
|
||||
if isinstance(chain_file, str):
|
||||
self._chain_file = Path(chain_file).resolve()
|
||||
elif isinstance(chain_file, Path):
|
||||
self._chain_file = chain_file.resolve()
|
||||
@intracomm.setter
|
||||
def intracomm(self, intracomm):
|
||||
try:
|
||||
from mpi4py import MPI
|
||||
mpi_avail = True
|
||||
except ImportError:
|
||||
mpi_avail = False
|
||||
if intracomm is None or not mpi_avail:
|
||||
# TODO: move dummy_comm from openmc.deplete to openmc
|
||||
from openmc.deplete.dummy_comm import DummyCommunicator
|
||||
self._intracomm = DummyCommunicator()
|
||||
else:
|
||||
self._chain_file = None
|
||||
|
||||
@fission_q.setter
|
||||
def fission_q(self, fission_q):
|
||||
check_type('fission_q', fission_q, (type(None), dict))
|
||||
self._fission_q = fission_q
|
||||
check_type('intracomm', intracomm, MPI.Comm)
|
||||
self._intracomm = intracomm
|
||||
|
||||
@classmethod
|
||||
def from_xml(cls, geometry='geometry.xml', materials='materials.xml',
|
||||
|
|
@ -218,17 +231,20 @@ class Model:
|
|||
settings = openmc.Settings.from_xml(settings)
|
||||
return cls(geometry, materials, settings)
|
||||
|
||||
def init_C_api(self, threads=None, geometry_debug=False, restart_file=None,
|
||||
tracks=False, output=True, event_based=False):
|
||||
"""Initializes the model in memory via the C-API
|
||||
def init_lib(self, threads=None, geometry_debug=False, restart_file=None,
|
||||
tracks=False, output=True, event_based=False):
|
||||
"""Initializes the model in memory via the C API
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
threads : int, optional
|
||||
Number of OpenMP threads. If OpenMC is compiled with OpenMP threading
|
||||
enabled, the default is implementation-dependent but is usually equal to
|
||||
the number of hardware threads available (or a value set by the
|
||||
:envvar:`OMP_NUM_THREADS` environment variable).
|
||||
Number of OpenMP threads. If OpenMC is compiled with OpenMP
|
||||
threading enabled, the default is implementation-dependent but is
|
||||
usually equal to the number of hardware threads available
|
||||
(or a value set by the :envvar:`OMP_NUM_THREADS` environment
|
||||
variable).
|
||||
geometry_debug : bool, optional
|
||||
Turn on geometry debugging during simulation. Defaults to False.
|
||||
restart_file : str, optional
|
||||
|
|
@ -242,7 +258,7 @@ class Model:
|
|||
"""
|
||||
|
||||
# TODO: right now the only way to set most of the above parameters via
|
||||
# the C-API are at initialization time despite use-cases existing to
|
||||
# the C API are at initialization time despite use-cases existing to
|
||||
# set them for individual runs. For now this functionality is exposed
|
||||
# where it exists (here in init), but in the future the functionality
|
||||
# should be exposed so that it can be accessed via model.run(...)
|
||||
|
|
@ -267,42 +283,46 @@ class Model:
|
|||
if tracks:
|
||||
args.append('-t')
|
||||
|
||||
self.clear_C_api()
|
||||
self.finalize_lib()
|
||||
|
||||
if dep.comm.rank == 0:
|
||||
if self.intracomm.rank == 0:
|
||||
self.export_to_xml()
|
||||
dep.comm.barrier()
|
||||
self.intracomm.barrier()
|
||||
|
||||
openmc.lib.init(args=args, intracomm=dep.comm)
|
||||
openmc.lib.init(args=args, intracomm=self.intracomm)
|
||||
|
||||
def finalize_lib(self):
|
||||
"""Finalize simulation and free memory allocated for the C API
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
"""
|
||||
|
||||
def clear_C_api(self):
|
||||
"""Finalize simulation and free memory allocated for the C-API"""
|
||||
openmc.lib.finalize()
|
||||
|
||||
def deplete(self, timesteps, chain_file=None, method='cecm',
|
||||
fission_q=None, final_step=True, directory='.',
|
||||
**kwargs):
|
||||
def deplete(self, timesteps, method='cecm', final_step=True,
|
||||
operator_kwargs=None, integrator_kwargs=None, directory='.'):
|
||||
"""Deplete model using specified timesteps/power
|
||||
|
||||
.. versionchanged:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
timesteps : iterable of float
|
||||
Array of timesteps in units of [s]. Note that values are not
|
||||
cumulative.
|
||||
chain_file : str, optional
|
||||
Path to the depletion chain XML file. Defaults to the chain
|
||||
found under the ``depletion_chain`` in the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable if it exists.
|
||||
method : str, optional
|
||||
Integration method used for depletion (e.g., 'cecm', 'predictor').
|
||||
Defaults to 'cecm'.
|
||||
fission_q : dict, optional
|
||||
Dictionary of nuclides and their fission Q values [eV].
|
||||
If not given, values will be pulled from the ``chain_file``.
|
||||
Defaults to pulling from the ``chain_file``.
|
||||
final_step : bool, optional
|
||||
Indicate whether or not a transport solve should be run at the end
|
||||
of the last timestep. Defaults to running this transport solve.
|
||||
operator_kwargs : dict
|
||||
Keyword arguments passed to the depletion Operator initializer
|
||||
(e.g., :func:`openmc.deplete.Operator`)
|
||||
integrator_kwargs : dict
|
||||
Keyword arguments passed to the depletion Operator initializer
|
||||
(e.g., :func:`openmc.deplete.integrator.cecm`)
|
||||
directory : str, optional
|
||||
Directory to write XML files to. If it doesn't exist already, it
|
||||
will be created. Defaults to the current working directory
|
||||
|
|
@ -312,69 +332,43 @@ class Model:
|
|||
|
||||
"""
|
||||
|
||||
# To keep Model.deplete(...) API compatibility, we will allow the
|
||||
# chain_file and fission_q params to be set if provided while we set
|
||||
# the depletion operator
|
||||
if chain_file is not None:
|
||||
this_chain_file = Path(chain_file).resolve()
|
||||
warnings.warn("The chain_file argument of Model.deplete(...) "
|
||||
"has been deprecated and may be removed in a "
|
||||
"future version. The Model.chain_file should be"
|
||||
"used instead.", DeprecationWarning)
|
||||
else:
|
||||
this_chain_file = self.chain_file
|
||||
if fission_q is not None:
|
||||
warnings.warn("The fission_q argument of Model.deplete(...) "
|
||||
"has been deprecated and may be removed in a "
|
||||
"future version. The Model.fission_q should be"
|
||||
"used instead.", DeprecationWarning)
|
||||
this_fission_q = fission_q
|
||||
else:
|
||||
this_fission_q = fission_q
|
||||
# Import openmc.deplete here so the Model can be used even if the
|
||||
# shared library is unavailable.
|
||||
import openmc.deplete as dep
|
||||
|
||||
# Create directory if required
|
||||
d = Path(directory)
|
||||
if not d.is_dir():
|
||||
d.mkdir(parents=True)
|
||||
start_dir = Path.cwd()
|
||||
os.chdir(d)
|
||||
with _change_directory(Path(directory)):
|
||||
depletion_operator = \
|
||||
dep.Operator(self.geometry, self.settings, **operator_kwargs)
|
||||
# Tell depletion_operator.finalize NOT to clear C API memory when
|
||||
# it is done
|
||||
depletion_operator.cleanup_when_done = False
|
||||
|
||||
depletion_operator = \
|
||||
dep.Operator(self.geometry, self.settings,
|
||||
str(this_chain_file.absolute()),
|
||||
fission_q=this_fission_q)
|
||||
# Tell depletion_operator.finalize NOT to clear C-API memory when it is
|
||||
# done
|
||||
depletion_operator.cleanup_when_done = False
|
||||
# Set up the integrator
|
||||
check_value('method', method,
|
||||
dep.integrators.integrator_by_name.keys())
|
||||
integrator_class = dep.integrators.integrator_by_name[method]
|
||||
integrator = integrator_class(depletion_operator, timesteps,
|
||||
**integrator_kwargs)
|
||||
|
||||
# Set up the integrator
|
||||
integrator_class = dep.integrators.integrator_factory(method)
|
||||
integrator = integrator_class(depletion_operator,
|
||||
timesteps, **kwargs)
|
||||
# Now perform the depletion
|
||||
integrator.integrate(final_step)
|
||||
|
||||
# Now perform the depletion
|
||||
integrator.integrate(final_step)
|
||||
# If we did not perform a transport calculation on the final step,
|
||||
# then make the code update the C API material inventory
|
||||
if not final_step:
|
||||
depletion_operator._update_materials()
|
||||
|
||||
# If we did not perform a transport calculation on the final step, then
|
||||
# make the code update the C-API material inventory
|
||||
if not final_step:
|
||||
depletion_operator._update_materials()
|
||||
|
||||
# Now make the python Materials match the C-API material data
|
||||
for mat_id, mat in self._materials_by_id.items():
|
||||
if mat.depletable:
|
||||
# Get the C data
|
||||
c_mat = openmc.lib.materials[mat_id]
|
||||
nuclides, densities = c_mat._get_densities()
|
||||
# And now we can remove isotopes and add these ones in
|
||||
atom_density = 0.
|
||||
for nuc, density in zip(nuclides, densities):
|
||||
mat.remove_nuclide(nuc) # Replace if it's there
|
||||
mat.add_nuclide(nuc, density)
|
||||
atom_density += density
|
||||
mat.set_density('atom/b-cm', atom_density)
|
||||
|
||||
os.chdir(start_dir)
|
||||
# Now make the python Materials match the C API material data
|
||||
for mat_id, mat in self._materials_by_id.items():
|
||||
if mat.depletable:
|
||||
# Get the C data
|
||||
c_mat = openmc.lib.materials[mat_id]
|
||||
nuclides, densities = c_mat._get_densities()
|
||||
# And now we can remove isotopes and add these ones in
|
||||
mat.nuclides.clear()
|
||||
for nuc, density in zip(nuclides, densities):
|
||||
mat.add_nuclide(nuc, density)
|
||||
mat.set_density('atom/b-cm', sum(densities))
|
||||
|
||||
def export_to_xml(self, directory='.'):
|
||||
"""Export model to XML files.
|
||||
|
|
@ -412,8 +406,8 @@ class Model:
|
|||
def import_properties(self, filename):
|
||||
"""Import physical properties
|
||||
|
||||
.. versionchanged:: 0.12.3
|
||||
This method now updates values as loaded in memory with the C-API
|
||||
.. versionchanged:: 0.13.0
|
||||
This method now updates values as loaded in memory with the C API
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -443,9 +437,9 @@ class Model:
|
|||
cell = cells[cell_id]
|
||||
if cell.fill_type in ('material', 'distribmat'):
|
||||
cell.temperature = group['temperature'][()]
|
||||
if self.C_init:
|
||||
C_cell = openmc.lib.cells[cell_id]
|
||||
C_cell.set_temperature(group['temperature'][()])
|
||||
if self.is_initialized:
|
||||
lib_cell = openmc.lib.cells[cell_id]
|
||||
lib_cell.set_temperature(group['temperature'][()])
|
||||
|
||||
# Make sure number of materials matches
|
||||
mats_group = fh['materials']
|
||||
|
|
@ -459,14 +453,14 @@ class Model:
|
|||
mat_id = int(name.split()[1])
|
||||
atom_density = group.attrs['atom_density']
|
||||
materials[mat_id].set_density('atom/b-cm', atom_density)
|
||||
if self.C_init:
|
||||
if self.is_initialized:
|
||||
C_mat = openmc.lib.materials[mat_id]
|
||||
C_mat.set_density(atom_density, 'atom/b-cm')
|
||||
|
||||
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):
|
||||
"""Runs OpenMC. If the C-API has been initialized, then the C-API is
|
||||
"""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
|
||||
statepoint file generated.
|
||||
|
|
@ -475,8 +469,8 @@ class Model:
|
|||
Instead of returning the final k-effective value, this function now
|
||||
returns the path to the final statepoint written.
|
||||
|
||||
.. versionchanged:: 0.12.3
|
||||
This method can utilize the C-API for execution
|
||||
.. versionchanged:: 0.13.0
|
||||
This method can utilize the C API for execution
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -520,8 +514,8 @@ class Model:
|
|||
last_statepoint = None
|
||||
|
||||
# Operate in the provided working directory
|
||||
with openmc.change_directory(Path(cwd)):
|
||||
if self.C_init:
|
||||
with _change_directory(Path(cwd)):
|
||||
if self.is_initialized:
|
||||
# Handle the run options as applicable
|
||||
# First dont allow ones that must be set via init
|
||||
for arg_name, arg, default in zip(
|
||||
|
|
@ -529,8 +523,7 @@ class Model:
|
|||
[threads, geometry_debug, restart_file, tracks],
|
||||
[None, False, None, False]):
|
||||
if arg != default:
|
||||
msg = "{} must be set via Model.c_init(...)".format(
|
||||
arg_name)
|
||||
msg = f"{arg_name} must be set via Model.is_initialized(...)"
|
||||
raise ValueError(msg)
|
||||
|
||||
if particles is not None:
|
||||
|
|
@ -546,9 +539,9 @@ class Model:
|
|||
|
||||
# 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
|
||||
# TODO This will be dealt with in a future change to the C API
|
||||
|
||||
# Then run using the C-API
|
||||
# Then run using the C API
|
||||
openmc.lib.run()
|
||||
|
||||
# Reset changes for the openmc.run kwargs handling
|
||||
|
|
@ -577,12 +570,14 @@ class Model:
|
|||
last_statepoint = sp
|
||||
return last_statepoint
|
||||
|
||||
def calculate_volume(self, threads=None, output=True, cwd='.',
|
||||
openmc_exec='openmc', mpi_args=None,
|
||||
apply_volumes=True):
|
||||
def calculate_volumes(self, threads=None, output=True, cwd='.',
|
||||
openmc_exec='openmc', mpi_args=None,
|
||||
apply_volumes=True):
|
||||
"""Runs an OpenMC stochastic volume calculation and, if requested,
|
||||
applies volumes to the model
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
threads : int, optional
|
||||
|
|
@ -590,16 +585,16 @@ class Model:
|
|||
threading enabled, the default is implementation-dependent but is
|
||||
usually equal to the number of hardware threads available (or a
|
||||
value set by the :envvar:`OMP_NUM_THREADS` environment variable).
|
||||
This currenty only applies to the case when not using the C-API.
|
||||
This currenty only applies to the case when not using the C API.
|
||||
output : bool, optional
|
||||
Capture OpenMC output from standard out
|
||||
openmc_exec : str, optional
|
||||
Path to OpenMC executable. Defaults to 'openmc'.
|
||||
This only applies to the case when not using the C-API.
|
||||
This only applies to the case when not using the C API.
|
||||
mpi_args : list of str, optional
|
||||
MPI execute command and any additional MPI arguments to pass,
|
||||
e.g. ['mpiexec', '-n', '8'].
|
||||
This only applies to the case when not using the C-API.
|
||||
This only applies to the case when not using the C API.
|
||||
cwd : str, optional
|
||||
Path to working directory to run in. Defaults to the current
|
||||
working directory.
|
||||
|
|
@ -613,10 +608,10 @@ class Model:
|
|||
raise ValueError("The Settings.volume_calculation attribute must"
|
||||
" be specified before executing this method!")
|
||||
|
||||
with openmc.change_directory(Path(cwd)):
|
||||
if self.C_init:
|
||||
with _change_directory(Path(cwd)):
|
||||
if self.is_initialized:
|
||||
if threads is not None:
|
||||
msg = "Threads must be set via Model.c_init(...)"
|
||||
msg = "Threads must be set via Model.is_initialized(...)"
|
||||
raise ValueError(msg)
|
||||
if mpi_args is not None:
|
||||
msg = "The MPI environment must be set otherwise such as" \
|
||||
|
|
@ -645,7 +640,7 @@ class Model:
|
|||
if apply_volumes:
|
||||
# Load the results
|
||||
f_names = \
|
||||
["volume_{}.h5".format(i + 1)
|
||||
[f"volume_{i + 1}.h5"
|
||||
for i in range(len(self.settings.volume_calculations))]
|
||||
vol_calcs = [openmc.VolumeCalculation.load_results(f_name)
|
||||
for f_name in f_names]
|
||||
|
|
@ -654,9 +649,9 @@ class Model:
|
|||
# First add them to the Python side
|
||||
self.geometry.add_volume_information(vol_calc)
|
||||
|
||||
# And now repeat for the C-API
|
||||
# And now repeat for the C API
|
||||
if vol_calc.domain == 'material':
|
||||
# Then we can do this in the C-API
|
||||
# Then we can do this in the C API
|
||||
for domain_id in vol_calc.domains:
|
||||
self.update_material_volumes(
|
||||
[domain_id], vol_calc.volumes[domain_id])
|
||||
|
|
@ -670,6 +665,8 @@ class Model:
|
|||
`ImageMagick <https://www.imagemagick.org>`_ which includes a
|
||||
`convert` command.
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
output : bool, optional
|
||||
|
|
@ -679,7 +676,7 @@ class Model:
|
|||
working directory.
|
||||
openmc_exec : str, optional
|
||||
Path to OpenMC executable. Defaults to 'openmc'.
|
||||
This only applies to the case when not using the C-API.
|
||||
This only applies to the case when not using the C API.
|
||||
convert : bool, optional
|
||||
Whether or not to attempt to convert from PPM to PNG
|
||||
convert_exec : str, optional
|
||||
|
|
@ -691,14 +688,14 @@ class Model:
|
|||
raise ValueError("The Model.plots attribute must be specified "
|
||||
"before executing this method!")
|
||||
|
||||
with openmc.change_directory(Path(cwd)):
|
||||
# TODO: openmc_init doesnt read plots.xml unless it is in plot mode
|
||||
with _change_directory(Path(cwd)):
|
||||
# TODO: openmis_initialized doesnt read plots.xml unless it is in plot mode
|
||||
# so the following will not work. Commented out for now and
|
||||
# replacing with non-C-API code
|
||||
# replacing with non-C API code
|
||||
self.export_to_xml()
|
||||
openmc.plot_geometry(output=output, openmc_exec=openmc_exec)
|
||||
|
||||
# if self.C_init:
|
||||
# if self.is_initialized:
|
||||
# # Apply the output settings
|
||||
# if not output:
|
||||
# init_verbosity = openmc.lib.settings.verbosity
|
||||
|
|
@ -735,13 +732,13 @@ class Model:
|
|||
check_value('attrib_name', attrib_name,
|
||||
('temperature', 'volume', 'density', 'rotation',
|
||||
'translation'))
|
||||
# The C-API only allows setting density units of atom/b-cm and g/cm3
|
||||
# The C API only allows setting density units of atom/b-cm and g/cm3
|
||||
check_value('density_units', density_units, ('atom/b-cm', 'g/cm3'))
|
||||
# The C-API has no way to set cell volume so lets raise an exception
|
||||
# The C API has no way to set cell volume so lets raise an exception
|
||||
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
|
||||
# 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!')
|
||||
|
|
@ -756,62 +753,61 @@ class Model:
|
|||
if obj_type == 'cell':
|
||||
by_name = self._cells_by_name
|
||||
by_id = self._cells_by_id
|
||||
C_by_id = openmc.lib.cells
|
||||
obj_by_id = openmc.lib.cells
|
||||
else:
|
||||
by_name = self._materials_by_name
|
||||
by_id = self._materials_by_id
|
||||
C_by_id = openmc.lib.materials
|
||||
obj_by_id = openmc.lib.materials
|
||||
|
||||
# Get the list of ids to use if converting from names and accepting
|
||||
# only values that have actual ids
|
||||
ids = [None] * len(names_or_ids)
|
||||
for i, name_or_id in enumerate(names_or_ids):
|
||||
ids = []
|
||||
for name_or_id in names_or_ids:
|
||||
if isinstance(name_or_id, Integral):
|
||||
if name_or_id in by_id:
|
||||
ids[i] = int(name_or_id)
|
||||
ids.append(int(name_or_id))
|
||||
else:
|
||||
msg = '{} ID {} is not present in the model!'.format(
|
||||
obj_type.capitalize(), name_or_id)
|
||||
cap_obj = obj_type.capitalize()
|
||||
msg = f'{cap_obj} ID {name_or_id} " \
|
||||
"is not present in the model!'
|
||||
raise InvalidIDError(msg)
|
||||
elif isinstance(name_or_id, str):
|
||||
if name_or_id in by_name:
|
||||
ids[i] = by_name[name_or_id].id
|
||||
# Then by_name[name_or_id] is a list so we need to add all
|
||||
# entries
|
||||
ids.extend([obj.id for obj in by_name[name_or_id]])
|
||||
else:
|
||||
msg = '{} {} is not present in the model!'.format(
|
||||
obj_type.capitalize(), name_or_id)
|
||||
cap_obj = obj_type.capitalize()
|
||||
msg = f'{cap_obj} {name_or_id} " \
|
||||
"is not present in the model!'
|
||||
raise InvalidIDError(msg)
|
||||
|
||||
# Now perform the change to both python and C-API
|
||||
# Now perform the change to both python and C API
|
||||
for id_ in ids:
|
||||
obj = by_id[id_]
|
||||
if attrib_name == 'rotation':
|
||||
obj.rotation = value
|
||||
elif attrib_name == 'translation':
|
||||
obj.translation = value
|
||||
elif attrib_name == 'volume':
|
||||
obj.volume = value
|
||||
elif attrib_name == 'temperature':
|
||||
obj.temperature = value
|
||||
elif attrib_name == 'density':
|
||||
if attrib_name == 'density':
|
||||
obj.set_density(density_units, value)
|
||||
# Next lets keep what is in C-API memory up to date as well
|
||||
if self.C_init:
|
||||
C_obj = C_by_id[id_]
|
||||
if attrib_name == 'rotation':
|
||||
C_obj.rotation = value
|
||||
elif attrib_name == 'translation':
|
||||
C_obj.translation = value
|
||||
elif attrib_name == 'volume':
|
||||
C_obj.volume = value
|
||||
elif attrib_name == 'temperature':
|
||||
C_obj.set_temperature(value)
|
||||
else:
|
||||
setattr(obj, attrib_name, value)
|
||||
# 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':
|
||||
C_obj.set_density(value, density_units)
|
||||
lib_obj.set_density(value, density_units)
|
||||
else:
|
||||
setattr(lib_obj, attrib_name, value)
|
||||
|
||||
def rotate_cells(self, names_or_ids, vector):
|
||||
"""Rotate the identified cell(s) by the specified rotation vector.
|
||||
The rotation is only applied to cells filled with a universe.
|
||||
|
||||
.. note:: If applying this change to a name that is not unique, then
|
||||
the change will be applied to all objects of that name.
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names_or_ids : Iterable of str or int
|
||||
|
|
@ -829,6 +825,11 @@ class Model:
|
|||
"""Translate the identified cell(s) by the specified translation vector.
|
||||
The translation is only applied to cells filled with a universe.
|
||||
|
||||
.. note:: If applying this change to a name that is not unique, then
|
||||
the change will be applied to all objects of that name.
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names_or_ids : Iterable of str or int
|
||||
|
|
@ -845,6 +846,11 @@ class Model:
|
|||
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
|
||||
|
||||
.. note:: If applying this change to a name that is not unique, then
|
||||
the change will be applied to all objects of that name.
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names_or_ids : Iterable of str or int
|
||||
|
|
@ -863,6 +869,11 @@ class Model:
|
|||
def update_cell_temperatures(self, names_or_ids, temperature):
|
||||
"""Update the temperature of a set of cells to the given value
|
||||
|
||||
.. note:: If applying this change to a name that is not unique, then
|
||||
the change will be applied to all objects of that name.
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names_or_ids : Iterable of str or int
|
||||
|
|
@ -879,6 +890,11 @@ class Model:
|
|||
def update_material_temperatures(self, names_or_ids, temperature):
|
||||
"""Update the temperature of a set of materials to the given value
|
||||
|
||||
.. note:: If applying this change to a name that is not unique, then
|
||||
the change will be applied to all objects of that name.
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names_or_ids : Iterable of str or int
|
||||
|
|
@ -895,6 +911,11 @@ class Model:
|
|||
def update_material_volumes(self, names_or_ids, volume):
|
||||
"""Update the volume of a set of materials to the given value
|
||||
|
||||
.. note:: If applying this change to a name that is not unique, then
|
||||
the change will be applied to all objects of that name.
|
||||
|
||||
.. versionadded:: 0.13.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names_or_ids : Iterable of str or int
|
||||
|
|
|
|||
|
|
@ -129,9 +129,9 @@ def pin_model_attributes():
|
|||
</nuclide>
|
||||
</depletion_chain>
|
||||
"""
|
||||
operator_kwargs = {'chain_file': chain, 'fission_q': fission_q}
|
||||
|
||||
return (mats, geom, settings, tals, plots, chain, fission_q,
|
||||
chain_file_xml)
|
||||
return (mats, geom, settings, tals, plots, operator_kwargs, chain_file_xml)
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def mpi_intracomm():
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ from pathlib import Path
|
|||
from shutil import which
|
||||
import openmc
|
||||
import openmc.lib
|
||||
from openmc.deplete.dummy_comm import DummyCommunicator
|
||||
|
||||
|
||||
def test_init(run_in_tmpdir, pin_model_attributes):
|
||||
mats, geom, settings, tals, plots, chain, fission_q, _ = \
|
||||
def test_init(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _ = \
|
||||
pin_model_attributes
|
||||
|
||||
openmc.reset_auto_ids()
|
||||
|
|
@ -22,29 +23,25 @@ def test_init(run_in_tmpdir, pin_model_attributes):
|
|||
assert test_model.settings.__dict__[ref_k] == ref_v
|
||||
assert len(test_model.tallies) == 0
|
||||
assert len(test_model.plots) == 0
|
||||
assert test_model.chain_file is None
|
||||
assert test_model.fission_q is None
|
||||
assert test_model._materials_by_id == {}
|
||||
assert test_model._materials_by_name == {}
|
||||
assert test_model._cells_by_id == {}
|
||||
assert test_model._cells_by_name == {}
|
||||
assert test_model.C_init is False
|
||||
assert test_model.is_initialized is False
|
||||
assert isinstance(test_model.intracomm, DummyCommunicator)
|
||||
|
||||
# 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, chain,
|
||||
fission_q)
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
assert test_model.geometry is geom
|
||||
assert test_model.materials is mats
|
||||
assert test_model.settings is settings
|
||||
assert test_model.tallies is tals
|
||||
assert test_model.plots is plots
|
||||
assert test_model.chain_file == Path(chain).resolve()
|
||||
assert test_model.fission_q is fission_q
|
||||
assert test_model._materials_by_id == {1: mats[0], 2: mats[1], 3: mats[2]}
|
||||
assert test_model._materials_by_name == {'UO2': mats[0], 'Zirc': mats[1],
|
||||
'Borated water': mats[2]}
|
||||
assert test_model._materials_by_name == {
|
||||
'UO2': [mats[0]], 'Zirc': [mats[1]], 'Borated water': [mats[2]]}
|
||||
# The last cell is the one that contains the infinite fuel
|
||||
assert test_model._cells_by_id == \
|
||||
{2: geom.root_universe.cells[2], 3: geom.root_universe.cells[3],
|
||||
|
|
@ -53,13 +50,21 @@ def test_init(run_in_tmpdir, pin_model_attributes):
|
|||
# No cell name for 2 and 3, so we expect a blank name to be assigned to
|
||||
# cell 3 due to overwriting
|
||||
assert test_model._cells_by_name == {
|
||||
'fuel': geom.root_universe.cells[2], '': geom.root_universe.cells[4],
|
||||
'inf fuel': geom.root_universe.cells[2].fill.cells[1]}
|
||||
assert test_model.C_init is False
|
||||
'fuel': [geom.root_universe.cells[2]],
|
||||
'': [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
|
||||
def_params = [geom, mats, settings, tals, plots, chain, fission_q]
|
||||
if mpi_intracomm is not None:
|
||||
def_params = [geom, mats, settings, tals, plots, mpi_intracomm]
|
||||
else:
|
||||
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
|
||||
|
|
@ -69,7 +74,7 @@ def test_init(run_in_tmpdir, pin_model_attributes):
|
|||
|
||||
|
||||
def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
||||
mats, geom, settings, tals, plots, _, _, _ = pin_model_attributes
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
|
||||
# This test will write the individual files to xml and then init that way
|
||||
# and run the same sort of test as in test_init
|
||||
|
|
@ -99,14 +104,12 @@ def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
|||
assert test_model.settings.__dict__[ref_k] == settings.__dict__[ref_k]
|
||||
assert len(test_model.tallies) == 0
|
||||
assert len(test_model.plots) == 0
|
||||
assert test_model.chain_file is None
|
||||
assert test_model.fission_q is None
|
||||
assert test_model._materials_by_id == \
|
||||
{1: test_model.materials[0], 2: test_model.materials[1],
|
||||
3: test_model.materials[2]}
|
||||
assert test_model._materials_by_name == {
|
||||
'UO2': test_model.materials[0], 'Zirc': test_model.materials[1],
|
||||
'Borated water': test_model.materials[2]}
|
||||
'UO2': [test_model.materials[0]], 'Zirc': [test_model.materials[1]],
|
||||
'Borated water': [test_model.materials[2]]}
|
||||
assert test_model._cells_by_id == {
|
||||
2: test_model.geometry.root_universe.cells[2],
|
||||
3: test_model.geometry.root_universe.cells[3],
|
||||
|
|
@ -115,28 +118,23 @@ def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
|||
# No cell name for 2 and 3, so we expect a blank name to be assigned to
|
||||
# cell 3 due to overwriting
|
||||
assert test_model._cells_by_name == {
|
||||
'fuel': test_model.geometry.root_universe.cells[2],
|
||||
'': test_model.geometry.root_universe.cells[4],
|
||||
'inf fuel': test_model.geometry.root_universe.cells[2].fill.cells[1]}
|
||||
assert test_model.C_init is False
|
||||
'fuel': [test_model.geometry.root_universe.cells[2]],
|
||||
'': [test_model.geometry.root_universe.cells[3],
|
||||
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_clear_C_api(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
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)
|
||||
# Set the depletion module to use the test intracomm as the depletion mods
|
||||
# intracomm is the one that init uses. We will not perturb system state
|
||||
# outside of this test by re-setting the openmc.deplete.comm to what it was
|
||||
# before when we exist
|
||||
if mpi_intracomm is not None:
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
test_model.init_C_api()
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
test_model.init_lib()
|
||||
|
||||
# First check that the API is advertised as initialized
|
||||
assert openmc.lib.LIB_INIT is True
|
||||
assert test_model.C_init is True
|
||||
assert openmc.lib.is_initialized is True
|
||||
assert test_model.is_initialized is True
|
||||
# Now make sure it actually is initialized by making a call to the lib
|
||||
c_mat = openmc.lib.find_material((0.6, 0., 0.))
|
||||
# This should be Borated water
|
||||
|
|
@ -144,20 +142,14 @@ def test_init_clear_C_api(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
assert c_mat.id == 3
|
||||
|
||||
# Ok, now lets test that we can clear the data and check that it is cleared
|
||||
test_model.clear_C_api()
|
||||
test_model.finalize_lib()
|
||||
|
||||
# First check that the API is advertised as initialized
|
||||
assert openmc.lib.LIB_INIT is False
|
||||
assert test_model.C_init is False
|
||||
assert openmc.lib.is_initialized is False
|
||||
assert test_model.is_initialized is False
|
||||
# Note we cant actually test that a sys call fails because we should get a
|
||||
# seg fault
|
||||
|
||||
# And before done, reset the deplete communicator
|
||||
if mpi_intracomm is not None:
|
||||
openmc.deplete.comm = orig_comm
|
||||
|
||||
# TODO: in above test, tests are necessary for all the arguments of init
|
||||
|
||||
|
||||
def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
||||
"""Test importing properties on the Model class """
|
||||
|
|
@ -165,7 +157,7 @@ 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()
|
||||
model.init_C_api()
|
||||
model.init_lib()
|
||||
|
||||
# Change fuel temperature and density and export properties
|
||||
cell = openmc.lib.cells[1]
|
||||
|
|
@ -185,7 +177,7 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
assert openmc.lib.cells[1].get_temperature() == 600.
|
||||
assert openmc.lib.materials[1].get_density('g/cm3') == pytest.approx(5.0)
|
||||
|
||||
# Clear the C-API
|
||||
# Clear the C API
|
||||
openmc.lib.finalize()
|
||||
|
||||
# Verify the attributes survived by exporting to XML and re-creating
|
||||
|
|
@ -203,24 +195,17 @@ 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)
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, 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.
|
||||
# C API execution modes and ensuring they give the same result.
|
||||
sp_path = test_model.run(output=False)
|
||||
with openmc.StatePoint(sp_path) as sp:
|
||||
cli_keff = sp.k_combined
|
||||
cli_flux = sp.get_tally(id=1).get_values()[0, 0, 0]
|
||||
|
||||
if mpi_intracomm is not None:
|
||||
# Set the depletion module to use the test intracomm as the depletion
|
||||
# module's intracomm is the one that init uses. We will not perturb
|
||||
# system state outside of this test by re-setting the
|
||||
# openmc.deplete.comm to what it was before when we exist
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
test_model.init_C_api()
|
||||
test_model.init_lib()
|
||||
sp_path = test_model.run(output=False)
|
||||
with openmc.StatePoint(sp_path) as sp:
|
||||
C_keff = sp.k_combined
|
||||
|
|
@ -241,24 +226,12 @@ def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
with pytest.raises(ValueError):
|
||||
test_model.run(tracks=True)
|
||||
|
||||
test_model.clear_C_api()
|
||||
|
||||
# And before done, reset the deplete communicator
|
||||
if mpi_intracomm is not None:
|
||||
openmc.deplete.comm = orig_comm
|
||||
test_model.finalize_lib()
|
||||
|
||||
|
||||
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)
|
||||
|
||||
if mpi_intracomm is not None:
|
||||
# Set the depletion module to use the test intracomm as the depletion
|
||||
# module's intracomm is the one that init uses. We will not perturb
|
||||
# system state outside of this test by re-setting the
|
||||
# openmc.deplete.comm to what it was before when we exist
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, 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
|
||||
|
|
@ -272,10 +245,10 @@ def test_plots(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
else:
|
||||
exts = ['ppm']
|
||||
|
||||
# We will run the test twice, the first time without C-API, the second with
|
||||
# We will run the test twice, the first time without C API, the second with
|
||||
for i in range(2):
|
||||
if i == 1:
|
||||
test_model.init_C_api()
|
||||
test_model.init_lib()
|
||||
test_model.plot_geometry(output=True, convert=convert)
|
||||
|
||||
# Now look for the files, expect to find test.ppm, plot_2.ppm, and if
|
||||
|
|
@ -286,25 +259,14 @@ def test_plots(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
assert test_file.exists()
|
||||
test_file.unlink()
|
||||
|
||||
test_model.clear_C_api()
|
||||
|
||||
# And before done, reset the deplete communicator
|
||||
if mpi_intracomm is not None:
|
||||
openmc.deplete.comm = orig_comm
|
||||
test_model.finalize_lib()
|
||||
|
||||
|
||||
def test_py_C_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)
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots, mpi_intracomm)
|
||||
|
||||
if mpi_intracomm is not None:
|
||||
# Set the depletion module to use the test intracomm as the depletion
|
||||
# module's intracomm is the one that init uses. We will not perturb
|
||||
# system state outside of this test by re-setting the
|
||||
# openmc.deplete.comm to what it was before when we exist
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
test_model.init_C_api()
|
||||
test_model.init_lib()
|
||||
|
||||
# Now we can call rotate_cells, translate_cells, update_densities,
|
||||
# update_cell_temperatures, and update_material_temperatures and make sure
|
||||
|
|
@ -376,7 +338,7 @@ def test_py_C_attributes(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
# 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
|
||||
# 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
|
||||
|
|
@ -395,8 +357,4 @@ def test_py_C_attributes(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
assert abs(openmc.lib.materials[1].volume - 2.) < 1e-13
|
||||
assert abs(test_model.materials[0].volume - 2.) < 1e-13
|
||||
|
||||
test_model.clear_C_api()
|
||||
|
||||
# And before done, reset the deplete communicator
|
||||
if mpi_intracomm is not None:
|
||||
openmc.deplete.comm = orig_comm
|
||||
test_model.finalize_lib()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue