Allow Integrators to deplete w/o multiprocessing

Through a discussion on the user's group
https://groups.google.com/forum/#!topic/openmc-users/xHKYV-EBgrY
it was determined that some computing environments don't support
calls to fork() that multiprocessing.Pool requires. This can
lead to the depletion hanging indefinitely.

Users can now configure the
openmc.deplete.pool.USE_MULTIPROCESSING boolean to control
the use of multiprocessing during depletion. The default state
is to use multiprocessing. Otherwise itertools.starmap will be
used to update the compositions "in serial"
This commit is contained in:
Andrew Johnson 2020-06-18 16:02:34 -04:00
parent a905e5c9e2
commit 89259e310e
No known key found for this signature in database
GPG key ID: 253418E91B7F6FEB
3 changed files with 37 additions and 7 deletions

View file

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

View file

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

View file

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