armi.bookkeeping.db.database3 module¶
ARMI Database implementation, version 3.
This Implementation of the database is a significant departure from the previous. One of the foundational concepts in this version is that a reactor model should be fully recoverable from the database itself; 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, rather than an ad hoc collection of Block parameter fields and other parameters. Furthermore, this 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 most important contents of this module are the DatabaseInterface, the
Database3 class, the Layout class, and the special data
packing/unpacking functions. The Database3 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. When interacting with
the database file, the Layout class is used to help map the hierarchical Composite
Reactor Model to the flat representation in the database.
-
armi.bookkeeping.db.database3.describeInterfaces(cs)[source]¶ Function for exposing interface(s) to other code
-
class
armi.bookkeeping.db.database3.DatabaseInterface(r, cs)[source]¶ Bases:
armi.interfaces.InterfaceHandles 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.
Construct an interface.
The
randcsarguments are required, but may beNone, where appropriate for the specificInterfaceimplementation.- Parameters
- Raises
RuntimeError – Interfaces derived from Interface must define their name
-
name= 'database'¶
-
property
database¶ Presents the internal database object, if it exists.
-
initDB()[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.
-
distributable()[source]¶ Return true if this can be MPI broadcast.
Notes
Cases where this isn’t possible include the database interface, where the SQL driver cannot be distributed.
-
prepRestartRun(dbCycle, dbNode)[source]¶ Load the data history from the database being restarted from.
-
loadState(cycle, timeNode, timeStepName='', fileName=None, updateGlobalAssemNum=True)[source]¶ Loads a fresh reactor and applies it to the Operator.
Notes
timeStepName is not currently supportred by database load. 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) → 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
Database3class, 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) → 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 fumction on the
Database3class, but knows how to return the current value as well.See also
-
class
armi.bookkeeping.db.database3.Database3(fileName: str, permission: str)[source]¶ Bases:
armi.bookkeeping.db.database.DatabaseVersion 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
Layoutclass, 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”)
-
version= '3'¶
-
timeNodeGroupPattern= re.compile('^c(\\d\\d)n(\\d\\d)$')¶
-
close(completedSuccessfully=False)[source]¶ Close the DB and perform cleanups and auto-conversions.
Notes
Visualization tools like XTVIEW are still using DB format 2, so this will (for now) auto-generate a full XTVIEW-compatible database upon closing. It does this here because, in remote runs, this is where the I/O is fastest.
-
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¶
-
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 will be able to reproduce calculation showing 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.
-
__exit__(type, value, traceback)[source]¶ Typically we don’t care why it broke but we want the DB to close
-
genTimeStepGroups(timeSteps: 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.
-
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.
-
getAuxiliaryDataPath(ts: Tuple[int, int], name: str) → str[source]¶ Get a string describing a path to an auxiliary data location.
- Parameters
ts – The time step that the auxiliary data belongs to
name – The name of the auxiliary data
- Returns
An absolute location for storing auxiliary data with the given name for the given time step
- Return type
str
-
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.
-
load(cycle, node, cs=None, bp=None, geom=None)[source]¶ Load a new reactor from (cycle, node).
Case settings, blueprints, and geom 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 the like, where it is expected to use results from a run using different settings, then continue with new settings. Even in this case, the blueprints and geom should probably be the same as the original run.
- 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
geom (armi.geometry.Geometry (Optional)) – if not provided one is read from the database
-
getHistory(comp: armi.reactor.composites.ArmiObject, params: Sequence[str] = None, timeSteps: 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[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. It only knows about historical data that actually exists in the database. Usually one wants to be able to get historical, plus current data, for which the similar method on the DatabaseInterface is 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
-
class
armi.bookkeeping.db.database3.Layout(h5group=None, comp=None)[source]¶ Bases:
objectThe Layout class describes the hierarchical layout of the composite structure in a flat representation.
A Layout is built up by starting at the root of a composite tree and recursively appending each node in the tree to the list of data. So for a typical Reactor model, the data will be ordered something like [r, c, a1, a1b1, a1b1c1, a1b1c2, a1b2, a1b2c1, …, a2, …]
The layout is also responsible for storing Component attributes, like location, material, and temperatures (from blueprints), which aren’t stored as Parameters. Temperatures, specifically, are rather complicated beasts in ARMI, and more fundamental changes to how we deal with them may allow us to remove them from Layout.
-
armi.bookkeeping.db.database3.allSubclasses(cls)[source]¶ This currently include Materials… and it should not.
-
armi.bookkeeping.db.database3.packSpecialData(data: numpy.ndarray, paramName: str) → Tuple[Optional[numpy.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,
datawould 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 allinstances, 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
Nonein them: These are stored by replacing each instance ofNonewith a magical value that shouldn’t be encountered in realistic scenarios.
- Parameters
data – An ndarray storing the data that we want to stuff into the database. These are usually dtype=Object, which is how we usually end up here in the first place.
paramName – The parameter name that we are trying to store data for. This is mostly used for diagnostics.
See also
-
armi.bookkeeping.db.database3.unpackSpecialData(data: numpy.ndarray, attrs, paramName: str) → numpy.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
numpy.ndarray
See also
-
armi.bookkeeping.db.database3.replaceNonsenseWithNones(data: numpy.ndarray, paramName: str) → numpy.ndarray[source]¶ Replace special nonsense values with
None.This essentially reverses the operations performed by
replaceNonesWithNonsense().- Parameters
data – The array from the database that contains special
Nonenonsense values.paramName – The param name who’s data we are dealing with. Only used for diagnostics.
See also
-
armi.bookkeeping.db.database3.replaceNonesWithNonsense(data: numpy.ndarray, paramName: str, nones: numpy.ndarray = None) → numpy.ndarray[source]¶ Replace instances of
Nonewith nonsense values that can be detected/recovered when reading.- Parameters
data – The numpy array containing
Nonevalues that need to be replaced.paramName – The name of the parameter who’s data we are treating. Only used for diagnostics.
nones – An array containing the index locations on the
Noneelements. It is a little strange to pass these, in but we find these indices to determine whether we need to call this function in the first place, so might as well pass it in, so that we don’t need to perform the operation again.
Notes
This only supports situations where the data is a straight-up
None, or a valid, database-storable numpy array (or easily convertable to one (e.g. tuples/lists with numerical values)). This does not support, for instance, a numpy ndarray with some Nones in it.For example, the following is supported:
[[1, 2, 3], None, [7, 8, 9]]
However, the following is not:
[[1, 2, 3], [4, None, 6], [7, 8, 9]]
See also
replaceNonsenseWithNones()Reverses this operation.