diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index b01de477c..8423cd946 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -145,6 +145,17 @@ with :func:`cram.CRAM48` being the default. cram.CRAM48 pool.deplete +.. data:: pool.USE_MULTIPROCESSING + + Boolean switch to enable or disable the use of :mod:`multiprocessing` + when solving the Bateman equations. The default is to use + :mod:`multiprocessing`, but can cause the simulation for hang in + some computing environments, namely due to MPI and networking + restrictions. Disabling this option will not utilize all processing + units and take a little more time. + + :type: bool + The following classes are used to help the :class:`openmc.deplete.Operator` compute quantities like effective fission yields, reaction rates, and total system energy. diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 8846906b4..9d92920d5 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -887,6 +887,14 @@ class Integrator(ABC): Results.save(self.operator, [conc], res_list, [t, t], p, self._i_res + len(self), proc_time) self.operator.write_bos_data(len(self) + self._i_res) + self._finalize() + + @staticmethod + def _finalize(): + # Revert the se of multiprocessing, regardless of + # how the integration was performed + global _USE_MULTIPROCESSING + _USE_MULTIPROCESSING = True class SIIntegrator(Integrator): @@ -1021,6 +1029,9 @@ class SIIntegrator(Integrator): p, self._i_res + len(self), proc_time) self.operator.write_bos_data(self._i_res + len(self)) + # Tidy up: reset use of multiprocessing + super()._finalize() + class DepSystemSolver(ABC): r"""Abstract class for solving depletion equations diff --git a/openmc/deplete/pool.py b/openmc/deplete/pool.py index d9d359775..8360ef602 100644 --- a/openmc/deplete/pool.py +++ b/openmc/deplete/pool.py @@ -2,10 +2,15 @@ Provided to avoid some circular imports """ -from itertools import repeat +from itertools import repeat, starmap from multiprocessing import Pool +# Configurable switch that enables / disables the use of +# multiprocessing routines during depletion +USE_MULTIPROCESSING = True + + def deplete(func, chain, x, rates, dt, matrix_func=None): """Deplete materials using given reaction rates for a specified time @@ -41,8 +46,8 @@ def deplete(func, chain, x, rates, dt, matrix_func=None): fission_yields = repeat(fission_yields[0]) elif len(fission_yields) != len(x): raise ValueError( - "Number of material fission yield distributions {} is not equal " - "to the number of compositions {}".format( + "Number of material fission yield distributions {} is not " + "equal to the number of compositions {}".format( len(fission_yields), len(x))) if matrix_func is None: @@ -50,9 +55,12 @@ def deplete(func, chain, x, rates, dt, matrix_func=None): else: matrices = map(matrix_func, repeat(chain), rates, fission_yields) - # Use multiprocessing pool to distribute work - with Pool() as pool: - inputs = zip(matrices, x, repeat(dt)) - x_result = list(pool.starmap(func, inputs)) + inputs = zip(matrices, x, repeat(dt)) + + if USE_MULTIPROCESSING: + with Pool() as pool: + x_result = list(pool.starmap(func, inputs)) + else: + x_result = list(starmap(func, inputs)) return x_result