-
Notifications
You must be signed in to change notification settings - Fork 0
custom_tables
Agents are allowed to write their own custom output into the database during simulations. The interface for recording this data is accessible through the agent's :term:`context`. Data may be logged via the Context::NewDatum function:
C++:
MyReactor::Tick() {
...
double monthly_water = ...;
double monthly_op_cost = ...;
context()->NewDatum("MyReactorData")
->AddVal("AgentID", id())
->AddVal("Time", context()->time())
->AddVal("WaterUsage", monthl_water)
->AddVal("OperatingCost", monthly_op_cost)
->Record();
...
}
Python:
from cyclus.agents import Facility
import cyclus.typesystem as ts
class MyReactor(Facility):
def tick(self):
...
d = self.context.new_datum("MyReactorData")
d.add_val("AgentID", self.id, type=ts.INT)
d.add_val("Time", self.context.time, type=ts.INT)
d.add_val("WaterUsage", self.monthl_water, type=ts.DOUBLE)
d.add_val("OperatingCost", self.monthly_op_cost, type=ts.DOUBLE)
d.record()
...
This would create a table in the output database named "MyReactorData". The table would get a new row entry every time step with four columns named "AgentID", "Time", "WaterUsage" and "OperatingCost". "Add value" calls can be chained any number of times for an arbitrary number of columns. Record must be called once for each datum after all values have been added. Any custom tables created in this manner will appear in the output database alongside the |cyclus| core tables. Because there may be several agent instances of a single agent class, tables should generally include a column that adds their ID; and for similar reasons, it is often desirable to include the simulation time as a column in these tables:
C++:
context()->NewDatum("MyReactorData")
->AddVal("AgentID", id())
->AddVal("Time", context()->time())
->AddVal(...
...
Python:
d = self.context.new_datum("MyReactorData")
d.add_val("AgentID", self.id, type=ts.INT)
d.add_val("Time", self.context.time, type=ts.INT)
d.add_val(...
...
Datums with the same table name must have the same schema (e.g. same field names and value types). It is the responsibility of the developer to enforce this in their code.
Warning
Database formats only support a finite number of datum value-types. Do not add values to database tables that are not supported by the backend(s) in use. For information on which c++ types the backends support, you can check :doc:`here <dbtypes>`.
Note
If you require a datatype that isn't currently supported, please ask the kernel developers and they will help as soon as possible.
All added values can optionally take a std::vector<int>* shape argument that
is used as maximum dimensions for the value being added. The :doc:`dbtypes`
page lists the rank of the shape of different C++ types. A
std::vector<std::string>
has rank two - the first shape element being the
length of the vector, the second element being the length of each string in
the vector. When the shape argument is ommitted, the default is to treat all
elements in the value as variable-length. An entry of -1 in the shape
vector indicates variable length also. It is an error to pass in a shape
vector with the wrong rank (number of elements) for that type. An example of
using the shape vector follows:
C++:
std::vector<std::string> colors;
colors.push_back("green");
colors.push_back("blue");
colors.push_back("chartreuse");
std::vector<int> shape; // this should usually be a class member variable
shape->push_back(5); // maximum number of elements in the color vector
shape->push_back(8); // maximum character length of each color
context()->NewDatum("DecorPreferences")
->AddVal("AgentID", id())
->AddVal("Time", context()->time())
->AddVal("FavoriteColors", colors, shape)
->Record();
Python:
colors = ["green", "blue", "chartreuse"]
shape = [5, 8]
d = self.context.new_datum("DecorPreferences")
d.add_val("AgentID", self.id, type=ts.INT)
d.add_val("Time", self.context.time, type=ts.INT)
d.add_val("FavoriteColors", colors, shape, ts.VECTOR_STRING)
d.record()
In the example above, the "chartreuse" color is longer than the 8 characters specified in the shape. So it will be truncated to "chartreu" in the database. Shape vectors should generally be stored as class member variables to avoid excessive memory [de]allocation and should be set correctly from construction to destruction of your agent.
The |cyclus| kernel creates several of its own tables. The names of these tables are reserved, and you are responsible to avoid using them for custom table names. The reserved table names are (all case combos upper and lower):
-
all names starting with the prefixes:
- Cyclus
- Agent
- VL_
- Pair
- String
- Vector
- Map
- List
- Set
- Blob
-
Resources
-
Products
-
Transactions
-
Info
-
Finish
-
InputFiles
-
Prototypes
-
Recipes
-
Snapshots
-
MaterialInfo
-
Compositions
-
NextIds
-
ResCreators
-
CommodPriority
Warning
Table names may only contain alphanumeric characters and underscores and must not start with a number.