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()