powerio.dist
Parse and convert multiconductor distribution networks.
The typed model uses wire coordinates. Supported formats are OpenDSS .dss,
PowerModelsDistribution ENGINEERING JSON (pmd-json), and BMOPF JSON
(bmopf-json). Same format writes can return retained source bytes. Cross
format writes report unsupported fields in ~powerio.Conversion.
import powerio.dist as dist
net = dist.parse_file("feeder.dss")
for w in net.warnings:
print("parse:", w)
conv = net.to_format("pmd-json")
1"""Parse and convert multiconductor distribution networks. 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 writes can return retained source bytes. Cross 6format writes report unsupported fields in :class:`~powerio.Conversion`. 7 8 import powerio.dist as dist 9 10 net = dist.parse_file("feeder.dss") 11 for w in net.warnings: 12 print("parse:", w) 13 conv = net.to_format("pmd-json") 14""" 15 16from __future__ import annotations 17 18import json as _json 19from typing import Any, Optional 20 21from . import Conversion, _powerio 22 23__all__ = [ 24 "MulticonductorNetwork", 25 "convert_file", 26 "convert_str", 27 "parse_file", 28 "parse_str", 29] 30 31 32class MulticonductorNetwork: 33 """A parsed multiconductor distribution network in wire coordinates. 34 35 Buses carry named terminals, lines carry conductor impedance matrices, and 36 transformers carry per winding connections. This type is distinct from the 37 positive sequence :class:`powerio.BalancedNetwork`; balanced matrix builders do not 38 accept it. 39 """ 40 41 def __init__(self, inner) -> None: 42 self._inner = inner 43 44 @property 45 def name(self) -> Optional[str]: 46 """Distribution network name when the source format carries one.""" 47 return self._inner.name() 48 49 @property 50 def source_format(self) -> Optional[str]: 51 """Format parsed from: ``dss``, ``pmd-json``, or ``bmopf-json``.""" 52 return self._inner.source_format() 53 54 @property 55 def warnings(self) -> "list[str]": 56 """Return source fields not represented and assumptions made while parsing.""" 57 return self._inner.warnings() 58 59 @property 60 def n_buses(self) -> int: 61 return self._inner.n_buses() 62 63 @property 64 def n_lines(self) -> int: 65 return self._inner.n_lines() 66 67 @property 68 def n_transformers(self) -> int: 69 return self._inner.n_transformers() 70 71 @property 72 def n_loads(self) -> int: 73 return self._inner.n_loads() 74 75 @property 76 def n_generators(self) -> int: 77 return self._inner.n_generators() 78 79 @property 80 def n_sources(self) -> int: 81 return self._inner.n_sources() 82 83 def to_format(self, to: str) -> Conversion: 84 """Serialize to ``to`` (``dss``, ``pmd-json``, ``bmopf-json``). 85 86 Writing back to the source format echoes the retained source text byte 87 for byte; a cross format write regenerates from the typed model and 88 reports every fidelity loss in the warnings. 89 """ 90 text, warnings = self._inner.to_format(to) 91 return Conversion(text, warnings) 92 93 def to_canonical_format(self, to: str) -> Conversion: 94 """Serialize to ``to`` from the typed model, bypassing source echo.""" 95 text, warnings = self._inner.to_canonical_format(to) 96 return Conversion(text, warnings) 97 98 def write_file(self, path: Any, to: str) -> list[str]: 99 """Serialize to ``to`` and write it to ``path`` byte exact. 100 101 Any sidecar the writer produces goes beside ``path``: a dss write of a 102 network with bus coordinates emits a ``Buscoords`` directive, and the 103 CSV it names is written too. Returns the fidelity warnings. See 104 :meth:`powerio.BalancedNetwork.write_file` for why this beats writing 105 :meth:`to_format` text through ``open(path, "w")`` on Windows. 106 """ 107 return self._inner.write_file(str(path), to) 108 109 def graph(self) -> Any: 110 """Collapsed bus and terminal graph as Python data.""" 111 return _json.loads(self._inner.graph_json()) 112 113 def geo_layer(self) -> Any: 114 """This case's coordinates as a canonical GeoJSON FeatureCollection. 115 116 Raises when the case carries none. 117 """ 118 return _json.loads(self._inner.geo_layer_json()) 119 120 def apply_geo_layer( 121 self, text: str, name_hint: Optional[str] = None 122 ) -> tuple["MulticonductorNetwork", Any]: 123 """Apply a geographic sidecar and return ``(placed, report)``. 124 125 ``text`` is any form :func:`powerio.parse_geo` accepts. This network 126 is unchanged; the placed copy drops the retained source text, so a 127 same-format write re-serializes. 128 """ 129 inner, report = self._inner.apply_geo_layer(text, name_hint) 130 return MulticonductorNetwork(inner), report 131 132 def __repr__(self) -> str: 133 return self._inner.__repr__() 134 135 136 137 138def parse_file(path: Any, from_: Optional[str] = None) -> MulticonductorNetwork: 139 """Parse a distribution network file. 140 141 The format comes from ``from_`` when given, else from the file itself: 142 ``.dss`` is OpenDSS, and ``.json`` holding the ENGINEERING ``data_model`` 143 key is PMD JSON, otherwise BMOPF JSON. 144 """ 145 return MulticonductorNetwork(_powerio.dist_parse_file(str(path), from_)) 146 147 148def parse_str(text: str, format: str) -> MulticonductorNetwork: 149 """Parse an in-memory distribution network of the named ``format``.""" 150 return MulticonductorNetwork(_powerio.dist_parse_str(text, format)) 151 152 153def convert_file(path: Any, to: str, from_: Optional[str] = None) -> Conversion: 154 """Convert a distribution network file to ``to`` in one call. 155 156 The warnings carry both the parse warnings and the writer's fidelity 157 losses (there is no :class:`MulticonductorNetwork` to query them from). 158 """ 159 text, warnings = _powerio.dist_convert_file(str(path), to, from_) 160 return Conversion(text, warnings) 161 162 163def convert_str(text: str, to: str, format: str) -> Conversion: 164 """Convert an in-memory distribution network of the named ``format`` to ``to``. 165 166 The signature matches :func:`powerio.convert_str`: input, target, source, 167 except ``format`` is required (there is no extension to infer from and no 168 default). The warnings carry both the parse warnings and the writer's 169 fidelity losses (there is no :class:`MulticonductorNetwork` to query them from). 170 """ 171 text, warnings = _powerio.dist_convert_str(text, to, format) 172 return Conversion(text, warnings)
33class MulticonductorNetwork: 34 """A parsed multiconductor distribution network in wire coordinates. 35 36 Buses carry named terminals, lines carry conductor impedance matrices, and 37 transformers carry per winding connections. This type is distinct from the 38 positive sequence :class:`powerio.BalancedNetwork`; balanced matrix builders do not 39 accept it. 40 """ 41 42 def __init__(self, inner) -> None: 43 self._inner = inner 44 45 @property 46 def name(self) -> Optional[str]: 47 """Distribution network name when the source format carries one.""" 48 return self._inner.name() 49 50 @property 51 def source_format(self) -> Optional[str]: 52 """Format parsed from: ``dss``, ``pmd-json``, or ``bmopf-json``.""" 53 return self._inner.source_format() 54 55 @property 56 def warnings(self) -> "list[str]": 57 """Return source fields not represented and assumptions made while parsing.""" 58 return self._inner.warnings() 59 60 @property 61 def n_buses(self) -> int: 62 return self._inner.n_buses() 63 64 @property 65 def n_lines(self) -> int: 66 return self._inner.n_lines() 67 68 @property 69 def n_transformers(self) -> int: 70 return self._inner.n_transformers() 71 72 @property 73 def n_loads(self) -> int: 74 return self._inner.n_loads() 75 76 @property 77 def n_generators(self) -> int: 78 return self._inner.n_generators() 79 80 @property 81 def n_sources(self) -> int: 82 return self._inner.n_sources() 83 84 def to_format(self, to: str) -> Conversion: 85 """Serialize to ``to`` (``dss``, ``pmd-json``, ``bmopf-json``). 86 87 Writing back to the source format echoes the retained source text byte 88 for byte; a cross format write regenerates from the typed model and 89 reports every fidelity loss in the warnings. 90 """ 91 text, warnings = self._inner.to_format(to) 92 return Conversion(text, warnings) 93 94 def to_canonical_format(self, to: str) -> Conversion: 95 """Serialize to ``to`` from the typed model, bypassing source echo.""" 96 text, warnings = self._inner.to_canonical_format(to) 97 return Conversion(text, warnings) 98 99 def write_file(self, path: Any, to: str) -> list[str]: 100 """Serialize to ``to`` and write it to ``path`` byte exact. 101 102 Any sidecar the writer produces goes beside ``path``: a dss write of a 103 network with bus coordinates emits a ``Buscoords`` directive, and the 104 CSV it names is written too. Returns the fidelity warnings. See 105 :meth:`powerio.BalancedNetwork.write_file` for why this beats writing 106 :meth:`to_format` text through ``open(path, "w")`` on Windows. 107 """ 108 return self._inner.write_file(str(path), to) 109 110 def graph(self) -> Any: 111 """Collapsed bus and terminal graph as Python data.""" 112 return _json.loads(self._inner.graph_json()) 113 114 def geo_layer(self) -> Any: 115 """This case's coordinates as a canonical GeoJSON FeatureCollection. 116 117 Raises when the case carries none. 118 """ 119 return _json.loads(self._inner.geo_layer_json()) 120 121 def apply_geo_layer( 122 self, text: str, name_hint: Optional[str] = None 123 ) -> tuple["MulticonductorNetwork", Any]: 124 """Apply a geographic sidecar and return ``(placed, report)``. 125 126 ``text`` is any form :func:`powerio.parse_geo` accepts. This network 127 is unchanged; the placed copy drops the retained source text, so a 128 same-format write re-serializes. 129 """ 130 inner, report = self._inner.apply_geo_layer(text, name_hint) 131 return MulticonductorNetwork(inner), report 132 133 def __repr__(self) -> str: 134 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 builders do not
accept it.
45 @property 46 def name(self) -> Optional[str]: 47 """Distribution network name when the source format carries one.""" 48 return self._inner.name()
Distribution network name when the source format carries one.
50 @property 51 def source_format(self) -> Optional[str]: 52 """Format parsed from: ``dss``, ``pmd-json``, or ``bmopf-json``.""" 53 return self._inner.source_format()
Format parsed from: dss, pmd-json, or bmopf-json.
55 @property 56 def warnings(self) -> "list[str]": 57 """Return source fields not represented and assumptions made while parsing.""" 58 return self._inner.warnings()
Return source fields not represented and assumptions made while parsing.
84 def to_format(self, to: str) -> Conversion: 85 """Serialize to ``to`` (``dss``, ``pmd-json``, ``bmopf-json``). 86 87 Writing back to the source format echoes the retained source text byte 88 for byte; a cross format write regenerates from the typed model and 89 reports every fidelity loss in the warnings. 90 """ 91 text, warnings = self._inner.to_format(to) 92 return Conversion(text, warnings)
Serialize to to (dss, pmd-json, bmopf-json).
Writing back to the source format echoes the retained source text byte for byte; a cross format write regenerates from the typed model and reports every fidelity loss in the warnings.
94 def to_canonical_format(self, to: str) -> Conversion: 95 """Serialize to ``to`` from the typed model, bypassing source echo.""" 96 text, warnings = self._inner.to_canonical_format(to) 97 return Conversion(text, warnings)
Serialize to to from the typed model, bypassing source echo.
99 def write_file(self, path: Any, to: str) -> list[str]: 100 """Serialize to ``to`` and write it to ``path`` byte exact. 101 102 Any sidecar the writer produces goes beside ``path``: a dss write of a 103 network with bus coordinates emits a ``Buscoords`` directive, and the 104 CSV it names is written too. Returns the fidelity warnings. See 105 :meth:`powerio.BalancedNetwork.write_file` for why this beats writing 106 :meth:`to_format` text through ``open(path, "w")`` on Windows. 107 """ 108 return self._inner.write_file(str(path), to)
Serialize to to and write it to path byte exact.
Any sidecar the writer produces goes beside path: a dss write of a
network with bus coordinates emits a Buscoords directive, and the
CSV it names is written too. Returns the fidelity warnings. See
powerio.BalancedNetwork.write_file() for why this beats writing
to_format() text through open(path, "w") on Windows.
110 def graph(self) -> Any: 111 """Collapsed bus and terminal graph as Python data.""" 112 return _json.loads(self._inner.graph_json())
Collapsed bus and terminal graph as Python data.
114 def geo_layer(self) -> Any: 115 """This case's coordinates as a canonical GeoJSON FeatureCollection. 116 117 Raises when the case carries none. 118 """ 119 return _json.loads(self._inner.geo_layer_json())
This case's coordinates as a canonical GeoJSON FeatureCollection.
Raises when the case carries none.
121 def apply_geo_layer( 122 self, text: str, name_hint: Optional[str] = None 123 ) -> tuple["MulticonductorNetwork", Any]: 124 """Apply a geographic sidecar and return ``(placed, report)``. 125 126 ``text`` is any form :func:`powerio.parse_geo` accepts. This network 127 is unchanged; the placed copy drops the retained source text, so a 128 same-format write re-serializes. 129 """ 130 inner, report = self._inner.apply_geo_layer(text, name_hint) 131 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 write re-serializes.
154def convert_file(path: Any, to: str, from_: Optional[str] = None) -> Conversion: 155 """Convert a distribution network file to ``to`` in one call. 156 157 The warnings carry both the parse warnings and the writer's fidelity 158 losses (there is no :class:`MulticonductorNetwork` to query them from). 159 """ 160 text, warnings = _powerio.dist_convert_file(str(path), to, from_) 161 return Conversion(text, warnings)
Convert a distribution network file to to in one call.
The warnings carry both the parse warnings and the writer's fidelity
losses (there is no MulticonductorNetwork to query them from).
164def convert_str(text: str, to: str, format: str) -> Conversion: 165 """Convert an in-memory distribution network of the named ``format`` to ``to``. 166 167 The signature matches :func:`powerio.convert_str`: input, target, source, 168 except ``format`` is required (there is no extension to infer from and no 169 default). The warnings carry both the parse warnings and the writer's 170 fidelity losses (there is no :class:`MulticonductorNetwork` to query them from). 171 """ 172 text, warnings = _powerio.dist_convert_str(text, to, format) 173 return Conversion(text, warnings)
Convert an in-memory distribution network of the named format to to.
The signature matches powerio.convert_str(): input, target, source,
except format is required (there is no extension to infer from and no
default). The warnings carry both the parse warnings and the writer's
fidelity losses (there is no MulticonductorNetwork to query them from).
139def parse_file(path: Any, from_: Optional[str] = None) -> MulticonductorNetwork: 140 """Parse a distribution network file. 141 142 The format comes from ``from_`` when given, else from the file itself: 143 ``.dss`` is OpenDSS, and ``.json`` holding the ENGINEERING ``data_model`` 144 key is PMD JSON, otherwise BMOPF JSON. 145 """ 146 return MulticonductorNetwork(_powerio.dist_parse_file(str(path), from_))
Parse a distribution network file.
The format comes from from_ when given, else from the file itself:
.dss is OpenDSS, and .json holding the ENGINEERING data_model
key is PMD JSON, otherwise BMOPF JSON.
149def parse_str(text: str, format: str) -> MulticonductorNetwork: 150 """Parse an in-memory distribution network of the named ``format``.""" 151 return MulticonductorNetwork(_powerio.dist_parse_str(text, format))
Parse an in-memory distribution network of the named format.