From dcb08df15f6c002d8e275baaa2f32434078af71b Mon Sep 17 00:00:00 2001 From: Mark Onufer Date: Thu, 25 Aug 2022 09:46:20 -0700 Subject: [PATCH 1/7] resove #820 --- .../blueprints/tests/test_blockBlueprints.py | 4 -- armi/reactor/components/component.py | 46 +++++++++---------- armi/reactor/tests/test_components.py | 11 ++--- 3 files changed, 25 insertions(+), 36 deletions(-) diff --git a/armi/reactor/blueprints/tests/test_blockBlueprints.py b/armi/reactor/blueprints/tests/test_blockBlueprints.py index 98f0387b9..7053983e4 100644 --- a/armi/reactor/blueprints/tests/test_blockBlueprints.py +++ b/armi/reactor/blueprints/tests/test_blockBlueprints.py @@ -321,9 +321,6 @@ def test_explicitFlags(self): # TODO: This test passes, but shouldn't. 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 ) @@ -336,7 +333,6 @@ def test_densityConsistentWithComponentConstructor(self): self.assertAlmostEqual( clad.getMassDensity(), clad.material.density3(Tc=clad.temperatureInC), - delta=biggerDelta, ) self.assertAlmostEqual( diff --git a/armi/reactor/components/component.py b/armi/reactor/components/component.py index 5b1200a5b..0ffc0d531 100644 --- a/armi/reactor/components/component.py +++ b/armi/reactor/components/component.py @@ -232,27 +232,11 @@ def __init__( self.temperatureInC = Thot self.material = None self.setProperties(material) - self.tInputWarning(Tinput) self.applyMaterialMassFracsToNumberDensities() # not necessary when duplicating... self.setType(name) self.p.mergeWith = mergeWith self.p.customIsotopicsName = isotopics - def tInputWarning(self, Tinput): - """ - Check whether thermal expansion factor is 0.0% exactly at T=Tinput - """ - expansionFactor = ( - self.material.linearExpansionPercent(Tc=self.inputTemperatureInC) / 100.0 - ) - if not (abs(expansionFactor) < 1.0e-6): - runLog.warning( - f"Thermal expansion for {self.material} at Tinput = {Tinput} is non-zero " - f"({expansionFactor}). The modeled density for this material will be off " - f"by a factor of {(1 + expansionFactor) ** 2}.", - single=True, - ) - @property def temperatureInC(self): """Return the hot temperature in Celsius.""" @@ -360,14 +344,15 @@ def applyMaterialMassFracsToNumberDensities(self): """ # note, that this is not the actual material density, but rather 2D expanded # `density3` is 3D density + # call getProperty to cache and improve speed density = self.material.getProperty("density", Tc=self.temperatureInC) self.p.numberDensities = densityTools.getNDensFromMasses( density, self.material.p.massFrac ) - self.applyHotHeightDensityReduction() + self.applyHotHeightDensityReduction(initialColdMaterialExpansion=True) - def applyHotHeightDensityReduction(self): + def applyHotHeightDensityReduction(self, initialColdMaterialExpansion=False): """ Adjust number densities to account for hot block heights (axial expansion) (crucial for preserving 3D density). @@ -382,13 +367,24 @@ def applyHotHeightDensityReduction(self): -------- self.applyMaterialMassFracsToNumberDensities """ - # this is the same as getThermalExpansionFactor but doesn't fail - # on non-fluid materials that have 0 or undefined thermal expansion - # (we don't want materials to fail on __init__ which calls this) - axialExpansionFactor = 1.0 + self.material.linearExpansionFactor( - self.temperatureInC, self.inputTemperatureInC - ) - self.changeNDensByFactor(1.0 / axialExpansionFactor) + if initialColdMaterialExpansion: + # material needs to be expanded from the material's cold temp to hot, + # not components cold temp, so we don't use mat.linearExpansionFactor or + # component.getThermalExpansionFactor. + # materials don't typically define the temperature for which their ref dens + # is defined so linearExpansionPercent must be called + coldMatAxialExpansionFactor = ( + 1.0 + self.material.linearExpansionPercent(Tc=self.temperatureInC) / 100 + ) + self.changeNDensByFactor(1.0 / coldMatAxialExpansionFactor) + else: + # this is the same as getThermalExpansionFactor but doesn't fail + # on non-fluid materials that have 0 or undefined thermal expansion + # (we don't want materials to fail on __init__ which calls this) + # axialExpansionFactor = 1.0 + self.material.linearExpansionFactor( + # self.temperatureInC, self.inputTemperatureInC + # ) + self.changeNDensByFactor(1.0 / self.getThermalExpansionFactor()) def getProperties(self): """Return the active Material object defining thermo-mechanical properties.""" diff --git a/armi/reactor/tests/test_components.py b/armi/reactor/tests/test_components.py index b311d532a..05da07b8c 100644 --- a/armi/reactor/tests/test_components.py +++ b/armi/reactor/tests/test_components.py @@ -499,7 +499,6 @@ def test_changeNumberDensities(self): class TestComponentExpansion(unittest.TestCase): # 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.01 # g/cc tWarm = 50 tHot = 500 @@ -547,15 +546,16 @@ def test_ExpansionConservationHotHeightDefined(self): circle.getMassDensity(), circle.material.density(Tc=circle.temperatureInC), ) - # 2D density is off by the thermal exp factor + # 2D density is off by the material thermal exp factor + percent = circle.material.linearExpansionPercent(Tc=circle.temperatureInC) + thermalExpansionFactorFromColdMatTemp = 1 + percent / 100 self.assertAlmostEqual( - circle.getMassDensity() * circle.getThermalExpansionFactor(), + circle.getMassDensity() * thermalExpansionFactorFromColdMatTemp, circle.material.density(Tc=circle.temperatureInC), ) self.assertAlmostEqual( circle.getMassDensity(), circle.material.density3(Tc=circle.temperatureInC), - delta=self.biggerDelta, ) # Change temp forward and backward and show equal oldArea = circle1.getArea() @@ -604,7 +604,6 @@ def test_ExpansionConservationHotHeightDefined(self): self.assertAlmostEqual( circle1.getMassDensity(), circle1.material.density3(Tc=circle2.temperatureInC), - delta=self.biggerDelta, ) # change back to old temp circle1.changeNDensByFactor(circle1.getThermalExpansionFactor()) @@ -650,7 +649,6 @@ def test_ExpansionConservationColdHeightDefined(self): self.assertAlmostEqual( circle.getMassDensity(), circle.material.density3(Tc=circle.temperatureInC), - delta=self.biggerDelta, ) # total mass consistent between hot and cold # Hot height will be taller @@ -660,7 +658,6 @@ def test_ExpansionConservationColdHeightDefined(self): * circle.getArea(cold=True) * circle.material.density3(Tc=circle.inputTemperatureInC), hotHeight * circle.getArea() * circle.getMassDensity(), - delta=self.biggerDelta, ) From 648b054ea467e8bfbd6185b0e54020b791ecc8f8 Mon Sep 17 00:00:00 2001 From: Mark Onufer Date: Thu, 25 Aug 2022 09:53:36 -0700 Subject: [PATCH 2/7] revert unneeded changes --- armi/materials/zr.py | 2 +- .../refSmallReactorBase.yaml | 60 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/armi/materials/zr.py b/armi/materials/zr.py index a84b570e3..9eeaadcee 100644 --- a/armi/materials/zr.py +++ b/armi/materials/zr.py @@ -130,7 +130,7 @@ def linearExpansionPercent(self, Tk=None, Tc=None): Tk = getTk(Tc, Tk) self.checkPropertyTempRange("linear expansion percent", Tk) - if Tk >= 291.62 and Tk < 1137: + if Tk >= 293 and Tk < 1137: return ( -0.111 + (2.325e-4 * Tk) + (5.595e-7 * Tk ** 2) - (1.768e-10 * Tk ** 3) ) diff --git a/armi/tests/detailedAxialExpansion/refSmallReactorBase.yaml b/armi/tests/detailedAxialExpansion/refSmallReactorBase.yaml index 6c5a6baf1..417347609 100644 --- a/armi/tests/detailedAxialExpansion/refSmallReactorBase.yaml +++ b/armi/tests/detailedAxialExpansion/refSmallReactorBase.yaml @@ -23,7 +23,7 @@ blocks: grid: shape: Hexagon material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 ip: 15.277 mult: 1.0 @@ -60,7 +60,7 @@ blocks: shield: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 600.0 id: 0.0 mult: 169.0 @@ -76,7 +76,7 @@ blocks: clad: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 470.0 id: 1.0 mult: shield.mult @@ -84,7 +84,7 @@ blocks: wire: shape: Helix material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 axialPitch: 30.15 helixDiameter: 1.19056 @@ -95,7 +95,7 @@ blocks: duct: &component_fuel_duct shape: Hexagon material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 ip: 16.0 mult: 1.0 @@ -113,7 +113,7 @@ blocks: fuel: &component_fuel_fuel shape: Circle material: UZr - Tinput: 45.187 + Tinput: 25.0 Thot: 600.0 id: 0.0 mult: 169.0 @@ -129,7 +129,7 @@ blocks: clad: &component_fuel_clad shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 470.0 id: 1.0 mult: fuel.mult @@ -137,7 +137,7 @@ blocks: wire: &component_fuel_wire shape: Helix material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 axialPitch: 30.15 helixDiameter: 1.19056 @@ -160,7 +160,7 @@ blocks: clad: &component_plenum_clad shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 470.0 id: 1.0 mult: 169.0 @@ -168,7 +168,7 @@ blocks: wire: &component_plenum_wire shape: Helix material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 axialPitch: 30.15 helixDiameter: 1.19056 @@ -187,7 +187,7 @@ blocks: duct: shape: Hexagon material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 ip: 16.0 mult: 1.0 @@ -215,7 +215,7 @@ blocks: liner2: &component_fuel2_liner2 shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 600.0 id: 0.98 mergeWith: clad @@ -224,7 +224,7 @@ blocks: liner1: &component_fuel2_liner1 shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 600.0 id: 0.99 mergeWith: clad @@ -251,7 +251,7 @@ blocks: fuel: shape: Circle material: UZr - Tinput: 45.187 + Tinput: 25.0 Thot: 600.0 id: 0.0 isotopics: PuUZr @@ -278,7 +278,7 @@ blocks: fuel: shape: Circle material: UZr - Tinput: 45.187 + Tinput: 25.0 Thot: 600.0 id: 0.600 mult: 169.0 @@ -295,7 +295,7 @@ blocks: inner liner: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 430.0 id: 0.878 mult: fuel.mult @@ -311,7 +311,7 @@ blocks: outer liner: shape: Circle material: Zr - Tinput: 18.474 + Tinput: 25.0 Thot: 430.0 id: 0.898 mult: fuel.mult @@ -327,7 +327,7 @@ blocks: clad: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 430.0 id: 0.900 mult: fuel.mult @@ -344,7 +344,7 @@ blocks: duct: &component_control_duct shape: Hexagon material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 ip: 15.277 mult: 1.0 @@ -378,7 +378,7 @@ blocks: clad: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 id: 1.358 mult: control.mult @@ -386,7 +386,7 @@ blocks: wire: shape: Helix material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 axialPitch: 50.0 helixDiameter: 1.771 @@ -396,7 +396,7 @@ blocks: innerDuct: shape: Hexagon material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 ip: 14.268 mult: 1.0 @@ -417,7 +417,7 @@ blocks: clad: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 id: 1.358 mult: 61.0 @@ -425,7 +425,7 @@ blocks: wire: shape: Helix material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 axialPitch: 30.15 helixDiameter: 1.19056 @@ -442,7 +442,7 @@ blocks: shield: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 600.0 id: 0.0 mult: 169.0 @@ -458,7 +458,7 @@ blocks: clad: shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 id: 0.90562 mult: shield.mult @@ -466,7 +466,7 @@ blocks: wire: shape: Helix material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 axialPitch: 30.15 helixDiameter: 16.85056 @@ -489,7 +489,7 @@ blocks: clad: &component_radial_shield_clad shape: Circle material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 id: 0.90562 mult: 169.0 @@ -497,7 +497,7 @@ blocks: wire: &component_radial_shield_plenum_wire shape: Helix material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 axialPitch: 30.15 helixDiameter: 1.19056 @@ -516,7 +516,7 @@ blocks: duct: shape: Hexagon material: HT9 - Tinput: 27.548 + Tinput: 25.0 Thot: 450.0 ip: 16.0 mult: 1.0 From 5cca38fe66025d47e7225138b6ab151ee4de769b Mon Sep 17 00:00:00 2001 From: Mark Onufer Date: Thu, 25 Aug 2022 10:45:40 -0700 Subject: [PATCH 3/7] dumb unit test change to redo jenkins --- armi/reactor/tests/test_components.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/armi/reactor/tests/test_components.py b/armi/reactor/tests/test_components.py index 05da07b8c..9b08de27c 100644 --- a/armi/reactor/tests/test_components.py +++ b/armi/reactor/tests/test_components.py @@ -501,6 +501,7 @@ class TestComponentExpansion(unittest.TestCase): # We need a bigger delta, this will be investigated/fixed in another PR tWarm = 50 tHot = 500 + coldOuterDiameter = 1.0 def test_ExpansionConservationHotHeightDefined(self): """ @@ -512,9 +513,9 @@ def test_ExpansionConservationHotHeightDefined(self): inputHeightsConsideredHot = True (the default) """ hotHeight = 1.0 - coldOuterDiameter = 1.0 - circle1 = Circle("circle", "HT9", 20, self.tWarm, coldOuterDiameter) - circle2 = Circle("circle", "HT9", 20, self.tHot, coldOuterDiameter) + + circle1 = Circle("circle", "HT9", 20, self.tWarm, self.coldOuterDiameter) + circle2 = Circle("circle", "HT9", 20, self.tHot, self.coldOuterDiameter) # mass density is proportional to Fe number density and derived from # all the number densities and atomic masses @@ -627,8 +628,8 @@ def test_ExpansionConservationColdHeightDefined(self): inputHeightsConsideredHot = False """ coldHeight = 1.0 - circle1 = Circle("circle", "HT9", 20, self.tWarm, 1.0) - circle2 = Circle("circle", "HT9", 20, self.tHot, 1.0) + circle1 = Circle("circle", "HT9", 20, self.tWarm, self.coldOuterDiameter) + circle2 = Circle("circle", "HT9", 20, self.tHot, self.coldOuterDiameter) # same as 1 but we will make like 2 circle1AdjustTo2 = Circle("circle", "HT9", 20, self.tWarm, 1.0) From a10131288372b234fc5c50cba4e7b94edf85c8b6 Mon Sep 17 00:00:00 2001 From: Mark Onufer Date: Thu, 25 Aug 2022 14:02:39 -0700 Subject: [PATCH 4/7] fix test, reviewer comments --- armi/reactor/components/component.py | 52 +++++++------------ .../converters/axialExpansionChanger.py | 4 +- armi/reactor/tests/test_blocks.py | 9 +++- armi/reactor/tests/test_components.py | 47 +++++++++++------ 4 files changed, 60 insertions(+), 52 deletions(-) diff --git a/armi/reactor/components/component.py b/armi/reactor/components/component.py index 0ffc0d531..b69f507ce 100644 --- a/armi/reactor/components/component.py +++ b/armi/reactor/components/component.py @@ -337,10 +337,6 @@ def applyMaterialMassFracsToNumberDensities(self): due to the difference in self.inputTemperatureInC and self.temperatureInC - After the expansion, the density of the component should reflect the 3d density of the material - - See Also - -------- - self.applyHotHeightDensityReduction """ # note, that this is not the actual material density, but rather 2D expanded # `density3` is 3D density @@ -350,41 +346,31 @@ def applyMaterialMassFracsToNumberDensities(self): self.p.numberDensities = densityTools.getNDensFromMasses( density, self.material.p.massFrac ) - self.applyHotHeightDensityReduction(initialColdMaterialExpansion=True) - def applyHotHeightDensityReduction(self, initialColdMaterialExpansion=False): + # material needs to be expanded from the material's cold temp to hot, + # not components cold temp, so we don't use mat.linearExpansionFactor or + # component.getThermalExpansionFactor. + # Materials don't typically define the temperature for which their references + # density is defined so linearExpansionPercent must be called + coldMatAxialExpansionFactor = ( + 1.0 + self.material.linearExpansionPercent(Tc=self.temperatureInC) / 100 + ) + self.changeNDensByFactor(1.0 / coldMatAxialExpansionFactor) + + def adjustDensityForHeightExpansion(self): """ - Adjust number densities to account for hot block heights (axial expansion) - (crucial for preserving 3D density). + Change the densities in cases where height of the block/component is increasing Notes ----- - - We apply this hot height density reduction to account for pre-expanded - block heights in blueprints. - - This is called when inputHeightsConsideredHot: True. - - See Also - -------- - self.applyMaterialMassFracsToNumberDensities + Call after setTemperature. + This works well if there is only 1 solid component. + If there are multiple components expanding at different rates during thermal + expansion this becomes more complicated and, and axial expansion should be used. + Multiple expansion rates cannot trivially be accommodated. + See AxialExpansionChanger. """ - if initialColdMaterialExpansion: - # material needs to be expanded from the material's cold temp to hot, - # not components cold temp, so we don't use mat.linearExpansionFactor or - # component.getThermalExpansionFactor. - # materials don't typically define the temperature for which their ref dens - # is defined so linearExpansionPercent must be called - coldMatAxialExpansionFactor = ( - 1.0 + self.material.linearExpansionPercent(Tc=self.temperatureInC) / 100 - ) - self.changeNDensByFactor(1.0 / coldMatAxialExpansionFactor) - else: - # this is the same as getThermalExpansionFactor but doesn't fail - # on non-fluid materials that have 0 or undefined thermal expansion - # (we don't want materials to fail on __init__ which calls this) - # axialExpansionFactor = 1.0 + self.material.linearExpansionFactor( - # self.temperatureInC, self.inputTemperatureInC - # ) - self.changeNDensByFactor(1.0 / self.getThermalExpansionFactor()) + self.changeNDensByFactor(1.0 / self.getThermalExpansionFactor()) def getProperties(self): """Return the active Material object defining thermo-mechanical properties.""" diff --git a/armi/reactor/converters/axialExpansionChanger.py b/armi/reactor/converters/axialExpansionChanger.py index 6196b2142..e8e590ebd 100644 --- a/armi/reactor/converters/axialExpansionChanger.py +++ b/armi/reactor/converters/axialExpansionChanger.py @@ -152,8 +152,8 @@ def applyColdHeightMassIncrease(self): ----- A cold 1 cm tall component will have more mass that a component with the same mass/length as a component with a hot height of 1 cm. This should be - called when the setting `inputHeightsConsideredHot` is used. This basically - undoes component.applyHotHeightDensityReduction + called when the setting `inputHeightsConsideredHot` is used. This adjusts + the expansion factor applied during applyMaterialMassFracsToNumberDensities. """ for c in self.linked.a.getComponents(): axialExpansionFactor = 1.0 + c.material.linearExpansionFactor( diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index e1fe425b5..44fba43c3 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -2274,11 +2274,16 @@ def test_coldMass(self): # set ref (input/cold) temperature. Thot = fuel.temperatureInC Tcold = fuel.inputTemperatureInC + + # change temp to cold fuel.setTemperature(Tcold) massCold = fuel.getMass() fuelArea = fuel.getArea() + # we are at cold temp so cold and hot area are equal + self.assertAlmostEqual(fuel.getArea(cold=True), fuel.getArea()) height = self.b.getHeight() # hot height. - rho = fuel.getProperties().density(Tc=Tcold) + rho = fuel.getProperties().density3(Tc=Tcold) + # can't use getThermalExpansionFactor since hot=cold so it would be 0 dllHot = fuel.getProperties().linearExpansionFactor(Tc=Thot, T0=Tcold) coldHeight = height / (1 + dllHot) theoreticalMass = fuelArea * coldHeight * rho @@ -2287,7 +2292,7 @@ def test_coldMass(self): massCold, theoreticalMass, 7, - "Cold mass of fuel ({0}) != theoretical mass {1}. " + msg="Cold mass of fuel ({0}) != theoretical mass {1}. " "Check calculation of cold mass".format(massCold, theoreticalMass), ) diff --git a/armi/reactor/tests/test_components.py b/armi/reactor/tests/test_components.py index 9b08de27c..13cbe6996 100644 --- a/armi/reactor/tests/test_components.py +++ b/armi/reactor/tests/test_components.py @@ -503,6 +503,19 @@ class TestComponentExpansion(unittest.TestCase): tHot = 500 coldOuterDiameter = 1.0 + def test_ComponentMassIndependentOfInputTemp(self): + coldT = 20 + circle1 = Circle("circle", "HT9", coldT, self.tHot, self.coldOuterDiameter) + coldT += 200 + # pick the input dimension to get the same hot component + hotterDim = self.coldOuterDiameter * ( + 1 + circle1.material.linearExpansionFactor(coldT, 20) + ) + circle2 = Circle("circle", "HT9", coldT, self.tHot, hotterDim) + self.assertAlmostEqual(circle1.getDimension("od"), circle2.getDimension("od")) + self.assertAlmostEqual(circle1.getArea(), circle2.getArea()) + self.assertAlmostEqual(circle1.getMassDensity(), circle2.getMassDensity()) + def test_ExpansionConservationHotHeightDefined(self): """ Demonstrate tutorial for how to expand and relation ships conserved at during expansion. @@ -538,10 +551,8 @@ def test_ExpansionConservationHotHeightDefined(self): # material.density is the 2D density of a material # material.density3 is true density and not equal in this case - # density must be density by calling applyHotHeightDensityReduction - # or other methods (see rest of test). for circle in [circle1, circle2]: - # 2D density is not equal after application of applyHotHeightDensityReduction + # 2D density is not equal after application of coldMatAxialExpansionFactor # which happens during construction self.assertNotAlmostEqual( circle.getMassDensity(), @@ -558,19 +569,25 @@ def test_ExpansionConservationHotHeightDefined(self): circle.getMassDensity(), circle.material.density3(Tc=circle.temperatureInC), ) - # Change temp forward and backward and show equal + + # brief 2D expansion with set temp to show mass is conserved + # hot height would come from block value + warmMass = circle1.getMassDensity() * circle1.getArea() * hotHeight + circle1.setTemperature(self.tHot) + hotMass = circle1.getMassDensity() * circle1.getArea() * hotHeight + self.assertAlmostEqual(warmMass, hotMass) + circle1.setTemperature(self.tWarm) + + # Change temp forward and backward with axial expansion and show equal oldArea = circle1.getArea() initialDens = circle1.getMassDensity() - # this math is done in applyHotHeightDensityReduction - applyHotHeightDensityReductionFactor = ( - 1.0 - + circle1.material.linearExpansionFactor( - circle1.temperatureInC, circle1.inputTemperatureInC - ) + # this math is done in applyMaterialMassFracsToNumberDensities + coldMatAxialExpansionFactor = 1.0 + circle1.material.linearExpansionFactor( + circle1.temperatureInC, circle1.inputTemperatureInC ) factorToUndoHotHeight = circle1.getThermalExpansionFactor() self.assertAlmostEqual( - applyHotHeightDensityReductionFactor, + coldMatAxialExpansionFactor, factorToUndoHotHeight, ) # when block.setHeight is called (which effectively changes component height) @@ -578,10 +595,10 @@ def test_ExpansionConservationHotHeightDefined(self): # density so that now the 2D expansion will be approximated/expanded around # the hot temp which is akin to these adjustments - # undo the old applyHotHeightDensityReduction + # undo the old coldMatAxialExpansionFactor circle1.changeNDensByFactor(factorToUndoHotHeight) circle1.setTemperature(self.tHot) - circle1.applyHotHeightDensityReduction() # apply at new temp + circle1.adjustDensityForHeightExpansion() # apply at new temp # now its density is same as hot component self.assertAlmostEqual( @@ -609,7 +626,7 @@ def test_ExpansionConservationHotHeightDefined(self): # change back to old temp circle1.changeNDensByFactor(circle1.getThermalExpansionFactor()) circle1.setTemperature(self.tWarm) - circle1.applyHotHeightDensityReduction() + circle1.adjustDensityForHeightExpansion() # check for consistency self.assertAlmostEqual(initialDens, circle1.getMassDensity()) @@ -638,7 +655,7 @@ def test_ExpansionConservationColdHeightDefined(self): circle1AdjustTo2.getThermalExpansionFactor() ) circle1AdjustTo2.setTemperature(self.tHot) - circle1AdjustTo2.applyHotHeightDensityReduction() + circle1AdjustTo2.adjustDensityForHeightExpansion() # check that its like 2 self.assertAlmostEqual( circle2.getMassDensity(), circle1AdjustTo2.getMassDensity() From a9b9f44158f008fbeb1113168c85c5eefa64528b Mon Sep 17 00:00:00 2001 From: Mark Onufer Date: Thu, 25 Aug 2022 14:47:58 -0700 Subject: [PATCH 5/7] small unit test change --- armi/reactor/tests/test_components.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armi/reactor/tests/test_components.py b/armi/reactor/tests/test_components.py index 13cbe6996..6cbc1e696 100644 --- a/armi/reactor/tests/test_components.py +++ b/armi/reactor/tests/test_components.py @@ -621,7 +621,7 @@ def test_ExpansionConservationHotHeightDefined(self): self.assertAlmostEqual( circle1.getMassDensity(), - circle1.material.density3(Tc=circle2.temperatureInC), + circle1.material.density3(Tc=circle1.temperatureInC), ) # change back to old temp circle1.changeNDensByFactor(circle1.getThermalExpansionFactor()) From 84f5657a03178f5331fb7fbf2a363e4ef8d44a9c Mon Sep 17 00:00:00 2001 From: Mark Onufer Date: Thu, 25 Aug 2022 15:40:50 -0700 Subject: [PATCH 6/7] udpate adjustDensityForHeightExpansion --- armi/reactor/components/component.py | 18 ++++++++++++++---- armi/reactor/tests/test_components.py | 27 ++++++--------------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/armi/reactor/components/component.py b/armi/reactor/components/component.py index b69f507ce..0f25d0250 100644 --- a/armi/reactor/components/component.py +++ b/armi/reactor/components/component.py @@ -357,20 +357,30 @@ def applyMaterialMassFracsToNumberDensities(self): ) self.changeNDensByFactor(1.0 / coldMatAxialExpansionFactor) - def adjustDensityForHeightExpansion(self): + def adjustDensityForHeightExpansion(self, newHot): """ - Change the densities in cases where height of the block/component is increasing + Change the densities in cases where height of the block/component is changing with expansion. Notes ----- - Call after setTemperature. + Call before setTemperature since we need old hot temp. This works well if there is only 1 solid component. If there are multiple components expanding at different rates during thermal expansion this becomes more complicated and, and axial expansion should be used. Multiple expansion rates cannot trivially be accommodated. See AxialExpansionChanger. """ - self.changeNDensByFactor(1.0 / self.getThermalExpansionFactor()) + self.changeNDensByFactor(1.0 / self.getHeightFactor(newHot)) + + def getHeightFactor(self, newHot): + """ + Return the factor by which height would change by if we did 3D expansion. + + Notes + ----- + Call before setTemperature since we need old hot temp. + """ + return self.getThermalExpansionFactor(Tc=newHot, T0=self.temperatureInC) def getProperties(self): """Return the active Material object defining thermo-mechanical properties.""" diff --git a/armi/reactor/tests/test_components.py b/armi/reactor/tests/test_components.py index 6cbc1e696..f8d415a44 100644 --- a/armi/reactor/tests/test_components.py +++ b/armi/reactor/tests/test_components.py @@ -586,19 +586,15 @@ def test_ExpansionConservationHotHeightDefined(self): circle1.temperatureInC, circle1.inputTemperatureInC ) factorToUndoHotHeight = circle1.getThermalExpansionFactor() - self.assertAlmostEqual( - coldMatAxialExpansionFactor, - factorToUndoHotHeight, - ) # 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 - # undo the old coldMatAxialExpansionFactor - circle1.changeNDensByFactor(factorToUndoHotHeight) + # change to self.THot + heightFactor = circle1.getHeightFactor(self.tHot) + circle1.adjustDensityForHeightExpansion(self.tHot) # apply temp at new height circle1.setTemperature(self.tHot) - circle1.adjustDensityForHeightExpansion() # apply at new temp # now its density is same as hot component self.assertAlmostEqual( @@ -607,26 +603,18 @@ def test_ExpansionConservationHotHeightDefined(self): ) # show that mass is conserved after expansion - circle1NewHotHeight = ( - hotHeight * circle1.getThermalExpansionFactor() / factorToUndoHotHeight - ) + circle1NewHotHeight = hotHeight * heightFactor self.assertAlmostEqual( mass1, circle1.getMassDensity() * circle1.getArea() * circle1NewHotHeight ) - # you can calculate the height exp factor directly this way - self.assertAlmostEqual( - circle1.getThermalExpansionFactor() / factorToUndoHotHeight, - circle1.getThermalExpansionFactor(Tc=circle1.temperatureInC, T0=self.tWarm), - ) self.assertAlmostEqual( circle1.getMassDensity(), circle1.material.density3(Tc=circle1.temperatureInC), ) # change back to old temp - circle1.changeNDensByFactor(circle1.getThermalExpansionFactor()) + circle1.adjustDensityForHeightExpansion(self.tWarm) circle1.setTemperature(self.tWarm) - circle1.adjustDensityForHeightExpansion() # check for consistency self.assertAlmostEqual(initialDens, circle1.getMassDensity()) @@ -651,11 +639,8 @@ def test_ExpansionConservationColdHeightDefined(self): circle1AdjustTo2 = Circle("circle", "HT9", 20, self.tWarm, 1.0) # make it hot like 2 - circle1AdjustTo2.changeNDensByFactor( - circle1AdjustTo2.getThermalExpansionFactor() - ) + circle1AdjustTo2.adjustDensityForHeightExpansion(self.tHot) circle1AdjustTo2.setTemperature(self.tHot) - circle1AdjustTo2.adjustDensityForHeightExpansion() # check that its like 2 self.assertAlmostEqual( circle2.getMassDensity(), circle1AdjustTo2.getMassDensity() From 03f966d0874ccb0c4a31f845351d97b75c964668 Mon Sep 17 00:00:00 2001 From: Mark Onufer Date: Thu, 25 Aug 2022 16:55:42 -0700 Subject: [PATCH 7/7] remove unused --- armi/reactor/tests/test_components.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/armi/reactor/tests/test_components.py b/armi/reactor/tests/test_components.py index f8d415a44..8d8fe8b4b 100644 --- a/armi/reactor/tests/test_components.py +++ b/armi/reactor/tests/test_components.py @@ -578,20 +578,15 @@ def test_ExpansionConservationHotHeightDefined(self): self.assertAlmostEqual(warmMass, hotMass) circle1.setTemperature(self.tWarm) - # Change temp forward and backward with axial expansion and show equal + # 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.getMassDensity() - # this math is done in applyMaterialMassFracsToNumberDensities - coldMatAxialExpansionFactor = 1.0 + circle1.material.linearExpansionFactor( - circle1.temperatureInC, circle1.inputTemperatureInC - ) - factorToUndoHotHeight = circle1.getThermalExpansionFactor() + # 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 - - # change to self.THot heightFactor = circle1.getHeightFactor(self.tHot) circle1.adjustDensityForHeightExpansion(self.tHot) # apply temp at new height circle1.setTemperature(self.tHot)