armi.bookkeeping.db package¶
The db package is responsible for reading and writing the state of the reactor to/from disk.
As an ARMI run progresses, this is periodically updated as the primary output file. It can also be an input file for follow-on analysis or restart runs.
The database can be visualized through various tools such as XTVIEW.
This module contains factories for selecting and building DB-related objects.
Some notes on versions¶
Persistent storage of ARMI models has seen many changes throughout the years. Calculation results were originally stored on a SQL database (version 1), which has been fully deprecated at this point.
Version 2 was the first to use HDF5 as the primary storage format. This was beneficial, as it did not rely on any external infrastructure to operate, and benefited from the suite of tools that help interact with HDF5 files. It was eventually replaced because it did not store a complete model of the reactor, but rather a ghost of assembly, block, and reactor parameters that could be applied to an existing reactor model (so long as the dimensions were consistent!). This led to loading reactors being inconvenient and error-prone, and also posed a limitation for representing more complex systems that have non-core components.
Version 3 was created to make the schema more flexible and to permit storing the entire reactor model within the HDF5 file. All objects in the ARMI Composite Model are written to the database, and the model can be recovered in its entirety just from the HDF5 file. Since it’s inception, it has seen a number of tweaks to improve its functionality and fix bugs.
Being a serialization format, the code associated with reading and writing database files may not benefit from Don’t Repeat Yourself (DRY) practices in the same way as other code. Therefore, we do not share much, if any, code between different major versions of the databases. As such, new major-versioned database implementations should exist in their own modules. Minor revisions (e.g. M.(N+1)) to the database structure should be simple enough that specialized logic can be used to support all minor versions without posing a maintenance burden. A detailed change log should be maintained of each minor revision.
- class armi.bookkeeping.db.Database3(fileName: os.PathLike, permission: str)[source]¶
Bases:
object
Version 3 of the ARMI Database, handling serialization and loading of Reactor states.
This implementation of the database pushes all objects in the Composite Reactor Model into the database. This process is aided by the
Layout
class, which handles the packing and unpacking of the structure of the objects, their relationships, and their non-parameter attributes.See also
doc/user/outputs/database for more details.
Create a new Database3 object.
- Parameters
fileName – name of the file
permission – file permissions, write (“w”) or read (“r”)
- timeNodeGroupPattern = re.compile('^c(\\d\\d)n(\\d\\d)$')¶
- property versionMajor¶
- property versionMinor¶
- static grabLocalCommitHash()[source]¶
Try to determine the local Git commit.
We have to be sure to handle the errors where the code is run on a system that doesn’t have Git installed. Or if the code is simply not run from inside a repo.
- Returns
The commit hash if it exists, otherwise “unknown”.
- Return type
- splitDatabase(keepTimeSteps: Sequence[Tuple[int, int]], label: str) str [source]¶
Discard all data except for specific time steps, retaining old data in a separate file.
This is useful when performing more exotic analyses, where each “time step” may not represent a specific point in time, but something more nuanced. For example, equilibrium cases store a new “cycle” for each iteration as it attempts to converge the equilibrium cycle. At the end of the run, the last “cycle” is the converged equilibrium cycle, whereas the previous cycles constitute the path to convergence, which we typically wish to discard before further analysis.
- Parameters
keepTimeSteps – A collection of the time steps to retain
label – An informative label for the backed-up database. Usually something like “-all-iterations”. Will be interposed between the source name and the “.h5” extension.
- Returns
The name of the new, backed-up database file.
- Return type
- property fileName¶
- loadCS()[source]¶
Attempt to load settings from the database file
Notes
There are no guarantees here. If the database was written from a different version of ARMI than you are using, these results may not be usable. For instance, the database could have been written from a vastly old or future version of ARMI from the code you are using.
- loadBlueprints()[source]¶
Attempt to load reactor blueprints from the database file
Notes
There are no guarantees here. If the database was written from a different version of ARMI than you are using, these results may not be usable. For instance, the database could have been written from a vastly old or future version of ARMI from the code you are using.
- loadGeometry()[source]¶
This is primarily just used for migrations. The “geometry files” were replaced by
systems:
andgrids:
sections ofBlueprints
.
- writeInputsToDB(cs, csString=None, geomString=None, bpString=None)[source]¶
Write inputs into the database based the CaseSettings.
This is not DRY on purpose. The goal is that any particular Database implementation should be very stable, so we dont want it to be easy to change one Database implementation’s behavior when trying to change another’s.
Notes
This is hard-coded to read the entire file contents into memory and write that directly into the database. We could have the cs/blueprints/geom write to a string, however the ARMI log file contains a hash of each files’ contents. In the future, we should be able to reproduce a calculation with confidence that the inputs are identical.
- mergeHistory(inputDB, startCycle, startNode)[source]¶
Copy time step data up to, but not including the passed cycle and node.
Notes
This is used for restart runs with the standard operator for example. The current time step (being loaded from) should not be copied, as that time steps data will be written at the end of the time step.
- genTimeStepGroups(timeSteps: Optional[Sequence[Tuple[int, int]]] = None) Generator[h5py._hl.group.Group, None, None] [source]¶
Returns a generator of HDF5 Groups for all time nodes, or for the passed selection.
- getLayout(cycle, node)[source]¶
Return a Layout object representing the requested cycle and time node.
- genTimeSteps() Generator[Tuple[int, int], None, None] [source]¶
Returns a generator of (cycle, node) tuples that are present in the DB.
- genAuxiliaryData(ts: Tuple[int, int]) Generator[str, None, None] [source]¶
Returns a generator of names of auxiliary data on the requested time point.
- getH5Group(r, statePointName=None)[source]¶
Get the H5Group for the current ARMI timestep.
This method can be used to allow other interfaces to place data into the database at the correct timestep.
- hasTimeStep(cycle, timeNode, statePointName='')[source]¶
Returns True if (cycle, timeNode, statePointName) is contained in the database.
Copy DB to run working directory.
Needed when multiple MPI processes need to read the same db, for example when a history is needed from independent runs (e.g. for fuel performance on a variety of assemblies).
Notes
At some future point, we may implement a client-server like DB system which would render this kind of operation unnecessary.
- load(cycle, node, cs=None, bp=None, statePointName=None, allowMissing=False, updateGlobalAssemNum=True)[source]¶
Load a new reactor from (cycle, node).
Case settings and blueprints can be provided by the client, or read from the database itself. Providing these from the client could be useful when performing snapshot runs or where it is expected to use results from a run using different settings and continue with new settings (or if blueprints are not on the database). Geom is read from the database itself.
- Parameters
cycle (int) – cycle number
node (int) – time node
cs (armi.settings.Settings (optional)) – if not provided one is read from the database
bp (armi.reactor.Blueprints (optional)) – if not provided one is read from the database
statePointName (str) – Optional arbitrary statepoint name (e.g., “special” for “c00n00-special/”)
allowMissing (bool) – Whether to emit a warning, rather than crash if reading a database with undefined parameters. Default False.
updateGlobalAssemNum (bool) – Whether to update the global assembly number to the value stored in r.core.p.maxAssemNum. Default True.
- Returns
root – The top-level object stored in the database; usually a Reactor.
- Return type
ArmiObject
- getHistoryByLocation(comp: armi.reactor.composites.ArmiObject, params: Optional[List[str]] = None, timeSteps: Optional[Sequence[Tuple[int, int]]] = None) Dict[str, Dict[Tuple[int, int], Any]] [source]¶
Get the parameter histories at a specific location.
- getHistoriesByLocation(comps: Sequence[armi.reactor.composites.ArmiObject], params: Optional[List[str]] = None, timeSteps: Optional[Sequence[Tuple[int, int]]] = None) Dict[armi.reactor.composites.ArmiObject, Dict[str, Dict[Tuple[int, int], Any]]] [source]¶
Get the parameter histories at specific locations.
- This has a number of limitations, which should in practice not be too limiting:
The passed objects must have IndexLocations. This type of operation doesn’t make much sense otherwise.
The passed objects must exist in a hierarchy that leads to a Core object, which serves as an anchor that can fully define all index locations. This could possibly be made more general by extending grids, but that gets a little more complicated.
All requested objects must exist under the same anchor object, and at the same depth below it.
All requested objects must have the same type.
- Parameters
comps (list of ArmiObject) – The components/composites that currently occupy the location that you want histories at. ArmiObjects are passed, rather than locations, because this makes it easier to figure out things related to layout.
params (List of str, optional) – The parameter names for the parameters that we want the history of. If None, all parameter history is given
timeSteps (List of (cycle, node) tuples, optional) – The time nodes that you want history for. If None, all available time nodes will be returned.
- getHistory(comp: armi.reactor.composites.ArmiObject, params: Optional[Sequence[str]] = None, timeSteps: Optional[Sequence[Tuple[int, int]]] = None) Dict[str, Dict[Tuple[int, int], Any]] [source]¶
Get parameter history for a single ARMI Object.
- Parameters
comps – An individual ArmiObject
params – parameters to gather
- Returns
Dictionary of str/list pairs.
- Return type
- getHistories(comps: Sequence[armi.reactor.composites.ArmiObject], params: Optional[Sequence[str]] = None, timeSteps: Optional[Sequence[Tuple[int, int]]] = None) Dict[armi.reactor.composites.ArmiObject, Dict[str, Dict[Tuple[int, int], Any]]] [source]¶
Get the parameter histories for a sequence of ARMI Objects.
This implementation is unaware of the state of the reactor outside of the database itself, and is therefore not usually what client code should be calling directly during normal ARMI operation. It only knows about historical data that have actually been written to the database. Usually one wants to be able to get historical, plus current data, for which the similar method on the DatabaseInterface may be more useful.
- Parameters
comps – Something that is iterable multiple times
params – parameters to gather.
timeSteps – Selection of time nodes to get data for. If omitted, return full history
- Returns
Dictionary ArmiObject (input): dict of str/list pairs containing ((cycle, node), value).
- Return type
- class armi.bookkeeping.db.DatabaseInterface(r, cs)[source]¶
Bases:
armi.interfaces.Interface
Handles interactions between the ARMI data model and the persistent data storage system.
This reads/writes the ARMI state to/from the database and helps derive state information that can be derived.
- name: Optional[str] = 'database'¶
The name of the interface. This is undefined for the base class, and must be overridden by any concrete class that extends this one.
- property database¶
Presents the internal database object, if it exists.
- interactBOL()[source]¶
Initialize the database if the main interface was not available. (Begining of Life)
- initDB(fName: Optional[os.PathLike] = None)[source]¶
Open the underlying database to be written to, and write input files to DB.
Notes
Main Interface calls this so that the database is available as early as possible in the run. The database interface interacts near the end of the interface stack (so that all the parameters have been updated) while the Main Interface interacts first.
- interactEveryNode(cycle, node)[source]¶
Write to database.
DBs should receive the state information of the run at each node.
- interactEOC(cycle=None)[source]¶
In case anything changed since last cycle (e.g. rxSwing), update DB. (End of Cycle)
- interactDistributeState() None [source]¶
Reconnect to pre-existing database.
DB is created and managed by the primary node only but we can still connect to it from workers to enable things like history tracking.
- prepRestartRun()[source]¶
Load the data history from the database requested in the case setting reloadDBName.
Reactor state is put at the cycle/node requested in the case settings startCycle and startNode, having loaded the state from all cycles prior to that in the requested database.
Notes
Mixing the use of simple vs detailed cycles settings is allowed, provided that the cycle histories prior to startCycle/startNode are equivalent.
- loadState(cycle, timeNode, timeStepName='', fileName=None, updateGlobalAssemNum=True)[source]¶
Loads a fresh reactor and applies it to the Operator.
Notes
Will load preferentially from the fileName if passed. Otherwise will load from existing database in memory or cs[“reloadDBName”] in that order.
- Raises
RuntimeError – If fileName is specified and that file does not have the time step. If fileName is not specified and neither the database in memory, nor the cs[“reloadDBName”] have the time step specified.
- getHistory(comp: armi.reactor.composites.ArmiObject, params: Optional[Sequence[str]] = None, timeSteps: Optional[MutableSequence[Tuple[int, int]]] = None, byLocation: bool = False) Dict[str, Dict[Tuple[int, int], Any]] [source]¶
Get historical parameter values for a single object.
This is mostly a wrapper around the same function on the
Database3
class, but knows how to return the current value as well.See also
- getHistories(comps: Sequence[armi.reactor.composites.ArmiObject], params: Optional[Sequence[str]] = None, timeSteps: Optional[MutableSequence[Tuple[int, int]]] = None, byLocation: bool = False) Dict[armi.reactor.composites.ArmiObject, Dict[str, Dict[Tuple[int, int], Any]]] [source]¶
Get historical parameter values for one or more objects.
This is mostly a wrapper around the same function on the
Database3
class, but knows how to return the current value as well.See also
- armi.bookkeeping.db.compareDatabases(refFileName: str, srcFileName: str, exclusions: Optional[Sequence[str]] = None, tolerance: float = 0.0) Optional[armi.bookkeeping.db.compareDB3.DiffResults] [source]¶
High-level method to compare two ARMI H5 files, given file paths.
- armi.bookkeeping.db.databaseFactory(dbName: str, permission: str, version: Optional[str] = None)[source]¶
Return an appropriate object for interacting with a database file.
- Parameters
Notes
This is not a proper factory, as the different database versions do not present a common interface. However, this is useful code, since it at least creates an object based on some knowledge of how to probe around. This allows client code to just interrogate the type of the returned object to figure out to do based on whatever it needs.
- class armi.bookkeeping.db.Permissions[source]¶
Bases:
object
Mappings to HDF5 permissions flags
- READ_ONLY_FME = 'r'¶
- READ_WRITE_FME = 'r+'¶
- CREATE_FILE_TIE = 'w'¶
- CREATE_FILE_FIE = 'w-'¶
- CREATE_FILE_FIE2 = 'x'¶
- READ_WRITE_CREATE = 'a'¶
- DEFAULT = 'a'¶
- read = {'r', 'r+'}¶
- write = {'a', 'r+', 'w', 'w-', 'x'}¶
- create = {'a', 'w', 'w-', 'x'}¶
- all = {'a', 'r', 'r+', 'w', 'w-', 'x'}¶
- armi.bookkeeping.db.convertDatabase(inputDBName: str, outputDBName: Optional[str] = None, outputVersion: Optional[str] = None, nodes: Optional[List[Tuple[int, int]]] = None)[source]¶
Convert database files between different versions.
- Parameters
inputDB – name of the complete hierarchy database
outputDB – name of the output database that should be consistent with XTView
outputVersion – version of the database to convert to. Defaults to latest version
nodes – optional list of specific (cycle,node)s to convert
- armi.bookkeeping.db.loadOperator(pathToDb, loadCycle, loadNode, allowMissing=False)[source]¶
Return an operator given the path to a database.
- Parameters
pathToDb (str) – The path of the database to load from.
loadCycle (int) – The cycle to load the reactor state from.
loadNode (int) – The time node to load the reactor from.
allowMissing (bool) – Whether to emit a warning, rather than crash if reading a database with undefined parameters. Default False.
See also
armi.operator.Operator.loadState
A method for loading reactor state that is useful if you already have an operator and a reactor object. loadOperator varies in that it supplies these given only a database file. loadState should be used if you are in the middle of an ARMI calculation and need load a different time step.
Notes
The operator will have a reactor attached that is loaded to the specified cycle and node. The operator will not be in the same state that it was at that cycle and node, only the reactor.
Examples
>>> o = db.loadOperator(r"pathToDatabase", 0, 1) >>> r = o.r >>> cs = o.cs >>> r.p.timeNode 1 >>> r.getFPMass() # Note since it is loaded from step 1 there are fission products. 12345.67