Skip to content

Commit

Permalink
Fix loading calculation of lines and transformers
Browse files Browse the repository at this point in the history
  • Loading branch information
alihamdan committed Dec 2, 2024
1 parent d97bbee commit d69d41d
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 41 deletions.
20 changes: 7 additions & 13 deletions roseau/load_flow_single/models/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,27 +260,21 @@ def res_power_losses(self) -> Q_[Complex]:

@property
def res_loading(self) -> Q_[float] | None:
"""Get the loading of the line (unitless)."""
amp = self._parameters._ampacity
if amp is None:
"""The loading of the line (unitless) if ``self.parameters.ampacity`` is set, else ``None``."""
if (amp := self._parameters._ampacity) is None:
return None
current1, current2 = self._res_currents_getter(warning=True)
i_max = amp * self._max_loading
return Q_(max(abs(current1), abs(current2)) / i_max, "")
return Q_(max(abs(current1), abs(current2)) / amp, "")

@property
def res_violated(self) -> bool | None:
"""Whether the line current exceeds the maximal current of the line (computed with the parameters' ampacities
and the maximal loading of the line itself).
"""Whether the line current loading exceeds its maximal loading.
Returns ``None`` if the ampacities or the `max_loading` is not set are not set.
Returns ``None`` if the ``self.parameters.ampacity`` is not set.
"""
amp = self._parameters._ampacity
if amp is None:
if (loading := self.res_loading) is None:
return None
current1, current2 = self._res_currents_getter(warning=True)
i_max = amp * self._max_loading
return abs(current1) > i_max or abs(current2) > i_max
return bool(loading.m > self._max_loading)

#
# Json Mixin interface
Expand Down
2 changes: 1 addition & 1 deletion roseau/load_flow_single/models/tests/test_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def test_res_violated():
line.max_loading = Q_(50, "%")
assert line.max_loading.m == 0.5
assert line.res_violated
assert np.allclose(line.res_loading, 10 / (11 * 0.5))
assert np.allclose(line.res_loading, 10 / 11)

# Two violations
lp = LineParameters(id="lp", z_line=1.0, ampacity=9)
Expand Down
4 changes: 2 additions & 2 deletions roseau/load_flow_single/models/tests/test_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ def test_res_violated():
# Two violations
transformer.max_loading = 4 / 5
assert transformer.res_violated is True
assert np.allclose(transformer.res_loading, 0.8 * 20 * 3 / 40)
assert np.allclose(transformer.res_loading, 0.8 * 20 * 3 / 50)

# Primary side violation
transformer.max_loading = Q_(45, "%")
assert transformer.res_violated is True
assert np.allclose(transformer.res_loading, 0.8 * 20 * 3 / (50 * 0.45))
assert np.allclose(transformer.res_loading, 0.8 * 20 * 3 / 50)

# Secondary side violation
transformer.max_loading = 1
Expand Down
22 changes: 6 additions & 16 deletions roseau/load_flow_single/models/transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,28 +170,18 @@ def res_power_losses(self) -> Q_[complex]:
return power1 + power2

@property
def res_loading(self) -> Q_[float] | None:
@ureg_wraps("", (None,))
def res_loading(self) -> Q_[float]:
"""Get the loading of the transformer (unitless)."""
sn = self._parameters._sn
if sn is None:
return None
power1, power2 = self._res_powers_getter(warning=True)
s_max = sn * self._max_loading
return Q_(max(abs(power1), abs(power2)) / s_max, "")
return max(abs(power1), abs(power2)) / sn

@property
def res_violated(self) -> bool | None:
"""Whether the transformer power exceeds the maximum power (loading > max_loading).
Returns ``None`` if the maximum power is not set.
"""
sn = self._parameters._sn
if sn is None:
return None
power1, power2 = self._res_powers_getter(warning=True)
s_max = sn * self._max_loading
def res_violated(self) -> bool:
"""Whether the transformer power loading exceeds its maximal loading."""
# True if either the primary or secondary is overloaded
return abs(power1) > s_max or abs(power2) > s_max
return bool(self.res_loading.m > self._max_loading)

#
# Json Mixin interface
Expand Down
12 changes: 3 additions & 9 deletions roseau/load_flow_single/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,8 +681,7 @@ def res_lines(self) -> pd.DataFrame:
loading = None
violated = None
else:
i_max = ampacity * max_loading
loading = max(abs(current1), abs(current2)) / i_max
loading = max(abs(current1), abs(current2)) / ampacity
violated = loading > max_loading
res_dict["line_id"].append(line.id)
res_dict["current1"].append(current1)
Expand Down Expand Up @@ -739,13 +738,8 @@ def res_transformers(self) -> pd.DataFrame:
power2 = potential2 * current2.conjugate() * 3.0
sn = transformer.parameters._sn
max_loading = transformer._max_loading
if sn is None:
violated = None
loading = None
else:
s_max = sn * max_loading
loading = max(abs(power1), abs(power2)) / s_max
violated = loading > max_loading
loading = max(abs(power1), abs(power2)) / sn
violated = loading > max_loading
res_dict["transformer_id"].append(transformer.id)
res_dict["current1"].append(current1)
res_dict["current2"].append(current2)
Expand Down

0 comments on commit d69d41d

Please sign in to comment.