# 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.
"""
Reads and writes region and composition label data from a LABELS interface file.
LABELS files are produced by DIF3D/VARIANT. They are very similar in structure
and format to CCCC files but are not officially in the CCCC documents.
The file structure is listed here::
RECORD TYPE PRESENT IF
=============================== ================
FILE IDENTIFICATION ALWAYS
SPECIFICATIONS ALWAYS
LABEL AND AREA DATA ALWAYS
FINITE-GEOMETRY TRANSVERSE NHTS1.GT.0 OR
DISTANCES NGTS2.GT.0
NUCLIDE SET LABELS NSETS.GT.1
ALIAS ZONE LABELS NALIAS.GT.0
GENERAL CONTROL-ROD MODEL DATA NBANKS.GT.0
***********(REPEAT FOR ALL BANKS)
* CONTROL-ROD BANK DATA NBANKS.GT.0
*
* *******(REPEAT FOR ALL RODS IN BANK)
* * CONTROL-ROD CHANNEL DATA (LLCHN+LLROD+MMESH).GT.0
**********
BURNUP DEPENDENT CROSS SECTION NVARY.GT.0
SPECIFICATIONS
BURNUP DEPENDENT GROUPS MAXBRN.GT.0
BURNUP DEPENDENT FITTING MAXORD.GT.0
COEFFICIENTS
Reference: [DIF3D]_.
Examples
--------
>>> labelData = LabelStream.readBinary("LABELS")
"""
from armi import runLog
from armi.nuclearDataIO import cccc
LABELS = "LABELS"
FILE_SPEC_1D_KEYS = [
"numZones",
"numRegions",
"numAreas",
"numRegionAreaAssignments",
"numHalfHeightsDirection1",
"numHalfHeightsDirection2",
"numNuclideSets",
"numZoneAliases",
"numTrianglesPerHex",
"numHexagonalRings",
"numControlRodChannels",
"numControlRodBanks",
"numAxialFineMeshBins",
"maxControlRodBankTimes",
"maxControlRodsPerBank",
"maxControlRodsMeshes",
"maxControlRodPieces",
"maxControlRodChannels",
"numBurnupDependentIsotopes",
"maxBurnupDependentGroups",
"maxBurnupPolynomialOrder",
"modelDimensions",
]
[docs]class LabelsData(cccc.DataContainer):
"""
Data structure containing various region, zone, area, nuclide labels.
This is the data structure that is read from or written to a LABELS file.
"""
def __init__(self):
cccc.DataContainer.__init__(self)
self.regionLabels = []
self.zoneLabels = []
self.areaLabels = []
self.regionAreaAssignments = []
self.halfHeightsDirection1 = []
self.halfHeightsDirection2 = []
self.extrapolationDistance1 = []
self.extrapolationDistance2 = []
self.nuclideSetLabels = []
self.aliasZoneLabels = []
[docs]class LabelsStream(cccc.StreamWithDataContainer):
"""
Class for reading and writing the LABELS interface file produced by DIF3D/VARIANT.
Notes
-----
Contains region and composition labels, area data, half heights, nuclide set labels, alias zone labels,
control-rod model data, and burnup dependent cross section data.
See Also
--------
armi.nuclearDataIO.cccc.compxs
"""
@staticmethod
def _getDataContainer() -> LabelsData:
return LabelsData()
[docs] def readWrite(self):
runLog.info(
"{} LABELS data {}".format(
"Reading" if "r" in self._fileMode else "Writing", self
)
)
self._rwFileID()
self._rw1DRecord()
self._rw2DRecord()
if (
self._metadata["numHalfHeightsDirection1"] > 0
or self._metadata["numHalfHeightsDirection2"] > 0
):
self._rw3DRecord()
if self._metadata["numNuclideSets"] > 1:
self._rw4DRecord()
if self._metadata["numZoneAliases"] > 0:
self._rw5DRecord()
if self._metadata["numControlRodBanks"] > 0:
self._rw6DRecord()
self._rw7DRecord()
self._rw8DRecord()
if self._metadata["numBurnupDependentIsotopes"] > 0:
self._rw9DRecord()
if self._metadata["maxBurnupDependentGroups"] > 0:
self._rw10DRecord()
if self._metadata["maxBurnupPolynomialOrder"] > 0:
self._rw11DRecord()
def _rwFileID(self):
with self.createRecord() as record:
for name in ["hname", "huse", "huse2"]:
self._metadata[name] = record.rwString(self._metadata[name], 8)
self._metadata["version"] = record.rwInt(self._metadata["version"])
def _rw1DRecord(self):
"""Read/write the file specification data."""
with self.createRecord() as record:
for param in FILE_SPEC_1D_KEYS:
self._metadata[param] = record.rwInt(self._metadata[param])
self._metadata["dummy"] = record.rwList(self._metadata["dummy"], "int", 2)
def _rw2DRecord(self):
"""Read/write the label and area data"""
with self.createRecord() as record:
self._data.zoneLabels = record.rwList(
self._data.zoneLabels, "string", self._metadata["numZones"], 8
)
self._data.regionLabels = record.rwList(
self._data.regionLabels,
"string",
self._metadata["numRegions"],
8,
)
self._data.areaLabels = record.rwList(
self._data.areaLabels, "string", self._metadata["numAreas"], 8
)
self._data.regionAreaAssignments = record.rwList(
self._data.regionAreaAssignments,
"string",
self._metadata["numRegionAreaAssignments"],
8,
)
def _rw3DRecord(self):
"""Read/write the finite-geometry transverse distances."""
with self.createRecord() as record:
self._data.halfHeightsDirection1 = record.rwList(
self._data.halfHeightsDirection1,
"float",
self._metadata["numHalfHeightsDirection1"],
)
self._data.extrapolationDistance1 = record.rwList(
self._data.extrapolationDistance1,
"float",
self._metadata["numHalfHeightsDirection1"],
)
self._data.halfHeightsDirection2 = record.rwList(
self._data.halfHeightsDirection2,
"float",
self._metadata["numHalfHeightsDirection2"],
)
self._data.extrapolationDistance2 = record.rwList(
self._data.extrapolationDistance2,
"float",
self._metadata["numHalfHeightsDirection2"],
)
def _rw4DRecord(self):
"""Read/write the nuclide labels."""
with self.createRecord() as record:
self._data.nuclideSetLabels = record.rwList(
self._data.nuclideSetLabels,
"string",
self._metadata["numNuclideSets"],
8,
)
def _rw5DRecord(self):
"""Read/write the zone aliases."""
with self.createRecord() as record:
self._data.aliasZoneLabels = record.rwList(
self._data.aliasZoneLabels,
"string",
self._metadata["numZoneAliases"],
8,
)
def _rw6DRecord(self):
"""Read/write the general control-rod model data."""
raise NotImplementedError("Control rod data not implemented")
def _rw7DRecord(self):
"""Read/write the control-rod bank data."""
raise NotImplementedError("Control rod data not implemented")
def _rw8DRecord(self):
"""Read/write the control-rod channel data."""
raise NotImplementedError("Control rod data not implemented")
def _rw9DRecord(self):
"""Read/write the burnup-dependent cross section specifications."""
raise NotImplementedError("BU dependent XS data not implemented")
def _rw10DRecord(self):
"""Read/write the burnup-dependent group data."""
raise NotImplementedError("BU dependent XS data not implemented")
def _rw11DRecord(self):
"""Read/write the burnup-dependent fitting coefficient data."""
raise NotImplementedError("BU dependent XS data not implemented")
readBinary = LabelsStream.readBinary
readAscii = LabelsStream.readAscii
writeBinary = LabelsStream.writeBinary
writeAscii = LabelsStream.writeAscii