Skip to content

Commit

Permalink
Merge ec76374 into b9eb9ca
Browse files Browse the repository at this point in the history
  • Loading branch information
drewj-usnctech authored Apr 20, 2022
2 parents b9eb9ca + ec76374 commit 4cff7ff
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 21 deletions.
39 changes: 38 additions & 1 deletion armi/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,19 @@
user settings. This also predated the plugin infrastructure, and may one day be
replaced with plugin-based fuel handler logic.
"""
from typing import Dict, Union
from typing import Dict, Union, Callable, TYPE_CHECKING

import pluggy

from armi import pluginManager
from armi.utils import flags

# Not used during runtime so we could have a coverage drop here. Add the
# pragma line to tell coverage.py to skip this
# https://coverage.readthedocs.io/en/stable/excluding.html
if TYPE_CHECKING: # pragma: no cover
from armi.reactor.composites import Composite


HOOKSPEC = pluggy.HookspecMarker("armi")
HOOKIMPL = pluggy.HookimplMarker("armi")
Expand Down Expand Up @@ -562,6 +568,37 @@ def getReportContents(r, cs, report, stage, blueprint) -> None:
for a reactor (if None, only partial contents created)
"""

@staticmethod
@HOOKSPEC
def defineSystemBuilders() -> Dict[str, Callable[[str], "Composite"]]:
"""
Convert a user-string from the systems section into a valid composite builder
Parameters
----------
name : str
Name of the system type defined by the user, e.g., ``"core"``
Returns
-------
dict
Dictionary that maps a grid type from the input file (e.g., ``"core"``)
to a function responsible for building a grid of that type, e.g.,
.. code::
{
"core": armi.reactor.reactors.Core,
"sfp": armi.reactor.assemblyLists.SpentFuelPool,
}
Notes
-----
The default :class:`~armi.reactor.ReactorPlugin` defines a ``"core"`` lookup
and a ``"sfp"`` lookup, triggered to run after all other hooks have been run.
"""


def getNewPluginManager() -> pluginManager.ArmiPluginManager:
"""
Expand Down
23 changes: 23 additions & 0 deletions armi/reactor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,18 @@
See :doc:`/developer/index`.
"""

from typing import Dict, Callable, Union, TYPE_CHECKING

from armi import plugins

# Provide type checking but avoid circular imports
# Not used during runtime so we could have a coverage drop here. Add the
# pragma line to tell coverage.py to skip this
# https://coverage.readthedocs.io/en/stable/excluding.html
if TYPE_CHECKING: # pragma: no cover
from armi.reactor.reactors import Core
from armi.reactor.assemblyLists import SpentFuelPool


class ReactorPlugin(plugins.ArmiPlugin):
"""
Expand Down Expand Up @@ -66,3 +76,16 @@ def defineAssemblyTypes():
(CartesianBlock, CartesianAssembly),
(ThRZBlock, ThRZAssembly),
]

@staticmethod
@plugins.HOOKIMPL(trylast=True)
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,
}
2 changes: 1 addition & 1 deletion armi/reactor/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def r(self):

core = self.core
if core is None:
return None
return self.getAncestor(lambda o: isinstance(o, Reactor))

if not isinstance(core.parent, Reactor):
raise TypeError(
Expand Down
43 changes: 24 additions & 19 deletions armi/reactor/blueprints/reactorBlueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import tabulate
import yamlize

from armi import getPluginManagerOrFail
from armi import context
from armi import runLog
from armi.reactor import geometry
Expand Down Expand Up @@ -74,25 +75,29 @@ def __init__(self, name=None, gridName=None, origin=None):

@staticmethod
def _resolveSystemType(typ: str):
# avoid circular import, though ideally reactors shouldnt depend on blueprints!
from armi.reactor import reactors
from armi.reactor import assemblyLists

# TODO: This is far from the the perfect place for this; most likely plugins
# will need to be able to extend it. Also, the concept of "system" will need to
# be well-defined, and most systems will probably need their own, rather
# dissimilar Blueprints. We may need to break with yamlize unfortunately.
_map = {"core": reactors.Core, "sfp": assemblyLists.SpentFuelPool}

try:
cls = _map[typ]
except KeyError:
raise ValueError(
"Could not determine an appropriate class for handling a "
"system of type `{}`. Supported types are {}.".format(typ, _map.keys())
)

return cls
# Loop over all plugins that could be attached and determine if any
# tell us how to build a specific systems attribute. Sub-optimial
# as this check is called for each system (e.g., core, spent fuel pool).
# It is assumed that the number of systems is currently low enough to justify
# this structure.

manager = getPluginManagerOrFail()

# Only need this to handle the case we don't find the system we expect
seen = set()
for options in manager.hook.defineSystemBuilders():
for key, builder in options.items():
# Take the first match we find. This would allow other plugins to
# define a new core builder before finding those defined by the
# ReactorPlugin
if key == typ:
return builder
seen.add(key)

raise ValueError(
"Could not determine an appropriate class for handling a "
"system of type `{}`. Supported types are {}.".format(typ, sorted(seen))
)

def construct(self, cs, bp, reactor, geom=None):
"""Build a core/IVS/EVST/whatever and fill it with children."""
Expand Down
18 changes: 18 additions & 0 deletions doc/user/inputs/blueprints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,24 @@ The ``origin`` defines the point of origin in global space
in units of cm. This allows you to define the relative position of the various structures.
The ``grid name`` inputs are string mappings to the grid definitions described below.

Plugin Behavior
---------------

The :meth:`armi.plugins.ArmiPlugin.defineSystemBuilders` method can be provided
by plugins to control how ARMI converts the ``systems`` section into ``Composite``\ s
to be modeled. By default, the ``type`` field is used to determine what object is created.
The default :class:`armi.reactor.ReactorPlugin` provides the following mapping:

================== ==================================================
``type`` Value Builds
================== ==================================================
``core`` (default) :class:`~armi.reactor.reactors.Core`
``sfp`` :class:`~armi.reactor.assemblyLists.SpentFuelPool`
================== ==================================================

Plugins are able to provide a superset (e.g., include ``core`` and ``sfp``)
and new mappings of values to builders.

.. _grids:

Grids
Expand Down

0 comments on commit 4cff7ff

Please sign in to comment.