5. Hands-on at the ARMI Terminal

This tutorial will walk you through some exploration with ARMI on the command line with the goal of exposing you to some of the capabilities and organization of information in the ARMI system.

5.1. Initializing and Exploring the ARMI Model

First we need to get some inputs. We built some from scratch in Building input files for a fast reactor and we pick those up and use them here as well:

You can load these inputs using armi’s init function. This will build an Operator, a Reactor, and an Interface Stack full of various interfaces.

[1]:
# you can only configure an app once
import armi
if not armi.isConfigured():
    armi.configure(armi.apps.App())
Failed to import psutil; MemoryProfiler will not provide meaningful data.

                              ---------------------------------------------------
                             |             _      ____     __  __    ___         |
                             |            / \    |  _ \   |  \/  |  |_ _|        |
                             |           / _ \   | |_) |  | |\/| |   | |         |
                             |          / ___ \  |  _ <   | |  | |   | |         |
                             |         /_/   \_\ |_| \_\  |_|  |_|  |___|        |
                             |         Advanced  Reactor  Modeling Interface     |
                              ---------------------------------------------------
                                                   Version 0.2.3
[2]:
o=armi.init(fName="anl-afci-177.yaml");
=========== Case Information ===========
[info] ---------------------  ------------------------------------------------------------
       Case Title:            anl-afci-177
       Case Description:      ANL-AFCI-177 CR 1.0 metal core but with HALEU instead of TRU
       Run Type:              Standard - Operator
       Current User:          armi
       ARMI Location:         /home/runner/work/armi/armi/armi
       Working Directory:     /home/runner/work/armi/armi/doc/tutorials
       Python Interpreter:    3.8.12 (default, Oct 18 2021, 14:07:50)
                              [GCC 9.3.0]
       Master Machine:        ?
       Number of Processors:  1
       Date and Time:         Tue Feb  8 18:47:19 2022
       ---------------------  ------------------------------------------------------------
=========== Input File Information ===========
[info] -------------------  ------------------------------  ------------
       Input Type           Path                            SHA-1 Hash
       -------------------  ------------------------------  ------------
       Case Settings        anl-afci-177.yaml               5e5875c322
       Blueprints           anl-afci-177-blueprints.yaml    04761fb2b3
       Included blueprints  anl-afci-177-coreMap.yaml       5904530cb2
       Geometry                                             MISSING
       Shuffle Logic        anl-afci-177-fuelManagement.py  622957b035
       -------------------  ------------------------------  ------------
=========== Reactor Cycle Information ===========
[info] ---------------------------  ---------------------------------------------------------------
       Reactor Thermal Power (MW):  1000.0
       Number of Cycles:            10
       Cycle Lengths:               411.11, 411.11, 411.11, 411.11, 411.11, 411.11, 411.11, 411.11,
                                    411.11, 411.11
       Availability Factors:        0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9
       Power Fractions:             1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
       ---------------------------  ---------------------------------------------------------------
=========== Constructing Reactor and Verifying Inputs ===========
[info] Constructing the `core`
=========== Adding Assemblies to <Core: core id:140472825870992> ===========
[info] Will expand CR, FE, MO, NI, SI, ZR, HE, NA, MN, W elementals to have natural isotopics
[info] Nuclides truncating the burn-chain:  LFP38, DUMP1, LFP40, LFP41, LFP35, LFP39, DUMP2
[info] Constructing assembly `inner fuel`
[warn] No component matched Flags.CLAD in <reflector block-bol-000 at ExCore XS: A BU GP: A>. Returning None
[warn] Some component was missing in <reflector block-bol-000 at ExCore XS: A BU GP: A> so pin-to-duct gap not calculated
[warn] Cannot get pin pitch in <reflector block-bol-000 at ExCore XS: A BU GP: A> because it does not have a wire and a clad
[warn] The gap between wire wrap and clad in block <plenum block-bol-006 at ExCore XS: A BU GP: A> was 3.999999999998449e-05 cm. Expected 0.0.
[info] Constructing assembly `middle core fuel`
[warn] Some component was missing in <reflector block-bol-000 at ExCore XS: B BU GP: A> so pin-to-duct gap not calculated
[warn] Cannot get pin pitch in <reflector block-bol-000 at ExCore XS: B BU GP: A> because it does not have a wire and a clad
[warn] The gap between wire wrap and clad in block <plenum block-bol-006 at ExCore XS: B BU GP: A> was 3.999999999998449e-05 cm. Expected 0.0.
[info] Constructing assembly `outer core fuel`
[warn] Some component was missing in <reflector block-bol-000 at ExCore XS: C BU GP: A> so pin-to-duct gap not calculated
[warn] Cannot get pin pitch in <reflector block-bol-000 at ExCore XS: C BU GP: A> because it does not have a wire and a clad
[warn] The gap between wire wrap and clad in block <plenum block-bol-006 at ExCore XS: C BU GP: A> was 3.999999999998449e-05 cm. Expected 0.0.
[info] Constructing assembly `radial reflector`
[warn] Some component was missing in <reflector block-bol-000 at ExCore XS: A BU GP: A> so pin-to-duct gap not calculated
[info] Constructing assembly `radial shield`
[warn] Temperature 597.0 out of range (25 to 500) for B4C linear expansion percent
[warn] No component matched Flags.WIRE in <radial shield block-bol-000 at ExCore XS: A BU GP: A>. Returning None
[warn] Cannot get pin pitch in <radial shield block-bol-000 at ExCore XS: A BU GP: A> because it does not have a wire and a clad
[info] Constructing assembly `control`
[warn] Could not create a spatialGrid for block control, multiplicities are not 1 or N they are {1.0}
[info] Constructing assembly `ultimate shutdown`
=========== Verifying Assembly Configurations ===========
=========== Summarizing Source of Material Data for <Core: core id:140472825870992> ===========
[info] ---------------  -----------------  ----------------------------
       Material Name    Source Location    Property Data was Modified
                                           from the Source?
       ---------------  -----------------  ----------------------------
       B4C              ARMI               False
       HT9              ARMI               False
       Sodium           ARMI               False
       UZr              ARMI               False
       Void             ARMI               False
       ---------------  -----------------  ----------------------------
=========== Applying Geometry Modifications ===========
[info] Updating spatial grid pitch data for hex geometry
=========== Initializing Mesh, Assembly Zones, and Nuclide Categories ===========
[info] Nuclide categorization for cross section temperature assignments:
       ------------------  ------------------------------------------------------------
       Nuclide Category    Nuclides
       ------------------  ------------------------------------------------------------
       Fuel                U238, PU242, PU238, PU240, AM242, ZR92, LFP40, PU236, LFP41,
                           ZR91, DUMP2, DUMP1, PU239, NP238, CM246, U236, ZR96, LFP38,
                           CM242, CM244, ZR94, AM241, CM243, CM247, AM243, ZR90,
                           CM245, NP237, U234, LFP35, LFP39, HE4, PU241, U235
       Coolant             NA23
       Structure           MO94, FE56, MO100, NI62, FE54, NI61, FE57, NI64,
                           SI29, MO92, NI58, SI30, W182, NI60, SI28, MO95,
                           CR54, MO98, W184, V, CR52, CR53, MN55, MO96,
                           FE58, CR50, W186, B11, B10, C, MO97, W183
       ------------------  ------------------------------------------------------------
[info] Assembly zone definitions:
       --------  ------  ------------  -----------------------------------------------------  ----------  ------
           Zone                                                                                 Symmetry  Hot
         Number  Name      Assemblies  Locations                                                  Factor  Zone
       --------  ------  ------------  -----------------------------------------------------  ----------  ------
              1  ring-1           111  001-001, 002-001, 002-002, 003-001, 003-002, 003-003,           3  False
                                       003-012, 004-001, 004-002, 004-003, 004-004, 004-005,
                                       004-018, 005-001, 005-002, 005-003, 005-004, 005-005,
                                       005-006, 005-023, 005-024, 006-001, 006-002, 006-003,
                                       006-004, 006-005, 006-006, 006-007, 006-008, 006-029,
                                       006-030, 007-001, 007-002, 007-003, 007-004, 007-005,
                                       007-006, 007-007, 007-008, 007-009, 007-034, 007-035,
                                       007-036, 008-001, 008-002, 008-003, 008-004, 008-005,
                                       008-006, 008-007, 008-008, 008-009, 008-010, 008-011,
                                       008-040, 008-041, 008-042, 009-001, 009-002, 009-003,
                                       009-004, 009-005, 009-006, 009-007, 009-008, 009-009,
                                       009-010, 009-011, 009-012, 009-045, 009-046, 009-047,
                                       009-048, 010-001, 010-002, 010-003, 010-004, 010-005,
                                       010-006, 010-007, 010-008, 010-009, 010-010, 010-011,
                                       010-012, 010-013, 010-014, 010-051, 010-052, 010-053,
                                       010-054, 011-001, 011-002, 011-003, 011-004, 011-005,
                                       011-006, 011-007, 011-008, 011-009, 011-010,
                                       011-011, 011-012, 011-013, 011-014, 011-015,
                                       011-056, 011-057, 011-058, 011-059, 011-060
       --------  ------  ------------  -----------------------------------------------------  ----------  ------
[info] The setting `splitZones` is enabled. Building subzones from core zones:
       --------  --------------------------  ----------  ------------  -----------------------------------------------------  ----------  ------
           Zone                              Original                                                                           Symmetry  Hot
         Number  Name                        Name          Assemblies  Locations                                                  Factor  Zone
       --------  --------------------------  ----------  ------------  -----------------------------------------------------  ----------  ------
              1  ring-1-radial-shield-1      ring-1                20  011-056, 011-057, 011-058, 011-059, 010-054,                    3  False
                                                                       010-001, 010-002, 011-003, 011-004, 011-005,
                                                                       011-006, 011-007, 011-008, 010-009, 011-009,
                                                                       010-011, 010-010, 011-015, 011-014, 011-013
              2  ring-1-radial-reflector-1   ring-1                30  009-045, 010-051, 009-046, 010-052, 009-047, 010-053,           3  False
                                                                       009-048, 008-001, 009-001, 009-002, 009-003, 010-003,
                                                                       009-004, 010-004, 009-005, 010-005, 009-006, 010-006,
                                                                       009-007, 010-007, 008-008, 009-008, 010-008, 009-012,
                                                                       009-011, 009-010, 009-009, 010-014, 010-013, 010-012
              3  ring-1-control-1            ring-1                 3  007-034, 004-004, 007-004                                       3  False
              4  ring-1-outer-core-fuel-7    ring-1                22  008-040, 007-035, 008-041, 007-036, 008-042, 007-001,           3  False
                                                                       007-002, 008-002, 007-003, 008-003, 008-004, 007-005,
                                                                       008-005, 007-006, 008-006, 007-009, 007-008,
                                                                       007-007, 008-007, 008-011, 008-010, 008-009
              5  ring-1-middle-core-fuel-7   ring-1                22  005-023, 006-029, 004-018, 005-024, 006-030, 005-001,           3  False
                                                                       006-001, 004-002, 005-002, 006-002, 004-003, 005-003,
                                                                       006-003, 004-005, 005-004, 006-004, 005-006,
                                                                       005-005, 006-005, 006-008, 006-007, 006-006
              6  ring-1-inner-fuel-7         ring-1                 7  003-012, 001-001, 002-001, 003-001,                             3  False
                                                                       002-002, 003-002, 003-003
              7  ring-1-ultimate-shutdown-1  ring-1                 1  004-001                                                         3  False
       --------  --------------------------  ----------  ------------  -----------------------------------------------------  ----------  ------
=========== Interface Stack Summary  ===========
[info] -------  ------------------------  ---------------  ----------  ---------  -----------  ------------
         Index  Type                      Name             Function    Enabled    EOL order    BOL forced
       -------  ------------------------  ---------------  ----------  ---------  -----------  ------------
            01  Main                      main                         Yes        Reversed     No
            02  FissionProductModel       fissionProducts              Yes        Normal       No
            03  CrossSectionGroupManager  xsGroups                     Yes        Normal       No
            04  FuelHandler               fuelHandler                  Yes        Normal       No
            05  HistoryTracker            history                      Yes        Normal       No
            06  Report                    report                       Yes        Normal       No
            07  Database                  database                     Yes        Normal       No
            08  MemoryProfiler            memoryProfiler               Yes        Normal       No
            09  Snapshot                  snapshot                     Yes        Normal       No
       -------  ------------------------  ---------------  ----------  ---------  -----------  ------------
===========  Triggering Init Event ===========
=========== 01 - main                           Init            ===========
=========== 02 - fissionProducts                Init            ===========
=========== 03 - xsGroups                       Init            ===========
=========== 04 - fuelHandler                    Init            ===========
=========== 05 - history                        Init            ===========
=========== 06 - report                         Init            ===========
=========== 07 - database                       Init            ===========
=========== 08 - memoryProfiler                 Init            ===========
=========== 09 - snapshot                       Init            ===========
===========  Completed Init Event ===========

You have now created an operator object, which contains a Reactor object (called o.r) that represents the beginning-of-life (BOL) state of the nuclear reactor defined in the inputs. The reactor looks like this:

../_images/armi_reactor_objects.png

Figure 1. The primary data containers in ARMI

The data hierarchy in an ARMI model often is made up of:

  • Reactors, often named reactor or r contain a Core and possibly other equipment. They represent collections of assemblies.

  • Assemblies, often named assembly or a, are individual pieces that collect into a System.

  • Blocks, often called block or b are divisions of the assemblies into sections one on top of the other.

  • Components The geometrically defined objects (Circles, Hexagons, Helices, Dodecagons) and their dimensions.

  • Materials are objects which have material properties like linear expansion coefficients, thermal conductivities, isotopic mass fractions, and densities.

Each of these objects house more than the listed objects, they also are responsible for a variety of state information like the reactor’s overall keff, flux, height, temperature, etc. In this section, we will explore these objects, see how to access them, and how to view their contained information.

Exploring it a little, we can list all the assemblies in the reactor with:

[3]:
core = o.r.core
core.getAssemblies()[:25] # only print the first 25
[3]:
[<radial shield Assembly A0012 at 011-056>,
 <radial reflector Assembly A0011 at 009-045>,
 <radial reflector Assembly A0017 at 010-051>,
 <radial shield Assembly A0023 at 011-057>,
 <control Assembly A0010 at 007-034>,
 <outer core fuel Assembly A0016 at 008-040>,
 <radial reflector Assembly A0022 at 009-046>,
 <radial reflector Assembly A0028 at 010-052>,
 <radial shield Assembly A0034 at 011-058>,
 <middle core fuel Assembly A0009 at 005-023>,
 <middle core fuel Assembly A0015 at 006-029>,
 <outer core fuel Assembly A0021 at 007-035>,
 <outer core fuel Assembly A0027 at 008-041>,
 <radial reflector Assembly A0033 at 009-047>,
 <radial reflector Assembly A0040 at 010-053>,
 <radial shield Assembly A0046 at 011-059>,
 <inner fuel Assembly A0008 at 003-012>,
 <middle core fuel Assembly A0014 at 004-018>,
 <middle core fuel Assembly A0020 at 005-024>,
 <middle core fuel Assembly A0026 at 006-030>,
 <outer core fuel Assembly A0032 at 007-036>,
 <outer core fuel Assembly A0039 at 008-042>,
 <radial reflector Assembly A0045 at 009-048>,
 <radial shield Assembly A0052 at 010-054>,
 <inner fuel Assembly A0007 at 001-001>]

Quiz Question 1

How many assemblies does the model have? (see answers at bottom)

Tip

A reactor is made up of assemblies, which are made up of blocks, and so on. Each composite ARMI object has a getChildren method that will retrieve a list of its contents. For clarity, reactors have a getAssemblies() method and assemblies have a getBlocks() method, but these do exactly the same thing as getChildren() in both cases.

Reactor, assembly, blocks, etc. objects act like lists as well, so you can get the fifth assembly out of a reactor just like you’d get the fifth item out of any other list (don’t forget that Python uses zero-based numbering):

>>> fifthAssem = core[4]

You can drill down the hierarchy for a particular assembly:

[4]:
core = o.r[0]
print(core)
assem = core[1]
print(assem)
block = assem[5]
print(block)
print(f"Block's parent is: {block.parent}")
components = block.getChildren()
print(components)
material = components[0].material
print(material)
<Core: core id:140472825870992>
<inner fuel Assembly A0008 at 003-012>
<fuel B0008-005 at 003-012-005 XS: A BU GP: A>
Block's parent is: <inner fuel Assembly A0008 at 003-012>
[<Circle: clad>, <Helix: wire>, <Circle: fuel>, <Circle: bond>, <Hexagon: duct>, <Hexagon: intercoolant>, <DerivedShape: coolant>]
<Material: HT9>

5.2. Exploring the state of the reactor

State can be explored using a variety of framework methods, as well as looking at state parameters. Let’s first try out some methods to find out how much U-235 is in the model and what the average uranium enrichment is:

[5]:
u235 = core.getMass('U235')
u238 = core.getMass('U238')
print(f"The core contains {u235} grams of U-235")
print(f"The average fissile enrichment is {u235/(u235+u238)}")
The core contains 912822.5942999582 grams of U-235
The average fissile enrichment is 0.16152980132450312

That’s how much U-235 is in the 1/3 core. If we want the total mass (including all nuclides), we can just leave the argument out:

[6]:
core.getMass()/1.e6
[6]:
30.10217554403188
[7]:
core.getMass?

Furthermore, you can get a list of available methods by pressing the tab key. Try core. followed by [Tab]. Try out some options!

Use tab completion to explore other methods of ARMI reactors assemblies and blocks. You can view a summary of the methods of any object in the API documentation. For a good example, see the API docs for a block.

Next, lets find out what the number density of U235 is in a particular fuel block. We’ll use the FLAGS system to select a particular type of block (in this case, a fuel block):

[8]:
from armi.reactor.flags import Flags
b = core.getFirstBlock(Flags.FUEL)
print(f"U-235 ndens: {b.getNumberDensity('U235'):.4e} (atoms/bn-cm)")
print(f"Block name: {b.getName()}")
print(f"Block type: {b.getType()}")
U-235 ndens: 2.2585e-03 (atoms/bn-cm)
Block name: B0016-001
Block type: fuel

You can find lots of other details about this block with:

[9]:
b.printContents(includeNuclides=False)
[impt] <fuel B0016-001 at 008-040-001 XS: C BU GP: A>
[impt] <Circle: clad>
[impt] ---------------------------------------------------------------------------------------------
       Cladding Dimensions -  Of First Fuel Block
                                      Tcold (25.0)                   Thot (450.0)
       ---------------------------------------------------------------------------------------------
       Inner Diameter (cm)            0.6962                         0.6996347645979837
       Material                       HT9
       Multiplicity                   271                            271
       Name                           clad
       Outer Diameter (cm)            0.808                          0.8119863398379357
       Thickness (cm)                 0.0559000                      0.0561758
[impt] <Helix: wire>
[impt] ---------------------------------------------------------------------------------------------
       Wire Dimensions -  Of First Fuel Block
                                      Tcold (25.0)                   Thot (450.0)
       ---------------------------------------------------------------------------------------------
       Axial Pitch (cm)               30.0                           30.148007667250084
       Helix Diameter (cm)            0.8888                         0.8931849738217292
       Inner Diameter (cm)            0.0                            0.0
       Material                       HT9
       Multiplicity                   271                            271
       Name                           wire
       Outer Diameter (cm)            0.0808                         0.08119863398379355
[impt] <Circle: fuel>
[impt] ---------------------------------------------------------------------------------------------
       Fuel Dimensions -  Of First Fuel Block
                                      Tcold (25.0)                   Thot (500.0)
       ---------------------------------------------------------------------------------------------
       Inner Diameter (cm)            0.0                            0.0
       Material                       UZr
       Multiplicity                   271                            271
       Name                           fuel
       Outer Diameter (cm)            0.6029                         0.6086118601525807
[impt] <Circle: bond>
[impt] ---------------------------------------------------------------------------------------------
       Bond Dimensions -  Of First Fuel Block
                                      Tcold (447.0)                  Thot (447.0)
       ---------------------------------------------------------------------------------------------
       Inner Diameter (cm)            0.6029                         0.6086118601525807
       Material                       Sodium
       Multiplicity                   271                            271
       Name                           bond
       Outer Diameter (cm)            0.6962                         0.6996347645979837
       Thickness (cm)                 0.0466500                      0.0455115
[impt] <Hexagon: duct>
[impt] ---------------------------------------------------------------------------------------------
       Duct Dimensions -  Of First Fuel Block
                                      Tcold (25.0)                   Thot (450.0)
       ---------------------------------------------------------------------------------------------
       Inner Pitch (cm)               14.922                         14.995619013690193
       Material                       HT9
       Multiplicity                   1.0                            1.0
       Name                           duct
       Outer Pitch (cm)               15.71                          15.787506681749962
       Thickness (cm)                 0.3940000                      0.3959438
[impt] <Hexagon: intercoolant>
[impt] ---------------------------------------------------------------------------------------------
       Intercoolant Dimensions -  Of First Fuel Block
                                      Tcold (450.0)                  Thot (450.0)
       ---------------------------------------------------------------------------------------------
       Inner Pitch (cm)               15.71                          15.787506681749962
       Material                       Sodium
       Multiplicity                   1.0                            1.0
       Name                           intercoolant
       Outer Pitch (cm)               16.142                         16.142
       Thickness (cm)                 0.2160000                      0.1772467
[impt] <DerivedShape: coolant>
[impt] ---------------------------------------------------------------------------------------------
       Coolant Dimensions -  Of First Fuel Block
                                      Tcold (450.0)                  Thot (450.0)
       ---------------------------------------------------------------------------------------------
       Material                       Sodium
       Name                           coolant

5.3. Modifying the state of the reactor

Each object in the Reactor model has a bunch of state parameters contained in its special .p attribute, called its Parameter Collection. The state parameters are defined both by the ARMI framework and the collection of plugins. For instance, you can look at the core’s keff parameters or each individual block’s power and multi-group flux parameters like this:

[10]:
print(b.p.power)
print(core.p.keff)
print(b.p.mgFlux)
0.0
0.0
None

As you might expect, the values are zero because we have not performed any physics calculations yet. We could run a physics plugin at this point to add physics state, but for this tutorial, we’ll just apply dummy data. Here’s a fake physics kernel that just sets a power distribution based on spatial location of each block (e.g. a spherical distribution):

[11]:
import numpy as np
midplane = core[0].getHeight()/2.0
center = np.array([0,0,midplane])
peakPower = 1e6
mgFluxBase = np.arange(5)
def setFakePower(core):
    for a in core:
        for b in a:
            vol = b.getVolume()
            coords = b.spatialLocator.getGlobalCoordinates()
            r = np.linalg.norm(abs(coords-center))
            fuelFlag = 10 if b.isFuel() else 1.0
            b.p.power = peakPower / r**2 * fuelFlag
            b.p.pdens = b.p.power/vol
            b.p.mgFlux = mgFluxBase*b.p.pdens
setFakePower(core)
[12]:
print(b.p.power)
print(b.p.pdens)
381.5754294076418
0.08321687067850306
[13]:
import matplotlib.pyplot as plt
a = b.parent
z = [b.spatialLocator.getGlobalCoordinates()[2] for b in a]
power = a.getChildParamValues('power')
plt.plot(z,power,'.-')
plt.title("Fake power distribution on reactor")
[13]:
Text(0.5, 1.0, 'Fake power distribution on reactor')
../_images/tutorials_data_model_27_1.png

We can take a look at the spatial distribution as well:

[14]:
from armi.utils import plotting
# Note, if you were plotting outside jupyter, you could click
# on different depths at the bottom to view different axial planes.
plotting.plotBlockDepthMap(core, "power", depthIndex=5)
../_images/tutorials_data_model_29_0.png

5.4. Modifying number densities

Analysts frequently want to modify number densities. For example, if you needed to compute a coolant density coefficient, you could simply reduce the amount of coolant in the core.

[15]:
sodiumBefore = core.getMass('NA')
print(f"Before: {sodiumBefore/1e6:.2f} MT Sodium")
for b in core.getBlocks():      # loop through all blocks
    refDens = b.getNumberDensity('NA23')
    b.setNumberDensity('NA23',refDens*0.98) # reduce Na density by 2%
sodiumAfter = core.getMass('NA')
print(f"After:  {sodiumAfter/1e6:.2f} MT Sodium")
Before: 2.48 MT Sodium
After:  2.43 MT Sodium

If you analyze the keff with a physics plugin before and after, the change in the core.p.keff param would determine your density coefficient of reactivity.

5.5. Saving state to disk

During analysis, it’s often useful to save the reactor state to disk in a database. The ARMI database package handles this, and writes it out to an HDF-formatted file. This is typically done automatically at each point in time in a normal simulation, and can also be done manually, like this:

[16]:
dbi = o.getInterface("database")
dbi.initDB()
dbi.database.writeToDB(o.r)
[info] Opening database file at /home/runner/.armi/0-20220208184721138346/anl-afci-177.h5
[info] Writing to database for statepoint: /c00n00

5.6. Fuel management

One plugin that comes with the framework is the Fuel Handler. It attaches the Fuel Handler interface, which we can grab now to move fuel around. In a typical ARMI run, the detailed fuel management choices are specified by the user-input custom shuffle logic file. In this particular example, we will simply swap the 10 highest-power fuel assemblies with the 10 lowest-power ones.

[17]:
from armi.physics.fuelCycle import fuelHandlers
fh = fuelHandlers.fuelHandlerFactory(o)
[18]:
moved = []
for n in range(10):
    high = fh.findAssembly(param="power", compareTo=1.0e6, blockLevelMax=True, exclusions=moved)
    low = fh.findAssembly(param="power", compareTo=0.0, blockLevelMax=True, exclusions=moved)
    fh.swapAssemblies(high, low)
    moved.extend([high, low])
[19]:
plotting.plotBlockDepthMap(core, "power", depthIndex=5)
# You can also plot total assembly params, which are the sum of block params
plotting.plotFaceMap(core, "power", vals='sum')
../_images/tutorials_data_model_37_0.png
../_images/tutorials_data_model_37_1.png

We can write this new state to DB as well, since we’ve shuffled the fuel

[20]:
o.r.p.timeNode +=1
dbi.database.writeToDB(o.r)
dbi.database.close()
[info] Writing to database for statepoint: /c00n01

5.7. Loading from the database

Once you have a database, you can use it to load a Reactor object from any of the states that were written to it. First, create a Database3 object, then open it and call its load() method.

[21]:
from armi.bookkeeping import db
databaseLocation = "anl-afci-177.h5"
cycle, timeNode = 0, 1
dbo = db.databaseFactory(databaseLocation, "r")
with dbo:
    # Load a new reactor object from the requested cycle and time node
    r = dbo.load(cycle, timeNode)
[info] Loading reactor state for time node (0, 1)
[info] Applying <Migration from 0.1.2: Removes now-invalid `centers:` lines fro...
[info] Removing `centers:` sections.
[info] Applying <Migration from 0.1.2: Update elemental nuclide flags....
=========== Initializing Mesh, Assembly Zones, and Nuclide Categories ===========
[info] Nuclide categorization for cross section temperature assignments:
       ------------------  ------------------------------------------------------------
       Nuclide Category    Nuclides
       ------------------  ------------------------------------------------------------
       Fuel                U238, AM242, PU238, PU240, PU242, ZR92, LFP40, LFP41, PU236,
                           ZR91, DUMP2, DUMP1, PU239, NP238, CM246, U236, ZR96,
                           LFP38, CM242, CM244, ZR94, AM241, CM243, CM247, AM243,
                           ZR90, CM245, NP237, LFP35, U234, LFP39, PU241, U235
       Coolant             NA23
       Structure           MO94, FE56, MO100, NI62, FE54, NI61, FE57, NI64,
                           SI29, MO92, NI58, SI30, W182, NI60, SI28, MO95,
                           CR54, MO98, W184, V, CR52, CR53, MN55, MO96,
                           FE58, CR50, W186, B11, B10, C, MO97, W183
       ------------------  ------------------------------------------------------------
[info] The setting `splitZones` is enabled. Building subzones from core zones:
       --------  --------------------------  ----------  ------------  -----------------------------------------------------  ----------  ------
           Zone                              Original                                                                           Symmetry  Hot
         Number  Name                        Name          Assemblies  Locations                                                  Factor  Zone
       --------  --------------------------  ----------  ------------  -----------------------------------------------------  ----------  ------
              1  ring-1-radial-shield-1      ring-1                20  011-056, 011-057, 011-058, 011-059, 010-054,                    3  False
                                                                       010-001, 010-002, 011-003, 011-004, 011-005,
                                                                       011-006, 011-007, 011-008, 010-009, 011-009,
                                                                       010-011, 010-010, 011-015, 011-014, 011-013
              2  ring-1-radial-reflector-1   ring-1                30  009-045, 010-051, 009-046, 010-052, 009-047, 010-053,           3  False
                                                                       009-048, 008-001, 009-001, 009-002, 009-003, 010-003,
                                                                       009-004, 010-004, 009-005, 010-005, 009-006, 010-006,
                                                                       009-007, 010-007, 008-008, 009-008, 010-008, 009-012,
                                                                       009-011, 009-010, 009-009, 010-014, 010-013, 010-012
              3  ring-1-control-1            ring-1                 3  007-034, 004-004, 007-004                                       3  False
              4  ring-1-middle-core-fuel-7   ring-1                22  008-040, 005-023, 006-029, 005-024, 006-030, 005-001,           3  False
                                                                       006-001, 005-002, 006-002, 004-003, 005-003, 006-003,
                                                                       005-004, 006-004, 008-004, 005-006, 005-005,
                                                                       006-005, 006-008, 006-007, 006-006, 008-006
              5  ring-1-outer-core-fuel-7    ring-1                22  007-035, 003-012, 004-018, 007-036, 001-001, 002-001,           3  False
                                                                       003-001, 007-001, 002-002, 003-002, 004-002, 007-002,
                                                                       003-003, 007-003, 004-005, 007-005, 008-005,
                                                                       007-006, 007-009, 007-008, 007-007, 008-011
              6  ring-1-inner-fuel-7         ring-1                 7  008-041, 008-042, 008-002, 008-003,                             3  False
                                                                       008-007, 008-010, 008-009
              7  ring-1-ultimate-shutdown-1  ring-1                 1  004-001                                                         3  False
       --------  --------------------------  ----------  ------------  -----------------------------------------------------  ----------  ------

We can see that the time node is what we expect (node 1), and there is some fission product mass since we loaded from a cycle after a depletion step.

[22]:
print(r.p.timeNode)
print(o.r.getFissileMass())
1
908855.5902822559

Having a Reactor object by itself can be very useful for all sorts of post-processing tasks. However, sometimes we may wish initialize more ARMI components to do more advanced tasks and interactive follow-on analysis. Lucky for us, the database stores the settings that were used to run the case in the first place. We can get them like this:

[23]:
with dbo:
    cs = dbo.loadCS()
    print(cs["neutronicsKernel"])

With this CaseSettings object, we could create a brand new Case and Operator and do all sorts of magic. This way of interacting with ARMI is rather advanced, and beyond the scope of this tutorial.

That’s just a brief exploration of the data model. Hopefully it helped orient you to the underlying ARMI structure.