armi.bookkeeping.db.database module

ARMI Database implementation, version 3.4.

A reactor model should be fully recoverable from the database; all the way down to the component level. As a result, the structure of the underlying data is bound to the hierarchical Composite Reactor Model. Furthermore, this database format is intended to be more dynamic, permitting as-yet undeveloped levels and classes in the Composite Reactor Model to be supported as they are added. More high-level discussion is contained in The Database File.

The Database class contains most of the functionality for interacting with the underlying data. This includes things like dumping a Reactor state to the database and loading it back again, as well as extracting historical data for a given object or collection of object from the database file. However, for the nitty-gritty details of how the hierarchical Composite Reactor Model is translated to the flat file database, please refer to armi.bookkeeping.db.layout.

Refer to armi.bookkeeping.db for information about versioning.

armi.bookkeeping.db.database.getH5GroupName(cycle: int, timeNode: int, statePointName: Optional[str] = None) str[source]

Naming convention specifier.

ARMI defines the naming convention cXXnYY for groups of simulation data. That is, data is grouped by cycle and time node information during a simulated run.

class armi.bookkeeping.db.database.Database(fileName: PathLike, permission: str)[source]

Bases: object

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 Database object.

Parameters:
  • fileName – name of the file

  • permission – file permissions, write (“w”) or read (“r”)

timeNodeGroupPattern = re.compile('^c(\\d\\d)n(\\d\\d).*$')
h5db: Optional[File]
property version: str
property versionMajor
property versionMinor
open()[source]
isOpen()[source]
static writeSystemAttributes(h5db)[source]

Write system attributes to the database.

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:

str

close(completedSuccessfully=False)[source]

Close the DB and perform cleanups and auto-conversions.

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:

str

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: and grids: sections of Blueprints.

writeInputsToDB(cs, csString=None, geomString=None, bpString=None)[source]

Write inputs into the database based the Settings.

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.

readInputsFromDB()[source]
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[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.

static getAuxiliaryDataPath(ts: Tuple[int, int], name: str) str[source]
keys()[source]
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.

writeToDB(reactor, statePointName=None)[source]
syncToSharedFolder()[source]

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)[source]

Load a new reactor from a DB at (cycle, node).

Case settings and blueprints can be provided, or read from the database. Providing these can be useful for snapshot runs or when you want to change settings mid-simulation. Geometry is read from the database.

Parameters:
  • cycle (int) – Cycle number

  • node (int) – Time node. If value is negative, will be indexed from EOC backwards like a list.

  • 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) – Statepoint name (e.g., “special” for “c00n00-special/”)

  • allowMissing (bool, optional) – Whether to emit a warning, rather than crash if reading a database with undefined parameters. Default False.

Returns:

root – The top-level object stored in the database; a Reactor.

Return type:

Reactor

loadReadOnly(cycle, node, statePointName=None)[source]

Load a new reactor, in read-only mode from a DB at (cycle, node).

Parameters:
  • cycle (int) – Cycle number

  • node (int) – Time node. If value is negative, will be indexed from EOC backwards like a list.

  • statePointName (str, optional) – Statepoint name (e.g., “special” for “c00n00-special/”)

Returns:

The top-level object stored in the database; a Reactor.

Return type:

Reactor

getHistoryByLocation(comp: 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[ArmiObject], params: Optional[List[str]] = None, timeSteps: Optional[Sequence[Tuple[int, int]]] = None) Dict[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: 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:

dict

getHistories(comps: Sequence[ArmiObject], params: Optional[Sequence[str]] = None, timeSteps: Optional[Sequence[Tuple[int, int]]] = None) Dict[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:

dict

armi.bookkeeping.db.database.packSpecialData(arrayData: [<class 'numpy.ndarray'>, <class 'armi.bookkeeping.db.jaggedArray.JaggedArray'>], paramName: str) Tuple[Optional[ndarray], Dict[str, Any]][source]

Reduce data that wouldn’t otherwise play nicely with HDF5/numpy arrays to a format that will.

This is the main entry point for conforming “strange” data into something that will both fit into a numpy array/HDF5 dataset, and be recoverable to its original-ish state when reading it back in. This is accomplished by detecting a handful of known offenders and using various HDF5 attributes to store necessary auxiliary data. It is important to keep in mind that the data that is passed in has already been converted to a numpy array, so the top dimension is always representing the collection of composites that are storing the parameters. For instance, if we are dealing with a Block parameter, the first index in the numpy array of data is the block index; so if each block has a parameter that is a dictionary, data would be a ndarray, where each element is a dictionary. This routine supports a number of different “strange” things:

  • Dict[str, float]: These are stored by finding the set of all keys for all instances, and storing those keys as a list in an attribute. The data themselves are stored as arrays indexed by object, then key index. Dictionaries lacking data for a key store a nan in it’s place. This will work well in instances where most objects have data for most keys.

  • Jagged arrays: These are stored by concatenating all of the data into a single, one-dimensional array, and storing attributes to describe the shapes of each object’s data, and an offset into the beginning of each object’s data.

  • Arrays with None in them: These are stored by replacing each instance of None with a magical value that shouldn’t be encountered in realistic scenarios.

Parameters:
  • arrayData – An ndarray or JaggedArray object storing the data that we want to stuff into the database. If the data is jagged, a special JaggedArray instance is passed in, which contains a 1D array with offsets and shapes.

  • paramName – The parameter name that we are trying to store data for. This is mostly used for diagnostics.

armi.bookkeeping.db.database.unpackSpecialData(data: ndarray, attrs, paramName: str) ndarray[source]

Extract data from a specially-formatted HDF5 dataset into a numpy array.

This should invert the operations performed by packSpecialData().

Parameters:
  • data – Specially-formatted data array straight from the database.

  • attrs – The attributes associated with the dataset that contained the data.

  • paramName – The name of the parameter that is being unpacked. Only used for diagnostics.

Returns:

An ndarray containing the closest possible representation of the data that was originally written to the database.

Return type:

np.ndarray

See also

packSpecialData

armi.bookkeeping.db.database.collectBlockNumberDensities(blocks) Dict[str, ndarray][source]

Collect block-by-block homogenized number densities for each nuclide.

Long ago, composition was stored on block params. No longer; they are on the component numberDensity params. These block-level params, are still useful to see compositions in some visualization tools. Rather than keep them on the reactor model, we dynamically compute them here and slap them in the database. These are ignored upon reading and will not affect the results.

Remove this once a better viz tool can view composition distributions. Also remove the try/except in _readParams