diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index b845faad9d..f8288841f7 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -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() diff --git a/openmc/deplete/results.py b/openmc/deplete/results.py index 2b5bde0e57..6593d5fc5f 100644 --- a/openmc/deplete/results.py +++ b/openmc/deplete/results.py @@ -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 diff --git a/openmc/deplete/results_list.py b/openmc/deplete/results_list.py index 0ce5b01584..3b5166ed8a 100644 --- a/openmc/deplete/results_list.py +++ b/openmc/deplete/results_list.py @@ -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 diff --git a/tests/regression_tests/deplete/test.py b/tests/regression_tests/deplete/test.py index 59eca4a545..c7a9c162e0 100644 --- a/tests/regression_tests/deplete/test.py +++ b/tests/regression_tests/deplete/test.py @@ -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: diff --git a/tests/unit_tests/test_deplete_cecm.py b/tests/unit_tests/test_deplete_cecm.py index 8ad1ec95ea..65dd61643b 100644 --- a/tests/unit_tests/test_deplete_cecm.py +++ b/tests/unit_tests/test_deplete_cecm.py @@ -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") diff --git a/tests/unit_tests/test_deplete_celi.py b/tests/unit_tests/test_deplete_celi.py index 570ebe151d..01ec60d372 100644 --- a/tests/unit_tests/test_deplete_celi.py +++ b/tests/unit_tests/test_deplete_celi.py @@ -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") diff --git a/tests/unit_tests/test_deplete_cf4.py b/tests/unit_tests/test_deplete_cf4.py index eb3d8a0bc4..817dfb5e17 100644 --- a/tests/unit_tests/test_deplete_cf4.py +++ b/tests/unit_tests/test_deplete_cf4.py @@ -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") diff --git a/tests/unit_tests/test_deplete_epc_rk4.py b/tests/unit_tests/test_deplete_epc_rk4.py index 8f1160164b..0c656d7dbe 100644 --- a/tests/unit_tests/test_deplete_epc_rk4.py +++ b/tests/unit_tests/test_deplete_epc_rk4.py @@ -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") diff --git a/tests/unit_tests/test_deplete_integrator.py b/tests/unit_tests/test_deplete_integrator.py index 302ec28d73..fd4e2ba3ff 100644 --- a/tests/unit_tests/test_deplete_integrator.py +++ b/tests/unit_tests/test_deplete_integrator.py @@ -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): diff --git a/tests/unit_tests/test_deplete_leqi.py b/tests/unit_tests/test_deplete_leqi.py index 0ab4350f6e..113cb6e306 100644 --- a/tests/unit_tests/test_deplete_leqi.py +++ b/tests/unit_tests/test_deplete_leqi.py @@ -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") diff --git a/tests/unit_tests/test_deplete_predictor.py b/tests/unit_tests/test_deplete_predictor.py index e212f46514..38bee86c39 100644 --- a/tests/unit_tests/test_deplete_predictor.py +++ b/tests/unit_tests/test_deplete_predictor.py @@ -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") diff --git a/tests/unit_tests/test_deplete_restart.py b/tests/unit_tests/test_deplete_restart.py index 912f7e301e..c55f7fd0f4 100644 --- a/tests/unit_tests/test_deplete_restart.py +++ b/tests/unit_tests/test_deplete_restart.py @@ -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") diff --git a/tests/unit_tests/test_deplete_resultslist.py b/tests/unit_tests/test_deplete_resultslist.py index c4b7aceba5..c3ceda5d56 100644 --- a/tests/unit_tests/test_deplete_resultslist.py +++ b/tests/unit_tests/test_deplete_resultslist.py @@ -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): diff --git a/tests/unit_tests/test_deplete_si_celi.py b/tests/unit_tests/test_deplete_si_celi.py index 0a0103510b..5cc0d4e6c4 100644 --- a/tests/unit_tests/test_deplete_si_celi.py +++ b/tests/unit_tests/test_deplete_si_celi.py @@ -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") diff --git a/tests/unit_tests/test_deplete_si_leqi.py b/tests/unit_tests/test_deplete_si_leqi.py index 41215c22f4..8e3c3a4648 100644 --- a/tests/unit_tests/test_deplete_si_leqi.py +++ b/tests/unit_tests/test_deplete_si_leqi.py @@ -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") diff --git a/tests/unit_tests/test_transfer_volumes.py b/tests/unit_tests/test_transfer_volumes.py index ae2151b2d7..2e735c911e 100644 --- a/tests/unit_tests/test_transfer_volumes.py +++ b/tests/unit_tests/test_transfer_volumes.py @@ -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