# 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.
"""Tests for xsLibraries.IsotxsLibrary."""
import copy
import filecmp
import os
import traceback
import unittest
from six.moves import cPickle
from armi.nucDirectory import nuclideBases
from armi.nuclearDataIO import xsLibraries
from armi.nuclearDataIO.cccc import gamiso
from armi.nuclearDataIO.cccc import isotxs
from armi.nuclearDataIO.cccc import pmatrx
from armi.tests import mockRunLogs
from armi.utils import properties
from armi.utils.directoryChangers import TemporaryDirectoryChanger
THIS_DIR = os.path.dirname(__file__)
RUN_DIR = os.path.join(THIS_DIR, "library-file-generation")
FIXTURE_DIR = os.path.join(THIS_DIR, "fixtures")
# CCCC fixtures are less fancy than these merging ones.
FIXTURE_DIR_CCCC = os.path.join(os.path.dirname(isotxs.__file__), "tests", "fixtures")
ISOTXS_AA = os.path.join(FIXTURE_DIR, "ISOAA")
ISOTXS_AB = os.path.join(FIXTURE_DIR, "ISOAB")
ISOTXS_AA_AB = os.path.join(FIXTURE_DIR, "combined-AA-AB.isotxs")
ISOTXS_LUMPED = os.path.join(FIXTURE_DIR, "combined-and-lumped-AA-AB.isotxs")
PMATRX_AA = os.path.join(FIXTURE_DIR, "AA.pmatrx")
PMATRX_AB = os.path.join(FIXTURE_DIR, "AB.pmatrx")
PMATRX_AA_AB = os.path.join(FIXTURE_DIR, "combined-AA-AB.pmatrx")
PMATRX_LUMPED = os.path.join(FIXTURE_DIR, "combined-and-lumped-AA-AB.pmatrx")
GAMISO_AA = os.path.join(FIXTURE_DIR, "AA.gamiso")
GAMISO_AB = os.path.join(FIXTURE_DIR, "AB.gamiso")
GAMISO_AA_AB = os.path.join(FIXTURE_DIR, "combined-AA-AB.gamiso")
GAMISO_LUMPED = os.path.join(FIXTURE_DIR, "combined-and-lumped-AA-AB.gamiso")
DLAYXS_MCC3 = os.path.join(FIXTURE_DIR_CCCC, "mc2v3.dlayxs")
UFG_FLUX_EDIT = os.path.join(FIXTURE_DIR, "mc2v3-AA.flux_ufg")
[docs]class TempFileMixin(unittest.TestCase):
"""really a test case."""
def setUp(self):
self.td = TemporaryDirectoryChanger()
self.td.__enter__()
def tearDown(self):
self.td.__exit__(None, None, None)
@property
def testFileName(self):
return os.path.join(
self.td.destination,
"{}-{}.nucdata".format(self.__class__.__name__, self._testMethodName),
)
[docs]class TestXSLibrary(TempFileMixin):
@classmethod
def setUpClass(cls):
cls.isotxsAA = isotxs.readBinary(ISOTXS_AA)
cls.gamisoAA = gamiso.readBinary(GAMISO_AA)
cls.pmatrxAA = pmatrx.readBinary(PMATRX_AA)
cls.xsLib = xsLibraries.IsotxsLibrary()
cls.xsLibGenerationErrorStack = None
try:
cls.xsLib.merge(copy.deepcopy(cls.isotxsAA))
cls.xsLib.merge(copy.deepcopy(cls.gamisoAA))
cls.xsLib.merge(copy.deepcopy(cls.pmatrxAA))
except: # noqa: bare-except
cls.xsLibGenerationErrorStack = traceback.format_exc()
[docs] def test_canPickleAndUnpickleISOTXS(self):
pikAA = cPickle.loads(cPickle.dumps(self.isotxsAA))
self.assertTrue(xsLibraries.compare(pikAA, self.isotxsAA))
[docs] def test_canPickleAndUnpickleGAMISO(self):
pikAA = cPickle.loads(cPickle.dumps(self.gamisoAA))
self.assertTrue(xsLibraries.compare(pikAA, self.gamisoAA))
[docs] def test_canPickleAndUnpicklePMATRX(self):
pikAA = cPickle.loads(cPickle.dumps(self.pmatrxAA))
self.assertTrue(xsLibraries.compare(pikAA, self.pmatrxAA))
[docs] def test_compareWorks(self):
self.assertTrue(xsLibraries.compare(self.isotxsAA, self.isotxsAA))
self.assertTrue(xsLibraries.compare(self.pmatrxAA, self.pmatrxAA))
aa = isotxs.readBinary(ISOTXS_AA)
del aa[aa.nuclideLabels[0]]
self.assertFalse(xsLibraries.compare(aa, self.isotxsAA))
[docs] def test_compareDifferentComponentsOfAnXSLibrary(self):
self.assertTrue(xsLibraries.compare(self.isotxsAA, self.isotxsAA))
self.assertTrue(xsLibraries.compare(self.pmatrxAA, self.pmatrxAA))
aa = isotxs.readBinary(ISOTXS_AA)
del aa[aa.nuclideLabels[0]]
self.assertFalse(xsLibraries.compare(aa, self.isotxsAA))
[docs] def test_mergeFailsWithNonIsotxsFiles(self):
dummyFileName = "ISOSOMEFILE"
with open(dummyFileName, "w") as someFile:
someFile.write("hi")
try:
with mockRunLogs.BufferLog() as log:
lib = xsLibraries.IsotxsLibrary()
with self.assertRaises(OSError):
xsLibraries.mergeXSLibrariesInWorkingDirectory(lib, "ISOTXS", "")
self.assertIn(dummyFileName, log.getStdout())
finally:
os.remove(dummyFileName)
with TemporaryDirectoryChanger():
dummyFileName = "ISOtopics.txt"
with open(dummyFileName, "w") as file:
file.write(
"This is a file that starts with the letters 'ISO' but will"
" break the regular expression search."
)
try:
with mockRunLogs.BufferLog() as log:
lib = xsLibraries.IsotxsLibrary()
xsLibraries.mergeXSLibrariesInWorkingDirectory(lib)
self.assertIn(
f"{dummyFileName} in the merging of ISOXX files",
log.getStdout(),
)
finally:
pass
def _xsLibraryAttributeHelper(
self,
lib,
neutronEnergyLength,
neutronVelLength,
gammaEnergyLength,
neutronDoseLength,
gammaDoseLength,
):
for attrName, listLength in [
("neutronEnergyUpperBounds", neutronEnergyLength),
("neutronVelocity", neutronVelLength),
("gammaEnergyUpperBounds", gammaEnergyLength),
("neutronDoseConversionFactors", neutronDoseLength),
("gammaDoseConversionFactors", gammaDoseLength),
]:
if listLength > 0:
self.assertEqual(listLength, len(getattr(lib, attrName)))
else:
with self.assertRaises(properties.ImmutablePropertyError):
print("Getting the value {}".format(attrName))
print(getattr(lib, attrName))
[docs] def test_isotxsLibraryAttributes(self):
self._xsLibraryAttributeHelper(
self.isotxsAA,
neutronEnergyLength=33,
neutronVelLength=33,
gammaEnergyLength=0,
neutronDoseLength=0,
gammaDoseLength=0,
)
[docs] def test_gamisoLibraryAttributes(self):
self._xsLibraryAttributeHelper(
self.gamisoAA,
neutronEnergyLength=0,
neutronVelLength=0,
gammaEnergyLength=21,
neutronDoseLength=0,
gammaDoseLength=0,
)
[docs] def test_pmatrxLibraryAttributes(self):
self._xsLibraryAttributeHelper(
self.pmatrxAA,
neutronEnergyLength=33,
neutronVelLength=0,
gammaEnergyLength=21,
neutronDoseLength=0,
gammaDoseLength=0,
)
[docs] def test_mergeXSLibrariesWithDifferentDataWorks(self):
if self.xsLibGenerationErrorStack is not None:
print(self.xsLibGenerationErrorStack)
raise Exception("see stdout for stack trace")
# check to make sure they labels overlap... or are actually the same
labels = set(self.xsLib.nuclideLabels)
self.assertEqual(labels, set(self.isotxsAA.nuclideLabels))
self.assertEqual(labels, set(self.gamisoAA.nuclideLabels))
self.assertEqual(labels, set(self.pmatrxAA.nuclideLabels))
# the whole thing is different from the sum of its components
self.assertFalse(xsLibraries.compare(self.xsLib, self.isotxsAA))
self.assertFalse(xsLibraries.compare(self.xsLib, self.gamisoAA))
self.assertFalse(xsLibraries.compare(self.xsLib, self.pmatrxAA))
# individual components are the same
self.assertTrue(isotxs.compare(self.xsLib, self.isotxsAA))
self.assertTrue(gamiso.compare(self.xsLib, self.gamisoAA))
self.assertTrue(pmatrx.compare(self.xsLib, self.pmatrxAA))
[docs] def test_canWriteIsotxsFromCombinedXSLibrary(self):
self._canWritefromCombined(isotxs, ISOTXS_AA)
[docs] def test_canWriteGamisoFromCombinedXSLibrary(self):
self._canWritefromCombined(gamiso, GAMISO_AA)
[docs] def test_canWritePmatrxFromCombinedXSLibrary(self):
self._canWritefromCombined(pmatrx, PMATRX_AA)
def _canWritefromCombined(self, writer, refFile):
if self.xsLibGenerationErrorStack is not None:
print(self.xsLibGenerationErrorStack)
raise Exception("see stdout for stack trace")
# check to make sure they labels overlap... or are actually the same
writer.writeBinary(self.xsLib, self.testFileName)
self.assertTrue(filecmp.cmp(refFile, self.testFileName))
[docs]class TestGetISOTXSFilesInWorkingDirectory(unittest.TestCase):
[docs] def test_getISOTXSFilesWithoutLibrarySuffix(self):
shouldBeThere = ["ISOAA", "ISOBA", os.path.join("file-path", "ISOCA")]
shouldNotBeThere = [
"ISOBA-n2",
"ISOTXS",
"ISOTXS-c2",
"dummyISOTXS",
"ISOTXS.BCD",
"ISOAA.BCD",
]
filesInDirectory = shouldBeThere + shouldNotBeThere
toMerge = xsLibraries.getISOTXSLibrariesToMerge("", filesInDirectory)
self.assert_contains_only(toMerge, shouldBeThere, shouldNotBeThere)
[docs] def test_getISOTXSFilesWithLibrarySuffix(self):
shouldBeThere = [
"ISOAA-n23",
"ISOAAF-n23",
"ISOBA-n23",
"ISODA",
os.path.join("file-path", "ISOCA-n23"),
]
shouldNotBeThere = [
"ISOAA",
"ISOAA-n24",
"ISOBA-ISO",
"ISOBA-n2",
"ISOTXS",
"ISOTXS-c2",
"dummyISOTXS",
"ISOTXS.BCD",
"ISOAA.BCD",
"ISOCA-doppler",
"ISOSA-void",
os.path.join("file-path", "ISOCA-ISO"),
]
filesInDirectory = shouldBeThere + shouldNotBeThere
toMerge = xsLibraries.getISOTXSLibrariesToMerge("-n23", filesInDirectory)
self.assert_contains_only(toMerge, shouldBeThere, shouldNotBeThere)
[docs] def assert_contains_only(self, container, shouldBeThere, shouldNotBeThere):
"""
Utility method for saying what things contain.
This could just check the contents and the length, but the error produced when you pass shouldNotBeThere
is much nicer.
"""
container = set(container)
self.assertEqual(container, set(shouldBeThere))
self.assertEqual(set(), container & set(shouldNotBeThere))
# NOTE: This is just a base class, so it isn't run directly.
class TestXSlibraryMerging(TempFileMixin):
"""A shared class that defines tests that should be true for all IsotxsLibrary merging."""
@classmethod
def setUpClass(cls):
cls.libAA = None
cls.libAB = None
cls.libCombined = None
cls.libLumped = None
@classmethod
def tearDownClass(cls):
cls.libAA = None
cls.libAB = None
cls.libCombined = None
cls.libLumped = None
del cls.libAA
del cls.libAB
del cls.libCombined
del cls.libLumped
def setUp(self):
TempFileMixin.setUp(self)
# load a library that is in the ARMI tree. This should
# be a small library with LFPs, Actinides, structure, and coolant
for attrName, path in [
("libAA", self.getLibAAPath),
("libAB", self.getLibABPath),
("libCombined", self.getLibAA_ABPath),
("libLumped", self.getLibLumpedPath),
]:
if getattr(self.__class__, attrName) is None:
setattr(self.__class__, attrName, self.getReadFunc()(path()))
def getErrorType(self):
raise NotImplementedError()
def getReadFunc(self):
raise NotImplementedError()
def getWriteFunc(self):
raise NotImplementedError()
def getLibAAPath(self):
raise NotImplementedError()
def getLibABPath(self):
raise NotImplementedError()
def getLibAA_ABPath(self):
raise NotImplementedError()
def getLibLumpedPath(self):
raise NotImplementedError()
def test_cannotMergeXSLibWithSameNuclideNames(self):
with self.assertRaises(AttributeError):
self.libAA.merge(self.libCombined)
with self.assertRaises(AttributeError):
self.libAA.merge(self.libAA)
with self.assertRaises(AttributeError):
self.libAA.merge(self.libCombined)
with self.assertRaises(AttributeError):
self.libCombined.merge(self.libAA)
def test_cannotMergeXSLibxWithDifferentGroupStructure(self):
dummyXsLib = xsLibraries.IsotxsLibrary()
dummyXsLib.neutronEnergyUpperBounds = [1, 2, 3]
dummyXsLib.gammaEnergyUpperBounds = [1, 2, 3]
with self.assertRaises(properties.ImmutablePropertyError):
dummyXsLib.merge(self.libCombined)
def test_mergeEmptyXSLibWithOtherEssentiallyClonesTheOther(self):
emptyXSLib = xsLibraries.IsotxsLibrary()
emptyXSLib.merge(self.libAA)
self.__class__.libAA = None
self.getWriteFunc()(emptyXSLib, self.testFileName)
self.assertTrue(filecmp.cmp(self.getLibAAPath(), self.testFileName))
def test_mergeTwoXSLibFiles(self):
emptyXSLib = xsLibraries.IsotxsLibrary()
emptyXSLib.merge(self.libAA)
self.__class__.libAA = None
emptyXSLib.merge(self.libAB)
self.__class__.libAB = None
self.assertEqual(
set(self.libCombined.nuclideLabels), set(emptyXSLib.nuclideLabels)
)
self.assertTrue(xsLibraries.compare(emptyXSLib, self.libCombined))
self.getWriteFunc()(emptyXSLib, self.testFileName)
self.assertTrue(filecmp.cmp(self.getLibAA_ABPath(), self.testFileName))
def test_canRemoveIsotopes(self):
emptyXSLib = xsLibraries.IsotxsLibrary()
emptyXSLib.merge(self.libAA)
self.__class__.libAA = None
emptyXSLib.merge(self.libAB)
self.__class__.libAB = None
for nucId in [
"ZR93_7",
"ZR95_7",
"XE1287",
"XE1297",
"XE1307",
"XE1317",
"XE1327",
"XE1337",
"XE1347",
"XE1357",
"XE1367",
]:
nucLabel = nuclideBases.byMcc3Id[nucId].label
del emptyXSLib[nucLabel + "AA"]
del emptyXSLib[nucLabel + "AB"]
self.assertEqual(
set(self.libLumped.nuclideLabels), set(emptyXSLib.nuclideLabels)
)
self.getWriteFunc()(emptyXSLib, self.testFileName)
self.assertTrue(filecmp.cmp(self.getLibLumpedPath(), self.testFileName))
[docs]class Pmatrx_merge_Tests(TestXSlibraryMerging):
[docs] def getErrorType(self):
return OSError
[docs] def getReadFunc(self):
return pmatrx.readBinary
[docs] def getWriteFunc(self):
return pmatrx.writeBinary
[docs] def getLibAAPath(self):
return PMATRX_AA
[docs] def getLibABPath(self):
return PMATRX_AB
[docs] def getLibAA_ABPath(self):
return PMATRX_AA_AB
[docs] def getLibLumpedPath(self):
return PMATRX_LUMPED
[docs] @unittest.skip("Do not have data for comparing merged and purged PMATRX")
def test_canRemoveIsotopes(self):
# this test does not work for PMATRX, MC**2-v3 does not currently
pass
[docs] def test_cannotMergeXSLibsWithDifferentGammaGroupStructures(self):
dummyXsLib = xsLibraries.IsotxsLibrary()
dummyXsLib.gammaEnergyUpperBounds = [1, 2, 3]
with self.assertRaises(properties.ImmutablePropertyError):
dummyXsLib.merge(self.libCombined)
[docs]class Isotxs_merge_Tests(TestXSlibraryMerging):
[docs] def getErrorType(self):
return OSError
[docs] def getReadFunc(self):
return isotxs.readBinary
[docs] def getWriteFunc(self):
return isotxs.writeBinary
[docs] def getLibAAPath(self):
return ISOTXS_AA
[docs] def getLibABPath(self):
return ISOTXS_AB
[docs] def getLibAA_ABPath(self):
return ISOTXS_AA_AB
[docs] def getLibLumpedPath(self):
return ISOTXS_LUMPED
[docs]class Gamiso_merge_Tests(TestXSlibraryMerging):
[docs] def getErrorType(self):
return OSError
[docs] def getReadFunc(self):
return gamiso.readBinary
[docs] def getWriteFunc(self):
return gamiso.writeBinary
[docs] def getLibAAPath(self):
return GAMISO_AA
[docs] def getLibABPath(self):
return GAMISO_AB
[docs] def getLibAA_ABPath(self):
return GAMISO_AA_AB
[docs] def getLibLumpedPath(self):
return GAMISO_LUMPED
[docs]class Combined_merge_Tests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.isotxsAA = None
cls.isotxsAB = None
cls.gamisoAA = None
cls.gamisoAB = None
cls.pmatrxAA = None
cls.pmatrxAB = None
cls.libCombined = None
@classmethod
def tearDownClass(cls):
cls.isotxsAA = None
cls.isotxsAB = None
cls.gamisoAA = None
cls.gamisoAB = None
cls.pmatrxAA = None
cls.pmatrxAB = None
cls.libCombined = None
del cls.isotxsAA
del cls.isotxsAB
del cls.gamisoAA
del cls.gamisoAB
del cls.pmatrxAA
del cls.pmatrxAB
del cls.libCombined
def setUp(self):
# load a library that is in the ARMI tree. This should
# be a small library with LFPs, Actinides, structure, and coolant
for attrName, path, readFunc in [
("isotxsAA", ISOTXS_AA, isotxs.readBinary),
("gamisoAA", GAMISO_AA, gamiso.readBinary),
("pmatrxAA", PMATRX_AA, pmatrx.readBinary),
("isotxsAB", ISOTXS_AB, isotxs.readBinary),
("gamisoAB", GAMISO_AB, gamiso.readBinary),
("pmatrxAB", PMATRX_AB, pmatrx.readBinary),
("libCombined", ISOTXS_AA_AB, isotxs.readBinary),
]:
if getattr(self.__class__, attrName) is None:
setattr(self.__class__, attrName, readFunc(path))
[docs] def test_mergeAllXSLibFiles(self):
lib = xsLibraries.IsotxsLibrary()
xsLibraries.mergeXSLibrariesInWorkingDirectory(
lib, xsLibrarySuffix="", mergeGammaLibs=True, alternateDirectory=FIXTURE_DIR
)
self.assertEqual(set(lib.nuclideLabels), set(self.libCombined.nuclideLabels))
# Remove the abstract class, so that it does not run (all tests would fail)
del TestXSlibraryMerging