GDM Structure#

GDM currently implements Infrasys systems in three different ways:

  • DistributionSystem: A system of models needed to create a power flow model.

  • CatalogSystem: A set of equipment models (e.g., imagine a vendor catalog of transformers).

  • StructuralSystem: Represents distribution components necessary for making distribution networks, excluding those used in powerflow models (e.g., guy wires, poles junction boxes needed for resilience analysis).

DistributionSystem and CatalogSystem can be imported from gdm.distribution.

from gdm.distribution import DistributionSystem, CatalogSystem
/opt/homebrew/Caskroom/miniconda/base/envs/gdm2/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(

There are three types of data model definitions in GDM:

  • Components: These models represent physical assets 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 special types of components that are referenced multiple times by components. For example, 1/0 aluminum wire is a type of equipment that may be used by multiple distribution line components.

  • Controllers: These are special types of components that manage the state of a component. For example, a capacitor controller controls whether a capacitor is switched on or off.

from gdm.distribution.components import DistributionBus, DistributionLoad
from gdm.distribution.equipment import LoadEquipment, PhaseLoadEquipment
from gdm.distribution.controllers import *

Component Examples#

All data models have an example method that returns an example instance. These can be used to help debug, initialize or build quick and dirty examples. The pprint method can be used on an instance to “pretty-print” a model. In the example below, bus and load example components are instantiated and connected.

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#

Models can be added to a DistributionSystem using the add_component and add_components methods. Setting auto_add_composed_components to True can help with adding nested models. For example, DistributionBus is a nested component in the DistributionLoad component that was created above. Using auto_add_composed_components avoids a separate add_component function call for the DistributionBusand other components.

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 │
└────────────────────────┴───────┘

Exploring GDM Systems#

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