Source code for armi.nuclearDataIO.cccc.rtflux

# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Read and write the Regular Total flux from a RTFLUX CCCC interface file.

RTFLUX is a CCCC standard data file for storing multigroup total flux on a mesh of any
geometry type. It is defined in [CCCC-IV]_.

ATFLUX is in the same format but holds adjoint flux rather than regular flux.

Examples
--------
>>> flux = rtflux.RtfluxStream.readBinary("RTFLUX")
>>> rtflux.RtfluxStream.writeBinary(flux, "RTFLUX2")
>>> adjointFlux = rtflux.AtfluxStream.readBinary("ATFLUX")

See Also
--------
NHFLUX
    Reads/write nodal hex flux moments

RZFLUX
    Reads/writes total fluxes from zones
"""
import numpy

from armi.nuclearDataIO import cccc

RTFLUX = "RTFLUX"
ATFLUX = "ATFLUX"

# See CCCC-IV documentation for definitions
FILE_SPEC_1D_KEYS = (
    "NDIM",
    "NGROUP",
    "NINTI",
    "NINTJ",
    "NINTK",
    "ITER",
    "EFFK",
    "POWER",
    "NBLOK",
)


[docs]class RtfluxData(cccc.DataContainer): """ Multigroup flux as a function of i,j,k and g indices. The metadata also contains the power and k-eff. This is the data structure that is read from or written to a RTFLUX file. """ def __init__(self): cccc.DataContainer.__init__(self) self.groupFluxes: numpy.ndarray = numpy.array([]) """Maps i,j,k,g indices to total real or adjoint flux in n/cm^2-s"""
[docs]class RtfluxStream(cccc.StreamWithDataContainer): """ Stream for reading/writing a RTFLUX or ATFLUX file. Parameters ---------- flux : RtfluxData Data structure fileName: str path to RTFLUX file fileMode: str string indicating if ``fileName`` is being read or written, and in ascii or binary format """ @staticmethod def _getDataContainer() -> RtfluxData: return RtfluxData()
[docs] def readWrite(self): """Step through the structure of the file and read/write it.""" self._rwFileID() self._rw1DRecord() if self._metadata["NDIM"] == 1: self._rw2DRecord() elif self._metadata["NDIM"] >= 2: self._rw3DRecord() else: raise ValueError(f"Invalid NDIM value {self._metadata['NDIM']} in {self}.")
def _rwFileID(self): """ Read/write file id record. Notes ----- The username, version, etc are embedded in this string but it's usually blank. """ with self.createRecord() as record: self._metadata["label"] = record.rwString(self._metadata["label"], 28) def _rw1DRecord(self): """Read/write File specifications on 1D record.""" with self.createRecord() as record: self._metadata.update( record.rwImplicitlyTypedMap(FILE_SPEC_1D_KEYS, self._metadata) ) def _rw2DRecord(self): """Read/write 1-dimensional regular total flux.""" raise NotImplementedError("1-D RTFLUX files are not yet implemented.") def _rw3DRecord(self): """ Read/write multi-dimensional regular total flux. The records contain blocks of values in the i-j planes. """ ng = self._metadata["NGROUP"] imax = self._metadata["NINTI"] jmax = self._metadata["NINTJ"] kmax = self._metadata["NINTK"] nblck = self._metadata["NBLOK"] if self._data.groupFluxes.size == 0: self._data.groupFluxes = numpy.zeros((imax, jmax, kmax, ng)) for gi in range(ng): gEff = self.getEnergyGroupIndex(gi) for k in range(kmax): # data in i-j plane may be blocked for bi in range(nblck): # compute blocking parameters jLow, jUp = cccc.getBlockBandwidth(bi + 1, jmax, nblck) numZonesInBlock = jUp - jLow + 1 with self.createRecord() as record: # pass in shape in fortran (read) order self._data.groupFluxes[ :, jLow : jUp + 1, k, gEff ] = record.rwDoubleMatrix( self._data.groupFluxes[:, jLow : jUp + 1, k, gEff], numZonesInBlock, imax, )
[docs] def getEnergyGroupIndex(self, g): r""" Real fluxes stored in RTFLUX have "normal" (or "forward") energy groups. Also see the subclass method ATFLUX.getEnergyGroupIndex(). 0 based, so if NG=33 and you want the third group, this return 2. """ return g
[docs]class AtfluxStream(RtfluxStream): r""" This is a subclass for the ATFLUX file, which is identical in format to the RTFLUX file except that it contains the adjoint flux and has reversed energy group ordering. """
[docs] def getEnergyGroupIndex(self, g): r""" Adjoint fluxes stored in ATFLUX have "reversed" (or "backward") energy groups. 0 based, so if NG=33 and you want the third group (g=2), this returns 30. """ ng = self._metadata["NGROUP"] return ng - g - 1
[docs]def getFDFluxReader(adjointFlag): r""" Returns the appropriate DIF3D FD flux binary file reader class, either RTFLUX (real) or ATFLUX (adjoint). """ if adjointFlag: return AtfluxStream else: return RtfluxStream