Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling axial expansion with detailed depletion #1954

Merged
merged 34 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
833d08a
added `detailedNDens` component parameter
HunterPSmith Sep 25, 2024
66d4cf8
import isNumpyArray
HunterPSmith Sep 26, 2024
be73ee1
Add powerDecay and pdensDecay parameters to component level
HunterPSmith Oct 15, 2024
29f9dfb
update component detailedNDens in lockstep with `changeNDensByFactor`
HunterPSmith Oct 15, 2024
9a1104a
black
HunterPSmith Oct 15, 2024
d440a12
black and typo fix
HunterPSmith Oct 16, 2024
1a2eb98
Revert last three commits
HunterPSmith Oct 21, 2024
ee30c85
move functionality of updating detailedNDens within changeNDensByFact…
HunterPSmith Oct 21, 2024
16a884f
Revert "move functionality of updating detailedNDens within changeNDe…
HunterPSmith Oct 21, 2024
3bb63bf
move functionality of updating detailedNDens within changeNDensByFact…
HunterPSmith Oct 21, 2024
dba4ae6
black
HunterPSmith Oct 21, 2024
93a4fd2
remove old comment
HunterPSmith Oct 22, 2024
59a0d75
move `powerDecay` and `pdensDecay` component parameters (and block `p…
HunterPSmith Oct 24, 2024
c358aa4
add test for detailedNDensity with detailed axial expansion
HunterPSmith Oct 28, 2024
817bbe0
black
HunterPSmith Oct 28, 2024
2eb8f5b
add test for conservation of components when detailedAxialExpansion: …
HunterPSmith Oct 29, 2024
a93fa9d
Merge branch 'main' of https://github.com/terrapower/armi into CDSD-530
HunterPSmith Oct 30, 2024
3e7df65
Merge branch 'main' of https://github.com/terrapower/armi into CDSD-530
HunterPSmith Oct 31, 2024
bfb8766
Merge branch 'main' of https://github.com/terrapower/armi into CDSD-530
HunterPSmith Nov 1, 2024
1bc99ed
update axial expansion test
HunterPSmith Nov 1, 2024
00bdb8d
black and ruff
HunterPSmith Nov 1, 2024
75c70b6
black
HunterPSmith Nov 1, 2024
ccda7db
Update armi/reactor/converters/tests/test_axialExpansionChanger.py
HunterPSmith Nov 1, 2024
751a0c4
add release note
HunterPSmith Nov 1, 2024
9ef9630
Merge branch 'main' of https://github.com/terrapower/armi into CDSD-530
HunterPSmith Nov 1, 2024
221c5b2
Merge branch 'CDSD-530' of https://github.com/terrapower/armi into CD…
HunterPSmith Nov 1, 2024
b193500
changes from review
albeanth Nov 1, 2024
e285bd3
org imports
albeanth Nov 1, 2024
7ec0c9b
added comments
HunterPSmith Nov 1, 2024
39e47d8
ruff
HunterPSmith Nov 1, 2024
7449e7d
linting
HunterPSmith Nov 3, 2024
4e3d6c5
Alphabetizing imports
john-science Nov 4, 2024
99af47c
Merge branch 'main' of https://github.com/terrapower/armi into CDSD-530
HunterPSmith Nov 5, 2024
5894a15
Merge branch 'CDSD-530' of https://github.com/terrapower/armi into CD…
HunterPSmith Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions armi/physics/neutronics/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,8 +655,6 @@ def _getNeutronicsBlockParams():
categories=[parameters.Category.neutronics],
)

pb.defParam("powerDecay", units=units.WATTS, description="Total decay power")
john-science marked this conversation as resolved.
Show resolved Hide resolved

pb.defParam(
"powerGamma",
units=units.WATTS,
Expand Down
21 changes: 18 additions & 3 deletions armi/reactor/components/componentParameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""Component parameter definitions."""
from armi.reactor import parameters
from armi.reactor.parameters import ParamLocation
from armi.reactor.parameters.parameterDefinitions import isNumpyArray
john-science marked this conversation as resolved.
Show resolved Hide resolved
from armi.utils import units


Expand All @@ -35,7 +36,7 @@ def getComponentParameterDefinitions():
pb.defParam(
"mult",
units=units.UNITLESS,
description="The multiplicity of this component, i.e. how many of them there are. ",
description="The multiplicity of this component, i.e. how many of them there are.",
default=1,
)

Expand Down Expand Up @@ -63,6 +64,20 @@ def getComponentParameterDefinitions():
description="Number densities of each nuclide.",
)

pb.defParam(
"detailedNDens",
setter=isNumpyArray("detailedNDens"),
units=f"atoms/(bn*{units.CM})",
description=(
"High-fidelity number density vector with up to thousands of nuclides. "
"Used in high-fi depletion runs where low-fi depletion may also be occurring. "
"This param keeps the hi-fi and low-fi depletion values from interfering. "
"See core.p.detailedNucKeys for keys."
),
saveToDB=True,
default=None,
)

pb.defParam(
"percentBu",
units=f"{units.PERCENT_FIMA}",
Expand Down Expand Up @@ -98,7 +113,7 @@ def getComponentParameterDefinitions():
pb.defParam(
"customIsotopicsName",
units=units.UNITLESS,
description="Label of isotopics applied to this component. ",
description="Label of isotopics applied to this component.",
)

pb.defParam(
Expand All @@ -111,7 +126,7 @@ def getComponentParameterDefinitions():
pb.defParam(
"zrFrac",
units=units.UNITLESS,
description="Original Zr frac of this, used for material properties. ",
description="Original Zr frac of this, used for material properties.",
)

pb.defParam(
Expand Down
3 changes: 3 additions & 0 deletions armi/reactor/composites.py
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,9 @@ def changeNDensByFactor(self, factor):
nuc: val * factor for nuc, val in self.getNumberDensities().items()
}
self.setNumberDensities(densitiesScaled)
# Update detailedNDens
if self.p.detailedNDens is not None:
self.p.detailedNDens *= factor

def clearNumberDensities(self):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,7 @@ def axiallyExpandAssembly(self):
c.zbottom = self.linked.linkedBlocks[b].lower.p.ztop
c.ztop = c.zbottom + c.height
# update component number densities
newNumberDensities = {
nuc: c.getNumberDensity(nuc) / growFrac
for nuc in c.getNuclides()
}
c.setNumberDensities(newNumberDensities)
c.changeNDensByFactor(1.0 / growFrac)
# redistribute block boundaries if on the target component
if self.expansionData.isTargetComponent(c):
b.p.ztop = c.ztop
Expand Down Expand Up @@ -393,7 +389,7 @@ def manageCoreMesh(self, r):
if not self._detailedAxialExpansion:
# loop through again now that the reference is adjusted and adjust the non-fuel assemblies.
for a in r.core.getAssemblies():
a.setBlockMesh(r.core.refAssem.getAxialMesh())
a.setBlockMesh(r.core.refAssem.getAxialMesh(), conserveMassFlag="auto")

oldMesh = r.core.p.axialMesh
r.core.updateAxialMesh()
Expand Down
100 changes: 93 additions & 7 deletions armi/reactor/converters/tests/test_axialExpansionChanger.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""Test axialExpansionChanger."""
import collections
import copy
import os
import unittest
from statistics import mean
Expand All @@ -28,15 +29,15 @@
from armi.reactor.components.basicShapes import Circle, Hexagon, Rectangle
from armi.reactor.components.complexShapes import Helix
from armi.reactor.converters.axialExpansionChanger import (
AxialExpansionChanger,
AssemblyAxialLinkage,
AxialExpansionChanger,
ExpansionData,
getSolidComponents,
iterSolidComponents,
)
from armi.reactor.converters.axialExpansionChanger.assemblyAxialLinkage import (
areAxiallyLinked,
AxialLink,
areAxiallyLinked,
)
from armi.reactor.flags import Flags
from armi.reactor.tests.test_reactors import loadTestReactor, reduceTestReactorRings
Expand Down Expand Up @@ -270,6 +271,7 @@ def test_thermalExpansionContractionConservation_simple(self):
a = buildTestAssemblyWithFakeMaterial(name="HT9")
origMesh = a.getAxialMesh()[:-1]
origMasses, origNDens = self._getComponentMassAndNDens(a)
origDetailedNDens = self._setComponentDetailedNDens(a, origNDens)
axialExpChngr = AxialExpansionChanger(detailedAxialExpansion=True)

tempGrid = linspace(0.0, a.getHeight())
Expand All @@ -284,16 +286,20 @@ def test_thermalExpansionContractionConservation_simple(self):
# Set new isothermal temp and expand
tempField = array([temp] * len(tempGrid))
oldMasses, oldNDens = self._getComponentMassAndNDens(a)
oldDetailedNDens = self._getComponentDetailedNDens(a)
axialExpChngr.performThermalAxialExpansion(a, tempGrid, tempField)
newMasses, newNDens = self._getComponentMassAndNDens(a)
newDetailedNDens = self._getComponentDetailedNDens(a)
self._checkMass(oldMasses, newMasses)
self._checkNDens(oldNDens, newNDens, totGrowthFrac)
self._checkDetailedNDens(oldDetailedNDens, newDetailedNDens, totGrowthFrac)

# make sure that the assembly returned to the original state
for orig, new in zip(origMesh, a.getAxialMesh()):
self.assertAlmostEqual(orig, new, places=12)
self._checkMass(origMasses, newMasses)
self._checkNDens(origNDens, newNDens, 1.0)
self._checkDetailedNDens(origDetailedNDens, newDetailedNDens, 1.0)

def test_thermalExpansionContractionConservation_complex(self):
"""Thermally expand and then contract to ensure original state is recovered.
Expand Down Expand Up @@ -416,6 +422,17 @@ def _checkNDens(self, prevNDen, newNDens, ratio):
if prev:
self.assertAlmostEqual(prev / new, ratio, msg=f"{prev} / {new}")

def _checkDetailedNDens(self, prevDetailedNDen, newDetailedNDens, ratio):
john-science marked this conversation as resolved.
Show resolved Hide resolved
"""Check whether the detailedNDens of two input dictionaries containing the
detailedNDens arrays for all components of an assembly are conserved.
"""
for prevComp, newComp in zip(
prevDetailedNDen.values(), newDetailedNDens.values()
):
for prev, new in zip(prevComp, newComp):
if prev:
self.assertAlmostEqual(prev / new, ratio, msg=f"{prev} / {new}")

@staticmethod
def _getComponentMassAndNDens(a):
masses = {}
Expand All @@ -426,6 +443,30 @@ def _getComponentMassAndNDens(a):
nDens[c] = c.getNumberDensities()
return masses, nDens

@staticmethod
def _setComponentDetailedNDens(a, nDens):
john-science marked this conversation as resolved.
Show resolved Hide resolved
"""Returns a dictionary that contains detailedNDens for all components in an
assembly object input which are set to the corresponding component number densities
from a number density dictionary input.
"""
detailedNDens = {}
for b in a:
for c in getSolidComponents(b):
c.p.detailedNDens = copy.deepcopy([val for val in nDens[c].values()])
detailedNDens[c] = c.p.detailedNDens
return detailedNDens

@staticmethod
def _getComponentDetailedNDens(a):
john-science marked this conversation as resolved.
Show resolved Hide resolved
"""Returns a dictionary containing all solid components and their corresponding
detailedNDens from an assembly object input.
"""
detailedNDens = {}
for b in a:
for c in getSolidComponents(b):
detailedNDens[c] = copy.deepcopy(c.p.detailedNDens)
return detailedNDens

def test_targetComponentMassConservation(self):
"""Tests mass conservation for target components."""
self.expandAssemForMassConservationTest()
Expand Down Expand Up @@ -571,20 +612,65 @@ def setUp(self):
reduceTestReactorRings(self.r, o.cs, 3)

self.oldAxialMesh = self.r.core.p.axialMesh
self.componentLst = []
for b in self.r.core.refAssem:
if b.hasFlags([Flags.FUEL, Flags.PLENUM]):
self.componentLst.extend(getSolidComponents(b))
# expand refAssem by 1.01 L1/L0
componentLst = [c for b in self.r.core.refAssem for c in b]
expansionGrowthFracs = 1.01 + zeros(len(componentLst))
expansionGrowthFracs = 1.01 + zeros(len(self.componentLst))
(
self.origDetailedNDens,
self.origVolumes,
) = self._getComponentDetailedNDensAndVol(self.componentLst)
self.axialExpChngr.performPrescribedAxialExpansion(
self.r.core.refAssem, componentLst, expansionGrowthFracs, setFuel=True
self.r.core.refAssem, self.componentLst, expansionGrowthFracs, setFuel=True
)

def test_manageCoreMesh(self):
self.axialExpChngr.manageCoreMesh(self.r)
newAxialMesh = self.r.core.p.axialMesh
# skip first and last entries as they do not change
for old, new in zip(self.oldAxialMesh[1:-1], newAxialMesh[1:-1]):
# the top and bottom and top of the grid plate block are not expected to change
for old, new in zip(self.oldAxialMesh[2:-1], newAxialMesh[2:-1]):
self.assertLess(old, new)

def test_componentConservation(self):
self.axialExpChngr.manageCoreMesh(self.r)
newDetailedNDens, newVolumes = self._getComponentDetailedNDensAndVol(
self.componentLst
)
for c in newVolumes.keys():
self._checkMass(
self.origDetailedNDens[c],
self.origVolumes[c],
newDetailedNDens[c],
newVolumes[c],
c,
)

def _getComponentDetailedNDensAndVol(self, componentLst):
john-science marked this conversation as resolved.
Show resolved Hide resolved
"""Returns a tuple containing dictionaries of detailedNDens and volumes of
all components from a component list input.
"""
detailedNDens = {}
volumes = {}
for c in componentLst:
c.p.detailedNDens = [val for val in c.getNumberDensities().values()]
detailedNDens[c] = copy.deepcopy(c.p.detailedNDens)
volumes[c] = c.getVolume()
return (detailedNDens, volumes)

def _checkMass(self, origDetailedNDens, origVolume, newDetailedNDens, newVolume, c):
for prevMass, newMass in zip(
origDetailedNDens * origVolume, newDetailedNDens * newVolume
):
if c.parent.hasFlags(Flags.FUEL):
self.assertAlmostEqual(
prevMass, newMass, delta=1e-12, msg=f"{c}, {c.parent}"
)
else:
# should not conserve mass here as it is structural material above active fuel
self.assertAlmostEqual(newMass / prevMass, 0.99, msg=f"{c}, {c.parent}")


class TestExceptions(AxialExpansionTestBase, unittest.TestCase):
"""Verify exceptions are caught."""
Expand Down
2 changes: 2 additions & 0 deletions armi/reactor/tests/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,11 @@ def test_getNumberDensities(self):
def test_changeNumberDensities(self):
"""Test that demonstates that the number densities on a component can be modified."""
self.component.p.numberDensities = {"NA23": 1.0}
self.component.p.detailedNDens = [1.0]
self.assertEqual(self.component.getNumberDensity("NA23"), 1.0)
self.component.changeNDensByFactor(3.0)
self.assertEqual(self.component.getNumberDensity("NA23"), 3.0)
self.assertEqual(self.component.p.detailedNDens[0], 3.0)

def test_fuelMass(self):
nominalMass = self.component.getMass()
Expand Down
1 change: 1 addition & 0 deletions doc/release/0.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ New Features
#. Improve efficiency of reaction rate calculations. (`PR#1887 <https://github.com/terrapower/armi/pull/1887>`_)
#. Adding new options for simplifying 1D cross section modeling. (`PR#1949 <https://github.com/terrapower/armi/pull/1949>`_)
#. Updating ``copyOrWarn`` and ``getFileSHA1Hash`` to support directories. (`PR#1984 <https://github.com/terrapower/armi/pull/1984>`_)
#. Exposing ``detailedNDens`` to components. (`PR#1954 <https://github.com/terrapower/armi/pull/1954>`_)
#. TBD

API Changes
Expand Down
Loading