mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-25 20:45:35 -04:00
Merge pull request #2211 from paulromano/config
Allow configuration of data sources via openmc.config
This commit is contained in:
commit
ffe336c2ef
16 changed files with 299 additions and 172 deletions
|
|
@ -1,55 +1,73 @@
|
|||
.. _usersguide_cross_sections:
|
||||
.. _usersguide_data:
|
||||
|
||||
===========================
|
||||
Cross Section Configuration
|
||||
===========================
|
||||
==================
|
||||
Data Configuration
|
||||
==================
|
||||
|
||||
In order to run a simulation with OpenMC, you will need cross section data for
|
||||
each nuclide or material in your problem. OpenMC can be run in continuous-energy
|
||||
or multi-group mode.
|
||||
OpenMC relies on a variety of physical data in order to carry out transport
|
||||
simulations, depletion simulations, and other common tasks. As a user, you are
|
||||
responsible for specifying one or more of the following:
|
||||
|
||||
In continuous-energy mode, OpenMC uses a native `HDF5
|
||||
<https://support.hdfgroup.org/HDF5/>`_ format (see :ref:`io_nuclear_data`) to
|
||||
store all nuclear data. Pregenerated HDF5 libraries can be found at
|
||||
https://openmc.org; unless you have specific data needs, it is highly
|
||||
recommended to use one of the pregenerated libraries. Alternatively, if you have
|
||||
ACE format data that was produced with NJOY_, such as that distributed with
|
||||
MCNP_ or Serpent_, it can be converted to the HDF5 format using the :ref:`using
|
||||
the Python API <create_xs_library>`. Several sources provide openly available
|
||||
ACE data including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the
|
||||
`LANL Nuclear Data Team <https://nucleardata.lanl.gov/>`_. In addition to
|
||||
tabulated cross sections in the HDF5 files, OpenMC relies on :ref:`windowed
|
||||
multipole <windowed_multipole>` data to perform on-the-fly Doppler broadening.
|
||||
- **Cross sections (XML)** -- A :ref:`cross sections XML <io_cross_sections>`
|
||||
file (commonly named ``cross_sections.xml``) contains a listing of other data
|
||||
files, in particular neutron cross sections, photon cross sections, and
|
||||
windowed multipole data. Each of those files, in turn, uses a `HDF5
|
||||
<https://support.hdfgroup.org/HDF5/>`_ format (see :ref:`io_nuclear_data`). In
|
||||
order to run transport simulations with continuous-energy cross sections, you
|
||||
need to specify this file.
|
||||
|
||||
In multi-group mode, OpenMC utilizes an HDF5-based library format which can be
|
||||
used to describe nuclide- or material-specific quantities.
|
||||
- **Depletion chain (XML)** -- A :ref:`depletion chain XML <io_depletion_chain>`
|
||||
file contains decay data, fission product yields, and information on what
|
||||
neutron reactions can result in transmutation. This file is needed for
|
||||
depletion/activation calculations as well as some basic functions in the
|
||||
:mod:`openmc.data` module.
|
||||
|
||||
- **Multigroup cross sections (HDF5)** -- OpenMC can also perform transport
|
||||
simulations using multigroup data. In this case, multigroup cross sections are
|
||||
stored in a single :ref:`HDF5 file <io_mgxs_library>`. Thus, in order to run a
|
||||
multigroup transport simulation, this file needs to be specified.
|
||||
|
||||
Each of the above files can specified in several ways. In the Python API, a
|
||||
:ref:`runtime configuration variable <usersguide_data_runtime>`
|
||||
:data:`openmc.config` can be used to specify any of the above and is initialized
|
||||
using a set of environment variables.
|
||||
|
||||
.. _usersguide_data_runtime:
|
||||
|
||||
---------------------
|
||||
Environment Variables
|
||||
Runtime Configuration
|
||||
---------------------
|
||||
|
||||
When :ref:`scripts_openmc` is run, it will look for several environment
|
||||
variables that indicate where cross sections can be found. While the location of
|
||||
cross sections can also be indicated through the
|
||||
:attr:`openmc.Materials.cross_sections` attribute (or in the :ref:`materials.xml
|
||||
<io_materials>` file), if you always use the same set of cross section data, it
|
||||
is often easier to just set an environment variable that will be picked up by
|
||||
default every time OpenMC is run. The following environment variables are used:
|
||||
Data sources for OpenMC can be specified at runtime in Python using the
|
||||
:data:`openmc.config` variable. This variable acts like a dictionary and stores
|
||||
key-values pairs, where the values are file paths (strings or path-like objects)
|
||||
and the key can be one of the following:
|
||||
|
||||
:envvar:`OPENMC_CROSS_SECTIONS`
|
||||
Indicates the path to the :ref:`cross_sections.xml <io_cross_sections>`
|
||||
summary file that is used to locate HDF5 format cross section libraries if the
|
||||
user has not specified :attr:`openmc.Materials.cross_sections` (equivalently,
|
||||
the :ref:`cross_sections` in :ref:`materials.xml <io_materials>`).
|
||||
``"cross_sections"``
|
||||
Indicates the path to the :ref:`cross sections XML <io_cross_sections>` file
|
||||
that lists HDF5 format neutron cross sections, photon cross sections, and
|
||||
windowed multipole data. At startup, this is initialized with the value of the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable. Note that the
|
||||
:attr:`openmc.Materials.cross_sections` attribute will override this, if
|
||||
specified.
|
||||
|
||||
:envvar:`OPENMC_MG_CROSS_SECTIONS`
|
||||
``"chain_file"``
|
||||
Indicates the path to the :ref:`depletion chain XML <io_depletion_chain>` file
|
||||
that contains decay data, fission product yields, and what neutron reactions
|
||||
may result in transmutation of a target nuclide. At startup, this is
|
||||
initialized with the value of the :envvar:`OPENMC_CHAIN_FILE` environment
|
||||
variable.
|
||||
|
||||
``"mg_cross_sections"``
|
||||
Indicates the path to an :ref:`HDF5 file <io_mgxs_library>` that contains
|
||||
multi-group cross sections if the user has not specified
|
||||
:attr:`openmc.Materials.cross_sections` (equivalently, the
|
||||
:ref:`cross_sections` in :ref:`materials.xml <io_materials>`).
|
||||
multigroup cross sections. At startup, this is initialized with the value of
|
||||
the :envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable. Note that the
|
||||
:attr:`openmc.Materials.cross_sections` attribute will override this if
|
||||
specified.
|
||||
|
||||
To set these environment variables persistently, export them from your shell
|
||||
profile (``.profile`` or ``.bashrc`` in bash_).
|
||||
If you want to persistently set the environment variables used to initialized
|
||||
the configuration, export them from your shell profile (``.profile`` or
|
||||
``.bashrc`` in bash_).
|
||||
|
||||
.. _bash: http://www.linuxfromscratch.org/blfs/view/6.3/postlfs/profile.html
|
||||
|
||||
|
|
@ -61,12 +79,13 @@ Using Pregenerated Libraries
|
|||
----------------------------
|
||||
|
||||
Various evaluated nuclear data libraries have been processed into the HDF5
|
||||
format required by OpenMC and can be found at https://openmc.org. You
|
||||
can find both libraries generated by the OpenMC development team as well as
|
||||
libraries based on ACE files distributed elsewhere. To use these libraries,
|
||||
download the archive file, unpack it, and then set your
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable to the absolute path of
|
||||
the ``cross_sections.xml`` file contained in the unpacked directory.
|
||||
format required by OpenMC and can be found at https://openmc.org. Unless you
|
||||
have specific data needs, it is highly recommended to use one of the
|
||||
pregenerated libraries. You can find both libraries generated by the OpenMC
|
||||
development team as well as libraries based on ACE files distributed elsewhere.
|
||||
To use these libraries, download the archive file, unpack it, and then specify
|
||||
the path of the ``cross_sections.xml`` file contained in the unpacked directory
|
||||
as described in :ref:`usersguide_data_runtime`.
|
||||
|
||||
.. _create_xs_library:
|
||||
|
||||
|
|
@ -75,6 +94,12 @@ Manually Creating a Library from ACE files
|
|||
|
||||
.. currentmodule:: openmc.data
|
||||
|
||||
If you have ACE format data that was produced with NJOY_, such as that
|
||||
distributed with MCNP_ or Serpent_, it can be converted to the HDF5 format using
|
||||
the using the Python API. Several sources provide openly available ACE data
|
||||
including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the `LANL
|
||||
Nuclear Data Team <https://nucleardata.lanl.gov/>`_.
|
||||
|
||||
The :mod:`openmc.data` module in the Python API enables users to directly
|
||||
convert ACE data to OpenMC's HDF5 format and create a corresponding
|
||||
:ref:`cross_sections.xml <io_cross_sections>` file. For those who prefer to use
|
||||
|
|
@ -224,6 +249,19 @@ relaxation sublibrary files are required:
|
|||
Once the HDF5 files have been generated, a library can be created using the
|
||||
:class:`DataLibrary` class as described in :ref:`create_xs_library`.
|
||||
|
||||
-----------
|
||||
Chain Files
|
||||
-----------
|
||||
|
||||
Pregenerated depletion chain XML files can be found at https://openmc.org.
|
||||
Additionally, depletion chains can be generated using the
|
||||
:class:`openmc.deplete.Chain` class. In particular, the
|
||||
:meth:`~openmc.deplete.Chain.from_endf` method allows a chain to be generated
|
||||
starting from a set of ENDF incident neutron, decay, and fission product yield
|
||||
sublibrary files. Once you've downloaded or generated a depletion chain XML
|
||||
file, make sure to specify its path as described in
|
||||
:ref:`usersguide_data_runtime`.
|
||||
|
||||
-----------------------
|
||||
Windowed Multipole Data
|
||||
-----------------------
|
||||
|
|
@ -241,18 +279,16 @@ The `official ENDF/B-VII.1 HDF5 library
|
|||
multipole library, so if you are using this library, the windowed multipole data
|
||||
will already be available to you.
|
||||
|
||||
--------------------------
|
||||
Multi-Group Cross Sections
|
||||
--------------------------
|
||||
-------------------------
|
||||
Multigroup Cross Sections
|
||||
-------------------------
|
||||
|
||||
Multi-group cross section libraries are generally tailored to the specific
|
||||
Multigroup cross section libraries are generally tailored to the specific
|
||||
calculation to be performed. Therefore, at this point in time, OpenMC is not
|
||||
distributed with any pre-existing multi-group cross section libraries.
|
||||
However, if obtained or generated their own library, the user
|
||||
should set the :envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable
|
||||
to the absolute path of the file library expected to used most frequently.
|
||||
|
||||
For an example of how to create a multi-group library, see the `example notebook
|
||||
distributed with any pre-existing multigroup cross section libraries. However,
|
||||
if a multigroup library file is downloaded or generated, the path to the file
|
||||
needs to be specified as described in :ref:`usersguide_data_runtime`. For an
|
||||
example of how to create a multigroup library, see the `example notebook
|
||||
<../examples/mg-mode-part-i.ipynb>`__.
|
||||
|
||||
.. _NJOY: http://www.njoy21.io/
|
||||
|
|
@ -13,7 +13,7 @@ essential aspects of using OpenMC to perform simulations.
|
|||
|
||||
beginners
|
||||
install
|
||||
cross_sections
|
||||
data
|
||||
basics
|
||||
materials
|
||||
geometry
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ from openmc.search import *
|
|||
from openmc.polynomial import *
|
||||
from openmc.tracks import *
|
||||
from . import examples
|
||||
from .config import *
|
||||
|
||||
# Import a few names from the model module
|
||||
from openmc.model import rectangular_prism, hexagonal_prism, Model
|
||||
|
|
|
|||
83
openmc/config.py
Normal file
83
openmc/config.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
from collections.abc import MutableMapping
|
||||
import os
|
||||
from pathlib import Path
|
||||
import warnings
|
||||
|
||||
from openmc.data import DataLibrary
|
||||
|
||||
__all__ = ["config"]
|
||||
|
||||
|
||||
class _Config(MutableMapping):
|
||||
def __init__(self, data=()):
|
||||
self._mapping = {}
|
||||
self.update(data)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._mapping[key]
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._mapping[key]
|
||||
if key == 'cross_sections':
|
||||
del os.environ['OPENMC_CROSS_SECTIONS']
|
||||
elif key == 'mg_cross_sections':
|
||||
del os.environ['OPENMC_MG_CROSS_SECTIONS']
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key == 'cross_sections':
|
||||
# Force environment variable to match
|
||||
self._set_path(key, value)
|
||||
os.environ['OPENMC_CROSS_SECTIONS'] = str(value)
|
||||
elif key == 'mg_cross_sections':
|
||||
self._set_path(key, value)
|
||||
os.environ['OPENMC_MG_CROSS_SECTIONS'] = str(value)
|
||||
elif key == 'chain_file':
|
||||
self._set_path(key, value)
|
||||
os.environ['OPENMC_CHAIN_FILE'] = str(value)
|
||||
else:
|
||||
raise KeyError(f'Unrecognized config key: {key}')
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._mapping)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._mapping)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self._mapping)
|
||||
|
||||
def _set_path(self, key, value):
|
||||
self._mapping[key] = p = Path(value)
|
||||
if not p.exists():
|
||||
warnings.warn(f"'{value}' does not exist.")
|
||||
|
||||
|
||||
def _default_config():
|
||||
"""Return default configuration"""
|
||||
config = _Config()
|
||||
|
||||
# Set cross sections using environment variable
|
||||
if "OPENMC_CROSS_SECTIONS" in os.environ:
|
||||
config['cross_sections'] = os.environ["OPENMC_CROSS_SECTIONS"]
|
||||
if "OPENMC_MG_CROSS_SECTIONS" in os.environ:
|
||||
config['mg_cross_sections'] = os.environ["OPENMC_MG_CROSS_SECTIONS"]
|
||||
|
||||
# Set depletion chain
|
||||
chain_file = os.environ.get("OPENMC_CHAIN_FILE")
|
||||
if (chain_file is None and
|
||||
config.get('cross_sections') is not None and
|
||||
config['cross_sections'].exists()
|
||||
):
|
||||
# Check for depletion chain in cross_sections.xml
|
||||
data = DataLibrary.from_xml(config['cross_sections'])
|
||||
for lib in reversed(data.libraries):
|
||||
if lib['type'] == 'depletion_chain':
|
||||
chain_file = lib['path']
|
||||
break
|
||||
if chain_file is not None:
|
||||
config['chain_file'] = chain_file
|
||||
|
||||
return config
|
||||
|
||||
|
||||
config = _default_config()
|
||||
|
|
@ -4,6 +4,7 @@ import pathlib
|
|||
|
||||
import h5py
|
||||
|
||||
import openmc
|
||||
from openmc.mixin import EqualityMixin
|
||||
from openmc._xml import clean_indentation, reorder_attributes
|
||||
|
||||
|
|
@ -124,8 +125,8 @@ class DataLibrary(EqualityMixin):
|
|||
Parameters
|
||||
----------
|
||||
path : str, optional
|
||||
Path to XML file to read. If not provided, the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used.
|
||||
Path to XML file to read. If not provided,
|
||||
openmc.config['cross_sections'] will be used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -136,15 +137,14 @@ class DataLibrary(EqualityMixin):
|
|||
|
||||
data = cls()
|
||||
|
||||
# If path is None, get the cross sections from the
|
||||
# OPENMC_CROSS_SECTIONS environment variable
|
||||
# If path is None, get the cross sections from the global configuration
|
||||
if path is None:
|
||||
path = os.environ.get('OPENMC_CROSS_SECTIONS')
|
||||
path = openmc.config.get('cross_sections')
|
||||
|
||||
# Check to make sure there was an environmental variable.
|
||||
# Check to make sure we picked up cross sections
|
||||
if path is None:
|
||||
raise ValueError("Either path or OPENMC_CROSS_SECTIONS "
|
||||
"environmental variable must be set")
|
||||
raise ValueError("Either path or openmc.config['cross_sections'] "
|
||||
"must be set")
|
||||
|
||||
tree = ET.parse(path)
|
||||
root = tree.getroot()
|
||||
|
|
@ -162,7 +162,6 @@ class DataLibrary(EqualityMixin):
|
|||
data.libraries.append(library)
|
||||
|
||||
# get depletion chain data
|
||||
|
||||
dep_node = root.find("depletion_chain")
|
||||
if dep_node is not None:
|
||||
filename = os.path.join(directory, dep_node.attrib['path'])
|
||||
|
|
|
|||
|
|
@ -239,24 +239,6 @@ def replace_missing_fpy(actinide, fpy_data, decay_data):
|
|||
return 'U235'
|
||||
|
||||
|
||||
def _find_chain_file(cross_sections=None):
|
||||
# First check deprecated OPENMC_DEPLETE_CHAIN environment variable
|
||||
chain_file = os.environ.get("OPENMC_DEPLETE_CHAIN")
|
||||
if chain_file is not None:
|
||||
warn("Use of OPENMC_DEPLETE_CHAIN is deprecated in favor of adding "
|
||||
"depletion_chain to OPENMC_CROSS_SECTIONS", FutureWarning)
|
||||
return chain_file
|
||||
|
||||
# Check for depletion chain in cross_sections.xml
|
||||
data = DataLibrary.from_xml(cross_sections)
|
||||
for lib in reversed(data.libraries):
|
||||
if lib['type'] == 'depletion_chain':
|
||||
return lib['path']
|
||||
|
||||
raise DataError("No depletion chain specified and could not find depletion "
|
||||
f"chain in {cross_sections}")
|
||||
|
||||
|
||||
class Chain:
|
||||
"""Full representation of a depletion chain.
|
||||
|
||||
|
|
@ -265,9 +247,8 @@ class Chain:
|
|||
yield sublibrary files. The depletion chain used during a depletion
|
||||
simulation is indicated by either an argument to
|
||||
:class:`openmc.deplete.CoupledOperator` or
|
||||
:class:`openmc.deplete.IndependentOperator`, or through the
|
||||
``depletion_chain`` item in the :envvar:`OPENMC_CROSS_SECTIONS`
|
||||
environment variable.
|
||||
:class:`openmc.deplete.IndependentOperator`, or through
|
||||
openmc.config['chain_file'].
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ filesystem.
|
|||
"""
|
||||
|
||||
import copy
|
||||
import os
|
||||
from warnings import warn
|
||||
|
||||
import numpy as np
|
||||
|
|
@ -22,7 +21,6 @@ from openmc.exceptions import DataError
|
|||
import openmc.lib
|
||||
from openmc.mpi import comm
|
||||
from .abc import OperatorResult
|
||||
from .chain import _find_chain_file
|
||||
from .openmc_operator import OpenMCOperator, _distribute
|
||||
from .results import Results
|
||||
from .helpers import (
|
||||
|
|
@ -48,11 +46,11 @@ def _find_cross_sections(model):
|
|||
return model.materials.cross_sections
|
||||
|
||||
# otherwise fallback to environment variable
|
||||
cross_sections = os.environ.get("OPENMC_CROSS_SECTIONS")
|
||||
cross_sections = openmc.config.get("cross_sections")
|
||||
if cross_sections is None:
|
||||
raise DataError(
|
||||
"Cross sections were not specified in Model.materials and "
|
||||
"the OPENMC_CROSS_SECTIONS environment variable is not set."
|
||||
"openmc.config['cross_sections'] is not set."
|
||||
)
|
||||
return cross_sections
|
||||
|
||||
|
|
@ -103,9 +101,8 @@ class CoupledOperator(OpenMCOperator):
|
|||
model : openmc.model.Model
|
||||
OpenMC model object
|
||||
chain_file : str, optional
|
||||
Path to the depletion chain XML file. Defaults to the file
|
||||
listed under ``depletion_chain`` in
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable.
|
||||
Path to the depletion chain XML file. Defaults to
|
||||
``openmc.config['chain_file']``.
|
||||
prev_results : Results, optional
|
||||
Results from a previous depletion calculation. If this argument is
|
||||
specified, the depletion calculation will start from the latest state
|
||||
|
|
@ -231,10 +228,8 @@ class CoupledOperator(OpenMCOperator):
|
|||
" model with which to generate the transport Operator."
|
||||
raise TypeError(msg)
|
||||
|
||||
# Determine cross sections / depletion chain
|
||||
# Determine cross sections
|
||||
cross_sections = _find_cross_sections(model)
|
||||
if chain_file is None:
|
||||
chain_file = _find_chain_file(cross_sections)
|
||||
|
||||
check_value('fission yield mode', fission_yield_mode,
|
||||
self._fission_helpers.keys())
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ class IndependentOperator(OpenMCOperator):
|
|||
micro_xs : MicroXS
|
||||
One-group microscopic cross sections in [b] .
|
||||
chain_file : str
|
||||
Path to the depletion chain XML file.
|
||||
Path to the depletion chain XML file. Defaults to
|
||||
``openmc.config['chain_file']``.
|
||||
keff : 2-tuple of float, optional
|
||||
keff eigenvalue and uncertainty from transport calculation.
|
||||
Default is None.
|
||||
|
|
@ -111,7 +112,7 @@ class IndependentOperator(OpenMCOperator):
|
|||
def __init__(self,
|
||||
materials,
|
||||
micro_xs,
|
||||
chain_file,
|
||||
chain_file=None,
|
||||
keff=None,
|
||||
normalization_mode='fission-q',
|
||||
fission_q=None,
|
||||
|
|
|
|||
|
|
@ -5,18 +5,16 @@ nuclide names as row indices and reaction names as column indices.
|
|||
"""
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from copy import deepcopy
|
||||
|
||||
from pandas import DataFrame, read_csv, concat
|
||||
from pandas import DataFrame, read_csv
|
||||
import numpy as np
|
||||
|
||||
from openmc.checkvalue import check_type, check_value, check_iterable_type
|
||||
from openmc.exceptions import DataError
|
||||
from openmc.mgxs import EnergyGroups, ArbitraryXS, FissionXS
|
||||
from openmc.data import DataLibrary
|
||||
from openmc import Tallies, StatePoint, Materials, Material
|
||||
|
||||
|
||||
from openmc import Tallies, StatePoint, Materials
|
||||
import openmc
|
||||
from .chain import Chain, REACTIONS
|
||||
from .coupled_operator import _find_cross_sections, _get_nuclides_with_data
|
||||
|
||||
|
|
@ -35,7 +33,7 @@ class MicroXS(DataFrame):
|
|||
def from_model(cls,
|
||||
model,
|
||||
reaction_domain,
|
||||
chain_file,
|
||||
chain_file=None,
|
||||
dilute_initial=1.0e3,
|
||||
energy_bounds=(0, 20e6),
|
||||
run_kwargs=None):
|
||||
|
|
@ -48,11 +46,12 @@ class MicroXS(DataFrame):
|
|||
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.
|
||||
chain_file : str
|
||||
chain_file : str, optional
|
||||
Path to the depletion chain XML file that will be used in depletion
|
||||
simulation. Used to determine cross sections for materials not
|
||||
present in the inital composition.
|
||||
dilute_initial : float
|
||||
present in the inital composition. Defaults to
|
||||
``openmc.config['chain_file']``.
|
||||
dilute_initial : float, optional
|
||||
Initial atom density [atoms/cm^3] to add for nuclides that
|
||||
are zero in initial condition to ensure they exist in the cross
|
||||
section data. Only done for nuclides with reaction rates.
|
||||
|
|
@ -144,6 +143,13 @@ class MicroXS(DataFrame):
|
|||
:class:`openmc.Materials` object with nuclides added to burnable
|
||||
materials.
|
||||
"""
|
||||
if chain_file is None:
|
||||
chain_file = openmc.config.get('chain_file')
|
||||
if chain_file is None:
|
||||
raise DataError(
|
||||
"No depletion chain specified and could not find depletion "
|
||||
"chain in openmc.config['chain_file']"
|
||||
)
|
||||
chain = Chain.from_xml(chain_file)
|
||||
reactions = chain.reactions
|
||||
cross_sections = _find_cross_sections(model)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from collections import OrderedDict
|
|||
import numpy as np
|
||||
|
||||
import openmc
|
||||
from openmc.exceptions import DataError
|
||||
from openmc.mpi import comm
|
||||
from .abc import TransportOperator, OperatorResult
|
||||
from .atom_number import AtomNumber
|
||||
|
|
@ -57,9 +58,8 @@ class OpenMCOperator(TransportOperator):
|
|||
Path to continuous energy cross section library, or object containing
|
||||
one-group cross-sections.
|
||||
chain_file : str, optional
|
||||
Path to the depletion chain XML file. Defaults to the file
|
||||
listed under ``depletion_chain`` in
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable.
|
||||
Path to the depletion chain XML file. Defaults to
|
||||
openmc.config['chain_file'].
|
||||
prev_results : Results, optional
|
||||
Results from a previous depletion calculation. If this argument is
|
||||
specified, the depletion calculation will start from the latest state
|
||||
|
|
@ -83,7 +83,6 @@ class OpenMCOperator(TransportOperator):
|
|||
if ``reduce_chain`` evaluates to true. The default value of
|
||||
``None`` implies no limit on the depth.
|
||||
|
||||
|
||||
Attributes
|
||||
----------
|
||||
materials : openmc.Materials
|
||||
|
|
@ -133,6 +132,15 @@ class OpenMCOperator(TransportOperator):
|
|||
reduce_chain=False,
|
||||
reduce_chain_level=None):
|
||||
|
||||
# If chain file was not specified, try to get it from global config
|
||||
if chain_file is None:
|
||||
chain_file = openmc.config.get('chain_file')
|
||||
if chain_file is None:
|
||||
raise DataError(
|
||||
"No depletion chain specified and could not find depletion "
|
||||
"chain in openmc.config['chain_file']"
|
||||
)
|
||||
|
||||
super().__init__(chain_file, fission_q, dilute_initial, prev_results)
|
||||
self.round_number = False
|
||||
self.materials = materials
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ class Results(list):
|
|||
as such cannot be used in subsequent transport calculations.
|
||||
If not provided, nuclides from the cross_sections element of
|
||||
materials.xml will be used. If that element is not present,
|
||||
nuclides from OPENMC_CROSS_SECTIONS will be used.
|
||||
nuclides from openmc.config['cross_sections'] will be used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -412,7 +412,7 @@ class Results(list):
|
|||
# the new materials XML file. The precedence of nuclides to select
|
||||
# is first ones provided as a kwarg here, then ones specified
|
||||
# in the materials.xml file if provided, then finally from
|
||||
# the environment variable OPENMC_CROSS_SECTIONS.
|
||||
# openmc.config['cross_sections'].
|
||||
if nuc_with_data:
|
||||
cv.check_iterable_type('nuclide names', nuc_with_data, str)
|
||||
available_cross_sections = nuc_with_data
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
from collections import OrderedDict
|
||||
import os
|
||||
import re
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
import openmc
|
||||
from openmc.data import NATURAL_ABUNDANCE, atomic_mass, \
|
||||
isotopes as natural_isotopes
|
||||
|
||||
|
|
@ -40,10 +40,10 @@ class Element(str):
|
|||
cross_sections=None):
|
||||
"""Expand natural element into its naturally-occurring isotopes.
|
||||
|
||||
An optional cross_sections argument or the :envvar:`OPENMC_CROSS_SECTIONS`
|
||||
environment variable is used to specify a cross_sections.xml file.
|
||||
If the cross_sections.xml file is found, the element is expanded only
|
||||
into the isotopes/nuclides present in cross_sections.xml. If no
|
||||
An optional cross_sections argument or the ``cross_sections``
|
||||
configuration value is used to specify a cross_sections.xml file. If the
|
||||
cross_sections.xml file is found, the element is expanded only into the
|
||||
isotopes/nuclides present in cross_sections.xml. If no
|
||||
cross_sections.xml file is found, the element is expanded based on its
|
||||
naturally occurring isotopes.
|
||||
|
||||
|
|
@ -54,12 +54,13 @@ class Element(str):
|
|||
percent_type : {'ao', 'wo'}
|
||||
'ao' for atom percent and 'wo' for weight percent
|
||||
enrichment : float, optional
|
||||
Enrichment of an enrichment_target nuclide in percent (ao or wo).
|
||||
If enrichment_target is not supplied then it is enrichment for U235
|
||||
in weight percent. For example, input 4.95 for 4.95 weight percent
|
||||
Enrichment of an enrichment_target nuclide in percent (ao or wo). If
|
||||
enrichment_target is not supplied then it is enrichment for U235 in
|
||||
weight percent. For example, input 4.95 for 4.95 weight percent
|
||||
enriched U. Default is None (natural composition).
|
||||
enrichment_target: str, optional
|
||||
Single nuclide name to enrich from a natural composition (e.g., 'O16')
|
||||
Single nuclide name to enrich from a natural composition (e.g.,
|
||||
'O16')
|
||||
|
||||
.. versionadded:: 0.12
|
||||
enrichment_type: {'ao', 'wo'}, optional
|
||||
|
|
@ -82,8 +83,8 @@ class Element(str):
|
|||
ValueError
|
||||
No data is available for any of natural isotopes of the element
|
||||
ValueError
|
||||
If only some natural isotopes are available in the cross-section data
|
||||
library and the element is not O, W, or Ta
|
||||
If only some natural isotopes are available in the cross-section
|
||||
data library and the element is not O, W, or Ta
|
||||
ValueError
|
||||
If a non-naturally-occurring isotope is requested
|
||||
ValueError
|
||||
|
|
@ -101,8 +102,8 @@ class Element(str):
|
|||
`ORNL/CSD/TM-244 <https://doi.org/10.2172/5561567>`_ is used to
|
||||
calculate the weight fractions of U234, U235, U236, and U238. Namely,
|
||||
the weight fraction of U234 and U236 are taken to be 0.89% and 0.46%,
|
||||
respectively, of the U235 weight fraction. The remainder of the
|
||||
isotopic weight is assigned to U238.
|
||||
respectively, of the U235 weight fraction. The remainder of the isotopic
|
||||
weight is assigned to U238.
|
||||
|
||||
When the `enrichment` argument is specified with `enrichment_target`, a
|
||||
general enrichment procedure is used for elements composed of exactly
|
||||
|
|
@ -125,10 +126,10 @@ class Element(str):
|
|||
# Create dict to store the expanded nuclides and abundances
|
||||
abundances = OrderedDict()
|
||||
|
||||
# If cross_sections is None, get the cross sections from the
|
||||
# OPENMC_CROSS_SECTIONS environment variable
|
||||
# If cross_sections is None, get the cross sections from the global
|
||||
# configuration
|
||||
if cross_sections is None:
|
||||
cross_sections = os.environ.get('OPENMC_CROSS_SECTIONS')
|
||||
cross_sections = openmc.config.get('cross_sections')
|
||||
|
||||
# If a cross_sections library is present, check natural nuclides
|
||||
# against the nuclides in the library
|
||||
|
|
|
|||
|
|
@ -1310,9 +1310,8 @@ class Materials(cv.CheckedList):
|
|||
"""Collection of Materials used for an OpenMC simulation.
|
||||
|
||||
This class corresponds directly to the materials.xml input file. It can be
|
||||
thought of as a normal Python list where each member is a
|
||||
:class:`Material`. It behaves like a list as the following example
|
||||
demonstrates:
|
||||
thought of as a normal Python list where each member is a :class:`Material`.
|
||||
It behaves like a list as the following example demonstrates:
|
||||
|
||||
>>> fuel = openmc.Material()
|
||||
>>> clad = openmc.Material()
|
||||
|
|
@ -1332,9 +1331,9 @@ class Materials(cv.CheckedList):
|
|||
Indicates the path to an XML cross section listing file (usually named
|
||||
cross_sections.xml). If it is not set, the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used for
|
||||
continuous-energy calculations and
|
||||
:envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group
|
||||
calculations to find the path to the HDF5 cross section file.
|
||||
continuous-energy calculations and :envvar:`OPENMC_MG_CROSS_SECTIONS`
|
||||
will be used for multi-group calculations to find the path to the HDF5
|
||||
cross section file.
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import copy
|
||||
from numbers import Real, Integral
|
||||
import os
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
|
|
@ -2536,8 +2535,7 @@ class MGXSLibrary:
|
|||
----------
|
||||
filename : str, optional
|
||||
Name of HDF5 file containing MGXS data. Default is None.
|
||||
If not provided, the value of the OPENMC_MG_CROSS_SECTIONS
|
||||
environmental variable will be used
|
||||
If not provided, openmc.config['mg_cross_sections'] will be used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -2545,15 +2543,14 @@ class MGXSLibrary:
|
|||
Multi-group cross section data object.
|
||||
|
||||
"""
|
||||
# If filename is None, get the cross sections from the
|
||||
# OPENMC_CROSS_SECTIONS environment variable
|
||||
# If filename is None, get the cross sections from openmc.config
|
||||
if filename is None:
|
||||
filename = os.environ.get('OPENMC_MG_CROSS_SECTIONS')
|
||||
filename = openmc.config.get('mg_cross_sections')
|
||||
|
||||
# Check to make sure there was an environmental variable.
|
||||
if filename is None:
|
||||
raise ValueError("Either path or OPENMC_MG_CROSS_SECTIONS "
|
||||
"environmental variable must be set")
|
||||
raise ValueError("Either path or openmc.config['mg_cross_sections']"
|
||||
"must be set")
|
||||
|
||||
check_type('filename', filename, str)
|
||||
file = h5py.File(filename, 'r')
|
||||
|
|
|
|||
43
tests/unit_tests/test_config.py
Normal file
43
tests/unit_tests/test_config.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
from collections.abc import Mapping
|
||||
import os
|
||||
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope='module')
|
||||
def reset_config():
|
||||
config = dict(openmc.config)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
openmc.config.clear()
|
||||
openmc.config.update(config)
|
||||
|
||||
|
||||
def test_config_basics():
|
||||
assert isinstance(openmc.config, Mapping)
|
||||
for key, value in openmc.config.items():
|
||||
assert isinstance(key, str)
|
||||
assert isinstance(value, os.PathLike)
|
||||
|
||||
# Set and delete
|
||||
openmc.config['cross_sections'] = '/path/to/cross_sections.xml'
|
||||
del openmc.config['cross_sections']
|
||||
assert 'cross_sections' not in openmc.config
|
||||
assert 'OPENMC_CROSS_SECTIONS' not in os.environ
|
||||
|
||||
# Can't use any key
|
||||
with pytest.raises(KeyError):
|
||||
openmc.config['🐖'] = '/like/to/eat/bacon'
|
||||
|
||||
|
||||
def test_config_set_envvar():
|
||||
openmc.config['cross_sections'] = '/path/to/cross_sections.xml'
|
||||
assert os.environ['OPENMC_CROSS_SECTIONS'] == '/path/to/cross_sections.xml'
|
||||
|
||||
openmc.config['mg_cross_sections'] = '/path/to/mg_cross_sections.h5'
|
||||
assert os.environ['OPENMC_MG_CROSS_SECTIONS'] == '/path/to/mg_cross_sections.h5'
|
||||
|
||||
openmc.config['chain_file'] = '/path/to/chain_file.xml'
|
||||
assert os.environ['OPENMC_CHAIN_FILE'] == '/path/to/chain_file.xml'
|
||||
|
|
@ -1,37 +1,15 @@
|
|||
"""Basic unit tests for openmc.deplete.Operator instantiation
|
||||
|
||||
Modifies and resets environment variable OPENMC_CROSS_SECTIONS
|
||||
to a custom file with new depletion_chain node
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from openmc.deplete.abc import TransportOperator
|
||||
from openmc.deplete.chain import Chain, _find_chain_file
|
||||
from openmc.deplete.chain import Chain
|
||||
|
||||
BARE_XS_FILE = "bare_cross_sections.xml"
|
||||
CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def bare_xs(run_in_tmpdir):
|
||||
"""Create a very basic cross_sections file, return simple Chain.
|
||||
|
||||
"""
|
||||
|
||||
bare_xs_contents = """<?xml version="1.0"?>
|
||||
<cross_sections>
|
||||
<depletion_chain path="{}" />
|
||||
</cross_sections>
|
||||
""".format(CHAIN_PATH)
|
||||
|
||||
with open(BARE_XS_FILE, "w") as out:
|
||||
out.write(bare_xs_contents)
|
||||
|
||||
yield BARE_XS_FILE
|
||||
|
||||
|
||||
class BareDepleteOperator(TransportOperator):
|
||||
"""Very basic class for testing the initialization."""
|
||||
|
||||
|
|
@ -52,10 +30,10 @@ class BareDepleteOperator(TransportOperator):
|
|||
pass
|
||||
|
||||
|
||||
def test_operator_init(bare_xs):
|
||||
def test_operator_init():
|
||||
"""The test uses a temporary dummy chain. This file will be removed
|
||||
at the end of the test, and only contains a depletion_chain node."""
|
||||
bare_op = BareDepleteOperator(_find_chain_file(bare_xs))
|
||||
bare_op = BareDepleteOperator(CHAIN_PATH)
|
||||
act_chain = bare_op.chain
|
||||
ref_chain = Chain.from_xml(CHAIN_PATH)
|
||||
assert len(act_chain) == len(ref_chain)
|
||||
|
|
@ -73,8 +51,7 @@ def test_operator_init(bare_xs):
|
|||
def test_operator_fiss_q():
|
||||
"""Make sure fission q values can be set"""
|
||||
new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7}
|
||||
chain_file = Path(__file__).parents[1] / "chain_simple.xml"
|
||||
operator = BareDepleteOperator(chain_file=chain_file, fission_q=new_q)
|
||||
operator = BareDepleteOperator(chain_file=CHAIN_PATH, fission_q=new_q)
|
||||
mod_chain = operator.chain
|
||||
for name, q in new_q.items():
|
||||
chain_nuc = mod_chain[name]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue