powerio.dist

Multiconductor distribution network values.

The typed model uses wire coordinates. Supported formats are OpenDSS .dss, PowerModelsDistribution ENGINEERING JSON (pmd-json), and BMOPF JSON (bmopf-json). Same format emissions can return retained source bytes. Cross format emissions report unsupported fields as diagnostics.

import powerio

module = powerio.parse("feeder.dss")
net = module.value
for diagnostic in module.diagnostics:
    print("parse:", diagnostic)
conv = powerio.emit(module, "pmd-json")
  1"""Multiconductor distribution network values.
  2
  3The typed model uses wire coordinates. Supported formats are OpenDSS ``.dss``,
  4PowerModelsDistribution ENGINEERING JSON (``pmd-json``), and BMOPF JSON
  5(``bmopf-json``). Same format emissions can return retained source bytes. Cross
  6format emissions report unsupported fields as diagnostics.
  7
  8    import powerio
  9
 10    module = powerio.parse("feeder.dss")
 11    net = module.value
 12    for diagnostic in module.diagnostics:
 13        print("parse:", diagnostic)
 14    conv = powerio.emit(module, "pmd-json")
 15"""
 16
 17from __future__ import annotations
 18
 19import json as _json
 20from typing import Any, Optional
 21
 22from ._guard import guard_class as _guard_class
 23
 24__all__ = ["MulticonductorNetwork"]
 25
 26
 27@_guard_class
 28class MulticonductorNetwork:
 29    """A parsed multiconductor distribution network in wire coordinates.
 30
 31    Buses carry named terminals, lines carry conductor impedance matrices, and
 32    transformers carry per winding connections. This type is distinct from the
 33    positive sequence :class:`powerio.BalancedNetwork`; balanced matrix calculations do not
 34    accept it.
 35    """
 36
 37    def __init__(self, inner) -> None:
 38        self._inner = inner
 39
 40    @property
 41    def name(self) -> Optional[str]:
 42        """Distribution network name when the source format carries one."""
 43        return self._inner.name()
 44
 45    @property
 46    def source_format(self) -> Optional[str]:
 47        """Format parsed from: ``dss``, ``pmd-json``, or ``bmopf-json``."""
 48        return self._inner.source_format()
 49
 50    @property
 51    def base_frequency(self) -> float:
 52        """System base frequency in hertz."""
 53        return self._inner.base_frequency()
 54
 55    @property
 56    def n_buses(self) -> int:
 57        return self._inner.n_buses()
 58
 59    @property
 60    def n_lines(self) -> int:
 61        return self._inner.n_lines()
 62
 63    @property
 64    def n_line_codes(self) -> int:
 65        return self._inner.n_line_codes()
 66
 67    @property
 68    def n_switches(self) -> int:
 69        return self._inner.n_switches()
 70
 71    @property
 72    def n_transformers(self) -> int:
 73        return self._inner.n_transformers()
 74
 75    @property
 76    def n_loads(self) -> int:
 77        return self._inner.n_loads()
 78
 79    @property
 80    def n_generators(self) -> int:
 81        return self._inner.n_generators()
 82
 83    @property
 84    def n_ibrs(self) -> int:
 85        return self._inner.n_ibrs()
 86
 87    @property
 88    def n_control_profiles(self) -> int:
 89        return self._inner.n_control_profiles()
 90
 91    @property
 92    def n_shunts(self) -> int:
 93        return self._inner.n_shunts()
 94
 95    @property
 96    def n_capacitors(self) -> int:
 97        return self._inner.n_capacitors()
 98
 99    @property
100    def n_voltage_sources(self) -> int:
101        """Number of grid forming voltage sources."""
102        return self._inner.n_voltage_sources()
103
104    @property
105    def n_untyped_objects(self) -> int:
106        return self._inner.n_untyped_objects()
107
108    # These properties are copies of the native model tables. Nested field
109    # names come from the Rust model's serialization, so this wrapper does not
110    # maintain a second distribution schema.
111
112    @property
113    def buses(self) -> "list[dict[str, Any]]":
114        return self._inner.buses()
115
116    @property
117    def line_codes(self) -> "list[dict[str, Any]]":
118        return self._inner.line_codes()
119
120    @property
121    def lines(self) -> "list[dict[str, Any]]":
122        return self._inner.lines()
123
124    @property
125    def switches(self) -> "list[dict[str, Any]]":
126        return self._inner.switches()
127
128    @property
129    def transformers(self) -> "list[dict[str, Any]]":
130        return self._inner.transformers()
131
132    @property
133    def loads(self) -> "list[dict[str, Any]]":
134        return self._inner.loads()
135
136    @property
137    def generators(self) -> "list[dict[str, Any]]":
138        return self._inner.generators()
139
140    @property
141    def ibrs(self) -> "list[dict[str, Any]]":
142        return self._inner.ibrs()
143
144    @property
145    def control_profiles(self) -> "list[dict[str, Any]]":
146        return self._inner.control_profiles()
147
148    @property
149    def shunts(self) -> "list[dict[str, Any]]":
150        return self._inner.shunts()
151
152    @property
153    def capacitors(self) -> "list[dict[str, Any]]":
154        return self._inner.capacitors()
155
156    @property
157    def voltage_sources(self) -> "list[dict[str, Any]]":
158        return self._inner.voltage_sources()
159
160    @property
161    def untyped_objects(self) -> "list[dict[str, Any]]":
162        return self._inner.untyped_objects()
163
164    def to_graph(self) -> Any:
165        """Transform the network to collapsed bus and terminal graph data."""
166        return _json.loads(self._inner.graph_json())
167
168    def to_geo_layer(self) -> Any:
169        """Transform coordinates to a canonical GeoJSON FeatureCollection.
170
171        A network without coordinates produces an empty feature collection.
172        """
173        return _json.loads(self._inner.to_geo_layer_json())
174
175    def apply_geo_layer(
176        self, text: str, name_hint: Optional[str] = None
177    ) -> tuple["MulticonductorNetwork", Any]:
178        """Apply a geographic sidecar and return ``(placed, report)``.
179
180        ``text`` is any form :func:`powerio.parse_geo` accepts. This network
181        is unchanged; the placed copy drops the retained source text, so a
182        same-format emission re-serializes.
183        """
184        inner, report = self._inner.apply_geo_layer(text, name_hint)
185        return MulticonductorNetwork(inner), report
186
187    def __repr__(self) -> str:
188        return self._inner.__repr__()
class MulticonductorNetwork:
 28@_guard_class
 29class MulticonductorNetwork:
 30    """A parsed multiconductor distribution network in wire coordinates.
 31
 32    Buses carry named terminals, lines carry conductor impedance matrices, and
 33    transformers carry per winding connections. This type is distinct from the
 34    positive sequence :class:`powerio.BalancedNetwork`; balanced matrix calculations do not
 35    accept it.
 36    """
 37
 38    def __init__(self, inner) -> None:
 39        self._inner = inner
 40
 41    @property
 42    def name(self) -> Optional[str]:
 43        """Distribution network name when the source format carries one."""
 44        return self._inner.name()
 45
 46    @property
 47    def source_format(self) -> Optional[str]:
 48        """Format parsed from: ``dss``, ``pmd-json``, or ``bmopf-json``."""
 49        return self._inner.source_format()
 50
 51    @property
 52    def base_frequency(self) -> float:
 53        """System base frequency in hertz."""
 54        return self._inner.base_frequency()
 55
 56    @property
 57    def n_buses(self) -> int:
 58        return self._inner.n_buses()
 59
 60    @property
 61    def n_lines(self) -> int:
 62        return self._inner.n_lines()
 63
 64    @property
 65    def n_line_codes(self) -> int:
 66        return self._inner.n_line_codes()
 67
 68    @property
 69    def n_switches(self) -> int:
 70        return self._inner.n_switches()
 71
 72    @property
 73    def n_transformers(self) -> int:
 74        return self._inner.n_transformers()
 75
 76    @property
 77    def n_loads(self) -> int:
 78        return self._inner.n_loads()
 79
 80    @property
 81    def n_generators(self) -> int:
 82        return self._inner.n_generators()
 83
 84    @property
 85    def n_ibrs(self) -> int:
 86        return self._inner.n_ibrs()
 87
 88    @property
 89    def n_control_profiles(self) -> int:
 90        return self._inner.n_control_profiles()
 91
 92    @property
 93    def n_shunts(self) -> int:
 94        return self._inner.n_shunts()
 95
 96    @property
 97    def n_capacitors(self) -> int:
 98        return self._inner.n_capacitors()
 99
100    @property
101    def n_voltage_sources(self) -> int:
102        """Number of grid forming voltage sources."""
103        return self._inner.n_voltage_sources()
104
105    @property
106    def n_untyped_objects(self) -> int:
107        return self._inner.n_untyped_objects()
108
109    # These properties are copies of the native model tables. Nested field
110    # names come from the Rust model's serialization, so this wrapper does not
111    # maintain a second distribution schema.
112
113    @property
114    def buses(self) -> "list[dict[str, Any]]":
115        return self._inner.buses()
116
117    @property
118    def line_codes(self) -> "list[dict[str, Any]]":
119        return self._inner.line_codes()
120
121    @property
122    def lines(self) -> "list[dict[str, Any]]":
123        return self._inner.lines()
124
125    @property
126    def switches(self) -> "list[dict[str, Any]]":
127        return self._inner.switches()
128
129    @property
130    def transformers(self) -> "list[dict[str, Any]]":
131        return self._inner.transformers()
132
133    @property
134    def loads(self) -> "list[dict[str, Any]]":
135        return self._inner.loads()
136
137    @property
138    def generators(self) -> "list[dict[str, Any]]":
139        return self._inner.generators()
140
141    @property
142    def ibrs(self) -> "list[dict[str, Any]]":
143        return self._inner.ibrs()
144
145    @property
146    def control_profiles(self) -> "list[dict[str, Any]]":
147        return self._inner.control_profiles()
148
149    @property
150    def shunts(self) -> "list[dict[str, Any]]":
151        return self._inner.shunts()
152
153    @property
154    def capacitors(self) -> "list[dict[str, Any]]":
155        return self._inner.capacitors()
156
157    @property
158    def voltage_sources(self) -> "list[dict[str, Any]]":
159        return self._inner.voltage_sources()
160
161    @property
162    def untyped_objects(self) -> "list[dict[str, Any]]":
163        return self._inner.untyped_objects()
164
165    def to_graph(self) -> Any:
166        """Transform the network to collapsed bus and terminal graph data."""
167        return _json.loads(self._inner.graph_json())
168
169    def to_geo_layer(self) -> Any:
170        """Transform coordinates to a canonical GeoJSON FeatureCollection.
171
172        A network without coordinates produces an empty feature collection.
173        """
174        return _json.loads(self._inner.to_geo_layer_json())
175
176    def apply_geo_layer(
177        self, text: str, name_hint: Optional[str] = None
178    ) -> tuple["MulticonductorNetwork", Any]:
179        """Apply a geographic sidecar and return ``(placed, report)``.
180
181        ``text`` is any form :func:`powerio.parse_geo` accepts. This network
182        is unchanged; the placed copy drops the retained source text, so a
183        same-format emission re-serializes.
184        """
185        inner, report = self._inner.apply_geo_layer(text, name_hint)
186        return MulticonductorNetwork(inner), report
187
188    def __repr__(self) -> str:
189        return self._inner.__repr__()

A parsed multiconductor distribution network in wire coordinates.

Buses carry named terminals, lines carry conductor impedance matrices, and transformers carry per winding connections. This type is distinct from the positive sequence powerio.BalancedNetwork; balanced matrix calculations do not accept it.

MulticonductorNetwork(inner)
38    def __init__(self, inner) -> None:
39        self._inner = inner
name: Optional[str]
41    @property
42    def name(self) -> Optional[str]:
43        """Distribution network name when the source format carries one."""
44        return self._inner.name()

Distribution network name when the source format carries one.

source_format: Optional[str]
46    @property
47    def source_format(self) -> Optional[str]:
48        """Format parsed from: ``dss``, ``pmd-json``, or ``bmopf-json``."""
49        return self._inner.source_format()

Format parsed from: dss, pmd-json, or bmopf-json.

base_frequency: float
51    @property
52    def base_frequency(self) -> float:
53        """System base frequency in hertz."""
54        return self._inner.base_frequency()

System base frequency in hertz.

n_buses: int
56    @property
57    def n_buses(self) -> int:
58        return self._inner.n_buses()
n_lines: int
60    @property
61    def n_lines(self) -> int:
62        return self._inner.n_lines()
n_line_codes: int
64    @property
65    def n_line_codes(self) -> int:
66        return self._inner.n_line_codes()
n_switches: int
68    @property
69    def n_switches(self) -> int:
70        return self._inner.n_switches()
n_transformers: int
72    @property
73    def n_transformers(self) -> int:
74        return self._inner.n_transformers()
n_loads: int
76    @property
77    def n_loads(self) -> int:
78        return self._inner.n_loads()
n_generators: int
80    @property
81    def n_generators(self) -> int:
82        return self._inner.n_generators()
n_ibrs: int
84    @property
85    def n_ibrs(self) -> int:
86        return self._inner.n_ibrs()
n_control_profiles: int
88    @property
89    def n_control_profiles(self) -> int:
90        return self._inner.n_control_profiles()
n_shunts: int
92    @property
93    def n_shunts(self) -> int:
94        return self._inner.n_shunts()
n_capacitors: int
96    @property
97    def n_capacitors(self) -> int:
98        return self._inner.n_capacitors()
n_voltage_sources: int
100    @property
101    def n_voltage_sources(self) -> int:
102        """Number of grid forming voltage sources."""
103        return self._inner.n_voltage_sources()

Number of grid forming voltage sources.

n_untyped_objects: int
105    @property
106    def n_untyped_objects(self) -> int:
107        return self._inner.n_untyped_objects()
buses: list[dict[str, typing.Any]]
113    @property
114    def buses(self) -> "list[dict[str, Any]]":
115        return self._inner.buses()
line_codes: list[dict[str, typing.Any]]
117    @property
118    def line_codes(self) -> "list[dict[str, Any]]":
119        return self._inner.line_codes()
lines: list[dict[str, typing.Any]]
121    @property
122    def lines(self) -> "list[dict[str, Any]]":
123        return self._inner.lines()
switches: list[dict[str, typing.Any]]
125    @property
126    def switches(self) -> "list[dict[str, Any]]":
127        return self._inner.switches()
transformers: list[dict[str, typing.Any]]
129    @property
130    def transformers(self) -> "list[dict[str, Any]]":
131        return self._inner.transformers()
loads: list[dict[str, typing.Any]]
133    @property
134    def loads(self) -> "list[dict[str, Any]]":
135        return self._inner.loads()
generators: list[dict[str, typing.Any]]
137    @property
138    def generators(self) -> "list[dict[str, Any]]":
139        return self._inner.generators()
ibrs: list[dict[str, typing.Any]]
141    @property
142    def ibrs(self) -> "list[dict[str, Any]]":
143        return self._inner.ibrs()
control_profiles: list[dict[str, typing.Any]]
145    @property
146    def control_profiles(self) -> "list[dict[str, Any]]":
147        return self._inner.control_profiles()
shunts: list[dict[str, typing.Any]]
149    @property
150    def shunts(self) -> "list[dict[str, Any]]":
151        return self._inner.shunts()
capacitors: list[dict[str, typing.Any]]
153    @property
154    def capacitors(self) -> "list[dict[str, Any]]":
155        return self._inner.capacitors()
voltage_sources: list[dict[str, typing.Any]]
157    @property
158    def voltage_sources(self) -> "list[dict[str, Any]]":
159        return self._inner.voltage_sources()
untyped_objects: list[dict[str, typing.Any]]
161    @property
162    def untyped_objects(self) -> "list[dict[str, Any]]":
163        return self._inner.untyped_objects()
def to_graph(self) -> Any:
165    def to_graph(self) -> Any:
166        """Transform the network to collapsed bus and terminal graph data."""
167        return _json.loads(self._inner.graph_json())

Transform the network to collapsed bus and terminal graph data.

def to_geo_layer(self) -> Any:
169    def to_geo_layer(self) -> Any:
170        """Transform coordinates to a canonical GeoJSON FeatureCollection.
171
172        A network without coordinates produces an empty feature collection.
173        """
174        return _json.loads(self._inner.to_geo_layer_json())

Transform coordinates to a canonical GeoJSON FeatureCollection.

A network without coordinates produces an empty feature collection.

def apply_geo_layer( self, text: str, name_hint: Optional[str] = None) -> tuple[MulticonductorNetwork, typing.Any]:
176    def apply_geo_layer(
177        self, text: str, name_hint: Optional[str] = None
178    ) -> tuple["MulticonductorNetwork", Any]:
179        """Apply a geographic sidecar and return ``(placed, report)``.
180
181        ``text`` is any form :func:`powerio.parse_geo` accepts. This network
182        is unchanged; the placed copy drops the retained source text, so a
183        same-format emission re-serializes.
184        """
185        inner, report = self._inner.apply_geo_layer(text, name_hint)
186        return MulticonductorNetwork(inner), report

Apply a geographic sidecar and return (placed, report).

text is any form powerio.parse_geo() accepts. This network is unchanged; the placed copy drops the retained source text, so a same-format emission re-serializes.