Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 8 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.11.30
rev: 0.11.33
hooks:
- id: uv-lock
- repo: https://github.com/python-jsonschema/check-jsonschema
Expand All @@ -28,21 +28,19 @@ repos:
- id: typos
args: [--force-exclude]
- repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v1.27.0
rev: v1.28.0
hooks:
- id: zizmor
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.22
rev: v0.16.0
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
- repo: https://github.com/adamchainz/blacken-docs
rev: 1.20.0
hooks:
- id: blacken-docs
files: ^doc/.*\.md$
args: [-l 90]
types_or: [python, pyi, jupyter]
- id: ruff-format
types_or: [markdown]
args: [--line-length, "90"]
- repo: https://github.com/executablebooks/mdformat
rev: 1.0.0
hooks:
Expand All @@ -69,7 +67,7 @@ repos:
- id: latexindent
args: [-l, -m, -s, -wd]
- repo: https://github.com/biomejs/pre-commit
rev: v2.5.4
rev: v2.5.5
hooks:
- id: biome-check
types_or: [json, html, css]
Expand Down
10 changes: 8 additions & 2 deletions doc/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ og:description: See what's new in the latest release of Roseau Load Flow !

# Changelog

## Version 0.16.0-alpha
## Version 0.16.0a1

- {gh-pr}`484` Disallow buses from having both a short-circuit and a voltage source similar to the restriction for power
and current loads. This now fails with a clear error message early instead of a cryptic singular matrix error during
load flow calculation.

## Version 0.16.0a0

- {gh-pr}`481` Add `sort_keys` parameter to the `to_json` method to control the sorting of keys in the JSON output. The
default value is `False`.
Expand Down Expand Up @@ -115,7 +121,7 @@ The public license key can now be used with networks containing up to 50 buses.
- Underground lines are dashed while other lines are solid including lines with unknown line type
- Transformers are now represented with a square icon with a divider in the middle and with both HV and LV buses
information in the tooltip and popup
- Sourcers are represented with a bigger square icon
- Sources are represented with a bigger square icon
- If the new parameter `fit_bounds` is set to `True` (default), the bounds of the map will be automatically adjusted
using `folium.FitOverlays` to fit the network elements.

Expand Down
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

# The full version, including alpha/beta/rc tags
version = "0.16"
release = "0.16.0-alpha"
release = "0.16.0a1"

# -- General configuration ---------------------------------------------------

Expand Down
10 changes: 5 additions & 5 deletions doc/models/Line/Parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ The following resistivities are used by _Roseau Load Flow_:
| ACSR -- Fr: Alu-Acier | $4.0587\times10^{-8}$ |
| AACSR -- Fr: Almélec-Acier | $3.26\times10^{-8}$ |

These values are defined in the `utils` module: {data}`roseau.load_flow.utils.RHO`.
These values are defined in the `constants` module: {data}`roseau.load_flow.constants.RHO`.

#### Inductance

Expand Down Expand Up @@ -290,7 +290,7 @@ where:
- $D_{ij}$ the distances between the center of the conductor $i$ and the center of the conductor $j$
- $GMR_i$ the _geometric mean radius_ of the conductor $i$.

The vacuum magnetic permeability is defined in the `utils` module {data}`roseau.load_flow.utils.MU_0`.
The vacuum magnetic permeability is defined in the `constants` module {data}`roseau.load_flow.constants.MU_0`.

The geometric mean radius is defined for all $i\in \{\mathrm{a}, \mathrm{b}, \mathrm{c}, \mathrm{n}\}$ as

Expand Down Expand Up @@ -344,8 +344,8 @@ compute the distances based on the position of wires.

The permittivity of the insulator $\varepsilon$ (in F/m) is defined as $\varepsilon_0\varepsilon_{\mathrm{r}}$ with
$\varepsilon_0$ the permittivity of the vacuum (in F/m) and $\varepsilon_{\mathrm{r}}$ the relative permittivity of the
insulator (no unit). These values are defined in the `utils` module {data}`roseau.load_flow.utils.EPSILON_0` and
{data}`roseau.load_flow.utilsEPSILON_R`.
insulator (no unit). These values are defined in the `constants` module {data}`roseau.load_flow.constants.EPSILON_0` and
{data}`roseau.load_flow.constants.EPSILON_R`.

The capacitance matrix $C$ is then defined by:

Expand Down Expand Up @@ -386,7 +386,7 @@ $\tan\delta$ is the loss tangent and is taken from this table:
| Cross-linked polyethylene (PEX) | $30\times10^{-4}$ |
| Ethylene-Propylene Rubber (EPR) | $125\times10^{-4}$ |

These values are defined in the `utils` module: {data}`roseau.load_flow.utils.TAN_D`.
These values are defined in the `constants` module: {data}`roseau.load_flow.constants.TAN_D`.

Finally, the impedance matrix and the admittance matrix can be computed.

Expand Down
9 changes: 6 additions & 3 deletions doc/models/Load/FlexibleLoad/FeasibleDomain.md
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,8 @@ import roseau.load_flow as rlf
# Flexible parameter
fp = rlf.FlexibleParameter(
control_p=rlf.Control.p_max_u_production(
u_up=rlf.Q_(245, "V"), u_max=rlf.Q_(250, "V") # <----
u_up=rlf.Q_(245, "V"), # <----
u_max=rlf.Q_(250, "V"),
),
control_q=rlf.Control.q_u(
u_min=rlf.Q_(210, "V"),
Expand Down Expand Up @@ -756,7 +757,8 @@ import roseau.load_flow as rlf
# Flexible parameter
fp = rlf.FlexibleParameter(
control_p=rlf.Control.p_max_u_production(
u_up=rlf.Q_(230, "V"), u_max=rlf.Q_(240, "V") # <----
u_up=rlf.Q_(230, "V"),
u_max=rlf.Q_(240, "V"), # <----
),
control_q=rlf.Control.q_u(
u_min=rlf.Q_(210, "V"),
Expand Down Expand Up @@ -821,7 +823,8 @@ import roseau.load_flow as rlf
# Flexible parameter
fp = rlf.FlexibleParameter(
control_p=rlf.Control.p_max_u_production(
u_up=rlf.Q_(240, "V"), u_max=rlf.Q_(250, "V") # <----
u_up=rlf.Q_(240, "V"), # <----
u_max=rlf.Q_(250, "V"), # <----
),
control_q=rlf.Control.q_u(
u_min=rlf.Q_(210, "V"),
Expand Down
4 changes: 2 additions & 2 deletions doc/models/Transformer/Center_Tapped_Transformer.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ myst:

# Center-tapped transformer

Center-tapped transformers allow to split two-phase connection on its HV side into a two-phase connection with a neutral
point in the middle on its LV side. It is modelled as follows:
Center-tapped transformers allow splitting a two-phase connection on their HV side into a two-phase connection with a
neutral point in the middle on their LV side. It is modelled as follows:

````{tab} European standards
```{image} /_static/Transformer/European_Center_Tapped_Transformer.svg
Expand Down
1 change: 1 addition & 0 deletions doc/usage/Catalogues.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ the same table:

```pycon
>>> import roseau.load_flow as rlf
...
... rlf.TransformerParameters.get_catalogue(sn=3150e3) # in VA by default

>>> rlf.TransformerParameters.get_catalogue(sn=rlf.Q_(3150, "kVA"))
Expand Down
2 changes: 1 addition & 1 deletion doc/usage/Data_Exchange.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ The data on these two screenshots translate to:
... r1=rlf.Q_(0.3225, "ohm/km"), # Parameters per Length 1,2 Sequence, "Basic data"
... x0=rlf.Q_(0.502654, "ohm/km"), # Parameters per Length Zero Sequence, "Basic data"
... x1=rlf.Q_(0.125663, "ohm/km"), # Parameters per Length 1,2 Sequence, "Basic data"
... b0=rlf.Q_(75.05265, "uS/km"), # Parameters per Length Sero Sequence, "Load Flow"
... b0=rlf.Q_(75.05265, "uS/km"), # Parameters per Length Zero Sequence, "Load Flow"
... b1=rlf.Q_(72.25663, "uS/km"), # Parameters per Length 1,2 Sequence, "Load Flow"
... nphase=3, # Phases, "Basic Data"
... nneutral=0, # Number of Neutrals, "Basic Data"
Expand Down
2 changes: 1 addition & 1 deletion doc/usage/Extras.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ As you can see, for this positive-sequence balanced voltage, only the positive-s
Converting back to phasor, you get the original voltage values back:

```pycon
>>> sym_to_phasor(v_sym)
>>> rlf.sym.sym_to_phasor(v_sym)
array([[ 230.-7.21644966e-16j],
[-115.-1.99185843e+02j],
[-115.+1.99185843e+02j]])
Expand Down
4 changes: 2 additions & 2 deletions doc/usage/Flexible_Loads.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ only different in case of delta loads. To access the powers that flow in the lin
Here, one can note that:

- The active power for the phase `'a'` is negative meaning production;
- The actual value of this active power is lower that the one requested as the control was activated;
- The actual value of this active power is lower than the one requested as the control was activated;
- The power for phases `'b'` and `'c'` is 0 VA as expected.

## $PQ(U)$ control
Expand All @@ -191,7 +191,7 @@ requires several arguments:
- Above `uq_max`, the power plant consumes the maximum possible reactive power.

In the example below, as the new load is a production load, only the `up_up`, `up_max`, `uq_up` and `uq_max` are of
interests. The $Q(U)$ control starts its action at 235 V and is fully exhausted at 240 V. After that, the $P(U)$ is
interest. The $Q(U)$ control starts its action at 235 V and is fully exhausted at 240 V. After that, the $P(U)$ is
activated and is exhausted at 250 V where the production is totally shut down.

```pycon
Expand Down
5 changes: 3 additions & 2 deletions doc/usage/Getting_Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The following is a summary of the available elements:
once and used to describe multiple lines.
- [`Switch`](../models/Switch.md): An ideal connection between two buses on the same voltage level. Currently, a
switch cannot be opened.
- [`Transformer`](../models/Transformer/index.md): A transformer connecting a buses on potentially different voltage
- [`Transformer`](../models/Transformer/index.md): A transformer connecting two buses on potentially different voltage
levels called the high-voltage side and the low-voltage side. The impedance of the transformer and its physical
characteristics including its winding configuration are defined by a `TransformerParameters` object. This object can
be defined once and used to describe multiple transformers.
Expand Down Expand Up @@ -294,7 +294,7 @@ arrays `line.side1.res_currents` and `line.side2.res_currents`:

- `line.side1.res_currents` is the current flowing **into** the first side of the line. It contains 4 values: one per
phase and the neutral current.
- `line.side1.res_currents` is the current flowing **into** the second side of the line i.e. in the opposite direction
- `line.side2.res_currents` is the current flowing **into** the second side of the line i.e. in the opposite direction
of the first side.

```pycon
Expand Down Expand Up @@ -531,6 +531,7 @@ Or, if you prefer the angles in degrees:

```pycon
>>> import functools as ft
...
... en.res_buses_voltages_pp["voltage"].transform([np.abs, ft.partial(np.angle, deg=True)])
```

Expand Down
6 changes: 6 additions & 0 deletions doc/usage/Plotting.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ To visualize the voltage profile of a network, use one of the `plot_<backend>` m

```pycon
>>> import roseau.load_flow as rlf
...
... en = rlf.ElectricalNetwork.from_catalogue("LVFeeder36360", "Winter")
... en
<ElectricalNetwork: 9 buses, 7 lines, 1 transformer, 0 switches, 14 loads, 1 source, 1 ground, 2 potential refs, 1 ground connection>
Expand Down Expand Up @@ -87,6 +88,7 @@ You can plot both minimum and maximum voltage profiles on the same plot by passi
```pycon
>>> import matplotlib.pyplot as plt
... import roseau.load_flow as rlf
...
... en = rlf.ElectricalNetwork.from_catalogue("LVFeeder36360", "Winter")
... en.solve_load_flow()
... ax = plt.figure(figsize=(8, 4)).gca()
Expand Down Expand Up @@ -115,6 +117,7 @@ The simplest way to visualize an electrical network with bus and line geometries

```pycon
>>> import roseau.load_flow as rlf
...
... en = rlf.ElectricalNetwork.from_catalogue(name="MVFeeder210", load_point_name="Winter")
... rlf.plotting.plot_interactive_map(en)
```
Expand Down Expand Up @@ -157,6 +160,7 @@ the map. The network must have valid results before calling this function. Examp

```pycon
>>> import roseau.load_flow as rlf
...
... en = rlf.ElectricalNetwork.from_catalogue(name="MVFeeder210", load_point_name="Winter")
... # Let's create some extreme conditions to see voltage drops/rises and line overloads
... en.loads["MVLV14633_consumption"].powers = 3.5e6
Expand Down Expand Up @@ -192,6 +196,7 @@ For example, to highlight all buses that have loads with a power >60kW, you can

```pycon
>>> import roseau.load_flow as rlf
...
... en = rlf.ElectricalNetwork.from_catalogue(name="MVFeeder210", load_point_name="Winter")
... buses_with_loads_gt_60kva = {
... load.bus.id
Expand Down Expand Up @@ -234,6 +239,7 @@ following example we plot the graph of the network `MVFeeder210` from the previo
```pycon
>>> import networkx as nx
... import roseau.load_flow as rlf
...
... en = rlf.ElectricalNetwork.from_catalogue(name="MVFeeder210", load_point_name="Winter")
... for bus in en.buses.values():
... bus.geometry = None # Pretend buses don't have geometries
Expand Down
10 changes: 3 additions & 7 deletions doc/usage/Short_Circuit.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ a short-circuited bus. This is because having `I = (S/U)*` with `U=0` cannot be
... # Create the network
... en = rlf.ElectricalNetwork.from_element(bus1)
... return en
...

>>> # Create the network
... en = create_network()
Expand Down Expand Up @@ -167,17 +166,15 @@ are also zero indicating that the current of phase "a" went through the ground.

## Additional notes

The library will prevent the user from making mistakes, for example when trying to add a constant-power or
constant-current load on a short-circuited bus:
The library will prevent the user from making mistakes, for example when trying to add a voltage source, a
constant-power, or a constant-current load on a short-circuited bus:

```pycon
>>> try:
... load = rlf.PowerLoad("Load", bus=en.buses["Bus3"], powers=[10, 10, 10])
... except RoseauLoadFlowException as e:
... print(e)
...
The power load 'Load' is connected on bus 'Bus3' that already has a short-circuit.
It makes the short-circuit calculation impossible. [bad_short_circuit]
Cannot create power load 'Load' on short-circuited bus 'Bus3'. [bad_short_circuit]
```

At least two phases or a phase and a ground must be given when creating a short-circuit:
Expand All @@ -187,7 +184,6 @@ At least two phases or a phase and a ground must be given when creating a short-
... en.buses["Bus3"].add_short_circuit("a")
... except RoseauLoadFlowException as e:
... print(e)
...
For the short-circuit on bus 'Bus3', expected at least two phases or a phase and a ground.
Only phase 'a' is given. [bad_phase]
```
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "roseau-load-flow"
version = "0.16.0-alpha"
version = "0.16.0a1"
description = "Highly capable multi-phase load flow solver"
readme = "README.md"
requires-python = ">=3.12"
Expand Down Expand Up @@ -31,7 +31,7 @@ dependencies = [
"pint>=0.21.0",
"platformdirs>=4.0.0",
"pyproj>=3.3.0",
"roseau-load-flow-engine==0.19.2-alpha",
"roseau-load-flow-engine==0.19.2a1",
"shapely>=2.0.0",
"typing-extensions>=4.6.2",
]
Expand Down
5 changes: 4 additions & 1 deletion roseau/load_flow/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ class RoseauLoadFlowExceptionCode(StrEnum):
BAD_TRANSFORMER_IMPEDANCE = auto()
BAD_TRANSFORMER_PARAMETERS = auto()

# Transformer and line
# Regulator
BAD_REGULATOR_ID = auto()

# Transformer, line and regulator
BAD_MAX_LOADING_VALUE = auto()
BAD_PARAMETERS_ID = auto()

Expand Down
11 changes: 6 additions & 5 deletions roseau/load_flow/models/buses.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def add_short_circuit(self, *phases: str, ground: "Ground | None" = None) -> Non
ground:
If a ground is given, the phases will also be connected to the ground.
"""
from roseau.load_flow import CurrentLoad, PowerLoad
from roseau.load_flow import AbstractDisconnectable

for phase in phases:
if phase not in self.phases:
Expand All @@ -260,10 +260,11 @@ def add_short_circuit(self, *phases: str, ground: "Ground | None" = None) -> Non
logger.error(msg)
raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_PHASE)
for element in self._connected_elements:
if isinstance(element, (PowerLoad, CurrentLoad)):
if isinstance(element, AbstractDisconnectable) and not element._short_circuit_compatible:
et = f"{element.type} {element.element_type}"
msg = (
f"A {element.type} load {element.id!r} is already connected on bus {self.id!r}. "
f"It makes the short-circuit calculation impossible."
f"Cannot short-circuit bus {self.id!r} with a {et}. Disconnect the {et} "
f"{element.id!r} before adding the short-circuit."
)
logger.error(msg)
raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_SHORT_CIRCUIT)
Expand Down Expand Up @@ -496,7 +497,7 @@ def res_voltage_levels_pn(self) -> Q_[FloatArray] | None:
def res_violated(self) -> BoolArray | None:
"""Whether the bus has voltage limits violations.

Returns ``None`` if the bus has no voltage limits are not set.
Returns ``None`` if the bus has no voltage limits set.
"""
u_min = self._min_voltage_level
u_max = self._max_voltage_level
Expand Down
Loading
Loading