Merge pull request #1312 from drewejohnson/bug-restart-mpi

Distribute reaction rates and densities when restarting under MPI
This commit is contained in:
Paul Romano 2019-08-07 16:46:31 -05:00 committed by GitHub
commit f5c421d24e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 102 additions and 46 deletions

View file

@ -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()

View file

@ -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

View 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

View file

@ -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:

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -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):

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -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):

View file

@ -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")

View file

@ -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")

View file

@ -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