From d22468c364bced56bdb8eb9de279524ec093a201 Mon Sep 17 00:00:00 2001 From: aalberti Date: Thu, 5 Oct 2023 15:13:56 -0700 Subject: [PATCH 01/13] remove block.r --- armi/reactor/blocks.py | 39 --------------------------- armi/reactor/tests/test_assemblies.py | 6 ++--- armi/reactor/tests/test_blocks.py | 19 ++++++------- 3 files changed, 10 insertions(+), 54 deletions(-) diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index a7b80150f..b85a47c1f 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -179,42 +179,6 @@ def core(self): c = self.getAncestor(lambda c: isinstance(c, Core)) return c - @property - def r(self): - """ - Look through the ancestors of the Block to find a Reactor, and return it. - - Notes - ----- - Typical hierarchy: Reactor <- Core <- Assembly <- Block - A block should only have a reactor through a parent assembly. - It may make sense to try to factor out usage of ``b.r``. - - Returns - ------- - core.parent : armi.reactor.reactors.Reactor - ARMI reactor object that is an ancestor of the block. - - Raises - ------ - ValueError - If the parent of the block's ``core`` is not an ``armi.reactor.reactors.Reactor``. - """ - from armi.reactor.reactors import Reactor - - core = self.core - if core is None: - return self.getAncestor(lambda o: isinstance(o, Reactor)) - - if not isinstance(core.parent, Reactor): - raise TypeError( - "Parent of Block ({}) core is not a Reactor. Got {} instead".format( - core.parent, type(core.parent) - ) - ) - - return core.parent - def makeName(self, assemNum, axialIndex): """ Generate a standard block from assembly number. @@ -734,7 +698,6 @@ def adjustDensity(self, frac, adjustList, returnMass=False): numDensities = self.getNuclideNumberDensities(adjustList) for nuclideName, dens in zip(adjustList, numDensities): - if not dens: # don't modify zeros. continue @@ -1577,7 +1540,6 @@ def getPinCoordinates(self): class HexBlock(Block): - PITCH_COMPONENT_TYPE: ClassVar[_PitchDefiningComponent] = (components.Hexagon,) def __init__(self, name, height=1.0): @@ -2290,7 +2252,6 @@ def getHydraulicDiameter(self): class CartesianBlock(Block): - PITCH_DIMENSION = "widthOuter" PITCH_COMPONENT_TYPE = components.Rectangle diff --git a/armi/reactor/tests/test_assemblies.py b/armi/reactor/tests/test_assemblies.py index 47ee795d5..85b7f8707 100644 --- a/armi/reactor/tests/test_assemblies.py +++ b/armi/reactor/tests/test_assemblies.py @@ -504,7 +504,6 @@ def test_makeAxialSnapList(self): # add some blocks with a component for _i in range(assemNum2): - self.hexDims = { "Tinput": 273.0, "Thot": 273.0, @@ -645,9 +644,9 @@ def test_duplicate(self): else: self.assertEqual(cur, ref) - # Block level reactor and parent + # Block level core and parent for b in assembly2: - self.assertEqual(b.r, None) + self.assertEqual(b.core, None) self.assertEqual(b.parent, assembly2) def test_hasFlags(self): @@ -708,7 +707,6 @@ def test_getBlockData(self): self.assertAlmostEqual(cur, ref, places=places) def test_getMaxParam(self): - for bi, b in enumerate(self.assembly): b.p.power = bi self.assertAlmostEqual( diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index 381bce355..45c72fe05 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -286,7 +286,7 @@ def applyDummyData(block): xslib._nuclides["WAA"] = xslib._nuclides["W184AA"] xslib._nuclides["MNAA"] = xslib._nuclides["MN55AA"] block.p.mgFlux = flux - block.r.core.lib = xslib + block.core.lib = xslib def getComponentData(component): @@ -306,7 +306,6 @@ class Block_TestCase(unittest.TestCase): def setUp(self): self.block = loadTestBlock() self._hotBlock = loadTestBlock(cold=False) - self.r = self.block.r def test_getSmearDensity(self): cur = self.block.getSmearDensity() @@ -840,7 +839,7 @@ def test_setLocation(self): 3, ), ): - self.r.core.symmetry = geometry.SymmetryType.fromAny(symmetry) + self.block.core.symmetry = geometry.SymmetryType.fromAny(symmetry) i, j = grids.HexGrid.getIndicesFromRingAndPos(1, 1) b.spatialLocator = b.core.spatialGrid[i, j, 0] self.assertEqual(0, b.spatialLocator.k) @@ -1089,7 +1088,6 @@ def test_completeInitialLoading(self): self.assertAlmostEqual(cur, ref, places=places) def test_add(self): - numComps = len(self.block.getComponents()) fuelDims = {"Tinput": 25.0, "Thot": 600, "od": 0.76, "id": 0.00, "mult": 127.0} @@ -1109,7 +1107,6 @@ def test_hasComponents(self): ) def test_getComponentNames(self): - cur = self.block.getComponentNames() ref = set( [ @@ -1393,7 +1390,7 @@ def test_106_getAreaFractions(self): fracs[c.getName()] = a / tot places = 6 - for (c, a) in cur: + for c, a in cur: self.assertAlmostEqual(a, fracs[c.getName()], places=places) self.assertAlmostEqual(sum(fracs.values()), sum([a for c, a in cur])) @@ -1764,12 +1761,12 @@ def test_getArea(self): self.assertAlmostEqual(cur, ref, places=places) def test_coords(self): - r = self.HexBlock.r + core = self.HexBlock.core a = self.HexBlock.parent - loc1 = r.core.spatialGrid[0, 1, 0] + loc1 = core.spatialGrid[0, 1, 0] a.spatialLocator = loc1 x0, y0 = self.HexBlock.coords() - a.spatialLocator = r.core.spatialGrid[0, -1, 0] # symmetric + a.spatialLocator = core.spatialGrid[0, -1, 0] # symmetric x2, y2 = self.HexBlock.coords() a.spatialLocator = loc1 self.HexBlock.p.displacementX = 0.01 @@ -1789,7 +1786,7 @@ def test_getNumPins(self): def test_symmetryFactor(self): # full hex - self.HexBlock.spatialLocator = self.HexBlock.r.core.spatialGrid[2, 0, 0] + self.HexBlock.spatialLocator = self.HexBlock.core.spatialGrid[2, 0, 0] self.HexBlock.clearCache() self.assertEqual(1.0, self.HexBlock.getSymmetryFactor()) a0 = self.HexBlock.getArea() @@ -1797,7 +1794,7 @@ def test_symmetryFactor(self): m0 = self.HexBlock.getMass() # 1/3 symmetric - self.HexBlock.spatialLocator = self.HexBlock.r.core.spatialGrid[0, 0, 0] + self.HexBlock.spatialLocator = self.HexBlock.core.spatialGrid[0, 0, 0] self.HexBlock.clearCache() self.assertEqual(3.0, self.HexBlock.getSymmetryFactor()) self.assertEqual(a0 / 3.0, self.HexBlock.getArea()) From 0bfa9fb4b41b9063525b147094cfd509d5beec7e Mon Sep 17 00:00:00 2001 From: aalberti Date: Thu, 5 Oct 2023 15:42:38 -0700 Subject: [PATCH 02/13] fix blueprints call --- armi/reactor/blocks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index b85a47c1f..fdd9fee70 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -722,7 +722,7 @@ def _updateDetailedNdens(self, frac, adjustList): # BOL assems get expanded to a reference so the first check is needed so it # won't call .blueprints on None since BOL assems don't have a core/r return - if any(nuc in self.r.blueprints.activeNuclides for nuc in adjustList): + if any(nuc in self.core.r.blueprints.activeNuclides for nuc in adjustList): self.p.detailedNDens *= frac # Other power densities do not need to be updated as they are calculated in # the global flux interface, which occurs after axial expansion from crucible From 17ef2631ca3dcb4eae79a81bbf5c2d53afb62e7e Mon Sep 17 00:00:00 2001 From: aalberti Date: Fri, 6 Oct 2023 07:26:13 -0700 Subject: [PATCH 03/13] fix unit tests --- .../tests/test_crossSectionManager.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/armi/physics/neutronics/tests/test_crossSectionManager.py b/armi/physics/neutronics/tests/test_crossSectionManager.py index 2282651c3..e7073a5a6 100644 --- a/armi/physics/neutronics/tests/test_crossSectionManager.py +++ b/armi/physics/neutronics/tests/test_crossSectionManager.py @@ -55,7 +55,9 @@ class TestBlockCollection(unittest.TestCase): def setUp(self): self.blockList = makeBlocks() - self.bc = BlockCollection(self.blockList[0].r.blueprints.allNuclidesInProblem) + self.bc = BlockCollection( + self.blockList[0].core.r.blueprints.allNuclidesInProblem + ) self.bc.extend(self.blockList) def test_add(self): @@ -86,12 +88,11 @@ def setUp(self): b.p.percentBu = bi / 4.0 * 100 self.blockList[0], self.blockList[2] = self.blockList[2], self.blockList[0] self.bc = MedianBlockCollection( - self.blockList[0].r.blueprints.allNuclidesInProblem + self.blockList[0].core.r.blueprints.allNuclidesInProblem ) self.bc.extend(self.blockList) def test_createRepresentativeBlock(self): - avgB = self.bc.createRepresentativeBlock() self.assertAlmostEqual(avgB.p.percentBu, 50.0) @@ -107,7 +108,7 @@ def setUp(self): b.setNumberDensity("U235", bi) b.p.gasReleaseFraction = bi * 2 / 8.0 self.bc = AverageBlockCollection( - self.blockList[0].r.blueprints.allNuclidesInProblem + self.blockList[0].core.r.blueprints.allNuclidesInProblem ) self.bc.extend(self.blockList) @@ -318,7 +319,6 @@ def test_ComponentAverage1DCylinder(self): ) def test_checkComponentConsistency(self): - xsgm = self.o.getInterface("xsGroups") xsgm.interactBOL() blockCollectionsByXsGroup = xsgm.makeCrossSectionGroups() @@ -454,7 +454,7 @@ def setUp(self): b.p.flux = bi + 1 self.bc = FluxWeightedAverageBlockCollection( - self.blockList[0].r.blueprints.allNuclidesInProblem + self.blockList[0].core.r.blueprints.allNuclidesInProblem ) self.bc.extend(self.blockList) @@ -475,7 +475,7 @@ class Test_CrossSectionGroupManager(unittest.TestCase): def setUp(self): cs = settings.Settings() self.blockList = makeBlocks(20) - self.csm = CrossSectionGroupManager(self.blockList[0].r, cs) + self.csm = CrossSectionGroupManager(self.blockList[0].core.r, cs) for bi, b in enumerate(self.blockList): b.p.percentBu = bi / 19.0 * 100 self.csm._setBuGroupBounds([3, 10, 30, 100]) @@ -615,14 +615,14 @@ def test_createRepresentativeBlocksUsingExistingBlocks(self): def test_interactBOL(self): """Test `BOL` lattice physics update frequency.""" - self.blockList[0].r.p.timeNode = 0 + self.blockList[0].core.r.p.timeNode = 0 self.csm.cs[CONF_LATTICE_PHYSICS_FREQUENCY] = "BOL" self.csm.interactBOL() self.assertTrue(self.csm.representativeBlocks) def test_interactBOC(self): """Test `BOC` lattice physics update frequency.""" - self.blockList[0].r.p.timeNode = 0 + self.blockList[0].core.r.p.timeNode = 0 self.csm.cs[CONF_LATTICE_PHYSICS_FREQUENCY] = "BOC" self.csm.interactBOL() self.csm.interactBOC() From 582a727a17b4a72352ec7d0e15fdb2cbe73913d0 Mon Sep 17 00:00:00 2001 From: aalberti Date: Fri, 6 Oct 2023 08:12:26 -0700 Subject: [PATCH 04/13] fix more unit tests --- armi/mpiActions.py | 6 +++--- .../neutronics/globalFlux/tests/test_globalFluxInterface.py | 2 +- armi/reactor/tests/test_composites.py | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/armi/mpiActions.py b/armi/mpiActions.py index ce9b32237..383914514 100644 --- a/armi/mpiActions.py +++ b/armi/mpiActions.py @@ -138,7 +138,7 @@ def _mpiOperationHelper(self, obj, mpiFunction): self.o = self.r = self.cs = None try: return mpiFunction(obj, root=0) - except (cPickle.PicklingError) as error: + except cPickle.PicklingError as error: runLog.error("Failed to {} {}.".format(mpiFunction.__name__, obj)) runLog.error(error) raise @@ -553,8 +553,8 @@ def invokeHook(self): self.r.core.regenAssemblyLists() # check to make sure that everything has been properly reattached - if self.r.core.getFirstBlock().r is not self.r: - raise RuntimeError("Block.r is not self.r. Reattach the blocks!") + if self.r.core.getFirstBlock().core.r is not self.r: + raise RuntimeError("Block.core.r is not self.r. Reattach the blocks!") beforeCollection = timeit.default_timer() diff --git a/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py b/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py index ff8957660..3033201bc 100644 --- a/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py +++ b/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py @@ -352,7 +352,7 @@ def test_calcReactionRates(self): b = test_blocks.loadTestBlock() test_blocks.applyDummyData(b) self.assertAlmostEqual(b.p.rateAbs, 0.0) - globalFluxInterface.calcReactionRates(b, 1.01, b.r.core.lib) + globalFluxInterface.calcReactionRates(b, 1.01, b.core.r.lib) self.assertGreater(b.p.rateAbs, 0.0) vfrac = b.getComponentAreaFrac(Flags.FUEL) self.assertEqual(b.p.fisDens, b.p.rateFis / vfrac) diff --git a/armi/reactor/tests/test_composites.py b/armi/reactor/tests/test_composites.py index 6094b4010..8e05412b9 100644 --- a/armi/reactor/tests/test_composites.py +++ b/armi/reactor/tests/test_composites.py @@ -294,7 +294,6 @@ def test_syncParameters(self): class TestCompositeTree(unittest.TestCase): - blueprintYaml = """ name: test assembly height: [1, 1] # 2 blocks @@ -359,7 +358,7 @@ def __init__(self, *args, **kwargs): def setUp(self): self.Block = loadTestBlock() - self.r = self.Block.r + self.r = self.Block.core.r self.Block.setHeight(100.0) self.refDict = { "U235": 0.00275173784234, From ebbcdcb6610ae5a25c7fdf3075789ca7ae105a76 Mon Sep 17 00:00:00 2001 From: aalberti Date: Fri, 6 Oct 2023 09:31:08 -0700 Subject: [PATCH 05/13] mv get*EnergyDepositionConstants to blocks.py - in ARMI and at least one major downstream project, these are only every used on blocks. So these can be safely moved off of composites.py and onto blocks.py. - also, given the current properties, only Blocks are even able to use these methods. assembly.r and component.r don't exist so they wouldn't work anyway. and Core.getMicroSuffix doesn't exist so Core wouldn't work either. These methods really only work for blocks, so let's move them to blocks.py. --- .../tests/test_globalFluxInterface.py | 2 +- armi/reactor/blocks.py | 119 ++++++++++++++++++ armi/reactor/composites.py | 119 ------------------ armi/reactor/tests/test_blocks.py | 12 ++ armi/reactor/tests/test_composites.py | 12 -- 5 files changed, 132 insertions(+), 132 deletions(-) diff --git a/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py b/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py index 3033201bc..ee7ef4a5a 100644 --- a/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py +++ b/armi/physics/neutronics/globalFlux/tests/test_globalFluxInterface.py @@ -352,7 +352,7 @@ def test_calcReactionRates(self): b = test_blocks.loadTestBlock() test_blocks.applyDummyData(b) self.assertAlmostEqual(b.p.rateAbs, 0.0) - globalFluxInterface.calcReactionRates(b, 1.01, b.core.r.lib) + globalFluxInterface.calcReactionRates(b, 1.01, b.core.lib) self.assertGreater(b.p.rateAbs, 0.0) vfrac = b.getComponentAreaFrac(Flags.FUEL) self.assertEqual(b.p.fisDens, b.p.rateFis / vfrac) diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index fdd9fee70..28f968972 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -48,6 +48,7 @@ from armi.utils import units from armi.utils.plotting import plotBlockFlux from armi.utils.units import TRACE_NUMBER_DENSITY +from armi.nuclearDataIO import xsCollections PIN_COMPONENTS = [ Flags.CONTROL, @@ -1538,6 +1539,124 @@ def getPinCoordinates(self): coords.append(clad.spatialLocator.getLocalCoordinates()) return coords + def getTotalEnergyGenerationConstants(self): + """ + Get the total energy generation group constants for a block. + + Gives the total energy generation rates when multiplied by the multigroup flux. + + Returns + ------- + totalEnergyGenConstant: numpy.array + Total (fission + capture) energy generation group constants (Joules/cm) + """ + return ( + self.getFissionEnergyGenerationConstants() + + self.getCaptureEnergyGenerationConstants() + ) + + def getFissionEnergyGenerationConstants(self): + """ + Get the fission energy generation group constants for a block. + + Gives the fission energy generation rates when multiplied by the multigroup + flux. + + Returns + ------- + fissionEnergyGenConstant: numpy.array + Energy generation group constants (Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot compute energy generation group constants without a library" + ". Please ensure a library exists." + ) + + return xsCollections.computeFissionEnergyGenerationConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + + def getCaptureEnergyGenerationConstants(self): + """ + Get the capture energy generation group constants for a block. + + Gives the capture energy generation rates when multiplied by the multigroup + flux. + + Returns + ------- + fissionEnergyGenConstant: numpy.array + Energy generation group constants (Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot compute energy generation group constants without a library" + ". Please ensure a library exists." + ) + + return xsCollections.computeCaptureEnergyGenerationConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + + def getNeutronEnergyDepositionConstants(self): + """ + Get the neutron energy deposition group constants for a block. + + Returns + ------- + energyDepConstants: numpy.array + Neutron energy generation group constants (in Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot get neutron energy deposition group constants without " + "a library. Please ensure a library exists." + ) + + return xsCollections.computeNeutronEnergyDepositionConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + + def getGammaEnergyDepositionConstants(self): + """ + Get the gamma energy deposition group constants for a block. + + Returns + ------- + energyDepConstants: numpy.array + Energy generation group constants (in Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot get gamma energy deposition group constants without " + "a library. Please ensure a library exists." + ) + + return xsCollections.computeGammaEnergyDepositionConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + class HexBlock(Block): PITCH_COMPONENT_TYPE: ClassVar[_PitchDefiningComponent] = (components.Hexagon,) diff --git a/armi/reactor/composites.py b/armi/reactor/composites.py index 92b5ad297..4ea9208e2 100644 --- a/armi/reactor/composites.py +++ b/armi/reactor/composites.py @@ -44,7 +44,6 @@ from armi import utils from armi.nucDirectory import elements from armi.nucDirectory import nucDir, nuclideBases -from armi.nuclearDataIO import xsCollections from armi.physics.neutronics.fissionProductModel import fissionProductModel from armi.reactor import grids from armi.reactor import parameters @@ -1277,124 +1276,6 @@ def getNumberDensities(self, expandFissionProducts=False): return self._expandLFPs(numberDensities) return numberDensities - def getNeutronEnergyDepositionConstants(self): - """ - Get the neutron energy deposition group constants for a composite. - - Returns - ------- - energyDepConstants: numpy.array - Neutron energy generation group constants (in Joules/cm) - - Raises - ------ - RuntimeError: - Reports if a cross section library is not assigned to a reactor. - """ - if not self.r.core.lib: - raise RuntimeError( - "Cannot get neutron energy deposition group constants without " - "a library. Please ensure a library exists." - ) - - return xsCollections.computeNeutronEnergyDepositionConstants( - self.getNumberDensities(), self.r.core.lib, self.getMicroSuffix() - ) - - def getGammaEnergyDepositionConstants(self): - """ - Get the gamma energy deposition group constants for a composite. - - Returns - ------- - energyDepConstants: numpy.array - Energy generation group constants (in Joules/cm) - - Raises - ------ - RuntimeError: - Reports if a cross section library is not assigned to a reactor. - """ - if not self.r.core.lib: - raise RuntimeError( - "Cannot get gamma energy deposition group constants without " - "a library. Please ensure a library exists." - ) - - return xsCollections.computeGammaEnergyDepositionConstants( - self.getNumberDensities(), self.r.core.lib, self.getMicroSuffix() - ) - - def getTotalEnergyGenerationConstants(self): - """ - Get the total energy generation group constants for a composite. - - Gives the total energy generation rates when multiplied by the multigroup flux. - - Returns - ------- - totalEnergyGenConstant: numpy.array - Total (fission + capture) energy generation group constants (Joules/cm) - """ - return ( - self.getFissionEnergyGenerationConstants() - + self.getCaptureEnergyGenerationConstants() - ) - - def getFissionEnergyGenerationConstants(self): - """ - Get the fission energy generation group constants for a composite. - - Gives the fission energy generation rates when multiplied by the multigroup - flux. - - Returns - ------- - fissionEnergyGenConstant: numpy.array - Energy generation group constants (Joules/cm) - - Raises - ------ - RuntimeError: - Reports if a cross section library is not assigned to a reactor. - """ - if not self.r.core.lib: - raise RuntimeError( - "Cannot compute energy generation group constants without a library" - ". Please ensure a library exists." - ) - - return xsCollections.computeFissionEnergyGenerationConstants( - self.getNumberDensities(), self.r.core.lib, self.getMicroSuffix() - ) - - def getCaptureEnergyGenerationConstants(self): - """ - Get the capture energy generation group constants for a composite. - - Gives the capture energy generation rates when multiplied by the multigroup - flux. - - Returns - ------- - fissionEnergyGenConstant: numpy.array - Energy generation group constants (Joules/cm) - - Raises - ------ - RuntimeError: - Reports if a cross section library is not assigned to a reactor. - """ - if not self.r.core.lib: - raise RuntimeError( - "Cannot compute energy generation group constants without a library" - ". Please ensure a library exists." - ) - - return xsCollections.computeCaptureEnergyGenerationConstants( - self.getNumberDensities(), self.r.core.lib, self.getMicroSuffix() - ) - def _expandLFPs(self, numberDensities): """ Expand the LFPs on the numberDensities dictionary using this composite's diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index 45c72fe05..57818c3b3 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -1689,6 +1689,18 @@ def test_getReactionRates(self): {"nG": 0, "nF": 0, "n2n": 0, "nA": 0, "nP": 0, "n3n": 0}, ) + def test_getNeutronEnergyDepositionConstants(self): + """Until we improve test architecture, this test can not be more interesting.""" + with self.assertRaises(RuntimeError): + # fails because this test reactor does not have a cross-section library + _x = self.block.getNeutronEnergyDepositionConstants() + + def test_getGammaEnergyDepositionConstants(self): + """Until we improve test architecture, this test can not be more interesting.""" + with self.assertRaises(RuntimeError): + # fails because this test reactor does not have a cross-section library + _x = self.block.getGammaEnergyDepositionConstants() + class Test_NegativeVolume(unittest.TestCase): def test_negativeVolume(self): diff --git a/armi/reactor/tests/test_composites.py b/armi/reactor/tests/test_composites.py index 8e05412b9..8bdeae437 100644 --- a/armi/reactor/tests/test_composites.py +++ b/armi/reactor/tests/test_composites.py @@ -431,18 +431,6 @@ def test_getFuelMass(self): self.assertEqual(fuelMass, a.getFuelMass()) - def test_getNeutronEnergyDepositionConstants(self): - """Until we improve test architecture, this test can not be more interesting.""" - with self.assertRaises(RuntimeError): - # fails because this test reactor does not have a cross-section library - _x = self.r.core.getNeutronEnergyDepositionConstants() - - def test_getGammaEnergyDepositionConstants(self): - """Until we improve test architecture, this test can not be more interesting.""" - with self.assertRaises(RuntimeError): - # fails because this test reactor does not have a cross-section library - _x = self.r.core.getGammaEnergyDepositionConstants() - def test_getChildrenIncludeMaterials(self): """Test that the ``StateRetainer`` retains material properties when they are modified.""" cs = settings.Settings() From e189870430e5ba68263f4d26842b7470b77b5cd2 Mon Sep 17 00:00:00 2001 From: aalberti Date: Fri, 6 Oct 2023 11:45:39 -0700 Subject: [PATCH 06/13] add proper tests for block energy dep methods --- armi/reactor/tests/test_blocks.py | 58 ++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index 57818c3b3..0b99c4d9c 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -16,6 +16,7 @@ import math import os import unittest +from unittest.mock import MagicMock, patch import numpy from numpy.testing import assert_allclose @@ -35,6 +36,7 @@ from armi.tests import ISOAA_PATH, TEST_ROOT from armi.utils import hexagon, units from armi.utils.units import MOLES_PER_CC_TO_ATOMS_PER_BARN_CM +from armi.nuclearDataIO import xsCollections NUM_PINS_IN_TEST_BLOCK = 217 @@ -1689,14 +1691,62 @@ def test_getReactionRates(self): {"nG": 0, "nF": 0, "n2n": 0, "nA": 0, "nP": 0, "n3n": 0}, ) - def test_getNeutronEnergyDepositionConstants(self): - """Until we improve test architecture, this test can not be more interesting.""" + +class BlockEnergyDepositionConstants(unittest.TestCase): + """Tests the energy deposition methods. + + MagicMocks xsCollections.compute*Constants() -- we're not testing those methods specifically so just make sure they're hit + """ + + @classmethod + def setUpClass(cls): + cls.block = loadTestBlock() + + def setUp(self): + self.block.core.lib = MagicMock() + + @patch.object(xsCollections, "computeFissionEnergyGenerationConstants") + def test_getFissionEnergyDepositionConstants(self, mock_method): + """Test RuntimeError and that it returns the right deposition constant""" + # make sure xsCollections.compute* gets hit + _x = self.block.getFissionEnergyGenerationConstants() + self.assertEqual(mock_method.call_count, 1) + # set core.lib to None and get RuntimeError + self.block.core.lib = None + with self.assertRaises(RuntimeError): + # fails because this test reactor does not have a cross-section library + _x = self.block.getFissionEnergyGenerationConstants() + + @patch.object(xsCollections, "computeCaptureEnergyGenerationConstants") + def test_getCaptureEnergyGenerationConstants(self, mock_method): + """Test RuntimeError and that it returns the right deposition constant""" + # make sure xsCollections.compute* gets hit + _x = self.block.getCaptureEnergyGenerationConstants() + self.assertEqual(mock_method.call_count, 1) + # set core.lib to None and get RuntimeError + self.block.core.lib = None with self.assertRaises(RuntimeError): # fails because this test reactor does not have a cross-section library + _x = self.block.getCaptureEnergyGenerationConstants() + + @patch.object(xsCollections, "computeNeutronEnergyDepositionConstants") + def test_getNeutronEnergyDepositionConstants(self, mock_method): + # make sure xsCollections.compute* gets hit + _x = self.block.getNeutronEnergyDepositionConstants() + self.assertEqual(mock_method.call_count, 1) + # set core.lib to None and get RuntimeError + self.block.core.lib = None + with self.assertRaises(RuntimeError): _x = self.block.getNeutronEnergyDepositionConstants() - def test_getGammaEnergyDepositionConstants(self): - """Until we improve test architecture, this test can not be more interesting.""" + @patch.object(xsCollections, "computeGammaEnergyDepositionConstants") + def test_getGammaEnergyDepositionConstants(self, mock_method): + """Test RuntimeError and that it returns the right deposition constant""" + # make sure xsCollections.compute* gets hit + _x = self.block.getGammaEnergyDepositionConstants() + self.assertEqual(mock_method.call_count, 1) + # set core.lib to None and get RuntimeError + self.block.core.lib = None with self.assertRaises(RuntimeError): # fails because this test reactor does not have a cross-section library _x = self.block.getGammaEnergyDepositionConstants() From 1843f34bdeac8404fce8aa47b65d3ecab2cab722 Mon Sep 17 00:00:00 2001 From: aalberti Date: Fri, 6 Oct 2023 11:58:32 -0700 Subject: [PATCH 07/13] add a test for the tot energy gen + fix docstrings --- armi/reactor/tests/test_blocks.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index 0b99c4d9c..09b87421e 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -1705,9 +1705,17 @@ def setUpClass(cls): def setUp(self): self.block.core.lib = MagicMock() + @patch.object(xsCollections, "computeFissionEnergyGenerationConstants") + @patch.object(xsCollections, "computeCaptureEnergyGenerationConstants") + def test_getTotalEnergyGenerationConstants(self, mock_capture, mock_fission): + """Mock both xsCollections methods so you get complete coverage""" + _x = self.block.getTotalEnergyGenerationConstants() + self.assertEqual(mock_fission.call_count, 1) + self.assertEqual(mock_capture.call_count, 1) + @patch.object(xsCollections, "computeFissionEnergyGenerationConstants") def test_getFissionEnergyDepositionConstants(self, mock_method): - """Test RuntimeError and that it returns the right deposition constant""" + """Test RuntimeError and that it gets to the deposition constant call""" # make sure xsCollections.compute* gets hit _x = self.block.getFissionEnergyGenerationConstants() self.assertEqual(mock_method.call_count, 1) @@ -1719,7 +1727,7 @@ def test_getFissionEnergyDepositionConstants(self, mock_method): @patch.object(xsCollections, "computeCaptureEnergyGenerationConstants") def test_getCaptureEnergyGenerationConstants(self, mock_method): - """Test RuntimeError and that it returns the right deposition constant""" + """Test RuntimeError and that it gets to the deposition constant call""" # make sure xsCollections.compute* gets hit _x = self.block.getCaptureEnergyGenerationConstants() self.assertEqual(mock_method.call_count, 1) @@ -1731,6 +1739,7 @@ def test_getCaptureEnergyGenerationConstants(self, mock_method): @patch.object(xsCollections, "computeNeutronEnergyDepositionConstants") def test_getNeutronEnergyDepositionConstants(self, mock_method): + """Test RuntimeError and that it gets to the deposition constant call""" # make sure xsCollections.compute* gets hit _x = self.block.getNeutronEnergyDepositionConstants() self.assertEqual(mock_method.call_count, 1) @@ -1741,7 +1750,7 @@ def test_getNeutronEnergyDepositionConstants(self, mock_method): @patch.object(xsCollections, "computeGammaEnergyDepositionConstants") def test_getGammaEnergyDepositionConstants(self, mock_method): - """Test RuntimeError and that it returns the right deposition constant""" + """Test RuntimeError and that it gets to the deposition constant call""" # make sure xsCollections.compute* gets hit _x = self.block.getGammaEnergyDepositionConstants() self.assertEqual(mock_method.call_count, 1) From 8ed3b0912346f873f0b31d5e9432ea056fef07b6 Mon Sep 17 00:00:00 2001 From: aalberti Date: Wed, 11 Oct 2023 08:09:56 -0700 Subject: [PATCH 08/13] release notes --- doc/release/0.2.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/release/0.2.rst b/doc/release/0.2.rst index 4f8bbd735..071b5854a 100644 --- a/doc/release/0.2.rst +++ b/doc/release/0.2.rst @@ -10,6 +10,7 @@ What's new in ARMI ------------------ #. The ``_copyInputsHelper()`` gives relative path and not absolute after copy. (`PR#1416 `_) #. ARMI now mandates ``ruff`` linting. (`PR#1419 `_) +#. Removal of the Block.reactor property. (`PR#1425 `_) #. TBD Bug fixes From 09f289efad3fa635e57e9da301639853a1a9de08 Mon Sep 17 00:00:00 2001 From: aalberti Date: Wed, 13 Mar 2024 11:36:58 -0700 Subject: [PATCH 09/13] clean up merge conflict error --- armi/reactor/tests/test_blocks.py | 69 ------------------------------- 1 file changed, 69 deletions(-) diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index 885de0cb2..25e030095 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -1850,75 +1850,6 @@ def test_getGammaEnergyDepositionConstants(self, mock_method): _x = self.block.getGammaEnergyDepositionConstants() -class BlockEnergyDepositionConstants(unittest.TestCase): - """Tests the energy deposition methods. - - MagicMocks xsCollections.compute*Constants() -- we're not testing those methods specifically so just make sure they're hit - """ - - @classmethod - def setUpClass(cls): - cls.block = loadTestBlock() - - def setUp(self): - self.block.core.lib = MagicMock() - - @patch.object(xsCollections, "computeFissionEnergyGenerationConstants") - @patch.object(xsCollections, "computeCaptureEnergyGenerationConstants") - def test_getTotalEnergyGenerationConstants(self, mock_capture, mock_fission): - """Mock both xsCollections methods so you get complete coverage""" - _x = self.block.getTotalEnergyGenerationConstants() - self.assertEqual(mock_fission.call_count, 1) - self.assertEqual(mock_capture.call_count, 1) - - @patch.object(xsCollections, "computeFissionEnergyGenerationConstants") - def test_getFissionEnergyDepositionConstants(self, mock_method): - """Test RuntimeError and that it gets to the deposition constant call""" - # make sure xsCollections.compute* gets hit - _x = self.block.getFissionEnergyGenerationConstants() - self.assertEqual(mock_method.call_count, 1) - # set core.lib to None and get RuntimeError - self.block.core.lib = None - with self.assertRaises(RuntimeError): - # fails because this test reactor does not have a cross-section library - _x = self.block.getFissionEnergyGenerationConstants() - - @patch.object(xsCollections, "computeCaptureEnergyGenerationConstants") - def test_getCaptureEnergyGenerationConstants(self, mock_method): - """Test RuntimeError and that it gets to the deposition constant call""" - # make sure xsCollections.compute* gets hit - _x = self.block.getCaptureEnergyGenerationConstants() - self.assertEqual(mock_method.call_count, 1) - # set core.lib to None and get RuntimeError - self.block.core.lib = None - with self.assertRaises(RuntimeError): - # fails because this test reactor does not have a cross-section library - _x = self.block.getCaptureEnergyGenerationConstants() - - @patch.object(xsCollections, "computeNeutronEnergyDepositionConstants") - def test_getNeutronEnergyDepositionConstants(self, mock_method): - """Test RuntimeError and that it gets to the deposition constant call""" - # make sure xsCollections.compute* gets hit - _x = self.block.getNeutronEnergyDepositionConstants() - self.assertEqual(mock_method.call_count, 1) - # set core.lib to None and get RuntimeError - self.block.core.lib = None - with self.assertRaises(RuntimeError): - _x = self.block.getNeutronEnergyDepositionConstants() - - @patch.object(xsCollections, "computeGammaEnergyDepositionConstants") - def test_getGammaEnergyDepositionConstants(self, mock_method): - """Test RuntimeError and that it gets to the deposition constant call""" - # make sure xsCollections.compute* gets hit - _x = self.block.getGammaEnergyDepositionConstants() - self.assertEqual(mock_method.call_count, 1) - # set core.lib to None and get RuntimeError - self.block.core.lib = None - with self.assertRaises(RuntimeError): - # fails because this test reactor does not have a cross-section library - _x = self.block.getGammaEnergyDepositionConstants() - - class TestNegativeVolume(unittest.TestCase): def test_negativeVolume(self): """Build a block with WAY too many fuel pins and show that the derived volume is negative.""" From 133060b64574b606c939a22419f0eb3dc4357072 Mon Sep 17 00:00:00 2001 From: aalberti Date: Wed, 13 Mar 2024 12:36:11 -0700 Subject: [PATCH 10/13] fix broken unit tests --- armi/physics/neutronics/tests/test_crossSectionManager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/armi/physics/neutronics/tests/test_crossSectionManager.py b/armi/physics/neutronics/tests/test_crossSectionManager.py index de9e951c5..872ec1d4c 100644 --- a/armi/physics/neutronics/tests/test_crossSectionManager.py +++ b/armi/physics/neutronics/tests/test_crossSectionManager.py @@ -162,7 +162,7 @@ def test_createRepresentativeBlock(self): # check that a new block collection of the representative block has right temperatures # this is required for Doppler coefficient calculations newBc = AverageBlockCollection( - self.blockList[0].r.blueprints.allNuclidesInProblem + self.blockList[0].core.r.blueprints.allNuclidesInProblem ) newBc.append(avgB) newBc.calcAvgNuclideTemperatures() @@ -201,7 +201,7 @@ def test_createRepresentativeBlockDissimilar(self): # U35 has different average temperature because blocks have different U235 content newBc = AverageBlockCollection( - self.blockList[0].r.blueprints.allNuclidesInProblem + self.blockList[0].core.r.blueprints.allNuclidesInProblem ) newBc.append(avgB) newBc.calcAvgNuclideTemperatures() @@ -253,7 +253,7 @@ def setUpClass(cls): def setUp(self): self.bc = AverageBlockCollection( - self.blockList[0].r.blueprints.allNuclidesInProblem + self.blockList[0].core.r.blueprints.allNuclidesInProblem ) blockCopies = [copy.deepcopy(b) for b in self.blockList] self.bc.extend(blockCopies) From e0eae8634c67343f4638ed6dacd176950373e091 Mon Sep 17 00:00:00 2001 From: aalberti Date: Fri, 19 Apr 2024 13:29:14 -0700 Subject: [PATCH 11/13] fix linter problems --- armi/reactor/blocks.py | 1 - armi/reactor/tests/test_blocks.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index e47882c71..91caa4e09 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -47,7 +47,6 @@ from armi.utils import units from armi.utils.plotting import plotBlockFlux from armi.utils.units import TRACE_NUMBER_DENSITY -from armi.nuclearDataIO import xsCollections PIN_COMPONENTS = [ Flags.CONTROL, diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index ac7589d76..4a610e534 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -1766,7 +1766,8 @@ def test_getReactionRates(self): class BlockEnergyDepositionConstants(unittest.TestCase): """Tests the energy deposition methods. - MagicMocks xsCollections.compute*Constants() -- we're not testing those methods specifically so just make sure they're hit + MagicMocks xsCollections.compute*Constants() -- we're not testing those methods specifically + so just make sure they're hit """ @classmethod From 9468d49e975edda8c2123d231f5a2b82a461682f Mon Sep 17 00:00:00 2001 From: aalberti Date: Fri, 19 Apr 2024 15:33:12 -0700 Subject: [PATCH 12/13] fix screwed up merge in of main --- armi/reactor/blocks.py | 119 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/armi/reactor/blocks.py b/armi/reactor/blocks.py index 91caa4e09..318330db1 100644 --- a/armi/reactor/blocks.py +++ b/armi/reactor/blocks.py @@ -47,6 +47,7 @@ from armi.utils import units from armi.utils.plotting import plotBlockFlux from armi.utils.units import TRACE_NUMBER_DENSITY +from armi.nuclearDataIO import xsCollections PIN_COMPONENTS = [ Flags.CONTROL, @@ -1596,6 +1597,124 @@ def getPinCoordinates(self): coords.append(clad.spatialLocator.getLocalCoordinates()) return coords + def getTotalEnergyGenerationConstants(self): + """ + Get the total energy generation group constants for a block. + + Gives the total energy generation rates when multiplied by the multigroup flux. + + Returns + ------- + totalEnergyGenConstant: numpy.array + Total (fission + capture) energy generation group constants (Joules/cm) + """ + return ( + self.getFissionEnergyGenerationConstants() + + self.getCaptureEnergyGenerationConstants() + ) + + def getFissionEnergyGenerationConstants(self): + """ + Get the fission energy generation group constants for a block. + + Gives the fission energy generation rates when multiplied by the multigroup + flux. + + Returns + ------- + fissionEnergyGenConstant: numpy.array + Energy generation group constants (Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot compute energy generation group constants without a library" + ". Please ensure a library exists." + ) + + return xsCollections.computeFissionEnergyGenerationConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + + def getCaptureEnergyGenerationConstants(self): + """ + Get the capture energy generation group constants for a block. + + Gives the capture energy generation rates when multiplied by the multigroup + flux. + + Returns + ------- + fissionEnergyGenConstant: numpy.array + Energy generation group constants (Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot compute energy generation group constants without a library" + ". Please ensure a library exists." + ) + + return xsCollections.computeCaptureEnergyGenerationConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + + def getNeutronEnergyDepositionConstants(self): + """ + Get the neutron energy deposition group constants for a block. + + Returns + ------- + energyDepConstants: numpy.array + Neutron energy generation group constants (in Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot get neutron energy deposition group constants without " + "a library. Please ensure a library exists." + ) + + return xsCollections.computeNeutronEnergyDepositionConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + + def getGammaEnergyDepositionConstants(self): + """ + Get the gamma energy deposition group constants for a block. + + Returns + ------- + energyDepConstants: numpy.array + Energy generation group constants (in Joules/cm) + + Raises + ------ + RuntimeError: + Reports if a cross section library is not assigned to a reactor. + """ + if not self.core.lib: + raise RuntimeError( + "Cannot get gamma energy deposition group constants without " + "a library. Please ensure a library exists." + ) + + return xsCollections.computeGammaEnergyDepositionConstants( + self.getNumberDensities(), self.core.lib, self.getMicroSuffix() + ) + def getBoronMassEnrich(self): """Return B-10 mass fraction.""" b10 = self.getMass("B10") From c2cd59d54051d93b744c0c49e7912eab6b5458c1 Mon Sep 17 00:00:00 2001 From: aalberti Date: Mon, 22 Apr 2024 08:39:00 -0700 Subject: [PATCH 13/13] fix release notes --- doc/release/0.2.rst | 17 ----------------- doc/release/0.3.rst | 8 ++++++++ 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/doc/release/0.2.rst b/doc/release/0.2.rst index a646a0a05..c8728e235 100644 --- a/doc/release/0.2.rst +++ b/doc/release/0.2.rst @@ -1,20 +1,3 @@ -*********************** -ARMI v0.3 Release Notes -======================= - -ARMI v0.3.1 -============ -Release Date: TBD - -What's new in ARMI ------------------- -#. Removal of the Block.reactor property. (`PR#1425 `_) -#. TBD - -Bug fixes ---------- -#. TBD - *********************** ARMI v0.2 Release Notes ======================= diff --git a/doc/release/0.3.rst b/doc/release/0.3.rst index bb58d291d..7c8534405 100644 --- a/doc/release/0.3.rst +++ b/doc/release/0.3.rst @@ -9,6 +9,7 @@ Release Date: TBD New Features ------------ #. Conserve mass by component in assembly.setBlockMesh(). (`PR#1665 `_) +#. Removal of the Block.reactor property. (`PR#1425 `_) #. TBD API Changes @@ -32,6 +33,13 @@ API Changes * Removing ``ArmiObject.printDensities()``. * Moving ``Composite.isOnWhichSymmetryLine()`` to ``Assembly``. * Removing ``Block.isOnWhichSymmetryLine()``. +#. Removal of the ``Block.reactor`` property. (`PR#1425 `_) +#. Moving several ``ArmiObject`` methods. (`PR#1425 `_) + * Moving ``ArmiObject.getNeutronEnergyDepositionConstants`` to ``Block``. + * Moving ``ArmiObject.getGammaEnergyDepositionConstants`` to ``Block``. + * Moving ``ArmiObject.getTotalEnergyGenerationConstants`` to ``Block``. + * Moving ``ArmiObject.getFissionEnergyGenerationConstants`` to ``Block``. + * Moving ``ArmiObject.getCaptureEnergyGenerationConstants`` to ``Block``. #. TBD Bug Fixes