mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 06:05:58 -04:00
Merge pull request #1312 from drewejohnson/bug-restart-mpi
Distribute reaction rates and densities when restarting under MPI
This commit is contained in:
commit
f5c421d24e
16 changed files with 102 additions and 46 deletions
|
|
@ -24,6 +24,7 @@ from . import comm
|
|||
from .abc import TransportOperator, OperatorResult
|
||||
from .atom_number import AtomNumber
|
||||
from .reaction_rates import ReactionRates
|
||||
from .results_list import ResultsList
|
||||
from .helpers import DirectReactionRateHelper, ChainFissionHelper
|
||||
|
||||
|
||||
|
|
@ -73,7 +74,8 @@ class Operator(TransportOperator):
|
|||
specified, the depletion calculation will start from the latest state
|
||||
in the previous results.
|
||||
diff_burnable_mats : bool, optional
|
||||
Whether to differentiate burnable materials with multiple instances
|
||||
Whether to differentiate burnable materials with multiple instances.
|
||||
Default: False.
|
||||
fission_q : dict, optional
|
||||
Dictionary of nuclides and their fission Q values [eV]. If not given,
|
||||
values will be pulled from the ``chain_file``.
|
||||
|
|
@ -123,14 +125,11 @@ class Operator(TransportOperator):
|
|||
dilute_initial=1.0e3):
|
||||
super().__init__(chain_file, fission_q, dilute_initial, prev_results)
|
||||
self.round_number = False
|
||||
self.prev_res = None
|
||||
self.settings = settings
|
||||
self.geometry = geometry
|
||||
self.diff_burnable_mats = diff_burnable_mats
|
||||
|
||||
if self.prev_res is not None:
|
||||
# Reload volumes into geometry
|
||||
self.prev_results[-1].transfer_volumes(geometry)
|
||||
|
||||
# Differentiate burnable materials with multiple instances
|
||||
if self.diff_burnable_mats:
|
||||
self._differentiate_burnable_mats()
|
||||
|
|
@ -144,6 +143,21 @@ class Operator(TransportOperator):
|
|||
self._mat_index_map = {
|
||||
lm: self.burnable_mats.index(lm) for lm in self.local_mats}
|
||||
|
||||
if self.prev_res is not None:
|
||||
# Reload volumes into geometry
|
||||
prev_results[-1].transfer_volumes(geometry)
|
||||
|
||||
# Store previous results in operator
|
||||
# Distribute reaction rates according to those tracked
|
||||
# on this process
|
||||
if comm.size == 1:
|
||||
self.prev_res = prev_results
|
||||
else:
|
||||
self.prev_res = ResultsList()
|
||||
mat_indexes = _distribute(range(len(self.burnable_mats)))
|
||||
for res_obj in prev_results:
|
||||
new_res = res_obj.distribute(self.local_mats, mat_indexes)
|
||||
self.prev_res.append(new_res)
|
||||
|
||||
# Determine which nuclides have incident neutron data
|
||||
self.nuclides_with_data = self._get_nuclides_with_data()
|
||||
|
|
|
|||
|
|
@ -153,6 +153,37 @@ class Results(object):
|
|||
# Create storage array
|
||||
self.data = np.zeros((stages, self.n_mat, self.n_nuc))
|
||||
|
||||
def distribute(self, local_materials, ranges):
|
||||
"""Create a new object containing data for distributed materials
|
||||
|
||||
Parameters
|
||||
----------
|
||||
local_materials : iterable of str
|
||||
Materials for this process
|
||||
ranges : iterable of int
|
||||
Slice-like object indicating indicies of ``local_materials``
|
||||
in the material dimension of :attr:`data` and each element
|
||||
in :attr:`rates`
|
||||
|
||||
Returns
|
||||
-------
|
||||
Results
|
||||
New results object
|
||||
"""
|
||||
new = Results()
|
||||
new.volume = {lm: self.volume[lm] for lm in local_materials}
|
||||
new.mat_to_ind = dict(zip(
|
||||
local_materials, range(len(local_materials))))
|
||||
# Direct transfer
|
||||
direct_attrs = ("time", "k", "power", "nuc_to_ind",
|
||||
"mat_to_hdf5_ind", "proc_time")
|
||||
for attr in direct_attrs:
|
||||
setattr(new, attr, getattr(self, attr))
|
||||
# Get applicable slice of data
|
||||
new.data = self.data[:, ranges]
|
||||
new.rates = [r[ranges] for r in self.rates]
|
||||
return new
|
||||
|
||||
def export_to_hdf5(self, filename, step):
|
||||
"""Export results to an HDF5 file
|
||||
|
||||
|
|
|
|||
|
|
@ -8,22 +8,34 @@ from openmc.checkvalue import check_filetype_version
|
|||
class ResultsList(list):
|
||||
"""A list of openmc.deplete.Results objects
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
The filename to read from.
|
||||
|
||||
It is recommended to use :meth:`from_hdf5` over
|
||||
direct creation.
|
||||
"""
|
||||
def __init__(self, filename):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def from_hdf5(cls, filename):
|
||||
"""Load in depletion results from a previous file
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Path to depletion result file
|
||||
|
||||
Returns
|
||||
-------
|
||||
new : ResultsList
|
||||
New instance of depletion results
|
||||
"""
|
||||
with h5py.File(str(filename), "r") as fh:
|
||||
check_filetype_version(fh, 'depletion results', _VERSION_RESULTS[0])
|
||||
new = cls()
|
||||
|
||||
# Get number of results stored
|
||||
n = fh["number"][...].shape[0]
|
||||
|
||||
for i in range(n):
|
||||
self.append(Results.from_hdf5(fh, i))
|
||||
new.append(Results.from_hdf5(fh, i))
|
||||
return new
|
||||
|
||||
def get_atoms(self, mat, nuc):
|
||||
"""Get number of nuclides over time from a single material
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ def test_full(run_in_tmpdir):
|
|||
return
|
||||
|
||||
# Load the reference/test results
|
||||
res_test = openmc.deplete.ResultsList(path_test)
|
||||
res_ref = openmc.deplete.ResultsList(path_reference)
|
||||
res_test = openmc.deplete.ResultsList.from_hdf5(path_test)
|
||||
res_ref = openmc.deplete.ResultsList.from_hdf5(path_reference)
|
||||
|
||||
# Assert same mats
|
||||
for mat in res_ref[0].mat_to_ind:
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ These tests integrate a simple test problem described in dummy_geometry.py.
|
|||
"""
|
||||
|
||||
from pytest import approx
|
||||
import openmc.deplete
|
||||
from openmc.deplete import CECMIntegrator
|
||||
from openmc.deplete import CECMIntegrator, ResultsList
|
||||
|
||||
from tests import dummy_operator
|
||||
|
||||
|
|
@ -23,7 +22,7 @@ def test_cecm(run_in_tmpdir):
|
|||
integrator.integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def test_celi(run_in_tmpdir):
|
|||
CELIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def test_cf4(run_in_tmpdir):
|
|||
CF4Integrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def test_epc_rk4(run_in_tmpdir):
|
|||
EPCRK4Integrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ def test_results_save(run_in_tmpdir):
|
|||
Results.save(op, x2, op_result2, t2, 0, 1)
|
||||
|
||||
# Load the files
|
||||
res = ResultsList("depletion_results.h5")
|
||||
res = ResultsList.from_hdf5("depletion_results.h5")
|
||||
|
||||
for i in range(stages):
|
||||
for mat_i, mat in enumerate(burn_list):
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def test_leqi(run_in_tmpdir):
|
|||
LEQIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ def test_predictor(run_in_tmpdir):
|
|||
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def test_restart_predictor(run_in_tmpdir):
|
|||
PredictorIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -37,7 +37,7 @@ def test_restart_predictor(run_in_tmpdir):
|
|||
PredictorIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
@ -67,7 +67,7 @@ def test_restart_cecm(run_in_tmpdir):
|
|||
cecm.integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -78,7 +78,7 @@ def test_restart_cecm(run_in_tmpdir):
|
|||
cecm_restart.integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
@ -107,7 +107,7 @@ def test_restart_predictor_cecm(run_in_tmpdir):
|
|||
PredictorIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -133,7 +133,7 @@ def test_restart_cecm_predictor(run_in_tmpdir):
|
|||
cecm.integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -156,7 +156,7 @@ def test_restart_cf4(run_in_tmpdir):
|
|||
CF4Integrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -166,7 +166,7 @@ def test_restart_cf4(run_in_tmpdir):
|
|||
CF4Integrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
@ -195,7 +195,7 @@ def test_restart_epc_rk4(run_in_tmpdir):
|
|||
EPCRK4Integrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -205,7 +205,7 @@ def test_restart_epc_rk4(run_in_tmpdir):
|
|||
EPCRK4Integrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
@ -234,7 +234,7 @@ def test_restart_celi(run_in_tmpdir):
|
|||
CELIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -244,7 +244,7 @@ def test_restart_celi(run_in_tmpdir):
|
|||
CELIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
@ -273,7 +273,7 @@ def test_restart_leqi(run_in_tmpdir):
|
|||
LEQIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -283,7 +283,7 @@ def test_restart_leqi(run_in_tmpdir):
|
|||
LEQIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
@ -311,7 +311,7 @@ def test_restart_si_celi(run_in_tmpdir):
|
|||
SICELIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -321,7 +321,7 @@ def test_restart_si_celi(run_in_tmpdir):
|
|||
SICELIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
@ -351,7 +351,7 @@ def test_restart_si_leqi(run_in_tmpdir):
|
|||
SILEQIIntegrator(op, dt, power, nstages).integrate()
|
||||
|
||||
# Load the files
|
||||
prev_res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
prev_res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Re-create depletion operator and load previous results
|
||||
op = dummy_operator.DummyOperator(prev_res)
|
||||
|
|
@ -361,7 +361,7 @@ def test_restart_si_leqi(run_in_tmpdir):
|
|||
SILEQIIntegrator(op, dt, power, nstages).integrate()
|
||||
|
||||
# Load the files
|
||||
res = openmc.deplete.ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ def res():
|
|||
"""Load the reference results"""
|
||||
filename = (Path(__file__).parents[1] / 'regression_tests' / 'deplete'
|
||||
/ 'test_reference.h5')
|
||||
return openmc.deplete.ResultsList(filename)
|
||||
return openmc.deplete.ResultsList.from_hdf5(filename)
|
||||
|
||||
|
||||
def test_get_atoms(res):
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def test_si_celi(run_in_tmpdir):
|
|||
SICELIIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def test_si_leqi(run_in_tmpdir):
|
|||
SILEQIIntegrator(op, dt, power, 10).integrate()
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
_, y1 = res.get_atoms("1", "1")
|
||||
_, y2 = res.get_atoms("1", "2")
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ def test_transfer_volumes(run_in_tmpdir):
|
|||
PredictorIntegrator(op, dt, power).integrate()
|
||||
|
||||
# Load the files
|
||||
res = ResultsList(op.output_dir / "depletion_results.h5")
|
||||
res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5")
|
||||
|
||||
# Create a dictionary of volumes to transfer
|
||||
res[0].volume['1'] = 1.5
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue