# 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.
"""XS Settings tests"""
# pylint: disable=missing-function-docstring,missing-class-docstring,abstract-method,protected-access,unused-variable
import io
import unittest
from ruamel.yaml import YAML
import voluptuous as vol
from armi import settings
from armi.physics.neutronics.const import CONF_CROSS_SECTION
from armi.physics.neutronics.crossSectionSettings import CONF_BLOCK_REPRESENTATION
from armi.physics.neutronics.crossSectionSettings import CONF_GEOM
from armi.physics.neutronics.crossSectionSettings import XSModelingOptions
from armi.physics.neutronics.crossSectionSettings import XSSettingDef
from armi.physics.neutronics.crossSectionSettings import XSSettings
from armi.physics.neutronics.crossSectionSettings import xsSettingsValidator
from armi.physics.neutronics.tests.test_neutronicsPlugin import XS_EXAMPLE
from armi.physics.neutronics.settings import (
CONF_XS_BLOCK_REPRESENTATION,
CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION,
)
from armi.settings import caseSettings
[docs]class TestCrossSectionSettings(unittest.TestCase):
[docs] def test_crossSections(self):
xsModel = XSModelingOptions(
xsID="AA",
geometry="0D",
criticalBuckling=True,
blockRepresentation="Median",
)
self.assertEqual("AA", xsModel.xsID)
self.assertEqual("0D", xsModel.geometry)
self.assertEqual("Median", xsModel.blockRepresentation)
self.assertFalse(xsModel.fluxIsPregenerated)
self.assertFalse(xsModel.xsIsPregenerated)
self.assertTrue(xsModel.criticalBuckling)
[docs] def test_pregeneratedCrossSections(self):
cs = settings.Settings()
xs = XSSettings()
xa = XSModelingOptions("XA", xsFileLocation=["ISOXA"])
xs["XA"] = xa
self.assertEqual(["ISOXA"], xa.xsFileLocation)
self.assertNotIn("XB", xs)
xs.setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
# Check that the file location of 'XB' still points to the same file location as 'XA'.
self.assertEqual(xa, xs["XB"])
self.assertFalse(xa.fluxIsPregenerated)
self.assertTrue(xa.xsIsPregenerated)
self.assertFalse(xa.criticalBuckling)
[docs] def test_prioritization(self):
xsModel = XSModelingOptions(
xsID="AA",
geometry="0D",
criticalBuckling=True,
xsPriority=2,
xsExecuteExclusive=True,
)
self.assertEqual("AA", xsModel.xsID)
self.assertEqual(True, xsModel.xsExecuteExclusive)
self.assertEqual(2, xsModel.xsPriority)
xsModel = XSModelingOptions(
xsID="AA",
geometry="0D",
criticalBuckling=True,
)
# defaults work
xsModel.setDefaults("Average", False)
self.assertEqual(False, xsModel.xsExecuteExclusive)
self.assertEqual(5, xsModel.xsPriority)
[docs] def test_homogeneousXsDefaultSettingAssignment(self):
"""
Make sure the object can whip up an unspecified xsID by default.
This is used when user hasn't specified anything.
"""
cs = settings.Settings()
xsModel = XSSettings()
xsModel.setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
self.assertNotIn("YA", xsModel)
self.assertEqual(xsModel["YA"].geometry, "0D")
self.assertEqual(xsModel["YA"].criticalBuckling, True)
[docs] def test_setDefaultSettingsByLowestBuGroupHomogeneous(self):
# Initialize some micro suffix in the cross sections
cs = settings.Settings()
xs = XSSettings()
jd = XSModelingOptions("JD", geometry="0D", criticalBuckling=False)
xs["JD"] = jd
xs.setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
self.assertIn("JD", xs)
# Check that new micro suffix `JF` with higher burn-up group gets assigned the same settings as `JD`
self.assertNotIn("JF", xs)
self.assertEqual(xs["JD"], xs["JF"])
self.assertNotIn("JF", xs)
# Check that new micro suffix `JG` with higher burn-up group gets assigned the same settings as `JD`
self.assertNotIn("JG", xs)
self.assertEqual(xs["JG"], xs["JD"])
# Check that new micro suffix `JB` with lower burn-up group does NOT get assigned the same settings as `JD`
self.assertNotIn("JB", xs)
self.assertNotEqual(xs["JD"], xs["JB"])
[docs] def test_setDefaultSettingsByLowestBuGroupOneDimensional(self):
# Initialize some micro suffix in the cross sections
cs = settings.Settings()
xsModel = XSSettings()
rq = XSModelingOptions(
"RQ",
geometry="1D cylinder",
blockRepresentation="ComponentAverage1DCylinder",
meshSubdivisionsPerCm=1.0,
)
xsModel["RQ"] = rq
xsModel.setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
# Check that new micro suffix `RY` with higher burn-up group gets assigned the same settings as `RQ`
self.assertNotIn("RY", xsModel)
self.assertEqual(xsModel["RY"], xsModel["RQ"])
# Check that new micro suffix `RZ` with higher burn-up group gets assigned the same settings as `RQ`
self.assertNotIn("RZ", xsModel)
self.assertEqual(xsModel["RZ"], xsModel["RQ"])
# Check that new micro suffix `RA` with lower burn-up group does NOT get assigned the same settings as `RQ`
self.assertNotIn("RA", xsModel)
self.assertNotEqual(xsModel["RA"], xsModel["RQ"])
[docs] def test_optionalKey(self):
"""Test that optional key shows up with default value."""
cs = settings.Settings()
xsModel = XSSettings()
da = XSModelingOptions("DA", geometry="1D cylinder", meshSubdivisionsPerCm=1.0)
xsModel["DA"] = da
xsModel.setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
self.assertEqual(xsModel["DA"].mergeIntoClad, ["gap"])
self.assertEqual(xsModel["DA"].meshSubdivisionsPerCm, 1.0)
[docs] def test_badCrossSections(self):
with self.assertRaises(TypeError):
# This will fail because it is not the required
# Dict[str: Dict] structure
xsSettingsValidator({CONF_GEOM: "4D"})
with self.assertRaises(vol.error.MultipleInvalid):
# This will fail because it has an invalid type for ``driverID``
xsSettingsValidator({"AA": {"driverId": 0.0}})
with self.assertRaises(vol.error.MultipleInvalid):
# This will fail because it has an invalid value for
# the ``blockRepresentation``
xsSettingsValidator({"AA": {CONF_BLOCK_REPRESENTATION: "Invalid"}})
with self.assertRaises(vol.error.MultipleInvalid):
# This will fail because the ``xsID`` is not one or two
# characters
xsSettingsValidator({"AAA": {CONF_BLOCK_REPRESENTATION: "Average"}})
[docs]class Test_XSSettings(unittest.TestCase):
[docs] def test_yamlIO(self):
"""Ensure we can read/write this custom setting object to yaml"""
yaml = YAML()
inp = yaml.load(io.StringIO(XS_EXAMPLE))
xs = XSSettingDef("TestSetting")
xs.setValue(inp)
self.assertEqual(xs.value["BA"].geometry, "1D slab")
outBuf = io.StringIO()
output = xs.dump()
yaml.dump(output, outBuf)
outBuf.seek(0)
inp2 = yaml.load(outBuf)
self.assertEqual(inp.keys(), inp2.keys())
[docs] def test_caseSettings(self):
"""
Test the setting of the cross section setting using the case settings object.
Notes
-----
The purpose of this test is to ensure that the cross sections sections can
be removed from an existing case settings object once they have been set.
"""
def _setInitialXSSettings():
cs = caseSettings.Settings()
cs[CONF_CROSS_SECTION] = XSSettings()
cs[CONF_CROSS_SECTION]["AA"] = XSModelingOptions("AA", geometry="0D")
cs[CONF_CROSS_SECTION]["BA"] = XSModelingOptions("BA", geometry="0D")
self.assertIn("AA", cs[CONF_CROSS_SECTION])
self.assertIn("BA", cs[CONF_CROSS_SECTION])
self.assertNotIn("CA", cs[CONF_CROSS_SECTION])
self.assertNotIn("DA", cs[CONF_CROSS_SECTION])
return cs
cs = _setInitialXSSettings()
cs[CONF_CROSS_SECTION] = {"AA": {}, "BA": {}}
self.assertDictEqual(cs[CONF_CROSS_SECTION], {})
self.assertTrue(isinstance(cs[CONF_CROSS_SECTION], XSSettings))
# Produce an error if the setting is set to
# a None value
cs = _setInitialXSSettings()
with self.assertRaises(TypeError):
cs[CONF_CROSS_SECTION] = None
cs = _setInitialXSSettings()
cs[CONF_CROSS_SECTION] = {"AA": None, "BA": {}}
self.assertDictEqual(cs[CONF_CROSS_SECTION], {})
# Test that a new XS setting can be added to an existing
# caseSetting using the ``XSModelingOptions`` or using
# a dictionary.
cs = _setInitialXSSettings()
cs[CONF_CROSS_SECTION].update(
{"CA": XSModelingOptions("CA", geometry="0D"), "DA": {CONF_GEOM: "0D"}}
)
self.assertIn("AA", cs[CONF_CROSS_SECTION])
self.assertIn("BA", cs[CONF_CROSS_SECTION])
self.assertIn("CA", cs[CONF_CROSS_SECTION])
self.assertIn("DA", cs[CONF_CROSS_SECTION])
# Clear out the settings by setting the value to a None.
# This will be interpreted as a empty dictionary.
cs[CONF_CROSS_SECTION] = {}
self.assertDictEqual(cs[CONF_CROSS_SECTION], {})
self.assertTrue(isinstance(cs[CONF_CROSS_SECTION], XSSettings))
# This will fail because the ``setDefaults`` method on the
# ``XSSettings`` has not yet been called.
with self.assertRaises(ValueError):
cs[CONF_CROSS_SECTION]["AA"]
cs[CONF_CROSS_SECTION].setDefaults(
blockRepresentation=cs[CONF_XS_BLOCK_REPRESENTATION],
validBlockTypes=cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
cs[CONF_CROSS_SECTION]["AA"]
self.assertEqual(cs[CONF_CROSS_SECTION]["AA"].geometry, "0D")
[docs] def test_csBlockRepresentation(self):
"""
Test that the XS block representation is applied globally,
but only to XS modeling options where the blockRepresentation
has not already been assigned.
"""
cs = caseSettings.Settings()
cs[CONF_XS_BLOCK_REPRESENTATION] = "FluxWeightedAverage"
cs[CONF_CROSS_SECTION] = XSSettings()
cs[CONF_CROSS_SECTION]["AA"] = XSModelingOptions("AA", geometry="0D")
cs[CONF_CROSS_SECTION]["BA"] = XSModelingOptions(
"BA", geometry="0D", blockRepresentation="Average"
)
self.assertEqual(cs[CONF_CROSS_SECTION]["AA"].blockRepresentation, None)
self.assertEqual(cs[CONF_CROSS_SECTION]["BA"].blockRepresentation, "Average")
cs[CONF_CROSS_SECTION].setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
self.assertEqual(
cs[CONF_CROSS_SECTION]["AA"].blockRepresentation, "FluxWeightedAverage"
)
self.assertEqual(cs[CONF_CROSS_SECTION]["BA"].blockRepresentation, "Average")
[docs] def test_csBlockRepresentationFileLocation(self):
"""
Test that default blockRepresentation is applied correctly to a
XSModelingOption that has the ``xsFileLocation`` attribute defined.
"""
cs = caseSettings.Settings()
cs[CONF_XS_BLOCK_REPRESENTATION] = "FluxWeightedAverage"
cs[CONF_CROSS_SECTION] = XSSettings()
cs[CONF_CROSS_SECTION]["AA"] = XSModelingOptions("AA", xsFileLocation=[])
# Check FluxWeightedAverage
cs[CONF_CROSS_SECTION].setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
self.assertEqual(
cs[CONF_CROSS_SECTION]["AA"].blockRepresentation, "FluxWeightedAverage"
)
# Check Average
cs[CONF_XS_BLOCK_REPRESENTATION] = "Average"
cs[CONF_CROSS_SECTION]["AA"] = XSModelingOptions("AA", xsFileLocation=[])
cs[CONF_CROSS_SECTION].setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
self.assertEqual(cs[CONF_CROSS_SECTION]["AA"].blockRepresentation, "Average")
# Check Median
cs[CONF_XS_BLOCK_REPRESENTATION] = "Average"
cs[CONF_CROSS_SECTION]["AA"] = XSModelingOptions(
"AA", xsFileLocation=[], blockRepresentation="Median"
)
cs[CONF_CROSS_SECTION].setDefaults(
cs[CONF_XS_BLOCK_REPRESENTATION],
cs[CONF_DISABLE_BLOCK_TYPE_EXCLUSION_IN_XS_GENERATION],
)
self.assertEqual(cs[CONF_CROSS_SECTION]["AA"].blockRepresentation, "Median")
[docs] def test_xsSettingsSetDefault(self):
"""Test the configuration options of the ``setDefaults`` method."""
cs = caseSettings.Settings()
cs[CONF_XS_BLOCK_REPRESENTATION] = "FluxWeightedAverage"
cs[CONF_CROSS_SECTION].setDefaults(
blockRepresentation=cs[CONF_XS_BLOCK_REPRESENTATION], validBlockTypes=None
)
self.assertEqual(cs[CONF_CROSS_SECTION]["AA"].validBlockTypes, None)
cs[CONF_CROSS_SECTION].setDefaults(
blockRepresentation=cs[CONF_XS_BLOCK_REPRESENTATION], validBlockTypes=True
)
self.assertEqual(cs[CONF_CROSS_SECTION]["AA"].validBlockTypes, None)
cs[CONF_CROSS_SECTION].setDefaults(
blockRepresentation=cs[CONF_XS_BLOCK_REPRESENTATION], validBlockTypes=False
)
self.assertEqual(cs[CONF_CROSS_SECTION]["AA"].validBlockTypes, ["fuel"])
cs[CONF_CROSS_SECTION].setDefaults(
blockRepresentation=cs[CONF_XS_BLOCK_REPRESENTATION],
validBlockTypes=["control", "fuel", "plenum"],
)
self.assertEqual(
cs[CONF_CROSS_SECTION]["AA"].validBlockTypes, ["control", "fuel", "plenum"]
)
if __name__ == "__main__":
unittest.main()