Merge pull request #2211 from paulromano/config

Allow configuration of data sources via openmc.config
This commit is contained in:
Jonathan Shimwell 2022-09-21 16:47:20 +01:00 committed by GitHub
commit ffe336c2ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 299 additions and 172 deletions

View file

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

View file

@ -13,7 +13,7 @@ essential aspects of using OpenMC to perform simulations.
beginners
install
cross_sections
data
basics
materials
geometry

View file

@ -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
View 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()

View file

@ -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'])

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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')

View 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'

View file

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