From 8074ee17cb2cea3de7df2c1260355489240f8e0e Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 21 Nov 2024 10:52:22 -0800 Subject: [PATCH 01/30] account for symmetry in initialB10ComponentVol calc --- armi/reactor/blockParameters.py | 3 +++ armi/reactor/blocks.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/armi/reactor/blockParameters.py b/armi/reactor/blockParameters.py index 820ebac9f..277f7928b 100644 --- a/armi/reactor/blockParameters.py +++ b/armi/reactor/blockParameters.py @@ -85,18 +85,21 @@ def getBlockParameterDefinitions(): "molesHmBOL", units=f"{units.MOLES}", description="Total number of atoms of heavy metal at BOL assuming a full assembly", + location=ParamLocation.VOLUME_INTEGRATED, ) pb.defParam( "massHmBOL", units=units.GRAMS, description="Mass of heavy metal at BOL", + location=ParamLocation.VOLUME_INTEGRATED, ) pb.defParam( "initialB10ComponentVol", units=f"{units.CM}^3", description="cc's of un-irradiated, cold B10 containing component (includes full volume if any B10)", + location=ParamLocation.VOLUME_INTEGRATED, ) pb.defParam( diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index f19b0381f..0bc45c21a 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -843,7 +843,7 @@ def setB10VolParam(self, heightHot): coldArea = b10Comp.getArea(cold=True) coldFactor = b10Comp.getThermalExpansionFactor() if heightHot else 1 coldHeight = self.getHeight() / coldFactor - self.p.initialB10ComponentVol = coldArea * coldHeight + self.p.initialB10ComponentVol = coldArea * coldHeight / self.getSymmetryFactor() def replaceBlockWithBlock(self, bReplacement): """ From 2d3d3fed9c9d9b90f850520f4630a4dc3e4fc27d Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 21 Nov 2024 11:01:53 -0800 Subject: [PATCH 02/30] add test --- armi/reactor/tests/test_reactors.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/armi/reactor/tests/test_reactors.py b/armi/reactor/tests/test_reactors.py index 6187155e6..117ea8623 100644 --- a/armi/reactor/tests/test_reactors.py +++ b/armi/reactor/tests/test_reactors.py @@ -452,6 +452,18 @@ def test_setB10VolOnCreation(self): controlBlock.p.initialB10ComponentVol, ) + @patch("armi.reactor.blocks.HexBlock.getSymmetryFactor") + def test_setB10VolWithSymmetry(self, mockGetSymmetryFactor): + """Tests that initialB10ComponentVol is modified by the symmetry factor.""" + for controlBlock in self.r.core.getBlocks(Flags.CONTROL): + mockGetSymmetryFactor.return_value = 1 + controlBlock.setB10VolParam(True) # height being hot shouldn't matter here + fullVol = controlBlock.p.initialB10ComponentVol + mockGetSymmetryFactor.return_value = 3 + controlBlock.setB10VolParam(True) + thirdVol = controlBlock.p.initialB10ComponentVol + self.assertAlmostEqual(thirdVol / fullVol, 1 / 3) + def test_countFuelAxialBlocks(self): """Tests that the users definition of fuel blocks is preserved.""" numFuelBlocks = self.r.core.countFuelAxialBlocks() From 40b76d1f58acd9a43e78f036e8fd4167dad63f81 Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 21 Nov 2024 11:31:29 -0800 Subject: [PATCH 03/30] remove unnecessary changes --- armi/reactor/blocks.py | 2 +- armi/reactor/tests/test_reactors.py | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index 0bc45c21a..f19b0381f 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -843,7 +843,7 @@ def setB10VolParam(self, heightHot): coldArea = b10Comp.getArea(cold=True) coldFactor = b10Comp.getThermalExpansionFactor() if heightHot else 1 coldHeight = self.getHeight() / coldFactor - self.p.initialB10ComponentVol = coldArea * coldHeight / self.getSymmetryFactor() + self.p.initialB10ComponentVol = coldArea * coldHeight def replaceBlockWithBlock(self, bReplacement): """ diff --git a/armi/reactor/tests/test_reactors.py b/armi/reactor/tests/test_reactors.py index 117ea8623..6187155e6 100644 --- a/armi/reactor/tests/test_reactors.py +++ b/armi/reactor/tests/test_reactors.py @@ -452,18 +452,6 @@ def test_setB10VolOnCreation(self): controlBlock.p.initialB10ComponentVol, ) - @patch("armi.reactor.blocks.HexBlock.getSymmetryFactor") - def test_setB10VolWithSymmetry(self, mockGetSymmetryFactor): - """Tests that initialB10ComponentVol is modified by the symmetry factor.""" - for controlBlock in self.r.core.getBlocks(Flags.CONTROL): - mockGetSymmetryFactor.return_value = 1 - controlBlock.setB10VolParam(True) # height being hot shouldn't matter here - fullVol = controlBlock.p.initialB10ComponentVol - mockGetSymmetryFactor.return_value = 3 - controlBlock.setB10VolParam(True) - thirdVol = controlBlock.p.initialB10ComponentVol - self.assertAlmostEqual(thirdVol / fullVol, 1 / 3) - def test_countFuelAxialBlocks(self): """Tests that the users definition of fuel blocks is preserved.""" numFuelBlocks = self.r.core.countFuelAxialBlocks() From 7c0b696df997c59b2b1dfd53167ef1bc6f4caf84 Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 21 Nov 2024 16:09:52 -0800 Subject: [PATCH 04/30] add parameter scaling on assembly move --- armi/reactor/assemblies.py | 14 ++++++++++++++ armi/reactor/cores.py | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index 73503efcd..83ea5dbab 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -206,6 +206,7 @@ def insert(self, index, obj): def moveTo(self, locator): """Move an assembly somewhere else.""" + oldSymmetryFactor = self.getSymmetryFactor() composites.Composite.moveTo(self, locator) if self.lastLocationLabel != self.DATABASE: self.p.numMoves += 1 @@ -213,6 +214,19 @@ def moveTo(self, locator): self.parent.childrenByLocator[locator] = self # symmetry may have changed (either moving on or off of symmetry line) self.clearCache() + self.scaleParamsToNewSymmetryFactor(oldSymmetryFactor) + + def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor=1.0): + volIntegratedParamsToScale = self.getBlocks()[0].p.paramDefs.atLocation( + ParamLocation.VOLUME_INTEGRATED + ) + scalingFactor = oldSymmetryFactor / self.getSymmetryFactor() + for b in self.getBlocks(): + for param in volIntegratedParamsToScale: + if b.p[param] is None: + continue + else: + b.p[param] = b.p[param] / scalingFactor def getNum(self): """Return unique integer for this assembly.""" diff --git a/armi/reactor/cores.py b/armi/reactor/cores.py index 00ce8d47d..2bb128966 100644 --- a/armi/reactor/cores.py +++ b/armi/reactor/cores.py @@ -52,6 +52,7 @@ from armi.utils import tabulate from armi.utils.iterables import Sequence from armi.utils.mathematics import average1DWithinTolerance +from armi.reactor.converters.geometryConverters import _scaleParamsInBlock class Core(composites.Composite): @@ -581,6 +582,8 @@ def add(self, a, spatialLocator=None): if aNum > self.p.maxAssemNum: self.p.maxAssemNum = aNum + self._scaleParametersOnInitialPlacement(a) + if a.lastLocationLabel != a.DATABASE: # time the assembly enters the core in days a.p.chargeTime = self.r.p.time @@ -590,6 +593,19 @@ def add(self, a, spatialLocator=None): a.p.chargeFis = a.getFissileMass() / 1000.0 a.p.chargeBu = a.getMaxParam("percentBu") + @staticmethod + def _scaleParametersOnInitialPlacement(a): + """ + Scale volume integrated parameters by the symmetry factor when assembly is first placed in core. + + Assemblies are always generated with symmetry factors of 1 since they do not have a location + upon generation, so this always divides the volume integrated parameters by the symmetry + factor. + """ + if a.getAge() == 0: + return + a.scaleParamsToNewSymmetryFactor(oldSymmetryFactor=1.0) + def genAssembliesAddedThisCycle(self): """ Yield the assemblies that have been added in the current cycle. From 3d7265716a0a96aaba45cdf9eaeb4caa0cdda121 Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 21 Nov 2024 16:13:27 -0800 Subject: [PATCH 05/30] flip getAge check to be what was intended --- armi/reactor/cores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armi/reactor/cores.py b/armi/reactor/cores.py index 2bb128966..58831e0d2 100644 --- a/armi/reactor/cores.py +++ b/armi/reactor/cores.py @@ -602,7 +602,7 @@ def _scaleParametersOnInitialPlacement(a): upon generation, so this always divides the volume integrated parameters by the symmetry factor. """ - if a.getAge() == 0: + if a.getAge() != 0: return a.scaleParamsToNewSymmetryFactor(oldSymmetryFactor=1.0) From 1d9e80703b880b7d26606c566b8095ac5a126d8a Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 22 Nov 2024 10:25:42 -0800 Subject: [PATCH 06/30] remove superfluous symmetry adjustment The core.add method uses assembly.moveTo to place assemblies in the reactor. Since moveTo now accounts for changes in symmetry factor, having an additional adjustment in the core.add method is incorrect and would double account for any change in symmetry factor. --- armi/reactor/cores.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/armi/reactor/cores.py b/armi/reactor/cores.py index 58831e0d2..b7bb4aa9d 100644 --- a/armi/reactor/cores.py +++ b/armi/reactor/cores.py @@ -582,8 +582,6 @@ def add(self, a, spatialLocator=None): if aNum > self.p.maxAssemNum: self.p.maxAssemNum = aNum - self._scaleParametersOnInitialPlacement(a) - if a.lastLocationLabel != a.DATABASE: # time the assembly enters the core in days a.p.chargeTime = self.r.p.time @@ -593,19 +591,6 @@ def add(self, a, spatialLocator=None): a.p.chargeFis = a.getFissileMass() / 1000.0 a.p.chargeBu = a.getMaxParam("percentBu") - @staticmethod - def _scaleParametersOnInitialPlacement(a): - """ - Scale volume integrated parameters by the symmetry factor when assembly is first placed in core. - - Assemblies are always generated with symmetry factors of 1 since they do not have a location - upon generation, so this always divides the volume integrated parameters by the symmetry - factor. - """ - if a.getAge() != 0: - return - a.scaleParamsToNewSymmetryFactor(oldSymmetryFactor=1.0) - def genAssembliesAddedThisCycle(self): """ Yield the assemblies that have been added in the current cycle. From 85bdd018ac03ad3571cc77520a519bae4ddfc0d1 Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 22 Nov 2024 13:45:18 -0800 Subject: [PATCH 07/30] fix error when accessing parameters --- armi/reactor/assemblies.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index 83ea5dbab..bac68d463 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -223,10 +223,11 @@ def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor=1.0): scalingFactor = oldSymmetryFactor / self.getSymmetryFactor() for b in self.getBlocks(): for param in volIntegratedParamsToScale: - if b.p[param] is None: + name = param.name + if b.p[name] is None: continue else: - b.p[param] = b.p[param] / scalingFactor + b.p[name] = b.p[name] / scalingFactor def getNum(self): """Return unique integer for this assembly.""" From b34542e34902e6d48145f306846cbd05b21ca5a4 Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 22 Nov 2024 15:19:25 -0800 Subject: [PATCH 08/30] change test to add assembly after it has blocks --- armi/reactor/tests/test_assemblies.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/armi/reactor/tests/test_assemblies.py b/armi/reactor/tests/test_assemblies.py index c18850ed0..125c0d364 100644 --- a/armi/reactor/tests/test_assemblies.py +++ b/armi/reactor/tests/test_assemblies.py @@ -204,7 +204,6 @@ def setUp(self): ) self.assembly = makeTestAssembly(NUM_BLOCKS, self.assemNum, r=self.r) - self.r.core.add(self.assembly) # Use these if they are needed self.blockParams = { @@ -267,6 +266,7 @@ def setUp(self): self.assembly.add(b) self.blockList.append(b) + self.r.core.add(self.assembly) self.assembly.calculateZCoords() def test_isOnWhichSymmetryLine(self): @@ -345,6 +345,12 @@ def test_moveTo(self): cur = self.assembly.spatialLocator self.assertEqual(cur, ref) + def test_scaleParamsWhenMoved(self): + """Volume integrated parameters must be scaled when an assembly is placed on a core boundary.""" + ref = self.r.core.spatialGrid.getLocatorFromRingAndPos(3, 10) + i, j = grids.HexGrid.getIndicesFromRingAndPos(3, 10) + locator = self.r.core.spatialGrid[i, j, 0] + def test_getName(self): cur = self.assembly.getName() ref = self.name From be19b2a701ba0c021b55e3ac1a7f82a7446f1e1c Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 22 Nov 2024 16:03:35 -0800 Subject: [PATCH 09/30] add test for scaling params when moving assembly --- armi/reactor/assemblies.py | 2 +- armi/reactor/tests/test_assemblies.py | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index bac68d463..e19ed7a4e 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -227,7 +227,7 @@ def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor=1.0): if b.p[name] is None: continue else: - b.p[name] = b.p[name] / scalingFactor + b.p[name] = b.p[name] * scalingFactor def getNum(self): """Return unique integer for this assembly.""" diff --git a/armi/reactor/tests/test_assemblies.py b/armi/reactor/tests/test_assemblies.py index 125c0d364..91a2d8e18 100644 --- a/armi/reactor/tests/test_assemblies.py +++ b/armi/reactor/tests/test_assemblies.py @@ -42,6 +42,7 @@ runLog, ) from armi.reactor.tests import test_reactors +from armi.reactor.parameters import ParamLocation from armi.tests import TEST_ROOT, mockRunLogs from armi.utils import directoryChangers from armi.utils import textProcessors @@ -223,6 +224,7 @@ def setUp(self): "xsTypeNum": 40, "zbottom": 97.3521, "ztop": 111.80279999999999, + "massHmBOL": 9.0, } self.blockSettings = { @@ -248,6 +250,7 @@ def setUp(self): for i in range(NUM_BLOCKS): b = blocks.HexBlock("TestHexBlock") b.setHeight(self.height) + b.p["massHmBOL"] = self.blockParams["massHmBOL"] self.hexDims = { "Tinput": 273.0, @@ -347,9 +350,18 @@ def test_moveTo(self): def test_scaleParamsWhenMoved(self): """Volume integrated parameters must be scaled when an assembly is placed on a core boundary.""" - ref = self.r.core.spatialGrid.getLocatorFromRingAndPos(3, 10) - i, j = grids.HexGrid.getIndicesFromRingAndPos(3, 10) + i, j = grids.HexGrid.getIndicesFromRingAndPos(1, 1) locator = self.r.core.spatialGrid[i, j, 0] + originalParamValues = np.array( + [b.p["massHmBOL"] for b in self.assembly.getBlocks(Flags.FUEL)] + ) + self.assertEqual(self.assembly.getSymmetryFactor(), 1) + self.assembly.moveTo(locator) + self.assertEqual(self.assembly.getSymmetryFactor(), 3) + thirdParamValues = np.array( + [b.p["massHmBOL"] for b in self.assembly.getBlocks(Flags.FUEL)] + ) + assert_allclose(thirdParamValues / originalParamValues, 1 / 3) def test_getName(self): cur = self.assembly.getName() From 7f7206da0995e6c5376acbd1650ce58e61afe2cc Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 22 Nov 2024 16:05:53 -0800 Subject: [PATCH 10/30] ruff --- armi/reactor/tests/test_assemblies.py | 1 - 1 file changed, 1 deletion(-) diff --git a/armi/reactor/tests/test_assemblies.py b/armi/reactor/tests/test_assemblies.py index 91a2d8e18..83a0bc0e1 100644 --- a/armi/reactor/tests/test_assemblies.py +++ b/armi/reactor/tests/test_assemblies.py @@ -42,7 +42,6 @@ runLog, ) from armi.reactor.tests import test_reactors -from armi.reactor.parameters import ParamLocation from armi.tests import TEST_ROOT, mockRunLogs from armi.utils import directoryChangers from armi.utils import textProcessors From 8777b4df92fc0baf01c5fcc88448ae77e4ba6ffc Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 22 Nov 2024 16:08:29 -0800 Subject: [PATCH 11/30] ruff2 --- armi/reactor/cores.py | 1 - 1 file changed, 1 deletion(-) diff --git a/armi/reactor/cores.py b/armi/reactor/cores.py index b7bb4aa9d..00ce8d47d 100644 --- a/armi/reactor/cores.py +++ b/armi/reactor/cores.py @@ -52,7 +52,6 @@ from armi.utils import tabulate from armi.utils.iterables import Sequence from armi.utils.mathematics import average1DWithinTolerance -from armi.reactor.converters.geometryConverters import _scaleParamsInBlock class Core(composites.Composite): From 792a5e9f6e61a89353cc1eed34da0e0217b82d17 Mon Sep 17 00:00:00 2001 From: bsculac Date: Tue, 3 Dec 2024 10:36:42 -0800 Subject: [PATCH 12/30] add volume integrated tags to params that should have it, fix test --- armi/bookkeeping/db/tests/test_comparedb3.py | 2 +- armi/reactor/blockParameters.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/armi/bookkeeping/db/tests/test_comparedb3.py b/armi/bookkeeping/db/tests/test_comparedb3.py index 3d56ee022..47ebb8dd7 100644 --- a/armi/bookkeeping/db/tests/test_comparedb3.py +++ b/armi/bookkeeping/db/tests/test_comparedb3.py @@ -181,7 +181,7 @@ def test_compareDatabaseSim(self): dbs[1]._fullPath, timestepCompare=[(0, 0), (0, 1)], ) - self.assertEqual(len(diffs.diffs), 480) + self.assertEqual(len(diffs.diffs), 552) # Cycle length is only diff (x3) self.assertEqual(diffs.nDiffs(), 3) diff --git a/armi/reactor/blockParameters.py b/armi/reactor/blockParameters.py index 277f7928b..d9a49005e 100644 --- a/armi/reactor/blockParameters.py +++ b/armi/reactor/blockParameters.py @@ -84,7 +84,7 @@ def getBlockParameterDefinitions(): pb.defParam( "molesHmBOL", units=f"{units.MOLES}", - description="Total number of atoms of heavy metal at BOL assuming a full assembly", + description="Total number of atoms of heavy metal at BOL.", location=ParamLocation.VOLUME_INTEGRATED, ) @@ -98,7 +98,7 @@ def getBlockParameterDefinitions(): pb.defParam( "initialB10ComponentVol", units=f"{units.CM}^3", - description="cc's of un-irradiated, cold B10 containing component (includes full volume if any B10)", + description="cc's of un-irradiated, cold B10 containing component (includes full volume of any components with B10)", location=ParamLocation.VOLUME_INTEGRATED, ) @@ -115,6 +115,7 @@ def getBlockParameterDefinitions(): "molesHmNow", units=f"{units.MOLES}", description="Total number of atoms of heavy metal", + location=ParamLocation.VOLUME_INTEGRATED, ) pb.defParam( From a1d1699bca224092f6c24e102b7516df316dbd30 Mon Sep 17 00:00:00 2001 From: bsculac Date: Tue, 3 Dec 2024 10:41:33 -0800 Subject: [PATCH 13/30] lint --- armi/reactor/blockParameters.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/armi/reactor/blockParameters.py b/armi/reactor/blockParameters.py index d9a49005e..dde877f65 100644 --- a/armi/reactor/blockParameters.py +++ b/armi/reactor/blockParameters.py @@ -98,7 +98,10 @@ def getBlockParameterDefinitions(): pb.defParam( "initialB10ComponentVol", units=f"{units.CM}^3", - description="cc's of un-irradiated, cold B10 containing component (includes full volume of any components with B10)", + description=( + "cc's of un-irradiated, cold B10 containing component " + "(includes full volume of any components with B10)" + ), location=ParamLocation.VOLUME_INTEGRATED, ) From 9f4becb3934d05cef44139f2c278835aaa6bcdc0 Mon Sep 17 00:00:00 2001 From: bsculac Date: Wed, 4 Dec 2024 10:54:40 -0800 Subject: [PATCH 14/30] fix unit test and example notebook the unit test was comparing the power in a block between two timesteps. the block was being moved from a non-central location to the central location, where only 1/3rd of the assembly should be in the reactor. The assert in the test was incorrect in that it was saying the power in the assembly should be the same before and after the move. This is wrong for a few reasons, first being that the power is no longer valid after the move. But aside from that, the power should be 1/3rd what it was because the assembly is only 1/3rd in the core. Really it should be zeroed out but other non-power parameters that are volume calculated should be reduced by the amount that the assembly actually exists in the reactor. Additionally, the power in the central assembly in the example was calculated assuming the full assembly exists in the core. the example was modified to correctly calculate the power in the central assembly, which then required FuelHandler._getParamMax to account for the symmetry factor of the assembly, otherwise the ordering was incorrect and the shuffling in the example occured in a different order. --- armi/bookkeeping/tests/test_historyTracker.py | 17 +++++++++++++++-- armi/physics/fuelCycle/fuelHandlers.py | 16 +++++++++++++++- armi/reactor/assemblies.py | 2 ++ armi/tests/tutorials/data_model.ipynb | 12 ++++++++---- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/armi/bookkeeping/tests/test_historyTracker.py b/armi/bookkeeping/tests/test_historyTracker.py index 0b615a37d..6bf523fe9 100644 --- a/armi/bookkeeping/tests/test_historyTracker.py +++ b/armi/bookkeeping/tests/test_historyTracker.py @@ -168,6 +168,12 @@ def test_historyParameters(self): ) b.getVolume() bName = b.name + print( + "XXXXXXXXXXXXXXXXXXXXXXXXXX", + b.getLocation(), + b.getSymmetryFactor(), + b.p.power, + ) # duration is None in this DB hti = o.getInterface("history") @@ -184,7 +190,12 @@ def test_historyParameters(self): params[param] = [] for ts, years in enumerate(timesInYears): cycle, node = utils.getCycleNodeFromCumulativeNode(ts, self.o.cs) - + print( + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + hti.getBlockHistoryVal(bName, param, (cycle, node)), + bName, + ) + print(cycle, node) params[param].append( hti.getBlockHistoryVal(bName, param, (cycle, node)) ) @@ -196,7 +207,9 @@ def test_historyParameters(self): # verify the power parameter is retrievable from the history self.assertEqual(o.cs["power"], 1000000000.0) self.assertAlmostEqual(params["power"][0], 360, delta=0.1) - self.assertEqual(params["power"][0], params["power"][1]) + self.assertEqual( + params["power"][0] / 3, params["power"][1] + ) # assembly was moved to the central location with 1/3rd symmetry # verify the power density parameter is retrievable from the history self.assertAlmostEqual(params["pdens"][0], 0.0785, delta=0.001) diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index abe079d0b..83411a052 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -38,6 +38,7 @@ from armi.physics.fuelCycle.settings import CONF_ASSEMBLY_ROTATION_ALG from armi.reactor.flags import Flags from armi.utils.customExceptions import InputError +from armi.reactor.parameters import ParamLocation class FuelHandler: @@ -212,8 +213,21 @@ def _compareAssem(candidate, current): @staticmethod def _getParamMax(a, paramName, blockLevelMax=True): """Get parameter with Block-level maximum.""" + print( + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + a.getBlocks()[0].p.paramDefs.atLocation(ParamLocation.VOLUME_INTEGRATED), + ) + volIntegratedParamNames = [ + p.name + for p in a.getBlocks()[0].p.paramDefs.atLocation( + ParamLocation.VOLUME_INTEGRATED + ) + ] + multiplier = ( + a.getSymmetryFactor() if paramName in volIntegratedParamNames else 1.0 + ) if blockLevelMax: - return a.getChildParamValues(paramName).max() + return a.getChildParamValues(paramName).max() * multiplier return a.p[paramName] diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index aa9456629..faff654a3 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -221,6 +221,8 @@ def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor=1.0): ParamLocation.VOLUME_INTEGRATED ) scalingFactor = oldSymmetryFactor / self.getSymmetryFactor() + if scalingFactor == 1: + return # noop for b in self.getBlocks(): for param in volIntegratedParamsToScale: name = param.name diff --git a/armi/tests/tutorials/data_model.ipynb b/armi/tests/tutorials/data_model.ipynb index 9b6dbe8fd..0a4118c47 100644 --- a/armi/tests/tutorials/data_model.ipynb +++ b/armi/tests/tutorials/data_model.ipynb @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 54, "metadata": {}, "outputs": [], "source": [ @@ -294,14 +294,18 @@ "mgFluxBase = np.arange(5)\n", "def setFakePower(core):\n", " for a in core:\n", + " sf = a.getSymmetryFactor()\n", " for b in a:\n", " vol = b.getVolume()\n", " coords = b.spatialLocator.getGlobalCoordinates()\n", " r = np.linalg.norm(abs(coords-center))\n", " fuelFlag = 10 if b.isFuel() else 1.0\n", - " b.p.power = peakPower / r**2 * fuelFlag\n", + " # Use the symmetry factor to account for the central assembly being split\n", + " b.p.power = peakPower / r**2 * fuelFlag / sf\n", " b.p.pdens = b.p.power/vol\n", " b.p.mgFlux = mgFluxBase*b.p.pdens\n", + " if b.isFuel():\n", + " print(b.p.power, b.getLocation())\n", "setFakePower(core)" ] }, @@ -402,7 +406,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 70, "metadata": {}, "outputs": [], "source": [ @@ -412,7 +416,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 71, "metadata": {}, "outputs": [], "source": [ From 1e08e8496dcffb871fd6aeaf0ccd1477dad55d05 Mon Sep 17 00:00:00 2001 From: bsculac Date: Wed, 4 Dec 2024 12:45:29 -0800 Subject: [PATCH 15/30] remove breadcrumbs --- armi/bookkeeping/tests/test_historyTracker.py | 12 ------------ armi/physics/fuelCycle/fuelHandlers.py | 4 ---- 2 files changed, 16 deletions(-) diff --git a/armi/bookkeeping/tests/test_historyTracker.py b/armi/bookkeeping/tests/test_historyTracker.py index 6bf523fe9..e655d595c 100644 --- a/armi/bookkeeping/tests/test_historyTracker.py +++ b/armi/bookkeeping/tests/test_historyTracker.py @@ -168,12 +168,6 @@ def test_historyParameters(self): ) b.getVolume() bName = b.name - print( - "XXXXXXXXXXXXXXXXXXXXXXXXXX", - b.getLocation(), - b.getSymmetryFactor(), - b.p.power, - ) # duration is None in this DB hti = o.getInterface("history") @@ -190,12 +184,6 @@ def test_historyParameters(self): params[param] = [] for ts, years in enumerate(timesInYears): cycle, node = utils.getCycleNodeFromCumulativeNode(ts, self.o.cs) - print( - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - hti.getBlockHistoryVal(bName, param, (cycle, node)), - bName, - ) - print(cycle, node) params[param].append( hti.getBlockHistoryVal(bName, param, (cycle, node)) ) diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index 83411a052..a2d132302 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -213,10 +213,6 @@ def _compareAssem(candidate, current): @staticmethod def _getParamMax(a, paramName, blockLevelMax=True): """Get parameter with Block-level maximum.""" - print( - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - a.getBlocks()[0].p.paramDefs.atLocation(ParamLocation.VOLUME_INTEGRATED), - ) volIntegratedParamNames = [ p.name for p in a.getBlocks()[0].p.paramDefs.atLocation( From 1a562f7e09d042fd53ad89d13708897ff97fd63f Mon Sep 17 00:00:00 2001 From: bsculac Date: Wed, 4 Dec 2024 12:50:14 -0800 Subject: [PATCH 16/30] remove execution counts from example notebook --- armi/tests/tutorials/data_model.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/armi/tests/tutorials/data_model.ipynb b/armi/tests/tutorials/data_model.ipynb index 0a4118c47..739e5e2de 100644 --- a/armi/tests/tutorials/data_model.ipynb +++ b/armi/tests/tutorials/data_model.ipynb @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -406,7 +406,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -416,7 +416,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ From 72ffaeeaf4a83d975cad87208cc3a65b610d7767 Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 5 Dec 2024 08:51:48 -0800 Subject: [PATCH 17/30] fix test that uses assembly comparison --- armi/physics/fuelCycle/tests/test_fuelHandlers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/armi/physics/fuelCycle/tests/test_fuelHandlers.py b/armi/physics/fuelCycle/tests/test_fuelHandlers.py index 5248aa4de..52116ea9b 100644 --- a/armi/physics/fuelCycle/tests/test_fuelHandlers.py +++ b/armi/physics/fuelCycle/tests/test_fuelHandlers.py @@ -261,8 +261,9 @@ def test_width(self): for ring, power in zip(range(1, 8), range(10, 80, 10)): aList = assemsByRing[ring] for a in aList: + sf = a.getSymmetryFactor() # center assembly is only 1/3rd in the core for b in a: - b.p.power = power + b.p.power = power / sf paramName = "power" # 1 ring outer and inner from ring 3 From e410d089337b7fa83474348a42d8e6e02bd8451e Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 5 Dec 2024 09:23:53 -0800 Subject: [PATCH 18/30] update test to account for symmetry factor --- armi/bookkeeping/db/tests/test_comparedb3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armi/bookkeeping/db/tests/test_comparedb3.py b/armi/bookkeeping/db/tests/test_comparedb3.py index 62989d9df..4eb5531d8 100644 --- a/armi/bookkeeping/db/tests/test_comparedb3.py +++ b/armi/bookkeeping/db/tests/test_comparedb3.py @@ -181,7 +181,7 @@ def test_compareDatabaseSim(self): dbs[1]._fullPath, timestepCompare=[(0, 0), (0, 1)], ) - self.assertEqual(len(diffs.diffs), 576) + self.assertEqual(len(diffs.diffs), 504) # Cycle length is only diff (x3) self.assertEqual(diffs.nDiffs(), 3) From 7ca1e13710e930a709ee99763e0ef8c9b1dab6aa Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 5 Dec 2024 15:41:48 -0800 Subject: [PATCH 19/30] resolve errors in tests that specially accounted for symmetry --- armi/reactor/blocks.py | 11 +++-------- armi/reactor/composites.py | 19 ++++--------------- armi/reactor/tests/test_blocks.py | 18 ++++-------------- 3 files changed, 11 insertions(+), 37 deletions(-) diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index e88e7cd01..023e86361 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -790,21 +790,16 @@ def completeInitialLoading(self, bolBlock=None): self.p.enrichmentBOL = self.getFissileMassEnrich() massHmBOL = 0.0 - sf = self.getSymmetryFactor() for child in self: - # multiplying by sf ends up cancelling out the symmetry factor used in - # Component.getMass(). So massHmBOL does not respect the symmetry factor. - hmMass = child.getHMMass() * sf + hmMass = child.getHMMass() massHmBOL += hmMass # Components have the following parameters but not every composite will # massHmBOL, molesHmBOL, puFrac if isinstance(child, components.Component): child.p.massHmBOL = hmMass - # to stay consistent with massHmBOL, molesHmBOL and puFrac should be - # independent of sf. As such, the need to be scaled by 1/sf. - child.p.molesHmBOL = child.getHMMoles() / sf + child.p.molesHmBOL = child.getHMMoles() child.p.puFrac = ( - self.getPuMoles() / sf / child.p.molesHmBOL + self.getPuMoles() / child.p.molesHmBOL if child.p.molesHmBOL > 0.0 else 0.0 ) diff --git a/armi/reactor/composites.py b/armi/reactor/composites.py index f61ad5580..442893067 100644 --- a/armi/reactor/composites.py +++ b/armi/reactor/composites.py @@ -1947,29 +1947,18 @@ def getHMMass(self): def getHMMoles(self): """ - Get the number of moles of heavy metal in this object in full symmetry. + Get the number of moles of heavy metal in this object. Notes ----- - If an object is on a symmetry line, the number of moles will be scaled up by the - symmetry factor. This is done because this is typically used for tracking - burnup, and BOL moles are computed in full objects too so there are no - complications as things move on and off of symmetry lines. - - Warning - ------- - getHMMoles is different than every other get mass call since it multiplies by - symmetry factor but getVolume() on the block level divides by symmetry factor - causing them to cancel out. - - This was needed so that HM moles mass did not change based on if the - block/assembly was on a symmetry line or not. + If an object is on a symmetry line, the volume reported by getVolume + is reduced to reflect that the block is not wholly within the reactor. This + reduction in volume reduces the reported HM moles. """ return ( self.getHMDens() / units.MOLES_PER_CC_TO_ATOMS_PER_BARN_CM * self.getVolume() - * self.getSymmetryFactor() ) def getHMDens(self): diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index 8205bf1d7..db2adf8a8 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -1230,13 +1230,7 @@ def test_completeInitialLoading(self, mock_sf): sf = self.block.getSymmetryFactor() cur = self.block.p.molesHmBOL - ref = ( - self.block.getHMDens() - / MOLES_PER_CC_TO_ATOMS_PER_BARN_CM - * height - * area - * sf - ) + ref = self.block.getHMDens() / MOLES_PER_CC_TO_ATOMS_PER_BARN_CM * height * area self.assertAlmostEqual(cur, ref, places=12) totalHMMass = 0.0 @@ -1244,20 +1238,16 @@ def test_completeInitialLoading(self, mock_sf): nucs = c.getNuclides() hmNucs = [nuc for nuc in nucs if nucDir.isHeavyMetal(nuc)] hmNDens = {hmNuc: c.getNumberDensity(hmNuc) for hmNuc in hmNucs} - hmMass = densityTools.calculateMassDensity(hmNDens) * c.getVolume() + # use sf to account for only a 1/sf portion of the component being in the block + hmMass = densityTools.calculateMassDensity(hmNDens) * c.getVolume() / sf totalHMMass += hmMass if hmMass: - # hmMass does not need to account for sf since what's calculated in blocks.completeInitialLoading - # ends up cancelling out sf self.assertAlmostEqual(c.p.massHmBOL, hmMass, places=12) - # since sf is cancelled out in massHmBOL, there needs to be a factor 1/sf here to cancel out the - # factor of sf in getHMMoles. self.assertAlmostEqual( c.p.molesHmBOL, sum(ndens for ndens in hmNDens.values()) / units.MOLES_PER_CC_TO_ATOMS_PER_BARN_CM - * c.getVolume() - / sf, + * c.getVolume(), places=12, ) else: From 19bb4fb1b12fbe34e2ace8f35ecf4622ec3e5ec6 Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 5 Dec 2024 16:07:53 -0800 Subject: [PATCH 20/30] apply multiplier more universally in _getParamMax --- armi/physics/fuelCycle/fuelHandlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index a2d132302..c30ad0807 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -225,7 +225,7 @@ def _getParamMax(a, paramName, blockLevelMax=True): if blockLevelMax: return a.getChildParamValues(paramName).max() * multiplier - return a.p[paramName] + return a.p[paramName] * multiplier def findAssembly( self, From 29e75a834fed15d0560b57deda7d512ccfdf17e0 Mon Sep 17 00:00:00 2001 From: bsculac Date: Thu, 5 Dec 2024 16:10:50 -0800 Subject: [PATCH 21/30] remove bad variable default, minor efficiency improvement --- armi/reactor/assemblies.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index faff654a3..7cc2a21fc 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -216,13 +216,13 @@ def moveTo(self, locator): self.clearCache() self.scaleParamsToNewSymmetryFactor(oldSymmetryFactor) - def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor=1.0): - volIntegratedParamsToScale = self.getBlocks()[0].p.paramDefs.atLocation( - ParamLocation.VOLUME_INTEGRATED - ) + def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor): scalingFactor = oldSymmetryFactor / self.getSymmetryFactor() if scalingFactor == 1: return # noop + volIntegratedParamsToScale = self.getBlocks()[0].p.paramDefs.atLocation( + ParamLocation.VOLUME_INTEGRATED + ) for b in self.getBlocks(): for param in volIntegratedParamsToScale: name = param.name From c03c5bb9737e60d084afc000a43ed13cd43f0ef1 Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 6 Dec 2024 11:55:44 -0800 Subject: [PATCH 22/30] account for iterable parameters --- armi/reactor/assemblies.py | 9 +++++++- armi/reactor/tests/test_assemblies.py | 30 +++++++++++++++++++-------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index 7cc2a21fc..0cfdd080c 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -22,6 +22,7 @@ import pickle from random import randint from typing import ClassVar, Optional, Type +from collections.abc import Iterable import numpy as np from scipy import interpolate @@ -226,8 +227,14 @@ def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor): for b in self.getBlocks(): for param in volIntegratedParamsToScale: name = param.name - if b.p[name] is None: + if b.p[name] is None or isinstance(b.p[name], str): continue + elif isinstance(b.p[name], np.ndarray): + print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", b.p[name]) + b.p[name] = b.p[name] * scalingFactor + print("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", b.p[name]) + elif isinstance(b.p[name], Iterable): + b.p[name] = [value * scalingFactor for value in b.p[name]] else: b.p[name] = b.p[name] * scalingFactor diff --git a/armi/reactor/tests/test_assemblies.py b/armi/reactor/tests/test_assemblies.py index 83a0bc0e1..787dd129c 100644 --- a/armi/reactor/tests/test_assemblies.py +++ b/armi/reactor/tests/test_assemblies.py @@ -223,7 +223,6 @@ def setUp(self): "xsTypeNum": 40, "zbottom": 97.3521, "ztop": 111.80279999999999, - "massHmBOL": 9.0, } self.blockSettings = { @@ -249,7 +248,6 @@ def setUp(self): for i in range(NUM_BLOCKS): b = blocks.HexBlock("TestHexBlock") b.setHeight(self.height) - b.p["massHmBOL"] = self.blockParams["massHmBOL"] self.hexDims = { "Tinput": 273.0, @@ -349,18 +347,32 @@ def test_moveTo(self): def test_scaleParamsWhenMoved(self): """Volume integrated parameters must be scaled when an assembly is placed on a core boundary.""" + blockParams = { + # volume integrated parameters + "massHmBOL": 9.0, + "molesHmBOL": np.array([[1, 2, 3], [4, 5, 6]]), # ndarray for testing + "adjMgFlux": [1, 2, 3], # Should normally be an ndarray, list for testing + "lastMgFlux": "foo", # Should normally be an ndarray, str for testing + } + for b in self.assembly.getBlocks(Flags.FUEL): + b.p.update(blockParams) + i, j = grids.HexGrid.getIndicesFromRingAndPos(1, 1) locator = self.r.core.spatialGrid[i, j, 0] - originalParamValues = np.array( - [b.p["massHmBOL"] for b in self.assembly.getBlocks(Flags.FUEL)] - ) self.assertEqual(self.assembly.getSymmetryFactor(), 1) self.assembly.moveTo(locator) self.assertEqual(self.assembly.getSymmetryFactor(), 3) - thirdParamValues = np.array( - [b.p["massHmBOL"] for b in self.assembly.getBlocks(Flags.FUEL)] - ) - assert_allclose(thirdParamValues / originalParamValues, 1 / 3) + for b in self.assembly.getBlocks(Flags.FUEL): + # float + assert_allclose(b.p["massHmBOL"] / blockParams["massHmBOL"], 1 / 3) + # np.ndarray + assert_allclose(b.p["molesHmBOL"] / blockParams["molesHmBOL"], 1 / 3) + # list + assert_allclose( + np.array(b.p["adjMgFlux"]) / np.array(blockParams["adjMgFlux"]), 1 / 3 + ) + # string + self.assertEqual(b.p["lastMgFlux"], blockParams["lastMgFlux"]) def test_getName(self): cur = self.assembly.getName() From 7ccc70dd6746d7e5594f74ef5c7cda11ae13a819 Mon Sep 17 00:00:00 2001 From: bsculac Date: Fri, 6 Dec 2024 11:56:33 -0800 Subject: [PATCH 23/30] remove breadcrumbs (again) --- armi/reactor/assemblies.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index 0cfdd080c..95c088220 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -230,9 +230,7 @@ def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor): if b.p[name] is None or isinstance(b.p[name], str): continue elif isinstance(b.p[name], np.ndarray): - print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", b.p[name]) b.p[name] = b.p[name] * scalingFactor - print("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", b.p[name]) elif isinstance(b.p[name], Iterable): b.p[name] = [value * scalingFactor for value in b.p[name]] else: From 89997f24b6b947da32ae57ebcdbe63245fdef9c4 Mon Sep 17 00:00:00 2001 From: bsculac Date: Mon, 9 Dec 2024 09:44:29 -0800 Subject: [PATCH 24/30] correct getPuMoles to be in line with other parameters --- armi/reactor/composites.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/armi/reactor/composites.py b/armi/reactor/composites.py index 442893067..62a0e329d 100644 --- a/armi/reactor/composites.py +++ b/armi/reactor/composites.py @@ -3118,12 +3118,7 @@ def getPuMoles(self): nucNames = [nuc.name for nuc in elements.byZ[94].nuclides] puN = sum(self.getNuclideNumberDensities(nucNames)) - return ( - puN - / units.MOLES_PER_CC_TO_ATOMS_PER_BARN_CM - * self.getVolume() - * self.getSymmetryFactor() - ) + return puN / units.MOLES_PER_CC_TO_ATOMS_PER_BARN_CM * self.getVolume() class StateRetainer: From e6e3af148bfe1b75939e4ce672e41dcb0bc4f90c Mon Sep 17 00:00:00 2001 From: bsculac Date: Mon, 9 Dec 2024 09:50:15 -0800 Subject: [PATCH 25/30] relocate param defenintions for clarity --- armi/reactor/blockParameters.py | 62 ++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/armi/reactor/blockParameters.py b/armi/reactor/blockParameters.py index 44a438ba5..8952bfc97 100644 --- a/armi/reactor/blockParameters.py +++ b/armi/reactor/blockParameters.py @@ -81,30 +81,6 @@ def getBlockParameterDefinitions(): description="Ratio of fissile mass to heavy metal mass at block-level", ) - pb.defParam( - "molesHmBOL", - units=f"{units.MOLES}", - description="Total number of atoms of heavy metal at BOL.", - location=ParamLocation.VOLUME_INTEGRATED, - ) - - pb.defParam( - "massHmBOL", - units=units.GRAMS, - description="Mass of heavy metal at BOL", - location=ParamLocation.VOLUME_INTEGRATED, - ) - - pb.defParam( - "initialB10ComponentVol", - units=f"{units.CM}^3", - description=( - "cc's of un-irradiated, cold B10 containing component " - "(includes full volume of any components with B10)" - ), - location=ParamLocation.VOLUME_INTEGRATED, - ) - pb.defParam( "molesHmBOLByPin", units=f"{units.MOLES}", @@ -114,13 +90,6 @@ def getBlockParameterDefinitions(): location=ParamLocation.CHILDREN, ) - pb.defParam( - "molesHmNow", - units=f"{units.MOLES}", - description="Total number of atoms of heavy metal", - location=ParamLocation.VOLUME_INTEGRATED, - ) - pb.defParam( "newDPA", units=units.DPA, @@ -168,6 +137,37 @@ def getBlockParameterDefinitions(): categories=["cumulative"], ) + with pDefs.createBuilder( + default=0.0, location=ParamLocation.VOLUME_INTEGRATED, categories=["depletion"] + ) as pb: + + pb.defParam( + "molesHmNow", + units=f"{units.MOLES}", + description="Total number of atoms of heavy metal", + ) + + pb.defParam( + "molesHmBOL", + units=f"{units.MOLES}", + description="Total number of atoms of heavy metal at BOL.", + ) + + pb.defParam( + "massHmBOL", + units=units.GRAMS, + description="Mass of heavy metal at BOL", + ) + + pb.defParam( + "initialB10ComponentVol", + units=f"{units.CM}^3", + description=( + "cc's of un-irradiated, cold B10 containing component " + "(includes full volume of any components with B10)" + ), + ) + pDefs.add( Parameter( name="depletionMatrix", From 22ec25085c32b304405ecf54a2ca08820cc0781a Mon Sep 17 00:00:00 2001 From: bsculac <102382931+bsculac@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:33:01 -0500 Subject: [PATCH 26/30] Apply suggestions from code review Co-authored-by: John Stilley <1831479+john-science@users.noreply.github.com> --- armi/bookkeeping/tests/test_historyTracker.py | 5 ++--- armi/reactor/assemblies.py | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/armi/bookkeeping/tests/test_historyTracker.py b/armi/bookkeeping/tests/test_historyTracker.py index e655d595c..e27a92395 100644 --- a/armi/bookkeeping/tests/test_historyTracker.py +++ b/armi/bookkeeping/tests/test_historyTracker.py @@ -195,9 +195,8 @@ def test_historyParameters(self): # verify the power parameter is retrievable from the history self.assertEqual(o.cs["power"], 1000000000.0) self.assertAlmostEqual(params["power"][0], 360, delta=0.1) - self.assertEqual( - params["power"][0] / 3, params["power"][1] - ) # assembly was moved to the central location with 1/3rd symmetry + # assembly was moved to the central location with 1/3rd symmetry + self.assertEqual(params["power"][0] / 3, params["power"][1]) # verify the power density parameter is retrievable from the history self.assertAlmostEqual(params["pdens"][0], 0.0785, delta=0.001) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index 95c088220..9d06df6d9 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -229,11 +229,10 @@ def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor): name = param.name if b.p[name] is None or isinstance(b.p[name], str): continue - elif isinstance(b.p[name], np.ndarray): - b.p[name] = b.p[name] * scalingFactor elif isinstance(b.p[name], Iterable): b.p[name] = [value * scalingFactor for value in b.p[name]] else: + # numpy array or other b.p[name] = b.p[name] * scalingFactor def getNum(self): From 6dcebcbe3034dff8172cebe071050d6cac560ae0 Mon Sep 17 00:00:00 2001 From: bsculac Date: Tue, 10 Dec 2024 15:39:53 -0800 Subject: [PATCH 27/30] rephrase volume integrated check --- armi/physics/fuelCycle/fuelHandlers.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index c30ad0807..c8ae55c32 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -213,15 +213,11 @@ def _compareAssem(candidate, current): @staticmethod def _getParamMax(a, paramName, blockLevelMax=True): """Get parameter with Block-level maximum.""" - volIntegratedParamNames = [ - p.name - for p in a.getBlocks()[0].p.paramDefs.atLocation( - ParamLocation.VOLUME_INTEGRATED - ) - ] - multiplier = ( - a.getSymmetryFactor() if paramName in volIntegratedParamNames else 1.0 + isVolumeIntegrated = ( + a.getBlocks()[0].p.paramDefs[paramName].location + == ParamLocation.VOLUME_INTEGRATED ) + multiplier = a.getSymmetryFactor() if isVolumeIntegrated else 1.0 if blockLevelMax: return a.getChildParamValues(paramName).max() * multiplier From 67eafd1166c732a5ccace175178ba756ad5d94f1 Mon Sep 17 00:00:00 2001 From: bsculac <102382931+bsculac@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:42:20 -0500 Subject: [PATCH 28/30] Apply suggestions from code review Co-authored-by: John Stilley <1831479+john-science@users.noreply.github.com> --- armi/reactor/assemblies.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/armi/reactor/assemblies.py b/armi/reactor/assemblies.py index 9d06df6d9..da55c7694 100644 --- a/armi/reactor/assemblies.py +++ b/armi/reactor/assemblies.py @@ -220,7 +220,8 @@ def moveTo(self, locator): def scaleParamsToNewSymmetryFactor(self, oldSymmetryFactor): scalingFactor = oldSymmetryFactor / self.getSymmetryFactor() if scalingFactor == 1: - return # noop + return + volIntegratedParamsToScale = self.getBlocks()[0].p.paramDefs.atLocation( ParamLocation.VOLUME_INTEGRATED ) From 969f409502661222ffc0e586966e1170711ea895 Mon Sep 17 00:00:00 2001 From: bsculac Date: Tue, 10 Dec 2024 15:54:11 -0800 Subject: [PATCH 29/30] short circuit checking when not needed --- armi/physics/fuelCycle/fuelHandlers.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index c8ae55c32..a715216f3 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -213,11 +213,14 @@ def _compareAssem(candidate, current): @staticmethod def _getParamMax(a, paramName, blockLevelMax=True): """Get parameter with Block-level maximum.""" - isVolumeIntegrated = ( - a.getBlocks()[0].p.paramDefs[paramName].location - == ParamLocation.VOLUME_INTEGRATED - ) - multiplier = a.getSymmetryFactor() if isVolumeIntegrated else 1.0 + multiplier = a.getSymmetryFactor() + # handle special case: volume-integrated parameters where symmetry factor is 1.0 + if multiplier != 1: + isVolumeIntegrated = ( + a.getBlocks()[0].p.paramDefs[paramName].location + == ParamLocation.VOLUME_INTEGRATED + ) + multiplier = a.getSymmetryFactor() if isVolumeIntegrated else 1.0 if blockLevelMax: return a.getChildParamValues(paramName).max() * multiplier From cab4eb642171700cf6266f025f9eff99b12d910c Mon Sep 17 00:00:00 2001 From: John Stilley <1831479+john-science@users.noreply.github.com> Date: Wed, 11 Dec 2024 08:06:32 -0800 Subject: [PATCH 30/30] Update armi/physics/fuelCycle/fuelHandlers.py --- armi/physics/fuelCycle/fuelHandlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armi/physics/fuelCycle/fuelHandlers.py b/armi/physics/fuelCycle/fuelHandlers.py index a715216f3..51e5eb81b 100644 --- a/armi/physics/fuelCycle/fuelHandlers.py +++ b/armi/physics/fuelCycle/fuelHandlers.py @@ -214,8 +214,8 @@ def _compareAssem(candidate, current): def _getParamMax(a, paramName, blockLevelMax=True): """Get parameter with Block-level maximum.""" multiplier = a.getSymmetryFactor() - # handle special case: volume-integrated parameters where symmetry factor is 1.0 if multiplier != 1: + # handle special case: volume-integrated parameters where symmetry factor is not 1 isVolumeIntegrated = ( a.getBlocks()[0].p.paramDefs[paramName].location == ParamLocation.VOLUME_INTEGRATED