On GDM Data Models#
GDM currently implements three Infrasys
systems. Each system is a collection of model definitions:
DistributionSystem: Represents a complete power flow model.
CatalogSystem: A catalog of valid electrical equipment definitions (imagine a vendor catalog).
StructuralSystem: Represents structural definitions for distribution components, used for resilience-type studies (e.g., guy wires, junction boxes, etc.).
DistributionSystem and CatalogSystem can be imported from gdm.distribution
.
from gdm.distribution import DistributionSystem, CatalogSystem
/opt/hostedtoolcache/Python/3.12.10/x64/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py:502: UserWarning: Ellipsis is not a Python type (it may be an instance of an object), Pydantic will allow any object with no validation since we cannot even enforce that the input is an instance of the given type. To get rid of this error wrap the type with `pydantic.SkipValidation`.
warn(
Distribution models consist of three types of data model definitions:
Components: These models represent physical equipment on the distribution system. They include:
Bus connectivity (e.g., load connection to a bus)
Model state (e.g., state of switches)
Model specifics (e.g., length of a line section)
Equipment: The equipment model this component maps to
Controller: Controller settings for the connected equipment, which can be None
Equipment: These are specific model definitions for equipment. They may be referenced in multiple component definitions.
Controllers: These are controller definitions.
from gdm.distribution.components import DistributionBus, DistributionLoad
from gdm.distribution.equipment import LoadEquipment, PhaseLoadEquipment
from gdm.distribution.controllers import *
Data Model Examples#
All data models have an example
method that returns an example instance. These can be used to help debug or build quick and dirty examples. The pprint
method can be used on an instance to pretty-print a model.
bus = DistributionBus.example()
load = DistributionLoad.example()
load.bus = bus
bus.pprint()
DistributionBus( name='DistBus1', substation=DistributionSubstation(name='Test Substation', feeders=[DistributionFeeder(name='Test Feeder')]), feeder=DistributionFeeder(name='Test Feeder'), voltage_type=<VoltageTypes.LINE_TO_LINE: 'line-to-line'>, phases=[<Phase.A: 'A'>, <Phase.B: 'B'>, <Phase.C: 'C'>], voltagelimits=[ VoltageLimitSet(name='', limit_type=<LimitType.MIN: 'min'>, value=<Quantity(360.0, 'volt')>), VoltageLimitSet(name='', limit_type=<LimitType.MAX: 'max'>, value=<Quantity(440.0, 'volt')>) ], rated_voltage=<Quantity(400, 'volt')>, coordinate=Location(name='', x=20.0, y=30.0, crs=None) )
Building a System#
Once all models are built, they can be added to a DistributionSystem using the add_component
and add_components
methods. Set auto_add_composed_components
to True if you have nested models not already added to the system. In our example, we have a DistributionBus
nested in a DistributionLoad
component.
system = DistributionSystem(auto_add_composed_components = True)
system.add_component(load)
system.info()
System ┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓ ┃ Property ┃ Value ┃ ┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━┩ │ System name │ │ │ Data format version │ 2.0.1 │ │ Components attached │ 13 │ │ Time Series attached │ 0 │ │ Description │ │ └──────────────────────┴───────┘
Component Information ┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓ ┃ Type ┃ Count ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━┩ │ DistributionBus │ 1 │ │ DistributionFeeder │ 4 │ │ DistributionLoad │ 1 │ │ DistributionSubstation │ 2 │ │ LoadEquipment │ 1 │ │ Location │ 1 │ │ PhaseLoadEquipment │ 1 │ │ VoltageLimitSet │ 2 │ └────────────────────────┴───────┘
Working with Systems#
All system interfaces provide helper functions to explore system models.
from gdm.distribution.components import DistributionCapacitor
capacitor = DistributionCapacitor.example()
has_bus = system.has_component(bus)
print(f"{has_bus=}")
has_capacitor= system.has_component(capacitor)
print(f"{has_capacitor=}")
has_bus=True
has_capacitor=False
Data models can be retrieved from the system using the get_component
and get_components
methods. These methods can also utilize filter functions to offer powerful filtering capabilities to users.
buses = system.get_components(DistributionBus)
for bus in buses:
bus.pprint()
DistributionBus( name='DistBus1', substation=DistributionSubstation(name='Test Substation', feeders=[DistributionFeeder(name='Test Feeder')]), feeder=DistributionFeeder(name='Test Feeder'), voltage_type=<VoltageTypes.LINE_TO_LINE: 'line-to-line'>, phases=[<Phase.A: 'A'>, <Phase.B: 'B'>, <Phase.C: 'C'>], voltagelimits=[ VoltageLimitSet(name='', limit_type=<LimitType.MIN: 'min'>, value=<Quantity(360.0, 'volt')>), VoltageLimitSet(name='', limit_type=<LimitType.MAX: 'max'>, value=<Quantity(440.0, 'volt')>) ], rated_voltage=<Quantity(400, 'volt')>, coordinate=Location(name='', x=20.0, y=30.0, crs=None) )
buses = system.get_components(DistributionBus, filter_func=lambda x: x.name=="not valid name")
for bus in buses:
bus.pprint()