System¶
The System class provides a data store for components and time series data.
Refer to the System API for complete information.
Items to consider for parent packages¶
Composition vs Inheritance¶
Parent packages must choose one of the following:
Derive a custom System class that inherits from
infrasys.System. Re-implement methods as desired. Add custom attributes to the System that will be serialized to JSON.Reimplement
System.add_componentsin order to perform custom validation or custom behavior. This is only needed for validation that needs information from both the system and the component. Note that theSystemconstructor provides the keyword argumentauto_add_composed_componentsthat dictates how to handle the condition where a component contains another component which is not already attached to the system.Reimplement
System.serialize_system_attributesandSystem.deserialize_system_attributes.infrasyswill call those methods duringto_jsonandfrom_jsonand serialize/de-serialize the contents.Reimplement
System.data_format_versionandSystem.handle_data_format_upgrade.infrasyswill call the upgrade function if it detects a version change during de-serialization.
Implement an independent System class and compose the
infrasys.System. This can be beneficial if you want to make the underlying system opaque to users.This pattern requires that you call
System.to_json()with the keyword argumentdataset to a dictionary containing your system’s attributes.infrasyswill add its contents to a field calledsysteminside that dictionary.
Use
infrasys.Systemdirectly. This is probably not what most packages want because they will not be able to serialize custom attributes or implement specialized behavior as discussed above.
Units¶
infrasys uses the pint library to help manage units.
Package developers should consider storing fields that are quantities as subtypes of
Base.Quantity. Pint performs unit conversion automatically when performing
arithmetic.
If you want to be able to generate JSON schema for a model that contains a Pint quantity, you must add an annotation as shown below. Otherwise, Pydantic will raise an exception.
from pydantic import WithJsonSchema
from infrasys import Component
class ComponentWithPintQuantity(Component):
distance: Annotated[Distance, WithJsonSchema({"type": "string"})]
Component.model_json_schema()
Notes:
infrasysincludes some basic quantities in infrasys.quantities.Pint will automatically convert a list or list of lists of values into a
numpy.ndarray. infrasys will handle serialization/de-serialization of these types.
Component Associations¶
The system tracks associations between components in order to optimize lookups.
For example, suppose a Generator class has a field for a Bus. It is trivial to find a generator’s bus. However, if you need to find all generators connected to specific bus, you would have to traverse all generators in the system and check their bus values.
Every time you add a component to a system, infrasys inspects the component type for composed
components. It checks for directly connected components, such as Generator.bus, and lists of
components. (It does not inspect other composite data structures like dictionaries.)
infrasys stores these component associations in a SQLite table and so lookups are fast.
Here is how to complete this example:
generators = system.list_parent_components(bus)
If you only want to find specific types, you can pass that type as well.
generators = system.list_parent_components(bus, component_type=Generator)
Warning: There is one potentially problematic case.
Suppose that you have a system with generators and buses and then reassign the buses, as in
gen1.bus = other_bus
infrasys cannot detect such reassignments and so the component associations will be incorrect.
You must inform infrasys to rebuild its internal table.
system.rebuild_component_associations()