# 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 functionalities of components within ARMI."""
import copy
import math
import unittest
from armi.materials.material import Material
from armi.reactor import components
from armi.reactor import flags
from armi.reactor.components import (
Component,
UnshapedComponent,
NullComponent,
Circle,
Hexagon,
HoledHexagon,
HexHoledCircle,
HoledRectangle,
HoledSquare,
Helix,
Sphere,
Cube,
Rectangle,
SolidRectangle,
Square,
Triangle,
RadialSegment,
DifferentialRadialSegment,
DerivedShape,
UnshapedVolumetricComponent,
ComponentType,
)
from armi.reactor.components import materials
from armi.materials import air, alloy200
[docs]class TestComponentFactory(unittest.TestCase):
[docs] def getCircleVoidDict(self):
return dict(
shape="circle",
name="gap",
Tinput=25,
Thot=600,
od=2.1,
id=0.0,
mult=7,
material="Void",
isotopics="",
)
[docs] def getCircleFuelDict(self):
return dict(
shape="circle",
name="fuel",
Tinput=25,
Thot=600,
od=2.1,
id=0.0,
mult=7,
material="UZr",
isotopics="",
)
[docs] def test_factory(self):
"""Creating and verifying void and fuel components.
.. test:: Example void and fuel components are initialized.
:id: T_ARMI_COMP_DEF0
:tests: R_ARMI_COMP_DEF
"""
voidAttrs = self.getCircleVoidDict()
voidComp = components.factory(voidAttrs.pop("shape"), [], voidAttrs)
fuelAttrs = self.getCircleFuelDict()
fuelComp = components.factory(fuelAttrs.pop("shape"), [], fuelAttrs)
self.assertIsInstance(voidComp, components.Circle)
self.assertIsInstance(voidComp.material, materials.Void)
self.assertIsInstance(fuelComp, components.Circle)
self.assertIsInstance(fuelComp.material, materials.UZr)
[docs] def test_componentInitializationAndDuplication(self):
"""Initialize and duplicate a component, veifying the parameters.
.. test:: Verify the parameters of an initialized component.
:id: T_ARMI_COMP_DEF1
:tests: R_ARMI_COMP_DEF
"""
# populate the class/signature dict, and create a basis attrs
attrs = self.getCircleVoidDict()
del attrs["shape"]
del attrs["od"]
del attrs["id"]
del attrs["mult"]
for i, (name, klass) in enumerate(ComponentType.TYPES.items()):
# hack together a dictionary input
thisAttrs = {k: 1.0 for k in set(klass.INIT_SIGNATURE).difference(attrs)}
del thisAttrs["components"]
thisAttrs.update(attrs)
thisAttrs["name"] = "banana{}".format(i)
if "modArea" in thisAttrs:
thisAttrs["modArea"] = None
component = components.factory(name, [], thisAttrs)
duped = copy.deepcopy(component)
for key, val in component.p.items():
if key not in ["area", "volume", "serialNum"]: # they get recomputed
self.assertEqual(
val,
duped.p[key],
msg="Key: {}, val1: {}, val2: {}".format(
key, val, duped.p[key]
),
)
[docs] def test_factoryBadShapeName(self):
badDict = self.getCircleFuelDict()
with self.assertRaises(ValueError):
components.factory("turtle", [], badDict)
[docs] def test_invalidCoolantComponentAssignment(self):
invalidComponentTypes = [Component, NullComponent]
for CompType in invalidComponentTypes:
with self.assertRaises(ValueError):
_c = CompType("coolant", "Sodium", 0, 0)
[docs]class TestGeneralComponents(unittest.TestCase):
"""Base test for all individual component tests."""
componentCls = Component
componentMaterial = "HT9"
componentDims = {"Tinput": 25.0, "Thot": 25.0}
def setUp(self, component=None):
"""
Most of the time nothing will be passed as `component` and the result will
be stored in self, but you can also pass a component object as `component`,
in which case the object will be returned with the `parent` attribute assigned.
"""
class _Parent:
def getSymmetryFactor(self):
return 1.0
def getHeight(self):
return 1.0
def clearCache(self):
pass
def getChildren(self):
return []
derivedMustUpdate = False
if component is None:
self.component = self.componentCls(
"TestComponent", self.componentMaterial, **self.componentDims
)
self.component.parent = _Parent()
else:
component.parent = _Parent()
return component
[docs]class TestComponent(TestGeneralComponents):
"""Test the base component."""
componentCls = Component
[docs] def test_initializeComponentMaterial(self):
"""Creating component with single material.
.. test:: Components are made of one material.
:id: T_ARMI_COMP_1MAT0
:tests: R_ARMI_COMP_1MAT
"""
expectedName = "TestComponent"
actualName = self.component.getName()
expectedMaterialName = "HT9"
actualMaterialName = self.component.material.getName()
self.assertEqual(expectedName, actualName)
self.assertEqual(expectedMaterialName, actualMaterialName)
[docs] def test_setNumberDensity(self):
"""Test setting a single number density.
.. test:: Users can set Component number density.
:id: T_ARMI_COMP_NUCLIDE_FRACS0
:tests: R_ARMI_COMP_NUCLIDE_FRACS
"""
component = self.component
self.assertAlmostEqual(component.getNumberDensity("C"), 0.000780, 6)
component.setNumberDensity("C", 0.57)
self.assertEqual(component.getNumberDensity("C"), 0.57)
[docs] def test_setNumberDensities(self):
"""Test setting multiple number densities.
.. test:: Users can set Component number densities.
:id: T_ARMI_COMP_NUCLIDE_FRACS1
:tests: R_ARMI_COMP_NUCLIDE_FRACS
"""
component = self.component
self.assertAlmostEqual(component.getNumberDensity("MN"), 0.000426, 6)
component.setNumberDensities({"C": 1, "MN": 0.58})
self.assertEqual(component.getNumberDensity("C"), 1.0)
self.assertEqual(component.getNumberDensity("MN"), 0.58)
[docs] def test_solid_material(self):
"""Determine if material is solid.
.. test:: Determine if material is solid.
:id: T_ARMI_COMP_SOLID
:tests: R_ARMI_COMP_SOLID
.. test:: Components have material properties.
:id: T_ARMI_COMP_MAT
:tests: R_ARMI_COMP_MAT
"""
self.assertTrue(isinstance(self.component.getProperties(), Material))
self.assertTrue(hasattr(self.component.material, "density"))
self.assertIn("HT9", str(self.component.getProperties()))
self.component.material = air.Air()
self.assertFalse(self.component.containsSolidMaterial())
self.component.material = alloy200.Alloy200()
self.assertTrue(self.component.containsSolidMaterial())
self.assertTrue(isinstance(self.component.getProperties(), Material))
self.assertTrue(hasattr(self.component.material, "density"))
self.assertIn("Alloy200", str(self.component.getProperties()))
[docs]class TestNullComponent(TestGeneralComponents):
componentCls = NullComponent
[docs] def test_cmp(self):
"""Test null component."""
cur = self.component
ref = DerivedShape("DerivedShape", "Material", 0, 0)
self.assertLess(cur, ref)
[docs] def test_nonzero(self):
cur = bool(self.component)
ref = False
self.assertEqual(cur, ref)
[docs] def test_getDimension(self):
"""Test getting empty component.
.. test:: Retrieve a null dimension.
:id: T_ARMI_COMP_DIMS0
:tests: R_ARMI_COMP_DIMS
"""
for temp in range(400, 901, 25):
self.assertEqual(self.component.getDimension("", Tc=temp), 0.0)
[docs]class TestUnshapedComponent(TestGeneralComponents):
componentCls = UnshapedComponent
componentMaterial = "HT9"
componentDims = {"Tinput": 25.0, "Thot": 430.0, "area": math.pi}
[docs] def test_getComponentArea(self):
# a case without thermal expansion
self.assertEqual(self.component.getComponentArea(cold=True), math.pi)
# a case with thermal expansion
self.assertEqual(
self.component.getComponentArea(cold=False),
math.pi
* self.component.getThermalExpansionFactor(self.component.temperatureInC)
** 2,
)
# show that area expansion is consistent with the density change in the material
hotDensity = self.component.density()
hotArea = self.component.getArea()
thermalExpansionFactor = self.component.getThermalExpansionFactor(
self.component.temperatureInC
)
coldComponent = self.setUp(
UnshapedComponent(
name="coldComponent",
material=self.componentMaterial,
Tinput=self.component.inputTemperatureInC,
Thot=self.component.inputTemperatureInC,
area=math.pi,
)
)
coldDensity = coldComponent.density()
coldArea = coldComponent.getArea()
self.assertGreater(thermalExpansionFactor, 1)
# thermalExpansionFactor accounts for density being 3D while area is 2D
self.assertAlmostEqual(
(coldDensity * coldArea),
(thermalExpansionFactor * hotDensity * hotArea),
)
[docs] def test_getBoundingCircleOuterDiameter(self):
# a case without thermal expansion
self.assertEqual(self.component.getBoundingCircleOuterDiameter(cold=True), 2.0)
# a case with thermal expansion
self.assertEqual(
self.component.getBoundingCircleOuterDiameter(cold=False),
2.0
* self.component.getThermalExpansionFactor(self.component.temperatureInC),
)
[docs] def test_component_less_than(self):
"""Ensure that comparisons between components properly reference bounding circle outer diameter.
.. test:: Order components by their outermost diameter
:id: T_ARMI_COMP_ORDER
:tests: R_ARMI_COMP_ORDER
"""
componentCls = UnshapedComponent
componentMaterial = "HT9"
smallDims = {"Tinput": 25.0, "Thot": 430.0, "area": 0.5 * math.pi}
sameDims = {"Tinput": 25.0, "Thot": 430.0, "area": 1.0 * math.pi}
bigDims = {"Tinput": 25.0, "Thot": 430.0, "area": 2.0 * math.pi}
smallComponent = componentCls("TestComponent", componentMaterial, **smallDims)
sameComponent = componentCls("TestComponent", componentMaterial, **sameDims)
bigComponent = componentCls("TestComponent", componentMaterial, **bigDims)
self.assertTrue(smallComponent < self.component)
self.assertFalse(bigComponent < self.component)
self.assertFalse(sameComponent < self.component)
[docs] def test_fromComponent(self):
circle = components.Circle("testCircle", "HT9", 25, 500, 1.0)
unshaped = components.UnshapedComponent.fromComponent(circle)
self.assertEqual(circle.getComponentArea(), unshaped.getComponentArea())
[docs]class TestShapedComponent(TestGeneralComponents):
"""Abstract class for all shaped components."""
[docs] def test_preserveMassDuringThermalExpansion(self):
"""Test that when we thermally expand any arbitrary shape, mass is conserved."""
if not self.component.THERMAL_EXPANSION_DIMS:
return
temperatures = [25.0, 30.0, 40.0, 60.0, 80.0, 430.0]
masses = []
report = "Temperature, mass, volume, dLL\n"
for ht in temperatures:
self.component.setTemperature(ht)
mass = self.component.getMass()
masses.append(mass)
report += "{:10.1f}, {:7.5e}, {:7.5e}, {:7.5e}\n".format(
ht,
mass,
self.component.getVolume(),
self.component.getThermalExpansionFactor(),
)
for mass in masses:
self.assertNotAlmostEqual(mass, 0.0)
self.assertAlmostEqual(
masses[0],
mass,
msg="Masses are not preserved during thermal expansion of component {} at {} C. "
"Original Mass: {}, Thermally Expanded Mass: {}\n{}"
"".format(self.component, ht, masses[0], mass, report),
)
[docs] def test_volumeAfterClearCache(self):
"""
Test volume after cache has been cleared.
.. test:: Clear cache after a dimensions updated.
:id: T_ARMI_COMP_VOL0
:tests: R_ARMI_COMP_VOL
"""
c = UnshapedVolumetricComponent("testComponent", "Custom", 0, 0, volume=1)
self.assertAlmostEqual(c.getVolume(), 1, 6)
c.clearCache()
self.assertAlmostEqual(c.getVolume(), 1, 6)
[docs] def test_densityConsistent(self):
"""Testing the Component matches quick hand calc."""
c = self.component
# no volume defined
if isinstance(c, (DerivedShape, UnshapedVolumetricComponent)):
return
elif type(c) == Component:
return
# basic density sanity test
self.assertAlmostEqual(c.density(), c.getMass() / c.getVolume())
# test 2D expanding density
if c.temperatureInC == c.inputTemperatureInC:
self.assertAlmostEqual(
c.density(), c.material.pseudoDensity(Tc=c.temperatureInC), delta=0.001
)
if not c.is3D:
self.assertAlmostEqual(
c.getArea() * c.parent.getHeight() * c.density(),
self.component.getMass(),
)
[docs] def test_density(self):
"""Testing the Component density gets the correct 3D material density."""
class StrangeMaterial(Material):
"""material designed to make the test easier to understand."""
def pseduoDensity(self, Tk=None, Tc=None):
return 1.0
def density(self, Tk=None, Tc=None):
return 3.0
c = Sphere(
name="strangeBall",
material=StrangeMaterial(),
Tinput=200,
Thot=500,
od=1,
id=0,
mult=1,
)
# we expect to see the 3D material density here
self.assertEqual(c.density(), 3.0)
[docs]class TestDerivedShape(TestShapedComponent):
componentCls = DerivedShape
componentMaterial = "Sodium"
componentDims = {"Tinput": 25.0, "Thot": 400.0, "area": 1.0}
[docs] def test_getBoundingCircleOuterDiameter(self):
self.assertGreater(
self.component.getBoundingCircleOuterDiameter(cold=True), 0.0
)
[docs] def test_computeVolume(self):
"""Test the computeVolume method on a number of components in a block.
.. test:: Compute the volume of a DerivedShape inside solid shapes.
:id: T_ARMI_COMP_FLUID
:tests: R_ARMI_COMP_FLUID
"""
from armi.reactor.tests.test_blocks import buildSimpleFuelBlock
# Calculate the total volume of the block
b = buildSimpleFuelBlock()
totalVolume = b.getVolume()
# calculate the total volume by adding up all the components
c = b.getComponent(flags.Flags.COOLANT)
totalByParts = 0
for co in b.getComponents():
totalByParts += co.computeVolume()
self.assertAlmostEqual(totalByParts, totalVolume)
# test the computeVolume method on the one DerivedShape in thi block
self.assertAlmostEqual(c.computeVolume(), 1386.5232044586771)
[docs]class TestCircle(TestShapedComponent):
"""Test circle shaped component."""
componentCls = Circle
_id = 5.0
_od = 10
_coldTemp = 25.0
componentDims = {
"Tinput": _coldTemp,
"Thot": 25.0,
"od": _od,
"id": _id,
"mult": 1.5,
}
[docs] def test_getThermalExpansionFactorConservedMassByLinearExpansionPercent(self):
"""Test that when ARMI thermally expands a circle, mass is conserved.
.. test:: Calculate thermal expansion.
:id: T_ARMI_COMP_EXPANSION0
:tests: R_ARMI_COMP_EXPANSION
"""
hotTemp = 700.0
dLL = self.component.material.linearExpansionFactor(
Tc=hotTemp, T0=self._coldTemp
)
ref = 1.0 + dLL
cur = self.component.getThermalExpansionFactor(Tc=hotTemp)
self.assertAlmostEqual(cur, ref)
[docs] def test_getDimension(self):
"""Test getting component dimension at specific temperature.
.. test:: Retrieve a dimension at a temperature.
:id: T_ARMI_COMP_DIMS1
:tests: R_ARMI_COMP_DIMS
.. test:: Calculate thermal expansion.
:id: T_ARMI_COMP_EXPANSION1
:tests: R_ARMI_COMP_EXPANSION
"""
for hotTemp in range(600, 901, 25):
ref = self._od * self.component.getThermalExpansionFactor(Tc=hotTemp)
cur = self.component.getDimension("od", Tc=hotTemp)
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a circle."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_getBoundingCircleOuterDiameter(self):
ref = self._od
cur = self.component.getBoundingCircleOuterDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getCircleInnerDiameter(self):
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertAlmostEqual(self._id, cur)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["od", "id", "mult"]
ref = [True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs] def test_getArea(self):
"""Calculate area of circle.
.. test:: Calculate area of circle.
:id: T_ARMI_COMP_VOL1
:tests: R_ARMI_COMP_VOL
"""
# show we can calculate the area once
od = self.component.getDimension("od")
idd = self.component.getDimension("id")
mult = self.component.getDimension("mult")
ref = math.pi * ((od / 2) ** 2 - (idd / 2) ** 2) * mult
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
# show we can clear the cache, change the temp, and correctly re-calc the area
for newTemp in range(500, 690, 19):
self.component.clearCache()
# re-calc area
self.component.temperatureInC = newTemp
od = self.component.getDimension("od", Tc=newTemp)
idd = self.component.getDimension("id", Tc=newTemp)
ref = math.pi * ((od / 2) ** 2 - (idd / 2) ** 2) * mult
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_componentInteractionsLinkingByDimensions(self):
"""Tests linking of Components by dimensions.
.. test:: Show the dimensions of a liquid Component can be defined to depend on the solid Components that bound it.
:id: T_ARMI_COMP_FLUID1
:tests: R_ARMI_COMP_FLUID
The component ``gap``, representing the fuel-clad gap filled with Void,
is defined with dimensions that depend on the fuel outer diameter and
clad inner diameter. The
:py:meth:`~armi.reactor.components.component.Component.resolveLinkedDims`
method links the gap dimensions appropriately when the Component is
constructed, and the test shows the area of the gap is calculated
correctly based on the thermally-expanded dimensions of the fuel and
clad Components.
"""
nPins = 217
fuelDims = {"Tinput": 25.0, "Thot": 430.0, "od": 0.9, "id": 0.0, "mult": nPins}
cladDims = {"Tinput": 25.0, "Thot": 430.0, "od": 1.1, "id": 1.0, "mult": nPins}
fuel = Circle("fuel", "UZr", **fuelDims)
clad = Circle("clad", "HT9", **cladDims)
gapDims = {
"Tinput": 25.0,
"Thot": 430.0,
"od": "clad.id",
"id": "fuel.od",
"mult": nPins,
}
gapDims["components"] = {"clad": clad, "fuel": fuel}
gap = Circle("gap", "Void", **gapDims)
mult = gap.getDimension("mult")
od = gap.getDimension("od")
idd = gap.getDimension("id")
ref = mult * math.pi * ((od / 2.0) ** 2 - (idd / 2.0) ** 2)
cur = gap.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_badComponentName(self):
"""This shows that resolveLinkedDims cannot support names with periods in them."""
nPins = 12
fuelDims = {"Tinput": 25.0, "Thot": 430.0, "od": 0.9, "id": 0.0, "mult": nPins}
cladDims = {"Tinput": 25.0, "Thot": 430.0, "od": 1.1, "id": 1.0, "mult": nPins}
fuel = Circle("fuel", "UZr", **fuelDims)
clad = Circle("clad_4.2.3", "HT9", **cladDims)
gapDims = {
"Tinput": 25.0,
"Thot": 430.0,
"od": "clad_4.2.3.id",
"id": "fuel.od",
"mult": nPins,
}
gapDims["components"] = {"clad_4.2.3": clad, "fuel": fuel}
with self.assertRaises(ValueError):
_gap = Circle("gap", "Void", **gapDims)
[docs] def test_componentInteractionsLinkingBySubtraction(self):
"""Tests linking of components by subtraction."""
nPins = 217
gapDims = {"Tinput": 25.0, "Thot": 430.0, "od": 1.0, "id": 0.9, "mult": nPins}
gap = Circle("gap", "Void", **gapDims)
fuelDims = {
"Tinput": 25.0,
"Thot": 430.0,
"od": 0.9,
"id": 0.0,
"mult": nPins,
"modArea": "gap.sub",
}
fuel = Circle("fuel", "UZr", components={"gap": gap}, **fuelDims)
gapArea = (
gap.getDimension("mult")
* math.pi
* (
(gap.getDimension("od") / 2.0) ** 2
- (gap.getDimension("id") / 2.0) ** 2
)
)
fuelArea = (
fuel.getDimension("mult")
* math.pi
* (
(fuel.getDimension("od") / 2.0) ** 2
- (fuel.getDimension("id") / 2.0) ** 2
)
)
ref = fuelArea - gapArea
cur = fuel.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_getNumberDensities(self):
"""Test that demonstrates that number densities can be retrieved on from component."""
self.component.p.numberDensities = {"NA23": 1.0}
self.assertEqual(self.component.getNumberDensity("NA23"), 1.0)
[docs] def test_changeNumberDensities(self):
"""Test that demonstates that the number densities on a component can be modified."""
self.component.p.numberDensities = {"NA23": 1.0}
self.assertEqual(self.component.getNumberDensity("NA23"), 1.0)
self.component.changeNDensByFactor(3.0)
self.assertEqual(self.component.getNumberDensity("NA23"), 3.0)
[docs] def test_fuelMass(self):
nominalMass = self.component.getMass()
self.component.p.flags = flags.Flags.FUEL
self.assertEqual(self.component.getFuelMass(), nominalMass)
self.component.p.flags = flags.Flags.MODERATOR
self.assertEqual(self.component.getFuelMass(), 0.0)
[docs]class TestComponentExpansion(unittest.TestCase):
tCold = 20
tWarm = 50
tHot = 500
coldOuterDiameter = 1.0
[docs] def test_HT9Expansion(self):
self.runExpansionTests(mat="HT9", isotope="FE")
[docs] def test_UZrExpansion(self):
self.runExpansionTests(mat="UZr", isotope="U235")
[docs] def test_B4CExpansion(self):
self.runExpansionTests(mat="B4C", isotope="B10")
[docs] def runExpansionTests(self, mat: str, isotope: str):
self.componentMassIndependentOfInputTemp(mat)
self.expansionConservationHotHeightDefined(mat, isotope)
self.expansionConservationColdHeightDefined(mat)
[docs] def expansionConservationHotHeightDefined(self, mat: str, isotope: str):
"""
Demonstrate tutorial for how to expand and relationships conserved at during expansion.
Notes
-----
- height taken as hot height and show how quantity is conserved with
inputHeightsConsideredHot = True (the default)
"""
hotHeight = 1.0
circle1 = Circle("circle", mat, self.tCold, self.tWarm, self.coldOuterDiameter)
circle2 = Circle("circle", mat, self.tCold, self.tHot, self.coldOuterDiameter)
# mass density is proportional to Fe number density and derived from
# all the number densities and atomic masses
self.assertAlmostEqual(
circle1.p.numberDensities[isotope] / circle2.p.numberDensities[isotope],
circle1.density() / circle2.density(),
)
# the colder one has more because it is the same cold outer diameter
# but it would be taller at the same temperature
mass1 = circle1.density() * circle1.getArea() * hotHeight
mass2 = circle2.density() * circle2.getArea() * hotHeight
self.assertGreater(mass1, mass2)
# they are off by factor of thermal exp
self.assertAlmostEqual(
mass1 * circle1.getThermalExpansionFactor(),
mass2 * circle2.getThermalExpansionFactor(),
)
# material.pseudoDensity is the 2D density of a material
# material.density is true density and not equal in this case
for circle in [circle1, circle2]:
# 2D density is not equal after application of coldMatAxialExpansionFactor
# which happens during construction
self.assertNotAlmostEqual(
circle.density(),
circle.material.pseudoDensity(Tc=circle.temperatureInC),
)
# 2D density is off by the material thermal exp factor
percent = circle.material.linearExpansionPercent(Tc=circle.temperatureInC)
thermalExpansionFactorFromColdMatTemp = 1 + percent / 100
self.assertAlmostEqual(
circle.density() * thermalExpansionFactorFromColdMatTemp,
circle.material.pseudoDensity(Tc=circle.temperatureInC),
)
self.assertAlmostEqual(
circle.density(),
circle.material.density(Tc=circle.temperatureInC),
)
# brief 2D expansion with set temp to show mass is conserved
# hot height would come from block value
warmMass = circle1.density() * circle1.getArea() * hotHeight
circle1.setTemperature(self.tHot)
hotMass = circle1.density() * circle1.getArea() * hotHeight
self.assertAlmostEqual(warmMass, hotMass)
circle1.setTemperature(self.tWarm)
# Change temp to circle 2 temp to show equal to circle2
# and then change back to show recoverable to original values
oldArea = circle1.getArea()
initialDens = circle1.density()
# when block.setHeight is called (which effectively changes component height)
# component.setNumberDensity is called (for solid isotopes) to adjust the number
# density so that now the 2D expansion will be approximated/expanded around
# the hot temp which is akin to these adjustments
heightFactor = circle1.getHeightFactor(self.tHot)
circle1.adjustDensityForHeightExpansion(self.tHot) # apply temp at new height
circle1.setTemperature(self.tHot)
# now its density is same as hot component
self.assertAlmostEqual(
circle1.density(),
circle2.density(),
)
# show that mass is conserved after expansion
circle1NewHotHeight = hotHeight * heightFactor
self.assertAlmostEqual(
mass1, circle1.density() * circle1.getArea() * circle1NewHotHeight
)
self.assertAlmostEqual(
circle1.density(),
circle1.material.density(Tc=circle1.temperatureInC),
)
# change back to old temp
circle1.adjustDensityForHeightExpansion(self.tWarm)
circle1.setTemperature(self.tWarm)
# check for consistency
self.assertAlmostEqual(initialDens, circle1.density())
self.assertAlmostEqual(oldArea, circle1.getArea())
self.assertAlmostEqual(mass1, circle1.density() * circle1.getArea() * hotHeight)
[docs] def expansionConservationColdHeightDefined(self, mat: str):
"""
Demonstrate that material is conserved at during expansion.
Notes
-----
- height taken as cold height and show how quantity is conserved with
inputHeightsConsideredHot = False
"""
coldHeight = 1.0
circle1 = Circle("circle", mat, self.tCold, self.tWarm, self.coldOuterDiameter)
circle2 = Circle("circle", mat, self.tCold, self.tHot, self.coldOuterDiameter)
# same as 1 but we will make like 2
circle1AdjustTo2 = Circle(
"circle", mat, self.tCold, self.tWarm, self.coldOuterDiameter
)
# make it hot like 2
circle1AdjustTo2.adjustDensityForHeightExpansion(self.tHot)
circle1AdjustTo2.setTemperature(self.tHot)
# check that its like 2
self.assertAlmostEqual(circle2.density(), circle1AdjustTo2.density())
self.assertAlmostEqual(circle2.getArea(), circle1AdjustTo2.getArea())
for circle in [circle1, circle2, circle1AdjustTo2]:
self.assertAlmostEqual(
circle.density(),
circle.material.density(Tc=circle.temperatureInC),
)
# total mass consistent between hot and cold
# Hot height will be taller
hotHeight = coldHeight * circle.getThermalExpansionFactor()
self.assertAlmostEqual(
coldHeight
* circle.getArea(cold=True)
* circle.material.density(Tc=circle.inputTemperatureInC),
hotHeight * circle.getArea() * circle.density(),
)
[docs]class TestTriangle(TestShapedComponent):
"""Test triangle shaped component."""
componentCls = Triangle
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"base": 3.0,
"height": 2.0,
"mult": 30,
}
[docs] def test_getArea(self):
"""Calculate area of triangle.
.. test:: Calculate area of triangle.
:id: T_ARMI_COMP_VOL2
:tests: R_ARMI_COMP_VOL
.. test:: Triangle shaped component
:id: T_ARMI_COMP_SHAPES1
:tests: R_ARMI_COMP_SHAPES
"""
b = self.component.getDimension("base")
h = self.component.getDimension("height")
mult = self.component.getDimension("mult")
ref = mult * 0.5 * b * h
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a triangle."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["base", "height", "mult"]
ref = [True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestRectangle(TestShapedComponent):
"""Test rectangle shaped component."""
componentCls = Rectangle
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"lengthOuter": 6.0,
"lengthInner": 4.0,
"widthOuter": 5.0,
"widthInner": 3.0,
"mult": 2,
}
[docs] def test_negativeArea(self):
dims = {
"Tinput": 25.0,
"Thot": 430.0,
"lengthOuter": 1.0,
"lengthInner": 2.0,
"widthOuter": 5.0,
"widthInner": 6.0,
"mult": 2,
}
refArea = dims["mult"] * (
dims["lengthOuter"] * dims["widthOuter"]
- dims["lengthInner"] * dims["widthInner"]
)
negativeRectangle = Rectangle("test", "Void", **dims)
self.assertAlmostEqual(negativeRectangle.getArea(), refArea)
with self.assertRaises(ArithmeticError):
negativeRectangle = Rectangle("test", "UZr", **dims)
negativeRectangle.getArea()
[docs] def test_getBoundingCircleOuterDiameter(self):
"""Get outer diameter bounding circle.
.. test:: Rectangle shaped component
:id: T_ARMI_COMP_SHAPES2
:tests: R_ARMI_COMP_SHAPES
"""
ref = math.sqrt(61.0)
cur = self.component.getBoundingCircleOuterDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
# verify the area of the rectangle is correct
ref = self.componentDims["lengthOuter"] * self.componentDims["widthOuter"]
ref -= self.componentDims["lengthInner"] * self.componentDims["widthInner"]
ref *= self.componentDims["mult"]
cur = self.component.getArea(cold=True)
self.assertAlmostEqual(cur, ref)
[docs] def test_getCircleInnerDiameter(self):
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertAlmostEqual(math.sqrt(25.0), cur)
[docs] def test_getArea(self):
"""Calculate area of rectangle.
.. test:: Calculate area of rectangle.
:id: T_ARMI_COMP_VOL3
:tests: R_ARMI_COMP_VOL
"""
outerL = self.component.getDimension("lengthOuter")
innerL = self.component.getDimension("lengthInner")
outerW = self.component.getDimension("widthOuter")
innerW = self.component.getDimension("widthInner")
mult = self.component.getDimension("mult")
ref = mult * (outerL * outerW - innerL * innerW)
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a rectangle."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = [
"lengthInner",
"lengthOuter",
"widthInner",
"widthOuter",
"mult",
]
ref = [True, True, True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestSolidRectangle(TestShapedComponent):
componentCls = SolidRectangle
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"lengthOuter": 5.0,
"widthOuter": 5.0,
"mult": 1,
}
[docs] def test_getBoundingCircleOuterDiameter(self):
"""Test get bounding circle of the outer diameter."""
ref = math.sqrt(50)
cur = self.component.getBoundingCircleOuterDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getArea(self):
"""Calculate area of solid rectangle.
.. test:: Calculate area of solid rectangle.
:id: T_ARMI_COMP_VOL4
:tests: R_ARMI_COMP_VOL
"""
outerL = self.component.getDimension("lengthOuter")
outerW = self.component.getDimension("widthOuter")
mult = self.component.getDimension("mult")
ref = mult * (outerL * outerW)
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a solid rectangle."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["lengthOuter", "widthOuter", "mult"]
ref = [True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestSquare(TestShapedComponent):
"""Test square shaped component."""
componentCls = Square
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"widthOuter": 3.0,
"widthInner": 2.0,
"mult": 1,
}
[docs] def test_negativeArea(self):
dims = {
"Tinput": 25.0,
"Thot": 430.0,
"widthOuter": 1.0,
"widthInner": 5.0,
"mult": 1,
}
refArea = dims["mult"] * (
dims["widthOuter"] * dims["widthOuter"]
- dims["widthInner"] * dims["widthInner"]
)
negativeRectangle = Square("test", "Void", **dims)
self.assertAlmostEqual(negativeRectangle.getArea(), refArea)
with self.assertRaises(ArithmeticError):
negativeRectangle = Square("test", "UZr", **dims)
negativeRectangle.getArea()
[docs] def test_getBoundingCircleOuterDiameter(self):
"""Get bounding circle outer diameter.
.. test:: Square shaped component
:id: T_ARMI_COMP_SHAPES3
:tests: R_ARMI_COMP_SHAPES
"""
ref = math.sqrt(18.0)
cur = self.component.getBoundingCircleOuterDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
# verify the area of the circle is correct
ref = (
self.componentDims["widthOuter"] ** 2
- self.componentDims["widthInner"] ** 2
)
cur = self.component.getComponentArea(cold=True)
self.assertAlmostEqual(cur, ref)
[docs] def test_getCircleInnerDiameter(self):
ref = math.sqrt(8.0)
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getArea(self):
"""Calculate area of square.
.. test:: Calculate area of square.
:id: T_ARMI_COMP_VOL5
:tests: R_ARMI_COMP_VOL
"""
outerW = self.component.getDimension("widthOuter")
innerW = self.component.getDimension("widthInner")
mult = self.component.getDimension("mult")
ref = mult * (outerW * outerW - innerW * innerW)
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a square."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["widthOuter", "widthInner", "mult"]
ref = [True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestCube(TestShapedComponent):
componentCls = Cube
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"lengthOuter": 5.0,
"lengthInner": 4.0,
"widthOuter": 5.0,
"widthInner": 3.0,
"heightOuter": 20.0,
"heightInner": 10.0,
"mult": 2,
}
[docs] def test_negativeVolume(self):
dims = {
"Tinput": 25.0,
"Thot": 430.0,
"lengthOuter": 5.0,
"lengthInner": 20.0,
"widthOuter": 5.0,
"widthInner": 30.0,
"heightOuter": 20.0,
"heightInner": 30.0,
"mult": 2,
}
refVolume = dims["mult"] * (
dims["lengthOuter"] * dims["widthOuter"] * dims["heightOuter"]
- dims["lengthInner"] * dims["widthInner"] * dims["heightInner"]
)
negativeCube = Cube("test", "Void", **dims)
self.assertAlmostEqual(negativeCube.getVolume(), refVolume)
with self.assertRaises(ArithmeticError):
negativeCube = Cube("test", "UZr", **dims)
negativeCube.getVolume()
[docs] def test_getVolume(self):
"""Calculate area of cube.
.. test:: Calculate area of cube.
:id: T_ARMI_COMP_VOL6
:tests: R_ARMI_COMP_VOL
"""
lengthO = self.component.getDimension("lengthOuter")
widthO = self.component.getDimension("widthOuter")
heightO = self.component.getDimension("heightOuter")
lengthI = self.component.getDimension("lengthInner")
widthI = self.component.getDimension("widthInner")
heightI = self.component.getDimension("heightInner")
mult = self.component.getDimension("mult")
ref = mult * (lengthO * widthO * heightO - lengthI * widthI * heightI)
cur = self.component.getVolume()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a cube."""
self.assertFalse(self.component.THERMAL_EXPANSION_DIMS)
[docs]class TestHexagon(TestShapedComponent):
"""Test hexagon shaped component."""
componentCls = Hexagon
componentDims = {"Tinput": 25.0, "Thot": 430.0, "op": 10.0, "ip": 5.0, "mult": 1}
[docs] def test_getPerimeter(self):
"""Get perimeter of hexagon.
.. test:: Hexagon shaped component
:id: T_ARMI_COMP_SHAPES4
:tests: R_ARMI_COMP_SHAPES
"""
ip = self.component.getDimension("ip")
mult = self.component.getDimension("mult")
ref = 6 * (ip / math.sqrt(3)) * mult
cur = self.component.getPerimeter()
self.assertAlmostEqual(cur, ref)
[docs] def test_getBoundingCircleOuterDiameter(self):
ref = 2.0 * 10 / math.sqrt(3)
cur = self.component.getBoundingCircleOuterDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getCircleInnerDiameter(self):
ref = 2.0 * 5.0 / math.sqrt(3)
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getArea(self):
"""Calculate area of hexagon.
.. test:: Calculate area of hexagon.
:id: T_ARMI_COMP_VOL7
:tests: R_ARMI_COMP_VOL
"""
cur = self.component.getArea()
mult = self.component.getDimension("mult")
op = self.component.getDimension("op")
ip = self.component.getDimension("ip")
ref = math.sqrt(3.0) / 2.0 * (op**2 - ip**2) * mult
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a hexagon."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["op", "ip", "mult"]
ref = [True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestHoledHexagon(TestShapedComponent):
"""Test holed hexagon shaped component."""
componentCls = HoledHexagon
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"op": 16.5,
"holeOD": 3.6,
"nHoles": 7,
"mult": 1.0,
}
[docs] def test_getBoundingCircleOuterDiameter(self):
ref = 2.0 * 16.5 / math.sqrt(3)
cur = self.component.getBoundingCircleOuterDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getCircleInnerDiameter(self):
ref = 0 # there are multiple holes, so the function should return 0
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertEqual(ref, cur)
# make and test another one with just 1 hole
simpleHoledHexagon = HoledHexagon(
"hex",
"Void",
self.componentDims["Tinput"],
self.componentDims["Thot"],
self.componentDims["op"],
self.componentDims["holeOD"],
nHoles=1,
)
self.assertEqual(
self.componentDims["holeOD"],
simpleHoledHexagon.getCircleInnerDiameter(cold=True),
)
[docs] def test_getArea(self):
"""Calculate area of holed hexagon.
.. test:: Calculate area of holed hexagon.
:id: T_ARMI_COMP_VOL8
:tests: R_ARMI_COMP_VOL
"""
op = self.component.getDimension("op")
odHole = self.component.getDimension("holeOD")
nHoles = self.component.getDimension("nHoles")
mult = self.component.getDimension("mult")
hexarea = math.sqrt(3.0) / 2.0 * (op**2)
holeArea = nHoles * math.pi * ((odHole / 2.0) ** 2)
ref = mult * (hexarea - holeArea)
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a holed hexagon."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["op", "holeOD", "mult"]
ref = [True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestHexHoledCircle(TestShapedComponent):
componentCls = HexHoledCircle
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"od": 16.5,
"holeOP": 3.6,
"mult": 1.0,
}
[docs] def test_getCircleInnerDiameter(self):
simpleHexHoledCircle = HexHoledCircle(
"Circle",
"Void",
self.componentDims["Tinput"],
self.componentDims["Thot"],
self.componentDims["od"],
self.componentDims["holeOP"],
)
self.assertEqual(
self.componentDims["holeOP"],
simpleHexHoledCircle.getCircleInnerDiameter(cold=True),
)
[docs] def test_getArea(self):
"""Calculate area of hex holed circle.
.. test:: Calculate area of hex holed circle.
:id: T_ARMI_COMP_VOL9
:tests: R_ARMI_COMP_VOL
"""
od = self.component.getDimension("od")
holeOP = self.component.getDimension("holeOP")
mult = self.component.getDimension("mult")
hexarea = math.sqrt(3.0) / 2.0 * (holeOP**2)
holeArea = math.pi * ((od / 2.0) ** 2)
ref = mult * (holeArea - hexarea)
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
"""Test that ARMI can thermally expands a holed hexagon."""
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["od", "holeOP", "mult"]
ref = [True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestHoledRectangle(TestShapedComponent):
"""Tests HoledRectangle, and provides much support for HoledSquare test."""
componentCls = HoledRectangle
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"lengthOuter": 16.0,
"widthOuter": 10.0,
"holeOD": 3.6,
"mult": 1.0,
}
dimsToTestExpansion = ["lengthOuter", "widthOuter", "holeOD", "mult"]
def setUp(self):
TestShapedComponent.setUp(self)
self.setClassDims()
[docs] def setClassDims(self):
# This enables subclassing testing for square
self.length = self.component.getDimension("lengthOuter")
self.width = self.component.getDimension("widthOuter")
[docs] def test_getBoundingCircleOuterDiameter(self):
# hypotenuse
ref = (self.length**2 + self.width**2) ** 0.5
cur = self.component.getBoundingCircleOuterDiameter()
self.assertAlmostEqual(ref, cur)
[docs] def test_getCircleInnerDiameter(self):
ref = self.componentDims["holeOD"]
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertEqual(ref, cur)
[docs] def test_getArea(self):
"""Calculate area of holed rectangle.
.. test:: Calculate area of holed rectangle.
:id: T_ARMI_COMP_VOL10
:tests: R_ARMI_COMP_VOL
"""
rectArea = self.length * self.width
odHole = self.component.getDimension("holeOD")
mult = self.component.getDimension("mult")
holeArea = math.pi * ((odHole / 2.0) ** 2)
ref = mult * (rectArea - holeArea)
cur = self.component.getArea()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
ref = [True] * len(self.dimsToTestExpansion)
ref[-1] = False # mult shouldn't expand
for i, d in enumerate(self.dimsToTestExpansion):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs]class TestHoledSquare(TestHoledRectangle):
"""Test holed square shaped component."""
componentCls = HoledSquare
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"widthOuter": 16.0,
"holeOD": 3.6,
"mult": 1.0,
}
dimsToTestExpansion = ["widthOuter", "holeOD", "mult"]
[docs] def setClassDims(self):
# This enables subclassing testing for square
self.width = self.length = self.component.getDimension("widthOuter")
[docs] def test_thermallyExpands(self):
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_getCircleInnerDiameter(self):
ref = self.componentDims["holeOD"]
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertEqual(ref, cur)
[docs]class TestHelix(TestShapedComponent):
"""Test helix shaped component."""
componentCls = Helix
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"od": 0.25,
"axialPitch": 1.0,
"mult": 1.5,
"helixDiameter": 2.0,
"id": 0.1,
}
[docs] def test_getBoundingCircleOuterDiameter(self):
ref = 2.0 + 0.25
cur = self.component.getBoundingCircleOuterDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getCircleInnerDiameter(self):
ref = 2.0 - 0.25
cur = self.component.getCircleInnerDiameter(cold=True)
self.assertAlmostEqual(ref, cur)
[docs] def test_getArea(self):
"""Calculate area of helix.
.. test:: Calculate area of helix.
:id: T_ARMI_COMP_VOL11
:tests: R_ARMI_COMP_VOL
"""
cur = self.component.getArea()
axialPitch = self.component.getDimension("axialPitch")
helixDiameter = self.component.getDimension("helixDiameter")
innerDiameter = self.component.getDimension("id")
outerDiameter = self.component.getDimension("od")
mult = self.component.getDimension("mult")
c = axialPitch / (2.0 * math.pi)
helixFactor = math.sqrt((helixDiameter / 2.0) ** 2 + c**2) / c
ref = (
mult
* math.pi
* (outerDiameter**2 / 4.0 - innerDiameter**2 / 4.0)
* helixFactor
)
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
self.assertTrue(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_dimensionThermallyExpands(self):
expandedDims = ["od", "id", "axialPitch", "helixDiameter", "mult"]
ref = [True, True, True, True, False]
for i, d in enumerate(expandedDims):
cur = d in self.component.THERMAL_EXPANSION_DIMS
self.assertEqual(cur, ref[i])
[docs] def test_validParameters(self):
"""Testing the Helix class performs as expected with various inputs."""
# stupid/simple inputs
h = Helix("thing", "Cu", 0, 0, 1, 1, 1)
self.assertEqual(h.getDimension("axialPitch"), 1)
# standard case / inputs ordered well
h = Helix(
"what",
"Cu",
Tinput=25.0,
Thot=425.0,
id=0.1,
od=0.35,
mult=1.0,
axialPitch=1.123,
helixDiameter=1.5,
)
self.assertTrue(1.123 < h.getDimension("axialPitch") < 1.15)
# inputs ordered crazy
h = Helix(
material="Cu",
id=0.1,
mult=1.0,
Tinput=25.0,
Thot=425.0,
axialPitch=1.123,
name="stuff",
od=0.35,
helixDiameter=1.5,
)
self.assertTrue(1.123 < h.getDimension("axialPitch") < 1.15)
# missing helixDiameter input
with self.assertRaises(TypeError):
h = Helix(
name="helix",
material="Cu",
Tinput=25.0,
Thot=425.0,
id=0.1,
od=0.35,
mult=1.0,
axialPitch=1.123,
)
[docs]class TestSphere(TestShapedComponent):
componentCls = Sphere
componentDims = {"Tinput": 25.0, "Thot": 430.0, "od": 1.0, "id": 0.0, "mult": 3}
[docs] def test_getVolume(self):
"""Calculate area of sphere.
.. test:: Calculate volume of sphere.
:id: T_ARMI_COMP_VOL12
:tests: R_ARMI_COMP_VOL
"""
od = self.component.getDimension("od")
idd = self.component.getDimension("id")
mult = self.component.getDimension("mult")
ref = mult * 4.0 / 3.0 * math.pi * ((od / 2.0) ** 3 - (idd / 2.0) ** 3)
cur = self.component.getVolume()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
self.assertFalse(self.component.THERMAL_EXPANSION_DIMS)
[docs]class TestRadialSegment(TestShapedComponent):
componentCls = RadialSegment
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"inner_radius": 110,
"outer_radius": 170,
"height": 160,
"mult": 1,
}
[docs] def test_getVolume(self):
mult = self.component.getDimension("mult")
outerRad = self.component.getDimension("outer_radius")
innerRad = self.component.getDimension("inner_radius")
outerTheta = self.component.getDimension("outer_theta")
innerTheta = self.component.getDimension("inner_theta")
height = self.component.getDimension("height")
radialArea = math.pi * (outerRad**2 - innerRad**2)
aziFraction = (outerTheta - innerTheta) / (math.pi * 2.0)
ref = mult * radialArea * aziFraction * height
cur = self.component.getVolume()
self.assertAlmostEqual(cur, ref)
[docs] def test_thermallyExpands(self):
self.assertFalse(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_getBoundingCircleOuterDiameter(self):
self.assertEqual(
self.component.getBoundingCircleOuterDiameter(cold=True), 170.0
)
[docs]class TestDifferentialRadialSegment(TestShapedComponent):
componentCls = DifferentialRadialSegment
componentDims = {
"Tinput": 25.0,
"Thot": 430.0,
"inner_radius": 110,
"radius_differential": 60,
"inner_axial": 60,
"height": 160,
}
[docs] def test_getVolume(self):
mult = self.component.getDimension("mult")
outerRad = self.component.getDimension("outer_radius")
innerRad = self.component.getDimension("inner_radius")
outerTheta = self.component.getDimension("outer_theta")
innerTheta = self.component.getDimension("inner_theta")
height = self.component.getDimension("height")
radialArea = math.pi * (outerRad**2 - innerRad**2)
aziFraction = (outerTheta - innerTheta) / (math.pi * 2.0)
ref = mult * radialArea * aziFraction * height
cur = self.component.getVolume()
self.assertAlmostEqual(cur, ref)
[docs] def test_updateDims(self):
"""
Test Update dimensions.
.. test:: Dimensions can be updated.
:id: T_ARMI_COMP_VOL13
:tests: R_ARMI_COMP_VOL
"""
self.assertEqual(self.component.getDimension("inner_radius"), 110)
self.assertEqual(self.component.getDimension("radius_differential"), 60)
self.component.updateDims()
self.assertEqual(self.component.getDimension("outer_radius"), 170)
self.assertEqual(self.component.getDimension("outer_axial"), 220)
self.assertEqual(self.component.getDimension("outer_theta"), 2 * math.pi)
[docs] def test_thermallyExpands(self):
self.assertFalse(self.component.THERMAL_EXPANSION_DIMS)
[docs] def test_getBoundingCircleOuterDiameter(self):
self.assertEqual(self.component.getBoundingCircleOuterDiameter(cold=True), 170)
[docs]class TestMaterialAdjustments(unittest.TestCase):
"""Tests to make sure enrichment and mass fractions can be adjusted properly."""
def setUp(self):
dims = {"Tinput": 25.0, "Thot": 600.0, "od": 10.0, "id": 5.0, "mult": 1.0}
self.fuel = Circle("fuel", "UZr", **dims)
class fakeBlock:
def getHeight(self): # unit height
return 1.0
def getSymmetryFactor(self):
return 1.0
self.fuel.parent = fakeBlock()
[docs] def test_setMassFrac(self):
"""Make sure we can set a mass fraction properly."""
target35 = 0.2
self.fuel.setMassFrac("U235", target35)
self.assertAlmostEqual(self.fuel.getMassFrac("U235"), target35)
[docs] def test_setMassFracOnComponentMaterial(self):
"""Checks for valid and invalid mass fraction assignments on a component's material."""
# Negative value is not acceptable.
with self.assertRaises(ValueError):
self.fuel.material.setMassFrac("U235", -0.1)
# Greater than 1.0 value is not acceptable.
with self.assertRaises(ValueError):
self.fuel.material.setMassFrac("U235", 1.1)
# String is not acceptable.
with self.assertRaises(TypeError):
self.fuel.material.setMassFrac("U235", "")
# `NoneType` is not acceptable.
with self.assertRaises(TypeError):
self.fuel.material.setMassFrac("U235", None)
# Zero is acceptable
self.fuel.material.setMassFrac("U235", 0.0)
self.assertAlmostEqual(self.fuel.material.getMassFrac("U235"), 0.0)
# One is acceptable
self.fuel.material.setMassFrac("U235", 1.0)
self.assertAlmostEqual(self.fuel.material.getMassFrac("U235"), 1.0)
[docs] def test_adjustMassFrac_invalid(self):
with self.assertRaises(ValueError):
self.fuel.adjustMassFrac(nuclideToAdjust="ZR", val=-0.23)
with self.assertRaises(ValueError):
self.fuel.adjustMassFrac(nuclideToAdjust="ZR", val=1.12)
alwaysFalse = lambda a: False
self.fuel.parent = None
self.assertIsNone(self.fuel.getAncestorAndDistance(alwaysFalse))
[docs] def test_adjustMassFrac_U235(self):
zrMass = self.fuel.getMass("ZR")
uMass = self.fuel.getMass("U")
zrFrac = zrMass / (uMass + zrMass)
enrichmentFrac = 0.3
u235Frac = enrichmentFrac * uMass / (uMass + zrMass)
u238Frac = (1.0 - enrichmentFrac) * uMass / (uMass + zrMass)
self.fuel.adjustMassFrac(
nuclideToAdjust="U235", elementToHoldConstant="ZR", val=u235Frac
)
self.assertAlmostEqual(self.fuel.getMassFrac("U235"), u235Frac)
self.assertAlmostEqual(self.fuel.getMassFrac("U238"), u238Frac)
self.assertAlmostEqual(self.fuel.getMassFrac("ZR"), zrFrac)
[docs] def test_adjustMassFrac_U(self):
self.fuel.adjustMassFrac(elementToAdjust="U", val=0.7)
uFrac = self.fuel.getMassFrac("U")
u235Enrichment = 0.1
u238Frac = (1.0 - u235Enrichment) * uFrac
u235Frac = u235Enrichment * uFrac
self.assertAlmostEqual(self.fuel.getMassFrac("U235"), u235Frac)
self.assertAlmostEqual(self.fuel.getMassFrac("U238"), u238Frac)
self.assertAlmostEqual(self.fuel.getMassFrac("ZR"), 0.30)
[docs] def test_adjustMassFrac_clear_ZR(self):
self.fuel.adjustMassFrac(nuclideToAdjust="ZR", val=0.0)
self.assertAlmostEqual(self.fuel.getMassFrac("ZR"), 0.0)
self.assertAlmostEqual(self.fuel.getNumberDensity("ZR"), 0.0)
self.assertAlmostEqual(
self.fuel.getMassFrac("U235") + self.fuel.getMassFrac("U238"), 1.0
)
[docs] def test_adjustMassFrac_set_ZR(self):
u235Enrichment = 0.1
zrFrac = 0.1
uFrac = 1.0 - zrFrac
u238Frac = (1.0 - u235Enrichment) * uFrac
u235Frac = u235Enrichment * uFrac
self.fuel.adjustMassFrac(nuclideToAdjust="ZR", val=zrFrac)
self.assertAlmostEqual(self.fuel.getMassFrac("U235"), u235Frac)
self.assertAlmostEqual(self.fuel.getMassFrac("U238"), u238Frac)
self.assertAlmostEqual(self.fuel.getMassFrac("ZR"), zrFrac)
[docs] def test_adjustMassFrac_leave_same(self):
zrFrac = 0.1
u238Enrichment = 0.9
uFrac = 1.0 - zrFrac
u238Frac = uFrac * u238Enrichment
self.fuel.adjustMassFrac(nuclideToAdjust="ZR", val=zrFrac)
self.assertAlmostEqual(self.fuel.getMassFrac("U238"), u238Frac)
self.assertAlmostEqual(self.fuel.getMassFrac("ZR"), zrFrac)
[docs] def test_adjustMassEnrichment(self):
self.fuel.adjustMassEnrichment(0.2)
self.assertAlmostEqual(self.fuel.getMassFrac("U235"), 0.18)
self.assertAlmostEqual(self.fuel.getMassFrac("U238"), 0.72)
self.assertAlmostEqual(self.fuel.getMassFrac("ZR"), 0.1)
[docs] def test_getEnrichment(self):
self.fuel.adjustMassEnrichment(0.3)
self.assertAlmostEqual(self.fuel.getEnrichment(), 0.3)