Serialization¶
This page describes how infrasys serializes a system and its components to JSON when a user calls
System.to_json() and System.from_json().
Components¶
infrasys converts its nested dictionaries of components-by-type into a flat array. Each component
records metadata about its actual Python type into a field called __metadata__. Here is an example
of a serialized Location object. Note that it includes the module and type. infrasys uses this
information during de-serialization to dynamically import the type and construct it. This allows
serialization to work with types defined outside of infrasys as long as the user has imported
those types.
{
"id": 1,
"name": "",
"x": 0.0,
"y": 0.0,
"crs": null,
"__metadata__": {
"module": "infrasys.location",
"type": "Location",
"serialized_type": "base"
}
}
Composed components¶
There are many cases where one component will contain an instance of another component. For example,
a Bus may contain a Location or a Generator may contain a Bus. When serializing each
component, infrasys checks the type of each of that component’s fields. If a value is another
component (which means that it must also be attached to system), infrasys replaces that instance
with its integer id. It does this to avoid duplicating data in the JSON file.
Here is an example of a serialized Bus. Note the value for the coordinates field. It contains the
type and id of the actual coordinates. During de-serialization, infrasys will detect this
condition and only attempt to de-serialize the bus once all Location instances have been
de-serialized.
{
"id": 2,
"name": "bus1",
"voltage": 1.1,
"__metadata__": {
"module": "tests.models.simple_system",
"type": "SimpleBus",
"serialized_type": "base"
},
"coordinates": {
"__metadata__": {
"module": "infrasys.location",
"type": "Location",
"serialized_type": "composed_component",
"id": 1
}
}
}
Denormalized component data¶
There are cases where users may prefer to have the full, denormalized JSON data for a component.
All components are of type pydantic.BaseModel and so implement the method model_dump_json.
Here is an example of a bus serialized that way (bus.model_dump_json(indent=2)):
{
"id": 2,
"name": "bus1",
"voltage": 1.1,
"coordinates": {
"id": 1,
"name": "",
"x": 0.0,
"y": 0.0,
"crs": null
}
}
Pint Quantities¶
infrasys encodes metadata into component JSON when that component contains a pint.Quantity
instance. Here is an example of such a component:
{
"id": 1,
"name": "test",
"__metadata__": {
"module": "tests.test_serialization",
"type": "ComponentWithPintQuantity",
"serialized_type": "base"
},
"distance": {
"value": 2,
"units": "meter",
"__metadata__": {
"module": "infrasys.quantities",
"type": "Distance",
"serialized_type": "quantity"
}
}
}
Time Series¶
infrasys stores all time series arrays and their metadata in the Rust-backed infrastore
backend (HDF5 arrays plus a SQLite database). When the user calls system.to_json(), infrasys
copies those store files into the user-specified directory alongside the JSON file.