Skip to content

Commit

Permalink
Merge 885b17a into aa16faa
Browse files Browse the repository at this point in the history
  • Loading branch information
onufer committed Aug 5, 2022
2 parents aa16faa + 885b17a commit 95281e6
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 50 deletions.
2 changes: 1 addition & 1 deletion armi/materials/material.py
Expand Up @@ -350,7 +350,7 @@ def density(self, Tk: float = None, Tc: float = None) -> float:
density3 should be in agreement at both cold and hot temperatures as long as the block height is correct for
the specified temperature.
In the case of Fluids, density and density3 are the same as density is not driven by linear expansion, but
rather an exilicit density function dependent on Temperature. linearExpansionPercent is zero for a fluid.
rather an explicit density function dependent on Temperature. linearExpansionPercent is zero for a fluid.
See Also
--------
Expand Down
4 changes: 2 additions & 2 deletions armi/reactor/blueprints/blockBlueprint.py
Expand Up @@ -122,12 +122,12 @@ def construct(
if cs["inputHeightsConsideredHot"]:
if "group" in c.name:
for component in c:
component.adjustNDensForHotHeight()
component.applyHotHeightDensityReduction()
componentBlueprint.insertDepletableNuclideKeys(
component, blueprint
)
else:
c.adjustNDensForHotHeight()
c.applyHotHeightDensityReduction()
componentBlueprint.insertDepletableNuclideKeys(c, blueprint)
components[c.name] = c
if spatialGrid:
Expand Down
53 changes: 44 additions & 9 deletions armi/reactor/blueprints/tests/test_blockBlueprints.py
Expand Up @@ -18,6 +18,7 @@
from armi.reactor import blueprints
from armi import settings
from armi.reactor.flags import Flags
from armi.reactor.tests import test_blocks

FULL_BP = """
blocks:
Expand All @@ -29,15 +30,15 @@
Tinput: 25.0
Thot: 600.0
id: 0.0
od: 0.86602
od: 0.7
latticeIDs: [1]
clad:
clad: # same args as test_blocks (except mult)
shape: Circle
material: HT9
Tinput: 25.0
Thot: 470.0
id: 1.0
od: 1.09
Thot: 450.0
id: .77
od: .80
latticeIDs: [1,2]
coolant:
shape: DerivedShape
Expand Down Expand Up @@ -69,15 +70,15 @@
Tinput: 25.0
Thot: 600.0
id: 0.0
od: 0.86602
od: 0.67
latticeIDs: [1]
clad:
shape: Circle
material: HT9
Tinput: 25.0
Thot: 470.0
id: 1.0
od: 1.09
Thot: 450.0
id: .77
od: .80
latticeIDs: [1,2]
coolant:
shape: DerivedShape
Expand Down Expand Up @@ -317,6 +318,40 @@ def test_explicitFlags(self):
self.assertTrue(a1.hasFlags(Flags.FUEL, exact=True))
self.assertTrue(a2.hasFlags(Flags.FUEL | Flags.TEST, exact=True))

def test_densityConsistentWithComponentConstructor(self):
# when comparing to 3D density, the comparison is not quite correct.
# We need a bigger delta, this will be investigated/fixed in another PR
biggerDelta = 0.001 # g/cc
a1 = self.blueprints.assemDesigns.bySpecifier["IC"].construct(
self.cs, self.blueprints
)
fuelBlock = a1[0]
clad = fuelBlock.getComponent(Flags.CLAD)

# now construct clad programmatically like in test_Blocks
programmaticBlock = test_blocks.buildSimpleFuelBlock()
programaticClad = programmaticBlock.getComponent(Flags.CLAD)
self.assertAlmostEqual(
clad.getMassDensity(),
clad.material.density3(Tc=clad.temperatureInC),
delta=biggerDelta,
)
# This should be equal, but block construction calls applyHotHeightDensityReduction
# while programmatic construction allows components to exist in a state where
# their density is not consistent with material density.
self.assertNotAlmostEqual(
clad.getMassDensity(),
programaticClad.getMassDensity(),
delta=biggerDelta,
)
# its off by a factor of thermal expansion
self.assertNotAlmostEqual(
clad.getMassDensity(),
programaticClad.getMassDensity()
* programaticClad.getThermalExpansionFactor(),
delta=biggerDelta,
)


if __name__ == "__main__":
# import sys;sys.argv = ['', 'Test.testName']
Expand Down
39 changes: 29 additions & 10 deletions armi/reactor/components/component.py
Expand Up @@ -232,7 +232,7 @@ def __init__(
self.temperatureInC = Thot
self.material = None
self.setProperties(material)
self.setNDensFromMassFracsAtTempInC() # not necessary when duplicating...
self.applyMaterialMassFracsToNumberDensities() # not necessary when duplicating...
self.setType(name)
self.p.mergeWith = mergeWith
self.p.customIsotopicsName = isotopics
Expand Down Expand Up @@ -327,7 +327,7 @@ def setProperties(self, properties):
self.material.parent = self
self.clearLinkedCache()

def setNDensFromMassFracsAtTempInC(self):
def applyMaterialMassFracsToNumberDensities(self):
"""
Set number densities for the component based on material mass fractions using hot temperatures.
Expand All @@ -339,15 +339,17 @@ def setNDensFromMassFracsAtTempInC(self):
See Also
--------
self.adjustNDensForHotHeight
self.applyHotHeightDensityReduction
"""
# note, that this is not the actual material density, but rather 2D expanded
# `density3` is 3D density
density = self.material.getProperty("density", Tc=self.temperatureInC)

self.p.numberDensities = densityTools.getNDensFromMasses(
density, self.material.p.massFrac
)

def adjustNDensForHotHeight(self):
def applyHotHeightDensityReduction(self):
"""
Adjust number densities to account for prescribed hot block heights (axial expansion).
Expand All @@ -359,7 +361,7 @@ def adjustNDensForHotHeight(self):
See Also
--------
self.setNDensFromMassFracsAtTempInC
self.applyMaterialMassFracsToNumberDensities
"""
axialExpansionFactor = 1.0 + self.material.linearExpansionFactor(
self.temperatureInC, self.inputTemperatureInC
Expand Down Expand Up @@ -735,15 +737,32 @@ def getMass(self, nuclideNames=None):
mass : float
The mass in grams.
"""
nuclideNames = self._getNuclidesFromSpecifier(nuclideNames)
volume = self.getVolume() / (
self.parent.getSymmetryFactor() if self.parent else 1.0
)
return self.getMassDensity(nuclideNames) * volume

def getMassDensity(self, nuclideNames=None):
"""
Return the mass density of the component, in g/cc.
Parameters
----------
nuclideNames : str, optional
The nuclide/element specifier to get the partial density of in
the object. If omitted, total density is returned.
Returns
-------
density : float
The density in grams/cc.
"""
nuclideNames = self._getNuclidesFromSpecifier(nuclideNames)
# densities comes from self.p.numberDensities
densities = self.getNuclideNumberDensities(nuclideNames)
return sum(
densityTools.getMassInGrams(nucName, volume, numberDensity)
for nucName, numberDensity in zip(nuclideNames, densities)
)
nDens = {nuc: dens for nuc, dens in zip(nuclideNames, densities)}
massDensity = densityTools.calculateMassDensity(nDens)
return massDensity

def setDimension(self, key, val, retainLink=False, cold=True):
"""
Expand Down
2 changes: 1 addition & 1 deletion armi/reactor/converters/tests/test_blockConverter.py
Expand Up @@ -55,7 +55,7 @@ def _perturbTemps(self, block, cName, tCold, tHot):
"Give the component different ref and hot temperatures than in test_Blocks."
c = block.getComponent(Flags.fromString(cName))
c.refTemp, c.refHot = tCold, tHot
c.adjustNDensForHotHeight()
c.applyHotHeightDensityReduction()
c.setTemperature(tHot)
return block

Expand Down
2 changes: 1 addition & 1 deletion armi/reactor/tests/test_blocks.py
Expand Up @@ -2282,7 +2282,7 @@ def test_coldMass(self):
and hot height.
"""
fuel = self.b.getComponent(Flags.FUEL)
fuel.adjustNDensForHotHeight()
fuel.applyHotHeightDensityReduction()
# set ref (input/cold) temperature.
Thot = fuel.temperatureInC
Tcold = fuel.inputTemperatureInC
Expand Down

0 comments on commit 95281e6

Please sign in to comment.