2. Software Design and Implementation Document (SDID)
2.1. Purpose and Scope
This document is the Software Design and Implementation Document (SDID) for ARMI.
The purpose of this document is to define how the ARMI requirements are implemented. These are important user stories for anyone wanting to use ARMI or develop their own ARMI-based application. The implementation of the ARMI requirements is described in detail in an Implementation Traceability Matrix (ITM).
2.1.1. Procedural Compliance
This document includes information on four topics: the (1) software environment, (2) measures to mitigate possible failures, (2) implementation of the computational sequence, and (4) technical adequacy.
2.1.2. Software Environment
ARMI is built using the Python programming language and runs on Windows and Linux operating systems.
2.1.3. Failure Mitigation
ARMI provides a suite of unit tests which provide indication of the proper usage of the program. These tests are described in the software test report and are directly traceable to the requirements in the software requirements specification document. The purpose of these tests is to provide a way for downstream users to test and measure the utility of the ARMI framework for their own purposes, in their own environment. This allows users and developers to perform failure analysis. These tests allow for a push-button way to measure and mitigate consequences and problems including external and internal abnormal conditions and events that can affect the software.
2.1.4. Implementation of Computational Sequence
The computational sequence and relevant portions of the technical adequacy are specific to the implementation and are described for each implementation in the Implementation Traceability Matrix.
2.1.5. Technical Adequacy
The internal completeness for each implementation is shown by providing traceability to the requirements as showing in the Implementation Traceability Matrix. The consistency of the implementation is provided by a best practice used by the development team including, revision control, ensuring that code content is reviewed by non-code originating team members, and ensuring training for developers. Clarity is provided by the descriptions of the implementations in the Implementation Traceability Matrix. Figures are added as needed in the implementation in the Implementation Traceability Matrix.
2.2. Design and Implementation
To automate the process of tracking the implementation of all requirements in ARMI, we are using the Implementation Traceability Matrix below. This will connect high-quality, in-code documentation with each requirement in a complete way. However, before giving a complete overview of the requirement implementations, this document will describe the design of two main features in the ARMI codebase: the plugin system and the reactor data model. These are the two major features which you need to understand to understand what ARMI is, and why it is useful. So, at the risk of duplicating documentation, the design of these two features will be discussed in some detail.
2.2.1. Implementation of Plugin System
The first important design idea to understand in ARMI is that ARMI is a framework for nuclear reactor modeling. What this means is that the science or engineering calculations for nuclear reactor modeling do not happen in ARMI. The point of ARMI is to tie together disparate nuclear modeling softwares that already exist. Thus, ARMI must be able to wrap external codes, and orchestrate running them at each time step we want to model.
The second design idea is that at each time step, there is an ordered list of conceptual reactor
modeling steps to be executed. ARMI calls these steps
Interfaces
and runs the code in each, in order, at each time
step. While ARMI does have a default list of modeling steps, and a default order, none of the steps
are mandatory, and their order is modifiable. An example interface stack would be:
preprocessing
fuel management
depletion
fuel performance
cross sections
critical control
flux
thermal hydraulics
reactivity coefficients
transient
bookkeeping
postprocessing
So, how do we add Interfaces to the simulation? The third major design idea is that developers can
create an ARMI Plugin
, which can add one or more Interfaces to
the simulation.
Lastly, at the highest level of the design, a developer can create an ARMI
Application
. This is a flexible container that allows developers to
register multiple Plugins, which register multiple Interfaces, which fully define all the code that
will be run at each time step of the simulation.
Below is a diagram from an example ARMI Application. Following this design, in the real world you would expect an ARMI Application to be made by various teams of scientists and engineers that define one Plugin and a small number of Interfaces. Then a simulation of the reactor would be carried out over some number of cycles / time nodes, where each of the Interfaces would be run in a specified order at each time node.

An example ARMI Application.
If this high-level design seems abstract, that is by design. ARMI is not concerned with implementing scientific codes, or enforcing nuclear modelers do things a certain way. ARMI is a tool that aims to support a wide audience of nuclear reactor modelers.
2.2.2. Implementation of Reactor Data Model
In the previous section, we described how an ARMI Application is put together. But that Application is only useful if it can pass information about the reactor between all the external codes that are being wrapped by each Interface. Thus, an important part of the ARMI design is that is has a robust and detailed software data model to represent the current state of the reactor. This data model can be queried and manipulated by each Interface to get data that is needed to run the external reactor modeling codes.
The structure of the ARMI reactor data model is designed to be quite flexible, and heavily modifiable in code. But most of the practical work done with ARMI so far has been on pin-type reactor cores, so we will focus on such an example.
At the largest scale, the Reactor
contains a
Core
and a
Spent Fuel Pool
. The Core is made primarily
of a collection of Assemblies
, which are vertical
collections of Blocks
. Each Block, and every other physical
piece of the Reactor is a Composite
. Composites have
a defined shape, material(s), location in space, and parent. Composites have parents because ARMI
defines all Reactors as a hierarchical model, where outer objects contain inner children, and the
Reactor is the outermost object. The important thing about this model is that it is in code, so
developers of ARMI Interfaces can query and modify the reactor data model in any way they need.

Structure of the ARMI reactor data model.
2.2.3. Hardware/OS Compatibility
ARMI is a Python-based framework, designed to help tie together various nuclear models, all written in a variety of languages. ARMI officially supports Python versions 3.9 and higher. ARMI is also designed to work on modern versions of both Windows and Linux.
The memory, CPU, and hardware needs of an ARMI simulation depend on the Reactor. Simulations run with lumped fission products will require more memory than those run without. Simulations with much larger, more detailed reactor core blueprints, or containing more components, will take up more memory than simpler blueprints. ARMI can also be run with only one process, but most users choose to run ARMI in parallel on a computing cluster of some kind. In practice, users tend to find that dozens or hundreds of parallel processes are helpful for speeding up ARMI runs, and each process will ideally have 1 or 2 GB of RAM.
2.2.4. Error/Input Handling
ARMI’s internal error-handling library is the runLog
. This tool handles the
warnings and errors for internal ARMI code and all the plugins. The runLog
system will handle
both print-to-screen and log file messages. At the end of the run, all log messages from every
plugin and from all parallel processes are tabulated into centralized log files.
The runLog
system will also tabulate a list of all warnings that occurred doing a simulation.
And it should be noted that most full “errors” will cause the ARMI simulation to fail and stop hard,
ending the run early. This is the ideal solution, so people know the run results are invalid. To
that affect, ARMI makes use of Python’s robust Exception system.
2.2.5. Implementation Traceability Matrix
The requirements and associated tests which demonstrate acceptance of the codebase with the requirements are in the Software Requirements Specification Document (SRSD). This section contains a list of all requirement implementations.
Here are some quick metrics for the requirement implementations in ARMI:
140 Accepted Requirements in ARMI
138 Accepted Requirements with implementations
190 implementations linked to Requirements
And here is a full listing of all the requirement implementations in ARMI, that are tied to requirements:
This method initializes an ARMI run, and if successful returns an Operator. That operator is designed to drive the reactor simulation through time steps to simulate its operation. This method takes in a settings file or object to initialize the operator. Whether a settings file or object is supplied, the operator will be built based on the those settings. Because the total collection of settings can be modified by developers of ARMI applications, providing these settings allow ARMI end-users to define their simulation as granularly as they need. |
The App class is intended to be subclassed in order to customize the functionality
and look-and-feel of the ARMI Framework for a specific use case. An App contains a
plugin manager, which should be populated in The base App class is also a good place to expose some more convenient ways to get
data out of the Plugin API; calling the |
This class implements a light wrapper around H5 files, so they can be used to
store ARMI outputs. H5 files are commonly used in scientific applications in
Fortran and C++. As such, they are entirely language agnostic binary files. The
implementation here is that ARMI wraps the |
This method writes some basic system information to the H5 file. This is
designed as a starting point, so users can see information about the system
their simulations were run on. As ARMI is used on Windows and Linux, the
tooling here has to be platform independent. The two major sources of
information are the ARMI |
A |
A |
This method creates a |
Implementation: Runs at a particular timenode can be re-instantiated for a snapshot. I_ARMI_SNAPSHOT_RESTART
|
This method loads the state of a reactor from a particular point in time
from a standard ARMI
* reloadDBName - Path to existing H5 file to reload from.
* startCycle - Operational cycle to restart from.
* startNode - Time node to start from.
|
This method writes a snapshot of the current state of the reactor to the
database. It takes a pointer to an existing HDF5 file as input, and it
writes the reactor data model to the file in depth-first search order.
Other than this search order, there are no guarantees as to what order the
objects are written to the file. Though, this turns out to still be very
powerful. For instance, the data for all |
Implementation: This interface allows users to retrieve run data from somewhere other
than the database. I_ARMI_HIST_TRACK
|
This is a special |
This is a special |
This method is responsible for "running" the ARMI simulation
instigated by the inputted settings. This initializes an
|
This method checks the validity of the current settings. It relies
on an |
This class serves as an abstract base class for modifying the inputs of
a case, typically case settings. Child classes must implement a
|
The CaseSuite object allows multiple, often related,
|
This class provides the capability to create a
|
Provides a basic command-line interface (CLI) for running an ARMI simulation. Available
commands can be listed with |
Provides a base class for plugin developers to use in creating application-specific CLIs.
Valid subclasses must at least provide a Optional class attributes that a subclass may provide include |
At each time node during a simulation, an ordered colletion of Interfaces are run (referred to as the interface stack). But ARMI does not force the order upon the analyst. Instead, each Interface registers where in that ordered list it belongs by giving itself an order number (which can be an integer or a decimal). This class defines a set of constants which can be imported and used by Interface developers to define that Interface's position in the stack. The constants defined are given names, based on common stack orderings in the ARMI ecosystem. But in the end, these are just constant values, and the names they are given are merely suggestions. |
Implementation: The TightCoupler defines the convergence criteria for physics coupling. I_ARMI_OPERATOR_PHYSICS0
|
During a simulation, the developers of an ARMI application frequently want to iterate on some physical calculation until that calculation has converged to within some small tolerance. This is typically done to solve the nonlinear dependence of different physical properties of the reactor, like fuel performance. However, what parameter is being tightly coupled is configurable by the developer. This class provides a way to calculate if a single parameter has converged
based on some convergence tolerance. The user provides the parameter,
tolerance, and a maximum number of iterations to define a basic convergence
calculation. If in the |
Implementation: The interface shall allow code execution at important operational points in time. I_ARMI_INTERFACE
|
The Interface class defines a number methods with names like The end goal of all this work is to allow the Plugins to carefully tune when and how they interact with the reactor data model. Interface instances are gathered into an interface stack in
|
Implementation: Material collections are defined with an order of precedence in the case
of duplicates. I_ARMI_MAT_ORDER
|
An ARMI application will need materials. Materials can be imported from any code the application has access to, like plugin packages. This leads to the situation where one ARMI application will want to import multiple collections of materials. To handle this, ARMI keeps a list of material namespaces. This is an ordered list of importable packages that ARMI can search for a particular material by name. This automatic exploration of an importable package saves the user the tedium have having to import or include hundreds of materials manually somehow. But it comes with a caveat; the list is ordered. If two different namespaces in the list include a material with the same name, the first one found in the list is chosen, i.e. earlier namespaces in the list have precedence. |
Implementation: Materials can be searched across packages in a defined namespace. I_ARMI_MAT_NAMESPACE
|
During the runtime of an ARMI application, but particularly during the construction of the reactor in memory, materials will be requested by name. At that point, this code is called to search for that material name. The search goes through the ordered list of Python namespaces provided. The first time an instance of that material is found, it is returned. In this way, the first items in the material namespace list take precedence. When a material name is passed to this function, it may be either a simple
name like the string |
The ARMI Materials library is based on the Object-Oriented Programming design approach, and
uses this generic |
An ARMI material is meant to be able to represent real world materials that might be used in the construction of a nuclear reactor. As such, they are not just individual nuclides, but practical materials like a particular concrete, steel, or water. One of the main things that will be needed to describe such a material is the exact nuclide fractions. As such, the constructor of every Material subclass attempts to set these mass fractions. |
ARMI does not model thermal expansion of fluids. The |
Implementation: A tool for querying basic data for elements of the periodic table. I_ARMI_ND_ELEMENTS0
|
The |
The The |
Implementation: Isotopes and isomers can be queried by name, label, MC2-3 ID, MCNP ID, and AAAZZZS ID. I_ARMI_ND_ISOTOPES0
|
The The The
|
The |
This method returns the |
This method returns the |
This method returns the |
This method generates the MCNP ID for an isotope using the standard MCNP format based on the atomic number A, number of protons Z, and excited state. The implementation includes the special rule for Am-242m, which is 95242. 95642 is used for the less common ground state Am-242. |
This method generates the AAAZZZS format ID for an isotope. Where AAA is the mass number, ZZZ is the atomic number, and S is the isomeric state. This is a general format independent of any code that precisely defines an isotope or isomer. |
This function reads the |
This function reads the mcc-nuclides.yaml file from the ARMI resources
folder. This file contains the MC2-2 ID (from ENDF/B-V.2) and MC2-3 ID
(from ENDF/B-VII.0) for all nuclides in MC2. The |
This function updates the keys for the |
Implementation: Generic tool for reading and writing Committee on Computer Code Coordination (CCCC) format
files for reactor physics codes I_ARMI_NUCDATA
|
This module provides a number of base classes that implement general capabilities for binary and
ASCII file I/O. The These For the CCCC file types that are outputs from a flux solver such as DIF3D (e.g., GEODST, DIF3D,
NHFLUX) the streams are subclassed from The data container structure for each type of CCCC file is implemented in the module for that
file, as a subclass of The logic to parse or write each specific file format is contained within the
|
The reading and writing of the DIF3D binary file is performed using
Each record is also embedded with the record size at the beginning and end of the record (always assumed to be present), which is used for error checking at the end of processing each record. The DIF3D reader processes the file identification record (stored as
the attribute This class can also read and write an ASCII version of the DIF3D file. While this format is not used by the DIF3D software, it can be a useful representation for users to access the file in a human-readable format. |
Reading and writing DLAYXS delayed neutron data files is performed using the general nuclear data I/O functionalities described in I_ARMI_NUCDATA. Reading/writing a DLAYXS file is performed through the following steps:
|
The majority of the functionality in this module is inherited from the
|
Reading and writing GEODST files is performed using the general nuclear data I/O functionalities described in I_ARMI_NUCDATA. Reading/writing a GEODST file is performed through the following steps:
|
Reading and writing ISOTXS files is performed using the general nuclear data I/O functionalities described in I_ARMI_NUCDATA. Reading/writing a ISOTXS file is performed through the following steps:
|
Reading and writing PMATRX files is performed using the general nuclear data I/O functionalities described in I_ARMI_NUCDATA. Reading/writing a PMATRX file is performed through the following steps:
|
Implementation: Compute macroscopic cross sections from microscopic cross sections and number densities. I_ARMI_NUCDATA_MACRO
|
This function computes the macroscopic cross sections of a specified
reaction type from inputted microscopic cross sections and number
densities. The
\[\Sigma_{g} = \sum_{n} N_n \sigma_{n,g}\nu_n \quad g=1,...,G\]
where \(n\) is the isotope index, \(g\) is the energy group
index, \(\sigma\) is the microscopic cross section, and \(\nu\)
is the scalar multiplier. If the library ( |
Implementation: An operator will have a reactor object to communicate between plugins. I_ARMI_OPERATOR_COMM
|
A major design feature of ARMI is that the Operator orchestrates the simulation, and as part of that, the Operator has access to the Reactor data model. In code, this just means the reactor object is a mandatory attribute of an instance of the Operator. But conceptually, this means that while the Operator drives the simulation of the reactor, all code has access to the same copy of the reactor data model. This is a crucial idea that allows disparate external nuclear models to interact; they interact with the ARMI reactor data model. |
A major design feature of ARMI is that a run is built from user settings.
In code, this means that a case |
In all computational modeling of physical systems, it is necessary to break time into discrete chunks. In reactor modeling, it is common to first break the time a reactor is simulated for into the practical cycles the reactor runs. And then those cycles are broken down into smaller chunks called burn steps. The final step lengths this method returns is a two-tiered list, where primary indices correspond to the cycle and secondary indices correspond to the length of each intra-cycle step (in days). |
This method runs all the interfaces that are defined as part of the tight physics coupling of the reactor. Then it returns if the coupling has converged or not. Tight coupling implies the operator has split iterations between two or more physics solvers at the same solution point in simulated time. For example, a flux solution might be computed, then a temperature solution, and then another flux solution based on updated temperatures (which updates densities, dimensions, and Doppler). This is distinct from loose coupling, which simply uses the temperature values from the previous timestep in the current flux solution. It's also distinct from full coupling where all fields are solved simultaneously. ARMI supports tight and loose coupling. |
This method returns an ordered list of instances of the Interface class. This list is useful because at any time node in the reactor simulation, these interfaces will be called in sequence to perform various types of calculations. It is important to note that this Operator instance has a list of Plugins, and each of those Plugins potentially defines multiple Interfaces. And these Interfaces define their own order, separate from the ordering of the Plugins. |
This sets up the main Operator on the primary MPI node and initializes worker processes on all other MPI nodes. At certain points in the run, particular interfaces might call into action all the workers. For example, a depletion or subchannel T/H module may ask the MPI pool to perform a few hundred independent physics calculations in parallel. In many cases, this can speed up the overall execution of an analysis, if a big enough computer or computing cluster is available. See |
Implements a basic container to hold and report options to be used in
the execution of an external code (see I_ARMI_EX1).
Options are stored as instance attibutes and can be dumped as a string
using Also facilitates the ability to execute parallel instances of a code by
providing the ability to resolve a |
Facilitates the execution of external calculations by accepting The Finally, any geometry perturbations that were performed are undone. |
This interface allows for a user to define custom shuffle logic that
modifies to the core model. Being based on the User logic is able to be executed from within the
If no class with the name specified by the See the user manual for how the custom shuffle logic file should be constructed. |
Implementation: User-specified blocks can be left in place during within-core swaps. I_ARMI_SHUFFLE_STATIONARY0
|
Before assemblies are moved, the If all checks pass, the Once this process is complete, the actual assembly movement can take place. Through this process, the stationary blocks remain in the same core location. |
Implementation: User-specified blocks can be left in place for the discharge swap. I_ARMI_SHUFFLE_STATIONARY1
|
Before assemblies are moved, the If all checks pass, the Once this process is complete, the actual assembly movement can take place. Through this process, the stationary blocks from the outgoing assembly remain in the original core position, while the stationary blocks from the incoming assembly are discharged with the outgoing assembly. |
Implementation: Provide an algorithm for rotating hexagonal assemblies to equalize burnup I_ARMI_ROTATE_HEX_BURNUP
|
Implementation: Create representative blocks using volume-weighted averaging. I_ARMI_XSGM_CREATE_REPR_BLOCKS0
|
This class constructs new blocks from an existing block list based on a volume-weighted
average. Inheriting functionality from the abstract
|
Implementation: Create representative blocks using custom cylindrical averaging. I_ARMI_XSGM_CREATE_REPR_BLOCKS1
|
This class constructs representative blocks based on a volume-weighted average using
cylindrical blocks from an existing block list. Inheriting functionality from the abstract
|
Implementation: Create partially heterogeneous representative blocks. I_ARMI_XSGM_CREATE_REPR_BLOCKS2
|
This class constructs representative blocks based on a volume-weighted average using
cylindrical blocks from an existing block list. Inheriting functionality from the abstract
The average nuclide temperatures are calculated only for the homogenized region inside of the duct. For the non-homogenized regions, the MC2 writer uses the component temperatures. |
Implementation: The lattice physics interface and cross-section group manager are connected at
BOL. I_ARMI_XSGM_FREQ0
|
This method sets the cross-section block averaging method and and logic for whether all
blocks in a cross section group should be used when generating a representative block.
Furthermore, if the control logic for lattice physics frequency updates is set at
beginning-of-life (BOL) through the |
Implementation: The lattice physics interface and cross-section group manager are connected at
BOC. I_ARMI_XSGM_FREQ1
|
This method updates representative blocks and block burnups at the beginning-of-cycle
for each cross-section ID if the control logic for lattice physics frequency updates is
set at beginning-of-cycle (BOC) through the |
Implementation: The lattice physics interface and cross-section group manager are connected at
every time node. I_ARMI_XSGM_FREQ2
|
This method updates representative blocks and block burnups at every node for each
cross-section ID if the control logic for lattices physics frequency updates is set for
every node (everyNode) through the |
Implementation: The lattice physics interface and cross-section group manager are connected
during coupling. I_ARMI_XSGM_FREQ3
|
This method updates representative blocks and block burnups at every node and the first
coupled iteration for each cross-section ID if the control logic for lattices physics
frequency updates is set for the first coupled iteration ( |
Implementation: Create collections of blocks based on cross-section type and burn-up group. I_ARMI_XSGM_CREATE_XS_GROUPS
|
This method constructs the representative blocks and block burnups for each cross-section ID in the reactor model. Starting with the making of cross-section groups, it will find candidate blocks and create representative blocks from that selection. |
This function returns the energy group within a given group structure
that contains the fast flux threshold energy. The threshold energy is
imported from the |
There are several built-in group structures that are defined in this module, which are stored in a dictionary. This function takes a group structure name as an input parameter, which it uses as a key for the group structure dictionary. If the group structure name is valid, it returns a copy of the energy group structure resulting from the dictionary lookup. Otherwise, it throws an error. |
This method checks that the global power computed from flux
evaluation matches the global power specified from the user within a
tolerance; if it does not, a |
This class functions as a data structure for setting and retrieving execution options for performing flux evaluations, these options involve:
These options can be retrieved by directly accessing class members. The
options are set by specifying a |
Implementation: Ensure the mesh in the reactor model is appropriate for neutronics solver execution. I_ARMI_FLUX_GEOM_TRANSFORM
|
The primary purpose of this class is perform geometric and mesh transformations on the reactor model to ensure a flux evaluation can properly perform. This includes:
|
This method calculates DPA rates using the inputted multigroup flux and DPA cross sections. Displacements calculated by displacement cross-section:
\begin{aligned}
\text{Displacement rate} &= \phi N_{\text{HT9}} \sigma \\
&= (\#/\text{cm}^2/s) \cdot (1/cm^3) \cdot (\text{barn})\\
&= (\#/\text{cm}^5/s) \cdot \text{(barn)} * 10^{-24} \text{cm}^2/\text{barn} \\
&= \#/\text{cm}^3/s
\end{aligned} DPA rate = displacement density rate / (number of atoms/cc)
= dr [#/cm^3/s] / (nHT9) [1/cm^3]
= flux * barn * 1e-24
\[\frac{\text{dpa}}{s} = \frac{\phi N \sigma}{N} = \phi * \sigma\]
the number density of the structural material cancels out. It's in the macroscopic cross-section and in the original number of atoms. |
This method computes 1-group reaction rates for the inputted
Scatter could be added as well. This function is quite slow so it is skipped for now as it is uncommonly needed. Reaction rates are:
\[\Sigma \phi = \sum_{\text{nuclides}} \sum_{\text{energy}} \Sigma
\phi\]
The units of \(N \sigma \phi\) are: [#/bn-cm] * [bn] * [#/cm^2/s] = [#/cm^3/s]
The group-averaged microscopic cross section is:
\[\sigma_g = \frac{\int_{E g}^{E_{g+1}} \phi(E) \sigma(E)
dE}{\int_{E_g}^{E_{g+1}} \phi(E) dE}\]
|
This method builds macroscopic cross sections for a user-specified
set of blocks using a specified microscopic neutron or gamma cross
section library. If no blocks are specified, cross sections are
calculated for all blocks in the core. If no library is specified,
the existing r.core.lib is used. The basic arithmetic involved in
generating macroscopic cross sections consists of multiplying
isotopic number densities by isotopic microscopic cross sections and
summing over all isotopes in a composition. The calculation is
implemented in |
Each plugin has the option of implementing the |
This method takes in a Settings object and returns a list of Interfaces, the position of each Interface in the Interface stack, and a list of arguments to pass to the Interface when initializing it later. These Interfaces can then be used to add code to a simulation. |
Through this method, plugin developers can create new Parameters. A parameter can represent any physical property an analyst might want to track. And they can be added at any level of the reactor data model. Through this, the developers can extend ARMI and what physical properties of the reactor they want to calculate, track, and store to the database. |
Through this method, plugin developers can create new Parameters. A parameter can represent any physical property an analyst might want to track. For example, through this method, a plugin developer can add a new thermodynamic property that adds a thermodynamic parameter to every block in the reactor. Or they could add a neutronics parameter to every fuel assembly. A parameter is quite generic. But these parameters will be tracked in the reactor data model, extend what developers can do with ARMI, and will be saved to the output database. |
This method allows a plugin developers to provide novel values for
the Flags system. This method returns a dictionary mapping flag names
to their desired numerical values. In most cases, no specific value
is needed, one can be automatically generated using
|
This hook allows plugin developers to provide their own configuration
settings, which can participate in the
|
Adds a unique Block to the top of the Assembly. If the Block already
exists in the Assembly, an error is raised in
|
This method returns a string label indicating the location of an Assembly. There are three options: 1) the Assembly is not within a Core object and is interpreted as in the "load queue"; 2) the Assembly is within the spent fuel pool; 3) the Assembly is within a Core object, so it has a physical location within the Core. |
In this method, the spatialLocator of an Assembly is leveraged to return its physical (x,y) coordinates in cm. |
Implementation: A hexagonal assembly shall support rotating around the z-axis in 60 degree increments. I_ARMI_ROTATE_HEX_ASSEM
|
This method loops through every |
If the block does not have its Otherwise, use the |
Calls to the |
Uses some simple criteria to infer the number of pins in the block. For every flag in the module list After looping over all possibilities, return the maximum value returned from the process above, or if no compatible components were found, return zero. |
Sets the This method is typically called from within
|
This class defines hexagonal-shaped Blocks. It inherits functionality from the parent class, Block, and defines hexagonal-specific methods including, but not limited to, querying pin pitch, pin linear power densities, hydraulic diameter, and retrieving inner and outer pitch. |
Calls to the Will additionally adjust the x and y coordinates based on the block
parameters |
This method creates and returns a homogenized representation of itself in the form of a new Block.
The homogenization occurs in the following manner. A single Hexagon Component is created
and added to the new Block. This Hexagon Component is given the
|
Implementation: Rotating a hex block updates parameters on the boundary, the orientation
parameter, and the spatial coordinates on contained objects. I_ARMI_ROTATE_HEX_BLOCK
|
Defines a yaml map attribute for the assembly portion of the blueprints (see
These material attributes can be used during the resolution of material classes during core
instantiation (see
|
Defines a yaml construct that allows the user to specify attributes of an assembly from within their blueprints file, including a name, flags, specifier for use in defining a core map, a list of blocks, a list of block heights, a list of axial mesh points in each block, a list of cross section identifiers for each block, and material options (see I_ARMI_MAT_USER_INPUT0). Relies on the underlying infrastructure from the Is implemented as part of a blueprints file by being imported and used
as an attribute within the larger Includes a |
Defines a yaml construct that allows the user to specify attributes of a block from within
their blueprints file, including a name, flags, a radial grid to specify locations of pins,
and the name of a component which drives the axial expansion of the block (see
In addition, the user may specify key-value pairs to specify the components contained within
the block, where the keys are component names and the values are component blueprints (see
Relies on the underlying infrastructure from the Is implemented into a blueprints file by being imported and used as an attribute within the
larger Includes a |
Defines a yaml construct that allows the user to specify attributes of a component from
within their blueprints file, including a name, flags, shape, material and/or isotopic
vector, input temperature, corresponding component dimensions, and ID for placement in a
block lattice (see Limited validation on the inputs is performed to ensure that the component shape corresponds to a valid shape defined by the ARMI application. Relies on the underlying infrastructure from the Is implemented as part of a blueprints file by being imported and used as an attribute
within the larger Includes a |
Allows for user input to impact a component's materials by applying
the "material modifications" section of a blueprints file (see I_ARMI_MAT_USER_INPUT0)
to the material during construction. This takes place during lower
calls to Within |
This is called during the component construction process for each component from within
For a given initialized component, check its flags to determine if it has been marked as
depletable. If it is, use
Note that certain case settings, including |
Defines a yaml construct that allows the user to specify a grid from within their blueprints file, including a name, geometry, dimensions, symmetry, and a map with the relative locations of components within that grid. Relies on the underlying infrastructure from the Is implemented as part of a blueprints file by being used in key-value pairs within the
Includes a |
First makes a copy of the blueprints that are passed in. Then modifies any grids specified
in the blueprints into a canonical lattice map style, if needed. Then uses the If called with the |
This class creates a yaml interface for the user to specify in their blueprints which
isotopes should be depleted. It is incorporated into the "nuclide flags" section of a
blueprints file by being included as key-value pairs within the
This class includes a boolean Note that while the |
Implementation: Certain material modifications will be applied using this code. I_ARMI_MAT_USER_INPUT2
|
Defines a yaml construct that allows the user to define a custom isotopic vector from within their blueprints file, including a name and key-value pairs corresponding to nuclide names and their concentrations. Relies on the underlying infrastructure from the Is implemented as part of a blueprints file by being used in key-value pairs within the
These isotopics are linked to a component during calls to
|
This class creates a yaml interface for the user to define systems with
grids, such as cores or spent fuel pools, each having their own name,
type, grid, and position in space. It is incorporated into the "systems"
section of a blueprints file by being included as key-value pairs within
the This class includes a
|
Implementation: The volume of a DerivedShape depends on the solid shapes surrounding
them. I_ARMI_COMP_FLUID0
|
Computing the volume of a |
This class provides the implementation of a Circle Component. This includes
setting key parameters such as its material, temperature, and dimensions. It
also includes a method to retrieve the area of a Circle
Component via the |
This class provides the implementation of a hexagonal Component. This
includes setting key parameters such as its material, temperature, and
dimensions. It also includes methods for retrieving geometric
dimension information unique to hexagons such as the |
This class provides the implementation for a rectangular Component. This
includes setting key parameters such as its material, temperature, and
dimensions. It also includes methods for computing geometric
information related to rectangles, such as the
|
This class provides the implementation for a square Component. This class
subclasses the |
This class provides the implementation for defining a triangular Component. This
includes setting key parameters such as its material, temperature, and
dimensions. It also includes providing a method for retrieving the area of a
Triangle Component via the |
This class provides an implementation for a holed hexagonal Component. This
includes setting key parameters such as its material, temperature, and
dimensions. It also provides the capability to retrieve the diameter of the
inner hole via the |
This class provides an implementation for a holed square Component. This
includes setting key parameters such as its material, temperature, and
dimensions. It also includes methods to retrieve geometric
dimension information unique to holed squares via the |
This class provides the implementation for a helical Component. This
includes setting key parameters such as its material, temperature, and
dimensions. It also includes the |
The primitive object in an ARMI reactor is a Component. A Component is comprised of a shape and composition. This class serves as a base class which all Component types within ARMI are built upon. All primitive shapes (such as a square, circle, holed hexagon, helix etc.) are derived from this base class. Fundamental capabilities of this class include the ability to store parameters and attributes which describe the physical state of each Component within the ARMI data model. |
Implementation: Order Components by their outermost diameter (using the < operator). I_ARMI_COMP_ORDER
|
Determining Component order by outermost diameters is implemented via
the |
Implementation: The volume of some defined shapes depend on the solid components surrounding them. I_ARMI_COMP_FLUID1
|
Some Components are fluids and are thus defined by the shapes surrounding them. This method cycles through each dimension defining the border of this Component and converts the name of that Component to a link to the object itself. This series of links is then used downstream to resolve dimensional information. |
This method returns the material object that is assigned to the Component. |
This method returns the material object that is assigned to the Component. |
This method returns the area of a Component. |
This method returns the volume of a Component. |
The method allows a user or plugin to set the number density of a Component.
It also indicates to other processes that may depend on a Component's
status about this change via the |
The method allows a user or plugin to set the number densities of a Component. In
contrast to the |
Dimensions should be set considering the impact of thermal expansion. This method allows for a user or plugin to set a dimension and indicate if the dimension is for a cold configuration or not. If it is not for a cold configuration, the thermal expansion factor is considered when setting the dimension. If the |
Due to thermal expansion, Component dimensions depend on their temperature. This method retrieves a dimension from the Component at a particular temperature, if provided. If the Component is a LinkedComponent then the dimensions are resolved to ensure that any thermal expansion that has occurred to the Components that the LinkedComponent depends on is reflected in the returned dimension. |
This method enables the calculation of the thermal expansion factor
for a given material. If the material is solid, the difference
between |
An ARMI reactor model is composed of collections of ARMIObject objects. These
objects are combined in a hierarchical manner. Each level of the composite tree
is able to be assigned parameters which define it, such as temperature, flux,
or keff values. This class defines an attribute of type |
This class method allows a user to obtain the
|
This method queries the flags (i.e. the If a list of flags is provided, then all input flags will be
checked against the flags of the object. If exact is |
This method allows for the setting of flags parameter of the Composite. |
This method allows for the querying of the mass of a Composite.
If the |
This method queries the number density
of a specific nuclide within the Composite. It invokes the
|
This method provides the capability to query the volume weighted number densities for a list of nuclides within a given Composite. It provides the result in units of atoms/barn-cm. The volume weighting is accomplished by multiplying the number densities within each child Composite by the volume of the child Composite and dividing by the total volume of the Composite. |
This method provides a way for retrieving the number densities
of all nuclides within the Composite. It does this by leveraging the
|
Implementation: Composites are a physical part of the reactor in a hierarchical data model. I_ARMI_CMP0
|
An ARMI reactor model is composed of collections of ARMIObject objects. This class is a child-class of the ARMIObject class and provides a structure allowing a reactor model to be composed of Composites. This class provides various methods to query and modify the hierarchical ARMI reactor model, including but not limited to, iterating, sorting, and adding or removing child Composites. |
This method retrieves all children within a given Composite object. Children of any generation can be retrieved. This is achieved by visiting all children and calling this method recursively for each generation requested. If the method is called with |
Parameters need to be handled properly during parallel code execution.This method synchronizes all parameters of the composite object across all processes by cycling through all the children of the Composite and ensuring that their parameters are properly synchronized. If it fails to synchronize, an error message is displayed which alerts the user to which Composite has inconsistent data across the processes. |
Implementation: Perform expansion during core construction based on block heights at a specified temperature. I_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 If the setting Once the Assemblies are axially expanded, the Block BOL heights are updated. To account for the change in
Block volume from axial expansion, |
Implementation: Perform expansion/contraction, given a list of components and expansion coefficients. I_ARMI_AXIAL_EXP_PRESC
|
This method performs component-wise axial expansion for an Assembly given expansion coefficients
and a corresponding list of Components. In |
Implementation: Perform thermal expansion/contraction, given an axial temperature distribution
over an assembly. I_ARMI_AXIAL_EXP_THERM
|
This method performs component-wise thermal expansion for an assembly given a discrete
temperature distribution over the axial length of the Assembly. In |
Implementation: Preserve the total height of an ARMI assembly, during expansion. I_ARMI_ASSEM_HEIGHT_PRES
|
The total height of an Assembly is preserved by not changing the |
This subclass of |
This subclass of |
This method converts a |
This method converts the hex-z mesh to r-theta-z mesh.
It first verifies that the geometry type of the input reactor |
Implementation: Convert a one-third-core geometry to a full-core geometry. I_ARMI_THIRD_TO_FULL_CORE0
|
This method first checks if the input reactor is already full core. If full-core symmetry is detected, the input reactor is returned. If not, it then verifies that the input reactor has the expected one-third core symmetry and HEX geometry. Upon conversion, it loops over the assembly vector of the source one-third core model, copies and rotates each source assembly to create new assemblies, and adds them on the full-core grid. For the center assembly, it modifies its parameters. Finally, it sets the domain type to full core. |
Implementation: Restore a one-third-core geometry to a full-core geometry. I_ARMI_THIRD_TO_FULL_CORE1
|
This method is a reverse process of the method |
Edge assemblies on the 120-degree symmetric line of a one-third core reactor model are added because they are needed for DIF3D-finite difference or MCNP models. This is done by copying the assemblies from the lower boundary and placing them in their reflective positions on the upper boundary of the symmetry line. |
This method is the reverse process of the method |
A core-wide mesh is computed via |
Implementation: Produce a mesh with a size no smaller than a user-specified value. I_ARMI_UMC_MIN_MESH
|
If a minimum mesh size |
Given a source Reactor, |
Implementation: Map select parameters from composites on the original mesh to the new mesh. I_ARMI_UMC_PARAM_FORWARD
|
In |
Implementation: Map select parameters from composites on the new mesh to the original mesh. I_ARMI_UMC_PARAM_BACKWARD
|
To ensure that the parameters on the original Reactor are from the converted Reactor,
the first step is to clear the Reactor-level parameters on the original Reactor
(see |
This property getter returns the symmetry attribute of the spatialGrid instance
attribute. The spatialGrid is an instance of a child of the abstract base class
Only specific combinations of |
This method returns the |
This method returns the |
This method takes an The The |
This method iterates through all of the assemblies provided, or all
assemblies in the core if no list of |
For a string passed as Then it splits the remaining string into words based on spaces. Looping over each of the words, if any word exactly matches a flag name. Otherwise, any numbers are stripped out and the remaining string is matched up to any class attribute names. If any matches are found these are returned as flags. |
This converts the representation of a bunch of flags from |
The reactor will usually have (i,j,k) coordinates to define a simple mesh for locating objects in the reactor. But inside that mesh can be a smaller mesh to define the layout of pins in a reactor, or fuel pellets in a pin, or the layout of some intricate ex-core structure. Every time the |
Every grid contains a It is important to note, that not all of these geometries will apply to every reactor or core. If your core is made of hexagonal assemblies, then a 1/3 core grid would make sense, but not if your reactor core was made up of square assemblies. Likewise, a hexagonal core would not make be able to support a 1/4 grid. You want to leave assemblies (and other objects) whole when dividing a grid up fractionally. |
This class represents a hexagonal |
When this method creates a |
Implementation: When creating a hexagonal grid, the user can specify the symmetry. I_ARMI_GRID_SYMMETRY1
|
When this method creates a |
This method takes in (I,J,K) indices, and if this |
This is a simple helper method to determine if a given locator (from an
ArmiObject) is in the first 1/3 of the |
As not all grids are "full core symmetry", ARMI will sometimes need to track
multiple positions for a single object: one for each symmetric portion of the
reactor. This class doesn't calculate those positions in the reactor, it just
tracks the multiple positions given to it. In practice, this class is mostly
just a list of |
Implementation: Return the location of all instances of grid components with
multiplicity greater than 1. I_ARMI_GRID_ELEM_LOC
|
This method returns the indices of all the |
Probably the most common request of a structure grid will be to give the grid indices and return the physical coordinates of the center of the mesh cell. This is super handy in any situation where the coordinates have physical meaning. The math for finding the centroid turns out to be very easy, as the mesh is defined on the coordinates. So finding the mid-point along one axis is just taking the upper and lower bounds and dividing by two. And this is done for all axes. There are no more complicated situations where we need to find the centroid of a octagon on a rectangular mesh, or the like. |
Important physical parameters are stored in every ARMI object. These parameters represent
the plant's state during execution of the model. Currently, this requires that the
parameters be serializable to a numpy array of a datatype supported by the This class allows for these parameters to be serialized in a custom manner by providing interfaces for packing and unpacking parameter data. The user or downstream plugin is able to specify how data is serialized if that data is not naturally serializable. |
Implementation: Provide a way to signal if a parameter needs updating across processes. I_ARMI_PARAM_PARALLEL
|
Parameters need to be handled properly during parallel code execution. This includes notifying processes if a parameter has been updated by another process. This method allows for setting a parameter's value as well as an attribute that signals whether this parameter has been updated. Future processes will be able to query this attribute so that the parameter's status is properly communicated. |
This method is called when writing the parameters to the database file. It queries the
parameter's |
The |
The Zone class facilitates the creation of a Zone object representing a collection of locations in the Core. A Zone contains a group of locations in the Core, used to subdivide it for analysis. Each location represents an Assembly or a Block, where a single Zone must contain items of the same type (i.e., Assembly or Block). Methods are provided to add or remove one or more locations to/from the Zone, and similarly, add or remove one or more items with a Core location (i.e., Assemblies or Blocks) to/from the Zone. In addition, several methods are provided to facilitate the retrieval of locations from a Zone by performing functions to check if a location exists in the Zone, looping through the locations in the Zone in alphabetical order, and returning the number of locations in the Zone, etc. |
The Zones class facilitates the creation of a Zones object representing a collection of Zone objects. Methods are provided to add or remove one or more Zone to/from the Zones object. Likewise, methods are provided to validate that the zones are mutually exclusive, obtain the location labels of zones, return the Zone object where a particular Assembly or Block resides, sort the Zone objects alphabetically, and summarize the zone definitions. In addition, methods are provided to facilitate the retrieval of Zone objects by name, loop through the Zones in order, and return the number of Zone objects. |
The log files are plain text files. Since ARMI is frequently run in parallel, the situation arises where each ARMI process generates its own plain text log file. This function combines the separate log files, per process, into one log file. The files are written in numerical order, with the lead process stdout first then the lead process stderr. Then each other process is written to the combined file, in order, stdout then stderr. Finally, the original stdout and stderr files are deleted. |
Log statements are any text a user wants to record during a run. For instance, basic notifications of what is happening in the run, simple warnings, or hard errors. Every log message has an associated log level, controlled by the "verbosity" of the logging statement in the code. In the ARMI codebase, you can see many examples of logging: runLog.error("This sort of error might usually terminate the run.")
runLog.warning("Users probably want to know.")
runLog.info("This is the usual verbosity.")
runLog.debug("This is only logged during a debug run.")
The full list of logging levels is defined in At the end of the ARMI-based simulation, the analyst will have a full record of potentially interesting information they can use to understand their run. |
This logger makes it easy for users to add log statements to and ARMI application, and ARMI will control the flow of those log statements. In particular, ARMI overrides the normal Python logging tooling, to allow developers to pipe their log statements to both screen and file. This works for stdout and stderr. At any place in the ARMI application, developers can interject a plain text
logging message, and when that code is hit during an ARMI simulation, the text
will be piped to screen and a log file. By default, the |
The Settings object is accessible to most ARMI objects through self.cs (for 'case settings'). It acts largely as a dictionary, and setting values are accessed by keys. The Settings object has a 1-to-1 correspondence with the ARMI settings input file. This file may be created by hand or by a GUI. |
Every Settings object has a "case title"; a string for users to help identify their run. This case title is used in log file names, it is printed during a run, it is frequently used to name the settings file. It is designed to be an easy-to-use and easy-to-understand way to keep track of simulations. The general idea here is that the average analyst that is using ARMI will run many ARMI-based simulations, and there needs to be an easy to identify them all. |
ARMI defines a collection of settings by default to be associated
with all runs, and one such setting is |
Because nuclear analysts have a lot to keep track of when doing
various simulations of a reactor, ARMI provides a Likewise, it is helpful to know what versions of software were
used in an ARMI application. There is a dictionary-like setting
called |
Setting objects hold all associated information of a setting in ARMI and should typically be accessed through the Settings methods rather than directly. Settings require a mandatory default value. Setting subclasses can implement custom |
ARMI uses the YAML standard for settings files. ARMI uses industry-standard
|
This class is meant to represent a generic validation test against a setting.
The goal is: developers create new settings and they want to make sure those
settings are used correctly. As an implementation, users pass in a
|
Loops over all provided nuclides (given as keys in the |
Loops over a vector of nuclides (of type A The boolean |
Given a vector of elements and nuclides with associated mass fractions ( Explicitly specifying the expansion isotopes provides a way for particular naturally-occurring isotopes to be excluded from the expansion, e.g. excluding O-18 from an expansion of elemental oxygen. |
A bitwise flag class intended to emulate the standard library's Note that while Python allows for arbitrary-width integers, exceeding the system-native
integer size can lead to challenges in storing data, e.g. in an HDF5 file. In this case, the
|
A class method to extend a |