Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions roseau/load_flow/io/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,16 @@ def network_from_dict(
return buses, branches_dict, loads, sources, grounds, potential_refs


def network_to_dict(en: "ElectricalNetwork") -> JsonDict:
def network_to_dict(en: "ElectricalNetwork", include_geometry: bool) -> JsonDict:
"""Return a dictionary of the current network data.

Args:
en:
The electrical network.

include_geometry:
If False, the geometry will not be added to the result dictionary.
Comment thread
Saelyos marked this conversation as resolved.
Outdated

Returns:
The created dictionary.
"""
Expand All @@ -152,7 +155,7 @@ def network_to_dict(en: "ElectricalNetwork") -> JsonDict:
sources: list[JsonDict] = []
short_circuits: list[JsonDict] = []
for bus in en.buses.values():
buses.append(bus.to_dict())
buses.append(bus.to_dict(include_geometry=include_geometry))
for element in bus._connected_elements:
if isinstance(element, AbstractLoad):
assert element.bus is bus
Expand All @@ -168,7 +171,7 @@ def network_to_dict(en: "ElectricalNetwork") -> JsonDict:
lines_params_dict: dict[Id, LineParameters] = {}
transformers_params_dict: dict[Id, TransformerParameters] = {}
for branch in en.branches.values():
branches.append(branch.to_dict())
branches.append(branch.to_dict(include_geometry=include_geometry))
if isinstance(branch, Line):
params_id = branch.parameters.id
if params_id in lines_params_dict and branch.parameters != lines_params_dict[params_id]:
Expand Down
44 changes: 33 additions & 11 deletions roseau/load_flow/io/tests/test_dict.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
import pytest
from shapely import Point
from shapely import LineString, Point

from roseau.load_flow import Line
from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode
Expand All @@ -23,8 +23,8 @@ def test_to_dict():
ground = Ground("ground")
vn = 400 / np.sqrt(3)
voltages = [vn, vn * np.exp(-2 / 3 * np.pi * 1j), vn * np.exp(2 / 3 * np.pi * 1j)]
source_bus = Bus(id="source", phases="abcn")
load_bus = Bus(id="load bus", phases="abcn")
source_bus = Bus(id="source", phases="abcn", geometry=Point(0.0, 0.0))
load_bus = Bus(id="load bus", phases="abcn", geometry=Point(0.0, 1.0))
ground.connect(load_bus)
p_ref = PotentialRef("pref", element=ground)
vs = VoltageSource("vs", source_bus, phases="abcn", voltages=voltages)
Expand All @@ -33,8 +33,9 @@ def test_to_dict():
lp1 = LineParameters("test", z_line=np.eye(4, dtype=complex), y_shunt=np.eye(4, dtype=complex))
lp2 = LineParameters("test", z_line=np.eye(4, dtype=complex), y_shunt=np.eye(4, dtype=complex) * 1.1)

line1 = Line("line1", source_bus, load_bus, phases="abcn", ground=ground, parameters=lp1, length=10)
line2 = Line("line2", source_bus, load_bus, phases="abcn", ground=ground, parameters=lp2, length=10)
geom = LineString([(0.0, 0.0), (0.0, 1.0)])
line1 = Line("line1", source_bus, load_bus, phases="abcn", ground=ground, parameters=lp1, length=10, geometry=geom)
line2 = Line("line2", source_bus, load_bus, phases="abcn", ground=ground, parameters=lp2, length=10, geometry=geom)
en = ElectricalNetwork(
buses=[source_bus, load_bus],
branches=[line1, line2],
Expand All @@ -51,14 +52,25 @@ def test_to_dict():
# Same id, same line parameters -> ok
lp2 = LineParameters("test", z_line=np.eye(4, dtype=complex), y_shunt=np.eye(4, dtype=complex))
line2.parameters = lp2
en.to_dict()
res = en.to_dict()
assert "geometry" in res["buses"][0]
assert "geometry" in res["buses"][1]
assert "geometry" in res["branches"][0]
assert "geometry" in res["branches"][1]

res = en.to_dict(include_geometry=False)
assert "geometry" not in res["buses"][0]
assert "geometry" not in res["buses"][1]
assert "geometry" not in res["branches"][0]
assert "geometry" not in res["branches"][1]

# Same id, different transformer parameters -> fail
ground = Ground("ground")
vn = 400 / np.sqrt(3)
voltages = [vn, vn * np.exp(-2 / 3 * np.pi * 1j), vn * np.exp(2 / 3 * np.pi * 1j)]
source_bus = Bus(id="source", phases="abcn")
load_bus = Bus(id="load bus", phases="abcn")
geom = Point(0.0, 0.0)
source_bus = Bus(id="source", phases="abcn", geometry=geom)
load_bus = Bus(id="load bus", phases="abcn", geometry=geom)
ground.connect(load_bus)
ground.connect(source_bus)
p_ref = PotentialRef("pref", element=ground)
Expand All @@ -71,8 +83,8 @@ def test_to_dict():
tp2 = TransformerParameters(
"t", type="Dyn11", uhv=20000, ulv=400, sn=200 * 1e3, p0=460, i0=2.3 / 100, psc=2350, vsc=4 / 100
)
transformer1 = Transformer(id="Transformer1", bus1=source_bus, bus2=load_bus, parameters=tp1)
transformer2 = Transformer(id="Transformer2", bus1=source_bus, bus2=load_bus, parameters=tp2)
transformer1 = Transformer(id="Transformer1", bus1=source_bus, bus2=load_bus, parameters=tp1, geometry=geom)
transformer2 = Transformer(id="Transformer2", bus1=source_bus, bus2=load_bus, parameters=tp2, geometry=geom)
en = ElectricalNetwork(
buses=[source_bus, load_bus],
branches=[transformer1, transformer2],
Expand All @@ -91,7 +103,17 @@ def test_to_dict():
"t", type="Dyn11", uhv=20000, ulv=400, sn=160 * 1e3, p0=460, i0=2.3 / 100, psc=2350, vsc=4 / 100
)
transformer2.parameters = tp2
en.to_dict()
res = en.to_dict()
assert "geometry" in res["buses"][0]
assert "geometry" in res["buses"][1]
assert "geometry" in res["branches"][0]
assert "geometry" in res["branches"][1]

res = en.to_dict(include_geometry=False)
assert "geometry" not in res["buses"][0]
assert "geometry" not in res["buses"][1]
assert "geometry" not in res["branches"][0]
assert "geometry" not in res["branches"][1]


def test_v0_to_v1_converter(monkeypatch):
Expand Down
4 changes: 2 additions & 2 deletions roseau/load_flow/models/branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def res_voltages(self) -> tuple[Q_[np.ndarray], Q_[np.ndarray]]:
def from_dict(cls, data: JsonDict) -> Self:
return cls(**data) # not used anymore

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
res = {
"id": self.id,
"type": self.branch_type,
Expand All @@ -135,7 +135,7 @@ def to_dict(self) -> JsonDict:
"bus1": self.bus1.id,
"bus2": self.bus2.id,
}
if self.geometry is not None:
if self.geometry is not None and include_geometry:
res["geometry"] = self.geometry.__geo_interface__
return res

Expand Down
4 changes: 2 additions & 2 deletions roseau/load_flow/models/buses.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ def from_dict(cls, data: JsonDict) -> Self:
potentials = [complex(v[0], v[1]) for v in potentials]
return cls(id=data["id"], phases=data["phases"], geometry=geometry, potentials=potentials)

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
res = {"id": self.id, "phases": self.phases}
if not np.allclose(self.potentials, 0):
res["potentials"] = [[v.real, v.imag] for v in self._potentials]
if self.geometry is not None:
if self.geometry is not None and include_geometry:
res["geometry"] = self.geometry.__geo_interface__
return res

Expand Down
2 changes: 1 addition & 1 deletion roseau/load_flow/models/grounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def from_dict(cls, data: JsonDict) -> Self:
self._connected_buses = data["buses"]
return self

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
# Shunt lines and potential references will have the ground in their dict not here.
return {
"id": self.id,
Expand Down
8 changes: 6 additions & 2 deletions roseau/load_flow/models/lines/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,12 @@ def res_power_losses(self) -> Q_[np.ndarray]:
#
# Json Mixin interface
#
def to_dict(self) -> JsonDict:
res = {**super().to_dict(), "length": self._length, "params_id": self.parameters.id}
def to_dict(self, include_geometry: bool = True) -> JsonDict:
res = {
**super().to_dict(include_geometry=include_geometry),
"length": self._length,
"params_id": self.parameters.id,
}
if self.ground is not None:
res["ground"] = self.ground.id
return res
2 changes: 1 addition & 1 deletion roseau/load_flow/models/lines/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ def from_dict(cls, data: JsonDict) -> Self:
logger.error(msg)
raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_LINE_MODEL)

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
"""Return the line parameters information as a dictionary format."""
res = {
"id": self.id,
Expand Down
6 changes: 3 additions & 3 deletions roseau/load_flow/models/loads/flexible_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ def from_dict(cls, data: JsonDict) -> Self:
logger.error(msg)
raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_CONTROL_TYPE)

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
if self.type == "constant":
return {"type": "constant"}
elif self.type == "p_max_u_production":
Expand Down Expand Up @@ -410,7 +410,7 @@ def from_dict(cls, data: JsonDict) -> Self:
epsilon = data["epsilon"] if "epsilon" in data else cls.DEFAULT_EPSILON
return cls(type=data["type"], alpha=alpha, epsilon=epsilon)

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
return {"type": self.type, "alpha": self._alpha, "epsilon": self._epsilon}

def _results_to_dict(self, warning: bool) -> NoReturn:
Expand Down Expand Up @@ -806,7 +806,7 @@ def from_dict(cls, data: JsonDict) -> Self:
projection = cls._projection_class.from_dict(data["projection"])
return cls(control_p=control_p, control_q=control_q, projection=projection, s_max=data["s_max"])

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
return {
"control_p": self.control_p.to_dict(),
"control_q": self.control_q.to_dict(),
Expand Down
6 changes: 3 additions & 3 deletions roseau/load_flow/models/loads/loads.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def res_flexible_powers(self) -> Q_[np.ndarray]:
#
# Json Mixin interface
#
def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
if self.bus is None:
msg = f"The load {self.id!r} is disconnected and cannot be used anymore."
logger.error(msg)
Expand Down Expand Up @@ -383,7 +383,7 @@ def currents(self, value: Sequence[complex]) -> None:
self._currents = self._validate_value(value)
self._invalidate_network_results()

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
if self.bus is None:
msg = f"The load {self.id!r} is disconnected and cannot be used anymore."
logger.error(msg)
Expand Down Expand Up @@ -441,7 +441,7 @@ def impedances(self, impedances: Sequence[complex]) -> None:
self._impedances = self._validate_value(impedances)
self._invalidate_network_results()

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
if self.bus is None:
msg = f"The load {self.id!r} is disconnected and cannot be used anymore."
logger.error(msg)
Expand Down
2 changes: 1 addition & 1 deletion roseau/load_flow/models/potential_refs.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def res_current(self) -> Q_[complex]:
def from_dict(cls, data: JsonDict) -> Self:
return cls(data["id"], data["element"], phase=data.get("phases"))

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
res = {"id": self.id}
e = self.element
if isinstance(e, Bus):
Expand Down
2 changes: 1 addition & 1 deletion roseau/load_flow/models/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def from_dict(cls, data: JsonDict) -> Self:
voltages = [complex(v[0], v[1]) for v in data["voltages"]]
return cls(data["id"], data["bus"], voltages=voltages, phases=data["phases"])

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
if self.bus is None:
msg = f"The voltage source {self.id!r} is disconnected and cannot be used anymore."
logger.error(msg)
Expand Down
2 changes: 1 addition & 1 deletion roseau/load_flow/models/transformers/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def from_dict(cls, data: JsonDict) -> Self:
vsc=data["vsc"],
)

def to_dict(self) -> JsonDict:
def to_dict(self, include_geometry: bool = True) -> JsonDict:
return {
"id": self.id,
"sn": self._sn,
Expand Down
4 changes: 2 additions & 2 deletions roseau/load_flow/models/transformers/transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ def parameters(self, value: TransformerParameters) -> None:
self._parameters = value
self._invalidate_network_results()

def to_dict(self) -> JsonDict:
return {**super().to_dict(), "params_id": self.parameters.id, "tap": self.tap}
def to_dict(self, include_geometry: bool = True) -> JsonDict:
return {**super().to_dict(include_geometry=include_geometry), "params_id": self.parameters.id, "tap": self.tap}

def _compute_phases_three(
self,
Expand Down
13 changes: 9 additions & 4 deletions roseau/load_flow/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ def solve_load_flow(

# Get the data
data = {
"network": self.to_dict(),
"network": self.to_dict(include_geometry=False),
"solver": {
"name": solver,
"params": solver_params,
Expand Down Expand Up @@ -1103,9 +1103,14 @@ def from_dict(cls, data: JsonDict) -> Self:
potential_refs=p_refs,
)

def to_dict(self) -> JsonDict:
"""Convert the electrical network to a dictionary."""
return network_to_dict(self)
def to_dict(self, include_geometry: bool = True) -> JsonDict:
"""Convert the electrical network to a dictionary.

Args:
include_geometry:
If False, the geometry will not be added to the result dictionary.
Comment thread
Saelyos marked this conversation as resolved.
Outdated
"""
return network_to_dict(self, include_geometry=include_geometry)

#
# Results saving/loading
Expand Down
9 changes: 7 additions & 2 deletions roseau/load_flow/utils/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ def from_json(cls, path: StrPath) -> Self:
return cls.from_dict(data=data)

@abstractmethod
def to_dict(self) -> JsonDict:
"""Return the element information as a dictionary format."""
def to_dict(self, include_geometry: bool = True) -> JsonDict:
"""Return the element information as a dictionary format.

Args:
include_geometry:
If False, the geometry will not be added to the result dictionary.
"""
raise NotImplementedError

def to_json(self, path: StrPath) -> Path:
Expand Down