Skip to content

Commit

Permalink
Update b.p.heightBOL in Core::processLoading for thermal expansio…
Browse files Browse the repository at this point in the history
…n at BOL (#823)

* add update BOL heights when therm exp to Thot

* add test (WIP)

- needs assertion(s) and completion...

* expand blueprints assems at BOL

- needs testing + code cleanup/optimization

* correcting block BOL height update

- was incorrect before to use `self.getAssemblies()`. To support both dbload: True/False, should pass in the specific list of assemblies that were expanded.
- also making it a protected method.

* reorg axialExpChngr for dbload

Summary:
1. updateBlockBOLHeights doesn't need core mesh params updated on dbload
2. manageCoreMesh should not be called for dbload.
    - setBlockMesh for assems will get set when assemblies are created from the blueprints in Core::createAsssemblyOfType

* code clean up/reorg, fix dbLoad case

- manageCoreMesh should not be called during a dbLoad. rather, the blueprints assems are expanded, block BOL heights updated, and then have their block mesh set to the refAssem.getAxialMesh() on the existing r.core.
- The last part may not be needed, as setBlockMesh is called with createAssemblyOfType, but it's cheap to add and won't hurt anything.

* code cleanup + address comments

Comments addressed:
- https://github.com/terrapower/armi/pull/823/files#r939442958
- https://github.com/terrapower/armi/pull/823/files#r941630224
- https://github.com/terrapower/armi/pull/823/files#r939445205
- https://github.com/terrapower/armi/pull/823/files#r939443611

* fix order for updateBlocKBOLHeights with dbload

- if doing a dbLoad and detailedAxialExpansion: False, then setBlockMesh needs to be called after the BOL block heights are updated
- addresses comment  #823 (comment)

* creating test for Core::_updateBlockBOLHeights

* Update release notes.

* remove detAxExp from arg list, simplify logic

Addresses the following comments from review:
- https://github.com/terrapower/armi/pull/823/files#r942921304
- https://github.com/terrapower/armi/pull/823/files#r942926277

* initially set blueprints assems to hot height

Addresses comment here
- #823 (comment)

- Blueprints assems should be at hot height only. When created and placed into the core then they'll be set to the current core height (possibly thermal + irradiation expansion).

* simplify setting core axial mesh params

- Instead of doing twice (once at the onset and another if the block heights are updated), just do once at the end. This is simpler, cleaner, and easier to maintain.
- a ramification is that the runLog.extra statement in manageCoreMesh will not be printed during Core construction
- Addresses this comment #823 (comment)

* code cleanup and method rename for processLoading

- Also updating test_updateBlockBOLHeights to improve code coverage
- Fixing Tinput for fuel component in block_fuel3 in armi/tests test reactor.

* bug fix in _applyThermalExpansion for dbLoad

and reformat unit test to catch bug. And is simpler than before.
- The bug: by passing in the finestAssemblyMesh.getAxialMesh() before the expansion happened, we were snapping the expanded meshes back to the non-expanded mesh and in turn, undoing the expansion... This isn't what we want. So this commit fixes that.

* revert blueprints back to original state
  • Loading branch information
albeanth committed Aug 12, 2022
1 parent aa2d373 commit e1e7e3d
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 19 deletions.
9 changes: 6 additions & 3 deletions armi/reactor/converters/axialExpansionChanger.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ def manageCoreMesh(self, r):
-----
- if no detailedAxialExpansion, then do "cheap" approach to uniformMesh converter.
- update average core mesh values with call to r.core.updateAxialMesh()
- oldMesh will be None during initial core construction at processLoading as it has not yet
been set.
"""
if not self._detailedAxialExpansion:
# loop through again now that the reference is adjusted and adjust the non-fuel assemblies.
Expand All @@ -258,9 +260,10 @@ def manageCoreMesh(self, r):

oldMesh = r.core.p.axialMesh
r.core.updateAxialMesh()
runLog.extra("Updated r.core.p.axialMesh (old, new)")
for old, new in zip(oldMesh, r.core.p.axialMesh):
runLog.extra(f"{old:.6e}\t{new:.6e}")
if oldMesh:
runLog.extra("Updated r.core.p.axialMesh (old, new)")
for old, new in zip(oldMesh, r.core.p.axialMesh):
runLog.extra(f"{old:.6e}\t{new:.6e}")


def _conserveComponentMass(b, oldHeight, oldVolume):
Expand Down
69 changes: 53 additions & 16 deletions armi/reactor/reactors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2261,41 +2261,44 @@ def processLoading(self, cs, dbLoad: bool = False):
if not cs["detailedAxialExpansion"]:
# Apply mesh snapping for self.parent.blueprints.assemblies
# This is stored as a param for assemblies in-core, so only blueprints assemblies are
# considereed here. To guarantee mesh snapping will function, makeAxialSnapList
# considered here. To guarantee mesh snapping will function, makeAxialSnapList
# should be in reference to the assembly with the finest mesh as defined in the blueprints.
finestAssemblyMesh = sorted(
finestMeshAssembly = sorted(
self.parent.blueprints.assemblies.values(),
key=lambda a: len(a),
reverse=True,
)[0]
for a in self.parent.blueprints.assemblies.values():
if a.hasFlags(nonUniformAssems, exact=True):
continue
a.makeAxialSnapList(refAssem=finestAssemblyMesh)
a.makeAxialSnapList(refAssem=finestMeshAssembly)
if not cs["inputHeightsConsideredHot"]:
runLog.header(
"=========== Axially expanding blueprints assemblies (except control) from Tinput to Thot ==========="
)
self._applyThermalExpansion(
self.parent.blueprints.assemblies.values(),
dbLoad,
finestMeshAssembly,
)

else:
self.p.referenceBlockAxialMesh = self.findAllAxialMeshPoints(
applySubMesh=False
)
self.p.axialMesh = self.findAllAxialMeshPoints()
if not cs["detailedAxialExpansion"]:
# prepare core for mesh snapping during axial expansion
for a in self.getAssemblies(includeAll=True):
if a.hasFlags(nonUniformAssems, exact=True):
continue
a.makeAxialSnapList(self.refAssem)

if not cs["inputHeightsConsideredHot"]:
runLog.header(
"=========== Axially expanding all (except control) assemblies from Tinput to Thot ==========="
"=========== Axially expanding all assemblies (except control) from Tinput to Thot ==========="
)
axialExpChngr = AxialExpansionChanger(cs["detailedAxialExpansion"])
for a in self.getAssemblies():
if not a.hasFlags(Flags.CONTROL):
axialExpChngr.setAssembly(a)
axialExpChngr.expansionData.computeThermalExpansionFactors()
axialExpChngr.axiallyExpandAssembly(thermal=True)
axialExpChngr.manageCoreMesh(self.parent)
self._applyThermalExpansion(self.getAssemblies(includeAll=True), dbLoad)

self.p.referenceBlockAxialMesh = self.findAllAxialMeshPoints(
applySubMesh=False
)
self.p.axialMesh = self.findAllAxialMeshPoints()

self.numRings = self.getNumRings() # TODO: why needed?

Expand All @@ -2315,3 +2318,37 @@ def processLoading(self, cs, dbLoad: bool = False):
self.p.maxAssemNum = self.getMaxParam("assemNum")

getPluginManagerOrFail().hook.onProcessCoreLoading(core=self, cs=cs)

def _applyThermalExpansion(
self, assems: list, dbLoad: bool, referenceAssembly=None
):
"""expand assemblies, resolve disjoint axial mesh (if needed), and update block BOL heights
Parameters
----------
assems: list
list of :py:class:`Assembly <armi.reactor.assemblies.Assembly>` objects to be thermally expanded
dbLoad: bool
boolean to determine if Core::processLoading is loading a database or constructing a Core
referenceAssembly: optional, :py:class:`Assembly <armi.reactor.assemblies.Assembly>`
is the thermally expanded assembly whose axial mesh is used to snap the
blueprints assemblies axial mesh to
"""
axialExpChngr = AxialExpansionChanger(self._detailedAxialExpansion)
for a in assems:
if not a.hasFlags(Flags.CONTROL):
axialExpChngr.setAssembly(a)
axialExpChngr.expansionData.computeThermalExpansionFactors()
axialExpChngr.axiallyExpandAssembly(thermal=True)
# resolve axially disjoint mesh (if needed)
if not dbLoad:
axialExpChngr.manageCoreMesh(self.parent)
elif not self._detailedAxialExpansion:
for a in assems:
if not a.hasFlags(Flags.CONTROL):
a.setBlockMesh(referenceAssembly.getAxialMesh())
# update block BOL heights to reflect hot heights
for a in assems:
if not a.hasFlags(Flags.CONTROL):
for b in a:
b.p.heightBOL = b.getHeight()
52 changes: 52 additions & 0 deletions armi/reactor/tests/test_reactors.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,58 @@ def test_pinCoordsAllBlocks(self):
coords = b.getPinCoordinates()
self.assertGreater(len(coords), -1)

def test_applyThermalExpansion_CoreConstruct(self):
"""test Core::_applyThermalExpansion for core construction
Notes:
------
- all assertions skip the first block as it has no $\Delta T$ and does not expand
- to maintain code coverage, _applyThermalExpansion is called via processLoading
"""
self.o.cs["inputHeightsConsideredHot"] = False
assemsToChange = self.r.core.getAssemblies()
# stash original axial mesh info
oldRefBlockAxialMesh = self.r.core.p.referenceBlockAxialMesh
oldAxialMesh = self.r.core.p.axialMesh
oldBlockBOLHeights = {}
for a in assemsToChange:
for b in a[1:]:
oldBlockBOLHeights[b] = b.p.heightBOL
self.r.core.processLoading(self.o.cs, dbLoad=False)
for i, val in enumerate(oldRefBlockAxialMesh[1:]):
self.assertNotEqual(val, self.r.core.p.referenceBlockAxialMesh[i])
for i, val in enumerate(oldAxialMesh[1:]):
self.assertNotEqual(val, self.r.core.p.axialMesh[i])
for a in assemsToChange:
if not a.hasFlags(Flags.CONTROL):
for b in a[1:]:
self.assertNotEqual(oldBlockBOLHeights[b], b.p.heightBOL)

def test_updateBlockBOLHeights_DBLoad(self):
"""test Core::_applyThermalExpansion for db load
Notes:
------
- all assertions skip the first block as it has no $\Delta T$ and does not expand
- to maintain code coverage, _applyThermalExpansion is called via processLoading
"""
self.o.cs["inputHeightsConsideredHot"] = False
# stash original blueprint assemblies axial mesh info
oldBlockBOLHeights = {}
assemsToChange = [a for a in self.r.blueprints.assemblies.values()]
for a in assemsToChange:
for b in a[1:]:
oldBlockBOLHeights[b] = b.p.heightBOL
self.r.core.processLoading(self.o.cs, dbLoad=True)
for a in assemsToChange:
if not a.hasFlags(Flags.CONTROL):
for b in a[1:]:
self.assertNotEqual(
oldBlockBOLHeights[b],
b.p.heightBOL,
msg="{0}, {1}".format(a, b),
)

def test_nonUniformAssems(self):
o, r = loadTestReactor(
customSettings={"nonUniformAssemFlags": ["primary control"]}
Expand Down
1 change: 1 addition & 0 deletions doc/release/0.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Bug fixes
#. Bug fix and clarity improvements for how number densities are initialized for components.
#. Bug fix in ``armi/cases/case.py::copyInterfaceInputs``
#. Bug fix in ``armi/reactor/components/component.py::getReac``
#. Store thermally expanded block heights at BOL (via ``b.p.heightBOL``) when thermally expanding assemblies in ``armi/reactor/reactors.py::Core::processLoading``.
#. TBD


Expand Down

0 comments on commit e1e7e3d

Please sign in to comment.