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

Providing plugin hook getAxialExpansionChanger #1870

Merged
merged 19 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
bca8a6a
Move expandColdDimsToHot to AxialExpansionChanger classmethod
drewj-tp Sep 9, 2024
c334aca
Add plugin hook getAxialExpansionChanger
drewj-tp Sep 9, 2024
344f5a5
Implement ReactorPlugin.getAxialExpansionChanger hook
drewj-tp Sep 9, 2024
054f6c0
Use getAxialExpanionChanger hook in blueprints construction
drewj-tp Sep 9, 2024
190f815
Remove self from staticmethod hookspec defineSystemBuilders
drewj-tp Sep 9, 2024
57a860b
Add release notes on getAxialExpansionChanger hook
drewj-tp Sep 12, 2024
0416cb7
Add test for axial expansion changer hook
drewj-tp Sep 12, 2024
9dbbca2
Document that one additional plugin per app should implement getAxial…
drewj-tp Sep 17, 2024
c5185af
Apply suggestions from code review
drewj-tp Sep 17, 2024
b1270c9
Add docs and comments for posterity in plugin tests
drewj-tp Sep 17, 2024
b2ff1ee
Merge remote-tracking branch 'refs/remotes/origin/drewj/ax-exp-hook/1…
drewj-tp Sep 17, 2024
bb01240
Remove confusing doc reference to ReactorPlugin in getAxialExpanderHook
drewj-tp Sep 17, 2024
6084c17
Update doc/release/0.4.rst
drewj-tp Sep 17, 2024
896e472
Use getPluginManagerOrFail in blueprints/__init__.py
drewj-tp Sep 17, 2024
86be86c
Allow getAxialExpansionChanger to be None in Blueprints
drewj-tp Sep 17, 2024
042df0e
Update armi/tests/test_plugins.py
john-science Sep 18, 2024
577a91f
Merge branch 'main' into drewj/ax-exp-hook/1843
drewj-tp Sep 18, 2024
4618602
Merge remote-tracking branch 'origin/main' into drewj/ax-exp-hook/1843
drewj-tp Sep 20, 2024
baf1055
Merge remote-tracking branch 'origin/main' into drewj/ax-exp-hook/1843
drewj-tp Sep 24, 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
39 changes: 39 additions & 0 deletions armi/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
# https://coverage.readthedocs.io/en/stable/excluding.html
if TYPE_CHECKING: # pragma: no cover
from armi.reactor.composites import Composite
from armi.reactor.converters.axialExpansionChanger import AxialExpansionChanger


HOOKSPEC = pluggy.HookspecMarker("armi")
Expand Down Expand Up @@ -665,6 +666,44 @@ def defineSystemBuilders() -> Dict[str, Callable[[str], "Composite"]]:
and a ``"sfp"`` lookup, triggered to run after all other hooks have been run.
"""

@staticmethod
@HOOKSPEC(firstresult=True)
def getAxialExpansionChanger() -> type["AxialExpansionChanger"]:
"""Produce the class responsible for performing thermal axial expansion.
drewj-tp marked this conversation as resolved.
Show resolved Hide resolved

Plugins can provide this hook to override or negate axial thermal expansion.
drewj-tp marked this conversation as resolved.
Show resolved Hide resolved
Will be used during initial construction of the core and assemblies, and
can be a standard class for performing all the thermally driven axial
drewj-tp marked this conversation as resolved.
Show resolved Hide resolved
expansion.
drewj-tp marked this conversation as resolved.
Show resolved Hide resolved

The first object returned that is not ``None`` will be used.
Plugins are encouraged to add the ``tryfirst=True`` arguments to their
``HOOKIMPL`` invocations to make sure their specific are earlier in the
hook call sequence. The default reactor plugin
:class:`armi.reactor.ReactorPlugin` is marked ``trylast=True`` to help
put other implementations earlier in the sequence.
albeanth marked this conversation as resolved.
Show resolved Hide resolved

Returns
-------
type of :class:`armi.reactor.converters.axialExpansionChanger.AxialExpansionChanger`

Notes
-----
This hook **should not** provide an instance of the class. The construction
of the changer will be handled by applications and plugins that need it.

Examples
--------
>>> class MyPlugin(ArmiPlugin):
... @staticmethod
... @HOOKIMPL(tryfirst=True)
... def getAxialExpansionChanger():
... from myproject.physics import BespokeAxialExpansion
...
... return BespokeAxialExpansion

"""


class UserPlugin(ArmiPlugin):
"""
Expand Down
13 changes: 10 additions & 3 deletions armi/reactor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,20 @@ def defineAssemblyTypes():

@staticmethod
@plugins.HOOKIMPL(trylast=True)
def defineSystemBuilders() -> Dict[
str, Callable[[str], Union["Core", "SpentFuelPool"]]
]:
def defineSystemBuilders() -> (
Dict[str, Callable[[str], Union["Core", "SpentFuelPool"]]]
):
from armi.reactor.reactors import Core
from armi.reactor.assemblyLists import SpentFuelPool

return {
"core": Core,
"sfp": SpentFuelPool,
}

@staticmethod
@plugins.HOOKIMPL(trylast=True)
def getAxialExpansionChanger():
from armi.reactor.converters.axialExpansionChanger import AxialExpansionChanger

return AxialExpansionChanger
5 changes: 3 additions & 2 deletions armi/reactor/blueprints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def __new__(mcs, name, bases, attrs):
else:
pluginSections = pm.hook.defineBlueprintsSections()
for plug in pluginSections:
for (attrName, section, resolver) in plug:
for attrName, section, resolver in plug:
assert isinstance(section, yamlize.Attribute)
if attrName in attrs:
raise plugins.PluginError(
Expand Down Expand Up @@ -326,7 +326,8 @@ def _prepConstruction(self, cs):
for a in list(self.assemblies.values())
if not any(a.hasFlags(f) for f in assemsToSkip)
)
axialExpansionChanger.axialExpansionChanger.expandColdDimsToHot(
chngrT = getPluginManager().hook.getAxialExpansionChanger()
albeanth marked this conversation as resolved.
Show resolved Hide resolved
drewj-tp marked this conversation as resolved.
Show resolved Hide resolved
chngrT.expandColdDimsToHot(
john-science marked this conversation as resolved.
Show resolved Hide resolved
assemsToExpand,
cs[CONF_DETAILED_AXIAL_EXPANSION],
)
Expand Down
130 changes: 65 additions & 65 deletions armi/reactor/converters/axialExpansionChanger/axialExpansionChanger.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,71 +52,6 @@ def makeAssemsAbleToSnapToUniformMesh(
a.makeAxialSnapList(referenceAssembly)


def expandColdDimsToHot(
assems: list,
isDetailedAxialExpansion: bool,
referenceAssembly=None,
):
"""
Expand BOL assemblies, resolve disjoint axial mesh (if needed), and update block BOL heights.

.. impl:: Perform expansion during core construction based on block heights at a specified temperature.
:id: I_ARMI_INP_COLD_HEIGHT
:implements: R_ARMI_INP_COLD_HEIGHT

This method is designed to be used during core construction to axially thermally expand the
assemblies to their "hot" temperatures (as determined by ``Thot`` values in blueprints).
First, The Assembly is prepared for axial expansion via ``setAssembly``. In
``applyColdHeightMassIncrease``, the number densities on each Component is adjusted to
reflect that Assembly inputs are at cold (i.e., ``Tinput``) temperatures. To expand to
the requested hot temperatures, thermal expansion factors are then computed in
``computeThermalExpansionFactors``. Finally, the Assembly is axially thermally expanded in
``axiallyExpandAssembly``.

If the setting ``detailedAxialExpansion`` is ``False``, then each Assembly gets its Block mesh
set to match that of the "reference" Assembly (see ``getDefaultReferenceAssem`` and ``setBlockMesh``).

Once the Assemblies are axially expanded, the Block BOL heights are updated. To account for the change in
Block volume from axial expansion, ``completeInitialLoading`` is called to update any volume-dependent
Block information.

Parameters
----------
assems: list[:py:class:`Assembly <armi.reactor.assemblies.Assembly>`]
list of assemblies to be thermally expanded
isDetailedAxialExpansion: bool
If False, assemblies will be forced to conform to the reference mesh after expansion
referenceAssembly: :py:class:`Assembly <armi.reactor.assemblies.Assembly>`, optional
Assembly whose mesh other meshes will conform to if isDetailedAxialExpansion is False.
If not provided, will assume the finest mesh assembly which is typically fuel.

Notes
-----
Calling this method will result in an increase in mass via applyColdHeightMassIncrease!

See Also
--------
:py:meth:`armi.reactor.converters.axialExpansionChanger.axialExpansionChanger.AxialExpansionChanger.applyColdHeightMassIncrease`
"""
assems = list(assems)
if not referenceAssembly:
referenceAssembly = getDefaultReferenceAssem(assems)
axialExpChanger = AxialExpansionChanger(isDetailedAxialExpansion)
for a in assems:
axialExpChanger.setAssembly(a, expandFromTinputToThot=True)
axialExpChanger.applyColdHeightMassIncrease()
axialExpChanger.expansionData.computeThermalExpansionFactors()
axialExpChanger.axiallyExpandAssembly()
if not isDetailedAxialExpansion:
for a in assems:
a.setBlockMesh(referenceAssembly.getAxialMesh())
# update block BOL heights to reflect hot heights
for a in assems:
for b in a:
b.p.heightBOL = b.getHeight()
b.completeInitialLoading()


class AxialExpansionChanger:
"""
Axially expand or contract assemblies or an entire core.
Expand Down Expand Up @@ -148,6 +83,71 @@ def __init__(self, detailedAxialExpansion: bool = False):
self.linked = None
self.expansionData = None

@classmethod
def expandColdDimsToHot(
cls,
assems: list,
isDetailedAxialExpansion: bool,
referenceAssembly=None,
):
"""Expand BOL assemblies, resolve disjoint axial mesh (if needed), and update block BOL heights.

.. impl:: Perform expansion during core construction based on block heights at a specified temperature.
:id: I_ARMI_INP_COLD_HEIGHT
:implements: R_ARMI_INP_COLD_HEIGHT

This method is designed to be used during core construction to axially thermally expand the
assemblies to their "hot" temperatures (as determined by ``Thot`` values in blueprints).
First, The Assembly is prepared for axial expansion via ``setAssembly``. In
``applyColdHeightMassIncrease``, the number densities on each Component is adjusted to
reflect that Assembly inputs are at cold (i.e., ``Tinput``) temperatures. To expand to
the requested hot temperatures, thermal expansion factors are then computed in
``computeThermalExpansionFactors``. Finally, the Assembly is axially thermally expanded in
``axiallyExpandAssembly``.

If the setting ``detailedAxialExpansion`` is ``False``, then each Assembly gets its Block mesh
set to match that of the "reference" Assembly (see ``getDefaultReferenceAssem`` and ``setBlockMesh``).

Once the Assemblies are axially expanded, the Block BOL heights are updated. To account for the change in
Block volume from axial expansion, ``completeInitialLoading`` is called to update any volume-dependent
Block information.

Parameters
----------
assems: list[:py:class:`Assembly <armi.reactor.assemblies.Assembly>`]
list of assemblies to be thermally expanded
isDetailedAxialExpansion: bool
If False, assemblies will be forced to conform to the reference mesh after expansion
referenceAssembly: :py:class:`Assembly <armi.reactor.assemblies.Assembly>`, optional
Assembly whose mesh other meshes will conform to if isDetailedAxialExpansion is False.
If not provided, will assume the finest mesh assembly which is typically fuel.

Notes
-----
Calling this method will result in an increase in mass via applyColdHeightMassIncrease!

See Also
--------
:py:meth:`armi.reactor.converters.axialExpansionChanger.axialExpansionChanger.AxialExpansionChanger.applyColdHeightMassIncrease`
"""
assems = list(assems)
if not referenceAssembly:
referenceAssembly = getDefaultReferenceAssem(assems)
axialExpChanger = cls(isDetailedAxialExpansion)
john-science marked this conversation as resolved.
Show resolved Hide resolved
for a in assems:
axialExpChanger.setAssembly(a, expandFromTinputToThot=True)
axialExpChanger.applyColdHeightMassIncrease()
axialExpChanger.expansionData.computeThermalExpansionFactors()
axialExpChanger.axiallyExpandAssembly()
if not isDetailedAxialExpansion:
for a in assems:
a.setBlockMesh(referenceAssembly.getAxialMesh())
# update block BOL heights to reflect hot heights
for a in assems:
for b in a:
b.p.heightBOL = b.getHeight()
b.completeInitialLoading()

def performPrescribedAxialExpansion(
self, a, componentLst: list, percents: list, setFuel=True
):
Expand Down
Loading