mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-26 21:25:36 -04:00
Made changes from paulromano's 2nd round of comments
- Syntax improvements and fixes - removed `flux` parameter from Integrator - Moved generate_1g_cross_sections to a top level function in flux_operator.py - changed normalization modes: constant-flux -> source-rate; constant-power -> fission-q - fixed regression tests (fission-q reference solution was bad before, but is now much more reasonable and comparable to the source-rate reference solution) - added `nuc_units` parameter to the `from_nuclides` method. - docstring fixes - RST doc fixes - spelling fixes
This commit is contained in:
parent
8102226e70
commit
4818a296d4
11 changed files with 178 additions and 175 deletions
|
|
@ -19,10 +19,10 @@ transmutation equations and the method used for advancing time. At present, the
|
|||
:class:`openmc.deplete.Operator` (which uses the OpenMC transport solver), but
|
||||
in principle additional operator classes based on other transport codes could be
|
||||
implemented and no changes to the depletion solver itself would be needed. The
|
||||
operator class requires a :class:`openmc.model.Model` instance containing
|
||||
operator class requires a :class:`~openmc.Model` instance containing
|
||||
material, geometry, and settings information::
|
||||
|
||||
model = openmc.model.Model()
|
||||
model = openmc.Model()
|
||||
...
|
||||
|
||||
op = openmc.deplete.Operator(model)
|
||||
|
|
@ -189,17 +189,18 @@ Transport-independent depletion
|
|||
|
||||
OpenMC supports running depletion calculations independent of the OpenMC
|
||||
transport solver using the :class:`~openmc.deplete.FluxDepletionOperator` class.
|
||||
This class supports both constant-flux and constant-power depletion.
|
||||
This class supports both constant-flux (``source-rate`` normalization) and
|
||||
constant-power depletion (``fission-q`` normalization).
|
||||
|
||||
.. important::
|
||||
|
||||
Make sure you set the correct parameter in the :class:`openmc.abc.Integrator` class. Use the ``flux`` parameter when ``normalization_mode == constant-flux``, and use ``power`` or ``power_density`` when ``normalization_mode == constant-power``.
|
||||
Make sure you set the correct parameter in the :class:`openmc.abc.Integrator` class. Use the ``source_rates`` parameter when ``normalization_mode == source-rate``, and use ``power`` or ``power_density`` when ``normalization_mode == fission-q``.
|
||||
|
||||
.. warning::
|
||||
|
||||
The accuracy of results when using ``constant-power`` is entirely dependent on your depletion chain. Make sure it has sufficient data to resolve the dynamics of your particular scenario.
|
||||
The accuracy of results when using ``fission-q`` is entirely dependent on your depletion chain. Make sure it has sufficient data to resolve the dynamics of your particular scenario.
|
||||
|
||||
This class has two ways to initalize it: the default constructor accepts an
|
||||
This class has two ways to initialize it: the default constructor accepts an
|
||||
:class:`openmc.Materials` object and one-group microscopic
|
||||
cross sections as a :class:`pandas.DataFrame`, while the ``from_nuclides``
|
||||
method accepts a volume and dictionary of nuclide concentrations in place of
|
||||
|
|
@ -221,7 +222,8 @@ or from data arrays::
|
|||
'O16': 4.64e22,
|
||||
'O17': 1.76e19}
|
||||
volume = 0.5
|
||||
op = FluxDepletionOperator.from_nuclides(volume, nuclides, micro_xs, flux, chain_file)
|
||||
op = FluxDepletionOperator.from_nuclides(volume, nuclides, 'atom/cm3',
|
||||
micro_xs, flux, chain_file)
|
||||
|
||||
A user can then define an integrator class as they would for a coupled
|
||||
transport-depletion calculation and follow the same steps from there.
|
||||
|
|
|
|||
|
|
@ -524,11 +524,10 @@ class Integrator(ABC):
|
|||
power_density : float or iterable of float, optional
|
||||
Power density of the reactor in [W/gHM]. It is multiplied by
|
||||
initial heavy metal inventory to get total power if ``power``
|
||||
is not speficied.
|
||||
flux : float or iterable of float, optional
|
||||
neutron flux in [neut/s-cm^2] for each interval in :attr:`timesteps`
|
||||
is not specified.
|
||||
source_rates : float or iterable of float, optional
|
||||
source rate in [neutron/sec] for each interval in :attr:`timesteps`
|
||||
Source rate in [neutron/sec] or neutron flux in [neut/s-cm^2] for each
|
||||
interval in :attr:`timesteps`
|
||||
|
||||
.. versionadded:: 0.12.1
|
||||
timestep_units : {'s', 'min', 'h', 'd', 'MWd/kg'}
|
||||
|
|
@ -579,7 +578,7 @@ class Integrator(ABC):
|
|||
"""
|
||||
|
||||
def __init__(self, operator, timesteps, power=None, power_density=None,
|
||||
flux=None, source_rates=None, timestep_units='s', solver="cram48"):
|
||||
source_rates=None, timestep_units='s', solver="cram48"):
|
||||
# Check number of stages previously used
|
||||
if operator.prev_res is not None:
|
||||
res = operator.prev_res[-1]
|
||||
|
|
@ -601,10 +600,8 @@ class Integrator(ABC):
|
|||
source_rates = power_density * operator.heavy_metal
|
||||
else:
|
||||
source_rates = [p*operator.heavy_metal for p in power_density]
|
||||
elif flux is not None:
|
||||
source_rates = flux
|
||||
elif source_rates is None:
|
||||
raise ValueError("Either power, power_density, flux, or source_rates must be set")
|
||||
raise ValueError("Either power, power_density, source_rates must be set")
|
||||
|
||||
if not isinstance(source_rates, Iterable):
|
||||
# Ensure that rate is single value if that is the case
|
||||
|
|
@ -865,11 +862,10 @@ class SIIntegrator(Integrator):
|
|||
power_density : float or iterable of float, optional
|
||||
Power density of the reactor in [W/gHM]. It is multiplied by
|
||||
initial heavy metal inventory to get total power if ``power``
|
||||
is not speficied.
|
||||
flux : float or iterable of float, optional
|
||||
neutron flux in [neut/s-cm^2] for each interval in :attr:`timesteps`
|
||||
is not specified.
|
||||
source_rates : float or iterable of float, optional
|
||||
Source rate in [neutron/sec] for each interval in :attr:`timesteps`
|
||||
Source rate in [neutron/sec] or neutron flux in [neut/s-cm^2] for each
|
||||
interval in :attr:`timesteps`
|
||||
|
||||
.. versionadded:: 0.12.1
|
||||
timestep_units : {'s', 'min', 'h', 'd', 'MWd/kg'}
|
||||
|
|
@ -924,12 +920,12 @@ class SIIntegrator(Integrator):
|
|||
"""
|
||||
|
||||
def __init__(self, operator, timesteps, power=None, power_density=None,
|
||||
flux=None, source_rates=None, timestep_units='s', n_steps=10,
|
||||
source_rates=None, timestep_units='s', n_steps=10,
|
||||
solver="cram48"):
|
||||
check_type("n_steps", n_steps, Integral)
|
||||
check_greater_than("n_steps", n_steps, 0)
|
||||
super().__init__(
|
||||
operator, timesteps, power, power_density, flux, source_rates,
|
||||
operator, timesteps, power, power_density, source_rates,
|
||||
timestep_units=timestep_units, solver=solver)
|
||||
self.n_steps = n_steps
|
||||
|
||||
|
|
@ -1014,7 +1010,7 @@ class DepSystemSolver(ABC):
|
|||
Parameters
|
||||
----------
|
||||
A : scipy.sparse.csr_matrix
|
||||
Sparse transmutation matrix ``A[j, i]`` desribing rates at
|
||||
Sparse transmutation matrix ``A[j, i]`` describing rates at
|
||||
which isotope ``i`` transmutes to isotope ``j``
|
||||
n0 : numpy.ndarray
|
||||
Initial compositions, typically given in number of atoms in some
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""Pure depletion operator
|
||||
|
||||
This module implements a pure depletion operator that uses user- provided fluxes
|
||||
and one-group cross sections.
|
||||
This module implements a pure depletion operator that user-provided one-group
|
||||
cross sections.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -20,12 +20,84 @@ from openmc.mpi import comm
|
|||
from openmc.mgxs import EnergyGroups, ArbitraryXS, FissionXS
|
||||
from .abc import ReactionRateHelper, OperatorResult
|
||||
from .chain import REACTIONS
|
||||
from .openmc_operator import OpenMCOperator
|
||||
from .openmc_operator import OpenMCOperator, _distribute
|
||||
from .results import Results
|
||||
from .helpers import ChainFissionHelper, ConstantFissionYieldHelper, SourceRateHelper
|
||||
|
||||
_valid_rxns = list(REACTIONS)
|
||||
_valid_rxns.append('fission')
|
||||
|
||||
def generate_1g_cross_sections(model,
|
||||
reaction_domain,
|
||||
reactions=['(n,gamma)',
|
||||
'(n,2n)',
|
||||
'(n,p)',
|
||||
'(n,a)',
|
||||
'(n,3n)',
|
||||
'(n,4n)',
|
||||
'fission'],
|
||||
energy_bounds=(0, 20e6),
|
||||
write_to_csv=False,
|
||||
filename='micro_xs.csv'):
|
||||
"""Helper function to generate a one-group cross-section dataframe using
|
||||
OpenMC. Note that the ``openmc`` executable must be compiled.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : openmc.model.Model
|
||||
OpenMC model object. Must contain geometry, materials, and settings.
|
||||
reaction_domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh
|
||||
Domain in which to tally reaction rates.
|
||||
reactions : list of str, optional
|
||||
Reaction names to tally
|
||||
energy_bound : 2-tuple of float, optional
|
||||
Bounds for the energy group.
|
||||
write_to_csv : bool, optional
|
||||
Option to write the DataFrame to a `.csv` file.
|
||||
filename : str
|
||||
Name for csv file. Only applicable if ``write_to_csv == True``
|
||||
|
||||
Returns
|
||||
-------
|
||||
None or pandas.DataFrame
|
||||
|
||||
"""
|
||||
groups = EnergyGroups(energy_bounds)
|
||||
|
||||
# Set up the reaction tallies
|
||||
original_tallies = model.tallies
|
||||
tallies = openmc.Tallies()
|
||||
xs = {}
|
||||
for rxn in reactions:
|
||||
if rxn == 'fission':
|
||||
xs[rxn] = FissionXS(domain=reaction_domain, groups=groups, by_nuclide=True)
|
||||
else:
|
||||
xs[rxn] = ArbitraryXS(rxn, domain=reaction_domain, groups=groups, by_nuclide=True)
|
||||
tallies += xs[rxn].tallies.values()
|
||||
|
||||
model.tallies = tallies
|
||||
statepoint_path = model.run()
|
||||
|
||||
# Revert to the original tallies
|
||||
model.tallies = old_tallies
|
||||
|
||||
with openmc.StatePoint(statepoint_path) as sp:
|
||||
for rxn in xs:
|
||||
xs[rxn].load_from_statepoint(sp)
|
||||
|
||||
# Build the DataFrame
|
||||
micro_xs = pd.DataFrame()
|
||||
for rxn in xs:
|
||||
df = xs[rxn].get_pandas_dataframe(xs_type='micro')
|
||||
df.index = df['nuclide']
|
||||
df.drop(['nuclide', xs[rxn].domain_type, 'group in', 'std. dev.'], axis=1, inplace=True)
|
||||
df.rename({'mean':rxn}, axis=1, inplace=True)
|
||||
micro_xs = pd.concat([micro_xs, df], axis=1)
|
||||
|
||||
if write_to_csv:
|
||||
micro_xs.to_csv(filename)
|
||||
|
||||
return micro_xs
|
||||
|
||||
class FluxDepletionOperator(OpenMCOperator):
|
||||
"""Depletion operator that uses one-group
|
||||
|
|
@ -50,14 +122,16 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
Default is None.
|
||||
prev_results : Results, optional
|
||||
Results from a previous depletion calculation.
|
||||
normalization_mode : {"constant-power", "constant-flux"}
|
||||
normalization_mode : {"fission-q", "source-rate"}
|
||||
Indicate how reaction rates should be calculated.
|
||||
``"constant-power"`` uses the fission Q values from the depletion chain to
|
||||
compute the flux based on the power. ``"constant-flux"`` uses the value stored in `_normalization_helper` as the flux.
|
||||
``"fission-q"`` uses the fission Q values from the depletion chain to
|
||||
compute the flux based on the power. ``"source-rate"`` uses a the
|
||||
source rate (assumed to be neutron flux) to calculate the
|
||||
reaction rates.
|
||||
fission_q : dict, optional
|
||||
Dictionary of nuclides and their fission Q values [eV]. If not given,
|
||||
values will be pulled from the ``chain_file``. Only applicable
|
||||
if ``"normalization_mode" == "constant-power"``.
|
||||
if ``"normalization_mode" == "fission-q"``.
|
||||
reduce_chain : bool, optional
|
||||
If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the
|
||||
depletion chain up to ``reduce_chain_level``. Default is False.
|
||||
|
|
@ -104,14 +178,14 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
Results from a previous depletion calculation. ``None`` if no
|
||||
results are to be used.
|
||||
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
materials,
|
||||
micro_xs,
|
||||
chain_file,
|
||||
keff=None,
|
||||
normalization_mode = 'constant-flux',
|
||||
normalization_mode='source-rate',
|
||||
fission_q=None,
|
||||
prev_results=None,
|
||||
reduce_chain=False,
|
||||
|
|
@ -126,7 +200,8 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
|
||||
self._keff = keff
|
||||
|
||||
helper_kwargs = dict()
|
||||
if fission_yield_opts is None:
|
||||
fission_yield_opts = {}
|
||||
helper_kwargs = {'normalization_mode': normalization_mode,
|
||||
'fission_yield_opts': fission_yield_opts}
|
||||
|
||||
|
|
@ -141,10 +216,11 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
reduce_chain_level=reduce_chain_level)
|
||||
|
||||
@classmethod
|
||||
def from_nuclides(cls, volume, nuclides, micro_xs,
|
||||
def from_nuclides(cls, volume, nuclides, nuc_units,
|
||||
micro_xs,
|
||||
chain_file,
|
||||
keff=None,
|
||||
normalization_mode='constant-flux',
|
||||
normalization_mode='source-rate',
|
||||
fission_q=None,
|
||||
prev_results=None,
|
||||
reduce_chain=False,
|
||||
|
|
@ -156,8 +232,10 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
volume : float
|
||||
Volume of the material being depleted in [cm^3]
|
||||
nuclides : dict of str to float
|
||||
,Dictionary with nuclide names as keys and nuclide concentrations as
|
||||
values. Nuclide concentration units are [atom/cm^3].
|
||||
Dictionary with nuclide names as keys and nuclide concentrations as
|
||||
values.
|
||||
nuc_units : {'atom/cm3', 'atom/b-cm'}
|
||||
Units for nuclide concentration.
|
||||
micro_xs : pandas.DataFrame
|
||||
DataFrame with nuclides names as index and microscopic cross section
|
||||
data in the columns. Cross section units are [cm^-2].
|
||||
|
|
@ -166,15 +244,16 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
keff : 2-tuple of float, optional
|
||||
keff eigenvalue and uncertainty from transport calculation.
|
||||
Default is None.
|
||||
normalization_mode : {"constant-power", "constant-flux"}
|
||||
normalization_mode : {"fission-q", "source-rate"}
|
||||
Indicate how reaction rates should be calculated.
|
||||
``"constant-power"`` uses the fission Q values from the depletion
|
||||
chain to compute the flux based on the power. ``"constant-flux"``
|
||||
uses the value stored in `_normalization_helper` as the flux.
|
||||
``"fission-q"`` uses the fission Q values from the depletion
|
||||
chain to compute the flux based on the power. ``"source-rate"`` uses
|
||||
the source rate (assumed to be neutron flux) to calculate the
|
||||
reaction rates.
|
||||
fission_q : dict, optional
|
||||
Dictionary of nuclides and their fission Q values [eV]. If not
|
||||
given, values will be pulled from the ``chain_file``. Only
|
||||
applicable if ``"normalization_mode" == "constant-power"``.
|
||||
applicable if ``"normalization_mode" == "fission-q"``.
|
||||
prev_results : Results, optional
|
||||
Results from a previous depletion calculation.
|
||||
reduce_chain : bool, optional
|
||||
|
|
@ -191,7 +270,7 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
|
||||
"""
|
||||
check_type('nuclides', nuclides, dict, str)
|
||||
materials = cls._consolidate_nuclides_to_material(nuclides, volume)
|
||||
materials = cls._consolidate_nuclides_to_material(nuclides, nuc_units, volume)
|
||||
return cls(materials,
|
||||
micro_xs,
|
||||
chain_file,
|
||||
|
|
@ -205,14 +284,20 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
|
||||
|
||||
@staticmethod
|
||||
def _consolidate_nuclides_to_material(nuclides, volume):
|
||||
def _consolidate_nuclides_to_material(nuclides, nuc_units, volume):
|
||||
"""Puts nuclide list into an openmc.Materials object.
|
||||
|
||||
"""
|
||||
openmc.reset_auto_ids()
|
||||
mat = openmc.Material()
|
||||
for nuc, conc in nuclides.items():
|
||||
mat.add_nuclide(nuc, conc * 1e-24) # convert to at/b-cm
|
||||
if nuc_units == 'atom/b-cm':
|
||||
for nuc, conc in nuclides.items():
|
||||
mat.add_nuclide(nuc, conc)
|
||||
elif nuc_units == 'atom/cm3':
|
||||
for nuc, conc in nuclides.items():
|
||||
mat.add_nuclide(nuc, conc * 1e-24) # convert to at/b-cm
|
||||
else:
|
||||
raise ValueError(f"Unit '{nuc_units}' is invalid.")
|
||||
|
||||
mat.volume = volume
|
||||
mat.depletable = True
|
||||
|
|
@ -273,13 +358,12 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
mat_index : int
|
||||
Material index
|
||||
|
||||
"""
|
||||
"""
|
||||
volume = self._op.number.get_mat_volume(mat_index)
|
||||
densities = np.empty(np.shape(fission_rates))
|
||||
for i_nuc in self.nuc_ind_map:
|
||||
nuc = self.nuc_ind_map[i_nuc]
|
||||
densities = np.empty_like(fission_rates)
|
||||
for i_nuc, nuc in self.nuc_ind_map.items():
|
||||
densities[i_nuc] = self._op.number.get_atom_density(mat_index, nuc)
|
||||
fission_rates = fission_rates * volume * densities
|
||||
fission_rates *= volume * densities
|
||||
|
||||
super().update(fission_rates)
|
||||
|
||||
|
|
@ -294,10 +378,6 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
n_nucs : int
|
||||
Number of burnable nuclides tracked by :class:`openmc.deplete.Operator`
|
||||
n_react : int
|
||||
Number of reactions tracked by :class:`openmc.deplete.Operator`
|
||||
op : openmc.deplete.FluxDepletionOperator
|
||||
Reference to the object encapsulate _FluxDepletionRateHelper.
|
||||
We pass this so we don't have to duplicate the ``number`` object.
|
||||
|
|
@ -312,9 +392,9 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, n_nuc, n_react, op):
|
||||
super().__init__(n_nuc, n_react)
|
||||
def __init__(self, op):
|
||||
rates = op.reaction_rates
|
||||
super().__init__(rates.n_nuc, rates.n_react)
|
||||
|
||||
self.nuc_ind_map = {ind: nuc for nuc, ind in rates.index_nuc.items()}
|
||||
self.rxn_ind_map = {ind: rxn for rxn, ind in rates.index_rx.items()}
|
||||
|
|
@ -349,7 +429,7 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
return self._results_cache
|
||||
|
||||
def _get_helper_classes(self, helper_kwargs):
|
||||
"""Get helper classes for calculating reation rates and fission yields
|
||||
"""Get helper classes for calculating reaction rates and fission yields
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -359,19 +439,16 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
"""
|
||||
|
||||
normalization_mode = helper_kwargs['normalization_mode']
|
||||
fission_yield_opts = helper_kwargs.get('fission_yield_opts', {})
|
||||
fission_yield_opts = helper_kwargs['fission_yield_opts']
|
||||
|
||||
self._rate_helper = self._FluxDepletionRateHelper(
|
||||
self.reaction_rates.n_nuc, self.reaction_rates.n_react, self)
|
||||
if normalization_mode == "constant-power":
|
||||
self._rate_helper = self._FluxDepletionRateHelper(self)
|
||||
if normalization_mode == "fission-q":
|
||||
self._normalization_helper = self._FluxDepletionNormalizationHelper(self)
|
||||
else:
|
||||
self._normalization_helper = SourceRateHelper()
|
||||
|
||||
# Select and create fission yield helper
|
||||
fission_helper = ConstantFissionYieldHelper
|
||||
if fission_yield_opts is None:
|
||||
fission_yield_opts = {}
|
||||
self._yield_helper = fission_helper.from_operator(
|
||||
self, **fission_yield_opts)
|
||||
|
||||
|
|
@ -395,7 +472,7 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
vec : list of numpy.ndarray
|
||||
Total atoms to be used in function.
|
||||
source_rate : float
|
||||
Power in [W] or source rate in [neutron/sec]
|
||||
Power in [W] or flux in [neut/s-cm^2]
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -444,11 +521,11 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
print(f'WARNING: nuclide {nuc} in material'
|
||||
f'{mat} is negative (density = {val}'
|
||||
|
||||
' at/barn-cm)')
|
||||
' atom/b-cm)')
|
||||
number_i[mat, nuc] = 0.0
|
||||
|
||||
@staticmethod
|
||||
def create_micro_xs_from_data_array(nuclides, reactions, data, units='barn'):
|
||||
def create_micro_xs_from_data_array(nuclides, reactions, data):
|
||||
"""
|
||||
Creates a ``micro_xs`` parameter from a dictionary.
|
||||
|
||||
|
|
@ -458,12 +535,10 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
List of nuclide symbols for that have data for at least one
|
||||
reaction.
|
||||
reactions : list of str
|
||||
List of reactions. All reactions must match those in ``chain.REACTONS``
|
||||
List of reactions. All reactions must match those in ``chain.REACTIONS``
|
||||
data : ndarray of floats
|
||||
Array containing one-group microscopic cross section information for each
|
||||
nuclide and reaction.
|
||||
units : {'barn', 'cm^2'}, optional
|
||||
Units of cross section values in ``data`` array. Defaults to ``barn``.
|
||||
Array containing one-group microscopic cross section values, in
|
||||
[barn], for each nuclide and reaction.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -483,8 +558,7 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
nuclides, reactions, data)
|
||||
|
||||
# Convert to cm^2
|
||||
if units == 'barn':
|
||||
data *= 1e-24
|
||||
data *= 1e-24
|
||||
|
||||
return pd.DataFrame(index=nuclides, columns=reactions, data=data)
|
||||
|
||||
|
|
@ -497,9 +571,7 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
----------
|
||||
csv_file : str
|
||||
Relative path to csv-file containing microscopic cross section
|
||||
data.
|
||||
units : {'barn', 'cm^2'}, optional
|
||||
Units of cross section values in the ``.csv`` file array. Defaults to ``barn``.
|
||||
data. Cross section values should be in [barn].
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -514,8 +586,7 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
list(micro_xs.columns),
|
||||
micro_xs.to_numpy())
|
||||
|
||||
if units == 'barn':
|
||||
micro_xs *= 1e-24
|
||||
micro_xs *= 1e-24
|
||||
|
||||
return micro_xs
|
||||
|
||||
|
|
@ -528,67 +599,3 @@ class FluxDepletionOperator(OpenMCOperator):
|
|||
for reaction in reactions:
|
||||
check_value('reactions', reaction, _valid_rxns)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def generate_1g_cross_sections(model, reaction_domain, reactions=['(n,gamma)', '(n,2n)', '(n,p)', '(n,a)', '(n,3n)', '(n,4n)', 'fission'], energy_bounds=(0, 20e6), write_to_csv=True, filename='micro_xs.csv'):
|
||||
"""Helper function to generate a one-group cross-section dataframe
|
||||
using OpenMC. Note that the ``openmc`` C executable must be compiled.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : openmc.model.Model
|
||||
OpenMC model object. Must contain geometry, materials, and settings.
|
||||
reaction_domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh
|
||||
Domain in which to tally reaction rates.
|
||||
reactions : list of str, optional
|
||||
Reaction names to tally
|
||||
energy_bound : 2-tuple of float, optional
|
||||
Bounds for the energy group.
|
||||
write_to_csv : bool, optional
|
||||
Option to write the DataFrame to a `.csv` file. If `False`,
|
||||
returns the dataframe object.
|
||||
filename : str
|
||||
Name for csv file. Only applicable if ``write_to_csv == True``
|
||||
|
||||
Returns
|
||||
-------
|
||||
None or pandas.DataFrame
|
||||
|
||||
"""
|
||||
groups = EnergyGroups()
|
||||
groups.group_edges = np.array(list(energy_bounds))
|
||||
|
||||
# Set up the reaction tallies
|
||||
tallies = openmc.Tallies()
|
||||
xs = dict()
|
||||
for rxn in reactions:
|
||||
if rxn == 'fission':
|
||||
xs[rxn] = FissionXS(domain=reaction_domain, groups=groups, by_nuclide=True)
|
||||
else:
|
||||
xs[rxn] = ArbitraryXS(rxn, domain=reaction_domain, groups=groups, by_nuclide=True)
|
||||
tallies += xs[rxn].tallies.values()
|
||||
|
||||
model.tallies = tallies
|
||||
statepoint_path = model.run()
|
||||
|
||||
sp = openmc.StatePoint(statepoint_path)
|
||||
|
||||
for rxn in xs:
|
||||
xs[rxn].load_from_statepoint(sp)
|
||||
|
||||
sp.close()
|
||||
|
||||
# Build the DataFrame
|
||||
micro_xs = pd.DataFrame()
|
||||
for rxn in xs:
|
||||
df = xs[rxn].get_pandas_dataframe(xs_type='micro')
|
||||
df.index = df['nuclide']
|
||||
df.drop(['nuclide', xs[rxn].domain_type, 'group in', 'std. dev.'], axis=1, inplace=True)
|
||||
df.rename({'mean':rxn}, axis=1, inplace=True)
|
||||
micro_xs = pd.concat([micro_xs, df], axis=1)
|
||||
|
||||
if write_to_csv:
|
||||
micro_xs.to_csv(filename)
|
||||
return None
|
||||
else:
|
||||
return micro_xs
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper):
|
|||
Default: 0.0253 [eV]
|
||||
fast_energy : float, optional
|
||||
Energy of yield data corresponding to fast yields.
|
||||
Default: 500 [kev]
|
||||
Default: 500 [KeV]
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
|
@ -634,7 +634,7 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper):
|
|||
Array of fission rate fractions with shape
|
||||
``(n_mats, 2, n_nucs)``. ``results[:, 0]``
|
||||
corresponds to the fraction of all fissions
|
||||
that occured below ``cutoff``. The number
|
||||
that occurred below ``cutoff``. The number
|
||||
of materials in the first axis corresponds
|
||||
to the number of materials burned by the
|
||||
:class:`openmc.deplete.Operator`
|
||||
|
|
@ -790,7 +790,7 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper):
|
|||
class AveragedFissionYieldHelper(TalliedFissionYieldHelper):
|
||||
r"""Class that computes fission yields based on average fission energy
|
||||
|
||||
Computes average energy at which fission events occured with
|
||||
Computes average energy at which fission events occurred with
|
||||
|
||||
.. math::
|
||||
|
||||
|
|
@ -908,7 +908,7 @@ class AveragedFissionYieldHelper(TalliedFissionYieldHelper):
|
|||
Use the computed average energy of fission
|
||||
events to determine fission yields. If average
|
||||
energy is between two sets of yields, linearly
|
||||
interpolate bewteen the two.
|
||||
interpolate between the two.
|
||||
Otherwise take the closet set of yields.
|
||||
|
||||
Parameters
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class CECMIntegrator(Integrator):
|
|||
op_results : list of openmc.deplete.OperatorResult
|
||||
Eigenvalue and reaction rates from transport simulations
|
||||
"""
|
||||
# deplete across first half of inteval
|
||||
# deplete across first half of interval
|
||||
time0, x_middle = self._timed_deplete(conc, rates, dt / 2)
|
||||
res_middle = self.operator(x_middle, source_rate)
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ class OpenMCOperator(TransportOperator):
|
|||
cross_sections : str or pandas.DataFrame
|
||||
Path to continuous energy cross section library, or object
|
||||
containing one-group cross-sections.
|
||||
|
||||
dilute_initial : float
|
||||
Initial atom density [atoms/cm^3] to add for nuclides that
|
||||
are zero in initial condition to ensure they exist in the decay
|
||||
|
|
@ -527,7 +526,9 @@ class OpenMCOperator(TransportOperator):
|
|||
|
||||
# Accumulate energy from fission
|
||||
if fission_ind is not None:
|
||||
self._normalization_helper.update(tally_rates[:, fission_ind], mat_index=mat_index)
|
||||
self._normalization_helper.update(
|
||||
tally_rates[:, fission_ind],
|
||||
mat_index=mat_index)
|
||||
|
||||
# Divide by total number and store
|
||||
rates[i] = self._rate_helper.divide_by_adens(number)
|
||||
|
|
|
|||
|
|
@ -225,7 +225,10 @@ class Operator(OpenMCOperator):
|
|||
|
||||
self.cleanup_when_done = True
|
||||
|
||||
helper_kwargs = dict()
|
||||
if reaction_rate_opts is None:
|
||||
reaction_rate_opts = {}
|
||||
if fission_yield_opts is None:
|
||||
fission_yield_opts = {}
|
||||
helper_kwargs = {
|
||||
'reaction_rate_mode': reaction_rate_mode,
|
||||
'normalization_mode': normalization_mode,
|
||||
|
|
@ -329,17 +332,14 @@ class Operator(OpenMCOperator):
|
|||
reaction_rate_mode = helper_kwargs['reaction_rate_mode']
|
||||
normalization_mode = helper_kwargs['normalization_mode']
|
||||
fission_yield_mode = helper_kwargs['fission_yield_mode']
|
||||
reaction_rate_opts = helper_kwargs.get('reaction_rate_opts', {})
|
||||
fission_yield_opts = helper_kwargs.get('fission_yield_opts', {})
|
||||
reaction_rate_opts = helper_kwargs['reaction_rate_opts']
|
||||
fission_yield_opts = helper_kwargs['fission_yield_opts']
|
||||
|
||||
# Get classes to assist working with tallies
|
||||
if reaction_rate_mode == "direct":
|
||||
self._rate_helper = DirectReactionRateHelper(
|
||||
self.reaction_rates.n_nuc, self.reaction_rates.n_react)
|
||||
elif reaction_rate_mode == "flux":
|
||||
if reaction_rate_opts is None:
|
||||
reaction_rate_opts = {}
|
||||
|
||||
# Ensure energy group boundaries were specified
|
||||
if 'energies' not in reaction_rate_opts:
|
||||
raise ValueError(
|
||||
|
|
@ -365,8 +365,6 @@ class Operator(OpenMCOperator):
|
|||
|
||||
# Select and create fission yield helper
|
||||
fission_helper = self._fission_helpers[fission_yield_mode]
|
||||
if fission_yield_opts is None:
|
||||
fission_yield_opts = {}
|
||||
self._yield_helper = fission_helper.from_operator(
|
||||
self, **fission_yield_opts)
|
||||
|
||||
|
|
@ -489,7 +487,7 @@ class Operator(OpenMCOperator):
|
|||
print(f'WARNING: nuclide {nuc} in material'
|
||||
f'{mat} is negative (density = {val}'
|
||||
|
||||
' at/barn-cm)')
|
||||
' atom/b-cm)')
|
||||
|
||||
number_i[mat, nuc] = 0.0
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
from math import floor
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from difflib import unified_diff
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import openmc
|
||||
|
|
@ -12,7 +12,6 @@ from openmc.data import JOULE_PER_EV
|
|||
import openmc.deplete
|
||||
from openmc.deplete import FluxDepletionOperator
|
||||
|
||||
|
||||
from tests.regression_tests import config
|
||||
|
||||
|
||||
|
|
@ -22,7 +21,7 @@ def fuel():
|
|||
fuel.add_element("U", 1, percent_type="ao", enrichment=4.25)
|
||||
fuel.add_element("O", 2)
|
||||
fuel.set_density("g/cc", 10.4)
|
||||
fuel.depletable=True
|
||||
fuel.depletable = True
|
||||
|
||||
fuel.volume = np.pi * 0.42 ** 2
|
||||
|
||||
|
|
@ -30,14 +29,14 @@ def fuel():
|
|||
|
||||
|
||||
@pytest.mark.parametrize("multiproc, from_nuclides, normalization_mode, power, flux", [
|
||||
(True, True,'constant-flux', None, 1164719970082145.0),
|
||||
(False, True, 'constant-flux', None, 1164719970082145.0),
|
||||
(True, True, 'constant-power', 174, None),
|
||||
(False, True, 'constant-power', 174, None),
|
||||
(True, False,'constant-flux', None, 1164719970082145.0),
|
||||
(False, False, 'constant-flux', None, 1164719970082145.0),
|
||||
(True, False, 'constant-power', 174, None),
|
||||
(False, False, 'constant-power', 174, None)])
|
||||
(True, True,'source-rate', None, 1164719970082145.0),
|
||||
(False, True, 'source-rate', None, 1164719970082145.0),
|
||||
(True, True, 'fission-q', 174, None),
|
||||
(False, True, 'fission-q', 174, None),
|
||||
(True, False,'source-rate', None, 1164719970082145.0),
|
||||
(False, False, 'source-rate', None, 1164719970082145.0),
|
||||
(True, False, 'fission-q', 174, None),
|
||||
(False, False, 'fission-q', 174, None)])
|
||||
def test_no_transport_from_nuclides(run_in_tmpdir, fuel, multiproc, from_nuclides, normalization_mode, power, flux):
|
||||
"""Transport free system test suite.
|
||||
|
||||
|
|
@ -53,10 +52,10 @@ def test_no_transport_from_nuclides(run_in_tmpdir, fuel, multiproc, from_nuclide
|
|||
if from_nuclides:
|
||||
nuclides = {}
|
||||
for nuc, dens in fuel.get_nuclide_atom_densities().items():
|
||||
nuclides[nuc] = dens * 1e24
|
||||
nuclides[nuc] = dens
|
||||
|
||||
op = FluxDepletionOperator.from_nuclides(
|
||||
fuel.volume, nuclides, micro_xs, chain_file, normalization_mode=normalization_mode)
|
||||
fuel.volume, nuclides,'atom/b-cm', micro_xs, chain_file, normalization_mode=normalization_mode)
|
||||
|
||||
else:
|
||||
op = FluxDepletionOperator(openmc.Materials([fuel]), micro_xs, chain_file, normalization_mode=normalization_mode)
|
||||
|
|
@ -67,14 +66,14 @@ def test_no_transport_from_nuclides(run_in_tmpdir, fuel, multiproc, from_nuclide
|
|||
# Perform simulation using the predictor algorithm
|
||||
openmc.deplete.pool.USE_MULTIPROCESSING = multiproc
|
||||
openmc.deplete.PredictorIntegrator(
|
||||
op, dt, power=power, flux=flux, timestep_units='d').integrate()
|
||||
op, dt, power=power, source_rates=flux, timestep_units='d').integrate()
|
||||
|
||||
# Get path to test and reference results
|
||||
path_test = op.output_dir / 'depletion_results.h5'
|
||||
if flux is not None:
|
||||
ref_path = 'test_reference_constant_flux.h5'
|
||||
ref_path = 'test_reference_source_rate.h5'
|
||||
else:
|
||||
ref_path = 'test_reference_constant_power.h5'
|
||||
ref_path = 'test_reference_fission_q.h5'
|
||||
path_reference = Path(__file__).with_name(ref_path)
|
||||
|
||||
# Load the reference/test results
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -71,7 +71,7 @@ def test_operator_init():
|
|||
'O17': 1.7588724018066158e+19}
|
||||
micro_xs = FluxDepletionOperator.create_micro_xs_from_csv(ONE_GROUP_XS)
|
||||
nuclide_flux_operator = FluxDepletionOperator.from_nuclides(
|
||||
volume, nuclides, micro_xs, CHAIN_PATH)
|
||||
volume, nuclides, 'atom/cm3', micro_xs, CHAIN_PATH)
|
||||
|
||||
fuel = Material(name="uo2")
|
||||
fuel.add_element("U", 1, percent_type="ao", enrichment=4.25)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue