Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Details for nuclearDataIO impl tags #1605

Merged
merged 9 commits into from
Jan 25, 2024
75 changes: 70 additions & 5 deletions armi/nuclearDataIO/cccc/cccc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,69 @@
# limitations under the License.

"""
Defines containers for the reading and writing standard interface files
Defines containers for the reading and writing standard interface files
for reactor physics codes.

.. impl:: Generic tool for reading and writing Committee on Computer Code Coordination (CCCC) format files for reactor physics codes
:id: I_ARMI_NUCDATA
:implements: R_ARMI_NUCDATA_ISOTXS,
R_ARMI_NUCDATA_GAMISO,
R_ARMI_NUCDATA_GEODST,
R_ARMI_NUCDATA_DIF3D,
R_ARMI_NUCDATA_PMATRX,
R_ARMI_NUCDATA_DLAYXS

This module provides a number of base classes that implement general
capabilities for binary and ASCII file I/O. The :py:class:`IORecord` serves
as an abstract base class that instantiates a number of methods that the
binary and ASCII children classes are meant to implement. These methods,
prefixed with ``rw``, are meant to convert literal data types, e.g. float or
int, to either binary or ASCII. This base class does its own conversion for
container data types, e.g. list or matrix, relying on the child
implementation of the literal types that the container possesses. The binary
conversion is implemented in :py:class:`BinaryRecordReader` and
:py:class`BinaryRecordWriter`. The ASCII conversion is implemented in
:py:class:`AsciiRecordReader` and :py:class:`AsciiRecordWriter`.

These :py:class`IORecord` classes are used within :py:class:`Stream` objects
for the data conversion. :py:class:`Stream` is a context manager that opens
a file for reading or writing on the ``__enter__`` and closes that file upon
``__exit__``. :py:class:`Stream` is an abstract base class that is
subclassed for each CCCC file. It is subclassed directly for the CCCC files
that contain XS data:

* :py:class:`ISOTXS <armi.nuclearDataIO.cccc.isotxs.IsotxsIO>`,
* :py:mod:`GAMISO <armi.nuclearDataIO.cccc.gamiso>`,
* :py:class:`PMATRX <armi.nuclearDataIO.cccc.pmatrx.PmatrxIO>`.
* :py:class:`DLAYXS <armi.nuclearDataIO.cccc.dlayxs.DlayxsIO>`.
* :py:mod:`COMPXS <armi.nuclearDataIO.cccc.compxs>`.

For the CCCC file types that are outputs from a flux solver such as DIF3D
(e.g., GEODST, DIF3D, NHFLUX) the streams are subclassed from
:py:class:`StreamWithDataContainer`, which is a special abstract subclass of
:py:class:`Stream` that implements a common pattern used for these file
types. In a :py:class:`StreamWithDataContainer`, the data is directly read
to or written from a specialized data container.

The data container structure for each type of CCCC file is implemented in
the module for that file, as a subclass of :py:class:`DataContainer`. The
subclasses for each CCCC file type define standard attribute names for the
data that will be read from or written to the CCCC file. CCCC file types
that follow this pattern include:

* :py:class:`GEODST <armi.nuclearDataIO.cccc.geodst.GeodstData>`
* :py:class:`DIF3D <armi.nuclearDataIO.cccc.dif3d.Dif3dData>`
* :py:class:`NHFLUX <armi.nuclearDataIO.cccc.nhflux.NHFLUX>`
(and multiple sub-classes thereof)
* :py:class:`LABELS <armi.nuclearDataIO.cccc.labels.LabelsData>`
* :py:class:`PWDINT <armi.nuclearDataIO.cccc.pwdint.PwdintData>`
* :py:class:`RTFLUX <armi.nuclearDataIO.cccc.rtflux.RtfluxData>`
* :py:class:`RZFLUX <armi.nuclearDataIO.cccc.rzflux.RzfluxData>`
* :py:class:`RTFLUX <armi.nuclearDataIO.cccc.rtflux.RtfluxData>`

The logic to parse or write each specific file format is contained within
the :py:meth:`Stream.readWrite` implementations of the respective
subclasses.
"""
import io
import itertools
Expand Down Expand Up @@ -274,7 +335,8 @@ def rwImplicitlyTypedMap(self, keys: List[str], contents) -> dict:


class BinaryRecordReader(IORecord):
"""Writes a single CCCC record in binary format.
"""
Writes a single CCCC record in binary format.

Notes
-----
Expand Down Expand Up @@ -345,7 +407,8 @@ def rwString(self, val, length):


class BinaryRecordWriter(IORecord):
r"""a single record from a CCCC file.
r"""
Reads a single CCCC record in binary format.

Reads binary information sequentially.
"""
Expand Down Expand Up @@ -406,7 +469,8 @@ def rwString(self, val, length):


class AsciiRecordReader(BinaryRecordReader):
"""Reads a single CCCC record in ASCII format.
"""
Reads a single CCCC record in ASCII format.

See Also
--------
Expand Down Expand Up @@ -441,7 +505,8 @@ def rwString(self, val, length):


class AsciiRecordWriter(IORecord):
r"""Writes a single CCCC record in ASCII format.
r"""
Writes a single CCCC record in ASCII format.

Since there is no specific format of an ASCII CCCC record, the format is roughly the same as
the :py:class:`BinaryRecordWriter`, except that the :class:`AsciiRecordReader` puts a space in
Expand Down
35 changes: 34 additions & 1 deletion armi/nuclearDataIO/cccc/dif3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,44 @@ def _rw5DRecord(self) -> None:
)

def readWrite(self):
"""Reads or writes metadata and data from 5 records.
"""Reads or writes metadata and data from the five records of the DIF3D binary file.

.. impl:: Tool to read and write DIF3D files.
:id: I_ARMI_NUCDATA_DIF3D
:implements: R_ARMI_NUCDATA_DIF3D

The reading and writing of the DIF3D binary file is performed using
:py:class:`StreamWithDataContainer <.cccc.StreamWithDataContainer>`
from the :py:mod:`~armi.nuclearDataIO.cccc` package. This class
allows for the reading and writing of CCCC binary files, processing
one record at a time using subclasses of the :py:class:`IORecord
<.cccc.IORecord>`. Each record in a CCCC binary file consists of
Nebbychadnezzar marked this conversation as resolved.
Show resolved Hide resolved
words that represent integers (short or long), floating-point
numbers (single or double precision), or strings of data. One or
more of these words are parsed one at a time by the reader. Multiple
words processed together have meaning, such as such as groupwise
overrelaxation factors. While reading, the data is stored in a
Python dictionary as an attribute on the object, one for each
record. The keys in each dictionary represent the parsed grouping of
words in the records; for example, for the 4D record (stored as the
attribute ``fourD``), each groupwise overrelaxation factor is stored
as the key ``OMEGA{i}``, where ``i`` is the group number. See
:need:`I_ARMI_NUCDATA` for more details on the general
implementation.

Each record is also embedded with the record size at the beginning
and end of the record (always assumed to be present), which is used
for error checking at the end of processing each record.

The DIF3D reader processes the file identification record (stored as
the attribute ``_metadata``) and the five data records for the DIF3D
file, as defined in the specification for the file distributed with
the DIF3D software.

This class can also read and write an ASCII version of the DIF3D
file. While this format is not used by the DIF3D software, it can be
a useful representation for users to access the file in a
human-readable format.
"""
msg = f"{'Reading' if 'r' in self._fileMode else 'Writing'} DIF3D binary data {self}"
runLog.info(msg)
Expand Down
34 changes: 33 additions & 1 deletion armi/nuclearDataIO/cccc/dlayxs.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,43 @@ def __init__(self, fileName, fileMode, dlayxs):
self.metadata = dlayxs.metadata

def readWrite(self):
"""Read and write DLAYXS files.
r"""Read and write DLAYXS files.
Nebbychadnezzar marked this conversation as resolved.
Show resolved Hide resolved

.. impl:: Tool to read and write DLAYXS files.
:id: I_ARMI_NUCDATA_DLAYXS
:implements: R_ARMI_NUCDATA_DLAYXS

Reading and writing DLAYXS delayed neutron data files is performed
using the general nuclear data I/O functionalities described in
:need:`I_ARMI_NUCDATA`. Reading/writing a DLAYXS file is performed
through the following steps:

#. Read/write the data ``label`` for identification.

.. note::

MC\ :sup:`2`-3 file does not use the expected number of
characters for the ``label``, so its length needs to be
stored in the :py:class:`~.cccc.IORecord`.

#. Read/write file control information, i.e. the 1D record, which includes:

* Number of energy groups
* Number of nuclides
* Number of precursor families

#. Read/write spectral data, including:

* Nuclide IDs
* Decay constants
* Emission spectra
* Energy group bounds
* Number of families to which fission in a given nuclide
contributes delayed neutron precursors

#. Read/write 3D delayed neutron yield matrix on the 3D record,
indexed by nuclide, precursor family, and outgoing neutron energy
group.
"""
runLog.info(
"{} DLAYXS library {}".format(
Expand Down
7 changes: 7 additions & 0 deletions armi/nuclearDataIO/cccc/gamiso.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
:id: I_ARMI_NUCDATA_GAMISO
:implements: R_ARMI_NUCDATA_GAMISO

The majority of the functionality in this module is inherited from the
:py:mod:`~armi.nuclearDataIO.cccc.isotxs` module. See
:py:class:`~armi.nuclearDataIO.cccc.isotxs.IsotxsIO` and its associated
implementation :need:`I_ARMI_NUCDATA_ISOTXS` for more information. The only
difference from ISOTXS neutron data is a special treatment for gamma
velocities, which is done by overriding ``_rwLibraryEnergies``.

See [GAMSOR]_.

.. [GAMSOR] Smith, M. A., Lee, C. H., and Hill, R. N. GAMSOR: Gamma Source Preparation and DIF3D Flux Solution. United States:
Expand Down
39 changes: 34 additions & 5 deletions armi/nuclearDataIO/cccc/geodst.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,39 @@ def readWrite(self):
.. impl:: Tool to read and write GEODST files.
:id: I_ARMI_NUCDATA_GEODST
:implements: R_ARMI_NUCDATA_GEODST

Reading and writing GEODST files is performed using the general
nuclear data I/O functionalities described in
:need:`I_ARMI_NUCDATA`. Reading/writing a GEODST file is performed
through the following steps:

#. Read/write file ID record

#. Read/write file specifications on 1D record.

#. Based on the geometry type (``IGOM``), one of following records
are read/written:

* Slab (1), cylinder (3), or sphere (3): Read/write 1-D coarse
mesh boundaries and fine mesh intervals.
* X-Y (6), R-Z (7), Theta-R (8), uniform triangular (9),
hexagonal (10), or R-Theta (11): Read/write 2-D coarse mesh
boundaries and fine mesh intervals.
* R-Theta-Z (12, 15), R-Theta-Alpha (13, 16), X-Y-Z (14),
uniform triangular-Z (17), hexagonal-Z(18): Read/write 3-D
coarse mesh boundaries and fine mesh intervals.

#. If the geometry is not zero-dimensional (``IGOM`` > 0) and
buckling values are specified (``NBS`` > 0): Read/write geometry
data from 5D record.

#. If the geometry is not zero-dimensional (``IGOM`` > 0) and region
assignments are coarse-mesh-based (``NRASS`` = 0): Read/write
region assignments to coarse mesh interval.

#. If the geometry is not zero-dimensional (``IGOM`` > 0) and region
assignments are fine-mesh-based (``NRASS`` = 1): Read/write
region assignments to fine mesh interval.
"""
self._rwFileID()
self._rw1DRecord()
Expand All @@ -162,8 +195,7 @@ def _rwFileID(self):

Notes
-----
The username, version, etc are embedded in this string but it's
usually blank. The number 28 was actually obtained from
The number 28 was actually obtained from
a hex editor and may be code specific.
"""
with self.createRecord() as record:
Expand All @@ -182,7 +214,6 @@ def _rw1DRecord(self):
def _rw2DRecord(self):
"""Read/write 1-D coarse mesh boundaries and fine mesh intervals."""
with self.createRecord() as record:

self._data.xmesh = record.rwList(
self._data.xmesh, "double", self._metadata["NCINTI"] + 1
)
Expand All @@ -193,7 +224,6 @@ def _rw2DRecord(self):
def _rw3DRecord(self):
"""Read/write 2-D coarse mesh boundaries and fine mesh intervals."""
with self.createRecord() as record:

self._data.xmesh = record.rwList(
self._data.xmesh, "double", self._metadata["NCINTI"] + 1
)
Expand All @@ -210,7 +240,6 @@ def _rw3DRecord(self):
def _rw4DRecord(self):
"""Read/write 3-D coarse mesh boundaries and fine mesh intervals."""
with self.createRecord() as record:

self._data.xmesh = record.rwList(
self._data.xmesh, "double", self._metadata["NCINTI"] + 1
)
Expand Down
47 changes: 45 additions & 2 deletions armi/nuclearDataIO/cccc/isotxs.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,48 @@ def readWrite(self):
.. impl:: Tool to read and write ISOTXS files.
:id: I_ARMI_NUCDATA_ISOTXS
:implements: R_ARMI_NUCDATA_ISOTXS

Reading and writing ISOTXS files is performed using the general
nuclear data I/O functionalities described in
:need:`I_ARMI_NUCDATA`. Reading/writing a ISOTXS file is performed
through the following steps:

#. Read/write file ID record
#. Read/write file 1D record, which includes:

* Number of energy groups (``NGROUP``)
* Maximum number of up-scatter groups (``MAXUP``)
* Maximum number of down-scatter groups (``MAXDN``)
* Maximum scattering order (``MAXORD``)
* File-wide specification on fission spectrum type, i.e. vector
or matrix (``ICHIST``)
* Maximum number of blocks of scattering data (``MSCMAX``)
* Subblocking control for scatter matrices (``NSBLOK``)

#. Read/write file 2D record, which includes:

* Library IDs for each isotope (``HSETID(I)``)
* Isotope names (``HISONM(I)``)
* Global fission spectrum (``CHI(J)``) if file-wide spectrum is
specified (``ICHIST`` = 1)
* Energy group structure (``EMAX(J)`` and ``EMIN``)
* Locations of each nuclide record in the file (``LOCA(I)``)

.. note::

The offset data is not read from the binary file because
the ISOTXS reader can dynamically calculate the offset
itself. Therefore, during a read operation, this data is
ignored.

#. Read/write file 4D record for each nuclide, which includes
isotope-dependent, group-independent data.
#. Read/write file 5D record for each nuclide, which includes
principal cross sections.
#. Read/write file 6D record for each nuclide, which includes
zachmprince marked this conversation as resolved.
Show resolved Hide resolved
fission spectrum if it is flagged as a matrix (``ICHI`` > 1).
#. Read/write file 7D record for each nuclide, which includes the
scattering matrices.
"""
self._rwMessage()
properties.unlockImmutableProperties(self._lib)
Expand Down Expand Up @@ -369,8 +411,9 @@ def _computeNuclideRecordOffset(self):

Notes
-----
This is not used within ARMI, because it can compute it arbitrarily. Other codes use this to seek to a
specific position within an ISOTXS file.
The offset data is not read from the binary file because the ISOTXS
reader can dynamically calculate the offset itself. Therefore, during a
read operation, this data is ignored.
"""
recordsPerNuclide = [
self._computeNumIsotxsRecords(nuc) for nuc in self._lib.nuclides
Expand Down
19 changes: 19 additions & 0 deletions armi/nuclearDataIO/cccc/pmatrx.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,25 @@ def readWrite(self):
.. impl:: Tool to read and write PMATRX files.
:id: I_ARMI_NUCDATA_PMATRX
:implements: R_ARMI_NUCDATA_PMATRX

Reading and writing PMATRX files is performed using the general
nuclear data I/O functionalities described in
:need:`I_ARMI_NUCDATA`. Reading/writing a PMATRX file is performed
through the following steps:

#. Read/write global information including:

* Number of gamma energy groups
* Number of neutron energy groups
* Maximum scattering order
* Maximum number of compositions
* Maximum number of materials
* Maximum number of regions

#. Read/write energy group structure for neutrons and gammas
#. Read/write dose conversion factors
#. Read/write gamma production matrices for each nuclide, as well as
other reaction constants related to neutron-gamma production.
"""
self._rwMessage()
properties.unlockImmutableProperties(self._lib)
Expand Down
Loading
Loading