From f37b854e4d00082cfdd0f226f8e9d24f5358b348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 29 Aug 2023 12:30:59 +0200 Subject: [PATCH 01/43] First test --- .github/workflows/conda.yml | 16 +++++++++------- doc/Changelog.md | 6 ++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index ff47b426..cb993638 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -2,11 +2,11 @@ name: Conda on: push: - branches: [main] + branches: [main, develop, conda] tags: - "*" pull_request: - branches: [main] + branches: [main, develop, conda] env: CI: true @@ -47,17 +47,19 @@ jobs: with: auto-update-conda: true python-version: ${{ matrix.python-version }} + miniforge-variant: Mambaforge + use-mamba: true - name: Conda Build id: conda-build shell: bash -l {0} run: | - conda config --add channels conda-forge - conda config --set channel_priority strict - conda install --channel conda-forge conda-build conda-verify + mambaforge config --add channels conda-forge + mambaforge config --set channel_priority strict + mambaforge install --channel conda-forge conda-build conda-verify mkdir -p dist/ - conda build --output-folder dist/ conda/ - echo "CONDA_ARCHIVE=$(conda build --output-folder dist/ --output conda/)" >> $GITHUB_OUTPUT + mambaforge build --output-folder dist/ conda/ + echo "CONDA_ARCHIVE=$(mambaforge build --output-folder dist/ --output conda/)" >> $GITHUB_OUTPUT - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/doc/Changelog.md b/doc/Changelog.md index d5af9daf..6e134f13 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -1,5 +1,11 @@ # Changelog +## Version 0.6.0 + +**In development** + +- {gh-pr}`125` Speed-up build of conda workflow using mamba. + ## Version 0.5.0 - {gh-pr}`121` {gh-issue}`68` Improvements of the `LineParameters` constructor: From 3d16187c1ab513c61d680b452260500627bc225d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 29 Aug 2023 12:39:30 +0200 Subject: [PATCH 02/43] Second test --- .github/workflows/conda.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index cb993638..08ea6ded 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -54,12 +54,12 @@ jobs: id: conda-build shell: bash -l {0} run: | - mambaforge config --add channels conda-forge - mambaforge config --set channel_priority strict - mambaforge install --channel conda-forge conda-build conda-verify + mamba config --add channels conda-forge + mamba config --set channel_priority strict + mamba install --channel conda-forge conda-build conda-verify mkdir -p dist/ - mambaforge build --output-folder dist/ conda/ - echo "CONDA_ARCHIVE=$(mambaforge build --output-folder dist/ --output conda/)" >> $GITHUB_OUTPUT + mamba build --output-folder dist/ conda/ + echo "CONDA_ARCHIVE=$(mamba build --output-folder dist/ --output conda/)" >> $GITHUB_OUTPUT - name: Upload artifact uses: actions/upload-artifact@v3 From 1cf7813194f179cbb9bbc62b8290d23e91a8bee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 29 Aug 2023 14:52:47 +0200 Subject: [PATCH 03/43] Change branches --- .github/workflows/conda.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index 08ea6ded..76003e27 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -2,11 +2,11 @@ name: Conda on: push: - branches: [main, develop, conda] + branches: [main] tags: - "*" pull_request: - branches: [main, develop, conda] + branches: [main] env: CI: true From 8901aeb2680c4dd5386b489001d1cf92642c2589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Wed, 6 Sep 2023 11:39:02 +0200 Subject: [PATCH 04/43] Add some shortcut to the Line class --- roseau/load_flow/models/lines/lines.py | 36 +++++++++++++------ roseau/load_flow/models/tests/test_lines.py | 38 +++++++++++++++++++-- roseau/load_flow/solvers.py | 2 +- roseau/load_flow/tests/test_solvers.py | 2 +- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/roseau/load_flow/models/lines/lines.py b/roseau/load_flow/models/lines/lines.py index f6862de8..725212b5 100644 --- a/roseau/load_flow/models/lines/lines.py +++ b/roseau/load_flow/models/lines/lines.py @@ -217,7 +217,7 @@ def __init__( self._initialized = True # Handle the ground - if self.ground is not None and not self.parameters.with_shunt: + if self.ground is not None and not self.with_shunt: warnings.warn( message=( f"The ground element must not be provided for line {self.id!r} as it does not have a shunt " @@ -227,7 +227,7 @@ def __init__( stacklevel=2, ) self.ground = None - elif self.parameters.with_shunt: + elif self.with_shunt: # Connect the ground self._connect(self.ground) @@ -260,7 +260,7 @@ def parameters(self, value: LineParameters) -> None: raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_Z_LINE_SHAPE) if value.with_shunt: - if self._initialized and not self.parameters.with_shunt: + if self._initialized and not self.with_shunt: msg = "Cannot set line parameters with a shunt to a line that does not have shunt components." logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_LINE_MODEL) @@ -273,18 +273,33 @@ def parameters(self, value: LineParameters) -> None: logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_LINE_TYPE) else: - if self._initialized and self.parameters.with_shunt: + if self._initialized and self.with_shunt: msg = "Cannot set line parameters without a shunt to a line that has shunt components." logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_LINE_MODEL) self._parameters = value self._invalidate_network_results() + @property + @ureg_wraps("ohm", (None,), strict=False) + def z_line(self) -> Q_[np.ndarray]: + """Impedance of the line in Ohm""" + return self.parameters._z_line * self._length + + @property + @ureg_wraps("S", (None,), strict=False) + def y_shunt(self) -> Q_[np.ndarray]: + """Shunt admittance of the line in Siemens""" + return self.parameters._y_shunt * self._length + + @property + def with_shunt(self) -> bool: + return self.parameters.with_shunt + def _res_series_values_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: pot1, pot2 = self._res_potentials_getter(warning) # V du_line = pot1 - pot2 - z_line = self.parameters.z_line * self.length - i_line = np.linalg.inv(z_line.m_as("ohm")) @ du_line # Zₗ x Iₗ = ΔU -> I = Zₗ⁻¹ x ΔU + i_line = np.linalg.inv(self.z_line.m_as("ohm")) @ du_line # Zₗ x Iₗ = ΔU -> I = Zₗ⁻¹ x ΔU return du_line, i_line def _res_series_currents_getter(self, warning: bool) -> np.ndarray: @@ -308,19 +323,18 @@ def res_series_power_losses(self) -> Q_[np.ndarray]: return self._res_series_power_losses_getter(warning=True) def _res_shunt_values_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: - assert self.parameters.with_shunt, "this method only works when there is a shunt" - y_shunt = self.parameters.y_shunt + assert self.with_shunt, "This method only works when there is a shunt" assert self.ground is not None pot1, pot2 = self._res_potentials_getter(warning) vg = self.ground.res_potential.m_as("V") - y_shunt = (y_shunt * self.length).m_as("S") + y_shunt = self.y_shunt.m_as("S") yg = y_shunt.sum(axis=1) # y_ig = Y_ia + Y_ib + Y_ic + Y_in for i in {a, b, c, n} i1_shunt = (y_shunt @ pot1 - yg * vg) / 2 i2_shunt = (y_shunt @ pot2 - yg * vg) / 2 return pot1, pot2, i1_shunt, i2_shunt def _res_shunt_currents_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: - if not self.parameters.with_shunt: + if not self.with_shunt: zeros = np.zeros(len(self.phases), dtype=complex) return zeros[:], zeros[:] _, _, cur1, cur2 = self._res_shunt_values_getter(warning) @@ -333,7 +347,7 @@ def res_shunt_currents(self) -> tuple[Q_[np.ndarray], Q_[np.ndarray]]: return self._res_shunt_currents_getter(warning=True) def _res_shunt_power_losses_getter(self, warning: bool) -> np.ndarray: - if not self.parameters.with_shunt: + if not self.with_shunt: return np.zeros(len(self.phases), dtype=complex) pot1, pot2, cur1, cur2 = self._res_shunt_values_getter(warning) return pot1 * cur1.conj() + pot2 * cur2.conj() diff --git a/roseau/load_flow/models/tests/test_lines.py b/roseau/load_flow/models/tests/test_lines.py index bcfa954a..5d6f4d24 100644 --- a/roseau/load_flow/models/tests/test_lines.py +++ b/roseau/load_flow/models/tests/test_lines.py @@ -2,8 +2,8 @@ import pytest from pint import DimensionalityError -from roseau.load_flow import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.models import Bus, Line, LineParameters +from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode +from roseau.load_flow.models import Bus, Ground, Line, LineParameters from roseau.load_flow.units import Q_ @@ -61,3 +61,37 @@ def test_lines_units(): line = Line("line", bus1=bus1, bus2=bus2, parameters=lp, length=5) with pytest.raises(DimensionalityError, match=r"Cannot convert from 'ampere' \(\[current\]\) to 'km'"): line.length = Q_(6.5, "A") + + +def test_line_parameters_shortcut(): + bus1 = Bus("bus1", phases="abcn") + bus2 = Bus("bus1", phases="abcn") + + # + # Without shunt + # + lp = LineParameters("lp", z_line=np.eye(4, dtype=complex)) + + # Z + line = Line("line", bus1=bus1, bus2=bus2, parameters=lp, length=Q_(50, "m")) + assert np.allclose(line.z_line.m_as("ohm"), 0.05 * np.eye(4, dtype=complex)) + + # Y + assert not line.with_shunt + assert np.allclose(line.y_shunt.m_as("S"), np.zeros(shape=(4, 4), dtype=complex)) + + # + # With shunt + # + z_line = 0.01 * np.eye(4, dtype=complex) + y_shunt = 1e-5 * np.eye(4, dtype=complex) + lp = LineParameters("lp", z_line=z_line, y_shunt=y_shunt) + + # Z + ground = Ground("ground") + line = Line("line", bus1=bus1, bus2=bus2, parameters=lp, length=Q_(50, "m"), ground=ground) + assert np.allclose(line.z_line.m_as("ohm"), 0.05 * z_line) + + # Y + assert line.with_shunt + assert np.allclose(line.y_shunt.m_as("S"), 0.05 * y_shunt) diff --git a/roseau/load_flow/solvers.py b/roseau/load_flow/solvers.py index 5071c115..4ef18260 100644 --- a/roseau/load_flow/solvers.py +++ b/roseau/load_flow/solvers.py @@ -1,7 +1,7 @@ import logging from typing import Optional -from roseau.load_flow import RoseauLoadFlowException, RoseauLoadFlowExceptionCode +from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.typing import JsonDict, Solver logger = logging.getLogger(__name__) diff --git a/roseau/load_flow/tests/test_solvers.py b/roseau/load_flow/tests/test_solvers.py index f684d869..ac03fa59 100644 --- a/roseau/load_flow/tests/test_solvers.py +++ b/roseau/load_flow/tests/test_solvers.py @@ -1,6 +1,6 @@ import pytest -from roseau.load_flow import RoseauLoadFlowException, RoseauLoadFlowExceptionCode +from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.solvers import check_solver_params From f6926fd73821136edb397de8d098d4b72383584c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Wed, 6 Sep 2023 14:03:59 +0200 Subject: [PATCH 05/43] Changelog and doc --- doc/Changelog.md | 1 + doc/models/Line/ShuntLine.md | 22 ++++++++++++++++++++++ doc/models/Line/SimplifiedLine.md | 21 +++++++++++++++++++++ doc/models/Line/index.md | 9 +++++++-- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/doc/Changelog.md b/doc/Changelog.md index 6e134f13..89b6b4f8 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,7 @@ **In development** +- {gh-pr}`128` Add the properties `z_line`, `y_shunt` and `with_shunt` to the `Line` class. - {gh-pr}`125` Speed-up build of conda workflow using mamba. ## Version 0.5.0 diff --git a/doc/models/Line/ShuntLine.md b/doc/models/Line/ShuntLine.md index d0342b5a..363a5645 100644 --- a/doc/models/Line/ShuntLine.md +++ b/doc/models/Line/ShuntLine.md @@ -128,6 +128,28 @@ load = PowerLoad( id="load", bus=bus2, powers=Q_(np.array([5.0, 2.5, 0]) * (1 - 0.3j), "kVA") ) +# The impedance matrix (in Ohm) can be accessed from the line instance +line.z_line +# array( +# [[0.3+0.35j, 0. +0.25j, 0. +0.25j, 0. +0.25j], +# [0. +0.25j, 0.3+0.35j, 0. +0.25j, 0. +0.25j], +# [0. +0.25j, 0. +0.25j, 0.3+0.35j, 0. +0.25j], +# [0. +0.25j, 0. +0.25j, 0. +0.25j, 0.3+0.35j]] +# ) + +# The shunt admittance matrix (in Siemens) can be accessed from the line instance +line.y_shunt +# array( +# [[2.e-05+4.75e-04j, 0.e+00-6.80e-05j, 0.e+00-1.00e-05j, 0.e+00-6.80e-05j], +# [0.e+00-6.80e-05j, 2.e-05+4.75e-04j, 0.e+00-6.80e-05j, 0.e+00-1.00e-05j], +# [0.e+00-1.00e-05j, 0.e+00-6.80e-05j, 2.e-05+4.75e-04j, 0.e+00-6.80e-05j], +# [0.e+00-6.80e-05j, 0.e+00-1.00e-05j, 0.e+00-6.80e-05j, 2.e-05+4.75e-04j]] +# ) + +# For a shunt line, the property `with_shunt` is True +line.with_shunt +# True + # Create a network and solve a load flow en = ElectricalNetwork.from_element(bus1) auth = ("username", "password") diff --git a/doc/models/Line/SimplifiedLine.md b/doc/models/Line/SimplifiedLine.md index 45869da1..fa83c1bf 100644 --- a/doc/models/Line/SimplifiedLine.md +++ b/doc/models/Line/SimplifiedLine.md @@ -74,6 +74,27 @@ load = PowerLoad( id="load", bus=bus2, powers=Q_(np.array([5.0, 2.5, 0]) * (1 - 0.3j), "kVA") ) +# The impedance matrix (in Ohm) can be accessed from the line instance +line.z_line +# array( +# [[0.35+0.j, 0. +0.j, 0. +0.j, 0. +0.j], +# [0. +0.j, 0.35+0.j, 0. +0.j, 0. +0.j], +# [0. +0.j, 0. +0.j, 0.35+0.j, 0. +0.j], +# [0. +0.j, 0. +0.j, 0. +0.j, 0.35+0.j]] +# ) + +# For a simplified line, the property `with_shunt` is False and the `y_shunt` matrix is zero +line.with_shunt +# False + +line.y_shunt +# array( +# [[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], +# [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], +# [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], +# [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]] +# ) + # Create a network and solve a load flow en = ElectricalNetwork.from_element(bus1) auth = ("username", "password") diff --git a/doc/models/Line/index.md b/doc/models/Line/index.md index dc2cad5e..d622f17b 100644 --- a/doc/models/Line/index.md +++ b/doc/models/Line/index.md @@ -8,8 +8,8 @@ $\underline{Y}$. ## Matrices definition -Before diving into the different line models, lets define the series impedance matrix $Z$, and the -shunt admittance matrix $Y$ used to model the lines. +Before diving into the different line models, lets define the series impedance matrix $\underline{Z}$, and the +shunt admittance matrix $\underline{Y}$ used to model the lines. ### Series impedance matrix @@ -158,6 +158,11 @@ shunt_line_parameters = LineParameters( ) ``` +```{tip} +The `Line` instance itself has the `z_line` and `y_shunt` properties. They retrieve the line impedance in $\Omega$ +and the line shunt admittance in Siemens (taking into account the length of the line). +``` + There are several alternative constructors for `LineParameters` objects. The description of them can be found in the dedicated [Line parameters page](Parameters.md). From 2b2d901e70e31cdd27e2480b821a2828f1f9093c Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Tue, 19 Sep 2023 14:06:07 +0200 Subject: [PATCH 06/43] Fix pint warnings and remove conditional import (#129) This PR fixes warnings when a pint quantity is transformed into a numpy array. It also removes a conditional import from typing_extensions as we have it as a dependency now. --- .gitignore | 3 +++ roseau/load_flow/models/lines/parameters.py | 2 +- .../models/tests/test_transformer_parameters.py | 12 ++++++++---- roseau/load_flow/typing.py | 12 +++--------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index c8dd5045..bd430e34 100644 --- a/.gitignore +++ b/.gitignore @@ -246,3 +246,6 @@ benchmark/*.mtx *.log .ruff_cache/ doc/images/*.pdf + +roseau/* +!roseau/load_flow diff --git a/roseau/load_flow/models/lines/parameters.py b/roseau/load_flow/models/lines/parameters.py index 9c21bd78..c64731d0 100644 --- a/roseau/load_flow/models/lines/parameters.py +++ b/roseau/load_flow/models/lines/parameters.py @@ -455,7 +455,7 @@ def _geometry_to_zy( c[mask_off_diagonal] = -lambda_inv[mask_off_diagonal] g = np.zeros((4, 4), dtype=float) # conductance (S/km) omega = OMEGA.m_as("rad/s") - g[mask_diagonal] = TAN_D[insulator_type] * np.einsum("ii->i", c) * omega + g[mask_diagonal] = TAN_D[insulator_type].magnitude * np.einsum("ii->i", c) * omega # Build the impedance and admittance matrices z_line = r + inductance * omega * 1j diff --git a/roseau/load_flow/models/tests/test_transformer_parameters.py b/roseau/load_flow/models/tests/test_transformer_parameters.py index 09920c4c..61a28c78 100644 --- a/roseau/load_flow/models/tests/test_transformer_parameters.py +++ b/roseau/load_flow/models/tests/test_transformer_parameters.py @@ -1,5 +1,6 @@ +import numbers + import numpy as np -import pandas as pd import pytest from pint import DimensionalityError @@ -350,9 +351,12 @@ def test_catalogue_data(): assert np.isclose(tp.psc.m_as("W"), catalogue_data.at[tp.id, "psc"]) assert np.isclose(tp.vsc.m_as(""), catalogue_data.at[tp.id, "vsc"]) - # Check that the transformer can be used - res = tp.to_zyk() - assert all(pd.notna(x) for x in res) + # Check that the parameters are valid + z, y, k, orientation = tp.to_zyk() + assert isinstance(z.m_as("ohm"), numbers.Number) + assert isinstance(y.m_as("S"), numbers.Number) + assert isinstance(k.m_as(""), numbers.Number) + assert orientation in (-1.0, 1.0) # At the end of the process, the found column must be full of True assert catalogue_data["found"].all(), error_message diff --git a/roseau/load_flow/typing.py b/roseau/load_flow/typing.py index b779a96c..52c8a293 100644 --- a/roseau/load_flow/typing.py +++ b/roseau/load_flow/typing.py @@ -26,15 +26,9 @@ Available solvers for the load flow computation. """ import os -import sys -from typing import TYPE_CHECKING, Any, Literal, Union - -if sys.version_info >= (3, 10): - from typing import TypeAlias as TypeAlias -elif TYPE_CHECKING: - from typing_extensions import TypeAlias as TypeAlias -else: - TypeAlias = Any +from typing import Any, Literal, Union + +from typing_extensions import TypeAlias Id: TypeAlias = Union[int, str] JsonDict: TypeAlias = dict[str, Any] From 2333f91d0dbbc0a2d8fd6929fd7e4c68c30d9724 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Tue, 19 Sep 2023 14:56:58 +0200 Subject: [PATCH 07/43] Mark internal attributes as private (#130) To avoid someone typing: ```python Control.DEFAULT_ALPHA = 2000 control = Control("constant", 220, 225, 235, 240) # no alpha provided ``` and expecting to see the new default value. --- doc/Changelog.md | 1 + .../models/loads/flexible_parameters.py | 52 +++++++++---------- roseau/load_flow/models/tests/test_loads.py | 4 +- roseau/load_flow/network.py | 36 ++++--------- .../tests/test_electrical_network.py | 10 ++-- 5 files changed, 44 insertions(+), 59 deletions(-) diff --git a/doc/Changelog.md b/doc/Changelog.md index 89b6b4f8..1ad7d719 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,7 @@ **In development** +- {gh-pr}`130` Mark some internal attributes as private, they were previously marked as public. - {gh-pr}`128` Add the properties `z_line`, `y_shunt` and `with_shunt` to the `Line` class. - {gh-pr}`125` Speed-up build of conda workflow using mamba. diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index 55cdc7f6..712c9904 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -34,7 +34,7 @@ class Control(JsonMixin): :ref:`Control documentation ` """ - DEFAULT_ALPHA: float = 1000.0 + _DEFAULT_ALPHA: float = 1000.0 @ureg_wraps(None, (None, None, "V", "V", "V", "V", None), strict=False) def __init__( @@ -44,7 +44,7 @@ def __init__( u_down: float, u_up: float, u_max: float, - alpha: float = DEFAULT_ALPHA, + alpha: float = _DEFAULT_ALPHA, ) -> None: """Control constructor. @@ -180,7 +180,7 @@ def constant(cls) -> Self: @classmethod @ureg_wraps(None, (None, "V", "V", None), strict=False) - def p_max_u_production(cls, u_up: float, u_max: float, alpha: float = DEFAULT_ALPHA) -> Self: + def p_max_u_production(cls, u_up: float, u_max: float, alpha: float = _DEFAULT_ALPHA) -> Self: """Create a control of the type ``"p_max_u_production"``. See Also: @@ -209,7 +209,7 @@ def p_max_u_production(cls, u_up: float, u_max: float, alpha: float = DEFAULT_AL @classmethod @ureg_wraps(None, (None, "V", "V", None), strict=False) - def p_max_u_consumption(cls, u_min: float, u_down: float, alpha: float = DEFAULT_ALPHA) -> Self: + def p_max_u_consumption(cls, u_min: float, u_down: float, alpha: float = _DEFAULT_ALPHA) -> Self: """Create a control of the type ``"p_max_u_consumption"``. See Also: @@ -238,7 +238,7 @@ def p_max_u_consumption(cls, u_min: float, u_down: float, alpha: float = DEFAULT @classmethod @ureg_wraps(None, (None, "V", "V", "V", "V", None), strict=False) - def q_u(cls, u_min: float, u_down: float, u_up: float, u_max: float, alpha: float = DEFAULT_ALPHA) -> Self: + def q_u(cls, u_min: float, u_down: float, u_up: float, u_max: float, alpha: float = _DEFAULT_ALPHA) -> Self: """Create a control of the type ``"q_u"``. See Also: @@ -280,7 +280,7 @@ def q_u(cls, u_min: float, u_down: float, u_up: float, u_max: float, alpha: floa # @classmethod def from_dict(cls, data: JsonDict) -> Self: - alpha = data["alpha"] if "alpha" in data else cls.DEFAULT_ALPHA + alpha = data["alpha"] if "alpha" in data else cls._DEFAULT_ALPHA if data["type"] == "constant": return cls.constant() elif data["type"] == "p_max_u_production": @@ -340,10 +340,10 @@ class Projection(JsonMixin): :ref:`Projection documentation ` """ - DEFAULT_ALPHA: float = 1000.0 - DEFAULT_EPSILON: float = 1e-8 + _DEFAULT_ALPHA: float = 1000.0 + _DEFAULT_EPSILON: float = 1e-8 - def __init__(self, type: ProjectionType, alpha: float = DEFAULT_ALPHA, epsilon: float = DEFAULT_EPSILON) -> None: + def __init__(self, type: ProjectionType, alpha: float = _DEFAULT_ALPHA, epsilon: float = _DEFAULT_EPSILON) -> None: """Projection constructor. Args: @@ -406,8 +406,8 @@ def epsilon(self) -> float: # @classmethod def from_dict(cls, data: JsonDict) -> Self: - alpha = data["alpha"] if "alpha" in data else cls.DEFAULT_ALPHA - epsilon = data["epsilon"] if "epsilon" in data else cls.DEFAULT_EPSILON + alpha = data["alpha"] if "alpha" in data else cls._DEFAULT_ALPHA + epsilon = data["epsilon"] if "epsilon" in data else cls._DEFAULT_EPSILON return cls(type=data["type"], alpha=alpha, epsilon=epsilon) def to_dict(self, include_geometry: bool = True) -> JsonDict: @@ -502,9 +502,9 @@ def p_max_u_production( u_up: float, u_max: float, s_max: float, - alpha_control: float = Control.DEFAULT_ALPHA, - alpha_proj: float = Projection.DEFAULT_ALPHA, - epsilon_proj: float = Projection.DEFAULT_EPSILON, + alpha_control: float = Control._DEFAULT_ALPHA, + alpha_proj: float = Projection._DEFAULT_ALPHA, + epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: """Build flexible parameters for production ``P(U)`` control with a Euclidean projection. @@ -554,9 +554,9 @@ def p_max_u_consumption( u_min: float, u_down: float, s_max: float, - alpha_control: float = Control.DEFAULT_ALPHA, - alpha_proj: float = Projection.DEFAULT_ALPHA, - epsilon_proj: float = Projection.DEFAULT_EPSILON, + alpha_control: float = Control._DEFAULT_ALPHA, + alpha_proj: float = Projection._DEFAULT_ALPHA, + epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: """Build flexible parameters for consumption ``P(U)`` control with a Euclidean projection. @@ -605,9 +605,9 @@ def q_u( u_up: float, u_max: float, s_max: float, - alpha_control: float = Control.DEFAULT_ALPHA, - alpha_proj: float = Projection.DEFAULT_ALPHA, - epsilon_proj: float = Projection.DEFAULT_EPSILON, + alpha_control: float = Control._DEFAULT_ALPHA, + alpha_proj: float = Projection._DEFAULT_ALPHA, + epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: """Build flexible parameters for ``Q(U)`` control with a Euclidean projection. @@ -665,9 +665,9 @@ def pq_u_production( uq_up: float, uq_max: float, s_max: float, - alpha_control=Control.DEFAULT_ALPHA, - alpha_proj=Projection.DEFAULT_ALPHA, - epsilon_proj=Projection.DEFAULT_EPSILON, + alpha_control=Control._DEFAULT_ALPHA, + alpha_proj=Projection._DEFAULT_ALPHA, + epsilon_proj=Projection._DEFAULT_EPSILON, ) -> Self: """Build flexible parameters for production ``P(U)`` control and ``Q(U)`` control with a Euclidean projection. @@ -736,9 +736,9 @@ def pq_u_consumption( uq_up: float, uq_max: float, s_max: float, - alpha_control: float = Control.DEFAULT_ALPHA, - alpha_proj: float = Projection.DEFAULT_ALPHA, - epsilon_proj: float = Projection.DEFAULT_EPSILON, + alpha_control: float = Control._DEFAULT_ALPHA, + alpha_proj: float = Projection._DEFAULT_ALPHA, + epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: """Build flexible parameters for consumption ``P(U)`` control and ``Q(U)`` control with a Euclidean projection. diff --git a/roseau/load_flow/models/tests/test_loads.py b/roseau/load_flow/models/tests/test_loads.py index d4244542..7276b0e5 100644 --- a/roseau/load_flow/models/tests/test_loads.py +++ b/roseau/load_flow/models/tests/test_loads.py @@ -305,8 +305,8 @@ def test_loads_to_dict(): "control_q": {"type": "constant"}, "projection": { "type": "euclidean", - "alpha": Projection.DEFAULT_ALPHA, - "epsilon": Projection.DEFAULT_EPSILON, + "alpha": Projection._DEFAULT_ALPHA, + "epsilon": Projection._DEFAULT_EPSILON, }, "s_max": 1.0, }, diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index 01c51c13..e4b5c974 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -92,22 +92,6 @@ class ElectricalNetwork(JsonMixin, CatalogueMixin[JsonDict]): be connected to a bus or to a ground. Attributes: - DEFAULT_TOLERANCE (float): - The default tolerance needed for the convergence of the load flow solver. At each - iteration, the solver computes the residuals of the equations of the problem. When the - maximum of the absolute values of the residuals vector is lower than the provided - tolerance, the solver stops. Default is 1e-6. - - DEFAULT_MAX_ITERATIONS (int): - Maximum number of iterations to perform the load flow analysis. The solver stops when - this number of iterations is reached. Default is 20. - - DEFAULT_BASE_URL (str): - Base URL of the Roseau Load Flow API endpoint. - - DEFAULT_SOLVER (str): - The default solver to compute the load flow. - buses (dict[Id, roseau.load_flow.Bus]): Dictionary of buses of the network indexed by their IDs. Also available as a :attr:`GeoDataFrame`. @@ -148,11 +132,11 @@ class ElectricalNetwork(JsonMixin, CatalogueMixin[JsonDict]): } """ - DEFAULT_TOLERANCE: float = 1e-6 - DEFAULT_MAX_ITERATIONS: int = 20 - DEFAULT_BASE_URL: str = "https://load-flow-api-dev.roseautechnologies.com/" - DEFAULT_WARM_START: bool = True - DEFAULT_SOLVER: Solver = "newton_goldstein" + _DEFAULT_TOLERANCE: float = 1e-6 + _DEFAULT_MAX_ITERATIONS: int = 20 + _DEFAULT_BASE_URL: str = "https://load-flow-api-dev.roseautechnologies.com/" + _DEFAULT_WARM_START: bool = True + _DEFAULT_SOLVER: Solver = "newton_goldstein" # Elements classes (for internal use only) _branch_class = AbstractBranch @@ -374,11 +358,11 @@ def short_circuits_frame(self) -> pd.DataFrame: def solve_load_flow( self, auth: Union[tuple[str, str], HTTPBasicAuth], - base_url: str = DEFAULT_BASE_URL, - max_iterations: int = DEFAULT_MAX_ITERATIONS, - tolerance: float = DEFAULT_TOLERANCE, - warm_start: bool = DEFAULT_WARM_START, - solver: Solver = DEFAULT_SOLVER, + base_url: str = _DEFAULT_BASE_URL, + max_iterations: int = _DEFAULT_MAX_ITERATIONS, + tolerance: float = _DEFAULT_TOLERANCE, + warm_start: bool = _DEFAULT_WARM_START, + solver: Solver = _DEFAULT_SOLVER, solver_params: Optional[JsonDict] = None, ) -> int: """Solve the load flow for this network (Requires internet access). diff --git a/roseau/load_flow/tests/test_electrical_network.py b/roseau/load_flow/tests/test_electrical_network.py index 33331316..1dbdd471 100644 --- a/roseau/load_flow/tests/test_electrical_network.py +++ b/roseau/load_flow/tests/test_electrical_network.py @@ -520,7 +520,7 @@ def test_solve_load_flow(small_network, good_json_results): # Good result # Request the server - solve_url = urljoin(ElectricalNetwork.DEFAULT_BASE_URL, "solve/") + solve_url = urljoin(ElectricalNetwork._DEFAULT_BASE_URL, "solve/") with requests_mock.Mocker() as m: m.post(solve_url, status_code=200, json=good_json_results, headers={"content-type": "application/json"}) small_network.solve_load_flow(auth=("", "")) @@ -607,7 +607,7 @@ def test_solve_load_flow(small_network, good_json_results): def test_solve_load_flow_error(small_network): # Solve url - solve_url = urljoin(ElectricalNetwork.DEFAULT_BASE_URL, "solve/") + solve_url = urljoin(ElectricalNetwork._DEFAULT_BASE_URL, "solve/") # Parse RLF error json_result = {"msg": "toto", "code": "roseau.load_flow.bad_branch_type"} @@ -778,7 +778,7 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): {"id": "pref", "current": [-1.2500243895541274e-13, 0.0]}, ], } - solve_url = urljoin(ElectricalNetwork.DEFAULT_BASE_URL, "solve/") + solve_url = urljoin(ElectricalNetwork._DEFAULT_BASE_URL, "solve/") with requests_mock.Mocker() as m: m.post(solve_url, status_code=200, json=json_results, headers={"content-type": "application/json"}) single_phase_network.solve_load_flow(auth=("", "")) @@ -1036,7 +1036,7 @@ def test_network_results_warning(small_network: ElectricalNetwork, good_json_res assert e.value.args[1] == RoseauLoadFlowExceptionCode.LOAD_FLOW_NOT_RUN # Solve a load flow - solve_url = urljoin(ElectricalNetwork.DEFAULT_BASE_URL, "solve/") + solve_url = urljoin(ElectricalNetwork._DEFAULT_BASE_URL, "solve/") with requests_mock.Mocker() as m: m.post(solve_url, status_code=200, json=good_json_results, headers={"content-type": "application/json"}) small_network.solve_load_flow(auth=("", "")) @@ -1310,7 +1310,7 @@ def set_index_dtype(df, dtype): def test_solver_warm_start(small_network: ElectricalNetwork, good_json_results): load: PowerLoad = small_network.loads["load"] load_bus = small_network.buses["bus1"] - solve_url = urljoin(ElectricalNetwork.DEFAULT_BASE_URL, "solve/") + solve_url = urljoin(ElectricalNetwork._DEFAULT_BASE_URL, "solve/") headers = {"Content-Type": "application/json"} def json_callback(request, context): From 293c7c62b913bcb4e640f560b604dea8d876cec4 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Tue, 19 Sep 2023 15:58:13 +0200 Subject: [PATCH 08/43] Fix new pandas warning --- roseau/load_flow/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index e4b5c974..babd5714 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -662,7 +662,7 @@ def res_branches(self) -> pd.DataFrame: "potential2": complex, } ) - .groupby(["branch_id", "phase"]) # aggregate x1 and x2 for the same phase + .groupby(["branch_id", "phase"], observed=True) # aggregate x1 and x2 for the same phase .mean() # 2 values; only one is not nan -> keep it .dropna(how="all") # if all values are nan -> drop the row (the phase does not exist) ) From d7306875aaa268e81921b7e02df1e0edcfa0a482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Wed, 13 Sep 2023 18:58:58 +0200 Subject: [PATCH 09/43] Update dependencies --- .pre-commit-config.yaml | 8 +- poetry.lock | 361 ++++++++++++++++++++-------------------- pyproject.toml | 4 +- 3 files changed, 184 insertions(+), 189 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 80f04937..5914a31b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,11 +17,11 @@ repos: hooks: - id: poetry-check - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.7.0 # keep in sync with pyproject.toml + rev: 23.9.1 # keep in sync with pyproject.toml hooks: - id: black-jupyter - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.286 # keep in sync with pyproject.toml + rev: v0.0.289 # keep in sync with pyproject.toml hooks: - id: ruff types_or: [python, pyi, jupyter] @@ -32,9 +32,9 @@ repos: - id: blacken-docs entry: bash -c "blacken-docs -l 90 $(find doc/ -name '*.md')" args: [-l 90] - additional_dependencies: [black==23.7.0] # keep in sync with black above + additional_dependencies: [black==23.9.1] # keep in sync with black above - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.2 + rev: v3.0.3 hooks: - id: prettier args: ["--print-width", "120"] diff --git a/poetry.lock b/poetry.lock index e6021b73..bd95107b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -54,17 +54,17 @@ wrapt = [ [[package]] name = "asttokens" -version = "2.2.1" +version = "2.4.0" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"}, - {file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"}, + {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, + {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, ] [package.dependencies] -six = "*" +six = ">=1.12.0" [package.extras] test = ["astroid", "pytest"] @@ -129,33 +129,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "23.7.0" +version = "23.9.1" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, - {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, - {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, - {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, - {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, - {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, - {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, - {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, - {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, - {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, - {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"}, + {file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"}, + {file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"}, + {file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"}, + {file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"}, + {file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"}, + {file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"}, + {file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"}, + {file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"}, + {file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"}, + {file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"}, ] [package.dependencies] @@ -167,7 +167,7 @@ pathspec = ">=0.9.0" platformdirs = ">=2" tokenize-rt = {version = ">=3.2.0", optional = true, markers = "extra == \"jupyter\""} tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -342,63 +342,63 @@ files = [ [[package]] name = "coverage" -version = "7.3.0" +version = "7.3.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, - {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, - {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, - {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, - {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, - {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, - {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, - {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, - {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, - {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, - {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, - {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, - {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, - {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, + {file = "coverage-7.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd0f7429ecfd1ff597389907045ff209c8fdb5b013d38cfa7c60728cb484b6e3"}, + {file = "coverage-7.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:966f10df9b2b2115da87f50f6a248e313c72a668248be1b9060ce935c871f276"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0575c37e207bb9b98b6cf72fdaaa18ac909fb3d153083400c2d48e2e6d28bd8e"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:245c5a99254e83875c7fed8b8b2536f040997a9b76ac4c1da5bff398c06e860f"}, + {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c96dd7798d83b960afc6c1feb9e5af537fc4908852ef025600374ff1a017392"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:de30c1aa80f30af0f6b2058a91505ea6e36d6535d437520067f525f7df123887"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:50dd1e2dd13dbbd856ffef69196781edff26c800a74f070d3b3e3389cab2600d"}, + {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9c0c19f70d30219113b18fe07e372b244fb2a773d4afde29d5a2f7930765136"}, + {file = "coverage-7.3.1-cp310-cp310-win32.whl", hash = "sha256:770f143980cc16eb601ccfd571846e89a5fe4c03b4193f2e485268f224ab602f"}, + {file = "coverage-7.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdd088c00c39a27cfa5329349cc763a48761fdc785879220d54eb785c8a38520"}, + {file = "coverage-7.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74bb470399dc1989b535cb41f5ca7ab2af561e40def22d7e188e0a445e7639e3"}, + {file = "coverage-7.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:025ded371f1ca280c035d91b43252adbb04d2aea4c7105252d3cbc227f03b375"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6191b3a6ad3e09b6cfd75b45c6aeeffe7e3b0ad46b268345d159b8df8d835f9"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7eb0b188f30e41ddd659a529e385470aa6782f3b412f860ce22b2491c89b8593"}, + {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c8f0df9dfd8ff745bccff75867d63ef336e57cc22b2908ee725cc552689ec8"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eb3cd48d54b9bd0e73026dedce44773214064be93611deab0b6a43158c3d5a0"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ac3c5b7e75acac31e490b7851595212ed951889918d398b7afa12736c85e13ce"}, + {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b4ee7080878077af0afa7238df1b967f00dc10763f6e1b66f5cced4abebb0a3"}, + {file = "coverage-7.3.1-cp311-cp311-win32.whl", hash = "sha256:229c0dd2ccf956bf5aeede7e3131ca48b65beacde2029f0361b54bf93d36f45a"}, + {file = "coverage-7.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c6f55d38818ca9596dc9019eae19a47410d5322408140d9a0076001a3dcb938c"}, + {file = "coverage-7.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5289490dd1c3bb86de4730a92261ae66ea8d44b79ed3cc26464f4c2cde581fbc"}, + {file = "coverage-7.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca833941ec701fda15414be400c3259479bfde7ae6d806b69e63b3dc423b1832"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd694e19c031733e446c8024dedd12a00cda87e1c10bd7b8539a87963685e969"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aab8e9464c00da5cb9c536150b7fbcd8850d376d1151741dd0d16dfe1ba4fd26"}, + {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d38444efffd5b056fcc026c1e8d862191881143c3aa80bb11fcf9dca9ae204"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8a07b692129b8a14ad7a37941a3029c291254feb7a4237f245cfae2de78de037"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2829c65c8faaf55b868ed7af3c7477b76b1c6ebeee99a28f59a2cb5907a45760"}, + {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f111a7d85658ea52ffad7084088277135ec5f368457275fc57f11cebb15607f"}, + {file = "coverage-7.3.1-cp312-cp312-win32.whl", hash = "sha256:c397c70cd20f6df7d2a52283857af622d5f23300c4ca8e5bd8c7a543825baa5a"}, + {file = "coverage-7.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:5ae4c6da8b3d123500f9525b50bf0168023313963e0e2e814badf9000dd6ef92"}, + {file = "coverage-7.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca70466ca3a17460e8fc9cea7123c8cbef5ada4be3140a1ef8f7b63f2f37108f"}, + {file = "coverage-7.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f2781fd3cabc28278dc982a352f50c81c09a1a500cc2086dc4249853ea96b981"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6407424621f40205bbe6325686417e5e552f6b2dba3535dd1f90afc88a61d465"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04312b036580ec505f2b77cbbdfb15137d5efdfade09156961f5277149f5e344"}, + {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9ad38204887349853d7c313f53a7b1c210ce138c73859e925bc4e5d8fc18e7"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:53669b79f3d599da95a0afbef039ac0fadbb236532feb042c534fbb81b1a4e40"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:614f1f98b84eb256e4f35e726bfe5ca82349f8dfa576faabf8a49ca09e630086"}, + {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1a317fdf5c122ad642db8a97964733ab7c3cf6009e1a8ae8821089993f175ff"}, + {file = "coverage-7.3.1-cp38-cp38-win32.whl", hash = "sha256:defbbb51121189722420a208957e26e49809feafca6afeef325df66c39c4fdb3"}, + {file = "coverage-7.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:f4f456590eefb6e1b3c9ea6328c1e9fa0f1006e7481179d749b3376fc793478e"}, + {file = "coverage-7.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f12d8b11a54f32688b165fd1a788c408f927b0960984b899be7e4c190ae758f1"}, + {file = "coverage-7.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f09195dda68d94a53123883de75bb97b0e35f5f6f9f3aa5bf6e496da718f0cb6"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6601a60318f9c3945be6ea0f2a80571f4299b6801716f8a6e4846892737ebe4"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d156269718670d00a3b06db2288b48527fc5f36859425ff7cec07c6b367745"}, + {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:636a8ac0b044cfeccae76a36f3b18264edcc810a76a49884b96dd744613ec0b7"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5d991e13ad2ed3aced177f524e4d670f304c8233edad3210e02c465351f785a0"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:586649ada7cf139445da386ab6f8ef00e6172f11a939fc3b2b7e7c9082052fa0"}, + {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4aba512a15a3e1e4fdbfed2f5392ec221434a614cc68100ca99dcad7af29f3f8"}, + {file = "coverage-7.3.1-cp39-cp39-win32.whl", hash = "sha256:6bc6f3f4692d806831c136c5acad5ccedd0262aa44c087c46b7101c77e139140"}, + {file = "coverage-7.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:553d7094cb27db58ea91332e8b5681bac107e7242c23f7629ab1316ee73c4981"}, + {file = "coverage-7.3.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:220eb51f5fb38dfdb7e5d54284ca4d0cd70ddac047d750111a68ab1798945194"}, + {file = "coverage-7.3.1.tar.gz", hash = "sha256:6cb7fe1581deb67b782c153136541e20901aa312ceedaf1467dcb35255787952"}, ] [package.dependencies] @@ -546,13 +546,13 @@ test = ["Fiona[s3]", "pytest (>=7)", "pytest-cov", "pytz"] [[package]] name = "furo" -version = "2023.8.19" +version = "2023.9.10" description = "A clean customisable Sphinx documentation theme." optional = false python-versions = ">=3.8" files = [ - {file = "furo-2023.8.19-py3-none-any.whl", hash = "sha256:12f99f87a1873b6746228cfde18f77244e6c1ffb85d7fed95e638aae70d80590"}, - {file = "furo-2023.8.19.tar.gz", hash = "sha256:e671ee638ab3f1b472f4033b0167f502ab407830e0db0f843b1c1028119c9cd1"}, + {file = "furo-2023.9.10-py3-none-any.whl", hash = "sha256:513092538537dc5c596691da06e3c370714ec99bc438680edc1debffb73e5bfc"}, + {file = "furo-2023.9.10.tar.gz", hash = "sha256:5707530a476d2a63b8cad83b4f961f3739a69f4b058bcf38a03a39fa537195b2"}, ] [package.dependencies] @@ -581,13 +581,13 @@ shapely = ">=1.7.1" [[package]] name = "identify" -version = "2.5.27" +version = "2.5.28" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.27-py2.py3-none-any.whl", hash = "sha256:fdb527b2dfe24602809b2201e033c2a113d7bdf716db3ca8e3243f735dcecaba"}, - {file = "identify-2.5.27.tar.gz", hash = "sha256:287b75b04a0e22d727bc9a41f0d4f3c1bcada97490fa6eabb5b28f0e9097e733"}, + {file = "identify-2.5.28-py2.py3-none-any.whl", hash = "sha256:87816de144bf46d161bd5b3e8f5596b16cade3b80be537087334b26bc5c177f3"}, + {file = "identify-2.5.28.tar.gz", hash = "sha256:94bb59643083ebd60dc996d043497479ee554381fbc5307763915cda49b0e78f"}, ] [package.extras] @@ -647,13 +647,13 @@ files = [ [[package]] name = "ipython" -version = "8.14.0" +version = "8.15.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" files = [ - {file = "ipython-8.14.0-py3-none-any.whl", hash = "sha256:248aca623f5c99a6635bc3857677b7320b9b8039f99f070ee0d20a5ca5a8e6bf"}, - {file = "ipython-8.14.0.tar.gz", hash = "sha256:1d197b907b6ba441b692c48cf2a3a2de280dc0ac91a3405b39349a50272ca0a1"}, + {file = "ipython-8.15.0-py3-none-any.whl", hash = "sha256:45a2c3a529296870a97b7de34eda4a31bee16bc7bf954e07d39abe49caf8f887"}, + {file = "ipython-8.15.0.tar.gz", hash = "sha256:2baeb5be6949eeebf532150f81746f8333e2ccce02de1c7eedde3f23ed5e9f1e"}, ] [package.dependencies] @@ -661,6 +661,7 @@ appnope = {version = "*", markers = "sys_platform == \"darwin\""} backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} @@ -672,9 +673,9 @@ traitlets = ">=5" typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [package.extras] -all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] black = ["black"] -doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] @@ -1004,70 +1005,64 @@ files = [ [[package]] name = "pandas" -version = "2.0.3" +version = "2.1.0" description = "Powerful data structures for data analysis, time series, and statistics" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pandas-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8"}, - {file = "pandas-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f"}, - {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183"}, - {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0"}, - {file = "pandas-2.0.3-cp310-cp310-win32.whl", hash = "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210"}, - {file = "pandas-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e"}, - {file = "pandas-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8"}, - {file = "pandas-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26"}, - {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d"}, - {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df"}, - {file = "pandas-2.0.3-cp311-cp311-win32.whl", hash = "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd"}, - {file = "pandas-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b"}, - {file = "pandas-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061"}, - {file = "pandas-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5"}, - {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089"}, - {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0"}, - {file = "pandas-2.0.3-cp38-cp38-win32.whl", hash = "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02"}, - {file = "pandas-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78"}, - {file = "pandas-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b"}, - {file = "pandas-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e"}, - {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b"}, - {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641"}, - {file = "pandas-2.0.3-cp39-cp39-win32.whl", hash = "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682"}, - {file = "pandas-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc"}, - {file = "pandas-2.0.3.tar.gz", hash = "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c"}, + {file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"}, + {file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"}, + {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"}, + {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"}, + {file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"}, + {file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"}, + {file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"}, + {file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"}, + {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"}, + {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"}, + {file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"}, + {file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"}, + {file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"}, + {file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"}, + {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"}, + {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"}, + {file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"}, + {file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"}, + {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, ] [package.dependencies] numpy = [ - {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" tzdata = ">=2022.1" [package.extras] -all = ["PyQt5 (>=5.15.1)", "SQLAlchemy (>=1.4.16)", "beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "s3fs (>=2021.08.0)", "scipy (>=1.7.1)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] -aws = ["s3fs (>=2021.08.0)"] -clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] -compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] -computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] +all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] +aws = ["s3fs (>=2022.05.0)"] +clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] +compression = ["zstandard (>=0.17.0)"] +computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2021.07.0)"] -gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] -hdf5 = ["tables (>=3.6.1)"] -html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] -mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] +fss = ["fsspec (>=2022.05.0)"] +gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] +hdf5 = ["tables (>=3.7.0)"] +html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] +mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] +performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] -spss = ["pyreadstat (>=1.1.2)"] -sql-other = ["SQLAlchemy (>=1.4.16)"] -test = ["hypothesis (>=6.34.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.6.3)"] +postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] +spss = ["pyreadstat (>=1.1.5)"] +sql-other = ["SQLAlchemy (>=1.4.36)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.8.0)"] [[package]] name = "parso" @@ -1176,13 +1171,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.3.3" +version = "3.4.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.8" files = [ - {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"}, - {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"}, + {file = "pre_commit-3.4.0-py2.py3-none-any.whl", hash = "sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945"}, + {file = "pre_commit-3.4.0.tar.gz", hash = "sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522"}, ] [package.dependencies] @@ -1318,13 +1313,13 @@ certifi = "*" [[package]] name = "pytest" -version = "7.4.0" +version = "7.4.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, ] [package.dependencies] @@ -1392,13 +1387,13 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2023.3" +version = "2023.3.post1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, - {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, ] [[package]] @@ -1607,45 +1602,45 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.0.286" +version = "0.0.289" description = "An extremely fast Python linter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.0.286-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:8e22cb557e7395893490e7f9cfea1073d19a5b1dd337f44fd81359b2767da4e9"}, - {file = "ruff-0.0.286-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:68ed8c99c883ae79a9133cb1a86d7130feee0397fdf5ba385abf2d53e178d3fa"}, - {file = "ruff-0.0.286-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8301f0bb4ec1a5b29cfaf15b83565136c47abefb771603241af9d6038f8981e8"}, - {file = "ruff-0.0.286-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:acc4598f810bbc465ce0ed84417ac687e392c993a84c7eaf3abf97638701c1ec"}, - {file = "ruff-0.0.286-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88c8e358b445eb66d47164fa38541cfcc267847d1e7a92dd186dddb1a0a9a17f"}, - {file = "ruff-0.0.286-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0433683d0c5dbcf6162a4beb2356e820a593243f1fa714072fec15e2e4f4c939"}, - {file = "ruff-0.0.286-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddb61a0c4454cbe4623f4a07fef03c5ae921fe04fede8d15c6e36703c0a73b07"}, - {file = "ruff-0.0.286-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:47549c7c0be24c8ae9f2bce6f1c49fbafea83bca80142d118306f08ec7414041"}, - {file = "ruff-0.0.286-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:559aa793149ac23dc4310f94f2c83209eedb16908a0343663be19bec42233d25"}, - {file = "ruff-0.0.286-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d73cfb1c3352e7aa0ce6fb2321f36fa1d4a2c48d2ceac694cb03611ddf0e4db6"}, - {file = "ruff-0.0.286-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3dad93b1f973c6d1db4b6a5da8690c5625a3fa32bdf38e543a6936e634b83dc3"}, - {file = "ruff-0.0.286-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26afc0851f4fc3738afcf30f5f8b8612a31ac3455cb76e611deea80f5c0bf3ce"}, - {file = "ruff-0.0.286-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9b6b116d1c4000de1b9bf027131dbc3b8a70507788f794c6b09509d28952c512"}, - {file = "ruff-0.0.286-py3-none-win32.whl", hash = "sha256:556e965ac07c1e8c1c2d759ac512e526ecff62c00fde1a046acb088d3cbc1a6c"}, - {file = "ruff-0.0.286-py3-none-win_amd64.whl", hash = "sha256:5d295c758961376c84aaa92d16e643d110be32add7465e197bfdaec5a431a107"}, - {file = "ruff-0.0.286-py3-none-win_arm64.whl", hash = "sha256:1d6142d53ab7f164204b3133d053c4958d4d11ec3a39abf23a40b13b0784e3f0"}, - {file = "ruff-0.0.286.tar.gz", hash = "sha256:f1e9d169cce81a384a26ee5bb8c919fe9ae88255f39a1a69fd1ebab233a85ed2"}, + {file = "ruff-0.0.289-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:c9a89d748e90c840bac9c37afe90cf13a5bfd460ca02ea93dad9d7bee3af03b4"}, + {file = "ruff-0.0.289-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:7f7396c6ea01ba332a6ad9d47642bac25d16bd2076aaa595b001f58b2f32ff05"}, + {file = "ruff-0.0.289-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7180de86c8ecd39624dec1699136f941c07e723201b4ce979bec9e7c67b40ad2"}, + {file = "ruff-0.0.289-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:73f37c65508203dd01a539926375a10243769c20d4fcab3fa6359cd3fbfc54b7"}, + {file = "ruff-0.0.289-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c14abcd7563b5c80be2dd809eeab20e4aa716bf849860b60a22d87ddf19eb88"}, + {file = "ruff-0.0.289-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:91b6d63b6b46d4707916472c91baa87aa0592e73f62a80ff55efdf6c0668cfd6"}, + {file = "ruff-0.0.289-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6479b8c4be3c36046c6c92054762b276fa0fddb03f6b9a310fbbf4c4951267fd"}, + {file = "ruff-0.0.289-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5424318c254bcb091cb67e140ec9b9f7122074e100b06236f252923fb41e767"}, + {file = "ruff-0.0.289-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4daa90865796aedcedf0d8897fdd4cd09bf0ddd3504529a4ccf211edcaff3c7d"}, + {file = "ruff-0.0.289-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8057e8ab0016c13b9419bad119e854f881e687bd96bc5e2d52c8baac0f278a44"}, + {file = "ruff-0.0.289-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7eebfab2e6a6991908ff1bf82f2dc1e5095fc7e316848e62124526837b445f4d"}, + {file = "ruff-0.0.289-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ebc7af550018001a7fb39ca22cdce20e1a0de4388ea4a007eb5c822f6188c297"}, + {file = "ruff-0.0.289-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6e4e6eccb753efe760ba354fc8e9f783f6bba71aa9f592756f5bd0d78db898ed"}, + {file = "ruff-0.0.289-py3-none-win32.whl", hash = "sha256:bbb3044f931c09cf17dbe5b339896eece0d6ac10c9a86e172540fcdb1974f2b7"}, + {file = "ruff-0.0.289-py3-none-win_amd64.whl", hash = "sha256:6d043c5456b792be2615a52f16056c3cf6c40506ce1f2d6f9d3083cfcb9eeab6"}, + {file = "ruff-0.0.289-py3-none-win_arm64.whl", hash = "sha256:04a720bcca5e987426bb14ad8b9c6f55e259ea774da1cbeafe71569744cfd20a"}, + {file = "ruff-0.0.289.tar.gz", hash = "sha256:2513f853b0fc42f0339b7ab0d2751b63ce7a50a0032d2689b54b2931b3b866d7"}, ] [[package]] name = "setuptools" -version = "68.1.2" +version = "68.2.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, - {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shapely" @@ -1725,24 +1720,24 @@ files = [ [[package]] name = "soupsieve" -version = "2.4.1" +version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, - {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, ] [[package]] name = "sphinx" -version = "7.2.4" +version = "7.2.5" description = "Python documentation generator" optional = false python-versions = ">=3.9" files = [ - {file = "sphinx-7.2.4-py3-none-any.whl", hash = "sha256:9b3aa23254ffc5be468646810543e491653bf5a67f3f23e4ccd4e515b0bd0b9c"}, - {file = "sphinx-7.2.4.tar.gz", hash = "sha256:1aeec862bf1edff4374012ac38082e0d1daa066c9e327841a846401164797988"}, + {file = "sphinx-7.2.5-py3-none-any.whl", hash = "sha256:9269f9ed2821c9ebd30e4204f5c2339f5d4980e377bc89cb2cb6f9b17409c20a"}, + {file = "sphinx-7.2.5.tar.gz", hash = "sha256:1a9290001b75c497fd087e92b0334f1bbfa1a1ae7fddc084990c4b7bd1130b88"}, ] [package.dependencies] @@ -2092,13 +2087,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.3" +version = "20.24.5" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.3-py3-none-any.whl", hash = "sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02"}, - {file = "virtualenv-20.24.3.tar.gz", hash = "sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc"}, + {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, + {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, ] [package.dependencies] @@ -2107,7 +2102,7 @@ filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<4" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] @@ -2223,4 +2218,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "337b546c564d8a2ac0cf8b133bb9a74d4d0525a98d396ad0f293f2013635ee69" +content-hash = "c7346fba55321b4af5fd5c892d8c89687ddbf7dbafdc75c6cd88fb486e1d4fe4" diff --git a/pyproject.toml b/pyproject.toml index 7cd97a26..28afcca8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,8 +56,8 @@ coverage = { version = "^7.0.5", extras = ["toml"] } [tool.poetry.group.dev.dependencies] pre-commit = "^3.0.0" -black = { version = "==23.7.0", extras = ["jupyter"] } # keep in sync with .pre-commit-config.yaml -ruff = "==0.0.286" # keep in sync with .pre-commit-config.yaml +black = { version = "==23.9.1", extras = ["jupyter"] } # keep in sync with .pre-commit-config.yaml +ruff = "==0.0.289" # keep in sync with .pre-commit-config.yaml [tool.poetry.group.doc.dependencies] sphinx = "^7.0.1" From f8fc7c8d3eed81a5b9adf7729dd792bfcc613377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Wed, 13 Sep 2023 18:59:44 +0200 Subject: [PATCH 10/43] Small bug --- roseau/load_flow/models/loads/loads.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/roseau/load_flow/models/loads/loads.py b/roseau/load_flow/models/loads/loads.py index 685a68cd..7247c344 100644 --- a/roseau/load_flow/models/loads/loads.py +++ b/roseau/load_flow/models/loads/loads.py @@ -286,19 +286,19 @@ def powers(self, value: Sequence[complex]) -> None: if fp.control_p.type == "constant" and fp.control_q.type == "constant": continue # No checks for this case if abs(power) > fp.s_max.m_as("VA"): - msg = f"The power is greater than the parameter s_max for flexible load {id!r}" + msg = f"The power is greater than the parameter s_max for flexible load {self.id!r}" logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_S_VALUE) if fp.control_p.type == "p_max_u_production" and power.real > 0: - msg = f"There is a production control but a positive power for flexible load {id!r}" + msg = f"There is a production control but a positive power for flexible load {self.id!r}" logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_S_VALUE) if fp.control_p.type == "p_max_u_consumption" and power.real < 0: - msg = f"There is a consumption control but a negative power for flexible load {id!r}" + msg = f"There is a consumption control but a negative power for flexible load {self.id!r}" logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_S_VALUE) if fp.control_p.type != "constant" and power.real == 0: - msg = f"There is a P control but a null active power for flexible load {id!r}" + msg = f"There is a P control but a null active power for flexible load {self.id!r}" logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_S_VALUE) self._powers = value From ce2868b8e450d5352284e1ab30c3623322660315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 19 Sep 2023 15:06:14 +0200 Subject: [PATCH 11/43] Improvement of the documentation --- doc/_static/Control_Trajectory_PmaxU_QU.svg | 25138 ---------------- doc/_static/Domain_PmaxU_QU.svg | 2267 -- .../FlexibleLoad}/Constant_P_Projection.svg | 0 .../FlexibleLoad}/Constant_Q_Projection.svg | 0 .../FlexibleLoad}/Control_PU_Cons.svg | 0 .../FlexibleLoad}/Control_PU_Prod.svg | 0 .../{ => Load/FlexibleLoad}/Control_QU.svg | 0 .../FlexibleLoad}/Domain_Pconst_QU_Eucl.svg | 40 +- .../FlexibleLoad}/Domain_Pconst_QU_P.svg | 36 +- .../FlexibleLoad}/Domain_Pconst_QU_Q.svg | 38 +- .../FlexibleLoad}/Domain_Pconst_Qconst.svg | 34 +- .../Load/FlexibleLoad/Domain_PmaxU_QU.svg | 3587 +++ .../FlexibleLoad}/Domain_PmaxU_Qconst.svg | 36 +- .../FlexibleLoad}/Euclidean_Projection.svg | 0 .../Pconst_QU_Eucl_Control_Curve_Example.svg | 587 + .../Pconst_QU_Eucl_Trajectory_Example.svg | 782 + .../Pconst_QU_P_Control_Curve_Example.svg | 587 + .../Pconst_QU_P_Trajectory_Example.svg | 782 + .../Pconst_QU_Q_Control_Curve_Example.svg | 587 + .../Pconst_QU_Q_Trajectory_Example.svg | 782 + ...axU_QU_Sequential_1_Trajectory_Example.svg | 811 + ...axU_QU_Sequential_2_Trajectory_Example.svg | 811 + ...U_QU_Simultaneous_2_Trajectory_Example.svg | 819 + ...axU_QU_Simultaneous_Trajectory_Example.svg | 811 + .../PmaxU_Qconst_Control_Curve_Example.svg | 544 + .../PmaxU_Qconst_Trajectory_Example.svg | 733 + doc/images/Constant_P_Projection.tex | 75 - doc/images/Constant_Q_Projection.tex | 75 - doc/images/Control_PU_Cons.tex | 107 - doc/images/Control_PU_Prod.tex | 107 - doc/images/Control_QU.tex | 116 - doc/images/Control_Trajectory_PmaxU_QU.tex | 119 - doc/images/Domain_Pconst_QU_Eucl.tex | 27 - doc/images/Domain_Pconst_QU_P.tex | 25 - doc/images/Domain_Pconst_QU_Q.tex | 26 - doc/images/Domain_Pconst_Qconst.tex | 22 - doc/images/Domain_PmaxU_QU.tex | 26 - doc/images/Domain_PmaxU_Qconst.tex | 24 - doc/images/Euclidean_Projection.tex | 73 - .../FlexibleLoad/Constant_P_Projection.tex | 75 + .../FlexibleLoad/Constant_Q_Projection.tex | 75 + .../Load/FlexibleLoad/Control_PU_Cons.tex | 108 + .../Load/FlexibleLoad/Control_PU_Prod.tex | 108 + doc/images/Load/FlexibleLoad/Control_QU.tex | 117 + .../FlexibleLoad}/Domain_Common.tikz | 4 +- .../FlexibleLoad/Domain_Pconst_QU_Eucl.tex | 30 + .../Load/FlexibleLoad/Domain_Pconst_QU_P.tex | 25 + .../Load/FlexibleLoad/Domain_Pconst_QU_Q.tex | 26 + .../FlexibleLoad/Domain_Pconst_Qconst.tex | 22 + .../Load/FlexibleLoad/Domain_PmaxU_QU.tex | 26 + .../Load/FlexibleLoad/Domain_PmaxU_Qconst.tex | 24 + .../FlexibleLoad/Euclidean_Projection.tex | 73 + .../Pconst_QU_Eucl_Control_Curve_Example.tex | 81 + .../FlexibleLoad/Pconst_QU_Eucl_Example.csv | 52 + .../Pconst_QU_Eucl_Trajectory_Example.tex | 94 + .../Pconst_QU_P_Control_Curve_Example.tex | 81 + .../Load/FlexibleLoad/Pconst_QU_P_Example.csv | 52 + .../Pconst_QU_P_Trajectory_Example.tex | 94 + .../Pconst_QU_Q_Control_Curve_Example.tex | 81 + .../Load/FlexibleLoad/Pconst_QU_Q_Example.csv | 52 + .../Pconst_QU_Q_Trajectory_Example.tex | 94 + .../PmaxU_QU_Sequential_1_Example.csv | 52 + ...axU_QU_Sequential_1_Trajectory_Example.tex | 102 + .../PmaxU_QU_Sequential_2_Example.csv | 52 + ...axU_QU_Sequential_2_Trajectory_Example.tex | 104 + .../PmaxU_QU_Simultaneous_2_Example.csv | 52 + ...U_QU_Simultaneous_2_Trajectory_Example.tex | 113 + .../PmaxU_QU_Simultaneous_Example.csv | 52 + ...axU_QU_Simultaneous_Trajectory_Example.tex | 102 + .../PmaxU_Qconst_Control_Curve_Example.tex | 78 + .../FlexibleLoad/PmaxU_Qconst_Example.csv | 52 + .../PmaxU_Qconst_Trajectory_Example.tex | 96 + doc/images/Makefile | 31 +- doc/models/Load/FlexibleLoad.md | 430 - doc/models/Load/FlexibleLoad/Control.md | 131 + .../Load/FlexibleLoad/FeasibleDomain.md | 828 + .../Load/FlexibleLoad/FlexibleParameter.md | 167 + doc/models/Load/FlexibleLoad/Projection.md | 84 + doc/models/Load/FlexibleLoad/index.md | 57 + doc/models/Load/index.md | 4 +- doc/usage/Flexible_Loads.md | 10 +- 81 files changed, 15852 insertions(+), 28773 deletions(-) delete mode 100644 doc/_static/Control_Trajectory_PmaxU_QU.svg delete mode 100644 doc/_static/Domain_PmaxU_QU.svg rename doc/_static/{ => Load/FlexibleLoad}/Constant_P_Projection.svg (100%) rename doc/_static/{ => Load/FlexibleLoad}/Constant_Q_Projection.svg (100%) rename doc/_static/{ => Load/FlexibleLoad}/Control_PU_Cons.svg (100%) rename doc/_static/{ => Load/FlexibleLoad}/Control_PU_Prod.svg (100%) rename doc/_static/{ => Load/FlexibleLoad}/Control_QU.svg (100%) rename doc/_static/{ => Load/FlexibleLoad}/Domain_Pconst_QU_Eucl.svg (77%) rename doc/_static/{ => Load/FlexibleLoad}/Domain_Pconst_QU_P.svg (81%) rename doc/_static/{ => Load/FlexibleLoad}/Domain_Pconst_QU_Q.svg (80%) rename doc/_static/{ => Load/FlexibleLoad}/Domain_Pconst_Qconst.svg (82%) create mode 100644 doc/_static/Load/FlexibleLoad/Domain_PmaxU_QU.svg rename doc/_static/{ => Load/FlexibleLoad}/Domain_PmaxU_Qconst.svg (81%) rename doc/_static/{ => Load/FlexibleLoad}/Euclidean_Projection.svg (100%) create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.svg delete mode 100644 doc/images/Constant_P_Projection.tex delete mode 100644 doc/images/Constant_Q_Projection.tex delete mode 100644 doc/images/Control_PU_Cons.tex delete mode 100644 doc/images/Control_PU_Prod.tex delete mode 100644 doc/images/Control_QU.tex delete mode 100644 doc/images/Control_Trajectory_PmaxU_QU.tex delete mode 100644 doc/images/Domain_Pconst_QU_Eucl.tex delete mode 100644 doc/images/Domain_Pconst_QU_P.tex delete mode 100644 doc/images/Domain_Pconst_QU_Q.tex delete mode 100644 doc/images/Domain_Pconst_Qconst.tex delete mode 100644 doc/images/Domain_PmaxU_QU.tex delete mode 100644 doc/images/Domain_PmaxU_Qconst.tex delete mode 100644 doc/images/Euclidean_Projection.tex create mode 100644 doc/images/Load/FlexibleLoad/Constant_P_Projection.tex create mode 100644 doc/images/Load/FlexibleLoad/Constant_Q_Projection.tex create mode 100644 doc/images/Load/FlexibleLoad/Control_PU_Cons.tex create mode 100644 doc/images/Load/FlexibleLoad/Control_PU_Prod.tex create mode 100644 doc/images/Load/FlexibleLoad/Control_QU.tex rename doc/images/{ => Load/FlexibleLoad}/Domain_Common.tikz (95%) create mode 100644 doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.tex create mode 100644 doc/images/Load/FlexibleLoad/Domain_Pconst_QU_P.tex create mode 100644 doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Q.tex create mode 100644 doc/images/Load/FlexibleLoad/Domain_Pconst_Qconst.tex create mode 100644 doc/images/Load/FlexibleLoad/Domain_PmaxU_QU.tex create mode 100644 doc/images/Load/FlexibleLoad/Domain_PmaxU_Qconst.tex create mode 100644 doc/images/Load/FlexibleLoad/Euclidean_Projection.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_P_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Q_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_Qconst_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.tex delete mode 100644 doc/models/Load/FlexibleLoad.md create mode 100644 doc/models/Load/FlexibleLoad/Control.md create mode 100644 doc/models/Load/FlexibleLoad/FeasibleDomain.md create mode 100644 doc/models/Load/FlexibleLoad/FlexibleParameter.md create mode 100644 doc/models/Load/FlexibleLoad/Projection.md create mode 100644 doc/models/Load/FlexibleLoad/index.md diff --git a/doc/_static/Control_Trajectory_PmaxU_QU.svg b/doc/_static/Control_Trajectory_PmaxU_QU.svg deleted file mode 100644 index 24045244..00000000 --- a/doc/_static/Control_Trajectory_PmaxU_QU.svg +++ /dev/null @@ -1,25138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/_static/Domain_PmaxU_QU.svg b/doc/_static/Domain_PmaxU_QU.svg deleted file mode 100644 index d6bebf95..00000000 --- a/doc/_static/Domain_PmaxU_QU.svg +++ /dev/null @@ -1,2267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/_static/Constant_P_Projection.svg b/doc/_static/Load/FlexibleLoad/Constant_P_Projection.svg similarity index 100% rename from doc/_static/Constant_P_Projection.svg rename to doc/_static/Load/FlexibleLoad/Constant_P_Projection.svg diff --git a/doc/_static/Constant_Q_Projection.svg b/doc/_static/Load/FlexibleLoad/Constant_Q_Projection.svg similarity index 100% rename from doc/_static/Constant_Q_Projection.svg rename to doc/_static/Load/FlexibleLoad/Constant_Q_Projection.svg diff --git a/doc/_static/Control_PU_Cons.svg b/doc/_static/Load/FlexibleLoad/Control_PU_Cons.svg similarity index 100% rename from doc/_static/Control_PU_Cons.svg rename to doc/_static/Load/FlexibleLoad/Control_PU_Cons.svg diff --git a/doc/_static/Control_PU_Prod.svg b/doc/_static/Load/FlexibleLoad/Control_PU_Prod.svg similarity index 100% rename from doc/_static/Control_PU_Prod.svg rename to doc/_static/Load/FlexibleLoad/Control_PU_Prod.svg diff --git a/doc/_static/Control_QU.svg b/doc/_static/Load/FlexibleLoad/Control_QU.svg similarity index 100% rename from doc/_static/Control_QU.svg rename to doc/_static/Load/FlexibleLoad/Control_QU.svg diff --git a/doc/_static/Domain_Pconst_QU_Eucl.svg b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.svg similarity index 77% rename from doc/_static/Domain_Pconst_QU_Eucl.svg rename to doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.svg index 88a97d14..7f60ad40 100644 --- a/doc/_static/Domain_Pconst_QU_Eucl.svg +++ b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.svg @@ -1,5 +1,5 @@ - + @@ -28,40 +28,42 @@ - + - + - - - - + + + + - + - + - + - + - + - - - + + + - - + + - + - + + + diff --git a/doc/_static/Domain_Pconst_QU_P.svg b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_P.svg similarity index 81% rename from doc/_static/Domain_Pconst_QU_P.svg rename to doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_P.svg index fd6f0a61..c103b187 100644 --- a/doc/_static/Domain_Pconst_QU_P.svg +++ b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_P.svg @@ -1,5 +1,5 @@ - + @@ -28,35 +28,35 @@ - + - - - - + + + + - + - + - + - + - + - - - + + + - - - - + + + + diff --git a/doc/_static/Domain_Pconst_QU_Q.svg b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Q.svg similarity index 80% rename from doc/_static/Domain_Pconst_QU_Q.svg rename to doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Q.svg index e7238144..803fe96b 100644 --- a/doc/_static/Domain_Pconst_QU_Q.svg +++ b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Q.svg @@ -1,5 +1,5 @@ - + @@ -28,40 +28,40 @@ - + - + - - - - + + + + - + - + - + - + - + - - - + + + - - + + - + - + diff --git a/doc/_static/Domain_Pconst_Qconst.svg b/doc/_static/Load/FlexibleLoad/Domain_Pconst_Qconst.svg similarity index 82% rename from doc/_static/Domain_Pconst_Qconst.svg rename to doc/_static/Load/FlexibleLoad/Domain_Pconst_Qconst.svg index eeb01cf0..b2f13d7f 100644 --- a/doc/_static/Domain_Pconst_Qconst.svg +++ b/doc/_static/Load/FlexibleLoad/Domain_Pconst_Qconst.svg @@ -1,5 +1,5 @@ - + @@ -28,34 +28,34 @@ - + - - - - + + + + - + - + - + - + - + - - - + + + - - - + + + diff --git a/doc/_static/Load/FlexibleLoad/Domain_PmaxU_QU.svg b/doc/_static/Load/FlexibleLoad/Domain_PmaxU_QU.svg new file mode 100644 index 00000000..17136493 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Domain_PmaxU_QU.svg @@ -0,0 +1,3587 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Domain_PmaxU_Qconst.svg b/doc/_static/Load/FlexibleLoad/Domain_PmaxU_Qconst.svg similarity index 81% rename from doc/_static/Domain_PmaxU_Qconst.svg rename to doc/_static/Load/FlexibleLoad/Domain_PmaxU_Qconst.svg index 6ae5ce94..19a8ae38 100644 --- a/doc/_static/Domain_PmaxU_Qconst.svg +++ b/doc/_static/Load/FlexibleLoad/Domain_PmaxU_Qconst.svg @@ -1,5 +1,5 @@ - + @@ -28,35 +28,35 @@ - + - - - - + + + + - + - + - + - + - + - - - + + + - - - - + + + + diff --git a/doc/_static/Euclidean_Projection.svg b/doc/_static/Load/FlexibleLoad/Euclidean_Projection.svg similarity index 100% rename from doc/_static/Euclidean_Projection.svg rename to doc/_static/Load/FlexibleLoad/Euclidean_Projection.svg diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg new file mode 100644 index 00000000..61255866 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg @@ -0,0 +1,587 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.svg new file mode 100644 index 00000000..ffa9650e --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.svg @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg new file mode 100644 index 00000000..50485eed --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg @@ -0,0 +1,587 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.svg new file mode 100644 index 00000000..406aa583 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.svg @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg new file mode 100644 index 00000000..32685db8 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg @@ -0,0 +1,587 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.svg new file mode 100644 index 00000000..9ca66dec --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.svg @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.svg new file mode 100644 index 00000000..c74aa94c --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.svg @@ -0,0 +1,811 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.svg new file mode 100644 index 00000000..c66562d7 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.svg @@ -0,0 +1,811 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.svg new file mode 100644 index 00000000..b7719f51 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.svg @@ -0,0 +1,819 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.svg new file mode 100644 index 00000000..dbe4d207 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.svg @@ -0,0 +1,811 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg new file mode 100644 index 00000000..ce22094e --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.svg new file mode 100644 index 00000000..76c8ecd0 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.svg @@ -0,0 +1,733 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/Constant_P_Projection.tex b/doc/images/Constant_P_Projection.tex deleted file mode 100644 index 60d609e6..00000000 --- a/doc/images/Constant_P_Projection.tex +++ /dev/null @@ -1,75 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - % Styles - \tikzset{fleche/.style={->, -{Latex}}}% - \tikzset{interdit/.style={pattern=north east lines, pattern color=red}}% - \tikzset{point/.pic={\filldraw[#1] (0,0) circle[radius=0.05];}, point/.default=black}% - - % Parameters - \pgfmathsetmacro{\r}{3.5}% - \pgfmathsetmacro{\R}{1.1 * \r}% - \pgfmathsetmacro{\pth}{0.8 * \r}% - \pgfmathsetmacro{\angth}{acos(\pth/\r)}% - \pgfmathsetmacro{\qth}{\r * sin(\angth)}% - \pgfmathsetmacro{\startangle}{-10}% - \pgfmathsetmacro{\endangle}{90-\startangle}% - - % Axes - \pgfmathsetmacro{\tmp}{\r*cos(90-\startangle)};% - \draw[fleche] (\tmp,0) -- (\R,0) node[below right] {$P$};% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \draw[fleche] (0,\tmp) -- (0,\R) node[above right] {$Q$};% - - % Circle - \draw (\startangle:\r) arc[start angle=\startangle, end angle=\endangle, radius=\r];% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \pgfmathsetmacro{\tmpdeux}{\r*cos(\endangle)};% - \pgfmathsetmacro{\tmptrois}{\r*sin(\endangle)};% - \fill[interdit] (0,\tmp) -- (\tmpdeux,\tmp) -- (\tmpdeux,\tmptrois) arc[start angle=\endangle, - end angle=90, radius=\r];% - \draw[fleche] (0,0) -- (20:\r) node[above, midway, sloped] {$\smax$};% - - % Rectangle - \draw (0,\r) -- (\r,\r) -- (\r,0);% - - % Theoretical power - \draw (\pth,0) -- (\pth,\r) node[below left] at (\pth,0) {$P^{\theo}$};% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \fill[interdit] (\pth,\qth) arc[start angle=\angth, end angle=\startangle, radius=\r] -- - (\pth,\tmp);% - - % Point P^{\theo} - \path (\pth,0) pic[pic type=point];% - - % Point outside the circle - \pgfmathsetmacro{\rayon}{1.15*\r}% - \pgfmathsetmacro{\anglevaleur}{55}% - \coordinate (S) at (\anglevaleur:\rayon);% - - \node[right] at (S) {$\underline{S}$};% - \path (S) pic[pic type=point];% - - % Projection - \pgfmathsetmacro{\tmp}{\rayon*cos(\anglevaleur)};% - \pgfmathsetmacro{\tmpdeux}{sqrt(pow(\r,2)-pow(\tmp,2))};% - \coordinate (S correct) at (\tmp,\tmpdeux);% - \draw[fleche, blue] (S) -- (S correct);% - \path (S correct) pic {point=blue};% - \node[below left] at (S correct) {$\underline{S^{\text{proj.}}}$};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Constant_Q_Projection.tex b/doc/images/Constant_Q_Projection.tex deleted file mode 100644 index 8e437c69..00000000 --- a/doc/images/Constant_Q_Projection.tex +++ /dev/null @@ -1,75 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - % Styles - \tikzset{fleche/.style={->, -{Latex}}}% - \tikzset{interdit/.style={pattern=north east lines, pattern color=red}}% - \tikzset{point/.pic={\filldraw[#1] (0,0) circle[radius=0.05];}, point/.default=black}% - - % Paramètres - \pgfmathsetmacro{\r}{3.5}% - \pgfmathsetmacro{\R}{1.1 * \r}% - \pgfmathsetmacro{\pth}{0.8 * \r}% - \pgfmathsetmacro{\angth}{acos(\pth/\r)}% - \pgfmathsetmacro{\qth}{\r * sin(\angth)}% - \pgfmathsetmacro{\startangle}{-10}% - \pgfmathsetmacro{\endangle}{90-\startangle}% - - % Axes - \pgfmathsetmacro{\tmp}{\r*cos(90-\startangle)};% - \draw[fleche] (\tmp,0) -- (\R,0) node[below right] {$P$};% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \draw[fleche] (0,\tmp) -- (0,\R) node[above right] {$Q$};% - - % Cercle - \draw (\startangle:\r) arc[start angle=\startangle, end angle=\endangle, radius=\r];% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \pgfmathsetmacro{\tmpdeux}{\r*cos(\endangle)};% - \pgfmathsetmacro{\tmptrois}{\r*sin(\endangle)};% - \fill[interdit] (0,\tmp) -- (\tmpdeux,\tmp) -- (\tmpdeux,\tmptrois) arc[start angle=\endangle, - end angle=90, radius=\r];% - \draw[fleche] (0,0) -- (20:\r) node[above, midway, sloped] {$\smax$};% - - % Rectangle - \draw (0,\r) -- (\r,\r) -- (\r,0);% - - % Puissance théorique - \draw (\pth,0) -- (\pth,\r) node[below left] at (\pth,0) {$P^{\theo}$};% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \fill[interdit] (\pth,\qth) arc[start angle=\angth, end angle=\startangle, radius=\r] -- - (\pth,\tmp);% - - % Point noir sur P^{\theo} - \path (\pth,0) pic[pic type=point];% - - % Point en dehors du cercle - \pgfmathsetmacro{\rayon}{1.15*\r}% - \pgfmathsetmacro{\anglevaleur}{55}% - \coordinate (S) at (\anglevaleur:\rayon);% - - \node[right] at (S) {$\underline{S}$};% - \path (S) pic[pic type=point];% - - % Projection - \pgfmathsetmacro{\tmp}{\rayon*sin(\anglevaleur)};% - \pgfmathsetmacro{\tmpdeux}{sqrt(pow(\r,2)-pow(\tmp,2))};% - \coordinate (S correct) at (\tmpdeux,\tmp);% - \draw[fleche, blue] (S) -- (S correct);% - \path (S correct) pic {point=blue};% - \node[below left] at (S correct) {$\underline{S^{\text{proj.}}}$};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Control_PU_Cons.tex b/doc/images/Control_PU_Cons.tex deleted file mode 100644 index d8466032..00000000 --- a/doc/images/Control_PU_Cons.tex +++ /dev/null @@ -1,107 +0,0 @@ -\input{Preambule}% - -\usepackage{pgfplots}% -\pgfplotsset{compat=newest}% -\usepgfplotslibrary{groupplots, colorbrewer}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - % - % Common parameters - % - \pgfmathsetmacro{\uminvaleur}{210.0}% - \pgfmathsetmacro{\uminnormvaleur}{1.0}% - \pgfmathsetmacro{\udownvaleur}{220.0}% - \pgfmathsetmacro{\udownnormvaleur}{\udownvaleur/\uminvaleur}% - \pgfmathsetmacro{\uupvaleur}{240.0}% - \pgfmathsetmacro{\uupnormvaleur}{\uupvaleur/\uminvaleur}% - \pgfmathsetmacro{\umaxvaleur}{250.0}% - \pgfmathsetmacro{\umaxnormvaleur}{\umaxvaleur/\uminvaleur}% - \pgfmathsetmacro{\unomvaleur}{(\udownvaleur+\uupvaleur)/2.0}% - \pgfmathsetmacro{\unomnormvaleur}{\unomvaleur/\uminvaleur}% - \pgfmathsetmacro{\umidminvaleur}{(\udownvaleur+\uminvaleur)/2.0}% - \pgfmathsetmacro{\umidminnormvaleur}{\umidminvaleur/\uminvaleur}% - \pgfmathsetmacro{\umidmaxvaleur}{(\uupvaleur+\umaxvaleur)/2.0}% - \pgfmathsetmacro{\umidmaxnormvaleur}{\umidmaxvaleur/\uminvaleur}% - - \pgfmathsetmacro{\xminvaleur}{\uminvaleur - 2.5}% - \pgfmathsetmacro{\xminnormvaleur}{\xminvaleur/\uminvaleur}% - \pgfmathsetmacro{\xmaxvaleur}{\umaxvaleur + 2.5}% - \pgfmathsetmacro{\xmaxnormvaleur}{\xmaxvaleur/\uminvaleur}% - - \pgfmathsetmacro{\yminnormvaleur}{0}% - \pgfmathsetmacro{\ymaxnormvaleur}{1}% - - % - % Style - % - \tikzset{lisse/.style={line width=0.3mm, - domain=\xminnormvaleur:\xmaxnormvaleur, samples=75, mark=none}}% - \tikzset{non lisse/.style={line width=0.3mm, mark=*}}% - - \begin{axis}[% - height=7cm,% - width=0.9\textwidth,% - enlarge y limits,% - grid=major,% - xlabel={$|V_{p_1}-V_{p_2}|$},% - xtick={\uminnormvaleur,\umidminnormvaleur,\udownnormvaleur,\unomnormvaleur,\uupnormvaleur,\umidmaxnormvaleur,\umaxnormvaleur},% - xticklabels={% - $\uminnorm$,,$\udownnorm$,$\unomnorm$,$\uupnorm$,,$\umaxnorm$% - },% - y tick label style={/pgf/number format/.cd,% - set thousands separator={},% - fixed,% - % fixed zerofill,% - precision=1,% - use comma% - },% - xmin=\xminnormvaleur,% - xmax=\xmaxnormvaleur,% - ymin=\yminnormvaleur,% - ymax=\ymaxnormvaleur,% - legend columns=2,% - legend style={% - at={(0.5,-0.25)},% - anchor=north,% - nodes={text width=4cm}% - },% - cycle list/YlOrRd-5, % initialize YlOrRd-5 - cycle list name=YlOrRd-5% - ] - - % Piecewise linear function - \addplot[non lisse, red] coordinates {% - (\xminnormvaleur,0)% - (\uminnormvaleur,0)% - (\udownnormvaleur,1)% - (\xmaxnormvaleur,1)% - };% - \addlegendentry{Non-smooth control};% - - - % Soft clipping functions - \pgfplotsset{cycle list shift=-1}% Reset cycle to 0 - \foreach \alphavaleur in {50,100,200,300,400} {% - \addplot+[lisse] expression {% - 1.0/(\alphavaleur*(\udownnormvaleur-\uminnormvaleur)) * - ln((1+exp(\alphavaleur*(x-\uminnormvaleur)))/(1+exp(\alphavaleur*(x-\udownnormvaleur)))) - };% - \addlegendentryexpanded{Soft clipping ($\alpha=\num{\alphavaleur}$)};% - };% - \end{axis} -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Control_PU_Prod.tex b/doc/images/Control_PU_Prod.tex deleted file mode 100644 index 421ecb4b..00000000 --- a/doc/images/Control_PU_Prod.tex +++ /dev/null @@ -1,107 +0,0 @@ -\input{Preambule}% - -\usepackage{pgfplots}% -\pgfplotsset{compat=newest}% -\usepgfplotslibrary{groupplots, colorbrewer}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - % - % Common parameters - % - \pgfmathsetmacro{\umaxvaleur}{250.0}% - \pgfmathsetmacro{\umaxnormvaleur}{1.0}% - \pgfmathsetmacro{\uupvaleur}{240.0}% - \pgfmathsetmacro{\uupnormvaleur}{\uupvaleur/\umaxvaleur}% - \pgfmathsetmacro{\udownvaleur}{220.0}% - \pgfmathsetmacro{\udownnormvaleur}{\udownvaleur/\umaxvaleur}% - \pgfmathsetmacro{\uminvaleur}{210.0}% - \pgfmathsetmacro{\uminnormvaleur}{\uminvaleur/\umaxvaleur}% - \pgfmathsetmacro{\unomvaleur}{(\udownvaleur+\uupvaleur)/2.0}% - \pgfmathsetmacro{\unomnormvaleur}{\unomvaleur/\umaxvaleur}% - \pgfmathsetmacro{\umidminvaleur}{(\udownvaleur+\uminvaleur)/2.0}% - \pgfmathsetmacro{\umidminnormvaleur}{\umidminvaleur/\umaxvaleur}% - \pgfmathsetmacro{\umidmaxvaleur}{(\uupvaleur+\umaxvaleur)/2.0}% - \pgfmathsetmacro{\umidmaxnormvaleur}{\umidmaxvaleur/\umaxvaleur}% - - \pgfmathsetmacro{\xminvaleur}{\uminvaleur - 2.5}% - \pgfmathsetmacro{\xminnormvaleur}{\xminvaleur/\umaxvaleur}% - \pgfmathsetmacro{\xmaxvaleur}{\umaxvaleur + 2.5}% - \pgfmathsetmacro{\xmaxnormvaleur}{\xmaxvaleur/\umaxvaleur}% - - \pgfmathsetmacro{\yminnormvaleur}{0}% - \pgfmathsetmacro{\ymaxnormvaleur}{1}% - - % - % Style - % - \tikzset{lisse/.style={line width=0.3mm, domain=\xminnormvaleur:\xmaxnormvaleur, samples=75, - mark=none}}% - \tikzset{non lisse/.style={line width=0.3mm, mark=*}}% - - \begin{axis}[% - height=7cm,% - width=0.9\textwidth,% - enlarge y limits,% - grid=major,% - xlabel={$|V_{p_1}-V_{p_2}|$},% - xtick={\uminnormvaleur,\umidminnormvaleur,\udownnormvaleur,\unomnormvaleur,\uupnormvaleur,\umidmaxnormvaleur,\umaxnormvaleur},% - xticklabels={% - $\uminnorm$,,$\udownnorm$,$\unomnorm$,$\uupnorm$,,$\umaxnorm$% - },% - y tick label style={/pgf/number format/.cd,% - set thousands separator={},% - fixed,% - % fixed zerofill,% - precision=1,% - use comma% - },% - xmin=\xminnormvaleur,% - xmax=\xmaxnormvaleur,% - ymin=\yminnormvaleur,% - ymax=\ymaxnormvaleur,% - legend columns=2,% - legend style={% - at={(0.5,-0.25)},% - anchor=north,% - nodes={text width=4cm}% - },% - cycle list/YlOrRd-5, % initialize YlOrRd-5 - cycle list name=YlOrRd-5% - ] - - % Piecewise linear function - \addplot[non lisse, red] coordinates {% - (\xminnormvaleur,1)% - (\uupnormvaleur,1)% - (\umaxnormvaleur,0)% - (\xmaxnormvaleur,0)% - };% - \addlegendentry{Non-smooth control};% - - - % Soft clipping functions - \pgfplotsset{cycle list shift=-1}% Reset cycle to 0 - \foreach \alphavaleur in {50,100,200,300,400} {% - \addplot+[lisse] expression {% - 1.0 + 1.0/(\alphavaleur*(\umaxnormvaleur-\uupnormvaleur)) * - ln((1+exp(\alphavaleur*(x-\umaxnormvaleur)))/(1+exp(\alphavaleur*(x-\uupnormvaleur)))) - };% - \addlegendentryexpanded{Soft clipping ($\alpha=\num{\alphavaleur}$)};% - };% - \end{axis} -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Control_QU.tex b/doc/images/Control_QU.tex deleted file mode 100644 index b8947919..00000000 --- a/doc/images/Control_QU.tex +++ /dev/null @@ -1,116 +0,0 @@ -\input{Preambule}% - -\usepackage{pgfplots}% -\pgfplotsset{compat=newest}% -\usepgfplotslibrary{groupplots, colorbrewer}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - % - % Common parameters - % - \pgfmathsetmacro{\umaxvaleur}{250.0}% - \pgfmathsetmacro{\umaxnormvaleur}{1.0}% - \pgfmathsetmacro{\uupvaleur}{240.0}% - \pgfmathsetmacro{\uupnormvaleur}{\uupvaleur/\umaxvaleur}% - \pgfmathsetmacro{\udownvaleur}{220.0}% - \pgfmathsetmacro{\udownnormvaleur}{\udownvaleur/\umaxvaleur}% - \pgfmathsetmacro{\uminvaleur}{210.0}% - \pgfmathsetmacro{\uminnormvaleur}{\uminvaleur/\umaxvaleur}% - \pgfmathsetmacro{\unomvaleur}{(\udownvaleur+\uupvaleur)/2.0}% - \pgfmathsetmacro{\unomnormvaleur}{\unomvaleur/\umaxvaleur}% - \pgfmathsetmacro{\umidminvaleur}{(\udownvaleur+\uminvaleur)/2.0}% - \pgfmathsetmacro{\umidminnormvaleur}{\umidminvaleur/\umaxvaleur}% - \pgfmathsetmacro{\umidmaxvaleur}{(\uupvaleur+\umaxvaleur)/2.0}% - \pgfmathsetmacro{\umidmaxnormvaleur}{\umidmaxvaleur/\umaxvaleur}% - - \pgfmathsetmacro{\xminvaleur}{\uminvaleur - 2.5}% - \pgfmathsetmacro{\xminnormvaleur}{\xminvaleur/\umaxvaleur}% - \pgfmathsetmacro{\xmaxvaleur}{\umaxvaleur + 2.5}% - \pgfmathsetmacro{\xmaxnormvaleur}{\xmaxvaleur/\umaxvaleur}% - - \pgfmathsetmacro{\yminnormvaleur}{-1}% - \pgfmathsetmacro{\ymaxnormvaleur}{1}% - - \pgfmathsetmacro{\qthnormvaleur}{0.30}% - - % - % Style - % - \tikzset{lisse/.style={line width=0.3mm, domain=\xminnormvaleur:\xmaxnormvaleur, samples=75, - mark=none}}% - \tikzset{non lisse/.style={line width=0.3mm, mark=*}}% - - \begin{axis}[% - height=7cm,% - width=0.9\textwidth,% - enlarge y limits,% - grid=major,% - xlabel={$|V_{p_1}-V_{p_2}|$},% - xtick={\uminnormvaleur,\umidminnormvaleur,\udownnormvaleur,\unomnormvaleur,\uupnormvaleur,\umidmaxnormvaleur,\umaxnormvaleur},% - xticklabels={% - $\uminnorm$,,$\udownnorm$,$\unomnorm$,$\uupnorm$,,$\umaxnorm$% - },% - y tick label style={/pgf/number format/.cd,% - set thousands separator={},% - fixed,% - fixed zerofill,% - precision=1,% - use comma% - },% - ytick={\yminnormvaleur,0,\qthnormvaleur,\ymaxnormvaleur},% - yticklabels={-1,0,$\dfrac{Q^{\theo}_{p_1p_2}}{\smax_{p_1p_2}}$,1},% - xmin=\xminnormvaleur,% - xmax=\xmaxnormvaleur,% - ymin=\yminnormvaleur,% - ymax=\ymaxnormvaleur,% - % ylabel={$\alpha\left(|V_{p}|\right)$},% - % legend entries={Contrôles non lisses,Contrôles lisses},% - legend columns=2,% - legend style={% - at={(0.5,-0.25)},% - anchor=north,% - nodes={text width=4cm}% - },% - cycle list/YlOrRd-5, % initialize YlOrRd-5 - cycle list name=YlOrRd-5% - ] - - % Fonction linéaire par morceaux - \addplot[non lisse, red] coordinates {% - (\xminnormvaleur,-1)% - (\uminnormvaleur,-1)% - (\udownnormvaleur,\qthnormvaleur)% - (\uupnormvaleur,\qthnormvaleur)% - (\umaxnormvaleur,1)% - (\xmaxnormvaleur,1)% - };% - \addlegendentry{Non-smooth control};% - - % Soft clipping functions - \pgfplotsset{cycle list shift=-1}% Reset cycle to 0 - \foreach \alphavaleur in {50,100,200,300,400} {% - \addplot+[lisse] expression {% - \qthnormvaleur + ( 1.0/(\alphavaleur*(\uminnormvaleur-\udownnormvaleur)) * - ln((1+exp(\alphavaleur*(x-\udownnormvaleur)))/(1+exp(\alphavaleur*(x-\uminnormvaleur))))-1.0 - )*(1+\qthnormvaleur) + ( 1.0/(\alphavaleur*(\umaxnormvaleur-\uupnormvaleur)) * - ln((1+exp(\alphavaleur*(x-\uupnormvaleur)))/(1+exp(\alphavaleur*(x-\umaxnormvaleur)))) - )*(1-\qthnormvaleur) };% - \addlegendentryexpanded{Soft clipping ($\alpha=\num{\alphavaleur}$)};% - };% - \end{axis} -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Control_Trajectory_PmaxU_QU.tex b/doc/images/Control_Trajectory_PmaxU_QU.tex deleted file mode 100644 index 62ca29bc..00000000 --- a/doc/images/Control_Trajectory_PmaxU_QU.tex +++ /dev/null @@ -1,119 +0,0 @@ -\input{Preambule}% - -\usepackage{pgfplots}% -\pgfplotsset{compat=newest}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - % - % Common parameters - % - % Control of P - \pgfmathsetmacro{\umaxpvaleur}{250}% - \pgfmathsetmacro{\umaxpnormvaleur}{1.0}% - \pgfmathsetmacro{\uuppvaleur}{240}% - \pgfmathsetmacro{\uuppnormvaleur}{\uuppvaleur/\umaxpvaleur}% - \pgfmathsetmacro{\alphapvaleur}{400}% - - % Control of Q - \pgfmathsetmacro{\umaxqvaleur}{240}% - \pgfmathsetmacro{\umaxqnormvaleur}{1}% - \pgfmathsetmacro{\uupqvaleur}{235}% - \pgfmathsetmacro{\uupqnormvaleur}{\uupqvaleur/\umaxqvaleur}% - \pgfmathsetmacro{\udownqvaleur}{220}% - \pgfmathsetmacro{\udownqnormvaleur}{\udownqvaleur/\umaxqvaleur}% - \pgfmathsetmacro{\uminqvaleur}{210}% - \pgfmathsetmacro{\uminqnormvaleur}{\uminqvaleur/\umaxqvaleur}% - \pgfmathsetmacro{\alphaqvaleur}{400}% - - - % User-defined values - \pgfmathsetmacro{\smaxvaleur}{5000}% - \pgfmathsetmacro{\smaxnormvaleur}{1}% - \pgfmathsetmacro{\pthvaleur}{3750}% - \pgfmathsetmacro{\pthnormvaleur}{\pthvaleur/\smaxvaleur}% - \pgfmathsetmacro{\angthvaleur}{acos(\pthvaleur/\smaxvaleur)}% - \pgfmathsetmacro{\qthvaleur}{\smaxvaleur * sin(\angthvaleur)}% - \pgfmathsetmacro{\qthnormvaleur}{\qthvaleur/\smaxvaleur}% - - % - % Style - % - \tikzset{interdit/.style={pattern=north east lines, pattern color=red}}% - - \begin{axis}[% - height=9cm,% - % width=0.9\textwidth,% - axis equal=true,% - enlarge y limits,% - enlarge x limits,% - grid=major,% - xmin=-\smaxnormvaleur,% - xmax=\smaxnormvaleur,% - ymin=-\smaxnormvaleur,% - ymax=\smaxnormvaleur,% - xlabel=$P$,% - ylabel=$Q$,% - xtick={-\smaxnormvaleur,-\pthnormvaleur,0,\smaxnormvaleur},% - xticklabels={$-\smax$,$P^{\theo}$,0,$\smax$},% - ytick={-\smaxnormvaleur,0,\smaxnormvaleur},% - yticklabels={$-\smax$,0,$\smax$},% - declare function={% - fp(\t)=1.0+1.0/(\alphapvaleur*(\umaxpnormvaleur-\uuppnormvaleur)) * - ln((1+exp(\alphapvaleur*(\t-\umaxpnormvaleur)))/(1+exp(\alphapvaleur*(\t-\uuppnormvaleur))));% - p(\t)=-fp(\t/\umaxpvaleur)*\pthnormvaleur;% - fq(\t)= 1.0/(\alphaqvaleur*(\uminqnormvaleur-\udownqnormvaleur)) * - ln((1+exp(\alphaqvaleur*(\t-\udownqnormvaleur)))/(1+exp(\alphaqvaleur*(\t-\uminqnormvaleur))))-1.0;% - gq(\t)=1.0/(\alphaqvaleur*(\umaxqnormvaleur-\uupqnormvaleur)) * - ln((1+exp(\alphaqvaleur*(\t-\uupqnormvaleur)))/(1+exp(\alphaqvaleur*(\t-\umaxqnormvaleur))));% - q(\t)=\qthnormvaleur + - fq(\t/\umaxqvaleur)*(\smaxnormvaleur+\qthnormvaleur)+gq(\t/\umaxqvaleur)*(\smaxnormvaleur-\qthnormvaleur);% - pclip(\t)=p(\t);% - qclip(\t)=sign(q(\t))*sqrt(min(q(\t)^2,\smaxnormvaleur^2-p(\t)^2));% - },% - ] - % Points - \addplot+ [samples at={210,211,...,250}] ({pclip(\x)},{qclip(\x)});% - - % Cercle - \draw (axis cs:0,0) circle[radius=\smaxnormvaleur];% - - % Axes - \draw (axis cs:0,\pgfkeysvalueof{/pgfplots/ymin}) -- (axis - cs:0,\pgfkeysvalueof{/pgfplots/ymax});% - \draw (axis cs:\pgfkeysvalueof{/pgfplots/xmin},0) -- (axis - cs:\pgfkeysvalueof{/pgfplots/xmax},0);% - - % Remplissage - \fill[interdit] (axis cs:0,-\smaxnormvaleur) -- (axis cs:0,\smaxnormvaleur) arc[start - angle=90, delta angle=-180, radius=\smaxnormvaleur];% - \fill[interdit] (axis cs:-\pthnormvaleur,\qthnormvaleur) arc[start angle=180-\angthvaleur, - delta angle=2*\angthvaleur, radius=\smaxnormvaleur];% - - % Notes - \node[pin={[pin distance=1mm] right:\SI{210}{\volt}}] at ({pclip(210)},{qclip(210)}) {};% - \node[pin={[pin distance=1mm] right:\SI{215}{\volt}}] at ({pclip(215)},{qclip(215)}) {};% - \node[pin={[pin distance=1mm] below right:\SI{220}{\volt}} ] at ({pclip(220)},{qclip(220)}) - {};% - \node[pin={[pin distance=1mm] left:\SI{230}{\volt}} ] at ({pclip(230)},{qclip(230)}) {};% - \node[pin={[pin distance=1mm] right:\SI{240}{\volt}}] at ({pclip(240)},{qclip(240)}) {};% - \node[pin={[pin distance=1mm] above left:\SI{245}{\volt}}] at ({pclip(245)},{qclip(245)}) - {};% - \node[pin={[pin distance=1mm] above right:\SI{250}{\volt}}] at ({pclip(250)},{qclip(250)}) - {};% - \end{axis} -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Domain_Pconst_QU_Eucl.tex b/doc/images/Domain_Pconst_QU_Eucl.tex deleted file mode 100644 index 2529f943..00000000 --- a/doc/images/Domain_Pconst_QU_Eucl.tex +++ /dev/null @@ -1,27 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - \input{Domain_Common.tikz}% - - % The domain is a segment with two arc circle - \draw[domaine] (-\angeuclthvaleur:\r) arc[start angle=-\angeuclthvaleur, end - angle=-\angthvaleur, radius=\r] -- (\pthvaleur,\qthmaxvaleur) arc [start angle=\angthvaleur, end - angle=\angeuclthvaleur, radius=\r];% - - \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Domain_Pconst_QU_P.tex b/doc/images/Domain_Pconst_QU_P.tex deleted file mode 100644 index cb528ed5..00000000 --- a/doc/images/Domain_Pconst_QU_P.tex +++ /dev/null @@ -1,25 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - \input{Domain_Common.tikz}% - - % The domain is a segment - \draw[domaine] (\pthvaleur,-\qthmaxvaleur) -- (\pthvaleur,\qthmaxvaleur);% - - \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Domain_Pconst_QU_Q.tex b/doc/images/Domain_Pconst_QU_Q.tex deleted file mode 100644 index 7b1275c5..00000000 --- a/doc/images/Domain_Pconst_QU_Q.tex +++ /dev/null @@ -1,26 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - \input{Domain_Common.tikz}% - - % The domain is a segment with two portions of circle arc - \draw[domaine] (0,-\r) arc[start angle=-90, end angle=-\angthvaleur, radius=\r] -- - (\pthvaleur,\qthmaxvaleur) arc [start angle=\angthvaleur, end angle=90, radius=\r];% - - \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Domain_Pconst_Qconst.tex b/doc/images/Domain_Pconst_Qconst.tex deleted file mode 100644 index 698b4d3f..00000000 --- a/doc/images/Domain_Pconst_Qconst.tex +++ /dev/null @@ -1,22 +0,0 @@ -\input{Preambule}% -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - \input{Domain_Common.tikz}% - - % The domain is limited to a point - \pic[domaine] at (\pthvaleur,\qthvaleur) {point}; -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Domain_PmaxU_QU.tex b/doc/images/Domain_PmaxU_QU.tex deleted file mode 100644 index 452040ab..00000000 --- a/doc/images/Domain_PmaxU_QU.tex +++ /dev/null @@ -1,26 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - \input{Domain_Common.tikz}% - - % The domain is a prtion of the circle - \filldraw[domaine hache] (0,-\r) arc[start angle=-90, end angle=-\angthvaleur, radius=\r] -- - (\pthvaleur, \qthmaxvaleur) arc[start angle=\angthvaleur, end angle=90, radius=\r] --cycle;% - - \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Domain_PmaxU_Qconst.tex b/doc/images/Domain_PmaxU_Qconst.tex deleted file mode 100644 index 7434c790..00000000 --- a/doc/images/Domain_PmaxU_Qconst.tex +++ /dev/null @@ -1,24 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - \input{Domain_Common.tikz}% - - % The domain is a segment - \draw[domaine] (0,\qthvaleur) -- (\pthvaleur,\qthvaleur);% - \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Euclidean_Projection.tex b/doc/images/Euclidean_Projection.tex deleted file mode 100644 index c774d8ba..00000000 --- a/doc/images/Euclidean_Projection.tex +++ /dev/null @@ -1,73 +0,0 @@ -\input{Preambule}% - -\begin{document} -\begin{tikzpicture}[% - show background rectangle,% - tight background,% - background rectangle/.style={fill=white}% - ] - % Styles - \tikzset{fleche/.style={->, -{Latex}}}% - \tikzset{interdit/.style={pattern=north east lines, pattern color=red}}% - \tikzset{point/.pic={\filldraw[#1] (0,0) circle[radius=0.05];}, point/.default=black}% - - % Paramètres - \pgfmathsetmacro{\r}{3.5}% - \pgfmathsetmacro{\R}{1.1 * \r}% - \pgfmathsetmacro{\pth}{0.8 * \r}% - \pgfmathsetmacro{\angth}{acos(\pth/\r)}% - \pgfmathsetmacro{\qth}{\r * sin(\angth)}% - \pgfmathsetmacro{\startangle}{-10}% - \pgfmathsetmacro{\endangle}{90-\startangle}% - - % Axes - \pgfmathsetmacro{\tmp}{\r*cos(90-\startangle)};% - \draw[fleche] (\tmp,0) -- (\R,0) node[below right] {$P$};% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \draw[fleche] (0,\tmp) -- (0,\R) node[above right] {$Q$};% - - % Circle - \draw (\startangle:\r) arc[start angle=\startangle, end angle=\endangle, radius=\r];% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \pgfmathsetmacro{\tmpdeux}{\r*cos(\endangle)};% - \pgfmathsetmacro{\tmptrois}{\r*sin(\endangle)};% - \fill[interdit] (0,\tmp) -- (\tmpdeux,\tmp) -- (\tmpdeux,\tmptrois) arc[start angle=\endangle, - end angle=90, radius=\r];% - \draw[fleche] (0,0) -- (20:\r) node[above, midway, sloped] {$\smax$};% - - % Rectangle - \draw (0,\r) -- (\r,\r) -- (\r,0);% - - % Theoretical power - \draw (\pth,0) -- (\pth,\r) node[below left] at (\pth,0) {$P^{\theo}$};% - \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% - \fill[interdit] (\pth,\qth) arc[start angle=\angth, end angle=\startangle, radius=\r] -- - (\pth,\tmp);% - - % Point P^{\theo} - \path (\pth,0) pic[pic type=point];% - - % Point outside of the circle - \pgfmathsetmacro{\rayon}{1.15*\r}% - \pgfmathsetmacro{\anglevaleur}{55}% - \coordinate (S) at (\anglevaleur:\rayon);% - - \node[right] at (S) {$\underline{S}$};% - \path (S) pic[pic type=point];% - - % Projection - \coordinate (S correct) at (\anglevaleur:\r);% - \draw[fleche, blue] (S) -- (S correct);% - \path (S correct) pic {point=blue};% - \node[below left] at (S correct) {$\underline{S^{\text{proj.}}}$};% -\end{tikzpicture} -\end{document} -% Local Variables: -% mode: latex -% TeX-engine: luatex -% TeX-source-correlate-method-active: synctex -% ispell-local-dictionary: "british" -% coding: utf-8 -% LaTeX-indent-level: 4 -% fill-column: 100 -% End: diff --git a/doc/images/Load/FlexibleLoad/Constant_P_Projection.tex b/doc/images/Load/FlexibleLoad/Constant_P_Projection.tex new file mode 100644 index 00000000..a213d2de --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Constant_P_Projection.tex @@ -0,0 +1,75 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + % Styles + \tikzset{fleche/.style={->, -{Latex}}}% + \tikzset{interdit/.style={pattern=north east lines, pattern color=red}}% + \tikzset{point/.pic={\filldraw[#1] (0,0) circle[radius=0.05];}, point/.default=black}% + + % Parameters + \pgfmathsetmacro{\r}{3.5}% + \pgfmathsetmacro{\R}{1.1 * \r}% + \pgfmathsetmacro{\pth}{0.8 * \r}% + \pgfmathsetmacro{\angth}{acos(\pth/\r)}% + \pgfmathsetmacro{\qth}{\r * sin(\angth)}% + \pgfmathsetmacro{\startangle}{-10}% + \pgfmathsetmacro{\endangle}{90-\startangle}% + + % Axes + \pgfmathsetmacro{\tmp}{\r*cos(90-\startangle)};% + \draw[fleche] (\tmp,0) -- (\R,0) node[below right] {$P$};% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \draw[fleche] (0,\tmp) -- (0,\R) node[above right] {$Q$};% + + % Circle + \draw (\startangle:\r) arc[start angle=\startangle, end angle=\endangle, radius=\r];% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \pgfmathsetmacro{\tmpdeux}{\r*cos(\endangle)};% + \pgfmathsetmacro{\tmptrois}{\r*sin(\endangle)};% + \fill[interdit] (0,\tmp) -- (\tmpdeux,\tmp) -- (\tmpdeux,\tmptrois) arc[start angle=\endangle, + end angle=90, radius=\r];% + \draw[fleche] (0,0) -- (20:\r) node[above, midway, sloped] {$\smax$};% + + % Rectangle + \draw (0,\r) -- (\r,\r) -- (\r,0);% + + % Theoretical power + \draw (\pth,0) -- (\pth,\r) node[below left] at (\pth,0) {$P^{\theo}$};% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \fill[interdit] (\pth,\qth) arc[start angle=\angth, end angle=\startangle, radius=\r] -- + (\pth,\tmp);% + + % Point P^{\theo} + \path (\pth,0) pic[pic type=point];% + + % Point outside the circle + \pgfmathsetmacro{\rayon}{1.15*\r}% + \pgfmathsetmacro{\anglevaleur}{55}% + \coordinate (S) at (\anglevaleur:\rayon);% + + \node[right] at (S) {$\underline{S}$};% + \path (S) pic[pic type=point];% + + % Projection + \pgfmathsetmacro{\tmp}{\rayon*cos(\anglevaleur)};% + \pgfmathsetmacro{\tmpdeux}{sqrt(pow(\r,2)-pow(\tmp,2))};% + \coordinate (S correct) at (\tmp,\tmpdeux);% + \draw[fleche, blue] (S) -- (S correct);% + \path (S correct) pic {point=blue};% + \node[below left] at (S correct) {$\underline{S^{\text{proj.}}}$};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Constant_Q_Projection.tex b/doc/images/Load/FlexibleLoad/Constant_Q_Projection.tex new file mode 100644 index 00000000..08746307 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Constant_Q_Projection.tex @@ -0,0 +1,75 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + % Styles + \tikzset{fleche/.style={->, -{Latex}}}% + \tikzset{interdit/.style={pattern=north east lines, pattern color=red}}% + \tikzset{point/.pic={\filldraw[#1] (0,0) circle[radius=0.05];}, point/.default=black}% + + % Paramètres + \pgfmathsetmacro{\r}{3.5}% + \pgfmathsetmacro{\R}{1.1 * \r}% + \pgfmathsetmacro{\pth}{0.8 * \r}% + \pgfmathsetmacro{\angth}{acos(\pth/\r)}% + \pgfmathsetmacro{\qth}{\r * sin(\angth)}% + \pgfmathsetmacro{\startangle}{-10}% + \pgfmathsetmacro{\endangle}{90-\startangle}% + + % Axes + \pgfmathsetmacro{\tmp}{\r*cos(90-\startangle)};% + \draw[fleche] (\tmp,0) -- (\R,0) node[below right] {$P$};% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \draw[fleche] (0,\tmp) -- (0,\R) node[above right] {$Q$};% + + % Cercle + \draw (\startangle:\r) arc[start angle=\startangle, end angle=\endangle, radius=\r];% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \pgfmathsetmacro{\tmpdeux}{\r*cos(\endangle)};% + \pgfmathsetmacro{\tmptrois}{\r*sin(\endangle)};% + \fill[interdit] (0,\tmp) -- (\tmpdeux,\tmp) -- (\tmpdeux,\tmptrois) arc[start angle=\endangle, + end angle=90, radius=\r];% + \draw[fleche] (0,0) -- (20:\r) node[above, midway, sloped] {$\smax$};% + + % Rectangle + \draw (0,\r) -- (\r,\r) -- (\r,0);% + + % Puissance théorique + \draw (\pth,0) -- (\pth,\r) node[below left] at (\pth,0) {$P^{\theo}$};% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \fill[interdit] (\pth,\qth) arc[start angle=\angth, end angle=\startangle, radius=\r] -- + (\pth,\tmp);% + + % Point noir sur P^{\theo} + \path (\pth,0) pic[pic type=point];% + + % Point en dehors du cercle + \pgfmathsetmacro{\rayon}{1.15*\r}% + \pgfmathsetmacro{\anglevaleur}{55}% + \coordinate (S) at (\anglevaleur:\rayon);% + + \node[right] at (S) {$\underline{S}$};% + \path (S) pic[pic type=point];% + + % Projection + \pgfmathsetmacro{\tmp}{\rayon*sin(\anglevaleur)};% + \pgfmathsetmacro{\tmpdeux}{sqrt(pow(\r,2)-pow(\tmp,2))};% + \coordinate (S correct) at (\tmpdeux,\tmp);% + \draw[fleche, blue] (S) -- (S correct);% + \path (S correct) pic {point=blue};% + \node[below left] at (S correct) {$\underline{S^{\text{proj.}}}$};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Control_PU_Cons.tex b/doc/images/Load/FlexibleLoad/Control_PU_Cons.tex new file mode 100644 index 00000000..702afdd4 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Control_PU_Cons.tex @@ -0,0 +1,108 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% +\usepgfplotslibrary{groupplots, colorbrewer}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + % + % Common parameters + % + \pgfmathsetmacro{\uminvaleur}{210.0}% + \pgfmathsetmacro{\uminnormvaleur}{1.0}% + \pgfmathsetmacro{\udownvaleur}{220.0}% + \pgfmathsetmacro{\udownnormvaleur}{\udownvaleur/\uminvaleur}% + \pgfmathsetmacro{\uupvaleur}{240.0}% + \pgfmathsetmacro{\uupnormvaleur}{\uupvaleur/\uminvaleur}% + \pgfmathsetmacro{\umaxvaleur}{250.0}% + \pgfmathsetmacro{\umaxnormvaleur}{\umaxvaleur/\uminvaleur}% + \pgfmathsetmacro{\unomvaleur}{(\udownvaleur+\uupvaleur)/2.0}% + \pgfmathsetmacro{\unomnormvaleur}{\unomvaleur/\uminvaleur}% + \pgfmathsetmacro{\umidminvaleur}{(\udownvaleur+\uminvaleur)/2.0}% + \pgfmathsetmacro{\umidminnormvaleur}{\umidminvaleur/\uminvaleur}% + \pgfmathsetmacro{\umidmaxvaleur}{(\uupvaleur+\umaxvaleur)/2.0}% + \pgfmathsetmacro{\umidmaxnormvaleur}{\umidmaxvaleur/\uminvaleur}% + + \pgfmathsetmacro{\xminvaleur}{\uminvaleur - 2.5}% + \pgfmathsetmacro{\xminnormvaleur}{\xminvaleur/\uminvaleur}% + \pgfmathsetmacro{\xmaxvaleur}{\umaxvaleur + 2.5}% + \pgfmathsetmacro{\xmaxnormvaleur}{\xmaxvaleur/\uminvaleur}% + + \pgfmathsetmacro{\yminnormvaleur}{0}% + \pgfmathsetmacro{\ymaxnormvaleur}{1}% + + % + % Style + % + \tikzset{lisse/.style={line width=0.3mm, + domain=\xminnormvaleur:\xmaxnormvaleur, samples=75, mark=none}}% + \tikzset{non lisse/.style={line width=0.3mm, mark=*}}% + + \begin{axis} + [% + height=7cm,% + width=0.9\textwidth,% + enlarge y limits,% + grid=major,% + xlabel={$|V_{p_1}-V_{p_2}|$},% + xtick={\uminnormvaleur,\umidminnormvaleur,\udownnormvaleur,\unomnormvaleur,\uupnormvaleur,\umidmaxnormvaleur,\umaxnormvaleur},% + xticklabels={% + $\uminnorm$,,$\udownnorm$,$\unomnorm$,$\uupnorm$,,$\umaxnorm$% + },% + y tick label style={/pgf/number format/.cd,% + set thousands separator={},% + fixed,% + % fixed zerofill,% + precision=1,% + use comma% + },% + xmin=\xminnormvaleur,% + xmax=\xmaxnormvaleur,% + ymin=\yminnormvaleur,% + ymax=\ymaxnormvaleur,% + legend columns=2,% + legend style={% + at={(0.5,-0.25)},% + anchor=north,% + nodes={text width=4cm}% + },% + cycle list/YlOrRd-5, % initialize YlOrRd-5 + cycle list name=YlOrRd-5% + ] + + % Piecewise linear function + \addplot[non lisse, red] coordinates {% + (\xminnormvaleur,0)% + (\uminnormvaleur,0)% + (\udownnormvaleur,1)% + (\xmaxnormvaleur,1)% + };% + \addlegendentry{Non-smooth control};% + + + % Soft clipping functions + \pgfplotsset{cycle list shift=-1}% Reset cycle to 0 + \foreach \alphavaleur in {50,100,200,300,400} {% + \addplot+[lisse] expression {% + 1.0/(\alphavaleur*(\udownnormvaleur-\uminnormvaleur)) * + ln((1+exp(\alphavaleur*(x-\uminnormvaleur)))/(1+exp(\alphavaleur*(x-\udownnormvaleur)))) + };% + \addlegendentryexpanded{Soft clipping ($\alpha=\num{\alphavaleur}$)};% + };% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Control_PU_Prod.tex b/doc/images/Load/FlexibleLoad/Control_PU_Prod.tex new file mode 100644 index 00000000..cdc28a40 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Control_PU_Prod.tex @@ -0,0 +1,108 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% +\usepgfplotslibrary{groupplots, colorbrewer}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + % + % Common parameters + % + \pgfmathsetmacro{\umaxvaleur}{250.0}% + \pgfmathsetmacro{\umaxnormvaleur}{1.0}% + \pgfmathsetmacro{\uupvaleur}{240.0}% + \pgfmathsetmacro{\uupnormvaleur}{\uupvaleur/\umaxvaleur}% + \pgfmathsetmacro{\udownvaleur}{220.0}% + \pgfmathsetmacro{\udownnormvaleur}{\udownvaleur/\umaxvaleur}% + \pgfmathsetmacro{\uminvaleur}{210.0}% + \pgfmathsetmacro{\uminnormvaleur}{\uminvaleur/\umaxvaleur}% + \pgfmathsetmacro{\unomvaleur}{(\udownvaleur+\uupvaleur)/2.0}% + \pgfmathsetmacro{\unomnormvaleur}{\unomvaleur/\umaxvaleur}% + \pgfmathsetmacro{\umidminvaleur}{(\udownvaleur+\uminvaleur)/2.0}% + \pgfmathsetmacro{\umidminnormvaleur}{\umidminvaleur/\umaxvaleur}% + \pgfmathsetmacro{\umidmaxvaleur}{(\uupvaleur+\umaxvaleur)/2.0}% + \pgfmathsetmacro{\umidmaxnormvaleur}{\umidmaxvaleur/\umaxvaleur}% + + \pgfmathsetmacro{\xminvaleur}{\uminvaleur - 2.5}% + \pgfmathsetmacro{\xminnormvaleur}{\xminvaleur/\umaxvaleur}% + \pgfmathsetmacro{\xmaxvaleur}{\umaxvaleur + 2.5}% + \pgfmathsetmacro{\xmaxnormvaleur}{\xmaxvaleur/\umaxvaleur}% + + \pgfmathsetmacro{\yminnormvaleur}{0}% + \pgfmathsetmacro{\ymaxnormvaleur}{1}% + + % + % Style + % + \tikzset{lisse/.style={line width=0.3mm, domain=\xminnormvaleur:\xmaxnormvaleur, samples=75, + mark=none}}% + \tikzset{non lisse/.style={line width=0.3mm, mark=*}}% + + \begin{axis} + [% + height=7cm,% + width=0.9\textwidth,% + enlarge y limits,% + grid=major,% + xlabel={$|V_{p_1}-V_{p_2}|$},% + xtick={\uminnormvaleur,\umidminnormvaleur,\udownnormvaleur,\unomnormvaleur,\uupnormvaleur,\umidmaxnormvaleur,\umaxnormvaleur},% + xticklabels={% + $\uminnorm$,,$\udownnorm$,$\unomnorm$,$\uupnorm$,,$\umaxnorm$% + },% + y tick label style={/pgf/number format/.cd,% + set thousands separator={},% + fixed,% + % fixed zerofill,% + precision=1,% + use comma% + },% + xmin=\xminnormvaleur,% + xmax=\xmaxnormvaleur,% + ymin=\yminnormvaleur,% + ymax=\ymaxnormvaleur,% + legend columns=2,% + legend style={% + at={(0.5,-0.25)},% + anchor=north,% + nodes={text width=4cm}% + },% + cycle list/YlOrRd-5, % initialize YlOrRd-5 + cycle list name=YlOrRd-5% + ] + + % Piecewise linear function + \addplot[non lisse, red] coordinates {% + (\xminnormvaleur,1)% + (\uupnormvaleur,1)% + (\umaxnormvaleur,0)% + (\xmaxnormvaleur,0)% + };% + \addlegendentry{Non-smooth control};% + + + % Soft clipping functions + \pgfplotsset{cycle list shift=-1}% Reset cycle to 0 + \foreach \alphavaleur in {50,100,200,300,400} {% + \addplot+[lisse] expression {% + 1.0 + 1.0/(\alphavaleur*(\umaxnormvaleur-\uupnormvaleur)) * + ln((1+exp(\alphavaleur*(x-\umaxnormvaleur)))/(1+exp(\alphavaleur*(x-\uupnormvaleur)))) + };% + \addlegendentryexpanded{Soft clipping ($\alpha=\num{\alphavaleur}$)};% + };% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Control_QU.tex b/doc/images/Load/FlexibleLoad/Control_QU.tex new file mode 100644 index 00000000..1c944ad1 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Control_QU.tex @@ -0,0 +1,117 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% +\usepgfplotslibrary{groupplots, colorbrewer}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + % + % Common parameters + % + \pgfmathsetmacro{\umaxvaleur}{250.0}% + \pgfmathsetmacro{\umaxnormvaleur}{1.0}% + \pgfmathsetmacro{\uupvaleur}{240.0}% + \pgfmathsetmacro{\uupnormvaleur}{\uupvaleur/\umaxvaleur}% + \pgfmathsetmacro{\udownvaleur}{220.0}% + \pgfmathsetmacro{\udownnormvaleur}{\udownvaleur/\umaxvaleur}% + \pgfmathsetmacro{\uminvaleur}{210.0}% + \pgfmathsetmacro{\uminnormvaleur}{\uminvaleur/\umaxvaleur}% + \pgfmathsetmacro{\unomvaleur}{(\udownvaleur+\uupvaleur)/2.0}% + \pgfmathsetmacro{\unomnormvaleur}{\unomvaleur/\umaxvaleur}% + \pgfmathsetmacro{\umidminvaleur}{(\udownvaleur+\uminvaleur)/2.0}% + \pgfmathsetmacro{\umidminnormvaleur}{\umidminvaleur/\umaxvaleur}% + \pgfmathsetmacro{\umidmaxvaleur}{(\uupvaleur+\umaxvaleur)/2.0}% + \pgfmathsetmacro{\umidmaxnormvaleur}{\umidmaxvaleur/\umaxvaleur}% + + \pgfmathsetmacro{\xminvaleur}{\uminvaleur - 2.5}% + \pgfmathsetmacro{\xminnormvaleur}{\xminvaleur/\umaxvaleur}% + \pgfmathsetmacro{\xmaxvaleur}{\umaxvaleur + 2.5}% + \pgfmathsetmacro{\xmaxnormvaleur}{\xmaxvaleur/\umaxvaleur}% + + \pgfmathsetmacro{\yminnormvaleur}{-1}% + \pgfmathsetmacro{\ymaxnormvaleur}{1}% + + \pgfmathsetmacro{\qthnormvaleur}{0.30}% + + % + % Style + % + \tikzset{lisse/.style={line width=0.3mm, domain=\xminnormvaleur:\xmaxnormvaleur, samples=75, + mark=none}}% + \tikzset{non lisse/.style={line width=0.3mm, mark=*}}% + + \begin{axis} + [% + height=7cm,% + width=0.9\textwidth,% + enlarge y limits,% + grid=major,% + xlabel={$|V_{p_1}-V_{p_2}|$},% + xtick={\uminnormvaleur,\umidminnormvaleur,\udownnormvaleur,\unomnormvaleur,\uupnormvaleur,\umidmaxnormvaleur,\umaxnormvaleur},% + xticklabels={% + $\uminnorm$,,$\udownnorm$,$\unomnorm$,$\uupnorm$,,$\umaxnorm$% + },% + y tick label style={/pgf/number format/.cd,% + set thousands separator={},% + fixed,% + fixed zerofill,% + precision=1,% + use comma% + },% + ytick={\yminnormvaleur,0,\qthnormvaleur,\ymaxnormvaleur},% + yticklabels={-1,0,$\dfrac{Q^{\theo}_{p_1p_2}}{\smax_{p_1p_2}}$,1},% + xmin=\xminnormvaleur,% + xmax=\xmaxnormvaleur,% + ymin=\yminnormvaleur,% + ymax=\ymaxnormvaleur,% + % ylabel={$\alpha\left(|V_{p}|\right)$},% + % legend entries={Contrôles non lisses,Contrôles lisses},% + legend columns=2,% + legend style={% + at={(0.5,-0.25)},% + anchor=north,% + nodes={text width=4cm}% + },% + cycle list/YlOrRd-5, % initialize YlOrRd-5 + cycle list name=YlOrRd-5% + ] + + % Fonction linéaire par morceaux + \addplot[non lisse, red] coordinates {% + (\xminnormvaleur,-1)% + (\uminnormvaleur,-1)% + (\udownnormvaleur,\qthnormvaleur)% + (\uupnormvaleur,\qthnormvaleur)% + (\umaxnormvaleur,1)% + (\xmaxnormvaleur,1)% + };% + \addlegendentry{Non-smooth control};% + + % Soft clipping functions + \pgfplotsset{cycle list shift=-1}% Reset cycle to 0 + \foreach \alphavaleur in {50,100,200,300,400} {% + \addplot+[lisse] expression {% + \qthnormvaleur + ( 1.0/(\alphavaleur*(\uminnormvaleur-\udownnormvaleur)) * + ln((1+exp(\alphavaleur*(x-\udownnormvaleur)))/(1+exp(\alphavaleur*(x-\uminnormvaleur))))-1.0 + )*(1+\qthnormvaleur) + ( 1.0/(\alphavaleur*(\umaxnormvaleur-\uupnormvaleur)) * + ln((1+exp(\alphavaleur*(x-\uupnormvaleur)))/(1+exp(\alphavaleur*(x-\umaxnormvaleur)))) + )*(1-\qthnormvaleur) };% + \addlegendentryexpanded{Soft clipping ($\alpha=\num{\alphavaleur}$)};% + };% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Domain_Common.tikz b/doc/images/Load/FlexibleLoad/Domain_Common.tikz similarity index 95% rename from doc/images/Domain_Common.tikz rename to doc/images/Load/FlexibleLoad/Domain_Common.tikz index d6164e22..63f2cf06 100644 --- a/doc/images/Domain_Common.tikz +++ b/doc/images/Load/FlexibleLoad/Domain_Common.tikz @@ -10,8 +10,8 @@ % % Macros % -\pgfmathsetmacro{\r}{1.2};% -\pgfmathsetmacro{\R}{1.5};% +\pgfmathsetmacro{\r}{1.6};% +\pgfmathsetmacro{\R}{2};% \pgfmathsetmacro{\pthvaleur}{-0.55*\r};% \pgfmathsetmacro{\qthvaleur}{0.6*\r};% \pgfmathsetmacro{\angthvaleur}{acos(\pthvaleur/\r)}% diff --git a/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.tex b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.tex new file mode 100644 index 00000000..b2aff101 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.tex @@ -0,0 +1,30 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \input{Load/FlexibleLoad/Domain_Common.tikz}% + + % The domain is a segment with two arc circle + \draw[domaine] (-\angeuclthvaleur:\r) arc[start angle=-\angeuclthvaleur, end + angle=-\angthvaleur, radius=\r] -- (\pthvaleur,\qthmaxvaleur) arc [start angle=\angthvaleur, end + angle=\angeuclthvaleur, radius=\r];% + + \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% + + \draw[dashed] (0,0) -- (\pthvaleur,\r);% + \draw[dashed] (0,0) -- (\pthvaleur,-\r);% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_P.tex b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_P.tex new file mode 100644 index 00000000..67cf5b91 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_P.tex @@ -0,0 +1,25 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \input{Load/FlexibleLoad/Domain_Common.tikz}% + + % The domain is a segment + \draw[domaine] (\pthvaleur,-\qthmaxvaleur) -- (\pthvaleur,\qthmaxvaleur);% + + \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Q.tex b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Q.tex new file mode 100644 index 00000000..9b58de00 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Q.tex @@ -0,0 +1,26 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \input{Load/FlexibleLoad/Domain_Common.tikz}% + + % The domain is a segment with two portions of circle arc + \draw[domaine] (0,-\r) arc[start angle=-90, end angle=-\angthvaleur, radius=\r] -- + (\pthvaleur,\qthmaxvaleur) arc [start angle=\angthvaleur, end angle=90, radius=\r];% + + \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Domain_Pconst_Qconst.tex b/doc/images/Load/FlexibleLoad/Domain_Pconst_Qconst.tex new file mode 100644 index 00000000..93829aeb --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Domain_Pconst_Qconst.tex @@ -0,0 +1,22 @@ +\input{Preambule}% +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \input{Load/FlexibleLoad/Domain_Common.tikz}% + + % The domain is limited to a point + \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Domain_PmaxU_QU.tex b/doc/images/Load/FlexibleLoad/Domain_PmaxU_QU.tex new file mode 100644 index 00000000..8b8cbe7c --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Domain_PmaxU_QU.tex @@ -0,0 +1,26 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \input{Load/FlexibleLoad/Domain_Common.tikz}% + + % The domain is a prtion of the circle + \filldraw[domaine hache] (0,-\r) arc[start angle=-90, end angle=-\angthvaleur, radius=\r] -- + (\pthvaleur, \qthmaxvaleur) arc[start angle=\angthvaleur, end angle=90, radius=\r] --cycle;% + + \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Domain_PmaxU_Qconst.tex b/doc/images/Load/FlexibleLoad/Domain_PmaxU_Qconst.tex new file mode 100644 index 00000000..cf85c1fe --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Domain_PmaxU_Qconst.tex @@ -0,0 +1,24 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \input{Load/FlexibleLoad/Domain_Common.tikz}% + + % The domain is a segment + \draw[domaine] (0,\qthvaleur) -- (\pthvaleur,\qthvaleur);% + \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Euclidean_Projection.tex b/doc/images/Load/FlexibleLoad/Euclidean_Projection.tex new file mode 100644 index 00000000..bc08f74b --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Euclidean_Projection.tex @@ -0,0 +1,73 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + % Styles + \tikzset{fleche/.style={->, -{Latex}}}% + \tikzset{interdit/.style={pattern=north east lines, pattern color=red}}% + \tikzset{point/.pic={\filldraw[#1] (0,0) circle[radius=0.05];}, point/.default=black}% + + % Paramètres + \pgfmathsetmacro{\r}{3.5}% + \pgfmathsetmacro{\R}{1.1 * \r}% + \pgfmathsetmacro{\pth}{0.8 * \r}% + \pgfmathsetmacro{\angth}{acos(\pth/\r)}% + \pgfmathsetmacro{\qth}{\r * sin(\angth)}% + \pgfmathsetmacro{\startangle}{-10}% + \pgfmathsetmacro{\endangle}{90-\startangle}% + + % Axes + \pgfmathsetmacro{\tmp}{\r*cos(90-\startangle)};% + \draw[fleche] (\tmp,0) -- (\R,0) node[below right] {$P$};% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \draw[fleche] (0,\tmp) -- (0,\R) node[above right] {$Q$};% + + % Circle + \draw (\startangle:\r) arc[start angle=\startangle, end angle=\endangle, radius=\r];% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \pgfmathsetmacro{\tmpdeux}{\r*cos(\endangle)};% + \pgfmathsetmacro{\tmptrois}{\r*sin(\endangle)};% + \fill[interdit] (0,\tmp) -- (\tmpdeux,\tmp) -- (\tmpdeux,\tmptrois) arc[start angle=\endangle, + end angle=90, radius=\r];% + \draw[fleche] (0,0) -- (20:\r) node[above, midway, sloped] {$\smax$};% + + % Rectangle + \draw (0,\r) -- (\r,\r) -- (\r,0);% + + % Theoretical power + \draw (\pth,0) -- (\pth,\r) node[below left] at (\pth,0) {$P^{\theo}$};% + \pgfmathsetmacro{\tmp}{\r*sin(\startangle)};% + \fill[interdit] (\pth,\qth) arc[start angle=\angth, end angle=\startangle, radius=\r] -- + (\pth,\tmp);% + + % Point P^{\theo} + \path (\pth,0) pic[pic type=point];% + + % Point outside of the circle + \pgfmathsetmacro{\rayon}{1.15*\r}% + \pgfmathsetmacro{\anglevaleur}{55}% + \coordinate (S) at (\anglevaleur:\rayon);% + + \node[right] at (S) {$\underline{S}$};% + \path (S) pic[pic type=point];% + + % Projection + \coordinate (S correct) at (\anglevaleur:\r);% + \draw[fleche, blue] (S) -- (S correct);% + \path (S correct) pic {point=blue};% + \node[below left] at (S correct) {$\underline{S^{\text{proj.}}}$};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex new file mode 100644 index 00000000..f7e33c4d --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex @@ -0,0 +1,81 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \begin{axis} + [% + xlabel={Voltages (V)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.1,0.5)},anchor=south},% + grid=both,% + legend entries={Effective power,Non-smooth theoretical control},% + legend style={% + legend cell align=left,% + legend pos=north west,% + },% + sharp plot,% + mark size=0.5mm,% + height=9cm,% + width=16cm,% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==210}{% + "\\$\umin$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==220}{% + "\\$\udown$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==240}{% + "\\$\uup$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==250}{% + "\\$\umax$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + ] + \addplot+[only marks] table[x=v, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_Eucl_Example.csv};% + \addplot+ coordinates {(205,-5000) (210,-5000) (220,0) (240,0) (250,5000) (255,5000)};% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Example.csv b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Example.csv new file mode 100644 index 00000000..81db670f --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-2236.0679775919675,-4472.135954953491 +206.0,-2236.067982532515,-4472.135952483217 +207.0,-2236.068252276505,-4472.135817611212 +208.0,-2236.082977416831,-4472.128455009614 +209.0,-2236.879924830704,-4471.729889191584 +210.0,-2267.4462214926693,-4456.308745210392 +211.0,-2429.150449642832,-4370.266364078971 +212.0,-2500.0,-3999.9580742033895 +213.0,-2500.0,-3499.999231975902 +214.0,-2500.0,-2999.999985937823 +215.0,-2500.0,-2500.0 +216.0,-2500.0,-2000.0000140621771 +217.0,-2500.0,-1500.0007680240985 +218.0,-2500.0,-1000.0419257966104 +219.0,-2500.0,-502.26874098972695 +220.0,-2500.0,-86.64339756999372 +221.0,-2500.0,-2.268740989725404 +222.0,-2500.0,-0.041925796612218846 +223.0,-2500.0,-0.0007680241859153725 +224.0,-2500.0,-1.4066895981379446e-05 +225.0,-2500.0,-2.5764390620963695e-07 +226.0,-2500.0,-4.719002966169228e-09 +227.0,-2500.0,-8.715250743307479e-11 +228.0,-2500.0,-2.7755575615628914e-12 +229.0,-2500.0,1.1102230246251565e-12 +230.0,-2500.0,0.0 +231.0,-2500.0,-1.0824674490095276e-12 +232.0,-2500.0,2.692290834715993e-12 +233.0,-2500.0,8.754108549166365e-11 +234.0,-2500.0,4.7189196993533036e-09 +235.0,-2500.0,2.576431010324217e-07 +236.0,-2500.0,1.4066897160515013e-05 +237.0,-2500.0,0.0007680241858286514 +238.0,-2500.0,0.041925796610847534 +239.0,-2500.0,2.26874098972511 +240.0,-2500.0,86.64339756999419 +241.0,-2500.0,502.26874098972735 +242.0,-2500.0,1000.0419257966093 +243.0,-2500.0,1500.000768024097 +244.0,-2500.0,2000.000014062176 +245.0,-2500.0,2499.999999999999 +246.0,-2500.0,2999.999985937824 +247.0,-2500.0,3499.9992319759026 +248.0,-2500.0,3999.9580742033904 +249.0,-2429.150449642832,4370.266364078971 +250.0,-2267.44622149267,4456.308745210391 +251.0,-2236.879924830704,4471.729889191584 +252.0,-2236.0829774168315,4472.128455009614 +253.0,-2236.0682522765055,4472.135817611211 +254.0,-2236.067982532515,4472.135952483217 +255.0,-2236.0679775919666,4472.135954953491 diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.tex new file mode 100644 index 00000000..98a6791d --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.tex @@ -0,0 +1,94 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] below:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] above:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_Eucl_Example.csv};% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex new file mode 100644 index 00000000..3a046575 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex @@ -0,0 +1,81 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \begin{axis} + [% + xlabel={Voltages (V)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.1,0.5)},anchor=south},% + grid=both,% + legend entries={Effective power,Non-smooth theoretical control},% + legend style={% + legend cell align=left,% + legend pos=north west,% + },% + sharp plot,% + mark size=0.5mm,% + height=9cm,% + width=16cm,% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==210}{% + "\\$\umin$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==220}{% + "\\$\udown$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==240}{% + "\\$\uup$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==250}{% + "\\$\umax$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + ] + \addplot+[only marks] table[x=v, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_P_Example.csv};% + \addplot+ coordinates {(205,-5000) (210,-5000) (220,0) (240,0) (250,5000) (255,5000)};% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_P_Example.csv b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Example.csv new file mode 100644 index 00000000..5094743d --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-2500.0,-4330.127018922193 +206.0,-2500.0,-4330.127018922193 +207.0,-2500.0,-4330.127018922193 +208.0,-2500.0,-4330.127018922193 +209.0,-2500.0,-4330.127018922193 +210.0,-2500.0,-4330.127018922199 +211.0,-2500.0,-4330.150847081422 +212.0,-2500.0,-3999.958097622331 +213.0,-2500.0,-3499.999231975902 +214.0,-2500.0,-2999.999985937823 +215.0,-2500.0,-2500.0 +216.0,-2500.0,-2000.0000140621771 +217.0,-2500.0,-1500.0007680240985 +218.0,-2500.0,-1000.0419257966104 +219.0,-2500.0,-502.26874098972695 +220.0,-2500.0,-86.64339756999357 +221.0,-2500.0,-0.9641585416943067 +222.0,-2500.0,-0.004192533096206056 +223.0,-2500.0,-7.680241798760731e-05 +224.0,-2500.0,-1.4066895981342335e-06 +225.0,-2500.0,-2.5764390620963675e-08 +226.0,-2500.0,-4.719002966169228e-10 +227.0,-2500.0,-8.715250743307479e-12 +228.0,-2500.0,-2.7755575615628914e-13 +229.0,-2500.0,1.1102230246251565e-13 +230.0,-2500.0,0.0 +231.0,-2500.0,-1.0824674490095276e-13 +232.0,-2500.0,2.692290834715993e-13 +233.0,-2500.0,8.754108549166364e-12 +234.0,-2500.0,4.718919699353304e-10 +235.0,-2500.0,2.5764310103242154e-08 +236.0,-2500.0,1.4066897160477902e-06 +237.0,-2500.0,7.680241797893518e-05 +238.0,-2500.0,0.004192533096068925 +239.0,-2500.0,0.9641585416940721 +240.0,-2500.0,86.64339756999404 +241.0,-2500.0,502.26874098972735 +242.0,-2500.0,1000.0419257966093 +243.0,-2500.0,1500.000768024097 +244.0,-2500.0,2000.000014062176 +245.0,-2500.0,2499.999999999999 +246.0,-2500.0,2999.999985937824 +247.0,-2500.0,3499.9992319759026 +248.0,-2500.0,3999.9580976223315 +249.0,-2500.0,4330.150847081422 +250.0,-2500.0,4330.127018922199 +251.0,-2500.0,4330.127018922193 +252.0,-2500.0,4330.127018922193 +253.0,-2500.0,4330.127018922193 +254.0,-2500.0,4330.127018922193 +255.0,-2500.0,4330.127018922193 diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.tex new file mode 100644 index 00000000..072bbab7 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.tex @@ -0,0 +1,94 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] below left:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] above left:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_P_Example.csv};% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex new file mode 100644 index 00000000..f6782305 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex @@ -0,0 +1,81 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \begin{axis} + [% + xlabel={Voltages (V)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.1,0.5)},anchor=south},% + grid=both,% + legend entries={Effective power,Non-smooth theoretical control},% + legend style={% + legend cell align=left,% + legend pos=north west,% + },% + sharp plot,% + mark size=0.5mm,% + height=9cm,% + width=16cm,% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==210}{% + "\\$\umin$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==220}{% + "\\$\udown$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==240}{% + "\\$\uup$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==250}{% + "\\$\umax$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + ] + \addplot+[only marks] table[x=v, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_Q_Example.csv};% + \addplot+ coordinates {(205,-5000) (210,-5000) (220,0) (240,0) (250,5000) (255,5000)};% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Example.csv b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Example.csv new file mode 100644 index 00000000..95733389 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-0.5000132304722589,-4999.999999742356 +206.0,-0.532061670101206,-4999.999985933104 +207.0,-2.771324820863182,-4999.999231975815 +208.0,-20.475746832553064,-4999.958074203388 +209.0,-150.60631697104301,-4997.731259010274 +210.0,-926.7830907809562,-4913.356602430007 +211.0,-2184.1748739974582,-4497.731259010274 +212.0,-2500.0000374699125,-3999.9580742033895 +213.0,-2500.0,-3499.999231975902 +214.0,-2500.0,-2999.999985937823 +215.0,-2500.0,-2500.0 +216.0,-2500.0,-2000.0000140621771 +217.0,-2500.0,-1500.0007680240985 +218.0,-2500.0,-1000.0419257966104 +219.0,-2500.0,-502.26874098972695 +220.0,-2500.0,-86.64339756999372 +221.0,-2500.0,-2.268740989725404 +222.0,-2500.0,-0.041925796612218846 +223.0,-2500.0,-0.0007680241859153725 +224.0,-2500.0,-1.4066895981379446e-05 +225.0,-2500.0,-2.5764390620963695e-07 +226.0,-2500.0,-4.719002966169228e-09 +227.0,-2500.0,-8.715250743307479e-11 +228.0,-2500.0,-2.7755575615628914e-12 +229.0,-2500.0,1.1102230246251565e-12 +230.0,-2500.0,0.0 +231.0,-2500.0,-1.0824674490095276e-12 +232.0,-2500.0,2.692290834715993e-12 +233.0,-2500.0,8.754108549166365e-11 +234.0,-2500.0,4.7189196993533036e-09 +235.0,-2500.0,2.576431010324217e-07 +236.0,-2500.0,1.4066897160515013e-05 +237.0,-2500.0,0.0007680241858286514 +238.0,-2500.0,0.041925796610847534 +239.0,-2500.0,2.26874098972511 +240.0,-2500.0,86.64339756999419 +241.0,-2500.0,502.26874098972735 +242.0,-2500.0,1000.0419257966093 +243.0,-2500.0,1500.000768024097 +244.0,-2500.0,2000.000014062176 +245.0,-2500.0,2499.999999999999 +246.0,-2500.0,2999.999985937824 +247.0,-2500.0,3499.9992319759026 +248.0,-2500.0000374699125,3999.9580742033904 +249.0,-2184.1748739974582,4497.731259010274 +250.0,-926.7830907809681,4913.356602430005 +251.0,-150.60631697104301,4997.731259010274 +252.0,-20.475746832824168,4999.958074203387 +253.0,-2.7713248238677637,4999.999231975813 +254.0,-0.5320616633668144,4999.999985933106 +255.0,-0.500013230187694,4999.999999742358 diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.tex new file mode 100644 index 00000000..aa1d2038 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.tex @@ -0,0 +1,94 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] below right:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] below:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] above:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] above right:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_Q_Example.csv};% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Example.csv b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Example.csv new file mode 100644 index 00000000..69b85579 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-2236.0679775382478,-4472.135954980351 +206.0,-2236.067979980322,-4472.135953759313 +207.0,-2236.068137494058,-4472.135875002441 +208.0,-2236.0782959651738,-4472.1307957520075 +209.0,-2236.7286604177757,-4471.805552533081 +210.0,-2266.1763700890097,-4456.954639622239 +211.0,-2428.9761116929394,-4370.36326279922 +212.0,-2500.0,-3999.9711591289265 +213.0,-2500.0,-3499.9995528024824 +214.0,-2500.0,-2999.9999930683607 +215.0,-2500.0,-2499.999999999993 +216.0,-2500.0,-2000.0000069316266 +217.0,-2500.0,-1500.0004471975176 +218.0,-2500.0,-1000.0288408710728 +219.0,-2500.0,-501.84618761732133 +220.0,-2500.0,-83.17766166719365 +221.0,-2500.0,-1.8461876173236913 +222.0,-2500.0,-0.028840871076507568 +223.0,-2500.0,-0.00044719752148036923 +224.0,-2500.0,-6.931630709416948e-06 +225.0,-2500.0,-6.222063389793264e-14 +226.0,-2500.0,6.93163158381857e-06 +227.0,-2500.0,0.000447197520726527 +228.0,-2500.0,0.0288408710766433 +229.0,-2500.0,1.846187617322751 +230.0,-2500.0,83.1776616671935 +231.0,-2500.0,501.8461876173226 +232.0,-2500.0,1000.0288408710736 +233.0,-2500.0,1500.0004471975176 +234.0,-2500.0,2000.0000069316252 +235.0,-2500.0,2499.999999999993 +236.0,-2500.0,2999.9999930683603 +237.0,-2500.0,3499.9995528024824 +238.0,-2500.0,3999.9711591289274 +239.0,-2428.9761116929385,4370.36326279922 +240.0,-2266.176370088993,4456.954639622248 +241.0,-2236.728660416862,4471.805552533539 +242.0,-2236.0782959152757,4472.130795776957 +243.0,-2236.0681347697605,4472.13587636459 +244.0,-2236.0678312387536,4472.136028130094 +245.0,-2236.059856693918,4472.140015393299 +246.0,-2235.625100721815,4472.357365978548 +247.0,-2213.2770547707137,4483.459008268669 +248.0,-1831.53905946031,4652.4686644480735 +249.0,-984.2745173321633,4902.16316277061 +250.0,-173.0958262224784,4994.816946155494 +251.0,-4.534130344163855,4996.535636675593 +252.0,-0.08378970712469609,4996.536664347264 +253.0,-0.0015349147105347424,4996.536664698182 +254.0,-2.8113029017036173e-05,4996.536664698299 +255.0,-5.149078683543149e-07,4996.536664698299 diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.tex new file mode 100644 index 00000000..f233c667 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.tex @@ -0,0 +1,102 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1,% + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] right:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] below:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] above:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] above:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] below:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {Load/FlexibleLoad/PmaxU_QU_Sequential_1_Example.csv};% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Example.csv b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Example.csv new file mode 100644 index 00000000..b85b7aad --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-2236.0679775919675,-4472.135954953491 +206.0,-2236.067982532515,-4472.135952483217 +207.0,-2236.068252276505,-4472.135817611212 +208.0,-2236.082977416831,-4472.128455009614 +209.0,-2236.879924830704,-4471.729889191584 +210.0,-2267.4462214926693,-4456.308745210392 +211.0,-2429.150449642832,-4370.266364078971 +212.0,-2500.0,-3999.9580742033895 +213.0,-2500.0,-3499.999231975902 +214.0,-2500.0,-2999.999985937823 +215.0,-2500.0,-2500.0 +216.0,-2500.0,-2000.0000140621771 +217.0,-2500.0,-1500.0007680240985 +218.0,-2500.0,-1000.0419257966104 +219.0,-2500.0,-502.26874098972695 +220.0,-2500.0,-86.64339756999372 +221.0,-2500.0,-2.268740989725404 +222.0,-2500.0,-0.041925796612218846 +223.0,-2500.0,-0.0007680241859153725 +224.0,-2500.0,-1.4066895981379446e-05 +225.0,-2500.0,-2.5764390620963695e-07 +226.0,-2500.0,-4.719002966169228e-09 +227.0,-2499.9999999999995,-8.715250743307479e-11 +228.0,-2499.999999999974,-2.7755575615628914e-12 +229.0,-2499.9999999983334,1.1102230246251565e-12 +230.0,-2499.9999998925073,0.0 +231.0,-2499.999993066702,-1.1102230246251565e-12 +232.0,-2499.999552802453,1.1102230246251565e-12 +233.0,-2499.9711591289492,1.1102230246251565e-12 +234.0,-2498.153812384344,0.0 +235.0,-2416.8223384402995,-1.1102230246251565e-12 +236.0,-1998.1538193159781,1.1657341758564144e-12 +237.0,-1499.971606326463,4.27435864480683e-12 +238.0,-1000.0283936735241,1.7175150190945182e-10 +239.0,-501.84618068402244,9.436729175681982e-09 +240.0,-83.17766155970074,5.152895327339173e-07 +241.0,-1.8461876156564139,2.813379315529586e-05 +242.0,-0.028840871050817007,0.0015360483651625176 +243.0,-0.00044719754704880543,0.08385159304994605 +244.0,-6.9332981023073614e-06,4.53748197001349 +245.0,-1.0749290346723228e-07,173.28679462469663 +246.0,-1.6669998714746725e-09,1004.5374538456617 +247.0,-2.609024107869118e-11,2000.0823155448559 +248.0,-5.551115123125783e-13,2999.917684455146 +249.0,-0.0,3995.46254615434 +250.0,-0.0,4826.713205375302 +251.0,-8.323850959092303e-13,4993.769666036564 +252.0,-0.0,4996.494563038826 +253.0,-0.0,4996.535896615463 +254.0,-8.320905096191371e-13,4996.536650631391 +255.0,-0.0,4996.536664440657 diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.tex new file mode 100644 index 00000000..6ed3e43a --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.tex @@ -0,0 +1,104 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1,% + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] below:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] below:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] below left:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {% + Load/FlexibleLoad/PmaxU_QU_Sequential_2_Example.csv% + };% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Example.csv b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Example.csv new file mode 100644 index 00000000..d8630953 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-3123.4752378702615,-3904.34404713664 +206.0,-3123.4752431303655,-3904.344042928556 +207.0,-3123.4755303214724,-3904.3438131756525 +208.0,-3123.4912078505167,-3904.3312710988703 +209.0,-3124.3395901559534,-3903.6524083714385 +210.0,-3156.7159632002063,-3877.517804946483 +211.0,-3322.7549000972035,-3736.2146450491878 +212.0,-3535.552434740721,-3535.5153770276493 +213.0,-3762.883831585663,-3292.52263014109 +214.0,-3997.2293351288868,-2997.921987294228 +215.0,-4000.0,-2500.0 +216.0,-4000.0,-2000.0000140621771 +217.0,-4000.0,-1500.0007680240985 +218.0,-4000.0,-1000.0419257966104 +219.0,-4000.0,-502.26874098972695 +220.0,-4000.0,-86.64339756999372 +221.0,-4000.0,-2.268740989725404 +222.0,-4000.0,-0.041925796612218846 +223.0,-4000.0,-0.0007680241859153725 +224.0,-4000.0,-1.4066895981379446e-05 +225.0,-4000.0,-2.5764390620963695e-07 +226.0,-4000.0,-4.719002966169228e-09 +227.0,-4000.0,-8.715250743307479e-11 +228.0,-4000.0,-2.7755575615628914e-12 +229.0,-4000.0,1.1102230246251565e-12 +230.0,-4000.0,0.0 +231.0,-4000.0,-1.0824674490095276e-12 +232.0,-4000.0,2.692290834715993e-12 +233.0,-4000.0,8.754108549166365e-11 +234.0,-3999.999999999998,4.7189196993533036e-09 +235.0,-3999.9999999999136,2.576431010324217e-07 +236.0,-3999.999999995281,1.4066897160515013e-05 +237.0,-3999.9999997423565,0.0007680241858286514 +238.0,-3999.9999859331037,0.041925796610847534 +239.0,-3999.9992319758153,2.26874098972511 +240.0,-3999.958074203388,86.64339756999419 +241.0,-3997.731259010274,502.26874098972735 +242.0,-3913.356602430009,1000.0419257966093 +243.0,-3497.73125901036,1500.000768024097 +244.0,-2999.9580742081066,2000.000014062176 +245.0,-2499.999232233459,2499.999999999999 +246.0,-2000.0,2999.999985937824 +247.0,-1500.0007677665405,3499.9992319759026 +248.0,-1000.041925791893,3999.9580742033904 +249.0,-502.2687409896398,4497.731259010274 +250.0,-86.64339756698323,4913.356602259406 +251.0,-2.2676257006015934,4995.274427072589 +252.0,-0.04189693115933036,4996.515657751498 +253.0,-0.0007674922580982291,4996.536280671605 +254.0,-1.4057152436597654e-05,4996.536657664851 +255.0,-2.5746611044154283e-07,4996.536664569479 diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.tex new file mode 100644 index 00000000..daf3208a --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.tex @@ -0,0 +1,113 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + extra x ticks={-4000},% + minor tick num=1,% + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-4}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + extra x tick label={% + \pgfmathparse{\tick/1000}% + $\pgfmathprintnumber{\pgfmathresult}$ + \pgfmathifthenelse{\tick==-4000}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] right:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] below:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] below left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] above:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] below right:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {% + Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Example.csv% + };% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Example.csv b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Example.csv new file mode 100644 index 00000000..14dacb5f --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-2236.0679775919675,-4472.135954953491 +206.0,-2236.067982532515,-4472.135952483217 +207.0,-2236.068252276505,-4472.135817611212 +208.0,-2236.082977416831,-4472.128455009614 +209.0,-2236.879924830704,-4471.729889191584 +210.0,-2267.4462214926693,-4456.308745210392 +211.0,-2429.150449642832,-4370.266364078971 +212.0,-2500.0,-3999.9580742033895 +213.0,-2500.0,-3499.999231975902 +214.0,-2500.0,-2999.999985937823 +215.0,-2500.0,-2500.0 +216.0,-2500.0,-2000.0000140621771 +217.0,-2500.0,-1500.0007680240985 +218.0,-2500.0,-1000.0419257966104 +219.0,-2500.0,-502.26874098972695 +220.0,-2500.0,-86.64339756999372 +221.0,-2500.0,-2.268740989725404 +222.0,-2500.0,-0.041925796612218846 +223.0,-2500.0,-0.0007680241859153725 +224.0,-2500.0,-1.4066895981379446e-05 +225.0,-2500.0,-2.5764390620963695e-07 +226.0,-2500.0,-4.719002966169228e-09 +227.0,-2500.0,-8.715250743307479e-11 +228.0,-2500.0,-2.7755575615628914e-12 +229.0,-2500.0,1.1102230246251565e-12 +230.0,-2500.0,0.0 +231.0,-2500.0,-1.0824674490095276e-12 +232.0,-2500.0,2.692290834715993e-12 +233.0,-2500.0,8.754108549166365e-11 +234.0,-2500.0,4.7189196993533036e-09 +235.0,-2500.0,2.576431010324217e-07 +236.0,-2500.0,1.4066897160515013e-05 +237.0,-2499.999999999998,0.0007680241858286514 +238.0,-2499.9999999999136,0.041925796610847534 +239.0,-2499.999999995281,2.26874098972511 +240.0,-2499.9999997423556,86.64339756999419 +241.0,-2499.999985933104,502.26874098972735 +242.0,-2499.9992319758167,1000.0419257966093 +243.0,-2499.9580742034746,1500.000768024097 +244.0,-2497.7312590149927,2000.000014062176 +245.0,-2413.356602687651,2499.999999999999 +246.0,-1997.7312730771698,2999.999985937824 +247.0,-1499.9588422275729,3499.9992319759026 +248.0,-1000.0411577724275,3999.9580742033904 +249.0,-502.2687269228301,4497.731259010274 +250.0,-86.64339730934032,4913.356602259406 +251.0,-2.2676256958850214,4995.274427072589 +252.0,-0.041896931073236374,4996.515657751498 +253.0,-0.0007674922572661384,4996.536280671605 +254.0,-1.4057152880379259e-05,4996.536657664851 +255.0,-2.5746572213263946e-07,4996.536664569479 diff --git a/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.tex new file mode 100644 index 00000000..9d346a6c --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.tex @@ -0,0 +1,102 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1,% + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$S^{\max}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] right:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] below:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] below left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] above:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] below right:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {Load/FlexibleLoad/PmaxU_QU_Simultaneous_Example.csv};% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex new file mode 100644 index 00000000..0051175c --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex @@ -0,0 +1,78 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \begin{axis} + [% + xlabel={Voltages (V)},% + x label style={at={(axis description cs:0.5,-0.15)},anchor=north},% + ylabel={Active power (W)},% + y label style={at={(axis description cs:-0.15,0.5)},anchor=south},% + grid=both,% + legend entries={Effective power,Non-smooth theoretical control},% + legend style={% + legend cell align=left,% + legend pos=north west,% + },% + sharp plot,% + mark size=0.5mm,% + height=9cm,% + width=16cm,% + ytick={-5000,-4000,-3000,-2000,-1000,0},% + extra y ticks={-2500},% + minor tick num=1,% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==240}{% + "\\$\uup$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==250}{% + "\\$\umax$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==-5}{% + "$-\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + extra y tick label={% + \pgfmathifthenelse{\tick==-2500}{% + "$P^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5000}{% + "$-\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathparse{\tick/1000}% + $\pgfmathprintnumber{\pgfmathresult}$ + },% + ] + \addplot+[only marks] table[x=v, y=p, col sep=comma] {Load/FlexibleLoad/PmaxU_Qconst_Example.csv};% + \addplot+ coordinates {(205,-5000) (240,-5000) (250,0) (255,0)};% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Example.csv b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Example.csv new file mode 100644 index 00000000..d4a5f236 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-2500.0,1000.0 +206.0,-2500.0,1000.0 +207.0,-2500.0,1000.0 +208.0,-2500.0,1000.0 +209.0,-2500.0,1000.0 +210.0,-2500.0,1000.0 +211.0,-2500.0,1000.0 +212.0,-2500.0,1000.0 +213.0,-2500.0,1000.0 +214.0,-2500.0,1000.0 +215.0,-2500.0,1000.0 +216.0,-2500.0,1000.0 +217.0,-2500.0,1000.0 +218.0,-2500.0,1000.0 +219.0,-2500.0,1000.0 +220.0,-2500.0,1000.0 +221.0,-2500.0,1000.0 +222.0,-2500.0,1000.0 +223.0,-2500.0,1000.0 +224.0,-2500.0,1000.0 +225.0,-2500.0,1000.0 +226.0,-2500.0,1000.0 +227.0,-2500.0,1000.0 +228.0,-2500.0,1000.0 +229.0,-2500.0,1000.0 +230.0,-2500.0,1000.0 +231.0,-2500.0,1000.0 +232.0,-2500.0,1000.0 +233.0,-2500.0,1000.0 +234.0,-2500.0,1000.0 +235.0,-2500.0,1000.0 +236.0,-2500.0,1000.0 +237.0,-2499.999999999998,1000.0 +238.0,-2499.9999999999136,1000.0 +239.0,-2499.999999995281,1000.0 +240.0,-2499.9999997423556,1000.0 +241.0,-2499.999985933104,1000.0 +242.0,-2499.9992319758167,1000.0 +243.0,-2499.9580742034746,1000.0 +244.0,-2497.7312590149927,1000.0 +245.0,-2413.356602687651,1000.0 +246.0,-1997.7312730771698,1000.0 +247.0,-1499.9588422275729,1000.0 +248.0,-1000.0411577724275,1000.0 +249.0,-502.2687269228301,1000.0 +250.0,-86.64339731234871,1000.0 +251.0,-2.2687409850075113,1000.0 +252.0,-0.04192579652562145,1000.0 +253.0,-0.0007680241834173707,1000.0 +254.0,-1.4066896536490958e-05,1000.0 +255.0,-2.576441837653931e-07,1000.0 diff --git a/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.tex new file mode 100644 index 00000000..e00fbb87 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.tex @@ -0,0 +1,96 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + extra y ticks={1000},% + minor tick num=1,% + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + extra y tick label={% + \pgfmathifthenelse{\tick==1000}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathparse{\tick/1000}% + $\pgfmathprintnumber{\pgfmathresult}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% +% coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] below right:{\mylabel}}},% +% coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] below:\mylabel}},% +% coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% +% coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below left:\mylabel}},% +% coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] below right:\mylabel}},% +% coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] below:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] above:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] above:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] below:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {Load/FlexibleLoad/PmaxU_Qconst_Example.csv};% + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Makefile b/doc/images/Makefile index 382627c3..3a293459 100644 --- a/doc/images/Makefile +++ b/doc/images/Makefile @@ -6,43 +6,42 @@ LUALATEX:=$(shell which lualatex) PDF2SVG:=$(shell which pdf2svg) # Folders +INPUT_FOLDER:=$(shell realpath .) OUTPUT_FOLDER:=$(shell realpath ../_static/) # Files -TEX_FILES:=$(filter-out Preambule.tex, $(wildcard *.tex) $(wildcard **/*.tex)) +TEX_FILES:=$(filter-out Preambule.tex, $(shell find . -name '*.tex' -type f | sed -r 's/^\.\///')) PDF_FILES:=$(TEX_FILES:%.tex=%.pdf) SVG_FILES:=$(TEX_FILES:%.tex=$(OUTPUT_FOLDER)/%.svg) -AUX_FILES:=$(TEX_FILES:%.tex=%.aux) $(wildcard $(OUTPUT_FOLDER)/*.aux) $(wildcard $(OUTPUT_FOLDER)/**/*.aux) -LOG_FILES:=$(TEX_FILES:%.tex=%.log) $(wildcard $(OUTPUT_FOLDER)/*.log) $(wildcard $(OUTPUT_FOLDER)/**/*.log) +AUX_FILES:=$(shell find $(OUTPUT_FOLDER) -name '*.aux' -type f | sed -r 's/^\.\///') +LOG_FILES:=$(shell find $(OUTPUT_FOLDER) -name '*.log' -type f | sed -r 's/^\.\///') # Rules -all: | checks $(SVG_FILES) .PHONY: clean cleanall checks -$(OUTPUT_FOLDER)/Domain_%.svg: Domain_%.tex Domain_Common.tikz Preambule.tex - @$(LUALATEX) --jobname=$(basename $<) --file-line-error --interaction=nonstopmode \ - --shell-escape --output-directory=$(OUTPUT_FOLDER) $< - -$(OUTPUT_FOLDER)/Transformer/Winding%.svg: Transformer/Winding%.tex Transformer/Windings_Common.tikz Preambule.tex - @$(LUALATEX) --jobname=$(basename $<) --file-line-error --interaction=nonstopmode \ - --shell-escape --output-directory=$(OUTPUT_FOLDER) $< +all: | checks $(SVG_FILES) +$(OUTPUT_FOLDER)/Domain_%.svg: $(INPUT_FOLDER)/Load/FlexibleLoad/Domain_%.tex $(INPUT_FOLDER)/Load/FlexibleLoad/Domain_Common.tikz Preambule.tex +$(OUTPUT_FOLDER)/Transformer/Winding%.svg: $(INPUT_FOLDER)/Transformer/Winding%.tex $(INPUT_FOLDER)/Transformer/Windings_Common.tikz Preambule.tex +$(OUTPUT_FOLDER)/Load/FlexibleLoad/%_Control_Curve_Example.svg: $(INPUT_FOLDER)/Load/FlexibleLoad/%_Control_Curve_Example.tex $(INPUT_FOLDER)/Load/FlexibleLoad/%_Example.csv Preambule.tex +$(OUTPUT_FOLDER)/Load/FlexibleLoad/%_Trajectory_Example.svg: $(INPUT_FOLDER)/Load/FlexibleLoad/%_Trajectory_Example.tex $(INPUT_FOLDER)/Load/FlexibleLoad/%_Example.csv Preambule.tex $(OUTPUT_FOLDER)/%.svg: %.tex Preambule.tex @$(LUALATEX) --jobname=$(basename $<) --file-line-error --interaction=nonstopmode \ --shell-escape --output-directory=$(OUTPUT_FOLDER) $< - clean: @rm -f $(AUX_FILES) $(LOG_FILES) $(PDF_FILES) *~ - @$(LATEXMK) -c -output-directory=$(OUTPUT_FOLDER) - @$(LATEXMK) -c + @for dir in $$(find $(INPUT_FOLDER) -type d); do \ + cd $$dir && $(LATEXMK) -c -output-directory=$(OUTPUT_FOLDER) && $(LATEXMK) -c && cd -; \ + done; cleanall: clean @rm -f $(SVG_FILES) - @$(LATEXMK) -C -output-directory=$(OUTPUT_FOLDER) - @$(LATEXMK) -C + @for dir in $$(find $(INPUT_FOLDER) -type d); do \ + cd $$dir && $(LATEXMK) -C -output-directory=$(OUTPUT_FOLDER) && $(LATEXMK) -C && cd -; \ + done; checks: @if [ -z "$(PDF2SVG)" ]; then \ diff --git a/doc/models/Load/FlexibleLoad.md b/doc/models/Load/FlexibleLoad.md deleted file mode 100644 index c25ceaf7..00000000 --- a/doc/models/Load/FlexibleLoad.md +++ /dev/null @@ -1,430 +0,0 @@ -# Flexible loads - -They are a special case of power loads: instead of being constant, the power will depend on the -voltage measured at the load and the control applied to the load. - -## Equations - -The equations are the following (star loads): - -```{math} -\left\{ - \begin{aligned} - \underline{I_{\mathrm{abc}}} &= \left(\frac{ - \underline{S_{\mathrm{abc}}}(\underline{V_{\mathrm{abc}}}-\underline{V_{\mathrm{n}}}) - }{\underline{V_{\mathrm{abc}}}-\underline{V_{\mathrm{n}}}}\right)^{\star} \\ - \underline{I_{\mathrm{n}}} &= -\sum_{p\in\{\mathrm{a},\mathrm{b},\mathrm{c}\}}\underline{I_{p}} - \end{aligned} -\right. -``` - -And the following (delta loads): - -```{math} -\left\{ - \begin{aligned} - \underline{I_{\mathrm{ab}}} &= \left(\frac{\underline{S_{\mathrm{ab}}}(\underline{V_{\mathrm{a}}}-\underline - {V_{\mathrm{b}}})}{\underline{V_{\mathrm{a}}}-\underline{V_{\mathrm{b}}}}\right)^{\star} \\ - \underline{I_{\mathrm{bc}}} &= \left(\frac{\underline{S_{\mathrm{bc}}}(\underline{V_{\mathrm{b}}}-\underline - {V_{\mathrm{c}}})}{\underline{V_{\mathrm{b}}}-\underline{V_{\mathrm{c}}}}\right)^{\star} \\ - \underline{I_{\mathrm{ca}}} &= \left(\frac{\underline{S_{\mathrm{ca}}}(\underline{V_{\mathrm{c}}}-\underline - {V_{\mathrm{a}}})}{\underline{V_{\mathrm{c}}}-\underline{V_{\mathrm{a}}}}\right)^{\star} - \end{aligned} -\right. -``` - -The expression $\underline{S}(U)$ depends on four parameters: - -- The theoretical power $\underline{S^{\mathrm{th.}}}$ that the load would have if no control is applied. -- The maximal power $S^{\max}$ that can be injected/consumed by the load. For a PV installation, this is - usually the rated power of the inverter. -- The type of control (see below). -- The type of projection (see below). - -(models-flexible_load-controls)= - -## Controls - -There are four available types of control. - -### Constant control - -No control is applied, this is equivalent to a classical power load. The constant control can be -built like this: - -```python -from roseau.load_flow import Control - -# Use the constructor. Note that the voltages are not important in this case. -control = Control(type="constant", u_min=0.0, u_down=0.0, u_up=0.0, u_max=0.0) - -# Or prefer using the shortcut -control = Control.constant() -``` - -(models-flexible_load-p_u_control)= - -### P(U) control - -Control the maximum active power of a load (often a PV inverter) based on the voltage $P^{\max}(U)$. - -```{note} -The functions $s_{\alpha}$ used for the P(U) controls are derived from the *soft clipping function* of -{cite:p}`Klimek_2020`. -``` - -#### Production - -With this control, the following soft clipping family of functions $s_{\alpha}(U)$ is used. The -default value of `alpha` is 1000. - -```{image} /_static/Control_PU_Prod.svg -:alt: P(U) production control -:width: 600 -:align: center -``` - -The final $P$ is then $P(U) = \max(s_{\alpha}(U) \times S^{\max}, P^{\mathrm{th.}})$ - -```python -from roseau.load_flow import Control, Q_ - -# Use the constructor. Note that u_min and u_down are useless with the production control -production_control = Control( - type="p_max_u_production", u_min=0, u_down=0, u_up=Q_(240, "V"), u_max=Q_(250, "V") -) - -# Or prefer the shortcut -production_control = Control.p_max_u_production(u_up=Q_(240, "V"), u_max=Q_(250, "V")) -``` - -#### Consumption - -With this control, the following soft clipping family of functions $s_{\alpha}(U)$ is used. The -default value of `alpha` is 1000. - -```{image} /_static/Control_PU_Cons.svg -:alt: P(U) consumption control -:width: 600 -:align: center -``` - -The final $P$ is then $P(U) = \min(s_{\alpha}(U) \times S^{\max}, P^{\mathrm{th.}})$ - -```python -from roseau.load_flow import Control, Q_ - -# Use the constructor. Note that u_max and u_up are useless with the consumption control -consumption_control = Control( - type="p_max_u_consumption", u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=0, u_max=0 -) - -# Or prefer the shortcut -consumption_control = Control.p_max_u_consumption(u_min=Q_(210, "V"), u_down=Q_(220, "V")) -``` - -(models-flexible_load-q_u_control)= - -### Q(U) control - -Control the reactive power based on the voltage $Q(U)$. With this control, the following soft -clipping family of functions $s_{\alpha}(U)$ is used. The default value of `alpha` is 1000. - -```{image} /_static/Control_QU.svg -:alt: Q(U) control -:width: 600 -:align: center -``` - -The final $Q$ is then $Q(U) = s_{\alpha}(U) \times S^{\max}$ - -```{note} -The function $s_{\alpha}$ used for the Q(U) control is derived from the *soft clipping function* of -{cite:p}`Klimek_2020`. -``` - -```python -from roseau.load_flow import Control, Q_ - -# Use the constructor. Note that all the voltages are important. -control = Control( - type="q_u", - u_min=Q_(210, "V"), - u_down=Q_(220, "V"), - u_up=Q_(240, "V"), - u_max=Q_(250, "V"), -) - -# Or prefer the shortcut -control = Control.q_u( - u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") -) -``` - -(models-flexible_load-projection)= - -## Projection - -The different controls may produce values for $P$ and $Q$ that are not feasible. The feasibility -domain in the $(P, Q)$ space is a part of the circle of radius $S^{\max}$. In these cases, the -solution found by the control algorithm has to be projected on the feasible domain. That's why we -need to define how the projection is done. There are three available projection types: the -_Euclidean_ projection, the projection at _Constant $P$_ and the projection at _Constant $Q$_. - -The projection accepts two approximation parameters: `alpha` and `epsilon`. - -- `alpha` is used to compute soft sign function and soft projection function. The higher `alpha` - is, the better the approximations are. -- `epsilon` is used to approximate a smooth square root function: - ```{math} - \sqrt{S} = \sqrt{\varepsilon \times \exp\left(\frac{-{|S|}^2}{\varepsilon}\right) + {|S|}^2} - ``` - The lower `epsilon` is, the better the approximations are. - -### Euclidean projection - -A Euclidean projection on the feasible domain. This is the default value for projections when it is -not specified. - -```{image} /_static/Euclidean_Projection.svg -:width: 300 -:align: center -``` - -```python -from roseau.load_flow import Projection - -projection = Projection(type="euclidean") # alpha and epsilon can be provided -``` - -### Constant $P$ - -Keep the value of $P$ computed by the control and project $Q$ on the feasible domain. - -```{image} /_static/Constant_P_Projection.svg -:width: 300 -:align: center -``` - -```python -from roseau.load_flow import Projection - -projection = Projection(type="keep_p") # alpha and epsilon can be provided -``` - -### Constant $Q$ - -Keep the value of $Q$ computed by the control and project $P$ on the feasible domain. - -```{image} /_static/Constant_Q_Projection.svg -:width: 300 -:align: center -``` - -```python -from roseau.load_flow import Projection - -projection = Projection(type="keep_q") # alpha and epsilon can be provided -``` - -(models-flexible_load-flexible_parameters)= - -## Flexible parameters - -A flexible parameter is a combination of a control on the active power, a control on the reactive -power, a projection and a maximal apparent power for one phase. - -### Example - -Here, we define a flexible parameter with: - -- a constant control on $P$ (meaning, no control), -- a control $Q(U)$ on $Q$, -- a projection which keeps $P$ constant, -- an $S^{\max}$ of 5 kVA. - -```python -from roseau.load_flow import FlexibleParameter, Control, Projection, Q_ - -fp = FlexibleParameter( - control_p=Control.constant(), - control_q=Control.q_u( - u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") - ), - projection=Projection(type="keep_p"), - s_max=Q_(5, "kVA"), -) -``` - -### Usage - -To create a flexible load, create a `PowerLoad` passing it a list of `FlexibleParameter` objects -using the `flexible_params` parameter, one for each phase of the load. - -#### Scenario 1: Same $Q(U)$ control on all phases - -In this scenario, we apply the same $Q(U)$ control on the three phases of a load. We define a -flexible parameter with constant $P$ control and use it three times in the load constructor. - -```python -import numpy as np - -from roseau.load_flow import FlexibleParameter, Control, Projection, Q_, PowerLoad, Bus - -bus = Bus(id="bus", phases="abcn") - -# Create a flexible parameter object -fp = FlexibleParameter( - control_p=Control.constant(), - control_q=Control.q_u( - u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") - ), - projection=Projection(type="keep_p"), - s_max=Q_(5, "kVA"), -) - -# Use it for the three phases of the load -load = PowerLoad( - id="load", - bus=bus, - powers=Q_(np.array([1000, 1000, 1000]) * (1 - 0.3j), "VA"), - flexible_params=[fp, fp, fp], # <- this makes the load "flexible" -) -``` - -The created load is a three-phase star-connected load as the phases inherited from the bus include -`"n"`. The `powers` parameter of the `PowerLoad` constructor represents the theoretical powers of -the three phases of the load. The load is flexible on its three phases with the same flexible -parameters. - -#### Scenario 2: Different controls on different phases - -In this scenario, we create a load with only two phases and a neutral connected to a three-phase -bus with a neutral. Two different controls are applied by the load on the two phases. - -```python -import numpy as np - -from roseau.load_flow import FlexibleParameter, Control, Projection, Q_, PowerLoad, Bus - -bus = Bus(id="bus", phases="abcn") - -# Create a first flexible parameter (Q(U) control) -fp1 = FlexibleParameter( - control_p=Control.constant(), - control_q=Control.q_u( - u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") - ), - projection=Projection(type="keep_p"), - s_max=Q_(5, "kVA"), -) - -# Create a second flexible parameter (P(U) control) -fp2 = FlexibleParameter( - control_p=Control.p_max_u_consumption(u_min=Q_(210, "V"), u_down=Q_(220, "V")), - control_q=Control.constant(), - projection=Projection(type="euclidean"), - s_max=Q_(3, "kVA"), -) - -# Use them in a load -load = PowerLoad( - id="load", - bus=bus, - phases="abn", - powers=Q_(np.array([1000, 1000]) * (1 - 0.3j), "VA"), - flexible_params=[fp1, fp2], -) -``` - -The first element of the load is connected between phase "a" and "n" of the bus. Its control is a -$Q(U)$ control with a projection at constant $P$ and an $S^{\max}$ of 5 kVA. - -The second element of the load is connected between phase "b" and "n" of the bus. Its control is a -$P(U)$ control with an Euclidean projection and an $S^{\max}$ of 3 kVA. - -#### Scenario 3: PQ(U) control - -Finally, it is possible to combine $P(U)$ and $Q(U)$ controls, for example by first using all -available reactive power before reducing the active power in order to limit the impact for the -client. - -```python -import numpy as np - -from roseau.load_flow import FlexibleParameter, Control, Projection, Q_, PowerLoad, Bus - -bus = Bus(id="bus", phases="abc") - -# Create a flexible parameter -fp = FlexibleParameter( - control_p=Control.p_max_u_production(u_up=Q_(245, "V"), u_max=Q_(250, "V")), - control_q=Control.q_u( - u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(245, "V") - ), - projection=Projection(type="euclidean"), - s_max=Q_(5, "kVA"), -) - -# Or using the shortcut -fp = FlexibleParameter.pq_u_production( - up_up=Q_(245, "V"), - up_max=Q_(250, "V"), - uq_min=Q_(210, "V"), - uq_down=Q_(220, "V"), - uq_up=Q_(240, "V"), - uq_max=Q_(245, "V"), - s_max=Q_(5, "kVA"), -) - -# Use it in a load -load = PowerLoad( - id="load", - bus=bus, - powers=Q_(-np.array([1000, 1000, 1000]), "VA"), - flexible_params=[fp, fp, fp], -) -``` - -In this example, the same flexible parameter is used to control all phases of the three-phase -delta-connected load. In the flexible parameter, one can remark that the $Q(U)$ control on high -voltages triggers at 240 V (production) and reaches its maximum at 245 V. The $P(U)$ control -however triggers at 245 V and is maxed out at 250 V. - -Using this configuration, a _sequential PQ(U) control_ has been created for this load. A -_simultaneous PQ(U) control_ could have been defined by using the same voltage thresholds for both -controls. - -## Feasible domains - -Depending on the mix of controls and projection used through this class, the feasible domains in -the $(P, Q)$ space changes. Here is an illustration with a theoretical production power -($P^{\mathrm{th.}} < 0$). - -```{list-table} -:class: borderless -:header-rows: 1 -:widths: 20 20 20 20 20 - -* - - - $Q^{\mathrm{const.}}$ - - $Q(U)$ with an Euclidean projection - - $Q(U)$ with a constant P projection - - $Q(U)$ with a constant Q projection -* - $P^{\mathrm{const.}}$ - - ![image](/_static/Domain_Pconst_Qconst.svg) - - ![image](/_static/Domain_Pconst_QU_Eucl.svg) - - ![image](/_static/Domain_Pconst_QU_P.svg) - - ![image](/_static/Domain_Pconst_QU_Q.svg) -* - $P^{\max}(U)$ - - ![image](/_static/Domain_PmaxU_Qconst.svg) - - ![image](/_static/Domain_PmaxU_QU.svg) - - ![image](/_static/Domain_PmaxU_QU.svg) - - ![image](/_static/Domain_PmaxU_QU.svg) -``` - -## Bibliography - -```{bibliography} -:filter: docname in docnames -``` diff --git a/doc/models/Load/FlexibleLoad/Control.md b/doc/models/Load/FlexibleLoad/Control.md new file mode 100644 index 00000000..e8d2d99d --- /dev/null +++ b/doc/models/Load/FlexibleLoad/Control.md @@ -0,0 +1,131 @@ +(models-flexible_load-controls)= + +# Controls + +There are four available types of control. + +## Constant control + +No control is applied, this is equivalent to a classical power load. The constant control can be +built like this: + +```python +from roseau.load_flow import Control + +# Use the constructor. Note that the voltages are not important in this case. +control = Control(type="constant", u_min=0.0, u_down=0.0, u_up=0.0, u_max=0.0) + +# Or prefer using the shortcut +control = Control.constant() +``` + +(models-flexible_load-p_u_control)= + +## $P(U)$ control + +Control the maximum active power of a load (often a PV inverter) based on the voltage $P^{\max}(U)$. + +```{note} +The functions $s_{\alpha}$ used for the $P(U)$ controls are derived from the *soft clipping function* of +{cite:p}`Klimek_2020`. +``` + +### Production + +With this control, the following soft clipping family of functions $s_{\alpha}(U)$ is used. The default value of +`alpha` is 1000. + +```{image} /_static/Load/FlexibleLoad/Control_PU_Prod.svg +:alt: P(U) production control +:width: 600 +:align: center +``` + +The final $P$ is then $P(U) = \max(s_{\alpha}(U) \times S^{\max}, P^{\mathrm{th.}})$. Note that this final +$\underline{S(U)}$ point may lie outside the disc of radius $S^{\max}$ in the $(P, Q)$ plane. See the +[Projection page](models-flexible_load-projections) for more details about this case. + +```python +from roseau.load_flow import Control, Q_ + +# Use the constructor. Note that u_min and u_down are useless with the production control +production_control = Control( + type="p_max_u_production", u_min=0, u_down=0, u_up=Q_(240, "V"), u_max=Q_(250, "V") +) + +# Or prefer the shortcut +production_control = Control.p_max_u_production(u_up=Q_(240, "V"), u_max=Q_(250, "V")) +``` + +### Consumption + +With this control, the following soft clipping family of functions $s_{\alpha}(U)$ is used. The default value of +`alpha` is 1000. + +```{image} /_static/Load/FlexibleLoad/Control_PU_Cons.svg +:alt: P(U) consumption control +:width: 600 +:align: center +``` + +The final $P$ is then $P(U) = \min(s_{\alpha}(U) \times S^{\max}, P^{\mathrm{th.}})$. Note that this final +$\underline{S(U)}$ point may lie outside the disc of radius $S^{\max}$ in the $(P, Q)$ plane. See the +[Projection page](models-flexible_load-projections) for more details about this case. + +```python +from roseau.load_flow import Control, Q_ + +# Use the constructor. Note that u_max and u_up are useless with the consumption control +consumption_control = Control( + type="p_max_u_consumption", u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=0, u_max=0 +) + +# Or prefer the shortcut +consumption_control = Control.p_max_u_consumption(u_min=Q_(210, "V"), u_down=Q_(220, "V")) +``` + +(models-flexible_load-q_u_control)= + +## $Q(U)$ control + +Control the reactive power based on the voltage $Q(U)$. With this control, the following soft clipping family of +functions $s_{\alpha}(U)$ is used. The default value of `alpha` is 1000. + +```{image} /_static/Load/FlexibleLoad/Control_QU.svg +:alt: Q(U) control +:width: 600 +:align: center +``` + +The final $Q$ is then $Q(U) = s_{\alpha}(U) \times S^{\max}$. Note that this final $\underline{S(U)}$ point +may lie outside the disc of radius $S^{\max}$ in the $(P, Q)$ plane. See the +[Projection page](models-flexible_load-projections) for more details about this case. + +```{note} +The function $s_{\alpha}$ used for the $Q(U)$ control is derived from the *soft clipping function* of +{cite:p}`Klimek_2020`. +``` + +```python +from roseau.load_flow import Control, Q_ + +# Use the constructor. Note that all the voltages are important. +control = Control( + type="q_u", + u_min=Q_(210, "V"), + u_down=Q_(220, "V"), + u_up=Q_(240, "V"), + u_max=Q_(250, "V"), +) + +# Or prefer the shortcut +control = Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") +) +``` + +## Bibliography + +```{bibliography} +:filter: docname in docnames +``` diff --git a/doc/models/Load/FlexibleLoad/FeasibleDomain.md b/doc/models/Load/FlexibleLoad/FeasibleDomain.md new file mode 100644 index 00000000..dc612498 --- /dev/null +++ b/doc/models/Load/FlexibleLoad/FeasibleDomain.md @@ -0,0 +1,828 @@ +(models-flexible_load-feasible_domains)= + +# Feasible domains + +Depending on the mix of controls and projection used through the class `FlexibleParameter`, the feasible domains in +the $(P, Q)$ space changes. + +```{note} +On this page, all the images are drawn for a producer so $P^{\text{th.}}\leqslant0$. +``` + +## Everything constant + +If there is no control at all, i.e. the `flexible_params` argument is **not** given to the `PowerLoad` constructor or +`constant` control used for both active and reactive powers, the consumed (or produced) power will be the one +provided by the user, noted $\underline{S^{\mathrm{th.}}}=P^{\mathrm{th.}}+jQ^{\mathrm{th.}}$. The feasible domain +is reduced to a single point as depicted in the figure below. + +```{image} /_static/Load/FlexibleLoad/Domain_Pconst_Qconst.svg +:width: 300 +:align: center +``` + +Here is a small example of usage of the constant control for active and reactive powers. + +```python +import numpy as np + +from roseau.load_flow import ( + PowerLoad, + Bus, + Q_, + FlexibleParameter, + Control, + Projection, + VoltageSource, + ElectricalNetwork, + PotentialRef, +) + +# A voltage source +bus = Bus(id="bus", phases="abcn") +un = 400 / np.sqrt(3) +voltages = Q_(un * np.exp([0, -2j * np.pi / 3, 2j * np.pi / 3]), "V") +vs = VoltageSource(id="source", bus=bus, voltages=voltages) + +# A potential ref +pref = PotentialRef("pref", element=bus, phase="n") + +# No flexible params +load = PowerLoad( + id="load", + bus=bus, + powers=Q_(np.array([1000, 1000, 1000]), "VA"), +) + +# Build a network and solve a load flow +en = ElectricalNetwork.from_element(bus) +auth = ("username", "password") +en.solve_load_flow(auth=auth) + +# The voltage source provided 1 kVA per phase for the load +vs.res_powers +# array( +# [-1000.-0.00000000e+00j, -1000.+1.93045819e-14j, -1000.-1.93045819e-14j, 0.+0.00000000e+00j] +# ) + +# Disconnect the load +load.disconnect() + +# Constant flexible params +# The projection is useless as there are only constant controls +# The s_max is useless as there are only constant controls +fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.constant(), + projection=Projection(type="euclidean"), + s_max=Q_(5, "kVA"), +) + +# For each phase, the provided `powers` are lower than 5 kVA. +load = PowerLoad( + id="load", + bus=bus, + powers=Q_(np.array([1000, 1000, 1000]), "VA"), + flexible_params=[fp, fp, fp], +) +en.solve_load_flow(auth=auth) + +# Again the voltage source provided 1 kVA per phase +vs.res_powers +# array( +# [-1000.-0.00000000e+00j, -1000.+1.93045819e-14j, -1000.-1.93045819e-14j, 0.+0.00000000e+00j] +# ) + +# Disconnect the load +load.disconnect() + +# For some phases, the provided `powers` are greater than 5 kVA. The projection is still useless. +load = PowerLoad( + id="load", + bus=bus, + powers=Q_(np.array([6, 4.5, 6]), "kVA"), # Above 5 kVA -> also OK! + flexible_params=[fp, fp, fp], +) +en.solve_load_flow(auth=auth) + +# The load provides exactly the power consumed by the load even if it is greater than s_max +vs.res_powers +# array( +# [-6000.-0.00000000e+00j, -4500.-3.01980663e-14j, -6000.-2.18385501e-13j, 0.+0.00000000e+00j] +# ) +``` + +## Active power control only + +When the reactive power is constant, only the active power may be modulated by the local voltage. Thus, the active +power may vary between 0 and $P^{\mathrm{th.}}$ (if the load is a consumer i.e. $P^{\mathrm{th.}}\geqslant 0$) or +between $P^{\mathrm{th.}}$ and 0 (if the load is a producer i.e. $P^{\mathrm{th.}}\leqslant0$). + +When a control is activated for a load, the theoretical power can not be outside the disc of radius $S^{\max}$. Here +is a small example of such error: + +```python +import numpy as np + +from roseau.load_flow import PowerLoad, Bus, Q_, FlexibleParameter, Control, Projection + +bus = Bus(id="bus", phases="an") + +# Flexible load +fp = FlexibleParameter( + control_p=Control.p_max_u_production(u_up=Q_(240, "V"), u_max=Q_(250, "V")), + control_q=Control.constant(), + projection=Projection(type="keep_p"), + s_max=Q_(5, "kVA"), +) + +# Raises an error! +load = PowerLoad( + id="load", + bus=bus, + powers=Q_( + np.array([-5 + 5j], dtype=complex), "kVA" + ), # Point outside the circle of radius s_max + flexible_params=[fp], +) +# RoseauLoadFlowException: The power is greater than the parameter s_max +# for flexible load "load" [bad_s_value] +``` + +Thus, the given $\underline{S^{\text{th.}}}=P^{\text{th.}}+jQ^{\text{th.}}$ lies in the disk of radius $S^{\max}$. +The resulting flexible power is the minimum absolute value between, on the one hand, the active power control function +(which takes values between 0 and 1) multiplied by $S^{\max}$ and, on the other hand, $P^{\mathrm{th.}}$. +As a consequence, the resulting power lies in the segment between the points $(0, Q^{\text{th.}})$ and +$(P^{\text{th.}}, Q^{\text{th.}})$. + +```{important} +The projection is useless when there is only an active power control as no point can lie outside the disc of radius +$S^{\max}$. +``` + +This domain of feasible points is depicted in the figure below: + +```{image} /_static/Load/FlexibleLoad/Domain_PmaxU_Qconst.svg +:width: 300 +:align: center +``` + +In the `FlexibleParameter` class, there is a method `compute_powers` which allows to compute the resulting voltages +powers + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + +# A flexible parameter +fp = FlexibleParameter( + control_p=Control.p_max_u_production(u_up=Q_(240, "V"), u_max=Q_(250, "V")), + control_q=Control.constant(), + projection=Projection(type="keep_p"), # <----- No consequence + s_max=Q_(5, "kVA"), +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.array(range(205, 256, 1), dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5 + 1j, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +Plotting the control curve $P(U)$ using the variables `voltages` and `res_flexible_powers` of the script above leads to +the following plot: + +```{image} /_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg +:width: 700 +:align: center +``` + +The non-smooth theoretical control function is the control function applied to $S^{\max}$. The effective power has been +plotted using the powers really produced by the load. Below 240 V, there is no variation in the produced power which is +expected. Between 240 V and approximately 245 V, there is no reduction of the produced power because the curtailment +factor (computed from the voltage) times $S^{\max}$ is lower than $P^{\mathrm{th.}}$. As a consequence, +$P^{\mathrm{th.}}$ is produced. Starting at approximately 245 V, the comparison changes and the really produced +power starts to decrease. It reaches 0 W above 250 V. + +The same plot can be obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax, res_flexible_powers = fp.plot_control_p( + auth=auth, voltages=voltages, power=power, res_flexible_powers=res_flexible_powers +) +plt.show() +``` + +In the above example, `res_flexible_powers` is provided as input. It could have been forgotten, and the flexible +powers would have been computed by requesting the server. The computed values are retrieved with the axis on which +the plot was drawn. + +`````{tip} +To install matplotlib along side with roseau-load-flow, you can type + +````{tab} Linux +```console +$ python -m pip install roseau-load-flow[plot] +``` +```` + +````{tab} Windows +Matplotlib is always installed when `conda` is used. +```` + +````` + +If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: + +```{image} /_static/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.svg +:width: 700 +:align: center +``` + +All the points have been plotted (1 per volt between 205 V and 255 V). A lot of points are overlapping. + +The same plot could have been obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [240, 250]), + ax=ax, +) +plt.show() +``` + +## Reactive power control only + +When the active power is constant, only the reactive power may be modulated by the local voltage. Thus, the reactive +power may vary between $-S^{\max}$ and $+S^{\max}$. In this segment, there are points outside the disc of radius +$S^{\max}$ (when $P^{\mathrm{th.}}\neq 0$). Those points are projected on the circle of radius $S^{\max}$ and +depending on the projection, the feasible domains change. + +### Constant $P$ + +If the _constant $P$_ (`keep_p`) projection is chosen, the feasible domain is limited to a segment as defined below. + +```{image} /_static/Load/FlexibleLoad/Domain_Pconst_QU_P.svg +:width: 300 +:align: center +``` + +Here is an example of a reactive power control (without active power control) flexible parameter creation: + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + +# Flexible parameter +fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") + ), + projection=Projection(type="keep_p"), # <---- Keep P + s_max=Q_(5, "kVA"), +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.array(range(205, 256, 1), dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +At the end of the script, the variable `res_flexible_powers` contains the powers that has been really produced by +the flexible load for the voltages stored in the variable named `voltages`. + +Plotting the control curve $Q(U)$ lead to the following plot: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg +:width: 700 +:align: center +``` + +One can remark that, even with a voltage lower than $U^{\min}$ or greater than $U^{\max}$ the available reactive +power (by default taken in the interval $[-S^{\max}, S^{\max}]$) was never totally used because of the choice of the +projection. + +The same plot can be obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_control_q( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + ax=ax, +) +plt.show() +``` + +If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.svg +:width: 700 +:align: center +``` + +As in the previous plot, there is one point per volt from 205 V to 255 V. Several remarks on this plot: + +1. All the points are aligned on the straight line $P=-2.5$ kVA because it was the power provided to the flexible + load and because the projection used was at _Constant P_. +2. One can remark that several points are overlapping for low and high voltages. For these extremities, the + theoretical control curves would have forced the point of operation to be outside the disc of radius $S^{\max}$ (5 + kVA in the example). + +The same plot could have been obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + +### Constant $Q$ + +If the _constant $Q$_ (`keep_q`) projection is chosen, the feasible domain is limited to a segment with two arcs as +defined below. + +```{image} /_static/Load/FlexibleLoad/Domain_Pconst_QU_Q.svg +:width: 300 +:align: center +``` + +```{warning} +Note that using this projection with a constant active power may result in a final active power lower than the one +provided (even 0 W in the worst cases)! +``` + +Here is an example the creattion of such control with a constant $Q$ projection: + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + +# Flexible parameter +fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") + ), + projection=Projection(type="keep_q"), # <---- Keep Q + s_max=Q_(5, "kVA"), +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.array(range(205, 256, 1), dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +At the end of the script, the variable `res_flexible_powers` contains the powers that has been really produced by +the flexible load for the voltages stored in the variable named `voltages`. + +Plotting the control curve $Q(U)$ leads to the following plot: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg +:width: 700 +:align: center +``` + +Here, the complete possible range of reactive power was used. Nevertheless, it was achieved with some active power +reduction because of the projection. + +The same plot can be obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_control_q( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + ax=ax, +) +plt.show() +``` + +If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.svg +:width: 700 +:align: center +``` + +The same plot could have been obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + +One can remark that when the voltages were too low or too high, the projection at constant $Q$ forces us to reduce +the produced active power to ensure a feasible point i.e. a point which is in the disc of radius $S^{\max}$. As +before, there is one point per volt. Several points of operation are overlapping near the coordinates (0,5 kVA) and +(0, -5 kVA). + +### Euclidean projection + +If the _Euclidean_ (`euclidean`) projection is chosen, the feasible domain is limited to a segment with two +small arcs as defined below. + +```{image} /_static/Load/FlexibleLoad/Domain_Pconst_QU_Eucl.svg +:width: 300 +:align: center +``` + +```{warning} +Note that using this projection with a constant active power may result in a final active power lower than the one +provided! +``` + +Here is an example of this usage with a single phase network limited to a single bus: + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + +# Flexible parameter +fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") + ), + projection=Projection(type="euclidean"), # <---- Euclidean + s_max=Q_(5, "kVA"), +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.array(range(205, 256, 1), dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +At the end of the script, the variable `res_flexible_powers` contains the powers that has been really produced by +the flexible load for the voltages stored in the variable named `voltages`. + +Plotting the control curve $Q(U)$ lead to the following plot: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg +:width: 700 +:align: center +``` + +Here, again the complete reactive power range is not fully used. + +The same plot can be obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_control_q( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + ax=ax, +) +plt.show() +``` + +If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.svg +:width: 700 +:align: center +``` + +The same plot could have been obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + +One can remark that when the voltages were too low or too high, the Euclidean projection forces us to +reduce the produced active power and the (produced and consumed) reactive power to ensure a feasible point i.e. a point +which is in the disc of radius $S^{\max}$. As before, there is one point per volt thus one can remark that several +points of operation are overlapping. + +## Both active and reactive powers control + +When both active and reactive powers are activated, the feasible domains is the following: + +```{image} /_static/Load/FlexibleLoad/Domain_PmaxU_QU.svg +:width: 300 +:align: center +``` + +Every point whose abscissa is between $P^{\mathrm{th.}}$ and 0, whose ordinate is between $-S^{\max}$ and $+S^{\max}$ +and which lies in the disc of radius $S^{\max}$ is reachable. Let's look at two examples: in the first one, the +controls are activated sequentially (reactive power first and then active power) and, in the other example, there +are used together. + +### Sequentially activated controls + +Let's play with the voltage thresholds of the control in order to fully activate a first control and then starts to +activate the second. + +#### Reactive power control first + +In this section, the reactive power control is activated at 230 V and fully used above 240 V. Then, at 245 V, the +active control power starts and is fully activated at 250 V. + +In the following script such control is used on a network with a single-phase load connected to a single bus: + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + +# Flexible parameter +fp = FlexibleParameter( + control_p=Control.p_max_u_production(u_up=Q_(245, "V"), u_max=Q_(250, "V")), # <---- + control_q=Control.q_u( + u_min=Q_(210, "V"), + u_down=Q_(220, "V"), + u_up=Q_(230, "V"), # <---- + u_max=Q_(240, "V"), # <---- + ), + projection=Projection(type="euclidean"), # <---- Euclidean + s_max=Q_(5, "kVA"), +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.array(range(205, 256, 1), dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +If we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: + +```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.svg +:width: 700 +:align: center +``` + +The same plot could have been obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + +When the voltage is low, there is only a reactive power control which is activated. Thus, everything works as +depicted in the previous dedicated section and the choice of the projection may change the operation points for the +lowest voltages. + +When the voltage is high, there are two phases: + +1. Between 230 V and 240 V, only the reactive power decreases to reach the symmetrical point (with respect to the + x-axis) of the 205 V operation point. +2. Between 245 V and 250 V, the active power control reduces the active power to reach 0 W above 250 V. + +#### Active power control first + +In this section, the active power control is activated at 240 V and fully used above 245 V. Then, at 245 V, the +reactive control power starts and is fully activated at 250 V. + +In the following script such control is used on a network with a single-phase load connected to a single bus: + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + + +# Flexible parameter +fp = FlexibleParameter( + control_p=Control.p_max_u_production(u_up=Q_(230, "V"), u_max=Q_(240, "V")), # <---- + control_q=Control.q_u( + u_min=Q_(210, "V"), + u_down=Q_(220, "V"), + u_up=Q_(245, "V"), # <---- + u_max=Q_(250, "V"), # <---- + ), + projection=Projection(type="euclidean"), # <---- Euclidean + s_max=Q_(5, "kVA"), +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.array(range(205, 256, 1), dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +If we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: + +```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.svg +:width: 700 +:align: center +``` + +The same plot could have been obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + +When the voltage is low, there is only a reactive power control which is activated. Thus, everything works as +depicted in the previous dedicated section and the choice of the projection may change the operation points for the +lowest voltages. + +When the voltage is high, there are two phases: + +1. Between 230 V and 240 V, only the active power decreases to reach a production of nearly 0 W. +2. Between 245 V and 250 V, the reactive power control increased the consumed the reactive power at 250 V. + +### Simultaneously activated controls + +In this second subsection, the active and the reactive powers controls are activated at 240 V and reach their full +effect at 250 V. + +Here is a small single phase network limited to a single bus to model the behaviour of the flexible load: + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + +# Flexible parameter +fp = FlexibleParameter( + control_p=Control.p_max_u_production(u_up=Q_(240, "V"), u_max=Q_(250, "V")), # <---- + control_q=Control.q_u( + u_min=Q_(210, "V"), + u_down=Q_(220, "V"), + u_up=Q_(240, "V"), # <---- + u_max=Q_(250, "V"), # <---- + ), + projection=Projection(type="euclidean"), # <---- Euclidean + s_max=Q_(5, "kVA"), +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.array(range(205, 256, 1), dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +If we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: + +```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.svg +:width: 700 +:align: center +``` + +The same plot could have been obtained using the following command: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + +When the voltage is low, there is only a reactive power control which is activated. Thus, everything works as +depicted in the previous dedicated section and the choice of the projection may change the operation points for the +lowest voltages. + +When the voltage is high, there are two phases: + +1. Between 240 V and 245 V, the active power control doesn't modify the value of the produced active power while the + reactive power control starts to increase the consumed reactive power. +2. Between 245 V and 250 V, the active power control starts to have effects on the produced active power. The + consumed reactive power continues to increase. +3. Above 250 V, no active power is produced. + +If now, the theoretical power is changed to 4 kVA of production. + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=Q_(-4, "kVA"), # <------ New power + # res_flexible_powers=res_flexible_powers, # Must be computed again! + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + +The following result is obtained: + +```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.svg +:width: 700 +:align: center +``` diff --git a/doc/models/Load/FlexibleLoad/FlexibleParameter.md b/doc/models/Load/FlexibleLoad/FlexibleParameter.md new file mode 100644 index 00000000..be3c5c3c --- /dev/null +++ b/doc/models/Load/FlexibleLoad/FlexibleParameter.md @@ -0,0 +1,167 @@ +(models-flexible_load-flexible_parameters)= + +# Flexible parameters + +A flexible parameter is a combination of a control on the active power, a control on the reactive +power, a projection and a maximal apparent power for one phase. + +## Example + +Here, we define a flexible parameter with: + +- a constant control on $P$ (meaning, no control), +- a control $Q(U)$ on $Q$, +- a projection which keeps $P$ constant, +- an $S^{\max}$ of 5 kVA. + +```python +from roseau.load_flow import FlexibleParameter, Control, Projection, Q_ + +fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") + ), + projection=Projection(type="keep_p"), + s_max=Q_(5, "kVA"), +) +``` + +## Usage + +To create a flexible load, create a `PowerLoad` passing it a list of `FlexibleParameter` objects +using the `flexible_params` parameter, one for each phase of the load. + +### Scenario 1: Same $Q(U)$ control on all phases + +In this scenario, we apply the same $Q(U)$ control on the three phases of a load. We define a +flexible parameter with constant $P$ control and use it three times in the load constructor. + +```python +import numpy as np + +from roseau.load_flow import FlexibleParameter, Control, Projection, Q_, PowerLoad, Bus + +bus = Bus(id="bus", phases="abcn") + +# Create a flexible parameter object +fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") + ), + projection=Projection(type="keep_p"), + s_max=Q_(5, "kVA"), +) + +# Use it for the three phases of the load +load = PowerLoad( + id="load", + bus=bus, + powers=Q_(np.array([1000, 1000, 1000]) * (1 - 0.3j), "VA"), + flexible_params=[fp, fp, fp], # <- this makes the load "flexible" +) +``` + +The created load is a three-phase star-connected load as the phases inherited from the bus include +`"n"`. The `powers` parameter of the `PowerLoad` constructor represents the theoretical powers of +the three phases of the load. The load is flexible on its three phases with the same flexible +parameters. + +### Scenario 2: Different controls on different phases + +In this scenario, we create a load with only two phases and a neutral connected to a three-phase +bus with a neutral. Two different controls are applied by the load on the two phases. + +```python +import numpy as np + +from roseau.load_flow import FlexibleParameter, Control, Projection, Q_, PowerLoad, Bus + +bus = Bus(id="bus", phases="abcn") + +# Create a first flexible parameter (Q(U) control) +fp1 = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") + ), + projection=Projection(type="keep_p"), + s_max=Q_(5, "kVA"), +) + +# Create a second flexible parameter (P(U) control) +fp2 = FlexibleParameter( + control_p=Control.p_max_u_consumption(u_min=Q_(210, "V"), u_down=Q_(220, "V")), + control_q=Control.constant(), + projection=Projection(type="euclidean"), + s_max=Q_(3, "kVA"), +) + +# Use them in a load +load = PowerLoad( + id="load", + bus=bus, + phases="abn", + powers=Q_(np.array([1000, 1000]) * (1 - 0.3j), "VA"), + flexible_params=[fp1, fp2], +) +``` + +The first element of the load is connected between phase "a" and "n" of the bus. Its control is a +$Q(U)$ control with a projection at constant $P$ and an $S^{\max}$ of 5 kVA. + +The second element of the load is connected between phase "b" and "n" of the bus. Its control is a +$P(U)$ control with a Euclidean projection and an $S^{\max}$ of 3 kVA. + +### Scenario 3: $PQ(U)$ control + +Finally, it is possible to combine $P(U)$ and $Q(U)$ controls, for example by first using all +available reactive power before reducing the active power in order to limit the impact for the +client. + +```python +import numpy as np + +from roseau.load_flow import FlexibleParameter, Control, Projection, Q_, PowerLoad, Bus + +bus = Bus(id="bus", phases="abc") + +# Create a flexible parameter +fp = FlexibleParameter( + control_p=Control.p_max_u_production(u_up=Q_(245, "V"), u_max=Q_(250, "V")), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(245, "V") + ), + projection=Projection(type="euclidean"), + s_max=Q_(5, "kVA"), +) + +# Or using the shortcut +fp = FlexibleParameter.pq_u_production( + up_up=Q_(245, "V"), + up_max=Q_(250, "V"), + uq_min=Q_(210, "V"), + uq_down=Q_(220, "V"), + uq_up=Q_(240, "V"), + uq_max=Q_(245, "V"), + s_max=Q_(5, "kVA"), +) + +# Use it in a load +load = PowerLoad( + id="load", + bus=bus, + powers=Q_(-np.array([1000, 1000, 1000]), "VA"), + flexible_params=[fp, fp, fp], +) +``` + +In this example, the same flexible parameter is used to control all phases of the three-phase +delta-connected load. In the flexible parameter, one can remark that the $Q(U)$ control on high +voltages triggers at 240 V (production) and reaches its maximum at 245 V. The $P(U)$ control +however triggers at 245 V and is maxed out at 250 V. + +Using this configuration, a _sequential $PQ(U)$ control_ has been created for this load. A +_simultaneous $PQ(U)$ control_ could have been defined by using the same voltage thresholds for both +controls. diff --git a/doc/models/Load/FlexibleLoad/Projection.md b/doc/models/Load/FlexibleLoad/Projection.md new file mode 100644 index 00000000..be7bf81e --- /dev/null +++ b/doc/models/Load/FlexibleLoad/Projection.md @@ -0,0 +1,84 @@ +(models-flexible_load-projections)= + +# Projections + +The different controls may produce values for $P$ and $Q$ that are not feasible. The feasibility +domain in the $(P, Q)$ space is a part of the disc of radius $S^{\max}$. In these cases, the +solution found by the control algorithm has to be projected on the feasible domain. That's why we +need to define how the projection is done. There are three available projection types: the +_Euclidean_ projection, the projection at _Constant $P$_ and the projection at _Constant $Q$_. + +The projection accepts two approximation parameters: `alpha` and `epsilon`. + +- `alpha` is used to compute soft sign function and soft projection function. The higher `alpha` + is, the better the approximations are. +- `epsilon` is used to approximate a smooth square root function: + ```{math} + \sqrt{S} \approx \sqrt{\varepsilon \times \exp\left(\frac{-{|S|}^2}{\varepsilon}\right) + {|S|}^2} + ``` + The lower `epsilon` is, the better the approximations are. + +```{important} +Please note that no projection is performed in the final $\underline{S(U)}$ point lies in the disc of radius $S^{\max}$. +``` + +## Euclidean projection + +A Euclidean projection on the feasible domain. This is the default value for projections when it is +not specified. + +```{image} /_static/Load/FlexibleLoad/Euclidean_Projection.svg +:width: 300 +:align: center +``` + +```python +from roseau.load_flow import Projection + +projection = Projection(type="euclidean") # alpha and epsilon can be provided +``` + +```{important} +Please note that using the Euclidean projection may reduce the provided $P^{\mathrm{th.}}$ and $Q^{\mathrm{th.}}$ of +the load. See the [Feasible Domain page](models-flexible_load-feasible_domains) for more details. +``` + +## Constant $P$ + +Keep the value of $P$ computed by the control and project $Q$ on the feasible domain. + +```{image} /_static/Load/FlexibleLoad/Constant_P_Projection.svg +:width: 300 +:align: center +``` + +```python +from roseau.load_flow import Projection + +projection = Projection(type="keep_p") # alpha and epsilon can be provided +``` + +```{important} +Please note that using the _Constant $P$_ projection may reduce the provided $Q^{\mathrm{th.}}$ of the load. See the +[Feasible Domain page](models-flexible_load-feasible_domains) for more details. +``` + +## Constant $Q$ + +Keep the value of $Q$ computed by the control and project $P$ on the feasible domain. + +```{image} /_static/Load/FlexibleLoad/Constant_Q_Projection.svg +:width: 300 +:align: center +``` + +```python +from roseau.load_flow import Projection + +projection = Projection(type="keep_q") # alpha and epsilon can be provided +``` + +```{important} +Please note that using the _Constant $Q$_ may reduce the provided $P^{\mathrm{th.}}$ of the load. See the [Feasible +Domain page](models-flexible_load-feasible_domains) for more details. +``` diff --git a/doc/models/Load/FlexibleLoad/index.md b/doc/models/Load/FlexibleLoad/index.md new file mode 100644 index 00000000..7fdb7f41 --- /dev/null +++ b/doc/models/Load/FlexibleLoad/index.md @@ -0,0 +1,57 @@ +# Flexible loads + +They are a special case of power loads: instead of being constant, the power will depend on the +voltage measured at the load and the control applied to the load. + +## Equations + +The equations are the following (star loads): + +```{math} +\left\{ + \begin{aligned} + \underline{I_{\mathrm{abc}}} &= \left(\frac{ + \underline{S_{\mathrm{abc}}}(\underline{V_{\mathrm{abc}}}-\underline{V_{\mathrm{n}}}) + }{\underline{V_{\mathrm{abc}}}-\underline{V_{\mathrm{n}}}}\right)^{\star} \\ + \underline{I_{\mathrm{n}}} &= -\sum_{p\in\{\mathrm{a},\mathrm{b},\mathrm{c}\}}\underline{I_{p}} + \end{aligned} +\right. +``` + +And the following (delta loads): + +```{math} +\left\{ + \begin{aligned} + \underline{I_{\mathrm{ab}}} &= \left(\frac{\underline{S_{\mathrm{ab}}}(\underline{V_{\mathrm{a}}}-\underline + {V_{\mathrm{b}}})}{\underline{V_{\mathrm{a}}}-\underline{V_{\mathrm{b}}}}\right)^{\star} \\ + \underline{I_{\mathrm{bc}}} &= \left(\frac{\underline{S_{\mathrm{bc}}}(\underline{V_{\mathrm{b}}}-\underline + {V_{\mathrm{c}}})}{\underline{V_{\mathrm{b}}}-\underline{V_{\mathrm{c}}}}\right)^{\star} \\ + \underline{I_{\mathrm{ca}}} &= \left(\frac{\underline{S_{\mathrm{ca}}}(\underline{V_{\mathrm{c}}}-\underline + {V_{\mathrm{a}}})}{\underline{V_{\mathrm{c}}}-\underline{V_{\mathrm{a}}}}\right)^{\star} + \end{aligned} +\right. +``` + +The expression $\underline{S}(U)$ depends on four parameters: + +- The theoretical power $\underline{S^{\mathrm{th.}}}$ that the load would have if no control is applied. +- The maximal power $S^{\max}$ that can be injected/consumed by the load. For a PV installation, this is + usually the rated power of the inverter. +- The type of control (see [here](models-flexible_load-controls)). +- The type of projection (see [here](models-flexible_load-projections)). + +## Detailed pages + +All these elements are detailed in the following sections: + +```{toctree} +--- +maxdepth: 2 +caption: Flexible loads +--- +Control +Projection +FlexibleParameter +FeasibleDomain +``` diff --git a/doc/models/Load/index.md b/doc/models/Load/index.md index fe8ce74b..5e4decf0 100644 --- a/doc/models/Load/index.md +++ b/doc/models/Load/index.md @@ -68,11 +68,11 @@ The following load models are available in _Roseau Load Flow_: ```{toctree} --- -maxdepth: 2 +maxdepth: 3 caption: Loads --- ImpedanceLoad CurrentLoad PowerLoad -FlexibleLoad +FlexibleLoad/index ``` diff --git a/doc/usage/Flexible_Loads.md b/doc/usage/Flexible_Loads.md index 5891c0f7..40291107 100644 --- a/doc/usage/Flexible_Loads.md +++ b/doc/usage/Flexible_Loads.md @@ -202,12 +202,12 @@ flexible load implementing a $PQ(U)$ control instead. As before, we first create a `FlexibleParameter` but this time, we will use the `pq_u_production` class method. It requires several arguments: -- `up_up` and `up_max`: the voltages defining the interval of the `P(U)` control activation. +- `up_up` and `up_max`: the voltages defining the interval of the $P(U)$ control activation. Below `up_up`, no control is applied and above `u_max`, the production is totally shut down. -- `uq_min`, `uq_down`, `uq_up` and `uq_max` which are the voltages defining the `Q(U)` control +- `uq_min`, `uq_down`, `uq_up` and `uq_max` which are the voltages defining the $Q(U)$ control activation. - Below `uq_min`, the power plant produces the maximum possible reactive power. - - Between `uq_down` and `uq_up`, there is no `Q(U)` control. + - Between `uq_down` and `uq_up`, there is no $Q(U)$ control. - 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` @@ -216,7 +216,7 @@ exhausted at 240 V. After that, the $P(U)$ is activated and is exhausted at 250 production is totally shut down. ```pycon ->>> # Let's try with pq(u) control, by injecting reactive power before reducing active power +>>> # Let's try with PQ(u) control, by injecting reactive power before reducing active power ... en.loads["load3"].disconnect() ... fp = FlexibleParameter.pq_u_production( ... up_up=240, up_max=250, uq_min=200, uq_down=210, uq_up=235, uq_max=240, s_max=4000 # V and VA @@ -244,4 +244,4 @@ array([-2566.23768012+3068.29336425j, 0.+0.j, 0.+0.j]) One can note that this time, the phase `'a'` consumes reactive power to limit the voltage rise in the network. Moreover, the magnitude of the power on phase `'a'` is approximately $4 kVA$ which is the maximum allowed apparent power for `load3`. In order to maintain this maximum, a -[Euclidean projection](models-flexible_load-projection) has been used. +[Euclidean projection](models-flexible_load-projections) has been used. From d1e367f872713607f12f802f7fe3c665533dd08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 19 Sep 2023 15:11:55 +0200 Subject: [PATCH 12/43] Add plot methods --- conda/environment.yml | 3 +- conda/meta.yaml | 1 + doc/Installation.md | 7 + poetry.lock | 554 ++++++++++++++++-- pyproject.toml | 3 + roseau/load_flow/exceptions.py | 3 + .../models/loads/flexible_parameters.py | 481 ++++++++++++++- roseau/load_flow/network.py | 5 +- roseau/load_flow/typing.py | 8 +- 9 files changed, 1003 insertions(+), 62 deletions(-) diff --git a/conda/environment.yml b/conda/environment.yml index a6e1ff7f..640acd57 100644 --- a/conda/environment.yml +++ b/conda/environment.yml @@ -12,4 +12,5 @@ dependencies: - pint >=0.21.0 - requests >=2.28.1 - typing-extensions >=4.6.2 - - rich >=13.5.2 + - rich >=13.5.1 + - matplotlib >=3.7.2 diff --git a/conda/meta.yaml b/conda/meta.yaml index 7d15d74e..8cc7e50b 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -35,6 +35,7 @@ requirements: - requests >=2.28.1 - typing-extensions >=4.6.2 - rich >=13.5.1 + - matplotlib >=3.7.2 test: imports: diff --git a/doc/Installation.md b/doc/Installation.md index e8b7fec4..5e86a8e7 100644 --- a/doc/Installation.md +++ b/doc/Installation.md @@ -50,6 +50,13 @@ To upgrade to the latest version (recommended), use: $ python -m pip install --upgrade roseau-load-flow ``` +Moreover, using the `pip` installation, some plot functions requires additional dependencies that are not installed by +default. If you need these functions, you can install the `plot` extra using + +```console +$ python -m pip install roseau-load-flow[plot] +``` + ## Using `conda` `roseau-load-flow` is also available on [conda-forge](https://anaconda.org/conda-forge/roseau-load-flow). diff --git a/poetry.lock b/poetry.lock index bd95107b..ab748975 100644 --- a/poetry.lock +++ b/poetry.lock @@ -340,6 +340,135 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "contourpy" +version = "1.1.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, + {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, + {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, + {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, + {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, + {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, + {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, +] + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + +[[package]] +name = "contourpy" +version = "1.1.1" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, + {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, + {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, + {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, + {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, + {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, + {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, + {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, + {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, + {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, + {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, + {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, + {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, + {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, + {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, + {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, + {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, + {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, +] + +[package.dependencies] +numpy = {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""} + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + [[package]] name = "coverage" version = "7.3.1" @@ -407,6 +536,17 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] + [[package]] name = "decorator" version = "5.1.1" @@ -484,21 +624,19 @@ tests = ["asttokens", "littleutils", "pytest", "rich"] [[package]] name = "filelock" -version = "3.12.3" +version = "3.12.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.3-py3-none-any.whl", hash = "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb"}, - {file = "filelock-3.12.3.tar.gz", hash = "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d"}, + {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, + {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.11\""} - [package.extras] docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +typing = ["typing-extensions (>=4.7.1)"] [[package]] name = "fiona" @@ -544,6 +682,63 @@ calc = ["shapely"] s3 = ["boto3 (>=1.3.1)"] test = ["Fiona[s3]", "pytest (>=7)", "pytest-cov", "pytz"] +[[package]] +name = "fonttools" +version = "4.42.1" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"}, + {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"}, + {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"}, + {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"}, + {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"}, + {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"}, + {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"}, + {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"}, + {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"}, + {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"}, + {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"}, + {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"}, + {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"}, + {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"}, + {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"}, + {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"}, + {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"}, + {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"}, + {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"}, + {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"}, + {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"}, + {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"}, + {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"}, + {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"}, + {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"}, + {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"}, + {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"}, + {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"}, + {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"}, + {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"}, + {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"}, + {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"}, + {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"}, + {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.0.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + [[package]] name = "furo" version = "2023.9.10" @@ -563,31 +758,31 @@ sphinx-basic-ng = "*" [[package]] name = "geopandas" -version = "0.13.2" +version = "0.14.0" description = "Geographic pandas extensions" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "geopandas-0.13.2-py3-none-any.whl", hash = "sha256:101cfd0de54bcf9e287a55b5ea17ebe0db53a5e25a28bacf100143d0507cabd9"}, - {file = "geopandas-0.13.2.tar.gz", hash = "sha256:e5b56d9c20800c77bcc0c914db3f27447a37b23b2cd892be543f5001a694a968"}, + {file = "geopandas-0.14.0-py3-none-any.whl", hash = "sha256:a402a565e727642cb44a500c911f226eea26c1b1247c6586827031e3d7a9403a"}, + {file = "geopandas-0.14.0.tar.gz", hash = "sha256:ea6c031889e1e1888aecaa6e182ca620d78f63551c49b3002a998bcbb280531f"}, ] [package.dependencies] -fiona = ">=1.8.19" +fiona = ">=1.8.21" packaging = "*" -pandas = ">=1.1.0" -pyproj = ">=3.0.1" -shapely = ">=1.7.1" +pandas = ">=1.4.0" +pyproj = ">=3.3.0" +shapely = ">=1.8.0" [[package]] name = "identify" -version = "2.5.28" +version = "2.5.29" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.28-py2.py3-none-any.whl", hash = "sha256:87816de144bf46d161bd5b3e8f5596b16cade3b80be537087334b26bc5c177f3"}, - {file = "identify-2.5.28.tar.gz", hash = "sha256:94bb59643083ebd60dc996d043497479ee554381fbc5307763915cda49b0e78f"}, + {file = "identify-2.5.29-py2.py3-none-any.whl", hash = "sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b"}, + {file = "identify-2.5.29.tar.gz", hash = "sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5"}, ] [package.extras] @@ -634,6 +829,24 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker perf = ["ipython"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +[[package]] +name = "importlib-resources" +version = "6.0.1" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.0.1-py3-none-any.whl", hash = "sha256:134832a506243891221b88b4ae1213327eea96ceb4e407a00d790bb0626f45cf"}, + {file = "importlib_resources-6.0.1.tar.gz", hash = "sha256:4359457e42708462b9626a04657c6208ad799ceb41e5c58c57ffa0e6a098a5d4"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -721,6 +934,119 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "kiwisolver" +version = "1.4.5" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] + [[package]] name = "latexcodec" version = "2.0.1" @@ -863,6 +1189,56 @@ files = [ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] +[[package]] +name = "matplotlib" +version = "3.8.0" +description = "Python plotting package" +optional = false +python-versions = ">=3.9" +files = [ + {file = "matplotlib-3.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c4940bad88a932ddc69734274f6fb047207e008389489f2b6f77d9ca485f0e7a"}, + {file = "matplotlib-3.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a33bd3045c7452ca1fa65676d88ba940867880e13e2546abb143035fa9072a9d"}, + {file = "matplotlib-3.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea6886e93401c22e534bbfd39201ce8931b75502895cfb115cbdbbe2d31f287"}, + {file = "matplotlib-3.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d670b9348e712ec176de225d425f150dc8e37b13010d85233c539b547da0be39"}, + {file = "matplotlib-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7b37b74f00c4cb6af908cb9a00779d97d294e89fd2145ad43f0cdc23f635760c"}, + {file = "matplotlib-3.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:0e723f5b96f3cd4aad99103dc93e9e3cdc4f18afdcc76951f4857b46f8e39d2d"}, + {file = "matplotlib-3.8.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5dc945a9cb2deb7d197ba23eb4c210e591d52d77bf0ba27c35fc82dec9fa78d4"}, + {file = "matplotlib-3.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8b5a1bf27d078453aa7b5b27f52580e16360d02df6d3dc9504f3d2ce11f6309"}, + {file = "matplotlib-3.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f25ffb6ad972cdffa7df8e5be4b1e3cadd2f8d43fc72085feb1518006178394"}, + {file = "matplotlib-3.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee482731c8c17d86d9ddb5194d38621f9b0f0d53c99006275a12523ab021732"}, + {file = "matplotlib-3.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:36eafe2128772195b373e1242df28d1b7ec6c04c15b090b8d9e335d55a323900"}, + {file = "matplotlib-3.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:061ee58facb3580cd2d046a6d227fb77e9295599c5ec6ad069f06b5821ad1cfc"}, + {file = "matplotlib-3.8.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3cc3776836d0f4f22654a7f2d2ec2004618d5cf86b7185318381f73b80fd8a2d"}, + {file = "matplotlib-3.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c49a2bd6981264bddcb8c317b6bd25febcece9e2ebfcbc34e7f4c0c867c09dc"}, + {file = "matplotlib-3.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ed11654fc83cd6cfdf6170b453e437674a050a452133a064d47f2f1371f8d3"}, + {file = "matplotlib-3.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dae97fdd6996b3a25da8ee43e3fc734fff502f396801063c6b76c20b56683196"}, + {file = "matplotlib-3.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:87df75f528020a6299f76a1d986c0ed4406e3b2bd44bc5e306e46bca7d45e53e"}, + {file = "matplotlib-3.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:90d74a95fe055f73a6cd737beecc1b81c26f2893b7a3751d52b53ff06ca53f36"}, + {file = "matplotlib-3.8.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c3499c312f5def8f362a2bf761d04fa2d452b333f3a9a3f58805273719bf20d9"}, + {file = "matplotlib-3.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31e793c8bd4ea268cc5d3a695c27b30650ec35238626961d73085d5e94b6ab68"}, + {file = "matplotlib-3.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d5ee602ef517a89d1f2c508ca189cfc395dd0b4a08284fb1b97a78eec354644"}, + {file = "matplotlib-3.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5de39dc61ca35342cf409e031f70f18219f2c48380d3886c1cf5ad9f17898e06"}, + {file = "matplotlib-3.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:dd386c80a98b5f51571b9484bf6c6976de383cd2a8cd972b6a9562d85c6d2087"}, + {file = "matplotlib-3.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:f691b4ef47c7384d0936b2e8ebdeb5d526c81d004ad9403dfb9d4c76b9979a93"}, + {file = "matplotlib-3.8.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0b11f354aae62a2aa53ec5bb09946f5f06fc41793e351a04ff60223ea9162955"}, + {file = "matplotlib-3.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f54b9fb87ca5acbcdd0f286021bedc162e1425fa5555ebf3b3dfc167b955ad9"}, + {file = "matplotlib-3.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:60a6e04dfd77c0d3bcfee61c3cd335fff1b917c2f303b32524cd1235e194ef99"}, + {file = "matplotlib-3.8.0.tar.gz", hash = "sha256:df8505e1c19d5c2c26aff3497a7cbd3ccfc2e97043d1e4db3e76afa399164b69"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.0.1" +numpy = ">=1.21,<2" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=7" + [[package]] name = "matplotlib-inline" version = "0.1.6" @@ -1115,6 +1491,73 @@ files = [ {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] +[[package]] +name = "pillow" +version = "10.0.1" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.0.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:8f06be50669087250f319b706decf69ca71fdecd829091a37cc89398ca4dc17a"}, + {file = "Pillow-10.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50bd5f1ebafe9362ad622072a1d2f5850ecfa44303531ff14353a4059113b12d"}, + {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6a90167bcca1216606223a05e2cf991bb25b14695c518bc65639463d7db722d"}, + {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f11c9102c56ffb9ca87134bd025a43d2aba3f1155f508eff88f694b33a9c6d19"}, + {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:186f7e04248103482ea6354af6d5bcedb62941ee08f7f788a1c7707bc720c66f"}, + {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0462b1496505a3462d0f35dc1c4d7b54069747d65d00ef48e736acda2c8cbdff"}, + {file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d889b53ae2f030f756e61a7bff13684dcd77e9af8b10c6048fb2c559d6ed6eaf"}, + {file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:552912dbca585b74d75279a7570dd29fa43b6d93594abb494ebb31ac19ace6bd"}, + {file = "Pillow-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:787bb0169d2385a798888e1122c980c6eff26bf941a8ea79747d35d8f9210ca0"}, + {file = "Pillow-10.0.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fd2a5403a75b54661182b75ec6132437a181209b901446ee5724b589af8edef1"}, + {file = "Pillow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d7e91b4379f7a76b31c2dda84ab9e20c6220488e50f7822e59dac36b0cd92b1"}, + {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e9adb3f22d4c416e7cd79b01375b17159d6990003633ff1d8377e21b7f1b21"}, + {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93139acd8109edcdeffd85e3af8ae7d88b258b3a1e13a038f542b79b6d255c54"}, + {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:92a23b0431941a33242b1f0ce6c88a952e09feeea9af4e8be48236a68ffe2205"}, + {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cbe68deb8580462ca0d9eb56a81912f59eb4542e1ef8f987405e35a0179f4ea2"}, + {file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:522ff4ac3aaf839242c6f4e5b406634bfea002469656ae8358644fc6c4856a3b"}, + {file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:84efb46e8d881bb06b35d1d541aa87f574b58e87f781cbba8d200daa835b42e1"}, + {file = "Pillow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:898f1d306298ff40dc1b9ca24824f0488f6f039bc0e25cfb549d3195ffa17088"}, + {file = "Pillow-10.0.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:bcf1207e2f2385a576832af02702de104be71301c2696d0012b1b93fe34aaa5b"}, + {file = "Pillow-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d6c9049c6274c1bb565021367431ad04481ebb54872edecfcd6088d27edd6ed"}, + {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28444cb6ad49726127d6b340217f0627abc8732f1194fd5352dec5e6a0105635"}, + {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de596695a75496deb3b499c8c4f8e60376e0516e1a774e7bc046f0f48cd620ad"}, + {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2872f2d7846cf39b3dbff64bc1104cc48c76145854256451d33c5faa55c04d1a"}, + {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4ce90f8a24e1c15465048959f1e94309dfef93af272633e8f37361b824532e91"}, + {file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ee7810cf7c83fa227ba9125de6084e5e8b08c59038a7b2c9045ef4dde61663b4"}, + {file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1be1c872b9b5fcc229adeadbeb51422a9633abd847c0ff87dc4ef9bb184ae08"}, + {file = "Pillow-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:98533fd7fa764e5f85eebe56c8e4094db912ccbe6fbf3a58778d543cadd0db08"}, + {file = "Pillow-10.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:764d2c0daf9c4d40ad12fbc0abd5da3af7f8aa11daf87e4fa1b834000f4b6b0a"}, + {file = "Pillow-10.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fcb59711009b0168d6ee0bd8fb5eb259c4ab1717b2f538bbf36bacf207ef7a68"}, + {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:697a06bdcedd473b35e50a7e7506b1d8ceb832dc238a336bd6f4f5aa91a4b500"}, + {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f665d1e6474af9f9da5e86c2a3a2d2d6204e04d5af9c06b9d42afa6ebde3f21"}, + {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:2fa6dd2661838c66f1a5473f3b49ab610c98a128fc08afbe81b91a1f0bf8c51d"}, + {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:3a04359f308ebee571a3127fdb1bd01f88ba6f6fb6d087f8dd2e0d9bff43f2a7"}, + {file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:723bd25051454cea9990203405fa6b74e043ea76d4968166dfd2569b0210886a"}, + {file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:71671503e3015da1b50bd18951e2f9daf5b6ffe36d16f1eb2c45711a301521a7"}, + {file = "Pillow-10.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:44e7e4587392953e5e251190a964675f61e4dae88d1e6edbe9f36d6243547ff3"}, + {file = "Pillow-10.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:3855447d98cced8670aaa63683808df905e956f00348732448b5a6df67ee5849"}, + {file = "Pillow-10.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed2d9c0704f2dc4fa980b99d565c0c9a543fe5101c25b3d60488b8ba80f0cce1"}, + {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5bb289bb835f9fe1a1e9300d011eef4d69661bb9b34d5e196e5e82c4cb09b37"}, + {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0d3e54ab1df9df51b914b2233cf779a5a10dfd1ce339d0421748232cea9876"}, + {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2cc6b86ece42a11f16f55fe8903595eff2b25e0358dec635d0a701ac9586588f"}, + {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ca26ba5767888c84bf5a0c1a32f069e8204ce8c21d00a49c90dabeba00ce0145"}, + {file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f0b4b06da13275bc02adfeb82643c4a6385bd08d26f03068c2796f60d125f6f2"}, + {file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bc2e3069569ea9dbe88d6b8ea38f439a6aad8f6e7a6283a38edf61ddefb3a9bf"}, + {file = "Pillow-10.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:8b451d6ead6e3500b6ce5c7916a43d8d8d25ad74b9102a629baccc0808c54971"}, + {file = "Pillow-10.0.1-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:32bec7423cdf25c9038fef614a853c9d25c07590e1a870ed471f47fb80b244db"}, + {file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cf63d2c6928b51d35dfdbda6f2c1fddbe51a6bc4a9d4ee6ea0e11670dd981e"}, + {file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f6d3d4c905e26354e8f9d82548475c46d8e0889538cb0657aa9c6f0872a37aa4"}, + {file = "Pillow-10.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:847e8d1017c741c735d3cd1883fa7b03ded4f825a6e5fcb9378fd813edee995f"}, + {file = "Pillow-10.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7f771e7219ff04b79e231d099c0a28ed83aa82af91fd5fa9fdb28f5b8d5addaf"}, + {file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459307cacdd4138edee3875bbe22a2492519e060660eaf378ba3b405d1c66317"}, + {file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b059ac2c4c7a97daafa7dc850b43b2d3667def858a4f112d1aa082e5c3d6cf7d"}, + {file = "Pillow-10.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6caf3cd38449ec3cd8a68b375e0c6fe4b6fd04edb6c9766b55ef84a6e8ddf2d"}, + {file = "Pillow-10.0.1.tar.gz", hash = "sha256:d72967b06be9300fed5cfbc8b5bafceec48bf7cdc7dab66b1d2549035287191d"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + [[package]] name = "pint" version = "0.22" @@ -1274,6 +1717,20 @@ files = [ [package.extras] plugins = ["importlib-metadata"] +[[package]] +name = "pyparsing" +version = "3.1.1" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + [[package]] name = "pyproj" version = "3.6.0" @@ -1584,13 +2041,13 @@ test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "tes [[package]] name = "rich" -version = "13.5.2" +version = "13.5.3" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.5.2-py3-none-any.whl", hash = "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808"}, - {file = "rich-13.5.2.tar.gz", hash = "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39"}, + {file = "rich-13.5.3-py3-none-any.whl", hash = "sha256:9257b468badc3d347e146a4faa268ff229039d4c2d176ab0cffb4c4fbc73d5d9"}, + {file = "rich-13.5.3.tar.gz", hash = "sha256:87b43e0543149efa1253f485cd845bb7ee54df16c9617b8a893650ab84b4acb6"}, ] [package.dependencies] @@ -1642,6 +2099,27 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +[[package]] +name = "setuptools-scm" +version = "7.1.0" +description = "the blessed package to manage your versions by scm tags" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools_scm-7.1.0-py3-none-any.whl", hash = "sha256:73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e"}, + {file = "setuptools_scm-7.1.0.tar.gz", hash = "sha256:6c508345a771aad7d56ebff0e70628bf2b0ec7573762be9960214730de278f27"}, +] + +[package.dependencies] +packaging = ">=20.0" +setuptools = "*" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +typing-extensions = "*" + +[package.extras] +test = ["pytest (>=6.2)", "virtualenv (>20)"] +toml = ["setuptools (>=42)"] + [[package]] name = "shapely" version = "2.0.1" @@ -1731,13 +2209,13 @@ files = [ [[package]] name = "sphinx" -version = "7.2.5" +version = "7.2.6" description = "Python documentation generator" optional = false python-versions = ">=3.9" files = [ - {file = "sphinx-7.2.5-py3-none-any.whl", hash = "sha256:9269f9ed2821c9ebd30e4204f5c2339f5d4980e377bc89cb2cb6f9b17409c20a"}, - {file = "sphinx-7.2.5.tar.gz", hash = "sha256:1a9290001b75c497fd087e92b0334f1bbfa1a1ae7fddc084990c4b7bd1130b88"}, + {file = "sphinx-7.2.6-py3-none-any.whl", hash = "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560"}, + {file = "sphinx-7.2.6.tar.gz", hash = "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5"}, ] [package.dependencies] @@ -2033,28 +2511,28 @@ files = [ [[package]] name = "traitlets" -version = "5.9.0" +version = "5.10.0" description = "Traitlets Python configuration system" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"}, - {file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"}, + {file = "traitlets-5.10.0-py3-none-any.whl", hash = "sha256:417745a96681fbb358e723d5346a547521f36e9bd0d50ba7ab368fff5d67aa54"}, + {file = "traitlets-5.10.0.tar.gz", hash = "sha256:f584ea209240466e66e91f3c81aa7d004ba4cf794990b0c775938a1544217cd1"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.5.1)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] [[package]] @@ -2202,20 +2680,20 @@ files = [ [[package]] name = "zipp" -version = "3.16.2" +version = "3.17.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, - {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "c7346fba55321b4af5fd5c892d8c89687ddbf7dbafdc75c6cd88fb486e1d4fe4" +content-hash = "de4181680060f36444109dc1ffd00f53fb6c40d7da4833a301c99c1c1e9d4c9d" diff --git a/pyproject.toml b/pyproject.toml index 28afcca8..e58039c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,9 @@ pint = ">=0.21.0" typing-extensions = ">=4.6.2" rich = ">=13.5.1" +# Plot Extra +matplotlib = { version = "^3.7.2", extras = ["plot"] } + [tool.poetry.group.test.dependencies] pytest = "^7.1.2" pytest-cov = "^4.0.0" diff --git a/roseau/load_flow/exceptions.py b/roseau/load_flow/exceptions.py index f843e31c..7806f209 100644 --- a/roseau/load_flow/exceptions.py +++ b/roseau/load_flow/exceptions.py @@ -107,6 +107,9 @@ class RoseauLoadFlowExceptionCode(Enum): CATALOGUE_NOT_FOUND = auto() CATALOGUE_SEVERAL_FOUND = auto() + # Import Error + IMPORT_ERROR = auto() + @classmethod def package_name(cls) -> str: return "roseau.load_flow" diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index 712c9904..fae73aa4 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -1,17 +1,20 @@ import logging import warnings -from typing import NoReturn +from typing import TYPE_CHECKING, NoReturn, Optional import numpy as np from typing_extensions import Self from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.typing import ControlType, JsonDict, ProjectionType +from roseau.load_flow.typing import Authentication, ControlType, JsonDict, ProjectionType from roseau.load_flow.units import Q_, ureg_wraps from roseau.load_flow.utils import JsonMixin logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from matplotlib import Axes + class Control(JsonMixin): """Control class for flexible loads. @@ -332,16 +335,17 @@ class Projection(JsonMixin): """This class defines the projection on the feasible circle for a flexible load. The three possible projection types are: - * ``"euclidean"``: for an Euclidean projection on the feasible space; + * ``"euclidean"``: for a Euclidean projection on the feasible space; * ``"keep_p"``: for maintaining a constant P; * ``"keep_q"``: for maintaining a constant Q. See Also: - :ref:`Projection documentation ` + :ref:`Projection documentation ` """ _DEFAULT_ALPHA: float = 1000.0 _DEFAULT_EPSILON: float = 1e-8 + _DEFAULT_TYPE: ProjectionType = "euclidean" def __init__(self, type: ProjectionType, alpha: float = _DEFAULT_ALPHA, epsilon: float = _DEFAULT_EPSILON) -> None: """Projection constructor. @@ -485,24 +489,24 @@ def constant(cls) -> Self: """Build flexible parameters for a constant control with a Euclidean projection. Returns: - A constant control i.e. no control at all. It is an equivalent of the constant power - load. + A constant control i.e. no control at all. It is an equivalent of the constant power load. """ return cls( control_p=cls._control_class.constant(), control_q=cls._control_class.constant(), - projection=cls._projection_class(type="euclidean"), + projection=cls._projection_class(type=cls._projection_class.DEFAULT_TYPE), s_max=1.0, ) @classmethod - @ureg_wraps(None, (None, "V", "V", "VA", None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None), strict=False) def p_max_u_production( cls, u_up: float, u_max: float, s_max: float, alpha_control: float = Control._DEFAULT_ALPHA, + type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: @@ -528,6 +532,9 @@ def p_max_u_production( An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. + type_proj: + The type of the projection to use. + alpha_proj: This value is used to make soft sign function and to build a soft projection function (see the diagram above). @@ -543,18 +550,19 @@ def p_max_u_production( return cls( control_p=control_p, control_q=cls._control_class.constant(), - projection=cls._projection_class(type="euclidean", alpha=alpha_proj, epsilon=epsilon_proj), + projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, ) @classmethod - @ureg_wraps(None, (None, "V", "V", "VA", None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None), strict=False) def p_max_u_consumption( cls, u_min: float, u_down: float, s_max: float, alpha_control: float = Control._DEFAULT_ALPHA, + type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: @@ -577,6 +585,9 @@ def p_max_u_consumption( An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. + type_proj: + The type of the projection to use. + alpha_proj: This value is used to make soft sign function and to build a soft projection function. @@ -592,12 +603,12 @@ def p_max_u_consumption( return cls( control_p=control_p, control_q=cls._control_class.constant(), - projection=cls._projection_class("euclidean", alpha=alpha_proj, epsilon=epsilon_proj), + projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "VA", None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "VA", None, None, None, None), strict=False) def q_u( cls, u_min: float, @@ -606,6 +617,7 @@ def q_u( u_max: float, s_max: float, alpha_control: float = Control._DEFAULT_ALPHA, + type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: @@ -635,6 +647,9 @@ def q_u( An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. + type_proj: + The type of the projection to use. + alpha_proj: This value is used to make soft sign function and to build a soft projection function. @@ -650,12 +665,12 @@ def q_u( return cls( control_p=cls._control_class.constant(), control_q=control_q, - projection=cls._projection_class(type="euclidean", alpha=alpha_proj, epsilon=epsilon_proj), + projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", None, None, None, None), strict=False) def pq_u_production( cls, up_up: float, @@ -666,6 +681,7 @@ def pq_u_production( uq_max: float, s_max: float, alpha_control=Control._DEFAULT_ALPHA, + type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj=Projection._DEFAULT_ALPHA, epsilon_proj=Projection._DEFAULT_EPSILON, ) -> Self: @@ -702,6 +718,9 @@ def pq_u_production( An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. + type_proj: + The type of the projection to use. + alpha_proj: This value is used to make soft sign function and to build a soft projection function. @@ -713,7 +732,7 @@ def pq_u_production( Returns: A flexible parameter which performs "p_max_u_production" control and a "q_u" control. - .. seealso:: + See Also: :meth:`p_max_u_production` and :meth:`q_u` for more details. """ control_p = cls._control_class.p_max_u_production(u_up=up_up, u_max=up_max, alpha=alpha_control) @@ -721,12 +740,12 @@ def pq_u_production( return cls( control_p=control_p, control_q=control_q, - projection=cls._projection_class(type="euclidean", alpha=alpha_proj, epsilon=epsilon_proj), + projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", None, None, None, None), strict=False) def pq_u_consumption( cls, up_min: float, @@ -737,6 +756,7 @@ def pq_u_consumption( uq_max: float, s_max: float, alpha_control: float = Control._DEFAULT_ALPHA, + type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, epsilon_proj: float = Projection._DEFAULT_EPSILON, ) -> Self: @@ -773,6 +793,9 @@ def pq_u_consumption( An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. + type_proj: + The type of the projection to use. + alpha_proj: This value is used to make soft sign function and to build a soft projection function. @@ -784,7 +807,7 @@ def pq_u_consumption( Returns: A flexible parameter which performs "p_max_u_consumption" control and "q_u" control. - .. seealso:: + See Also: :meth:`p_max_u_consumption` and :meth:`q_u` for more details. """ control_p = cls._control_class.p_max_u_consumption(u_min=up_min, u_down=up_down, alpha=alpha_control) @@ -792,7 +815,7 @@ def pq_u_consumption( return cls( control_p=control_p, control_q=control_q, - projection=cls._projection_class(type="euclidean", alpha=alpha_proj, epsilon=epsilon_proj), + projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, ) @@ -823,3 +846,423 @@ def results_from_dict(self, data: JsonDict) -> NoReturn: msg = f"The {type(self).__name__} has no results to import." logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.JSON_NO_RESULTS) + + # + # Equivalent Python method + # + @ureg_wraps("VA", (None, None, "V", "VA", None), strict=False) + def compute_powers( + self, auth: Authentication, voltages: np.ndarray[float], power: complex, solve_kwargs: Optional[JsonDict] = None + ) -> Q_[np.ndarray[complex]]: + """Compute the effective powers for different voltages (norms) + + Args: + auth: + The login and password for the roseau load flow api. + + voltages: + The array of voltage norms to test with this flexible parameter. + + power: + The input theoretical power of the load. + + solve_kwargs: + The keywords arguments of the :meth:`solve_load_flow` method. + + Returns: + The flexible powers really consumed taking into account the control. One value per provided voltage norm. + """ + return self._compute_powers(auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs) + + def _compute_powers( + self, auth: Authentication, voltages: np.ndarray[float], power: complex, solve_kwargs: Optional[JsonDict] + ) -> np.ndarray[complex]: + from roseau.load_flow import Bus, ElectricalNetwork, PotentialRef, PowerLoad, VoltageSource + + # Format the input + if solve_kwargs is None: + solve_kwargs = {} + voltages = np.array(np.abs(voltages), dtype=float) + + # Simple network + bus = Bus(id="bus", phases="an") + vs = VoltageSource(id="source", bus=bus, voltages=[voltages[0]]) + PotentialRef(id="pref", element=bus, phase="n") + fp = FlexibleParameter.from_dict(data=self.to_dict(include_geometry=False)) + load = PowerLoad(id="load", bus=bus, powers=[power], flexible_params=[fp]) + en = ElectricalNetwork.from_element(bus) + + # Iterate over the provided voltages to get the associated flexible powers + res_flexible_powers = [] + for v in voltages: + vs.voltages = [v] + en.solve_load_flow(auth=auth, **solve_kwargs) + res_flexible_powers.append(load.res_flexible_powers.m_as("VA")[0]) + + return np.array(res_flexible_powers, dtype=complex) + + @ureg_wraps(None, (None, None, "V", "VA", None, None, None, "VA"), strict=False) + def plot_pq( + self, + auth: Authentication, + voltages: np.ndarray[float], + power: complex, + ax: Optional["Axes"] = None, + solve_kwargs: Optional[JsonDict] = None, + voltages_labels_mask: Optional[np.ndarray[bool]] = None, + res_flexible_powers: Optional[np.ndarray[complex]] = None, + ) -> tuple["Axes", np.ndarray[complex]]: + """Plot the "trajectory" of the flexible powers (in the (P, Q) plane) for the provided voltages and theoretical + power. + + Args: + auth: + The login and password for the roseau load flow api. + + voltages: + The array of voltage norms to test with this flexible parameter. + + power: + The input theoretical power of the load. + + ax: + The optional axis to use for the plot. The current axis is used by default. + + solve_kwargs: + The keywords arguments of the :meth:`solve_load_flow` method. + + voltages_labels_mask: + A mask to activate the plot of voltages labels. By default, no voltages annotations. + + res_flexible_powers: + If None, is provided, the `res_flexible_powers` are computed. Other + + Returns: + The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else + the computed values). + """ + try: + from matplotlib import colormaps, patheffects + from matplotlib import pyplot as plt + from matplotlib.pyplot import Axes + except ImportError: + msg = 'The extra dependency "plot" is required. Please use `pip install -U roseau-load-flow[plot]`.' + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from None + + # Get the axes + if ax is None: + ax: Axes = plt.gca() + + # Initialise some variables + if voltages_labels_mask is None: + voltages_labels_mask = np.zeros_like(voltages, dtype=bool) + else: + voltages_labels_mask = np.array(voltages_labels_mask, dtype=bool) + s_max = self._s_max + v_min = voltages.min() + v_max = voltages.max() + + # Compute the powers for the voltages norms + if res_flexible_powers is None: + res_flexible_powers = self._compute_powers( + auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs + ) + + # Draw a circle + circle = plt.Circle((0, 0), radius=s_max, color="black", fill=False) + ax.add_artist(circle) + + # Draw the powers + cm = colormaps.get_cmap("Spectral_r") + sc = ax.scatter( + x=res_flexible_powers.real, + y=res_flexible_powers.imag, + c=voltages, + cmap=cm, + vmin=v_min, + vmax=v_max, + marker=".", + s=50, + zorder=4, + ) + for m, v, x, y in zip(voltages_labels_mask, voltages, res_flexible_powers.real, res_flexible_powers.imag): + if not m: + continue + ax.annotate( + text=f"{v:.1f} V", + xy=(x, y), + xycoords="data", + path_effects=[patheffects.withStroke(linewidth=2, foreground="w")], + xytext=(4, 4), + textcoords="offset points", + ) + + # Draw the theoretical power + ax.axhline(y=power.imag, c="red", zorder=1.9) + ax.axvline(x=power.real, c="red", zorder=1.9) + ax.scatter(x=power.real, y=power.imag, marker=".", c="red", zorder=3) + ax.annotate( + xy=(power.real, power.imag), + text=r"$S^{\mathrm{th.}}$", + path_effects=[patheffects.withStroke(linewidth=2, foreground="w")], + ha="right", + ) + + # Refine the axes + ax.grid(visible=True) + plt.colorbar(sc, ax=ax) + ax.set_xlim(-s_max * 1.05, s_max * 1.05) + ax.set_ylim(-s_max * 1.05, s_max * 1.05) + ax.set_aspect("equal") + ax.set_xlabel("Active power (W)") + ax.set_ylabel("Reactive power (VAr)") + + return ax, res_flexible_powers + + @ureg_wraps(None, (None, None, "V", "VA", None, None, "VA"), strict=False) + def plot_control_p( + self, + auth: Authentication, + voltages: np.ndarray[float], + power: complex, + ax: Optional["Axes"] = None, + solve_kwargs: Optional[JsonDict] = None, + res_flexible_powers: Optional[np.ndarray[complex]] = None, + ) -> tuple["Axes", np.ndarray[complex]]: + """Plot the effective active power consumed (or produced) for the provided voltages and theoretical power. + + Args: + auth: + The login and password for the roseau load flow api. + + voltages: + The array of voltage norms to test with this flexible parameter. + + power: + The input theoretical power of the load. + + ax: + The optional axis to use for the plot. The current axis is used by default. + + solve_kwargs: + The keywords arguments of the :meth:`solve_load_flow` method. + + res_flexible_powers: + If None, is provided, the `res_flexible_powers` are computed. Other + + Returns: + The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else + the computed values). + """ + try: + from matplotlib import pyplot as plt + from matplotlib.pyplot import Axes + except ImportError: + msg = 'The extra dependency "plot" is required. Please use `pip install -U roseau-load-flow[plot]`.' + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from None + + # Get the axes + if ax is None: + ax: Axes = plt.gca() + + # Depending on the type of the control, several options + x, y, x_ticks = self._theoretical_control_data( + control=self.control_p, v_min=voltages.min(), v_max=voltages.max(), power=power.real, s_max=self._s_max + ) + + # Compute the powers for the voltages norms + if res_flexible_powers is None: + res_flexible_powers = self._compute_powers( + auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs + ) + ax.scatter(voltages, res_flexible_powers.real, marker=".", c="blue", zorder=2, label="Effective power") + + # Add the theoretical non-smooth curve + ax.plot(x, y, marker="s", c="red", zorder=1.9, label="Non-smooth theoretical control") + + # Refine the axis + ax.grid(visible=True) + ax.set_xticks(x, x_ticks) + ax.set_xlabel("Voltage (V)") + ax.set_ylabel("Active power (W)") + ax.legend() + ax.figure.tight_layout() + + return ax, res_flexible_powers + + @ureg_wraps(None, (None, None, "V", "VA", None, None, "VA"), strict=False) + def plot_control_q( + self, + auth: Authentication, + voltages: np.ndarray[float], + power: complex, + ax: Optional["Axes"] = None, + solve_kwargs: Optional[JsonDict] = None, + res_flexible_powers: Optional[np.ndarray[complex]] = None, + ) -> tuple["Axes", np.ndarray[complex]]: + """Plot the effective reactive power consumed (or produced) for the provided voltages and theoretical power. + + Args: + auth: + The login and password for the roseau load flow api. + + voltages: + The array of voltage norms to test with this flexible parameter. + + power: + The input theoretical power of the load. + + ax: + The optional axis to use for the plot. The current axis is used by default. + + solve_kwargs: + The keywords arguments of the :meth:`solve_load_flow` method + + res_flexible_powers: + If None, is provided, the `res_flexible_powers` are computed. Other + + Returns: + The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else + the computed values). + """ + try: + from matplotlib import pyplot as plt + from matplotlib.pyplot import Axes + except ImportError: + msg = 'The extra dependency "plot" is required. Please use `pip install -U roseau-load-flow[plot]`.' + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from None + + # Get the axes + if ax is None: + ax: Axes = plt.gca() + + # Depending on the type of the control, several options + x, y, x_ticks = self._theoretical_control_data( + control=self.control_q, v_min=voltages.min(), v_max=voltages.max(), power=power.imag, s_max=self._s_max + ) + + # Compute the powers for the voltages norms + if res_flexible_powers is None: + res_flexible_powers = self._compute_powers( + auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs + ) + ax.scatter(voltages, res_flexible_powers.imag, marker=".", c="blue", zorder=2, label="Effective power") + + # Add the theoretical non-smooth curve + ax.plot(x, y, marker="s", c="red", zorder=1.9, label="Non-smooth theoretical control") + + # Refine the axis + ax.grid(visible=True) + ax.set_xticks(x, x_ticks) + ax.set_xlabel("Voltage (V)") + ax.set_ylabel("Reactive power (VAr)") + ax.legend() + ax.figure.tight_layout() + + return ax, res_flexible_powers + + # + # Helpers + # + @staticmethod + def _theoretical_control_data( + control: Control, v_min: float, v_max: float, power: float, s_max: float + ) -> tuple[np.ndarray[float], np.ndarray[float], np.ndarray[object]]: + """Helper to get data for the different plots of the class. It provides the theoretical control curve + abscissas and ordinates values. It also provides ticks for the abscissa axis. + + Args: + control: + The control to extract the theoretical value. + + v_min: + The minimum voltage norm provided by the user in the `voltages` array. + + v_max: + The maximum voltage norm provided by the user in the `voltages` array. + + power: + The active (or reactive, depending on the provided control) to use in the constant control. + + s_max: + The `s_max` parameter to scale the control functions. + + Returns: + The x- and y-values of the theoretical control function with x tixks to use for the plot. + """ + # Depending on the type of the control, several options + if control.type == "constant": + x = np.array([v_min, v_max], dtype=float) + y = np.array([power, power], dtype=float) + x_ticks = np.array([f"{v_min:.1f}", f"{v_max:.1f}"], dtype=object) + elif control.type == "p_max_u_production": + u_up = control._u_up + u_max = control._u_max + x = np.array([u_up, u_max, v_min, v_max], dtype=float) + y = np.zeros_like(x, dtype=float) + y[x < u_up] = -s_max + mask = np.logical_and(u_up <= x, x < u_max) + y[mask] = -s_max * (x[mask] - u_max) / (u_up - u_max) + y[x >= u_max] = 0 + x_ticks = np.array( + [f"{u_up:.1f}\n$U^{{\\mathrm{{up}}}}$", f"{u_max:.1f}\n$U^{{\\max}}$", f"{v_min:.1f}", f"{v_max:.1f}"], + dtype=object, + ) + elif control.type == "p_max_u_consumption": + u_min = control._u_min + u_down = control._u_down + x = np.array([u_min, u_down, v_min, v_max], dtype=float) + y = np.zeros_like(x, dtype=float) + y[x < u_min] = 0 + y[x >= u_down] = s_max + mask = np.logical_and(u_min <= x, x < u_down) + y[mask] = s_max * (x[mask] - u_min) / (u_down - u_min) + x_ticks = np.array( + [ + f"{u_min:.1f}\n$U^{{\\min}}$", + f"{u_down:.1f}\n$U^{{\\mathrm{{down}}}}$", + f"{v_min:.1f}", + f"{v_max:.1f}", + ], + dtype=object, + ) + elif control.type == "q_u": + u_min = control._u_min + u_down = control._u_down + u_up = control._u_up + u_max = control._u_max + x = np.array([u_min, u_down, u_up, u_max, v_min, v_max], dtype=float) + y = np.zeros_like(x, dtype=float) + y[x < u_min] = -s_max + mask = np.logical_and(u_min <= x, x < u_down) + y[mask] = -s_max * (x[mask] - u_down) / (u_min - u_down) + y[np.logical_and(u_down <= x, x < u_up)] = 0 + mask = np.logical_and(u_up <= x, x < u_max) + y[mask] = s_max * (x[mask] - u_up) / (u_max - u_up) + y[x >= u_max] = s_max + x_ticks = np.array( + [ + f"{u_min:.1f}\n$U^{{\\min}}$", + f"{u_down:.1f}\n$U^{{\\mathrm{{down}}}}$", + f"{u_up:.1f}\n$U^{{\\mathrm{{up}}}}$", + f"{u_max:.1f}\n$U^{{\\max}}$", + f"{v_min:.1f}", + f"{v_max:.1f}", + ], + dtype=object, + ) + else: # pragma: no-cover + msg = f"Unsupported control type {control.type!r}" + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_CONTROL_TYPE) + + # Sort everything according to the voltages + sort_index = np.argsort(x) + x = x[sort_index] + y = y[sort_index] + x_ticks = x_ticks[sort_index] + + return x, y, x_ticks diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index babd5714..4f953da1 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -17,7 +17,6 @@ import requests from pyproj import CRS from requests import Response -from requests.auth import HTTPBasicAuth from rich.table import Table from typing_extensions import Self @@ -37,7 +36,7 @@ VoltageSource, ) from roseau.load_flow.solvers import check_solver_params -from roseau.load_flow.typing import Id, JsonDict, Solver, StrPath +from roseau.load_flow.typing import Authentication, Id, JsonDict, Solver, StrPath from roseau.load_flow.utils import CatalogueMixin, JsonMixin, console logger = logging.getLogger(__name__) @@ -357,7 +356,7 @@ def short_circuits_frame(self) -> pd.DataFrame: # def solve_load_flow( self, - auth: Union[tuple[str, str], HTTPBasicAuth], + auth: Authentication, base_url: str = _DEFAULT_BASE_URL, max_iterations: int = _DEFAULT_MAX_ITERATIONS, tolerance: float = _DEFAULT_TOLERANCE, diff --git a/roseau/load_flow/typing.py b/roseau/load_flow/typing.py index 52c8a293..0c0e5c11 100644 --- a/roseau/load_flow/typing.py +++ b/roseau/load_flow/typing.py @@ -24,10 +24,15 @@ .. class:: Solver Available solvers for the load flow computation. + +.. class:: Authentication + + Valid authentication objects """ import os from typing import Any, Literal, Union +from requests.auth import HTTPBasicAuth from typing_extensions import TypeAlias Id: TypeAlias = Union[int, str] @@ -36,6 +41,7 @@ ControlType: TypeAlias = Literal["constant", "p_max_u_production", "p_max_u_consumption", "q_u"] ProjectionType: TypeAlias = Literal["euclidean", "keep_p", "keep_q"] Solver: TypeAlias = Literal["newton", "newton_goldstein"] +Authentication: TypeAlias = Union[tuple[str, str], HTTPBasicAuth] -__all__ = ["Id", "JsonDict", "StrPath", "ControlType", "ProjectionType", "Solver"] +__all__ = ["Id", "JsonDict", "StrPath", "ControlType", "ProjectionType", "Solver", "Authentication"] From 369e9ed0938dd7cb72c0bc6353831948560e045c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 19 Sep 2023 17:16:34 +0200 Subject: [PATCH 13/43] Add tests --- poetry.lock | 2 +- pyproject.toml | 1 + .../models/loads/flexible_parameters.py | 6 +- .../models/tests/test_flexible_parameters.py | 115 ++++++++++++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index ab748975..e0dcea74 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2696,4 +2696,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "de4181680060f36444109dc1ffd00f53fb6c40d7da4833a301c99c1c1e9d4c9d" +content-hash = "000f170e994a7fbd25ff959cbe475b07ef87ecb11d904d2461f8a4648561a25c" diff --git a/pyproject.toml b/pyproject.toml index e58039c5..b05938c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ pytest-cov = "^4.0.0" pytest-xdist = "^3.1.0" requests-mock = "^1.9.3" coverage = { version = "^7.0.5", extras = ["toml"] } +matplotlib = "^3.7.2" [tool.poetry.group.dev.dependencies] pre-commit = "^3.0.0" diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index fae73aa4..fbc3fc53 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -901,7 +901,7 @@ def _compute_powers( return np.array(res_flexible_powers, dtype=complex) - @ureg_wraps(None, (None, None, "V", "VA", None, None, None, "VA"), strict=False) + @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, None, "VA"), strict=False) def plot_pq( self, auth: Authentication, @@ -1020,7 +1020,7 @@ def plot_pq( return ax, res_flexible_powers - @ureg_wraps(None, (None, None, "V", "VA", None, None, "VA"), strict=False) + @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, "VA"), strict=False) def plot_control_p( self, auth: Authentication, @@ -1092,7 +1092,7 @@ def plot_control_p( return ax, res_flexible_powers - @ureg_wraps(None, (None, None, "V", "VA", None, None, "VA"), strict=False) + @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, "VA"), strict=False) def plot_control_q( self, auth: Authentication, diff --git a/roseau/load_flow/models/tests/test_flexible_parameters.py b/roseau/load_flow/models/tests/test_flexible_parameters.py index 61f3df91..8b82bb97 100644 --- a/roseau/load_flow/models/tests/test_flexible_parameters.py +++ b/roseau/load_flow/models/tests/test_flexible_parameters.py @@ -1,11 +1,17 @@ import warnings +from contextlib import contextmanager +import numpy as np +import numpy.testing as npt import pytest +from matplotlib import pyplot as plt from roseau.load_flow import ( Q_, Control, + ElectricalNetwork, FlexibleParameter, + PowerLoad, Projection, RoseauLoadFlowException, RoseauLoadFlowExceptionCode, @@ -195,3 +201,112 @@ def test_flexible_parameter(): ) assert e.value.msg == "'s_max' must be greater than 0 but -1.0 MVA was provided." assert e.value.code == RoseauLoadFlowExceptionCode.BAD_SMAX_VALUE + + +@pytest.fixture(params=["constant", "p_max_u_production", "p_max_u_consumption"]) +def control_p(request) -> Control: + if request.param == "constant": + return Control.constant() + elif request.param == "p_max_u_production": + return Control.p_max_u_production(u_up=Q_(240, "V"), u_max=Q_(250, "V")) + elif request.param == "p_max_u_consumption": + return Control.p_max_u_production(u_up=Q_(210, "V"), u_max=Q_(220, "V")) + raise NotImplementedError(request.param) + + +@pytest.fixture(params=["constant", "q_u"]) +def control_q(request) -> Control: + if request.param == "constant": + return Control.constant() + elif request.param == "q_u": + return Control.q_u(u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V")) + raise NotImplementedError(request.param) + + +@pytest.fixture(params=["keep_p", "keep_q", "euclidean"]) +def projection(request) -> Projection: + return Projection(type=request.param) + + +@pytest.fixture() +def flexible_parameter(control_p, control_q, projection): + return FlexibleParameter(control_p=control_p, control_q=control_q, projection=projection, s_max=Q_(5, "kVA")) + + +@pytest.fixture() +def monkeypatch_flexible_parameter_compute_powers(rg): + @contextmanager + def inner(): + with pytest.MonkeyPatch.context() as m: + m.setattr(target=ElectricalNetwork, name="solve_load_flow", value=lambda *args, **kwargs: 2) + m.setattr( + target=PowerLoad, + name="res_flexible_powers", + value=property( + lambda x: Q_([rg.normal(loc=-2500, scale=1000) + 1j * rg.normal(loc=0, scale=2500)], "VA") + ), + ) + yield m + + return inner + + +def test_plot(flexible_parameter, monkeypatch_flexible_parameter_compute_powers): + voltages = np.array(range(205, 256, 1), dtype=float) + power = Q_(-2.5 + 1j, "kVA") + auth = ("username", "password") + + # + # Test compute powers + # + with monkeypatch_flexible_parameter_compute_powers(): + res_flexible_powers = flexible_parameter.compute_powers(auth=auth, voltages=voltages, power=power) + + # + # Plot control P + # + fig, ax = plt.subplots() + ax, res_flexible_powers_1 = flexible_parameter.plot_control_p( + auth=auth, voltages=voltages, power=power, res_flexible_powers=res_flexible_powers, ax=ax + ) + npt.assert_allclose(res_flexible_powers, res_flexible_powers_1) + + # The same but do not provide the res_flexible_powers + fig, ax = plt.subplots() + with monkeypatch_flexible_parameter_compute_powers(): + ax, res_flexible_powers_2 = flexible_parameter.plot_control_p(auth=auth, voltages=voltages, power=power, ax=ax) + assert not np.allclose(res_flexible_powers, res_flexible_powers_2) + + # Plot control Q + ax, res_flexible_powers = flexible_parameter.plot_control_q( + auth=auth, voltages=voltages, power=power, res_flexible_powers=res_flexible_powers, ax=ax + ) + + # The same but do not provide the res_flexible_powers + fig, ax = plt.subplots() + with monkeypatch_flexible_parameter_compute_powers(): + ax, res_flexible_powers_3 = flexible_parameter.plot_control_q(auth=auth, voltages=voltages, power=power, ax=ax) + assert not np.allclose(res_flexible_powers, res_flexible_powers_3) + + # Plot trajectory in the (P, Q) plane + fig, ax = plt.subplots() + ax, res_flexible_powers_4 = flexible_parameter.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [240, 250]), + ax=ax, + ) + npt.assert_allclose(res_flexible_powers, res_flexible_powers_4) + + # The same but do not provide the res_flexible_powers + fig, ax = plt.subplots() # Create a new ax that is not used directly in the following function call + with monkeypatch_flexible_parameter_compute_powers(): + ax, res_flexible_powers_5 = flexible_parameter.plot_pq( + auth=auth, + voltages=voltages, + power=power, + voltages_labels_mask=np.isin(voltages, [240, 250]), + ) + assert not np.allclose(res_flexible_powers, res_flexible_powers_5) From 41e45c92299298b27837467137f05780d667fe91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 19 Sep 2023 17:29:54 +0200 Subject: [PATCH 14/43] Fill the changelog --- .pre-commit-config.yaml | 2 +- doc/Changelog.md | 7 +++++++ poetry.lock | 38 +++++++++++++++++++------------------- pyproject.toml | 2 +- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5914a31b..7273267c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: hooks: - id: black-jupyter - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.289 # keep in sync with pyproject.toml + rev: v0.0.290 # keep in sync with pyproject.toml hooks: - id: ruff types_or: [python, pyi, jupyter] diff --git a/doc/Changelog.md b/doc/Changelog.md index 1ad7d719..7e40b632 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,13 @@ **In development** +- {gh-pr}`131` {gh-issue}`127` Improve the documentation of the flexible loads. + - Add the method `compute_powers` method to the `FlexibleParameter` class to compute the resulting flexible powers + for a given theoretical power and a list of voltage norms. + - Add the `plot_control_p`, `plot_control_q` and `plot_pq` methods to the `FlexibleParameter` class to plot the + control curves and control trajectories. + - Add the extra `plot` to install `matplotlib` alongside `roseau-load-flow`. +- {gh-pr}`131` Correction of a bug in the error message of the powers setter method. - {gh-pr}`130` Mark some internal attributes as private, they were previously marked as public. - {gh-pr}`128` Add the properties `z_line`, `y_shunt` and `with_shunt` to the `Line` class. - {gh-pr}`125` Speed-up build of conda workflow using mamba. diff --git a/poetry.lock b/poetry.lock index e0dcea74..f0bef53e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2059,28 +2059,28 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.0.289" +version = "0.0.290" description = "An extremely fast Python linter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.0.289-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:c9a89d748e90c840bac9c37afe90cf13a5bfd460ca02ea93dad9d7bee3af03b4"}, - {file = "ruff-0.0.289-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:7f7396c6ea01ba332a6ad9d47642bac25d16bd2076aaa595b001f58b2f32ff05"}, - {file = "ruff-0.0.289-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7180de86c8ecd39624dec1699136f941c07e723201b4ce979bec9e7c67b40ad2"}, - {file = "ruff-0.0.289-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:73f37c65508203dd01a539926375a10243769c20d4fcab3fa6359cd3fbfc54b7"}, - {file = "ruff-0.0.289-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c14abcd7563b5c80be2dd809eeab20e4aa716bf849860b60a22d87ddf19eb88"}, - {file = "ruff-0.0.289-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:91b6d63b6b46d4707916472c91baa87aa0592e73f62a80ff55efdf6c0668cfd6"}, - {file = "ruff-0.0.289-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6479b8c4be3c36046c6c92054762b276fa0fddb03f6b9a310fbbf4c4951267fd"}, - {file = "ruff-0.0.289-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5424318c254bcb091cb67e140ec9b9f7122074e100b06236f252923fb41e767"}, - {file = "ruff-0.0.289-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4daa90865796aedcedf0d8897fdd4cd09bf0ddd3504529a4ccf211edcaff3c7d"}, - {file = "ruff-0.0.289-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8057e8ab0016c13b9419bad119e854f881e687bd96bc5e2d52c8baac0f278a44"}, - {file = "ruff-0.0.289-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7eebfab2e6a6991908ff1bf82f2dc1e5095fc7e316848e62124526837b445f4d"}, - {file = "ruff-0.0.289-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ebc7af550018001a7fb39ca22cdce20e1a0de4388ea4a007eb5c822f6188c297"}, - {file = "ruff-0.0.289-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6e4e6eccb753efe760ba354fc8e9f783f6bba71aa9f592756f5bd0d78db898ed"}, - {file = "ruff-0.0.289-py3-none-win32.whl", hash = "sha256:bbb3044f931c09cf17dbe5b339896eece0d6ac10c9a86e172540fcdb1974f2b7"}, - {file = "ruff-0.0.289-py3-none-win_amd64.whl", hash = "sha256:6d043c5456b792be2615a52f16056c3cf6c40506ce1f2d6f9d3083cfcb9eeab6"}, - {file = "ruff-0.0.289-py3-none-win_arm64.whl", hash = "sha256:04a720bcca5e987426bb14ad8b9c6f55e259ea774da1cbeafe71569744cfd20a"}, - {file = "ruff-0.0.289.tar.gz", hash = "sha256:2513f853b0fc42f0339b7ab0d2751b63ce7a50a0032d2689b54b2931b3b866d7"}, + {file = "ruff-0.0.290-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:0e2b09ac4213b11a3520221083866a5816616f3ae9da123037b8ab275066fbac"}, + {file = "ruff-0.0.290-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:4ca6285aa77b3d966be32c9a3cd531655b3d4a0171e1f9bf26d66d0372186767"}, + {file = "ruff-0.0.290-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35e3550d1d9f2157b0fcc77670f7bb59154f223bff281766e61bdd1dd854e0c5"}, + {file = "ruff-0.0.290-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d748c8bd97874f5751aed73e8dde379ce32d16338123d07c18b25c9a2796574a"}, + {file = "ruff-0.0.290-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:982af5ec67cecd099e2ef5e238650407fb40d56304910102d054c109f390bf3c"}, + {file = "ruff-0.0.290-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bbd37352cea4ee007c48a44c9bc45a21f7ba70a57edfe46842e346651e2b995a"}, + {file = "ruff-0.0.290-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d9be6351b7889462912e0b8185a260c0219c35dfd920fb490c7f256f1d8313e"}, + {file = "ruff-0.0.290-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75cdc7fe32dcf33b7cec306707552dda54632ac29402775b9e212a3c16aad5e6"}, + {file = "ruff-0.0.290-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb07f37f7aecdbbc91d759c0c09870ce0fb3eed4025eebedf9c4b98c69abd527"}, + {file = "ruff-0.0.290-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2ab41bc0ba359d3f715fc7b705bdeef19c0461351306b70a4e247f836b9350ed"}, + {file = "ruff-0.0.290-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:150bf8050214cea5b990945b66433bf9a5e0cef395c9bc0f50569e7de7540c86"}, + {file = "ruff-0.0.290-py3-none-musllinux_1_2_i686.whl", hash = "sha256:75386ebc15fe5467248c039f5bf6a0cfe7bfc619ffbb8cd62406cd8811815fca"}, + {file = "ruff-0.0.290-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ac93eadf07bc4ab4c48d8bb4e427bf0f58f3a9c578862eb85d99d704669f5da0"}, + {file = "ruff-0.0.290-py3-none-win32.whl", hash = "sha256:461fbd1fb9ca806d4e3d5c745a30e185f7cf3ca77293cdc17abb2f2a990ad3f7"}, + {file = "ruff-0.0.290-py3-none-win_amd64.whl", hash = "sha256:f1f49f5ec967fd5778813780b12a5650ab0ebcb9ddcca28d642c689b36920796"}, + {file = "ruff-0.0.290-py3-none-win_arm64.whl", hash = "sha256:ae5a92dfbdf1f0c689433c223f8dac0782c2b2584bd502dfdbc76475669f1ba1"}, + {file = "ruff-0.0.290.tar.gz", hash = "sha256:949fecbc5467bb11b8db810a7fa53c7e02633856ee6bd1302b2f43adcd71b88d"}, ] [[package]] @@ -2696,4 +2696,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "000f170e994a7fbd25ff959cbe475b07ef87ecb11d904d2461f8a4648561a25c" +content-hash = "7463ecbe37dbd7a88a8ef0615336f51b2f3e29f898e0e3820b595483115ee5f3" diff --git a/pyproject.toml b/pyproject.toml index b05938c2..b6c13df2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ matplotlib = "^3.7.2" [tool.poetry.group.dev.dependencies] pre-commit = "^3.0.0" black = { version = "==23.9.1", extras = ["jupyter"] } # keep in sync with .pre-commit-config.yaml -ruff = "==0.0.289" # keep in sync with .pre-commit-config.yaml +ruff = "==0.0.290" # keep in sync with .pre-commit-config.yaml [tool.poetry.group.doc.dependencies] sphinx = "^7.0.1" From ecab3e2ac8f2ff6131e3f1282c585a2537668b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 19 Sep 2023 17:50:34 +0200 Subject: [PATCH 15/43] Correction of the tests --- roseau/load_flow/models/loads/flexible_parameters.py | 2 +- roseau/load_flow/models/tests/test_flexible_parameters.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index fbc3fc53..e630a0cd 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -494,7 +494,7 @@ def constant(cls) -> Self: return cls( control_p=cls._control_class.constant(), control_q=cls._control_class.constant(), - projection=cls._projection_class(type=cls._projection_class.DEFAULT_TYPE), + projection=cls._projection_class(type=cls._projection_class._DEFAULT_TYPE), s_max=1.0, ) diff --git a/roseau/load_flow/models/tests/test_flexible_parameters.py b/roseau/load_flow/models/tests/test_flexible_parameters.py index 8b82bb97..e2a5ada4 100644 --- a/roseau/load_flow/models/tests/test_flexible_parameters.py +++ b/roseau/load_flow/models/tests/test_flexible_parameters.py @@ -234,10 +234,11 @@ def flexible_parameter(control_p, control_q, projection): @pytest.fixture() -def monkeypatch_flexible_parameter_compute_powers(rg): +def monkeypatch_flexible_parameter_compute_powers(monkeypatch, rg): @contextmanager def inner(): - with pytest.MonkeyPatch.context() as m: + nonlocal monkeypatch + with monkeypatch.context() as m: m.setattr(target=ElectricalNetwork, name="solve_load_flow", value=lambda *args, **kwargs: 2) m.setattr( target=PowerLoad, From 48eb36def17770bf26eb898e9e14bd7003e82b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 19 Sep 2023 18:09:45 +0200 Subject: [PATCH 16/43] Typo --- roseau/load_flow/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index 4f953da1..dfde9152 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -669,7 +669,7 @@ def res_branches(self) -> pd.DataFrame: @property def res_lines(self) -> pd.DataFrame: - """The load flow results of the the network lines. + """The load flow results of the network lines. This is similar to the :attr:`res_branches` property but provides more information that only apply to lines. This includes currents and complex power losses in the series From 08f28c3dc086684bf8f3eea40daf1d1ba5f73048 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Wed, 20 Sep 2023 09:15:03 +0200 Subject: [PATCH 17/43] Add a doc page about converters and constants (#132) Resolves #101 --- doc/Changelog.md | 1 + doc/usage/Extras.md | 103 ++++++++++++++++++++++++++++ doc/usage/index.md | 1 + roseau/load_flow/utils/constants.py | 8 +-- 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 doc/usage/Extras.md diff --git a/doc/Changelog.md b/doc/Changelog.md index 1ad7d719..cd6c232a 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,7 @@ **In development** +- {gh-pr}`132` {gh-issue}`101` Document extra utilities including converters and constants. - {gh-pr}`130` Mark some internal attributes as private, they were previously marked as public. - {gh-pr}`128` Add the properties `z_line`, `y_shunt` and `with_shunt` to the `Line` class. - {gh-pr}`125` Speed-up build of conda workflow using mamba. diff --git a/doc/usage/Extras.md b/doc/usage/Extras.md new file mode 100644 index 00000000..f185bdbe --- /dev/null +++ b/doc/usage/Extras.md @@ -0,0 +1,103 @@ +# Extras + +`roseau-load-flow` comes with some extra features that can be useful for some users. + +## Conversion to symmetrical components + +{mod}`roseau.load_flow.converters` contains helpers to convert between phasor and symmetrical +components. For example, to convert a phasor voltage to symmetrical components: + +```pycon +>>> import numpy as np +>>> from roseau.load_flow.converters import phasor_to_sym, sym_to_phasor +>>> v = 230 * np.exp([0, -2j * np.pi / 3, 2j * np.pi / 3]) +>>> v +array([ 230. +0.j , -115.-199.18584287j, -115.+199.18584287j]) +>>> v_sym = phasor_to_sym(v) +>>> v_sym +array([[ 8.52651283e-14-1.42108547e-14j], + [ 2.30000000e+02+4.19109192e-14j], + [-7.10542736e-14-2.84217094e-14j]]) +``` + +As you can see, for this positive-sequence balanced voltage, only the positive-sequence component +is non-zero. Converting back to phasor, you get the original voltage values back: + +```pycon +>>> sym_to_phasor(v_sym) +array([[ 230.-7.21644966e-16j], + [-115.-1.99185843e+02j], + [-115.+1.99185843e+02j]]) +``` + +You can also convert pandas Series to symmetrical components. If we take the example network of the +[Getting Started](Getting_Started.md) page: + +```pycon +>>> from roseau.load_flow.converters import series_phasor_to_sym +>>> series_phasor_to_sym(en.res_buses_voltages["voltage"]) +bus_id sequence +lb zero 8.526513e-14-1.421085e-14j + pos 2.219282e+02+4.167975e-14j + neg -5.684342e-14-2.842171e-14j +sb zero 9.947598e-14-1.421085e-14j + pos 2.309401e+02+3.483159e-14j + neg -4.263256e-14-2.842171e-14j +Name: voltage, dtype: complex128 +``` + +## Potentials to voltages conversion + +{mod}`roseau.load_flow.converters` also contains helpers to convert a vector of potentials to a +vector of voltages. Example: + +```pycon +>>> import numpy as np +>>> from roseau.load_flow.converters import calculate_voltages, calculate_voltage_phases +>>> potentials = 230 * np.array([1, np.exp(-2j * np.pi / 3), np.exp(2j * np.pi / 3), 0]) +>>> potentials +array([ 230. +0.j , -115.-199.18584287j, -115.+199.18584287j, + 0. +0.j ]) +>>> phases = "abcn" +>>> calculate_voltages(potentials, phases) +array([ 230. +0.j , -115.-199.18584287j, -115.+199.18584287j]) +``` + +Because the phases include the neutral, the voltages calculated are phase-to-neutral voltages. +You can also calculate phase-to-phase voltages by omitting the neutral: + +```pycon +>>> calculate_voltages(potentials[:-1], phases[:-1]) +array([ 345.+199.18584287j, 0.-398.37168574j, -345.+199.18584287j]) +``` + +To get the phases of the voltage, you can use `calculate_voltage_phases`: + +```pycon +>>> calculate_voltage_phases(phases) +['an', 'bn', 'cn'] +``` + +Of course these functions work with arbitrary phases: + +```pycon +>>> calculate_voltages(potentials[:2], phases[:2]) +array([345.+199.18584287j]) +>>> calculate_voltage_phases(phases[:2]) +['ab'] +>>> calculate_voltage_phases("abc") +['ab', 'bc', 'ca'] +>>> calculate_voltage_phases("bc") +['bc'] +>>> calculate_voltage_phases("bcn") +['bn', 'cn'] +``` + +## Constants + +{mod}`roseau.load_flow.utils.constants` contains some common constants like the resistivity +and permeability of common conductor types in addition to other useful constants. Please refer to +the module documentation for more details. + +An enumeration of available conductor types can be found in the {mod}`roseau.load_flow.utils.types` +module. diff --git a/doc/usage/index.md b/doc/usage/index.md index 05695cd9..664f16cc 100644 --- a/doc/usage/index.md +++ b/doc/usage/index.md @@ -13,4 +13,5 @@ Flexible_Loads Short_Circuit Catalogues Plotting +Extras ``` diff --git a/roseau/load_flow/utils/constants.py b/roseau/load_flow/utils/constants.py index eae33041..c1d7b586 100644 --- a/roseau/load_flow/utils/constants.py +++ b/roseau/load_flow/utils/constants.py @@ -38,8 +38,8 @@ ConductorType.CU: Q_(1.2566e-8, "H/m"), ConductorType.AL: Q_(1.2566e-8, "H/m"), ConductorType.AM: Q_(1.2566e-8, "H/m"), - ConductorType.AA: np.nan, # TODO - ConductorType.LA: np.nan, # TODO + ConductorType.AA: Q_(np.nan, "H/m"), # TODO + ConductorType.LA: Q_(np.nan, "H/m"), # TODO } """Magnetic permeability of common conductor materials (H/m).""" @@ -47,8 +47,8 @@ ConductorType.CU: Q_(9.3, "mm"), ConductorType.AL: Q_(112, "mm"), ConductorType.AM: Q_(12.9, "mm"), - ConductorType.AA: np.nan, # TODO - ConductorType.LA: np.nan, # TODO + ConductorType.AA: Q_(np.nan, "mm"), # TODO + ConductorType.LA: Q_(np.nan, "mm"), # TODO } """Skin effect of common conductor materials (mm).""" From e019e23c418c1df787121aff617037d8dc7a40ee Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Wed, 20 Sep 2023 09:57:37 +0200 Subject: [PATCH 18/43] Better missing matplotlib message, pint warnings, matplotlib warnings --- .../models/loads/flexible_parameters.py | 49 +++++++++---------- .../models/tests/test_flexible_parameters.py | 17 ++++--- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index e630a0cd..b8d784bd 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -13,7 +13,20 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: - from matplotlib import Axes + from matplotlib.axes import Axes + + +def _import_matplotlib_pyplot(): + try: + import matplotlib.pyplot + except ImportError as e: + msg = ( + 'matplotlib is required for plotting. Install it with the "plot" extra using ' + '`pip install -U "roseau-load-flow[plot]"`' + ) + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from e + return matplotlib.pyplot class Control(JsonMixin): @@ -941,18 +954,12 @@ def plot_pq( The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else the computed values). """ - try: - from matplotlib import colormaps, patheffects - from matplotlib import pyplot as plt - from matplotlib.pyplot import Axes - except ImportError: - msg = 'The extra dependency "plot" is required. Please use `pip install -U roseau-load-flow[plot]`.' - logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from None + plt = _import_matplotlib_pyplot() # this line first for better error handling + from matplotlib import colormaps, patheffects # Get the axes if ax is None: - ax: Axes = plt.gca() + ax: "Axes" = plt.gca() # Initialise some variables if voltages_labels_mask is None: @@ -1055,17 +1062,11 @@ def plot_control_p( The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else the computed values). """ - try: - from matplotlib import pyplot as plt - from matplotlib.pyplot import Axes - except ImportError: - msg = 'The extra dependency "plot" is required. Please use `pip install -U roseau-load-flow[plot]`.' - logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from None + plt = _import_matplotlib_pyplot() # Get the axes if ax is None: - ax: Axes = plt.gca() + ax: "Axes" = plt.gca() # Depending on the type of the control, several options x, y, x_ticks = self._theoretical_control_data( @@ -1127,17 +1128,11 @@ def plot_control_q( The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else the computed values). """ - try: - from matplotlib import pyplot as plt - from matplotlib.pyplot import Axes - except ImportError: - msg = 'The extra dependency "plot" is required. Please use `pip install -U roseau-load-flow[plot]`.' - logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from None + plt = _import_matplotlib_pyplot() # Get the axes if ax is None: - ax: Axes = plt.gca() + ax: "Axes" = plt.gca() # Depending on the type of the control, several options x, y, x_ticks = self._theoretical_control_data( @@ -1191,7 +1186,7 @@ def _theoretical_control_data( The `s_max` parameter to scale the control functions. Returns: - The x- and y-values of the theoretical control function with x tixks to use for the plot. + The x- and y-values of the theoretical control function with x-ticks to use for the plot. """ # Depending on the type of the control, several options if control.type == "constant": diff --git a/roseau/load_flow/models/tests/test_flexible_parameters.py b/roseau/load_flow/models/tests/test_flexible_parameters.py index e2a5ada4..5d91abd4 100644 --- a/roseau/load_flow/models/tests/test_flexible_parameters.py +++ b/roseau/load_flow/models/tests/test_flexible_parameters.py @@ -229,7 +229,7 @@ def projection(request) -> Projection: @pytest.fixture() -def flexible_parameter(control_p, control_q, projection): +def flexible_parameter(control_p, control_q, projection) -> FlexibleParameter: return FlexibleParameter(control_p=control_p, control_q=control_q, projection=projection, s_max=Q_(5, "kVA")) @@ -270,13 +270,15 @@ def test_plot(flexible_parameter, monkeypatch_flexible_parameter_compute_powers) ax, res_flexible_powers_1 = flexible_parameter.plot_control_p( auth=auth, voltages=voltages, power=power, res_flexible_powers=res_flexible_powers, ax=ax ) - npt.assert_allclose(res_flexible_powers, res_flexible_powers_1) + npt.assert_allclose(res_flexible_powers.m_as("VA"), res_flexible_powers_1.m_as("VA")) + plt.close(fig) # The same but do not provide the res_flexible_powers fig, ax = plt.subplots() with monkeypatch_flexible_parameter_compute_powers(): ax, res_flexible_powers_2 = flexible_parameter.plot_control_p(auth=auth, voltages=voltages, power=power, ax=ax) - assert not np.allclose(res_flexible_powers, res_flexible_powers_2) + assert not np.allclose(res_flexible_powers.m_as("VA"), res_flexible_powers_2.m_as("VA")) + plt.close(fig) # Plot control Q ax, res_flexible_powers = flexible_parameter.plot_control_q( @@ -287,7 +289,8 @@ def test_plot(flexible_parameter, monkeypatch_flexible_parameter_compute_powers) fig, ax = plt.subplots() with monkeypatch_flexible_parameter_compute_powers(): ax, res_flexible_powers_3 = flexible_parameter.plot_control_q(auth=auth, voltages=voltages, power=power, ax=ax) - assert not np.allclose(res_flexible_powers, res_flexible_powers_3) + assert not np.allclose(res_flexible_powers.m_as("VA"), res_flexible_powers_3.m_as("VA")) + plt.close(fig) # Plot trajectory in the (P, Q) plane fig, ax = plt.subplots() @@ -299,7 +302,8 @@ def test_plot(flexible_parameter, monkeypatch_flexible_parameter_compute_powers) voltages_labels_mask=np.isin(voltages, [240, 250]), ax=ax, ) - npt.assert_allclose(res_flexible_powers, res_flexible_powers_4) + npt.assert_allclose(res_flexible_powers.m_as("VA"), res_flexible_powers_4.m_as("VA")) + plt.close(fig) # The same but do not provide the res_flexible_powers fig, ax = plt.subplots() # Create a new ax that is not used directly in the following function call @@ -310,4 +314,5 @@ def test_plot(flexible_parameter, monkeypatch_flexible_parameter_compute_powers) power=power, voltages_labels_mask=np.isin(voltages, [240, 250]), ) - assert not np.allclose(res_flexible_powers, res_flexible_powers_5) + assert not np.allclose(res_flexible_powers.m_as("VA"), res_flexible_powers_5.m_as("VA")) + plt.close(fig) From 1abae9f3325dd7230cf990e96ffaee9b08551d06 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Wed, 20 Sep 2023 17:09:40 +0200 Subject: [PATCH 19/43] Some minor improvements * Replace the term "effective power" by "actual power" * A few grammatical changes * Fix some dead links in the flexible parameter docstring --- .../Pconst_QU_Eucl_Control_Curve_Example.svg | 119 ++++---- .../Pconst_QU_P_Control_Curve_Example.svg | 119 ++++---- .../Pconst_QU_Q_Control_Curve_Example.svg | 119 ++++---- .../PmaxU_Qconst_Control_Curve_Example.svg | 119 ++++---- .../Pconst_QU_Eucl_Control_Curve_Example.tex | 2 +- .../Pconst_QU_P_Control_Curve_Example.tex | 2 +- .../Pconst_QU_Q_Control_Curve_Example.tex | 2 +- .../PmaxU_Qconst_Control_Curve_Example.tex | 2 +- .../Load/FlexibleLoad/FeasibleDomain.md | 277 +++++++++--------- .../Load/FlexibleLoad/FlexibleParameter.md | 2 +- doc/models/Load/FlexibleLoad/Projection.md | 18 +- doc/models/Load/FlexibleLoad/index.md | 2 +- .../models/loads/flexible_parameters.py | 18 +- roseau/load_flow/typing.py | 2 +- 14 files changed, 386 insertions(+), 417 deletions(-) diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg index 61255866..93e9ed0c 100644 --- a/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg @@ -132,43 +132,40 @@ - + - + - + - + - + - + - + - + - + - + - + - - - - + @@ -504,84 +501,78 @@ - - - - - - - - + + - - - - - + - + + + + + - - + + - + - - + + - - + + - + - - - - - - - + + + + + + + - - + + - - - - - + + + + + - + - - - - - + + + + + - + - - + + - - + + - - + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg index 50485eed..b7f741e7 100644 --- a/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg @@ -132,43 +132,40 @@ - + - + - + - + - + - + - + - + - + - + - + - - - - + @@ -504,84 +501,78 @@ - - - - - - - - + + - - - - - + - + + + + + - - + + - + - - + + - - + + - + - - - - - - - + + + + + + + - - + + - - - - - + + + + + - + - - - - - + + + + + - + - - + + - - + + - - + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg index 32685db8..f0c87749 100644 --- a/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg @@ -132,43 +132,40 @@ - + - + - + - + - + - + - + - + - + - + - + - - - - + @@ -504,84 +501,78 @@ - - - - - - - - + + - - - - - + - + + + + + - - + + - + - - + + - - + + - + - - - - - - - + + + + + + + - - + + - - - - - + + + + + - + - - - - - + + + + + - + - - + + - - + + - - + + diff --git a/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg index ce22094e..e2bdb5e5 100644 --- a/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg +++ b/doc/_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg @@ -114,43 +114,40 @@ - + - + - + - + - + - + - + - + - + - + - + - - - - + @@ -461,84 +458,78 @@ - - - - - - - - + + - - - - - + - + + + + + - - + + - + - - + + - - + + - + - - - - - - - + + + + + + + - - + + - - - - - + + + + + - + - - - - - + + + + + - + - - + + - - + + - - + + diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex index f7e33c4d..de060c90 100644 --- a/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.tex @@ -16,7 +16,7 @@ ylabel={Reactive power (VAr)},% y label style={at={(axis description cs:-0.1,0.5)},anchor=south},% grid=both,% - legend entries={Effective power,Non-smooth theoretical control},% + legend entries={Actual power,Non-smooth theoretical control},% legend style={% legend cell align=left,% legend pos=north west,% diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex index 3a046575..598814a0 100644 --- a/doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.tex @@ -16,7 +16,7 @@ ylabel={Reactive power (VAr)},% y label style={at={(axis description cs:-0.1,0.5)},anchor=south},% grid=both,% - legend entries={Effective power,Non-smooth theoretical control},% + legend entries={Actual power,Non-smooth theoretical control},% legend style={% legend cell align=left,% legend pos=north west,% diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex index f6782305..ebd3d188 100644 --- a/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.tex @@ -16,7 +16,7 @@ ylabel={Reactive power (VAr)},% y label style={at={(axis description cs:-0.1,0.5)},anchor=south},% grid=both,% - legend entries={Effective power,Non-smooth theoretical control},% + legend entries={Actual power,Non-smooth theoretical control},% legend style={% legend cell align=left,% legend pos=north west,% diff --git a/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex index 0051175c..21e5b922 100644 --- a/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex +++ b/doc/images/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.tex @@ -16,7 +16,7 @@ ylabel={Active power (W)},% y label style={at={(axis description cs:-0.15,0.5)},anchor=south},% grid=both,% - legend entries={Effective power,Non-smooth theoretical control},% + legend entries={Actual power,Non-smooth theoretical control},% legend style={% legend cell align=left,% legend pos=north west,% diff --git a/doc/models/Load/FlexibleLoad/FeasibleDomain.md b/doc/models/Load/FlexibleLoad/FeasibleDomain.md index dc612498..f7f69666 100644 --- a/doc/models/Load/FlexibleLoad/FeasibleDomain.md +++ b/doc/models/Load/FlexibleLoad/FeasibleDomain.md @@ -2,7 +2,7 @@ # Feasible domains -Depending on the mix of controls and projection used through the class `FlexibleParameter`, the feasible domains in +Depending on the mix of controls and projection used through the class `FlexibleParameter`, the feasible domain in the $(P, Q)$ space changes. ```{note} @@ -13,7 +13,7 @@ On this page, all the images are drawn for a producer so $P^{\text{th.}}\leqslan If there is no control at all, i.e. the `flexible_params` argument is **not** given to the `PowerLoad` constructor or `constant` control used for both active and reactive powers, the consumed (or produced) power will be the one -provided by the user, noted $\underline{S^{\mathrm{th.}}}=P^{\mathrm{th.}}+jQ^{\mathrm{th.}}$. The feasible domain +provided to the load, noted $\underline{S^{\mathrm{th.}}}=P^{\mathrm{th.}}+jQ^{\mathrm{th.}}$. The feasible domain is reduced to a single point as depicted in the figure below. ```{image} /_static/Load/FlexibleLoad/Domain_Pconst_Qconst.svg @@ -114,12 +114,11 @@ vs.res_powers ## Active power control only -When the reactive power is constant, only the active power may be modulated by the local voltage. Thus, the active -power may vary between 0 and $P^{\mathrm{th.}}$ (if the load is a consumer i.e. $P^{\mathrm{th.}}\geqslant 0$) or -between $P^{\mathrm{th.}}$ and 0 (if the load is a producer i.e. $P^{\mathrm{th.}}\leqslant0$). +When the reactive power is constant, only the active power changes as a function of the local +voltage. Thus, the active power may vary between 0 and $P^{\mathrm{th.}}$. -When a control is activated for a load, the theoretical power can not be outside the disc of radius $S^{\max}$. Here -is a small example of such error: +When a control is activated, the load's "theoretical" power **must** always be inside the disc of +radius $S^{\max}$, otherwise an error is thrown: ```python import numpy as np @@ -140,23 +139,20 @@ fp = FlexibleParameter( load = PowerLoad( id="load", bus=bus, - powers=Q_( - np.array([-5 + 5j], dtype=complex), "kVA" - ), # Point outside the circle of radius s_max + powers=Q_(np.array([-5 + 5j], dtype=complex), "kVA"), # > s_max flexible_params=[fp], ) # RoseauLoadFlowException: The power is greater than the parameter s_max # for flexible load "load" [bad_s_value] ``` -Thus, the given $\underline{S^{\text{th.}}}=P^{\text{th.}}+jQ^{\text{th.}}$ lies in the disk of radius $S^{\max}$. -The resulting flexible power is the minimum absolute value between, on the one hand, the active power control function -(which takes values between 0 and 1) multiplied by $S^{\max}$ and, on the other hand, $P^{\mathrm{th.}}$. -As a consequence, the resulting power lies in the segment between the points $(0, Q^{\text{th.}})$ and -$(P^{\text{th.}}, Q^{\text{th.}})$. +The active power control algorithm produces a factor between 0 and 1 that gets multiplied by $S^{\max}$. +The resulting flexible power is the minimum absolute value between this result and $P^{\mathrm{th.}}$. +As a consequence, the resulting power lies on the horizontal segment between the points +$(0, Q^{\text{th.}})$ and $(P^{\text{th.}}, Q^{\text{th.}})$. ```{important} -The projection is useless when there is only an active power control as no point can lie outside the disc of radius +The projection is useless when only active power control is applied as no point can lie outside the disc of radius $S^{\max}$. ``` @@ -167,8 +163,13 @@ This domain of feasible points is depicted in the figure below: :align: center ``` -In the `FlexibleParameter` class, there is a method `compute_powers` which allows to compute the resulting voltages -powers +The `FlexibleParameter` class has a method {meth}`~roseau.load_flow.FlexibleParameter.compute_powers` +that allows to compute the resulting powers of the control at different voltage levels for a given +theoretical power. + +In the following example, we define a flexible parameter with a $P(U)$ control, a constant $P$ +projection, and a $5kVA$ maximum power. We want to know what would the control produce for all +voltages between 205 V and 255 V if given a theoretical power of $-2.5 + j$ kVA. ```python import numpy as np @@ -184,7 +185,7 @@ fp = FlexibleParameter( ) # We want to get the res_flexible_powers for a set of voltages norms -voltages = np.array(range(205, 256, 1), dtype=float) +voltages = np.arange(205, 256, dtype=float) # and when the theoretical power is the following power = Q_(-2.5 + 1j, "kVA") @@ -194,22 +195,29 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -Plotting the control curve $P(U)$ using the variables `voltages` and `res_flexible_powers` of the script above leads to -the following plot: +Plotting the control curve $P(U)$ using the variables `voltages` and `res_flexible_powers` of the +example above produces the following plot: ```{image} /_static/Load/FlexibleLoad/PmaxU_Qconst_Control_Curve_Example.svg :width: 700 :align: center ``` -The non-smooth theoretical control function is the control function applied to $S^{\max}$. The effective power has been -plotted using the powers really produced by the load. Below 240 V, there is no variation in the produced power which is -expected. Between 240 V and approximately 245 V, there is no reduction of the produced power because the curtailment +```{note} +Using `compute_powers` actually requests the solver to solve a load flow for each voltage in the list. +It needs an internet connection to access the server and may take some time (similar to the +{meth}`roseau.load_flow.ElectricalNetwork.solve_load_flow` method). +``` + +The non-smooth theoretical control function is the control function applied to $S^{\max}$. The +"Actual power" plotted is the power actually produced by the load for each voltage. Below 240 V, +there is no variation in the produced power which is expected. Between 240 V and approximately +245 V, there is no reduction of the produced power because the curtailment factor (computed from the voltage) times $S^{\max}$ is lower than $P^{\mathrm{th.}}$. As a consequence, -$P^{\mathrm{th.}}$ is produced. Starting at approximately 245 V, the comparison changes and the really produced -power starts to decrease. It reaches 0 W above 250 V. +$P^{\mathrm{th.}}$ is produced. Starting at approximately 245 V, the comparison changes and the +actually produced power starts to decrease until it reaches 0 W at 250 V. -The same plot can be obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -220,35 +228,39 @@ ax, res_flexible_powers = fp.plot_control_p( plt.show() ``` -In the above example, `res_flexible_powers` is provided as input. It could have been forgotten, and the flexible -powers would have been computed by requesting the server. The computed values are retrieved with the axis on which -the plot was drawn. +Note that in this example, `res_flexible_powers` is provided as input to the plotting function. If +it was not provided, the powers would have been computed by requesting the server (using the +`compute_powers()` method above). The method returns a 2-tuple with the _matplotlib axis_ of the +plot and the computed powers. `````{tip} -To install matplotlib along side with roseau-load-flow, you can type +To install _matplotlib_ along side _roseau-load-flow_, you can use the `plot` extra: -````{tab} Linux +````{tab} Linux/MacOS ```console -$ python -m pip install roseau-load-flow[plot] +$ python -m pip install "roseau-load-flow[plot]" ``` ```` ````{tab} Windows -Matplotlib is always installed when `conda` is used. +```doscon +C:> py -m pip install "roseau-load-flow[plot]" +``` ```` +Matplotlib is always installed when `conda` is used. ````` -If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: +If we plot the trajectory of the control in the $(P, Q)$ space, we get: ```{image} /_static/Load/FlexibleLoad/PmaxU_Qconst_Trajectory_Example.svg :width: 700 :align: center ``` -All the points have been plotted (1 per volt between 205 V and 255 V). A lot of points are overlapping. +All the points have been plotted (1 per volt between 205 V and 255 V). Many points overlap. -The same plot could have been obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -267,21 +279,24 @@ plt.show() ## Reactive power control only -When the active power is constant, only the reactive power may be modulated by the local voltage. Thus, the reactive -power may vary between $-S^{\max}$ and $+S^{\max}$. In this segment, there are points outside the disc of radius -$S^{\max}$ (when $P^{\mathrm{th.}}\neq 0$). Those points are projected on the circle of radius $S^{\max}$ and -depending on the projection, the feasible domains change. +When the active power is constant (no $P$ control), only the reactive power changes as a function +of the local voltage. Thus, the reactive power may vary between $-S^{\max}$ and $+S^{\max}$. When +$P^{\mathrm{th.}}\neq 0$, the point $(P, Q) produced by the control might lie outside the disc of +radius $S^{\max}$ (when $P^{\mathrm{th.}}\neq 0$). Those points are projected on the circle of +radius $S^{\max}$ and depending on the projection, the feasible domains change. ### Constant $P$ -If the _constant $P$_ (`keep_p`) projection is chosen, the feasible domain is limited to a segment as defined below. +If the _constant $P$_ (`keep_p`) projection is chosen, the feasible domain is limited to a vertical +segment as shown below. ```{image} /_static/Load/FlexibleLoad/Domain_Pconst_QU_P.svg :width: 300 :align: center ``` -Here is an example of a reactive power control (without active power control) flexible parameter creation: +Here is an example of a flexible parameter with a reactive power control and without active power +control: ```python import numpy as np @@ -299,7 +314,7 @@ fp = FlexibleParameter( ) # We want to get the res_flexible_powers for a set of voltages norms -voltages = np.array(range(205, 256, 1), dtype=float) +voltages = np.arange(205, 256, dtype=float) # and when the theoretical power is the following power = Q_(-2.5, "kVA") @@ -309,21 +324,21 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -At the end of the script, the variable `res_flexible_powers` contains the powers that has been really produced by +The variable `res_flexible_powers` contains the powers that have been actually produced by the flexible load for the voltages stored in the variable named `voltages`. -Plotting the control curve $Q(U)$ lead to the following plot: +Plotting the control curve $Q(U)$ gives: ```{image} /_static/Load/FlexibleLoad/Pconst_QU_P_Control_Curve_Example.svg :width: 700 :align: center ``` -One can remark that, even with a voltage lower than $U^{\min}$ or greater than $U^{\max}$ the available reactive -power (by default taken in the interval $[-S^{\max}, S^{\max}]$) was never totally used because of the choice of the +Notice that, even with a voltage lower than $U^{\min}$ or greater than $U^{\max}$, the available reactive +power (by default taken in the interval $[-S^{\max}, S^{\max}]$) was never fully used because of the choice of the projection. -The same plot can be obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -339,7 +354,7 @@ ax, res_flexible_powers = fp.plot_control_q( plt.show() ``` -If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: +If we plot the trajectory of the control in the $(P, Q)$ space, we get: ```{image} /_static/Load/FlexibleLoad/Pconst_QU_P_Trajectory_Example.svg :width: 700 @@ -350,11 +365,11 @@ As in the previous plot, there is one point per volt from 205 V to 255 V. Severa 1. All the points are aligned on the straight line $P=-2.5$ kVA because it was the power provided to the flexible load and because the projection used was at _Constant P_. -2. One can remark that several points are overlapping for low and high voltages. For these extremities, the +2. Several points are overlapping for low and high voltages. For these extremities, the theoretical control curves would have forced the point of operation to be outside the disc of radius $S^{\max}$ (5 - kVA in the example). + kVA in this example). -The same plot could have been obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -382,11 +397,11 @@ defined below. ``` ```{warning} -Note that using this projection with a constant active power may result in a final active power lower than the one -provided (even 0 W in the worst cases)! +Note that using this projection with a constant active power may result in a final active power +lower than the one provided (could reach 0 W in the worst-case)! ``` -Here is an example the creattion of such control with a constant $Q$ projection: +Here is an example the creation of such control with a constant $Q$ projection: ```python import numpy as np @@ -404,7 +419,7 @@ fp = FlexibleParameter( ) # We want to get the res_flexible_powers for a set of voltages norms -voltages = np.array(range(205, 256, 1), dtype=float) +voltages = np.arange(205, 256, dtype=float) # and when the theoretical power is the following power = Q_(-2.5, "kVA") @@ -414,20 +429,20 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -At the end of the script, the variable `res_flexible_powers` contains the powers that has been really produced by +The variable `res_flexible_powers` contains the powers that have been actually produced by the flexible load for the voltages stored in the variable named `voltages`. -Plotting the control curve $Q(U)$ leads to the following plot: +Plotting the control curve $Q(U)$ gives: ```{image} /_static/Load/FlexibleLoad/Pconst_QU_Q_Control_Curve_Example.svg :width: 700 :align: center ``` -Here, the complete possible range of reactive power was used. Nevertheless, it was achieved with some active power -reduction because of the projection. +Here, the complete possible range of reactive power is used. When the control finds an infeasible +solution, it reduces the active power because the projection type is _Constant Q_. -The same plot can be obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -443,14 +458,14 @@ ax, res_flexible_powers = fp.plot_control_q( plt.show() ``` -If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: +If we plot the trajectory of the control in the $(P, Q)$ space, we get: ```{image} /_static/Load/FlexibleLoad/Pconst_QU_Q_Trajectory_Example.svg :width: 700 :align: center ``` -The same plot could have been obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -467,9 +482,9 @@ ax, res_flexible_powers = fp.plot_pq( plt.show() ``` -One can remark that when the voltages were too low or too high, the projection at constant $Q$ forces us to reduce -the produced active power to ensure a feasible point i.e. a point which is in the disc of radius $S^{\max}$. As -before, there is one point per volt. Several points of operation are overlapping near the coordinates (0,5 kVA) and +Notice that when the voltages were too low or too high, the projection at constant $Q$ forces the +reduction of the produced active power to ensure a feasible solution. Like before, there is one +point per volt. Several points overlap at the extremities near the coordinates (0,5 kVA) and (0, -5 kVA). ### Euclidean projection @@ -487,8 +502,6 @@ Note that using this projection with a constant active power may result in a fin provided! ``` -Here is an example of this usage with a single phase network limited to a single bus: - ```python import numpy as np @@ -505,7 +518,7 @@ fp = FlexibleParameter( ) # We want to get the res_flexible_powers for a set of voltages norms -voltages = np.array(range(205, 256, 1), dtype=float) +voltages = np.arange(205, 256, dtype=float) # and when the theoretical power is the following power = Q_(-2.5, "kVA") @@ -515,10 +528,10 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -At the end of the script, the variable `res_flexible_powers` contains the powers that has been really produced by +The variable `res_flexible_powers` contains the powers that have been really produced by the flexible load for the voltages stored in the variable named `voltages`. -Plotting the control curve $Q(U)$ lead to the following plot: +Plotting the control curve $Q(U)$ gives: ```{image} /_static/Load/FlexibleLoad/Pconst_QU_Eucl_Control_Curve_Example.svg :width: 700 @@ -527,7 +540,7 @@ Plotting the control curve $Q(U)$ lead to the following plot: Here, again the complete reactive power range is not fully used. -The same plot can be obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -543,14 +556,14 @@ ax, res_flexible_powers = fp.plot_control_q( plt.show() ``` -If now, we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: +If we plot the trajectory of the control in the $(P, Q)$ space, we get: ```{image} /_static/Load/FlexibleLoad/Pconst_QU_Eucl_Trajectory_Example.svg :width: 700 :align: center ``` -The same plot could have been obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -567,36 +580,32 @@ ax, res_flexible_powers = fp.plot_pq( plt.show() ``` -One can remark that when the voltages were too low or too high, the Euclidean projection forces us to -reduce the produced active power and the (produced and consumed) reactive power to ensure a feasible point i.e. a point -which is in the disc of radius $S^{\max}$. As before, there is one point per volt thus one can remark that several -points of operation are overlapping. +Notice that when the voltages were too low or too high, the Euclidean projection forces the +reduction of the produced active power and the (produced and consumed) reactive power to ensure a +feasible solution. Like before, there is one point per volt and several points overlap. ## Both active and reactive powers control -When both active and reactive powers are activated, the feasible domains is the following: +When both active and reactive power controls are activated, the feasible domain is the following: ```{image} /_static/Load/FlexibleLoad/Domain_PmaxU_QU.svg :width: 300 :align: center ``` -Every point whose abscissa is between $P^{\mathrm{th.}}$ and 0, whose ordinate is between $-S^{\max}$ and $+S^{\max}$ -and which lies in the disc of radius $S^{\max}$ is reachable. Let's look at two examples: in the first one, the -controls are activated sequentially (reactive power first and then active power) and, in the other example, there -are used together. +Every point whose abscissa is between $P^{\mathrm{th.}}$ and 0, whose ordinate is between $-S^{\max}$ +and $+S^{\max}$ and which lies in the disc of radius $S^{\max}$ (blue shaded area) is reachable. +Let's look at two examples: in the first one, the controls are activated sequentially (reactive power +first and then active power) and, in the other example, they are used together. ### Sequentially activated controls -Let's play with the voltage thresholds of the control in order to fully activate a first control and then starts to -activate the second. +Let's define different voltage thresholds for each control so that one triggers before the other. #### Reactive power control first -In this section, the reactive power control is activated at 230 V and fully used above 240 V. Then, at 245 V, the -active control power starts and is fully activated at 250 V. - -In the following script such control is used on a network with a single-phase load connected to a single bus: +Here, the reactive power control is activated at 230 V and fully used above 240 V. Then, at 245 V, the +active power control starts and is fully used at 250 V: ```python import numpy as np @@ -609,15 +618,15 @@ fp = FlexibleParameter( control_q=Control.q_u( u_min=Q_(210, "V"), u_down=Q_(220, "V"), - u_up=Q_(230, "V"), # <---- - u_max=Q_(240, "V"), # <---- + u_up=Q_(230, "V"), # <---- lower than U_up of the P(U) control + u_max=Q_(240, "V"), # <---- lower than U_up of the P(U) control ), projection=Projection(type="euclidean"), # <---- Euclidean s_max=Q_(5, "kVA"), ) # We want to get the res_flexible_powers for a set of voltages norms -voltages = np.array(range(205, 256, 1), dtype=float) +voltages = np.arange(205, 256, dtype=float) # and when the theoretical power is the following power = Q_(-2.5, "kVA") @@ -627,14 +636,14 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -If we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: +If we plot the trajectory of the control in the $(P, Q)$ space, we get: ```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Sequential_1_Trajectory_Example.svg :width: 700 :align: center ``` -The same plot could have been obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -651,44 +660,41 @@ ax, res_flexible_powers = fp.plot_pq( plt.show() ``` -When the voltage is low, there is only a reactive power control which is activated. Thus, everything works as -depicted in the previous dedicated section and the choice of the projection may change the operation points for the -lowest voltages. +When the voltage is low, only the reactive power control is activated (vertical segment at +$P^{\mathrm{th.}}$); similar to what we saw in the $Q(U)$ control section. -When the voltage is high, there are two phases: +When the voltage is high, there are two stages: -1. Between 230 V and 240 V, only the reactive power decreases to reach the symmetrical point (with respect to the - x-axis) of the 205 V operation point. -2. Between 245 V and 250 V, the active power control reduces the active power to reach 0 W above 250 V. +1. Between 230 V and 240 V, only the reactive power changes: It increases on the vertical segment + to reach the perimeter of the disk. +2. Between 245 V and 250 V, the active power control starts reducing the active power until it + reaches 0 W at 250 V. #### Active power control first -In this section, the active power control is activated at 240 V and fully used above 245 V. Then, at 245 V, the -reactive control power starts and is fully activated at 250 V. - -In the following script such control is used on a network with a single-phase load connected to a single bus: +Here, the active power control is activated at 240 V and fully used above 245 V. Then, at 245 V, the +reactive power control starts and is fully activated at 250 V. ```python import numpy as np from roseau.load_flow import Q_, FlexibleParameter, Control, Projection - # Flexible parameter fp = FlexibleParameter( control_p=Control.p_max_u_production(u_up=Q_(230, "V"), u_max=Q_(240, "V")), # <---- control_q=Control.q_u( u_min=Q_(210, "V"), u_down=Q_(220, "V"), - u_up=Q_(245, "V"), # <---- - u_max=Q_(250, "V"), # <---- + u_up=Q_(245, "V"), # <---- higher than U_max of the P(U) control + u_max=Q_(250, "V"), # <---- higher than U_max of the P(U) control ), projection=Projection(type="euclidean"), # <---- Euclidean s_max=Q_(5, "kVA"), ) # We want to get the res_flexible_powers for a set of voltages norms -voltages = np.array(range(205, 256, 1), dtype=float) +voltages = np.arange(205, 256, dtype=float) # and when the theoretical power is the following power = Q_(-2.5, "kVA") @@ -698,14 +704,14 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -If we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: +If we plot the trajectory of the control in the $(P, Q)$ space, we get: ```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Sequential_2_Trajectory_Example.svg :width: 700 :align: center ``` -The same plot could have been obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -722,22 +728,20 @@ ax, res_flexible_powers = fp.plot_pq( plt.show() ``` -When the voltage is low, there is only a reactive power control which is activated. Thus, everything works as -depicted in the previous dedicated section and the choice of the projection may change the operation points for the -lowest voltages. +When the voltage is low, only the reactive power control is activated (vertical segment at +$P^{\mathrm{th.}}$); similar to what we saw in the $Q(U)$ control section. -When the voltage is high, there are two phases: +When the voltage is high, there are two stages: -1. Between 230 V and 240 V, only the active power decreases to reach a production of nearly 0 W. -2. Between 245 V and 250 V, the reactive power control increased the consumed the reactive power at 250 V. +1. Between 230 V and 240 V, only the active power changes. It decreases to about 0 W. +2. Between 245 V and 250 V, the reactive power control increases the reactive power until it + reaches $S^{max}$ at 250 V. ### Simultaneously activated controls -In this second subsection, the active and the reactive powers controls are activated at 240 V and reach their full +Here, the active and the reactive powers controls are both activated at 240 V and reach their full effect at 250 V. -Here is a small single phase network limited to a single bus to model the behaviour of the flexible load: - ```python import numpy as np @@ -749,15 +753,15 @@ fp = FlexibleParameter( control_q=Control.q_u( u_min=Q_(210, "V"), u_down=Q_(220, "V"), - u_up=Q_(240, "V"), # <---- - u_max=Q_(250, "V"), # <---- + u_up=Q_(240, "V"), # <---- same as U_up of the P(U) control + u_max=Q_(250, "V"), # <---- same as U_max of the P(U) control ), projection=Projection(type="euclidean"), # <---- Euclidean s_max=Q_(5, "kVA"), ) # We want to get the res_flexible_powers for a set of voltages norms -voltages = np.array(range(205, 256, 1), dtype=float) +voltages = np.arange(205, 256, dtype=float) # and when the theoretical power is the following power = Q_(-2.5, "kVA") @@ -767,14 +771,14 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -If we plot the trajectory of the control in the $(P, Q)$ space, the following result is obtained: +If we plot the trajectory of the control in the $(P, Q)$ space, we get: ```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_Trajectory_Example.svg :width: 700 :align: center ``` -The same plot could have been obtained using the following command: +The same plot can be obtained with: ```python from matplotlib import pyplot as plt @@ -791,19 +795,18 @@ ax, res_flexible_powers = fp.plot_pq( plt.show() ``` -When the voltage is low, there is only a reactive power control which is activated. Thus, everything works as -depicted in the previous dedicated section and the choice of the projection may change the operation points for the -lowest voltages. +When the voltage is low, only the reactive power control is activated (vertical segment at +$P^{\mathrm{th.}}$); similar to what we saw in the $Q(U)$ control section. -When the voltage is high, there are two phases: +When the voltage is high, there are two stages: -1. Between 240 V and 245 V, the active power control doesn't modify the value of the produced active power while the - reactive power control starts to increase the consumed reactive power. -2. Between 245 V and 250 V, the active power control starts to have effects on the produced active power. The - consumed reactive power continues to increase. -3. Above 250 V, no active power is produced. +1. Between 240 V and 245 V, the active power control does not modify the produced active power + while the reactive power control starts to increase the reactive power. +2. Between 245 V and 250 V, the active power control starts decreasing the active power while the + reactive power continues to increase. +3. Above 250 V, active power is reduced to 0 W and the reactive power is set to $S^{max}$. -If now, the theoretical power is changed to 4 kVA of production. +If we change the theoretical power to 4 kVA. ```python from matplotlib import pyplot as plt @@ -820,7 +823,7 @@ ax, res_flexible_powers = fp.plot_pq( plt.show() ``` -The following result is obtained: +Now we get a different result: ```{image} /_static/Load/FlexibleLoad/PmaxU_QU_Simultaneous_2_Trajectory_Example.svg :width: 700 diff --git a/doc/models/Load/FlexibleLoad/FlexibleParameter.md b/doc/models/Load/FlexibleLoad/FlexibleParameter.md index be3c5c3c..2a6f1823 100644 --- a/doc/models/Load/FlexibleLoad/FlexibleParameter.md +++ b/doc/models/Load/FlexibleLoad/FlexibleParameter.md @@ -152,7 +152,7 @@ fp = FlexibleParameter.pq_u_production( load = PowerLoad( id="load", bus=bus, - powers=Q_(-np.array([1000, 1000, 1000]), "VA"), + powers=Q_(-np.array([1000, 1000, 1000]), "VA"), # <- negative powers (generator) flexible_params=[fp, fp, fp], ) ``` diff --git a/doc/models/Load/FlexibleLoad/Projection.md b/doc/models/Load/FlexibleLoad/Projection.md index be7bf81e..beacd1f2 100644 --- a/doc/models/Load/FlexibleLoad/Projection.md +++ b/doc/models/Load/FlexibleLoad/Projection.md @@ -2,11 +2,13 @@ # Projections -The different controls may produce values for $P$ and $Q$ that are not feasible. The feasibility -domain in the $(P, Q)$ space is a part of the disc of radius $S^{\max}$. In these cases, the -solution found by the control algorithm has to be projected on the feasible domain. That's why we -need to define how the projection is done. There are three available projection types: the -_Euclidean_ projection, the projection at _Constant $P$_ and the projection at _Constant $Q$_. +When the control algorithm is trying to find the best control for given voltage constraints, it +could find a solution that is not "feasible" by the load. This means that the active and reactive +powers $P$ and $Q$ that constitute the solution lie outside the feasible domain defined by a part +of the disc of radius $S^{\max}$ in the $(P, Q)$ space. In these cases, the solution has to be +projected into the feasible domain. We can choose how the projection is performed using three +available projection types: +the _Euclidean_ projection, the projection at _Constant $P$_ and the projection at _Constant $Q$_. The projection accepts two approximation parameters: `alpha` and `epsilon`. @@ -19,7 +21,7 @@ The projection accepts two approximation parameters: `alpha` and `epsilon`. The lower `epsilon` is, the better the approximations are. ```{important} -Please note that no projection is performed in the final $\underline{S(U)}$ point lies in the disc of radius $S^{\max}$. +Please note that no projection is performed if the final $\underline{S(U)}$ point lies in the disc of radius $S^{\max}$. ``` ## Euclidean projection @@ -79,6 +81,6 @@ projection = Projection(type="keep_q") # alpha and epsilon can be provided ``` ```{important} -Please note that using the _Constant $Q$_ may reduce the provided $P^{\mathrm{th.}}$ of the load. See the [Feasible -Domain page](models-flexible_load-feasible_domains) for more details. +Please note that using the _Constant $Q$_ projection may reduce the provided $P^{\mathrm{th.}}$ of +the load. See the [Feasible Domain page](models-flexible_load-feasible_domains) for more details. ``` diff --git a/doc/models/Load/FlexibleLoad/index.md b/doc/models/Load/FlexibleLoad/index.md index 7fdb7f41..9dcb9a30 100644 --- a/doc/models/Load/FlexibleLoad/index.md +++ b/doc/models/Load/FlexibleLoad/index.md @@ -1,6 +1,6 @@ # Flexible loads -They are a special case of power loads: instead of being constant, the power will depend on the +They are a special type of power loads: instead of being constant, the power will depend on the voltage measured at the load and the control applied to the load. ## Equations diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index b8d784bd..0cb16913 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -867,7 +867,7 @@ def results_from_dict(self, data: JsonDict) -> NoReturn: def compute_powers( self, auth: Authentication, voltages: np.ndarray[float], power: complex, solve_kwargs: Optional[JsonDict] = None ) -> Q_[np.ndarray[complex]]: - """Compute the effective powers for different voltages (norms) + """Compute the flexible powers for different voltages (norms) Args: auth: @@ -880,7 +880,7 @@ def compute_powers( The input theoretical power of the load. solve_kwargs: - The keywords arguments of the :meth:`solve_load_flow` method. + Keywords arguments passed to the :meth:`~roseau.load_flow.ElectricalNetwork.solve_load_flow` method. Returns: The flexible powers really consumed taking into account the control. One value per provided voltage norm. @@ -942,7 +942,7 @@ def plot_pq( The optional axis to use for the plot. The current axis is used by default. solve_kwargs: - The keywords arguments of the :meth:`solve_load_flow` method. + The keywords arguments of the :meth:`~roseau.load_flow.ElectricalNetwork.solve_load_flow` method. voltages_labels_mask: A mask to activate the plot of voltages labels. By default, no voltages annotations. @@ -1037,7 +1037,7 @@ def plot_control_p( solve_kwargs: Optional[JsonDict] = None, res_flexible_powers: Optional[np.ndarray[complex]] = None, ) -> tuple["Axes", np.ndarray[complex]]: - """Plot the effective active power consumed (or produced) for the provided voltages and theoretical power. + """Plot the flexible active power consumed (or produced) for the provided voltages and theoretical power. Args: auth: @@ -1053,7 +1053,7 @@ def plot_control_p( The optional axis to use for the plot. The current axis is used by default. solve_kwargs: - The keywords arguments of the :meth:`solve_load_flow` method. + The keywords arguments of the :meth:`~roseau.load_flow.ElectricalNetwork.solve_load_flow` method. res_flexible_powers: If None, is provided, the `res_flexible_powers` are computed. Other @@ -1078,7 +1078,7 @@ def plot_control_p( res_flexible_powers = self._compute_powers( auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs ) - ax.scatter(voltages, res_flexible_powers.real, marker=".", c="blue", zorder=2, label="Effective power") + ax.scatter(voltages, res_flexible_powers.real, marker=".", c="blue", zorder=2, label="Actual power") # Add the theoretical non-smooth curve ax.plot(x, y, marker="s", c="red", zorder=1.9, label="Non-smooth theoretical control") @@ -1103,7 +1103,7 @@ def plot_control_q( solve_kwargs: Optional[JsonDict] = None, res_flexible_powers: Optional[np.ndarray[complex]] = None, ) -> tuple["Axes", np.ndarray[complex]]: - """Plot the effective reactive power consumed (or produced) for the provided voltages and theoretical power. + """Plot the flexible reactive power consumed (or produced) for the provided voltages and theoretical power. Args: auth: @@ -1119,7 +1119,7 @@ def plot_control_q( The optional axis to use for the plot. The current axis is used by default. solve_kwargs: - The keywords arguments of the :meth:`solve_load_flow` method + The keywords arguments of the :meth:`~roseau.load_flow.ElectricalNetwork.solve_load_flow` method res_flexible_powers: If None, is provided, the `res_flexible_powers` are computed. Other @@ -1144,7 +1144,7 @@ def plot_control_q( res_flexible_powers = self._compute_powers( auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs ) - ax.scatter(voltages, res_flexible_powers.imag, marker=".", c="blue", zorder=2, label="Effective power") + ax.scatter(voltages, res_flexible_powers.imag, marker=".", c="blue", zorder=2, label="Actual power") # Add the theoretical non-smooth curve ax.plot(x, y, marker="s", c="red", zorder=1.9, label="Non-smooth theoretical control") diff --git a/roseau/load_flow/typing.py b/roseau/load_flow/typing.py index 0c0e5c11..1e3f97a3 100644 --- a/roseau/load_flow/typing.py +++ b/roseau/load_flow/typing.py @@ -27,7 +27,7 @@ .. class:: Authentication - Valid authentication objects + Valid authentication types. """ import os from typing import Any, Literal, Union From 86e8306d38c4a1351314752f8d0cbebc1bdaef5e Mon Sep 17 00:00:00 2001 From: Saelyos Date: Wed, 20 Sep 2023 11:00:48 +0200 Subject: [PATCH 20/43] Add q_min and q_max to flexible parameters --- roseau/load_flow/exceptions.py | 2 +- .../models/loads/flexible_parameters.py | 99 +++++++++++++++++-- roseau/load_flow/models/loads/loads.py | 8 ++ .../models/tests/test_flexible_parameters.py | 24 ++++- roseau/load_flow/models/tests/test_loads.py | 16 +++ roseau/load_flow/units.py | 1 + 6 files changed, 141 insertions(+), 9 deletions(-) diff --git a/roseau/load_flow/exceptions.py b/roseau/load_flow/exceptions.py index 7806f209..31747d16 100644 --- a/roseau/load_flow/exceptions.py +++ b/roseau/load_flow/exceptions.py @@ -54,7 +54,7 @@ class RoseauLoadFlowExceptionCode(Enum): BAD_PROJECTION_VALUE = auto() # Flexible parameter - BAD_SMAX_VALUE = auto() + BAD_FLEXIBLE_PARAMETER_VALUE = auto() # Load BAD_LOAD_ID = auto() diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index 0cb16913..e37d6cff 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -461,8 +461,16 @@ class FlexibleParameter(JsonMixin): _control_class: type[Control] = Control _projection_class: type[Projection] = Projection - @ureg_wraps(None, (None, None, None, None, "VA"), strict=False) - def __init__(self, control_p: Control, control_q: Control, projection: Projection, s_max: float) -> None: + @ureg_wraps(None, (None, None, None, None, "VA", "VAr", "VAr"), strict=False) + def __init__( + self, + control_p: Control, + control_q: Control, + projection: Projection, + s_max: float, + q_min: Optional[float] = None, + q_max: Optional[float] = None, + ) -> None: """FlexibleParameter constructor. Args: @@ -477,11 +485,21 @@ def __init__(self, control_p: Control, control_q: Control, projection: Projectio s_max: The apparent power of the flexible load (VA). It is the radius of the feasible circle. + + q_min: + The minimum reactive power of the flexible load (VAr). By default it is equal to -s_max, but it can + be further constrained. + + q_max: + The maximum reactive power of the flexible load (VAr). By default it is equal to s_max, but it can + be further constrained. """ self.control_p = control_p self.control_q = control_q self.projection = projection self._s_max = s_max + self._q_min = q_min if q_min is not None else -s_max + self._q_max = q_max if q_max is not None else s_max self._check_values() def _check_values(self) -> None: @@ -489,7 +507,15 @@ def _check_values(self) -> None: if self._s_max <= 0: msg = f"'s_max' must be greater than 0 but {self.s_max:P#~} was provided." logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_SMAX_VALUE) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + if self._q_min < -self._s_max: + msg = f"'q_min' must be greater than -s_max ({-self.s_max:P#~}) but {self.q_min:P#~} was provided." + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + if self._q_max > self._s_max: + msg = f"'q_max' must be lesser than s_max ({self.s_max:P#~}) but {self.q_max:P#~} was provided." + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) @property @ureg_wraps("VA", (None,), strict=False) @@ -497,6 +523,18 @@ def s_max(self) -> Q_[float]: """The apparent power of the flexible load (VA). It is the radius of the feasible circle.""" return self._s_max + @property + @ureg_wraps("VAr", (None,), strict=False) + def q_min(self) -> Q_[float]: + """The minimum reactive power of the flexible load (VAr).""" + return self._q_min + + @property + @ureg_wraps("VAr", (None,), strict=False) + def q_max(self) -> Q_[float]: + """The maximum reactive power of the flexible load (VAr).""" + return self._q_max + @classmethod def constant(cls) -> Self: """Build flexible parameters for a constant control with a Euclidean projection. @@ -621,7 +659,7 @@ def p_max_u_consumption( ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "VA", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "VA", "Var", "Var", None, None, None, None), strict=False) def q_u( cls, u_min: float, @@ -629,6 +667,8 @@ def q_u( u_up: float, u_max: float, s_max: float, + q_min: Optional[float] = None, + q_max: Optional[float] = None, alpha_control: float = Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, @@ -656,6 +696,14 @@ def q_u( The apparent power of the flexible load (VA). It is the radius of the feasible circle. + q_min: + The minimum reactive power of the flexible load (VAr). By default it is equal to -s_max, but it can + be further constrained. + + q_max: + The maximum reactive power of the flexible load (VAr). By default it is equal to s_max, but it can + be further constrained. + alpha_control: An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. @@ -680,10 +728,12 @@ def q_u( control_q=control_q, projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, + q_min=q_min, + q_max=q_max, ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None), strict=False) def pq_u_production( cls, up_up: float, @@ -693,6 +743,8 @@ def pq_u_production( uq_up: float, uq_max: float, s_max: float, + q_min: Optional[float] = None, + q_max: Optional[float] = None, alpha_control=Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj=Projection._DEFAULT_ALPHA, @@ -727,6 +779,14 @@ def pq_u_production( The apparent power of the flexible load (VA). It is the radius of the feasible circle. + q_min: + The minimum reactive power of the flexible load (VAr). By default it is equal to -s_max, but it can + be further constrained. + + q_max: + The maximum reactive power of the flexible load (VAr). By default it is equal to s_max, but it can + be further constrained. + alpha_control: An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. @@ -755,10 +815,12 @@ def pq_u_production( control_q=control_q, projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, + q_min=q_min, + q_max=q_max, ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None), strict=False) def pq_u_consumption( cls, up_min: float, @@ -768,6 +830,8 @@ def pq_u_consumption( uq_up: float, uq_max: float, s_max: float, + q_min: Optional[float] = None, + q_max: Optional[float] = None, alpha_control: float = Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, @@ -802,6 +866,14 @@ def pq_u_consumption( The apparent power of the flexible load (VA). It is the radius of the feasible circle. + q_min: + The minimum reactive power of the flexible load (VAr). By default it is equal to -s_max, but it can + be further constrained. + + q_max: + The maximum reactive power of the flexible load (VAr). By default it is equal to s_max, but it can + be further constrained. + alpha_control: An approximation factor used by the family function (soft clip). The greater, the closer the function are from the non-differentiable function. @@ -830,6 +902,8 @@ def pq_u_consumption( control_q=control_q, projection=cls._projection_class(type=type_proj, alpha=alpha_proj, epsilon=epsilon_proj), s_max=s_max, + q_min=q_min, + q_max=q_max, ) # @@ -840,7 +914,16 @@ def from_dict(cls, data: JsonDict) -> Self: control_p = cls._control_class.from_dict(data["control_p"]) control_q = cls._control_class.from_dict(data["control_q"]) 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"]) + q_min = data.get("q_min", None) + q_max = data.get("q_max", None) + return cls( + control_p=control_p, + control_q=control_q, + projection=projection, + s_max=data["s_max"], + q_min=q_min, + q_max=q_max, + ) def to_dict(self, include_geometry: bool = True) -> JsonDict: return { @@ -848,6 +931,8 @@ def to_dict(self, include_geometry: bool = True) -> JsonDict: "control_q": self.control_q.to_dict(), "projection": self.projection.to_dict(), "s_max": self._s_max, + "q_min": self._q_min, + "q_max": self._q_max, } def _results_to_dict(self, warning: bool) -> NoReturn: diff --git a/roseau/load_flow/models/loads/loads.py b/roseau/load_flow/models/loads/loads.py index 7247c344..b64bc7c0 100644 --- a/roseau/load_flow/models/loads/loads.py +++ b/roseau/load_flow/models/loads/loads.py @@ -289,6 +289,14 @@ def powers(self, value: Sequence[complex]) -> None: msg = f"The power is greater than the parameter s_max for flexible load {self.id!r}" logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_S_VALUE) + if power.imag < fp.q_min.m_as("VAr"): + msg = f"The reactive power is lesser than the parameter q_min for flexible load {id!r}" + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_S_VALUE) + if power.imag > fp.q_max.m_as("VAr"): + msg = f"The reactive power is greater than the parameter q_max for flexible load {id!r}" + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_S_VALUE) if fp.control_p.type == "p_max_u_production" and power.real > 0: msg = f"There is a production control but a positive power for flexible load {self.id!r}" logger.error(msg) diff --git a/roseau/load_flow/models/tests/test_flexible_parameters.py b/roseau/load_flow/models/tests/test_flexible_parameters.py index 5d91abd4..922bbfa4 100644 --- a/roseau/load_flow/models/tests/test_flexible_parameters.py +++ b/roseau/load_flow/models/tests/test_flexible_parameters.py @@ -200,7 +200,29 @@ def test_flexible_parameter(): s_max=Q_(-1e3, "kVA"), ) assert e.value.msg == "'s_max' must be greater than 0 but -1.0 MVA was provided." - assert e.value.code == RoseauLoadFlowExceptionCode.BAD_SMAX_VALUE + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE + + with pytest.raises(RoseauLoadFlowException) as e: + FlexibleParameter( + control_p=Control.constant(), + control_q=Control.constant(), + projection=Projection(type="euclidean"), + s_max=Q_(1e3, "kVA"), + q_min=Q_(-2e3, "kVAr"), + ) + assert e.value.msg == "'q_min' must be greater than -s_max (-1.0 MVA) but -2.0 MVAr was provided." + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE + + with pytest.raises(RoseauLoadFlowException) as e: + FlexibleParameter( + control_p=Control.constant(), + control_q=Control.constant(), + projection=Projection(type="euclidean"), + s_max=Q_(1e3, "kVA"), + q_max=Q_(2e3, "kVAr"), + ) + assert e.value.msg == "'q_max' must be lesser than s_max (1.0 MVA) but 2.0 MVAr was provided." + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE @pytest.fixture(params=["constant", "p_max_u_production", "p_max_u_consumption"]) diff --git a/roseau/load_flow/models/tests/test_loads.py b/roseau/load_flow/models/tests/test_loads.py index 7276b0e5..4682e3b7 100644 --- a/roseau/load_flow/models/tests/test_loads.py +++ b/roseau/load_flow/models/tests/test_loads.py @@ -163,6 +163,8 @@ def test_flexible_load(): uq_up=240, uq_max=250, s_max=300, + q_min=-200, + q_max=200, alpha_control=100.0, alpha_proj=100.0, epsilon_proj=0.01, @@ -175,6 +177,8 @@ def test_flexible_load(): uq_up=240, uq_max=250, s_max=300, + q_min=-200, + q_max=200, alpha_control=100.0, alpha_proj=100.0, epsilon_proj=0.01, @@ -191,6 +195,18 @@ def test_flexible_load(): assert "The power is greater than the parameter s_max for flexible load" in e.value.msg assert e.value.code == RoseauLoadFlowExceptionCode.BAD_S_VALUE + fp = [fp_pq_prod, fp_const, fp_const] + with pytest.raises(RoseauLoadFlowException) as e: + PowerLoad("flexible load", bus, powers=[10 + 250j, 0, 0j], phases="abcn", flexible_params=fp) + assert "The reactive power is greater than the parameter q_max for flexible load" in e.value.msg + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_S_VALUE + + fp = [fp_pq_prod, fp_const, fp_const] + with pytest.raises(RoseauLoadFlowException) as e: + PowerLoad("flexible load", bus, powers=[10 - 250j, 0, 0j], phases="abcn", flexible_params=fp) + assert "The reactive power is lesser than the parameter q_min for flexible load" in e.value.msg + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_S_VALUE + fp = [fp_pq_prod, fp_const, fp_const] with pytest.raises(RoseauLoadFlowException) as e: PowerLoad("flexible load", bus, powers=[100 + 50j, 0, 0j], phases="abcn", flexible_params=fp) diff --git a/roseau/load_flow/units.py b/roseau/load_flow/units.py index 07c774ba..24e9212c 100644 --- a/roseau/load_flow/units.py +++ b/roseau/load_flow/units.py @@ -26,6 +26,7 @@ lambda s: s.replace("%", " percent "), ] ) +ureg.define("volt_ampere_reactive = 1 * volt_ampere = VAr") if TYPE_CHECKING: Q_: TypeAlias = PlainQuantity[T] From cff7279818759e86483ade03ea65130f6e62b8a9 Mon Sep 17 00:00:00 2001 From: Saelyos Date: Thu, 21 Sep 2023 16:25:33 +0200 Subject: [PATCH 21/43] Fix settings --- .../models/loads/flexible_parameters.py | 61 ++++++++++++------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index e37d6cff..bd5856bf 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -497,25 +497,11 @@ def __init__( self.control_p = control_p self.control_q = control_q self.projection = projection - self._s_max = s_max - self._q_min = q_min if q_min is not None else -s_max - self._q_max = q_max if q_max is not None else s_max - self._check_values() - - def _check_values(self) -> None: - """Check the provided values.""" - if self._s_max <= 0: - msg = f"'s_max' must be greater than 0 but {self.s_max:P#~} was provided." - logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) - if self._q_min < -self._s_max: - msg = f"'q_min' must be greater than -s_max ({-self.s_max:P#~}) but {self.q_min:P#~} was provided." - logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) - if self._q_max > self._s_max: - msg = f"'q_max' must be lesser than s_max ({self.s_max:P#~}) but {self.q_max:P#~} was provided." - logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + self._q_min = None + self._q_max = None + self.s_max = s_max + self.q_min = q_min + self.q_max = q_max @property @ureg_wraps("VA", (None,), strict=False) @@ -523,17 +509,50 @@ def s_max(self) -> Q_[float]: """The apparent power of the flexible load (VA). It is the radius of the feasible circle.""" return self._s_max + @s_max.setter + @ureg_wraps(None, (None, "VA"), strict=False) + def s_max(self, value: float) -> None: + self._s_max = value + if value <= 0: + msg = f"'s_max' must be greater than 0 but {self.s_max:P#~} was provided." + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + if self._q_max is not None and self._q_max > self._s_max: + logger.warning("'s_max' has been updated but now 'q_max' is greater than s_max. 'q_max' is set to s_max") + self._q_max = self._s_max + if self._q_min is not None and self._q_min < -self._s_max: + logger.warning("'s_max' has been updated but now 'q_min' is lesser than -s_max. 'q_min' is set to -s_max") + self._q_min = -self._s_max + @property @ureg_wraps("VAr", (None,), strict=False) def q_min(self) -> Q_[float]: """The minimum reactive power of the flexible load (VAr).""" - return self._q_min + return self._q_min if self._q_min is not None else -self._s_max + + @q_min.setter + @ureg_wraps(None, (None, "VAr"), strict=False) + def q_min(self, value: Optional[float]) -> None: + self._q_min = value + if value is not None and value < -self._s_max: + msg = f"'q_min' must be greater than -s_max ({-self.s_max:P#~}) but {self.q_min:P#~} was provided." + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) @property @ureg_wraps("VAr", (None,), strict=False) def q_max(self) -> Q_[float]: """The maximum reactive power of the flexible load (VAr).""" - return self._q_max + return self._q_max if self._q_max is not None else self._s_max + + @q_max.setter + @ureg_wraps(None, (None, "VAr"), strict=False) + def q_max(self, value: Optional[float]) -> None: + self._q_max = value + if value is not None and value > self._s_max: + msg = f"'q_max' must be lesser than s_max ({self.s_max:P#~}) but {self.q_max:P#~} was provided." + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) @classmethod def constant(cls) -> Self: From b23c892ee4480e30c86a70291b90e84d85ea2f91 Mon Sep 17 00:00:00 2001 From: Saelyos Date: Fri, 22 Sep 2023 16:17:55 +0200 Subject: [PATCH 22/43] Add doc --- .../Domain_Pconst_QU_Qmin_Qmax.svg | 95 +++ ...nst_QU_Qmin_Qmax_Control_Curve_Example.svg | 578 +++++++++++++ ...Pconst_QU_Qmin_Qmax_Trajectory_Example.svg | 782 ++++++++++++++++++ .../Domain_Pconst_QU_Qmin_Qmax.tex | 35 + ...nst_QU_Qmin_Qmax_Control_Curve_Example.tex | 83 ++ .../Pconst_QU_Qmin_Qmax_Example.csv | 52 ++ ...Pconst_QU_Qmin_Qmax_Trajectory_Example.tex | 94 +++ .../Load/FlexibleLoad/FeasibleDomain.md | 92 ++- 8 files changed, 1810 insertions(+), 1 deletion(-) create mode 100644 doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.svg create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.svg create mode 100644 doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.svg create mode 100644 doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.tex create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Example.csv create mode 100644 doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.tex diff --git a/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.svg b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.svg new file mode 100644 index 00000000..7923fd93 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.svg new file mode 100644 index 00000000..47a78c22 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.svg @@ -0,0 +1,578 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.svg b/doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.svg new file mode 100644 index 00000000..d9c5c0e8 --- /dev/null +++ b/doc/_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.svg @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.tex b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.tex new file mode 100644 index 00000000..42fc9995 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.tex @@ -0,0 +1,35 @@ +\input{Preambule}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \input{Load/FlexibleLoad/Domain_Common.tikz}% + \pgfmathsetmacro{\qmaxvaleur}{0.75*\r};% + \pgfmathsetmacro{\qminvaleur}{-0.5*\r};% + \pgfmathsetmacro{\qmaxx}{\r*cos(asin(\qmaxvaleur/\r))};% + \pgfmathsetmacro{\qminx}{\r*cos(asin(\qminvaleur/\r))};% + + % The domain is a segment + \draw[domaine] (\pthvaleur,\qminvaleur) -- (\pthvaleur,\qmaxvaleur);% + + \draw[dashed] (-\qmaxx,\qmaxvaleur) -- (\qmaxx,\qmaxvaleur);% + \draw[dashed] (-\qminx,\qminvaleur) -- (\qminx,\qminvaleur);% + + \node[below right] at (0,\qmaxvaleur) {$Q^{\max}$};% + \node[below right] at (0,\qminvaleur) {$Q^{\min}$};% + + \pic[domaine] at (\pthvaleur,\qthvaleur) {point};% + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.tex new file mode 100644 index 00000000..a57290e0 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.tex @@ -0,0 +1,83 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \begin{axis} + [% + xlabel={Voltages (V)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.1,0.5)},anchor=south},% + grid=both,% + legend entries={Actual power,Non-smooth theoretical control},% + legend style={% + legend cell align=left,% + legend pos=north west,% + },% + sharp plot,% + mark size=0.5mm,% + height=9cm,% + width=16cm,% + ymin=-6000, + ymax=6000, + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==210}{% + "\\$\umin$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==220}{% + "\\$\udown$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==240}{% + "\\$\uup$"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==250}{% + "\\$\umax$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==5}{% + "$\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + \pgfmathifthenelse{\tick==-5}{% + "$-\smax$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + ] + \addplot+[only marks] table[x=v, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Example.csv};% + \addplot+ coordinates {(205,-3000) (210,-3000) (220,0) (240,0) (250,4000) (255,4000)};% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Example.csv b/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Example.csv new file mode 100644 index 00000000..aaa5bf2e --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Example.csv @@ -0,0 +1,52 @@ +v,p,q +205.0,-2500.0,-2999.999999845413 +206.0,-2500.0,-2999.9999915598623 +207.0,-2500.0,-2999.999539185489 +208.0,-2500.0,-2999.9748445220325 +209.0,-2500.0,-2998.6387554061644 +210.0,-2500.0,-2948.0139614580035 +211.0,-2500.0,-2698.6387554061644 +212.0,-2500.0,-2399.974844522034 +213.0,-2500.0,-2099.9995391855414 +214.0,-2500.0,-1799.9999915626938 +215.0,-2500.0,-1500.0 +216.0,-2500.0,-1200.0000084373062 +217.0,-2500.0,-900.0004608144591 +218.0,-2500.0,-600.0251554779662 +219.0,-2500.0,-301.36124459383615 +220.0,-2500.0,-51.98603854199624 +221.0,-2500.0,-1.3612445938352424 +222.0,-2500.0,-0.025155477967331308 +223.0,-2500.0,-0.0004608145115492235 +224.0,-2500.0,-8.440137588827668e-06 +225.0,-2500.0,-1.5458634372578217e-07 +226.0,-2500.0,-2.8314017797015367e-09 +227.0,-2500.0,-5.229150445984487e-11 +228.0,-2500.0,-1.6653345369377348e-12 +229.0,-2500.0,6.661338147750939e-13 +230.0,-2500.0,0.0 +231.0,-2500.0,-6.439293542825908e-13 +232.0,-2500.0,1.931788062847763e-12 +233.0,-2500.0,6.981082378840588e-11 +234.0,-2500.0,3.775135759482643e-09 +235.0,-2500.0,2.0611470287054231e-07 +236.0,-2500.0,1.1253517506367405e-05 +237.0,-2500.0,0.0006144193484408765 +238.0,-2500.0,0.03354063728890007 +239.0,-2500.0,1.8149927917803101 +240.0,-2500.0,69.31471805599514 +241.0,-2500.0,401.8149927917817 +242.0,-2500.0,800.0335406372877 +243.0,-2500.0,1200.0006144192778 +244.0,-2500.0,1600.000011249741 +245.0,-2500.0,1999.9999999999993 +246.0,-2500.0,2399.9999887502586 +247.0,-2500.0,2799.9993855807215 +248.0,-2500.0,3199.966459362712 +249.0,-2500.0,3598.185007208219 +250.0,-2500.0,3930.6852819440046 +251.0,-2500.0,3998.1850072082193 +252.0,-2500.0,3999.96645936271 +253.0,-2500.0,3999.9993855806506 +254.0,-2500.0,3999.999988746485 +255.0,-2500.0,3999.999999793886 diff --git a/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.tex b/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.tex new file mode 100644 index 00000000..0e286b92 --- /dev/null +++ b/doc/images/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.tex @@ -0,0 +1,94 @@ +\input{Preambule}% + +\usepackage{pgfplots}% +\pgfplotsset{compat=newest}% + +\begin{document} + \begin{tikzpicture}[% + show background rectangle,% + tight background,% + background rectangle/.style={fill=white}% + ] + \tikzset{% + pin style/.style={pin distance=1mm},% + }% + + \begin{axis} + [% + xlabel={Active power (W)},% + x label style={at={(axis description cs:0.5,-0.1)},anchor=north},% + ylabel={Reactive power (VAr)},% + y label style={at={(axis description cs:-0.2,0.5)},anchor=south},% + grid=both,% + scatter,% + only marks,% + mark size=0.5mm,% + height=9cm,% + width=9cm,% + axis equal=true,% + enlarge y limits,% + enlarge x limits,% + xmin=-5000,% + xmax=5000,% + ymin=-5000,% + ymax=5000,% + xtick={-5000,-2500,0,2500,5000},% + ytick={-5000,-2500,0,2500,5000},% + minor tick num=1, + scaled x ticks=base 10:-3,% + every x tick scale label/.style={at={(axis description cs:1,-0.05)}},% + scaled y ticks=base 10:-3,% + xticklabel style={align=center},% + xticklabel={% + $\pgfmathprintnumber{\tick}$ + \pgfmathifthenelse{\tick==-2.5}{% + "\\$P^{\theo}$"% + }{""}% + \pgfmathresult% + },% + yticklabel style={align=center},% + yticklabel={% + \pgfmathifthenelse{\tick==0}{% + "$Q^{\theo}$\hspace{3mm}"% + }{""}% + \pgfmathresult% + $\pgfmathprintnumber{\tick}$ + },% + colorbar,% + colorbar style={% + ylabel=Voltage (V),% + },% + nodes near coords*={},% By default, nothing + nodes near coords style={% + anchor=center,% + },% + coordinate style/.condition={\thisrow{v}==205}{pin={[pin style] below left:{\mylabel}}},% + coordinate style/.condition={\thisrow{v}==210}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==215}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==220}{pin={[pin style] below left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==225}{pin={[pin style] below right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==230}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==235}{pin={[pin style] above right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==240}{pin={[pin style] above left:\mylabel}},% + coordinate style/.condition={\thisrow{v}==245}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==250}{pin={[pin style] right:\mylabel}},% + coordinate style/.condition={\thisrow{v}==255}{pin={[pin style] above left:\mylabel}},% + visualization depends on={\thisrow{v} \as \myvalue},% Required to use the "v" column for two usages + visualization depends on={% + value $\qty[parse-numbers=false]{\pgfmathprintnumber{\thisrow{v}}}{V}$\as\mylabel% + },% + ] + \addplot[point meta={\thisrow{v}}] table[x=p, y=q, col sep=comma] {Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Example.csv}; % + \draw[black] (axis cs:0,0) circle[radius=5000];% + \end{axis} + \end{tikzpicture} +\end{document} +% Local Variables: +% mode: latex +% TeX-engine: luatex +% TeX-source-correlate-method-active: synctex +% ispell-local-dictionary: "british" +% coding: utf-8 +% LaTeX-indent-level: 4 +% fill-column: 100 +% End: diff --git a/doc/models/Load/FlexibleLoad/FeasibleDomain.md b/doc/models/Load/FlexibleLoad/FeasibleDomain.md index f7f69666..ba3b300e 100644 --- a/doc/models/Load/FlexibleLoad/FeasibleDomain.md +++ b/doc/models/Load/FlexibleLoad/FeasibleDomain.md @@ -281,7 +281,7 @@ plt.show() When the active power is constant (no $P$ control), only the reactive power changes as a function of the local voltage. Thus, the reactive power may vary between $-S^{\max}$ and $+S^{\max}$. When -$P^{\mathrm{th.}}\neq 0$, the point $(P, Q) produced by the control might lie outside the disc of +$P^{\mathrm{th.}}\neq 0$, the point $(P, Q)$ produced by the control might lie outside the disc of radius $S^{\max}$ (when $P^{\mathrm{th.}}\neq 0$). Those points are projected on the circle of radius $S^{\max}$ and depending on the projection, the feasible domains change. @@ -584,6 +584,96 @@ Notice that when the voltages were too low or too high, the Euclidean projection reduction of the produced active power and the (produced and consumed) reactive power to ensure a feasible solution. Like before, there is one point per volt and several points overlap. +### $Q^{\min}$ and $Q^{\max}$ limits + +It is also possible to define a minimum and maximum reactive power value. In that case, the feasible domain is +constrained between those two values. + +```{image} /_static/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.svg +:width: 300 +:align: center +``` + +```python +import numpy as np + +from roseau.load_flow import Q_, FlexibleParameter, Control, Projection + +# Flexible parameter +fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.q_u( + u_min=Q_(210, "V"), u_down=Q_(220, "V"), u_up=Q_(240, "V"), u_max=Q_(250, "V") + ), + projection=Projection(type="euclidean"), + s_max=Q_(5, "kVA"), + q_min=Q_(-3, "kVAr"), # <---- set Q_min >= -S_max + q_max=Q_(4, "kVAr"), # <---- set Q_max <= S_max +) + +# We want to get the res_flexible_powers for a set of voltages norms +voltages = np.arange(205, 256, dtype=float) + +# and when the theoretical power is the following +power = Q_(-2.5, "kVA") + +# Get the resulting flexible powers for the given theoretical power and voltages list. +auth = ("username", "password") +res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) +``` + +The variable `res_flexible_powers` contains the powers that have been really produced by +the flexible load for the voltages stored in the variable named `voltages`. + +Plotting the control curve $Q(U)$ gives: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Control_Curve_Example.svg +:width: 700 +:align: center +``` + +Here, again the complete reactive power range is not fully used. + +The same plot can be obtained with: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_control_q( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + ax=ax, +) +plt.show() +``` + +If we plot the trajectory of the control in the $(P, Q)$ space, we get: + +```{image} /_static/Load/FlexibleLoad/Pconst_QU_Qmin_Qmax_Trajectory_Example.svg +:width: 700 +:align: center +``` + +The same plot can be obtained with: + +```python +from matplotlib import pyplot as plt + +ax = plt.subplot() # New axes +ax, res_flexible_powers = fp.plot_pq( + auth=auth, + voltages=voltages, + power=power, + res_flexible_powers=res_flexible_powers, + voltages_labels_mask=np.isin(voltages, [210, 215, 230, 245, 250]), + ax=ax, +) +plt.show() +``` + ## Both active and reactive powers control When both active and reactive power controls are activated, the feasible domain is the following: From 7395ca427e2de1e71c71a419472edd963f9ce946 Mon Sep 17 00:00:00 2001 From: Saelyos Date: Mon, 25 Sep 2023 10:02:14 +0200 Subject: [PATCH 23/43] Improve checks and doc --- .../Load/FlexibleLoad/FeasibleDomain.md | 9 +++-- .../models/loads/flexible_parameters.py | 36 +++++++++++++----- .../models/tests/test_flexible_parameters.py | 37 ++++++++++++++++++- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/doc/models/Load/FlexibleLoad/FeasibleDomain.md b/doc/models/Load/FlexibleLoad/FeasibleDomain.md index ba3b300e..2231381a 100644 --- a/doc/models/Load/FlexibleLoad/FeasibleDomain.md +++ b/doc/models/Load/FlexibleLoad/FeasibleDomain.md @@ -528,7 +528,7 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -The variable `res_flexible_powers` contains the powers that have been really produced by +The variable `res_flexible_powers` contains the powers that have been actually produced by the flexible load for the voltages stored in the variable named `voltages`. Plotting the control curve $Q(U)$ gives: @@ -586,7 +586,7 @@ feasible solution. Like before, there is one point per volt and several points o ### $Q^{\min}$ and $Q^{\max}$ limits -It is also possible to define a minimum and maximum reactive power value. In that case, the feasible domain is +It is also possible to define a minimum and maximum reactive power values. In that case, the feasible domain is constrained between those two values. ```{image} /_static/Load/FlexibleLoad/Domain_Pconst_QU_Qmin_Qmax.svg @@ -622,7 +622,7 @@ auth = ("username", "password") res_flexible_powers = fp.compute_powers(auth=auth, voltages=voltages, power=power) ``` -The variable `res_flexible_powers` contains the powers that have been really produced by +The variable `res_flexible_powers` contains the powers that have been actually produced by the flexible load for the voltages stored in the variable named `voltages`. Plotting the control curve $Q(U)$ gives: @@ -632,7 +632,8 @@ Plotting the control curve $Q(U)$ gives: :align: center ``` -Here, again the complete reactive power range is not fully used. +Here, again the complete reactive power range is not fully used as it is constrained between the $Q^{\min}$ and +$Q^{\max}$ values defined. The same plot can be obtained with: diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index bd5856bf..6d2353b2 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -512,16 +512,17 @@ def s_max(self) -> Q_[float]: @s_max.setter @ureg_wraps(None, (None, "VA"), strict=False) def s_max(self, value: float) -> None: - self._s_max = value if value <= 0: - msg = f"'s_max' must be greater than 0 but {self.s_max:P#~} was provided." + s_max = Q_(value, "VA") + msg = f"'s_max' must be greater than 0 but {s_max:P#~} was provided." logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + self._s_max = value if self._q_max is not None and self._q_max > self._s_max: logger.warning("'s_max' has been updated but now 'q_max' is greater than s_max. 'q_max' is set to s_max") self._q_max = self._s_max if self._q_min is not None and self._q_min < -self._s_max: - logger.warning("'s_max' has been updated but now 'q_min' is lesser than -s_max. 'q_min' is set to -s_max") + logger.warning("'s_max' has been updated but now 'q_min' is less than -s_max. 'q_min' is set to -s_max") self._q_min = -self._s_max @property @@ -533,11 +534,17 @@ def q_min(self) -> Q_[float]: @q_min.setter @ureg_wraps(None, (None, "VAr"), strict=False) def q_min(self, value: Optional[float]) -> None: - self._q_min = value if value is not None and value < -self._s_max: - msg = f"'q_min' must be greater than -s_max ({-self.s_max:P#~}) but {self.q_min:P#~} was provided." + q_min = Q_(value, "VAr") + msg = f"'q_min' must be greater than -s_max ({-self.s_max:P#~}) but {q_min:P#~} was provided." + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + if value is not None and self._q_max is not None and value > self._q_max: + q_min = Q_(value, "VAr") + msg = f"'q_min' must be greater than q_max ({self.q_max:P#~}) but {q_min:P#~} was provided." logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + self._q_min = value @property @ureg_wraps("VAr", (None,), strict=False) @@ -548,11 +555,17 @@ def q_max(self) -> Q_[float]: @q_max.setter @ureg_wraps(None, (None, "VAr"), strict=False) def q_max(self, value: Optional[float]) -> None: - self._q_max = value if value is not None and value > self._s_max: - msg = f"'q_max' must be lesser than s_max ({self.s_max:P#~}) but {self.q_max:P#~} was provided." + q_max = Q_(value, "VAr") + msg = f"'q_max' must be less than s_max ({self.s_max:P#~}) but {q_max:P#~} was provided." logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + if value is not None and self._q_min is not None and value < self._q_min: + q_max = Q_(value, "VAr") + msg = f"'q_max' must be greater than q_min ({self.q_min:P#~}) but {q_max:P#~} was provided." + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE) + self._q_max = value @classmethod def constant(cls) -> Self: @@ -945,14 +958,17 @@ def from_dict(cls, data: JsonDict) -> Self: ) def to_dict(self, include_geometry: bool = True) -> JsonDict: - return { + res = { "control_p": self.control_p.to_dict(), "control_q": self.control_q.to_dict(), "projection": self.projection.to_dict(), "s_max": self._s_max, - "q_min": self._q_min, - "q_max": self._q_max, } + if self._q_min is not None: + res["q_min"] = self._q_min + if self._q_max is not None: + res["q_max"] = self._q_max + return res def _results_to_dict(self, warning: bool) -> NoReturn: msg = f"The {type(self).__name__} has no results to export." diff --git a/roseau/load_flow/models/tests/test_flexible_parameters.py b/roseau/load_flow/models/tests/test_flexible_parameters.py index 922bbfa4..ba9194a0 100644 --- a/roseau/load_flow/models/tests/test_flexible_parameters.py +++ b/roseau/load_flow/models/tests/test_flexible_parameters.py @@ -192,6 +192,7 @@ def test_projection(): def test_flexible_parameter(): + # s_max > 0 with pytest.raises(RoseauLoadFlowException) as e: FlexibleParameter( control_p=Control.constant(), @@ -202,6 +203,7 @@ def test_flexible_parameter(): assert e.value.msg == "'s_max' must be greater than 0 but -1.0 MVA was provided." assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE + # q_min >= -s_max with pytest.raises(RoseauLoadFlowException) as e: FlexibleParameter( control_p=Control.constant(), @@ -213,6 +215,7 @@ def test_flexible_parameter(): assert e.value.msg == "'q_min' must be greater than -s_max (-1.0 MVA) but -2.0 MVAr was provided." assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE + # q_max <= s_max with pytest.raises(RoseauLoadFlowException) as e: FlexibleParameter( control_p=Control.constant(), @@ -221,7 +224,39 @@ def test_flexible_parameter(): s_max=Q_(1e3, "kVA"), q_max=Q_(2e3, "kVAr"), ) - assert e.value.msg == "'q_max' must be lesser than s_max (1.0 MVA) but 2.0 MVAr was provided." + assert e.value.msg == "'q_max' must be less than s_max (1.0 MVA) but 2.0 MVAr was provided." + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE + + fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.constant(), + projection=Projection(type="euclidean"), + s_max=Q_(3e3, "kVA"), + q_max=Q_(2e3, "kVAr"), + q_min=Q_(-2e3, "kVAr"), + ) + fp.s_max = Q_(1e3, "kVA") # reduce q_min and q_max + assert fp.q_max.magnitude == 1e6 + assert fp.q_min.magnitude == -1e6 + + # q_min < q_max + fp = FlexibleParameter( + control_p=Control.constant(), + control_q=Control.constant(), + projection=Projection(type="euclidean"), + s_max=Q_(3e3, "kVA"), + q_max=Q_(2e3, "kVAr"), + q_min=Q_(-2e3, "kVAr"), + ) + + with pytest.raises(RoseauLoadFlowException) as e: + fp.q_max = Q_(-2.5e3, "kVAr") + assert e.value.msg == "'q_max' must be greater than q_min (-2.0 MVAr) but -2.5 MVAr was provided." + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE + + with pytest.raises(RoseauLoadFlowException) as e: + fp.q_min = Q_(2.5e3, "kVAr") + assert e.value.msg == "'q_min' must be greater than q_max (2.0 MVAr) but 2.5 MVAr was provided." assert e.value.code == RoseauLoadFlowExceptionCode.BAD_FLEXIBLE_PARAMETER_VALUE From 36862249edd8e84b6df0b7d331b318fa3fe6b132 Mon Sep 17 00:00:00 2001 From: Saelyos Date: Mon, 25 Sep 2023 10:57:31 +0200 Subject: [PATCH 24/43] Update changelog --- doc/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Changelog.md b/doc/Changelog.md index 890ea928..19f8c3af 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,7 @@ **In development** +- {gh-pr}`133` {gh-issue}`126` Add Qmin and Qmax limits of flexible parameters. - {gh-pr}`132` {gh-issue}`101` Document extra utilities including converters and constants. - {gh-pr}`131` {gh-issue}`127` Improve the documentation of the flexible loads. - Add the method `compute_powers` method to the `FlexibleParameter` class to compute the resulting flexible powers From d176d80c6fef6b42654f42fa8e69e8206c58da17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:01:30 +0200 Subject: [PATCH 25/43] Bump actions/checkout from 3 to 4 (#134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
Release notes

Sourced from actions/checkout's releases.

v4.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v4.0.0

v3.6.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3.5.3...v3.6.0

v3.5.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v3.5.3

v3.5.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v3.5.1...v3.5.2

v3.5.1

What's Changed

New Contributors

... (truncated)

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/conda.yml | 2 +- .github/workflows/doc.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8e4ea47..7493830c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: python-version: ["3.9", "3.10", "3.11"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: false diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index 76003e27..7fcd9e14 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -20,7 +20,7 @@ jobs: python-version: ["3.9"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: false diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 3c179628..6f894dd8 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -29,7 +29,7 @@ jobs: sudo apt update sudo apt -yq --no-install-suggests --no-install-recommends install pandoc make - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: false diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index c665d2d6..5fa4ac0e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -18,7 +18,7 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: false - uses: actions/setup-python@v4 From c98e0d0e4701144a074f3fabb4f22bec18d41d2c Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Wed, 4 Oct 2023 16:51:07 +0200 Subject: [PATCH 26/43] Improve catalogue printing on dark background and narrow screens (#135) - Use more generic colors that work on both dark and light backgrounds. The colors are taken from the default palette in seaborn. - Change the overflow mechanism to fold instead of cropping the entries in the table. This works better on narrower screens. - Color by row instead of by column. This looks better in the case where an entry spans multiple rows. I also fix the console width to 210 columns in tests to get deterministic results because depending on the width, some rows might fold to next line. Now there is one line per catalogue entry in the table. --- roseau/load_flow/conftest.py | 7 +++ .../tests/test_transformer_parameters.py | 44 +++++++++---------- .../models/transformers/parameters.py | 21 +++++---- roseau/load_flow/network.py | 21 +++++---- .../tests/test_electrical_network.py | 20 ++++----- roseau/load_flow/utils/__init__.py | 3 +- roseau/load_flow/utils/console.py | 22 ++++++++++ 7 files changed, 87 insertions(+), 51 deletions(-) diff --git a/roseau/load_flow/conftest.py b/roseau/load_flow/conftest.py index d8079b39..e2181a46 100644 --- a/roseau/load_flow/conftest.py +++ b/roseau/load_flow/conftest.py @@ -4,6 +4,8 @@ import pytest from pandas.testing import assert_frame_equal +from roseau.load_flow.utils import console + # Variable to test the network HERE = Path(__file__).parent.expanduser().absolute() TEST_ALL_NETWORKS_DATA_FOLDER = HERE / "tests" / "data" / "networks" @@ -78,6 +80,11 @@ def dgs_network_path(request) -> Path: return request.param +@pytest.fixture(autouse=True, scope="session") +def _set_console_width() -> None: + console.width = 210 + + # # Utils # diff --git a/roseau/load_flow/models/tests/test_transformer_parameters.py b/roseau/load_flow/models/tests/test_transformer_parameters.py index 61a28c78..ce35849f 100644 --- a/roseau/load_flow/models/tests/test_transformer_parameters.py +++ b/roseau/load_flow/models/tests/test_transformer_parameters.py @@ -412,18 +412,18 @@ def test_print_catalogue(): # Print the entire catalogue with console.capture() as capture: TransformerParameters.print_catalogue() - assert len(capture.get().split("\n")) == 138 + assert len(capture.get().split("\n")) == 136 # Filter on a single attribute for field_name, value, expected_lines in ( - ("id", "SE_Minera_A0Ak_50kVA", 9), - ("manufacturer", "SE", 124), - ("range", r"min.*", 64), - ("efficiency", "c0", 37), - ("type", "dy", 134), - ("sn", Q_(160, "kVA"), 18), - ("uhv", Q_(20, "kV"), 138), - ("ulv", 400, 138), + ("id", "SE_Minera_A0Ak_50kVA", 7), + ("manufacturer", "SE", 122), + ("range", r"min.*", 62), + ("efficiency", "c0", 35), + ("type", "dy", 132), + ("sn", Q_(160, "kVA"), 16), + ("uhv", Q_(20, "kV"), 136), + ("ulv", 400, 136), ): with console.capture() as capture: TransformerParameters.print_catalogue(**{field_name: value}) @@ -431,13 +431,13 @@ def test_print_catalogue(): # Filter on two attributes for field_name, value, expected_lines in ( - ("id", "SE_Minera_A0Ak_50kVA", 9), - ("range", "minera", 64), - ("efficiency", "c0", 37), - ("type", r"^d.*11$", 120), - ("sn", Q_(160, "kVA"), 17), - ("uhv", Q_(20, "kV"), 124), - ("ulv", 400, 124), + ("id", "SE_Minera_A0Ak_50kVA", 7), + ("range", "minera", 62), + ("efficiency", "c0", 35), + ("type", r"^d.*11$", 118), + ("sn", Q_(160, "kVA"), 15), + ("uhv", Q_(20, "kV"), 122), + ("ulv", 400, 122), ): with console.capture() as capture: TransformerParameters.print_catalogue(**{field_name: value}, manufacturer="se") @@ -445,12 +445,12 @@ def test_print_catalogue(): # Filter on three attributes for field_name, value, expected_lines in ( - ("id", "se_VEGETA_C0BK_3150kva", 9), - ("efficiency", r"c0[abc]k", 23), - ("type", "dyn", 38), - ("sn", Q_(160, "kVA"), 10), - ("uhv", Q_(20, "kV"), 38), - ("ulv", 400, 38), + ("id", "se_VEGETA_C0BK_3150kva", 7), + ("efficiency", r"c0[abc]k", 21), + ("type", "dyn", 36), + ("sn", Q_(160, "kVA"), 8), + ("uhv", Q_(20, "kV"), 36), + ("ulv", 400, 36), ): with console.capture() as capture: TransformerParameters.print_catalogue(**{field_name: value}, manufacturer="se", range=r"^vegeta$") diff --git a/roseau/load_flow/models/transformers/parameters.py b/roseau/load_flow/models/transformers/parameters.py index c3f8acf9..a00247d6 100644 --- a/roseau/load_flow/models/transformers/parameters.py +++ b/roseau/load_flow/models/transformers/parameters.py @@ -2,6 +2,7 @@ import re import textwrap from importlib import resources +from itertools import cycle from pathlib import Path from typing import NoReturn, Optional, Union @@ -14,7 +15,7 @@ from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.typing import Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps -from roseau.load_flow.utils import CatalogueMixin, Identifiable, JsonMixin, console +from roseau.load_flow.utils import CatalogueMixin, Identifiable, JsonMixin, console, palette logger = logging.getLogger(__name__) @@ -487,14 +488,14 @@ def print_catalogue( # Start creating a table to display the results table = Table(title="Available Transformer Parameters") - table.add_column("Id") - table.add_column("Manufacturer", style="color(1)", header_style="color(1)") - table.add_column("Product range", style="color(2)", header_style="color(2)") - table.add_column("Efficiency", style="color(3)", header_style="color(3)") - table.add_column("Type", style="color(4)", header_style="color(4)") - table.add_column("Nominal power (kVA)", justify="right", style="color(5)", header_style="color(5)") - table.add_column("High voltage (kV)", justify="right", style="color(6)", header_style="color(6)") - table.add_column("Low voltage (kV)", justify="right", style="color(9)", header_style="color(9)") + table.add_column("Id", overflow="fold") + table.add_column("Manufacturer", overflow="fold") + table.add_column("Product range", overflow="fold") + table.add_column("Efficiency", overflow="fold") + table.add_column("Type", overflow="fold") + table.add_column("Nominal power (kVA)", justify="right", overflow="fold") + table.add_column("High voltage (kV)", justify="right", overflow="fold") + table.add_column("Low voltage (kV)", justify="right", overflow="fold") empty_table = True # Match on the manufacturer, range, efficiency and type @@ -525,6 +526,7 @@ def print_catalogue( # Iterate over the transformers selected_index = catalogue_mask[catalogue_mask].index + cycler = cycle(palette) for idx in selected_index: empty_table = False table.add_row( @@ -536,6 +538,7 @@ def print_catalogue( f"{catalogue_data.at[idx, 'sn']/1000:.1f}", # VA to kVA f"{catalogue_data.at[idx, 'uhv']/1000:.1f}", # V to kV f"{catalogue_data.at[idx, 'ulv']/1000:.1f}", # V to kV + style=next(cycler), ) # Handle the case of an empty table diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index dfde9152..4e18b238 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -8,6 +8,7 @@ import warnings from collections.abc import Sized from importlib import resources +from itertools import cycle from pathlib import Path from typing import NoReturn, Optional, TypeVar, Union from urllib.parse import urljoin @@ -37,7 +38,7 @@ ) from roseau.load_flow.solvers import check_solver_params from roseau.load_flow.typing import Authentication, Id, JsonDict, Solver, StrPath -from roseau.load_flow.utils import CatalogueMixin, JsonMixin, console +from roseau.load_flow.utils import CatalogueMixin, JsonMixin, console, palette logger = logging.getLogger(__name__) @@ -1298,14 +1299,14 @@ def print_catalogue( # Start creating a table to display the results table = Table(title="Available Networks") - table.add_column("Name") - table.add_column("Nb buses", justify="right", style="color(1)", header_style="color(1)") - table.add_column("Nb branches", justify="right", style="color(2)", header_style="color(2)") - table.add_column("Nb loads", justify="right", style="color(3)", header_style="color(3)") - table.add_column("Nb sources", justify="right", style="color(4)", header_style="color(4)") - table.add_column("Nb grounds", justify="right", style="color(5)", header_style="color(5)") - table.add_column("Nb potential refs", justify="right", style="color(6)", header_style="color(6)") - table.add_column("Available load points", justify="right", style="color(9)", header_style="color(9)") + table.add_column("Name", overflow="fold") + table.add_column("Nb buses", justify="right", overflow="fold") + table.add_column("Nb branches", justify="right", overflow="fold") + table.add_column("Nb loads", justify="right", overflow="fold") + table.add_column("Nb sources", justify="right", overflow="fold") + table.add_column("Nb grounds", justify="right", overflow="fold") + table.add_column("Nb potential refs", justify="right", overflow="fold") + table.add_column("Available load points", overflow="fold") empty_table = True # Match on the name @@ -1334,6 +1335,7 @@ def match_load_point_function(x: str) -> bool: return x.lower() == load_point_name_pattern # Iterate over the networks + cycler = cycle(palette) for c_name in match_names_list: c_data = catalogue_data[c_name] available_load_points = c_data["load_points"] @@ -1348,6 +1350,7 @@ def match_load_point_function(x: str) -> bool: str(c_data["nb_grounds"]), str(c_data["nb_potential_refs"]), ", ".join(repr(x) for x in sorted(c_data["load_points"])), + style=next(cycler), ) # Handle the case of an empty table diff --git a/roseau/load_flow/tests/test_electrical_network.py b/roseau/load_flow/tests/test_electrical_network.py index 1dbdd471..42b0fefc 100644 --- a/roseau/load_flow/tests/test_electrical_network.py +++ b/roseau/load_flow/tests/test_electrical_network.py @@ -1501,37 +1501,37 @@ def test_print_catalogue(): # Print the entire catalogue with console.capture() as capture: ElectricalNetwork.print_catalogue() - assert len(capture.get().split("\n")) == 88 + assert len(capture.get().split("\n")) == 46 # Filter on the network name with console.capture() as capture: ElectricalNetwork.print_catalogue(name="MV") - assert len(capture.get().split("\n")) == 48 + assert len(capture.get().split("\n")) == 26 with console.capture() as capture: ElectricalNetwork.print_catalogue(name=re.compile(r"^MV")) - assert len(capture.get().split("\n")) == 48 + assert len(capture.get().split("\n")) == 26 # Filter on the load point name with console.capture() as capture: ElectricalNetwork.print_catalogue(load_point_name="winter") - assert len(capture.get().split("\n")) == 88 + assert len(capture.get().split("\n")) == 46 with console.capture() as capture: ElectricalNetwork.print_catalogue(load_point_name=re.compile(r"^Winter")) - assert len(capture.get().split("\n")) == 88 + assert len(capture.get().split("\n")) == 46 # Filter on both with console.capture() as capture: ElectricalNetwork.print_catalogue(name="MV", load_point_name="winter") - assert len(capture.get().split("\n")) == 48 + assert len(capture.get().split("\n")) == 26 with console.capture() as capture: ElectricalNetwork.print_catalogue(name="MV", load_point_name=re.compile(r"^Winter")) - assert len(capture.get().split("\n")) == 48 + assert len(capture.get().split("\n")) == 26 with console.capture() as capture: ElectricalNetwork.print_catalogue(name=re.compile(r"^MV"), load_point_name="winter") - assert len(capture.get().split("\n")) == 48 + assert len(capture.get().split("\n")) == 26 with console.capture() as capture: ElectricalNetwork.print_catalogue(name=re.compile(r"^MV"), load_point_name=re.compile(r"^Winter")) - assert len(capture.get().split("\n")) == 48 + assert len(capture.get().split("\n")) == 26 # Regexp error with console.capture() as capture: @@ -1539,4 +1539,4 @@ def test_print_catalogue(): assert len(capture.get().split("\n")) == 2 with console.capture() as capture: ElectricalNetwork.print_catalogue(load_point_name=r"^winter[0-]") - assert len(capture.get().split("\n")) == 3 + assert len(capture.get().split("\n")) == 2 diff --git a/roseau/load_flow/utils/__init__.py b/roseau/load_flow/utils/__init__.py index 99e7cb65..b3156715 100644 --- a/roseau/load_flow/utils/__init__.py +++ b/roseau/load_flow/utils/__init__.py @@ -1,7 +1,7 @@ """ This module contains utility classes and functions for Roseau Load Flow. """ -from roseau.load_flow.utils.console import console +from roseau.load_flow.utils.console import console, palette from roseau.load_flow.utils.constants import CX, DELTA_P, EPSILON_0, EPSILON_R, MU_0, MU_R, OMEGA, PI, RHO, TAN_D, F from roseau.load_flow.utils.mixins import CatalogueMixin, Identifiable, JsonMixin from roseau.load_flow.utils.types import ConductorType, InsulatorType, LineType @@ -29,4 +29,5 @@ "InsulatorType", # Console "console", + "palette", ] diff --git a/roseau/load_flow/utils/console.py b/roseau/load_flow/utils/console.py index a9463afd..c16e9c7f 100644 --- a/roseau/load_flow/utils/console.py +++ b/roseau/load_flow/utils/console.py @@ -1,3 +1,25 @@ from rich.console import Console console = Console() + +palette = [ + "#4c72b0", + "#dd8452", + "#55a868", + "#c44e52", + "#8172b3", + "#937860", + "#da8bc3", + "#8c8c8c", + "#ccb974", + "#64b5cd", +] +"""Color palette for the catalogue tables. + +This is seaborn's default color palette. Generated with: +```python +import seaborn as sns +sns.set_theme() +list(sns.color_palette().as_hex()) +``` +""" From ec177be95f7173f24879a987110b912337e234ce Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Mon, 9 Oct 2023 15:49:15 +0200 Subject: [PATCH 27/43] Add network constraints (limits) for load flow analysis (#138) The constraints are not used by the load flow solver. They are only used to analyze the results. The limits that can be defined include: - For buses: minimum and maximum voltages. Use `bus.res_violated` to see if the bus has over- or under-voltage. - For lines: a maximum current. Use `line.res_violated` to see if the loading of any of the line's cables is too high. - For transformers: a maximum power. Use `transformer.res_violated` to see if the transformer loading is too high. - The new fields also appear in the data frames of the network. --- .pre-commit-config.yaml | 1 + .vscode/settings.json | 13 +- doc/Changelog.md | 8 + doc/usage/Getting_Started.md | 190 ++-- roseau/load_flow/exceptions.py | 1 + roseau/load_flow/io/dict.py | 14 +- roseau/load_flow/io/tests/test_dict.py | 30 +- roseau/load_flow/models/branches.py | 4 +- roseau/load_flow/models/buses.py | 158 ++- roseau/load_flow/models/grounds.py | 10 +- roseau/load_flow/models/lines/lines.py | 24 +- roseau/load_flow/models/lines/parameters.py | 56 +- .../models/loads/flexible_parameters.py | 8 +- roseau/load_flow/models/loads/loads.py | 6 +- roseau/load_flow/models/potential_refs.py | 2 +- roseau/load_flow/models/sources.py | 2 +- roseau/load_flow/models/tests/test_buses.py | 207 ++++ .../models/tests/test_line_parameters.py | 18 + roseau/load_flow/models/tests/test_lines.py | 40 + .../tests/test_transformer_parameters.py | 27 + .../models/tests/test_transformers.py | 38 + .../models/transformers/parameters.py | 54 +- .../models/transformers/transformers.py | 25 +- roseau/load_flow/network.py | 406 ++++++-- roseau/load_flow/tests/test_converters.py | 4 +- .../tests/test_electrical_network.py | 915 ++++++++++++++---- roseau/load_flow/units.py | 15 +- roseau/load_flow/utils/__init__.py | 13 +- roseau/load_flow/utils/mixins.py | 10 +- roseau/load_flow/utils/types.py | 43 + 30 files changed, 1932 insertions(+), 410 deletions(-) create mode 100644 roseau/load_flow/models/tests/test_transformers.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7273267c..38ffe32d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,3 +38,4 @@ repos: hooks: - id: prettier args: ["--print-width", "120"] + exclude: ^.vscode/ diff --git a/.vscode/settings.json b/.vscode/settings.json index fe97411f..8071bd53 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,24 +3,21 @@ "jupyter.notebookFileRoot": "${workspaceFolder}", "notebook.formatOnSave.enabled": true, "notebook.codeActionsOnSave": { - "source.organizeImports.ruff": true + "source.organizeImports.ruff": "explicit", }, // Python "python.analysis.diagnosticSeverityOverrides": { "reportInvalidStringEscapeSequence": "warning", "reportImportCycles": "warning", - "reportUnusedImport": "warning" + "reportUnusedImport": "warning", }, - "python.formatting.provider": "none", - "python.testing.pytestArgs": [], - "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "[python]": { "editor.defaultFormatter": "ms-python.black-formatter", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.organizeImports.ruff": true - } - } + "source.organizeImports.ruff": "explicit", + }, + }, } diff --git a/doc/Changelog.md b/doc/Changelog.md index 19f8c3af..845e0ce2 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,14 @@ **In development** +- {gh-pr}`138` Add network constraints for analysis of the results. + - Buses can define minimum and maximum voltages. Use `bus.res_violated` to see if the bus has + over- or under-voltage. + - Lines can define a maximum current. Use `line.res_violated` to see if the loading of any of the + line's cables is too high. + - Transformers can define a maximum power. Use `transformer.res_violated` to see if the transformer + loading is too high. + - The new fields also appear in the data frames of the network. - {gh-pr}`133` {gh-issue}`126` Add Qmin and Qmax limits of flexible parameters. - {gh-pr}`132` {gh-issue}`101` Document extra utilities including converters and constants. - {gh-pr}`131` {gh-issue}`127` Improve the documentation of the flexible loads. diff --git a/doc/usage/Getting_Started.md b/doc/usage/Getting_Started.md index be252290..00a93256 100644 --- a/doc/usage/Getting_Started.md +++ b/doc/usage/Getting_Started.md @@ -9,9 +9,10 @@ In this tutorial you will learn how to: 1. [Create a simple electrical network with one source and one load](gs-creating-network); 2. [Solve a load flow](gs-solving-load-flow); 3. [Get the results of the load flow](gs-getting-results); -4. [Update the elements of the network](gs-updating-elements); -5. [Save the network and the results to the disk for later analysis](gs-saving-network); -6. [Load the saved network and the results from the disk](gs-loading-network). +4. [Analyze the results](gs-analysis-and-violations); +5. [Update the elements of the network](gs-updating-elements); +6. [Save the network and the results to the disk for later analysis](gs-saving-network); +7. [Load the saved network and the results from the disk](gs-loading-network). (gs-creating-network)= @@ -70,9 +71,17 @@ It leads to the following code >>> import numpy as np ... from roseau.load_flow import * +>>> # Nominal phase-to-neutral voltage +... un = 400 / np.sqrt(3) # In Volts + +>>> # Optional network limits (for results analysis only) +... u_min = 0.9 * un # V +... u_max = 1.1 * un # V +... i_max = 500.0 # A + >>> # Create two buses -... source_bus = Bus(id="sb", phases="abcn") -... load_bus = Bus(id="lb", phases="abcn") +... source_bus = Bus(id="sb", phases="abcn", min_voltage=u_min, max_voltage=u_max) +... load_bus = Bus(id="lb", phases="abcn", min_voltage=u_min, max_voltage=u_max) >>> # Define the reference of potentials to be the neutral of the source bus ... ground = Ground(id="gnd") @@ -81,17 +90,20 @@ It leads to the following code ... ground.connect(source_bus, phase="n") >>> # Create a LV source at the first bus -... # Volts (phase-to-neutral because the source is connected to the neutral) -... un = 400 / np.sqrt(3) -... source_voltages = [un, un * np.exp(-2j * np.pi / 3), un * np.exp(2j * np.pi / 3)] -... vs = VoltageSource(id="vs", bus=source_bus, voltages=source_voltages) +... # (phase-to-neutral voltage because the source is connected to the neutral) +... source_voltages = un * np.exp([0, -2j * np.pi / 3, 2j * np.pi / 3]) +... vs = VoltageSource( +... id="vs", bus=source_bus, voltages=source_voltages +... ) # phases="abcn" inferred from the bus >>> # Add a load at the second bus ... load = PowerLoad(id="load", bus=load_bus, powers=[10e3 + 0j, 10e3, 10e3]) # VA >>> # Add a LV line between the source bus and the load bus ... # R = 0.1 Ohm/km, X = 0 -... lp = LineParameters("lp", z_line=(0.1 + 0.0j) * np.eye(4, dtype=complex)) +... lp = LineParameters( +... "lp", z_line=(0.1 + 0.0j) * np.eye(4, dtype=complex), max_current=i_max +... ) ... line = Line(id="line", bus1=source_bus, bus2=load_bus, parameters=lp, length=2.0) ``` @@ -208,15 +220,16 @@ The results returned by the `res_` properties are also `Quantity` objects. The available results depend on the type of element. The following table summarizes the available results for each element type: -| Element type | Available results | -| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| `Bus` | `res_potentials`, `res_voltages` | -| `Line` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages`, `res_series_power_losses`, `res_shunt_power_losses`, `res_power_losses` | -| `Transformer`, `Switch` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages` | -| `ImpedanceLoad`, `CurrentLoad`, `PowerLoad` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages`, `res_flexible_powers`⁎ | -| `VoltageSource` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages` | -| `Ground` | `res_potential` | -| `PotentialRef` | `res_current` _(Always zero for a successful load flow)_ | +| Element type | Available results | +| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Bus` | `res_potentials`, `res_voltages`, `res_violated` | +| `Line` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages`, `res_series_power_losses`, `res_shunt_power_losses`, `res_power_losses`, `res_violated` | +| `Transformer` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages`, `res_violated` | +| `Switch` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages` | +| `ImpedanceLoad`, `CurrentLoad`, `PowerLoad` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages`, `res_flexible_powers`⁎ | +| `VoltageSource` | `res_currents`, `res_powers`, `res_potentials`, `res_voltages` | +| `Ground` | `res_potential` | +| `PotentialRef` | `res_current` _(Always zero for a successful load flow)_ | ⁎: `res_flexible_powers` is only available for flexible loads (`PowerLoad`s with `flexible_params`). You'll see an example on the usage of flexible loads in the _Flexible Loads_ section. @@ -242,7 +255,8 @@ array([0.22192818, 0.22192818, 0.22192818]) ```{important} Everywhere in `roseau-load-flow`, the `voltages` of an element depend on the element's `phases`. -Voltages of elements connected in a *Star (wye)* configuration (elements that have a neutral connection indicated by the presence of the `'n'` char in their `phases` attribute) are the +Voltages of elements connected in a *Star (wye)* configuration (elements that have a neutral +connection indicated by the presence of the `'n'` char in their `phases` attribute) are the **phase-to-neutral** voltages. Voltages of elements connected in a *Delta* configuration (elements that do not have a neutral connection indicated by the absence of the `'n'` char from their `phases` attribute) are the **phase-to-phase** voltages. This is true for *input* voltages, such @@ -276,9 +290,13 @@ The results can also be retrieved for the entire network using `res_` properties Available results for the network are: - `res_buses`: Buses potentials indexed by _(bus id, phase)_ -- `res_buses_voltages`: Buses voltages indexed by _(bus id, voltage phase)_ +- `res_buses_voltages`: Buses voltages and voltage limits indexed by _(bus id, voltage phase)_ - `res_branches`: Branches currents, powers, and potentials indexed by _(branch id, phase)_ -- `res_lines`: Lines currents, powers, potentials, series losses, series currents indexed by _(line id, phase)_ +- `res_transformers`: Transformers currents, powers, potentials, and power limits indexed by + _(transformer id, phase)_ +- `res_lines`: Lines currents, powers, potentials, series losses, series currents, and current + limits indexed by _(line id, phase)_ +- `res_switches`: Switches currents, powers, and potentials indexed by _(switch id, phase)_ - `res_loads`: Loads currents, powers, and potentials indexed by _(load id, phase)_ - `res_loads_voltages`: Loads voltages indexed by _(load id, voltage phase)_ - `res_loads_flexible_powers`: Loads flexible powers (only for flexible loads) indexed by @@ -317,14 +335,14 @@ All the following tables are rounded to 2 decimals to be properly displayed. >>> en.res_buses_voltages ``` -| bus_id | phase | voltage | -| :----- | :---- | -------------: | -| sb | an | 230.94+0j | -| sb | bn | -115.47-200j | -| sb | cn | -115.47+200j | -| lb | an | 221.93+0j | -| lb | bn | -110.96-192.2j | -| lb | cn | -110.96+192.2j | +| bus_id | phase | voltage | min_voltage | max_voltage | violated | +| :----- | :---- | -------------: | ----------: | ----------: | :------- | +| sb | an | 230.94+0j | 207.846 | 254.034 | False | +| sb | bn | -115.47-200j | 207.846 | 254.034 | False | +| sb | cn | -115.47+200j | 207.846 | 254.034 | False | +| lb | an | 221.93-0j | 207.846 | 254.034 | False | +| lb | bn | -110.96-192.2j | 207.846 | 254.034 | False | +| lb | cn | -110.96+192.2j | 207.846 | 254.034 | False | ```pycon >>> en.res_branches @@ -341,12 +359,26 @@ All the following tables are rounded to 2 decimals to be properly displayed. >>> en.res_lines ``` -| branch_id | phase | current1 | current2 | power1 | power2 | potential1 | potential2 | series_losses | series_current | -| :-------- | :---- | ------------: | -----------: | ----------: | --------: | -----------: | -------------: | ------------: | -------------: | -| line | a | 45.06+0j | -45.06-0j | 10406.07-0j | -10000+0j | 230.94+0j | 221.93-0j | 406.07-0j | 45.06+0j | -| line | b | -22.53-39.02j | 22.53+39.02j | 10406.07+0j | -10000-0j | -115.47-200j | -110.96-192.2j | 406.07-0j | -22.53-39.02j | -| line | c | -22.53+39.02j | 22.53-39.02j | 10406.07-0j | -10000+0j | -115.47+200j | -110.96+192.2j | 406.07+0j | -22.53+39.02j | -| line | n | 0j | -0j | -0j | -0j | 0j | -0j | -0j | -0+0j | +| line_id | phase | current1 | current2 | power1 | power2 | potential1 | potential2 | series_losses | series_current | max_current | violated | +| :------ | :---- | ------------: | -----------: | ----------: | --------: | -----------: | -------------: | ------------: | -------------: | ----------: | :------- | +| line | a | 45.06-0j | -45.06+0j | 10406.07+0j | -10000-0j | 230.94+0j | 221.93+0j | 406.07-0j | 45.06-0j | 500 | False | +| line | b | -22.53-39.02j | 22.53+39.02j | 10406.07+0j | -10000-0j | -115.47-200j | -110.96-192.2j | 406.07-0j | -22.53-39.02j | 500 | False | +| line | c | -22.53+39.02j | 22.53-39.02j | 10406.07-0j | -10000+0j | -115.47+200j | -110.96+192.2j | 406.07+0j | -22.53+39.02j | 500 | False | +| line | n | -0-0j | 0j | -0+0j | -0j | 0j | 0j | -0j | -0-0j | 500 | False | + +```pycon +>>> en.res_transformers +``` + +| transformer_id | phase | current1 | current2 | power1 | power2 | potential1 | potential2 | max_power | violated | +| -------------- | ----- | -------- | -------- | ------ | ------ | ---------- | ---------- | --------- | -------- | + +```pycon +>>> en.res_switches +``` + +| switch_id | phase | current1 | current2 | power1 | power2 | potential1 | potential2 | +| --------- | ----- | -------- | -------- | ------ | ------ | ---------- | ---------- | ```pycon >>> en.res_loads @@ -373,12 +405,12 @@ All the following tables are rounded to 2 decimals to be properly displayed. >>> en.res_sources ``` -| source_id | phase | current | power | potential | -| :-------- | :---- | -----------: | ------------: | -----------: | -| vs | a | -45.06-0j | -10406.07+0j) | 230.94+0j | -| vs | b | 22.53+39.02j | -10406.07-0j) | -115.47-200j | -| vs | c | 22.53-39.02j | -10406.07+0j) | -115.47+200j | -| vs | n | 0j | 0j | 0j | +| source_id | phase | current | power | potential | +| :-------- | :---- | -----------: | -----------: | -----------: | +| vs | a | -45.06-0j | -10406.07+0j | 230.94+0j | +| vs | b | 22.53+39.02j | -10406.07-0j | -115.47-200j | +| vs | c | 22.53-39.02j | -10406.07+0j | -115.47+200j | +| vs | n | 0j | 0j | 0j | ```pycon >>> en.res_grounds @@ -400,33 +432,71 @@ Using the `transform` method of data frames, the results can easily be converted to magnitude and angle values. ```pycon ->>> en.res_buses_voltages.transform([np.abs, np.angle]) +>>> en.res_buses_voltages["voltage"].transform([np.abs, np.angle]) ``` -| bus_id | phase | ('voltage', 'absolute') | ('voltage', 'angle') | -| :----- | :---- | ----------------------: | -------------------: | -| sb | an | 230.94 | 0 | -| sb | bn | 230.94 | -2.0944 | -| sb | cn | 230.94 | 2.0944 | -| lb | an | 221.928 | 2.89102e-19 | -| lb | bn | 221.928 | -2.0944 | -| lb | cn | 221.928 | 2.0944 | +| bus_id | phase | absolute | angle | +| :----- | :---- | -------: | ----------: | +| sb | an | 230.94 | 0 | +| sb | bn | 230.94 | -2.0944 | +| sb | cn | 230.94 | 2.0944 | +| lb | an | 221.928 | 2.89102e-19 | +| lb | bn | 221.928 | -2.0944 | +| lb | cn | 221.928 | 2.0944 | Or, if you prefer degrees: ```pycon >>> import functools as ft -... en.res_buses_voltages.transform([np.abs, ft.partial(np.angle, deg=True)]) +... en.res_buses_voltages["voltage"].transform([np.abs, ft.partial(np.angle, deg=True)]) ``` -| bus_id | phase | ('voltage', 'absolute') | ('voltage', 'angle') | -| :----- | :---- | ----------------------: | -------------------: | -| sb | an | 230.94 | 0 | -| sb | bn | 230.94 | -120 | -| sb | cn | 230.94 | 120 | -| lb | an | 221.928 | 1.65643e-17 | -| lb | bn | 221.928 | -120 | -| lb | cn | 221.928 | 120 | +| bus_id | phase | absolute | angle | +| :----- | :---- | -------: | ----------: | +| sb | an | 230.94 | 0 | +| sb | bn | 230.94 | -120 | +| sb | cn | 230.94 | 120 | +| lb | an | 221.928 | 1.65643e-17 | +| lb | bn | 221.928 | -120 | +| lb | cn | 221.928 | 120 | + +(gs-analysis-and-violations)= + +## Analyzing the results and detecting violations + +In the example network above, `min_voltage` and `max_voltage` arguments were passed to the `Bus` +constructor and `max_current` was passed to the `LineParameters` constructor. These arguments +define the limits of the network that can be used to check if the network is in a valid state +or not. Note that these limits have no effect on the load flow calculation. + +If you set `min_voltage` or `max_voltage` on a bus, the `res_violated` property will tell you if +the voltage limits are violated or not at this bus. Here, the voltage limits are not violated. + +```pycon +>>> load_bus.res_violated +False +``` + +Similarly, if you set `max_current` on a line, the `res_violated` property will tell you if the +current loading of the line in any phase exceeds the limit. Here, the current limit is not violated. + +```pycon +>>> line.res_violated +False +``` + +The power limit of the transformer can be defined using the `max_power` argument of the +`TransformerParameters`. Transformers also have a `res_violated` property that indicates if the +power loading of the transformer exceeds the limit. + +The data frame results on the electrical network also include a `violated` column that indicates if +the limits are violated or not for the corresponding element. + +```{tip} +You can use the {meth}`Bus.propagate_limits() ` method to +propagate the limits from a bus to its neighboring buses, that is, buses on the same side of a +transformer. +``` (gs-updating-elements)= diff --git a/roseau/load_flow/exceptions.py b/roseau/load_flow/exceptions.py index 31747d16..31d8ed0d 100644 --- a/roseau/load_flow/exceptions.py +++ b/roseau/load_flow/exceptions.py @@ -24,6 +24,7 @@ class RoseauLoadFlowExceptionCode(Enum): BAD_BUS_ID = auto() BAD_BUS_TYPE = auto() BAD_POTENTIALS_SIZE = auto() + BAD_VOLTAGES = auto() BAD_VOLTAGES_SIZE = auto() BAD_SHORT_CIRCUIT = auto() diff --git a/roseau/load_flow/io/dict.py b/roseau/load_flow/io/dict.py index e1b481d3..8db7ac4f 100644 --- a/roseau/load_flow/io/dict.py +++ b/roseau/load_flow/io/dict.py @@ -132,15 +132,15 @@ def network_from_dict( return buses, branches_dict, loads, sources, grounds, potential_refs -def network_to_dict(en: "ElectricalNetwork", include_geometry: bool) -> JsonDict: +def network_to_dict(en: "ElectricalNetwork", *, _lf_only: 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 network dictionary. + _lf_only: + Internal argument, please do not use. Returns: The created dictionary. @@ -155,7 +155,7 @@ def network_to_dict(en: "ElectricalNetwork", include_geometry: bool) -> JsonDict sources: list[JsonDict] = [] short_circuits: list[JsonDict] = [] for bus in en.buses.values(): - buses.append(bus.to_dict(include_geometry=include_geometry)) + buses.append(bus.to_dict(_lf_only=_lf_only)) for element in bus._connected_elements: if isinstance(element, AbstractLoad): assert element.bus is bus @@ -171,7 +171,7 @@ def network_to_dict(en: "ElectricalNetwork", include_geometry: bool) -> JsonDict lines_params_dict: dict[Id, LineParameters] = {} transformers_params_dict: dict[Id, TransformerParameters] = {} for branch in en.branches.values(): - branches.append(branch.to_dict(include_geometry=include_geometry)) + branches.append(branch.to_dict(_lf_only=_lf_only)) if isinstance(branch, Line): params_id = branch.parameters.id if params_id in lines_params_dict and branch.parameters != lines_params_dict[params_id]: @@ -192,13 +192,13 @@ def network_to_dict(en: "ElectricalNetwork", include_geometry: bool) -> JsonDict # Line parameters line_params: list[JsonDict] = [] for lp in lines_params_dict.values(): - line_params.append(lp.to_dict()) + line_params.append(lp.to_dict(_lf_only=_lf_only)) line_params.sort(key=lambda x: x["id"]) # Always keep the same order # Transformer parameters transformer_params: list[JsonDict] = [] for tp in transformers_params_dict.values(): - transformer_params.append(tp.to_dict()) + transformer_params.append(tp.to_dict(_lf_only=_lf_only)) transformer_params.sort(key=lambda x: x["id"]) # Always keep the same order res = { diff --git a/roseau/load_flow/io/tests/test_dict.py b/roseau/load_flow/io/tests/test_dict.py index cc9a1057..2420586f 100644 --- a/roseau/load_flow/io/tests/test_dict.py +++ b/roseau/load_flow/io/tests/test_dict.py @@ -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", geometry=Point(0.0, 0.0)) - load_bus = Bus(id="load bus", phases="abcn", geometry=Point(0.0, 1.0)) + source_bus = Bus(id="source", phases="abcn", geometry=Point(0.0, 0.0), min_voltage=0.9 * vn) + load_bus = Bus(id="load bus", phases="abcn", geometry=Point(0.0, 1.0), max_voltage=1.1 * vn) ground.connect(load_bus) p_ref = PotentialRef("pref", element=ground) vs = VoltageSource("vs", source_bus, phases="abcn", voltages=voltages) @@ -44,6 +44,8 @@ def test_to_dict(): grounds=[ground], potential_refs=[p_ref], ) + + # Same id, different line parameters -> fail with pytest.raises(RoseauLoadFlowException) as e: en.to_dict() assert "There are multiple line parameters with id 'test'" in e.value.msg @@ -52,17 +54,28 @@ 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() + + # Dict content + line2.parameters = lp1 + lp1.max_current = 1000 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] + assert np.isclose(res["buses"][0]["min_voltage"], 0.9 * vn) + assert np.isclose(res["buses"][1]["max_voltage"], 1.1 * vn) + assert np.isclose(res["lines_params"][0]["max_current"], 1000) - res = en.to_dict(include_geometry=False) + res = en.to_dict(_lf_only=True) 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] + assert "min_voltage" not in res["buses"][0] + assert "max_voltage" not in res["buses"][1] + assert "max_current" not in res["lines_params"][0] # Same id, different transformer parameters -> fail ground = Ground("ground") @@ -93,6 +106,8 @@ def test_to_dict(): grounds=[ground], potential_refs=[p_ref], ) + + # Same id, different transformer parameters -> fail with pytest.raises(RoseauLoadFlowException) as e: en.to_dict() assert "There are multiple transformer parameters with id 't'" in e.value.msg @@ -103,17 +118,24 @@ 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() + + # Dict content + transformer2.parameters = tp1 + tp1.max_power = 180_000 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] + assert np.isclose(res["transformers_params"][0]["max_power"], 180_000) - res = en.to_dict(include_geometry=False) + res = en.to_dict(_lf_only=True) 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] + assert "max_power" not in res["transformers_params"][0] def test_v0_to_v1_converter(monkeypatch): diff --git a/roseau/load_flow/models/branches.py b/roseau/load_flow/models/branches.py index c9206f6e..08459e75 100644 --- a/roseau/load_flow/models/branches.py +++ b/roseau/load_flow/models/branches.py @@ -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, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: res = { "id": self.id, "type": self.branch_type, @@ -135,7 +135,7 @@ def to_dict(self, include_geometry: bool = True) -> JsonDict: "bus1": self.bus1.id, "bus2": self.bus2.id, } - if self.geometry is not None and include_geometry: + if not _lf_only and self.geometry is not None: res["geometry"] = self.geometry.__geo_interface__ return res diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index 604ce662..8fead19a 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Any, Optional import numpy as np +import pandas as pd from shapely import Point from typing_extensions import Self @@ -40,6 +41,8 @@ def __init__( phases: str, geometry: Optional[Point] = None, potentials: Optional[Sequence[complex]] = None, + min_voltage: Optional[float] = None, + max_voltage: Optional[float] = None, **kwargs: Any, ) -> None: """Bus constructor. @@ -60,8 +63,13 @@ def __init__( potentials: An optional list of initial potentials of each phase of the bus. - ground: - The ground of the bus. + min_voltage: + An optional minimum voltage of the bus (V). It is not used in the load flow. + It must be a phase-neutral voltage if the bus has a neutral, phase-phase otherwise. + + max_voltage: + An optional maximum voltage of the bus (V). It is not used in the load flow. + It must be a phase-neutral voltage if the bus has a neutral, phase-phase otherwise. """ super().__init__(id, **kwargs) self._check_phases(id, phases=phases) @@ -70,6 +78,10 @@ def __init__( potentials = [0] * len(phases) self.potentials = potentials self.geometry = geometry + self._min_voltage: Optional[float] = None + self._max_voltage: Optional[float] = None + self.min_voltage = min_voltage + self.max_voltage = max_voltage self._res_potentials: Optional[np.ndarray] = None self._short_circuits: list[dict[str, Any]] = [] @@ -127,6 +139,124 @@ def _get_potentials_of(self, phases: str, warning: bool) -> np.ndarray: potentials = self._res_potentials_getter(warning) return np.array([potentials[self.phases.index(p)] for p in phases]) + @property + def min_voltage(self) -> Optional[Q_[float]]: + """The minimum voltage of the bus (V) if it is set.""" + return None if self._min_voltage is None else Q_(self._min_voltage, "V") + + @min_voltage.setter + @ureg_wraps(None, (None, "V"), strict=False) + def min_voltage(self, value: Optional[float]) -> None: + if value is not None and self._max_voltage is not None and value > self._max_voltage: + msg = ( + f"Cannot set min voltage of bus {self.id!r} to {value} V as it is higher than its " + f"max voltage ({self._max_voltage} V)." + ) + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_VOLTAGES) + if pd.isna(value): + value = None + self._min_voltage = value + + @property + def max_voltage(self) -> Optional[Q_[float]]: + """The maximum voltage of the bus (V) if it is set.""" + return None if self._max_voltage is None else Q_(self._max_voltage, "V") + + @max_voltage.setter + @ureg_wraps(None, (None, "V"), strict=False) + def max_voltage(self, value: Optional[float]) -> None: + if value is not None and self._min_voltage is not None and value < self._min_voltage: + msg = ( + f"Cannot set max voltage of bus {self.id!r} to {value} V as it is lower than its " + f"min voltage ({self._min_voltage} V)." + ) + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_VOLTAGES) + if pd.isna(value): + value = None + self._max_voltage = value + + @property + def res_violated(self) -> Optional[bool]: + """Whether the bus has voltage limits violations. + + Returns ``None`` if the bus has no voltage limits are not set. + """ + if self._min_voltage is None and self._max_voltage is None: + return None + voltages = abs(self._res_voltages_getter(warning=True)) + if self._min_voltage is None: + assert self._max_voltage is not None + return float(max(voltages)) > self._max_voltage + elif self._max_voltage is None: + return float(min(voltages)) < self._min_voltage + else: + return float(min(voltages)) < self._min_voltage or float(max(voltages)) > self._max_voltage + + def propagate_limits(self, force: bool = False) -> None: + """Propagate the voltage limits to neighbor buses. + + Neighbor buses here refers to buses connected to this bus through lines or switches. This + ensures that these voltage limits are only applied to buses with the same voltage level. If + a bus is connected to this bus through a transformer, the voltage limits are not propagated + to that bus. + + If this bus does not define any voltage limits, calling this method will unset the limits + of the neighbor buses. + + Args: + force: + If ``False`` (default), an exception is raised if connected buses already have + limits different from this bus. If ``True``, the limits are propagated even if + connected buses have different limits. + """ + from roseau.load_flow.models.lines import Line, Switch + + buses: set[Bus] = set() + visited: set[Element] = set() + remaining = set(self._connected_elements) + + while remaining: + branch = remaining.pop() + visited.add(branch) + if not isinstance(branch, (Line, Switch)): + continue + for element in branch._connected_elements: + if not isinstance(element, Bus) or element is self or element in buses: + continue + buses.add(element) + to_add = set(element._connected_elements).difference(visited) + remaining.update(to_add) + if not ( + force + or self._min_voltage is None + or element._min_voltage is None + or np.isclose(element._min_voltage, self._min_voltage) + ): + msg = ( + f"Cannot propagate the minimum voltage ({self._min_voltage} V) of bus {self.id!r} " + f"to bus {element.id!r} with different minimum voltage ({element._min_voltage} V)." + ) + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_VOLTAGES) + if not ( + force + or self._max_voltage is None + or element._max_voltage is None + or np.isclose(element._max_voltage, self._max_voltage) + ): + msg = ( + f"Cannot propagate the maximum voltage ({self._max_voltage} V) of bus {self.id!r} " + f"to bus {element.id!r} with different maximum voltage ({element._max_voltage} V)." + ) + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_VOLTAGES) + + for bus in buses: + bus._min_voltage = self._min_voltage + bus._max_voltage = self._max_voltage + # # Json Mixin interface # @@ -136,14 +266,26 @@ def from_dict(cls, data: JsonDict) -> Self: potentials = data.get("potentials") if potentials is not None: 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, include_geometry: bool = True) -> JsonDict: + return cls( + id=data["id"], + phases=data["phases"], + geometry=geometry, + potentials=potentials, + min_voltage=data.get("min_voltage"), + max_voltage=data.get("max_voltage"), + ) + + def to_dict(self, *, _lf_only: bool = False) -> 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 and include_geometry: - res["geometry"] = self.geometry.__geo_interface__ + if not _lf_only: + if self.geometry is not None: + res["geometry"] = self.geometry.__geo_interface__ + if self.min_voltage is not None: + res["min_voltage"] = self.min_voltage.magnitude + if self.max_voltage is not None: + res["max_voltage"] = self.max_voltage.magnitude return res def results_from_dict(self, data: JsonDict) -> None: @@ -204,6 +346,6 @@ def short_circuits(self) -> list[dict[str, Any]]: """Return the list of short-circuits of this bus.""" return self._short_circuits[:] # return a copy as users should not modify the list directly - def clear_short_circuits(self): + def clear_short_circuits(self) -> None: """Remove the short-circuits.""" self._short_circuits = [] diff --git a/roseau/load_flow/models/grounds.py b/roseau/load_flow/models/grounds.py index bbaf0cb1..ca982213 100644 --- a/roseau/load_flow/models/grounds.py +++ b/roseau/load_flow/models/grounds.py @@ -1,14 +1,16 @@ import logging -from typing import Any, Optional +from typing import TYPE_CHECKING, Any, Optional from typing_extensions import Self from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.models.buses import Bus from roseau.load_flow.models.core import Element from roseau.load_flow.typing import Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps +if TYPE_CHECKING: + from roseau.load_flow.models.buses import Bus + logger = logging.getLogger(__name__) @@ -65,7 +67,7 @@ def connected_buses(self) -> dict[Id, str]: """The bus ID and phase of the buses connected to this ground.""" return self._connected_buses.copy() # copy so that the user does not change it - def connect(self, bus: Bus, phase: str = "n") -> None: + def connect(self, bus: "Bus", phase: str = "n") -> None: """Connect the ground to a bus on the given phase. Args: @@ -97,7 +99,7 @@ def from_dict(cls, data: JsonDict) -> Self: self._connected_buses = data["buses"] return self - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: # Shunt lines and potential references will have the ground in their dict not here. return { "id": self.id, diff --git a/roseau/load_flow/models/lines/lines.py b/roseau/load_flow/models/lines/lines.py index 725212b5..36564fd7 100644 --- a/roseau/load_flow/models/lines/lines.py +++ b/roseau/load_flow/models/lines/lines.py @@ -292,6 +292,13 @@ def y_shunt(self) -> Q_[np.ndarray]: """Shunt admittance of the line in Siemens""" return self.parameters._y_shunt * self._length + @property + def max_current(self) -> Optional[Q_[float]]: + """The maximum current loading of the line in A.""" + # Do not add a setter. The user must know that if they change the max_current, it changes + # for all lines that share the parameters. It is better to set it on the parameters. + return self.parameters.max_current + @property def with_shunt(self) -> bool: return self.parameters.with_shunt @@ -369,12 +376,25 @@ def res_power_losses(self) -> Q_[np.ndarray]: """Get the power losses in the line (VA).""" return self._res_power_losses_getter(warning=True) + @property + def res_violated(self) -> Optional[bool]: + """Whether the line current exceeds the maximum current (loading > 100%). + + Returns ``None`` if the maximum current is not set. + """ + i_max = self.parameters._max_current + if i_max is None: + return None + currents1, currents2 = self._res_currents_getter(warning=True) + # True if any phase is overloaded + return float(np.max([abs(currents1), abs(currents2)])) > i_max + # # Json Mixin interface # - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: res = { - **super().to_dict(include_geometry=include_geometry), + **super().to_dict(_lf_only=_lf_only), "length": self._length, "params_id": self.parameters.id, } diff --git a/roseau/load_flow/models/lines/parameters.py b/roseau/load_flow/models/lines/parameters.py index c64731d0..f9c86e68 100644 --- a/roseau/load_flow/models/lines/parameters.py +++ b/roseau/load_flow/models/lines/parameters.py @@ -43,8 +43,10 @@ class LineParameters(Identifiable, JsonMixin): rf"^({_type_re})_({_material_re})_{_section_re}$", flags=re.IGNORECASE ) - @ureg_wraps(None, (None, None, "ohm/km", "S/km"), strict=False) - def __init__(self, id: Id, z_line: np.ndarray, y_shunt: Optional[np.ndarray] = None) -> None: + @ureg_wraps(None, (None, None, "ohm/km", "S/km", "A"), strict=False) + def __init__( + self, id: Id, z_line: np.ndarray, y_shunt: Optional[np.ndarray] = None, max_current: Optional[float] = None + ) -> None: """LineParameters constructor. Args: @@ -56,6 +58,9 @@ def __init__(self, id: Id, z_line: np.ndarray, y_shunt: Optional[np.ndarray] = N y_shunt: The Y matrix of the line (Siemens/km). This field is optional if the line has no shunt part. + + max_current: + An optional maximum current loading of the line (A). It is not used in the load flow. """ super().__init__(id) self._z_line = np.asarray(z_line, dtype=complex) @@ -65,6 +70,7 @@ def __init__(self, id: Id, z_line: np.ndarray, y_shunt: Optional[np.ndarray] = N else: self._with_shunt = not np.allclose(y_shunt, 0) self._y_shunt = np.asarray(y_shunt, dtype=complex) + self.max_current = max_current self._check_matrix() def __eq__(self, other: object) -> bool: @@ -99,9 +105,19 @@ def y_shunt(self) -> Q_[np.ndarray]: def with_shunt(self) -> bool: return self._with_shunt + @property + def max_current(self) -> Optional[Q_[float]]: + """The maximum current loading of the line (A) if it is set.""" + return None if self._max_current is None else Q_(self._max_current, "A") + + @max_current.setter + @ureg_wraps(None, (None, "A"), strict=False) + def max_current(self, value: Optional[float]) -> None: + self._max_current = value + @classmethod @ureg_wraps( - None, (None, None, "ohm/km", "ohm/km", "S/km", "S/km", "ohm/km", "ohm/km", "S/km", "S/km"), strict=False + None, (None, None, "ohm/km", "ohm/km", "S/km", "S/km", "ohm/km", "ohm/km", "S/km", "S/km", "A"), strict=False ) def from_sym( cls, @@ -114,6 +130,7 @@ def from_sym( xpn: Optional[float] = None, bn: Optional[float] = None, bpn: Optional[float] = None, + max_current: Optional[float] = None, ) -> Self: """Create line parameters from a symmetric model. @@ -145,6 +162,9 @@ def from_sym( bpn: Phase to neutral susceptance (siemens/km) + max_current: + An optional maximum current loading of the line (A). It is not used in the load flow. + Returns: The created line parameters. @@ -154,7 +174,7 @@ def from_sym( impedance matrix is not invertible. """ z_line, y_shunt = cls._sym_to_zy(id=id, z0=z0, z1=z1, y0=y0, y1=y1, zn=zn, xpn=xpn, bn=bn, bpn=bpn) - return cls(id=id, z_line=z_line, y_shunt=y_shunt) + return cls(id=id, z_line=z_line, y_shunt=y_shunt, max_current=max_current) @staticmethod def _sym_to_zy( @@ -277,7 +297,7 @@ def _sym_to_zy( return z_line, y_shunt @classmethod - @ureg_wraps(None, (None, None, None, None, None, "mm**2", "mm**2", "m", "m"), strict=False) + @ureg_wraps(None, (None, None, None, None, None, "mm**2", "mm**2", "m", "m", "A"), strict=False) def from_geometry( cls, id: Id, @@ -288,6 +308,7 @@ def from_geometry( section_neutral: float, height: float, external_diameter: float, + max_current: Optional[float] = None, ) -> Self: """Create line parameters from its geometry. @@ -316,6 +337,9 @@ def from_geometry( external_diameter: External diameter of the wire (m). + max_current: + An optional maximum current loading of the line (A). It is not used in the load flow. + Returns: The created line parameters. @@ -332,7 +356,7 @@ def from_geometry( height=height, external_diameter=external_diameter, ) - return cls(id=id, z_line=z_line, y_shunt=y_shunt) + return cls(id=id, z_line=z_line, y_shunt=y_shunt, max_current=max_current) @staticmethod def _geometry_to_zy( @@ -469,13 +493,14 @@ def _geometry_to_zy( return z_line, y_shunt @classmethod - @ureg_wraps(None, (None, None, "mm²", "m", "mm"), strict=False) + @ureg_wraps(None, (None, None, "mm²", "m", "mm", "A"), strict=False) def from_name_lv( cls, name: str, section_neutral: Optional[float] = None, height: Optional[float] = None, external_diameter: Optional[float] = None, + max_current: Optional[float] = None, ) -> Self: """Method to get the electrical parameters of a LV line from its canonical name. Some hypothesis will be made: the section of the neutral is the same as the other sections, the height and @@ -494,6 +519,9 @@ def from_name_lv( external_diameter: External diameter of the wire (mm). If None a default value will be used. + max_current: + An optional maximum current loading of the line (A). It is not used in the load flow. + Returns: The corresponding line parameters. """ @@ -527,16 +555,20 @@ def from_name_lv( section_neutral=section_neutral, height=height, external_diameter=external_diameter, + max_current=max_current, ) @classmethod - def from_name_mv(cls, name: str) -> Self: + def from_name_mv(cls, name: str, max_current: Optional[float] = None) -> Self: """Method to get the electrical parameters of a MV line from its canonical name. Args: name: The name of the line the parameters must be computed. E.g. "U_AL_150". + max_current: + An optional maximum current loading of the line (A). It is not used in the load flow. + Returns: The corresponding line parameters. """ @@ -573,7 +605,7 @@ def from_name_mv(cls, name: str) -> Self: z_line = (r + x * 1j) * np.eye(3, dtype=float) # in ohms/km y_shunt = b * 1j * np.eye(3, dtype=float) # in siemens/km - return cls(name, z_line=z_line, y_shunt=y_shunt) + return cls(name, z_line=z_line, y_shunt=y_shunt, max_current=max_current) # # Json Mixin interface @@ -591,13 +623,15 @@ def from_dict(cls, data: JsonDict) -> Self: """ z_line = np.asarray(data["z_line"][0]) + 1j * np.asarray(data["z_line"][1]) y_shunt = np.asarray(data["y_shunt"][0]) + 1j * np.asarray(data["y_shunt"][1]) if "y_shunt" in data else None - return cls(id=data["id"], z_line=z_line, y_shunt=y_shunt) + return cls(id=data["id"], z_line=z_line, y_shunt=y_shunt, max_current=data.get("max_current")) - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: """Return the line parameters information as a dictionary format.""" res = {"id": self.id, "z_line": [self._z_line.real.tolist(), self._z_line.imag.tolist()]} if self.with_shunt: res["y_shunt"] = [self._y_shunt.real.tolist(), self._y_shunt.imag.tolist()] + if not _lf_only and self.max_current is not None: + res["max_current"] = self.max_current.magnitude return res def _results_to_dict(self, warning: bool) -> NoReturn: diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index 6d2353b2..e7fcb95d 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -312,7 +312,7 @@ def from_dict(cls, data: JsonDict) -> Self: logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_CONTROL_TYPE) - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: if self.type == "constant": return {"type": "constant"} elif self.type == "p_max_u_production": @@ -427,7 +427,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, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: return {"type": self.type, "alpha": self._alpha, "epsilon": self._epsilon} def _results_to_dict(self, warning: bool) -> NoReturn: @@ -957,7 +957,7 @@ def from_dict(cls, data: JsonDict) -> Self: q_max=q_max, ) - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: res = { "control_p": self.control_p.to_dict(), "control_q": self.control_q.to_dict(), @@ -1021,7 +1021,7 @@ def _compute_powers( bus = Bus(id="bus", phases="an") vs = VoltageSource(id="source", bus=bus, voltages=[voltages[0]]) PotentialRef(id="pref", element=bus, phase="n") - fp = FlexibleParameter.from_dict(data=self.to_dict(include_geometry=False)) + fp = FlexibleParameter.from_dict(data=self.to_dict(_lf_only=True)) load = PowerLoad(id="load", bus=bus, powers=[power], flexible_params=[fp]) en = ElectricalNetwork.from_element(bus) diff --git a/roseau/load_flow/models/loads/loads.py b/roseau/load_flow/models/loads/loads.py index b64bc7c0..428fc1f5 100644 --- a/roseau/load_flow/models/loads/loads.py +++ b/roseau/load_flow/models/loads/loads.py @@ -324,7 +324,7 @@ def res_flexible_powers(self) -> Q_[np.ndarray]: # # Json Mixin interface # - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: self._raise_disconnected_error() res = { "id": self.id, @@ -396,7 +396,7 @@ def currents(self, value: Sequence[complex]) -> None: self._currents = self._validate_value(value) self._invalidate_network_results() - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: self._raise_disconnected_error() return { "id": self.id, @@ -451,7 +451,7 @@ def impedances(self, impedances: Sequence[complex]) -> None: self._impedances = self._validate_value(impedances) self._invalidate_network_results() - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: self._raise_disconnected_error() return { "id": self.id, diff --git a/roseau/load_flow/models/potential_refs.py b/roseau/load_flow/models/potential_refs.py index deb25c3e..f49f3f6d 100644 --- a/roseau/load_flow/models/potential_refs.py +++ b/roseau/load_flow/models/potential_refs.py @@ -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, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: res = {"id": self.id} e = self.element if isinstance(e, Bus): diff --git a/roseau/load_flow/models/sources.py b/roseau/load_flow/models/sources.py index 5da3a7bd..9691a05f 100644 --- a/roseau/load_flow/models/sources.py +++ b/roseau/load_flow/models/sources.py @@ -161,7 +161,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, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: self._raise_disconnected_error() return { "id": self.id, diff --git a/roseau/load_flow/models/tests/test_buses.py b/roseau/load_flow/models/tests/test_buses.py index 298d7564..fb05e427 100644 --- a/roseau/load_flow/models/tests/test_buses.py +++ b/roseau/load_flow/models/tests/test_buses.py @@ -1,14 +1,21 @@ import numpy as np +import pandas as pd import pytest from roseau.load_flow import ( + Q_, Bus, ElectricalNetwork, Ground, + Line, + LineParameters, PotentialRef, PowerLoad, RoseauLoadFlowException, RoseauLoadFlowExceptionCode, + Switch, + Transformer, + TransformerParameters, VoltageSource, ) @@ -74,3 +81,203 @@ def test_short_circuit(): bus.add_short_circuit("a", "b") assert "is already connected on bus" in e.value.msg assert e.value.args[1] == RoseauLoadFlowExceptionCode.BAD_SHORT_CIRCUIT + + +def test_voltage_limits(): + # Default values + bus = Bus("bus", phases="abc") + assert bus.min_voltage is None + assert bus.max_voltage is None + + # Passed as arguments + bus = Bus("bus", phases="abc", min_voltage=350, max_voltage=420) + assert bus.min_voltage == Q_(350, "V") + assert bus.max_voltage == Q_(420, "V") + + # Can be set to a real number + bus.min_voltage = 350.0 + bus.max_voltage = 420.0 + assert bus.min_voltage == Q_(350.0, "V") + assert bus.max_voltage == Q_(420.0, "V") + + # Can be reset to None + bus.min_voltage = None + bus.max_voltage = None + assert bus.min_voltage is None + assert bus.max_voltage is None + + # Can be set to a Quantity + bus.min_voltage = Q_(19, "kV") + bus.max_voltage = Q_(21, "kV") + assert bus.min_voltage == Q_(19_000, "V") + assert bus.max_voltage == Q_(21_000, "V") + + # NaNs are converted to None + for na in (np.nan, float("nan"), pd.NA): + bus.min_voltage = na + bus.max_voltage = na + assert bus.min_voltage is None + assert bus.max_voltage is None + + # Bad values + bus.min_voltage = 220 + with pytest.raises(RoseauLoadFlowException) as e: + bus.max_voltage = 200 + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_VOLTAGES + assert e.value.msg == "Cannot set max voltage of bus 'bus' to 200 V as it is lower than its min voltage (220 V)." + bus.max_voltage = 240 + with pytest.raises(RoseauLoadFlowException) as e: + bus.min_voltage = 250 + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_VOLTAGES + assert e.value.msg == "Cannot set min voltage of bus 'bus' to 250 V as it is higher than its max voltage (240 V)." + + +def test_res_violated(): + bus = Bus("bus", phases="abc") + direct_seq = np.exp([0, -2 / 3 * np.pi * 1j, 2 / 3 * np.pi * 1j]) + bus._res_potentials = 230 * direct_seq + + # No limits + assert bus.res_violated is None + + # Only min voltage + bus.min_voltage = 350 + assert bus.res_violated is False + bus.min_voltage = 450 + assert bus.res_violated is True + + # Only max voltage + bus.min_voltage = None + bus.max_voltage = 450 + assert bus.res_violated is False + bus.max_voltage = 350 + assert bus.res_violated is True + + # Both min and max voltage + # min <= v <= max + bus.min_voltage = 350 + bus.max_voltage = 450 + assert bus.res_violated is False + # v < min + bus.min_voltage = 450 + assert bus.res_violated is True + # v > max + bus.min_voltage = 350 + bus.max_voltage = 350 + assert bus.res_violated is True + + +def test_propagate_limits(): # noqa: C901 + b1_mv = Bus("b1_mv", phases="abc") + b2_mv = Bus("b2_mv", phases="abc") + b3_mv = Bus("b3_mv", phases="abc") + b1_lv = Bus("b1_lv", phases="abcn") + b2_lv = Bus("b2_lv", phases="abcn") + + PotentialRef("pref_mv", element=b1_mv) + g = Ground("g") + PotentialRef("pref_lv", element=g) + + lp_mv = LineParameters("lp_mv", z_line=np.eye(3), y_shunt=0.1 * np.eye(3)) + lp_lv = LineParameters("lp_lv", z_line=np.eye(4)) + tp = TransformerParameters.from_catalogue(id="SE_Minera_A0Ak_100kVA", manufacturer="SE") + + Line("l1_mv", b1_mv, b2_mv, length=1.5, parameters=lp_mv, ground=g) + Line("l2_mv", b2_mv, b3_mv, length=2, parameters=lp_mv, ground=g) + Transformer("tr", b3_mv, b1_lv, parameters=tp) + Line("l1_lv", b1_lv, b2_lv, length=1, parameters=lp_lv) + + voltages = 20_000 * np.exp([0, -2 / 3 * np.pi * 1j, 2 / 3 * np.pi * 1j]) + VoltageSource("s_mv", bus=b1_mv, voltages=voltages) + + PowerLoad("pl1_mv", bus=b2_mv, powers=[10e3, 10e3, 10e3]) + PowerLoad("pl2_mv", bus=b3_mv, powers=[10e3, 10e3, 10e3]) + PowerLoad("pl1_lv", bus=b1_lv, powers=[1e3, 1e3, 1e3]) + PowerLoad("pl2_lv", bus=b2_lv, powers=[1e3, 1e3, 1e3]) + + # All buses have None as min and max voltage + for bus in (b1_mv, b2_mv, b3_mv, b1_lv, b2_lv): + assert bus.min_voltage is None + assert bus.max_voltage is None + + # Set min and max voltage of b1_mv + b1_mv.min_voltage = 19_000 + b1_mv.max_voltage = 21_000 + # propagate MV voltage limits + b1_mv.propagate_limits() + for bus in (b1_mv, b2_mv, b3_mv): + assert bus.min_voltage == Q_(19_000, "V") + assert bus.max_voltage == Q_(21_000, "V") + for bus in (b1_lv, b2_lv): + assert bus.min_voltage is None + assert bus.max_voltage is None + + # Set min and max voltage of b1_lv + b1_lv.min_voltage = 217 + b1_lv.max_voltage = 253 + b1_lv.propagate_limits() + for bus in (b1_mv, b2_mv, b3_mv): + assert bus.min_voltage == Q_(19_000, "V") + assert bus.max_voltage == Q_(21_000, "V") + for bus in (b1_lv, b2_lv): + assert bus.min_voltage == Q_(217, "V") + assert bus.max_voltage == Q_(253, "V") + + # Reset min MV voltage limits only + b1_mv.min_voltage = None + b1_mv.propagate_limits() + for bus in (b1_mv, b2_mv, b3_mv): + assert bus.min_voltage is None + assert bus.max_voltage == Q_(21_000, "V") + for bus in (b1_lv, b2_lv): + assert bus.min_voltage == Q_(217, "V") + assert bus.max_voltage == Q_(253, "V") + + # Error, different max voltage limits + b1_mv.max_voltage = 21_005 + with pytest.raises(RoseauLoadFlowException) as e: + b1_mv.propagate_limits() + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_VOLTAGES + assert e.value.msg == ( + "Cannot propagate the maximum voltage (21005 V) of bus 'b1_mv' to bus 'b2_mv' with " + "different maximum voltage (21000 V)." + ) + + # The limits are not changed after the error + for bus in (b2_mv, b3_mv): + assert bus.min_voltage is None + assert bus.max_voltage == Q_(21_000, "V") + for bus in (b1_lv, b2_lv): + assert bus.min_voltage == Q_(217, "V") + assert bus.max_voltage == Q_(253, "V") + + # It is okay to propagate with different limits if force=True + b1_mv.propagate_limits(force=True) + for bus in (b1_mv, b2_mv, b3_mv): + assert bus.min_voltage is None + assert bus.max_voltage == Q_(21_005, "V") + for bus in (b1_lv, b2_lv): + assert bus.min_voltage == Q_(217, "V") + assert bus.max_voltage == Q_(253, "V") + + # What if there is a switch? + b4_mv = Bus("b4_mv", phases="abc") + Switch("sw", b2_mv, b4_mv) + b1_mv.propagate_limits() + for bus in (b1_mv, b2_mv, b3_mv, b4_mv): + assert bus.min_voltage is None + assert bus.max_voltage == Q_(21_005, "V") + for bus in (b1_lv, b2_lv): + assert bus.min_voltage == Q_(217, "V") + assert bus.max_voltage == Q_(253, "V") + + # Let's add a MV loop; does it still work? + Line("l3_mv", b1_mv, b3_mv, length=1, parameters=lp_mv, ground=g) + b1_mv.min_voltage = 19_000 + b1_mv.propagate_limits() + for bus in (b1_mv, b2_mv, b3_mv, b4_mv): + assert bus.min_voltage == Q_(19_000, "V") + assert bus.max_voltage == Q_(21_005, "V") + for bus in (b1_lv, b2_lv): + assert bus.min_voltage == Q_(217, "V") + assert bus.max_voltage == Q_(253, "V") diff --git a/roseau/load_flow/models/tests/test_line_parameters.py b/roseau/load_flow/models/tests/test_line_parameters.py index 1dcfb110..92d0f3bf 100644 --- a/roseau/load_flow/models/tests/test_line_parameters.py +++ b/roseau/load_flow/models/tests/test_line_parameters.py @@ -5,6 +5,7 @@ from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.models import Bus, Ground, Line, LineParameters +from roseau.load_flow.units import Q_ from roseau.load_flow.utils import ConductorType, InsulatorType, LineType @@ -345,3 +346,20 @@ def test_from_name_mv(): lp = LineParameters.from_name_mv("U_AL_150") npt.assert_allclose(lp.z_line.m_as("ohm/km"), z_line_expected) npt.assert_allclose(lp.y_shunt.m_as("S/km"), y_shunt_expected, rtol=1e-4) + + +def test_max_current(): + lp = LineParameters("test", z_line=np.eye(3)) + assert lp.max_current is None + + lp = LineParameters("test", z_line=np.eye(3), max_current=100) + assert lp.max_current == Q_(100, "A") + + lp.max_current = 200 + assert lp.max_current == Q_(200, "A") + + lp.max_current = None + assert lp.max_current is None + + lp.max_current = Q_(3, "kA") + assert lp.max_current == Q_(3_000, "A") diff --git a/roseau/load_flow/models/tests/test_lines.py b/roseau/load_flow/models/tests/test_lines.py index 5d6f4d24..307e9af6 100644 --- a/roseau/load_flow/models/tests/test_lines.py +++ b/roseau/load_flow/models/tests/test_lines.py @@ -95,3 +95,43 @@ def test_line_parameters_shortcut(): # Y assert line.with_shunt assert np.allclose(line.y_shunt.m_as("S"), 0.05 * y_shunt) + + +def test_res_violated(): + bus1 = Bus("bus1", phases="abc") + bus2 = Bus("bus1", phases="abc") + lp = LineParameters("lp", z_line=np.eye(3, dtype=complex)) + line = Line("line", bus1=bus1, bus2=bus2, parameters=lp, length=Q_(50, "m")) + direct_seq = np.exp([0, -2 / 3 * np.pi * 1j, 2 / 3 * np.pi * 1j]) + + bus1._res_potentials = 230 * direct_seq + bus2._res_potentials = 225 * direct_seq + line._res_currents = 10 * direct_seq, -10 * direct_seq + + # No limits + assert line.res_violated is None + + # No constraint violated + lp.max_current = 11 + assert line.res_violated is False + + # Two violations + lp.max_current = 9 + assert line.res_violated is True + + # Side 1 violation + lp.max_current = 11 + line._res_currents = 12 * direct_seq, -10 * direct_seq + assert line.res_violated is True + + # Side 2 violation + lp.max_current = 11 + line._res_currents = 10 * direct_seq, -12 * direct_seq + assert line.res_violated is True + + # A single phase violation + lp.max_current = 11 + line._res_currents = 10 * direct_seq, -10 * direct_seq + line._res_currents[0][0] = 12 * direct_seq[0] + line._res_currents[1][0] = -12 * direct_seq[0] + assert line.res_violated is True diff --git a/roseau/load_flow/models/tests/test_transformer_parameters.py b/roseau/load_flow/models/tests/test_transformer_parameters.py index ce35849f..3b259f6d 100644 --- a/roseau/load_flow/models/tests/test_transformer_parameters.py +++ b/roseau/load_flow/models/tests/test_transformer_parameters.py @@ -460,3 +460,30 @@ def test_print_catalogue(): with console.capture() as capture: TransformerParameters.print_catalogue(ulv=250) assert len(capture.get().split("\n")) == 2 + + +def test_max_power(): + kwds = { + "type": "yzn11", + "psc": 1350.0, + "p0": 145.0, + "i0": 1.8 / 100, + "ulv": 400, + "uhv": 20000, + "sn": 50 * 1e3, + "vsc": 4 / 100, + } + tp = TransformerParameters("test", **kwds) + assert tp.max_power is None + + tp = TransformerParameters("test", **kwds, max_power=60_000) + assert tp.max_power == Q_(60_000, "VA") + + tp.max_power = 55_000 + assert tp.max_power == Q_(55_000, "VA") + + tp.max_power = None + assert tp.max_power is None + + tp.max_power = Q_(65, "kVA") + assert tp.max_power == Q_(65_000, "VA") diff --git a/roseau/load_flow/models/tests/test_transformers.py b/roseau/load_flow/models/tests/test_transformers.py new file mode 100644 index 00000000..c941e18c --- /dev/null +++ b/roseau/load_flow/models/tests/test_transformers.py @@ -0,0 +1,38 @@ +import numpy as np + +from roseau.load_flow.models import Bus, Transformer, TransformerParameters + + +def test_res_violated(): + bus1 = Bus("bus1", phases="abc") + bus2 = Bus("bus1", phases="abcn") + tp = TransformerParameters( + id="tp", psc=1350.0, p0=145.0, i0=1.8 / 100, ulv=400, uhv=20000, sn=50 * 1e3, vsc=4 / 100, type="yzn11" + ) + transformer = Transformer("transformer", bus1=bus1, bus2=bus2, parameters=tp) + direct_seq = np.exp([0, -2 / 3 * np.pi * 1j, 2 / 3 * np.pi * 1j]) + direct_seq_neutral = np.concatenate([direct_seq, [0]]) + + bus1._res_potentials = 20_000 * direct_seq + bus2._res_potentials = 230 * direct_seq_neutral + transformer._res_currents = 0.8 * direct_seq, -65 * direct_seq_neutral + + # No limits + assert transformer.res_violated is None + + # No constraint violated + tp.max_power = 50_000 + assert transformer.res_violated is False + + # Two violations + tp.max_power = 40_000 + assert transformer.res_violated is True + + # Primary side violation + tp.max_power = 47_900 + assert transformer.res_violated is True + + # Secondary side violation + tp.max_power = 50_000 + transformer._res_currents = 0.8 * direct_seq, -80 * direct_seq_neutral + assert transformer.res_violated is True diff --git a/roseau/load_flow/models/transformers/parameters.py b/roseau/load_flow/models/transformers/parameters.py index a00247d6..8717f6d2 100644 --- a/roseau/load_flow/models/transformers/parameters.py +++ b/roseau/load_flow/models/transformers/parameters.py @@ -41,7 +41,7 @@ class TransformerParameters(Identifiable, JsonMixin, CatalogueMixin[pd.DataFrame ) """The pattern to extract the winding of the primary and of the secondary of the transformer.""" - @ureg_wraps(None, (None, None, None, "V", "V", "VA", "W", "", "W", ""), strict=False) + @ureg_wraps(None, (None, None, None, "V", "V", "VA", "W", "", "W", "", "VA"), strict=False) def __init__( self, id: Id, @@ -53,6 +53,7 @@ def __init__( i0: float, psc: float, vsc: float, + max_power: Optional[float] = None, ) -> None: """TransformerParameters constructor. @@ -85,22 +86,11 @@ def __init__( vsc: Voltages on LV side during short-circuit test (%) + + max_power: + The maximum power loading of the transformer (VA). It is not used in the load flow. """ super().__init__(id) - self._sn = sn - self._uhv = uhv - self._ulv = ulv - self._i0 = i0 - self._p0 = p0 - self._psc = psc - self._vsc = vsc - self.type = type - if type in ("single", "center"): - self.winding1 = None - self.winding2 = None - self.phase_displacement = None - else: - self.winding1, self.winding2, self.phase_displacement = self.extract_windings(string=type) # Check if uhv < ulv: @@ -137,6 +127,22 @@ def __init__( f"imaginary part will be null." ) + self._sn = sn + self._uhv = uhv + self._ulv = ulv + self._i0 = i0 + self._p0 = p0 + self._psc = psc + self._vsc = vsc + self.type = type + if type in ("single", "center"): + self.winding1 = None + self.winding2 = None + self.phase_displacement = None + else: + self.winding1, self.winding2, self.phase_displacement = self.extract_windings(string=type) + self.max_power = max_power + def __eq__(self, other: object) -> bool: if not isinstance(other, TransformerParameters): return NotImplemented @@ -195,6 +201,16 @@ def vsc(self) -> Q_[float]: """Voltages on LV side during short-circuit test (%)""" return self._vsc + @property + def max_power(self) -> Optional[Q_[float]]: + """The maximum power loading of the transformer (VA) if it is set.""" + return None if self._max_power is None else Q_(self._max_power, "VA") + + @max_power.setter + @ureg_wraps(None, (None, "VA"), strict=False) + def max_power(self, value: Optional[float]) -> None: + self._max_power = value + @ureg_wraps(("ohm", "S", "", None), (None,), strict=False) def to_zyk(self) -> tuple[Q_[complex], Q_[complex], Q_[float], float]: """Compute the transformer parameters ``z2``, ``ym``, ``k`` and ``orientation`` mandatory @@ -262,10 +278,11 @@ def from_dict(cls, data: JsonDict) -> Self: i0=data["i0"], # Current during off-load test (%) psc=data["psc"], # Losses during short-circuit test (W) vsc=data["vsc"], # Voltages on LV side during short-circuit test (%) + max_power=data.get("max_power"), # Maximum power loading (VA) ) - def to_dict(self, include_geometry: bool = True) -> JsonDict: - return { + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: + res = { "id": self.id, "sn": self._sn, "uhv": self._uhv, @@ -276,6 +293,9 @@ def to_dict(self, include_geometry: bool = True) -> JsonDict: "vsc": self._vsc, "type": self.type, } + if not _lf_only and self.max_power is not None: + res["max_power"] = self.max_power.magnitude + return res def _results_to_dict(self, warning: bool) -> NoReturn: msg = f"The {type(self).__name__} has no results to export." diff --git a/roseau/load_flow/models/transformers/transformers.py b/roseau/load_flow/models/transformers/transformers.py index 300d8432..4dec6691 100644 --- a/roseau/load_flow/models/transformers/transformers.py +++ b/roseau/load_flow/models/transformers/transformers.py @@ -8,6 +8,7 @@ from roseau.load_flow.models.buses import Bus from roseau.load_flow.models.transformers.parameters import TransformerParameters from roseau.load_flow.typing import Id, JsonDict +from roseau.load_flow.units import Q_ logger = logging.getLogger(__name__) @@ -130,8 +131,15 @@ def parameters(self, value: TransformerParameters) -> None: self._parameters = value self._invalidate_network_results() - 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} + @property + def max_power(self) -> Optional[Q_[float]]: + """The maximum power loading of the transformer (in VA).""" + # Do not add a setter. The user must know that if they change the max_power, it changes + # for all transformers that share the parameters. It is better to set it on the parameters. + return self.parameters.max_power + + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: + return {**super().to_dict(_lf_only=_lf_only), "params_id": self.parameters.id, "tap": self.tap} def _compute_phases_three( self, @@ -245,3 +253,16 @@ def _check_bus_phases(id: Id, bus: Bus, **kwargs: str) -> None: ) logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_PHASE) + + @property + def res_violated(self) -> Optional[bool]: + """Whether the transformer power exceeds the maximum power (loading > 100%). + + Returns ``None`` if the maximum power is not set. + """ + s_max = self.parameters._max_power + if s_max is None: + return None + powers1, powers2 = self._res_powers_getter(warning=True) + # True if either the primary or secondary is overloaded + return float(max(abs(sum(powers1)), abs(sum(powers2)))) > s_max diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index 4e18b238..8af70487 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -39,14 +39,10 @@ from roseau.load_flow.solvers import check_solver_params from roseau.load_flow.typing import Authentication, Id, JsonDict, Solver, StrPath from roseau.load_flow.utils import CatalogueMixin, JsonMixin, console, palette +from roseau.load_flow.utils.types import _DTYPES, VoltagePhaseDtype logger = logging.getLogger(__name__) -# Phases dtype for all data frames -_PHASE_DTYPE = pd.CategoricalDtype(categories=["a", "b", "c", "n"], ordered=True) -# Phases dtype for voltage data frames -_VOLTAGE_PHASES_DTYPE = pd.CategoricalDtype(categories=["an", "bn", "cn", "ab", "bc", "ca"], ordered=True) - _T = TypeVar("_T", bound=Element) @@ -266,10 +262,15 @@ def from_element(cls, initial_bus: Bus) -> Self: @property def buses_frame(self) -> gpd.GeoDataFrame: """The :attr:`buses` of the network as a geo dataframe.""" + data = [] + for bus in self.buses.values(): + min_voltage = bus.min_voltage.magnitude if bus.min_voltage is not None else float("nan") + max_voltage = bus.max_voltage.magnitude if bus.max_voltage is not None else float("nan") + data.append((bus.id, bus.phases, min_voltage, max_voltage, bus.geometry)) return gpd.GeoDataFrame( data=pd.DataFrame.from_records( - data=[(bus_id, bus.phases, bus.geometry) for bus_id, bus in self.buses.items()], - columns=["id", "phases", "geometry"], + data=data, + columns=["id", "phases", "min_voltage", "max_voltage", "geometry"], index="id", ), geometry="geometry", @@ -300,6 +301,94 @@ def branches_frame(self) -> gpd.GeoDataFrame: crs=CRS("EPSG:4326"), ) + @property + def transformers_frame(self) -> gpd.GeoDataFrame: + """The transformers of the network as a geo dataframe. + + This is similar to :attr:`branches_frame` but only contains the transformers. It has a + `max_power` column that contains the maximum power loading (VA) of the transformers. + """ + data = [] + for branch in self.branches.values(): + if not isinstance(branch, Transformer): + continue + max_power = branch.max_power.magnitude if branch.max_power is not None else float("nan") + data.append( + ( + branch.id, + branch.phases1, + branch.phases2, + branch.bus1.id, + branch.bus2.id, + branch.parameters.id, + max_power, + branch.geometry, + ) + ) + return gpd.GeoDataFrame( + data=pd.DataFrame.from_records( + data=data, + columns=["id", "phases1", "phases2", "bus1_id", "bus2_id", "parameters_id", "max_power", "geometry"], + index="id", + ), + geometry="geometry", + crs=CRS("EPSG:4326"), + ) + + @property + def lines_frame(self) -> gpd.GeoDataFrame: + """The lines of the network as a geo dataframe. + + This is similar to :attr:`branches_frame` but only contains the lines. It has a + `max_current` column that contains the maximum current loading (A) of the lines. + """ + data = [] + for branch in self.branches.values(): + if not isinstance(branch, Line): + continue + max_current = branch.max_current.magnitude if branch.max_current is not None else float("nan") + data.append( + ( + branch.id, + branch.phases, + branch.bus1.id, + branch.bus2.id, + branch.parameters.id, + max_current, + branch.geometry, + ) + ) + return gpd.GeoDataFrame( + data=pd.DataFrame.from_records( + data=data, + columns=["id", "phases", "bus1_id", "bus2_id", "parameters_id", "max_current", "geometry"], + index="id", + ), + geometry="geometry", + crs=CRS("EPSG:4326"), + ) + + @property + def switches_frame(self) -> gpd.GeoDataFrame: + """The switches of the network as a geo dataframe. + + This is similar to :attr:`branches_frame` but only contains the switches. + """ + data = [] + for branch in self.branches.values(): + if not isinstance(branch, Switch): + continue + data.append((branch.id, branch.phases, branch.bus1.id, branch.bus2.id, branch.geometry)) + return gpd.GeoDataFrame( + data=pd.DataFrame.from_records( + data=data, + columns=["id", "phases", "bus1_id", "bus2_id", "geometry"], + index="id", + ), + geometry="geometry", + crs=CRS("EPSG:4326"), + ) + @property def loads_frame(self) -> pd.DataFrame: """The :attr:`loads` of the network as a dataframe.""" @@ -411,7 +500,7 @@ def solve_load_flow( # Get the data data = { - "network": self.to_dict(include_geometry=False), + "network": self.to_dict(_lf_only=True), "solver": { "name": solver, "params": solver_params, @@ -557,17 +646,13 @@ def res_buses(self) -> pd.DataFrame: """ self._warn_invalid_results() res_dict = {"bus_id": [], "phase": [], "potential": []} + dtypes = {c: _DTYPES[c] for c in res_dict} for bus_id, bus in self.buses.items(): for potential, phase in zip(bus._res_potentials_getter(warning=False), bus.phases): res_dict["bus_id"].append(bus_id) res_dict["phase"].append(phase) res_dict["potential"].append(potential) - res_df = ( - pd.DataFrame.from_dict(res_dict, orient="columns") - .astype({"phase": _PHASE_DTYPE, "potential": complex}) - .set_index(["bus_id", "phase"]) - ) - return res_df + return pd.DataFrame(res_dict).astype(dtypes).set_index(["bus_id", "phase"]) @property def res_buses_voltages(self) -> pd.DataFrame: @@ -582,20 +667,42 @@ def res_buses_voltages(self) -> pd.DataFrame: - `phase`: The phase of the bus (in ``{'an', 'bn', 'cn', 'ab', 'bc', 'ca'}``). and the following columns: - `voltage`: The complex voltage of the bus (in Volts) for the given phase. + - `min_voltage`: The minimum voltage of the bus (in Volts). + - `max_voltage`: The maximum voltage of the bus (in Volts). """ self._warn_invalid_results() - voltages_dict = {"bus_id": [], "phase": [], "voltage": []} + voltages_dict = { + "bus_id": [], + "phase": [], + "voltage": [], + "min_voltage": [], + "max_voltage": [], + "violated": [], + } + dtypes = {c: _DTYPES[c] for c in voltages_dict} | {"phase": VoltagePhaseDtype} for bus_id, bus in self.buses.items(): + min_voltage = bus._min_voltage + max_voltage = bus._max_voltage + voltage_limits_set = False + + if min_voltage is None: + min_voltage = float("nan") + else: + voltage_limits_set = True + if max_voltage is None: + max_voltage = float("nan") + else: + voltage_limits_set = True for voltage, phase in zip(bus._res_voltages_getter(warning=False), bus.voltage_phases): + voltage_abs = abs(voltage) + violated = (voltage_abs < min_voltage or voltage_abs > max_voltage) if voltage_limits_set else None voltages_dict["bus_id"].append(bus_id) voltages_dict["phase"].append(phase) voltages_dict["voltage"].append(voltage) - voltages_df = ( - pd.DataFrame.from_dict(voltages_dict, orient="columns") - .astype({"phase": _VOLTAGE_PHASES_DTYPE, "voltage": complex}) - .set_index(["bus_id", "phase"]) - ) - return voltages_df + voltages_dict["min_voltage"].append(min_voltage) + voltages_dict["max_voltage"].append(max_voltage) + voltages_dict["violated"].append(violated) + return pd.DataFrame(voltages_dict).astype(dtypes).set_index(["bus_id", "phase"]) @property def res_branches(self) -> pd.DataFrame: @@ -605,6 +712,7 @@ def res_branches(self) -> pd.DataFrame: - `branch_id`: The id of the branch. - `phase`: The phase of the branch (in ``{'a', 'b', 'c', 'n'}``). and the following columns: + - `branch_type`: The type of the branch, can be ``{'line', 'transformer', 'switch'}``. - `current1`: The complex current of the branch (in Amps) for the given phase at the first bus. - `current2`: The complex current of the branch (in Amps) for the given phase at the @@ -626,6 +734,7 @@ def res_branches(self) -> pd.DataFrame: { "branch_id": branch_id, "phase": phase, + "branch_type": branch.branch_type, "current1": i1, "current2": None, "power1": s1, @@ -639,6 +748,7 @@ def res_branches(self) -> pd.DataFrame: { "branch_id": branch_id, "phase": phase, + "branch_type": branch.branch_type, "current1": None, "current2": i2, "power1": None, @@ -649,24 +759,125 @@ def res_branches(self) -> pd.DataFrame: for i2, s2, v2, phase in zip(currents2, powers2, potentials2, branch.phases2) ) - res_df = ( - pd.DataFrame.from_records(res_list) - .astype( + columns = [ + "branch_id", + "phase", + "branch_type", + "current1", + "current2", + "power1", + "power2", + "potential1", + "potential2", + ] + dtypes = {c: _DTYPES[c] for c in columns} + return ( + pd.DataFrame.from_records(res_list, columns=columns) + .astype(dtypes) + # aggregate x1 and x2 for the same phase for I, V, S, ... + .groupby(["branch_id", "phase", "branch_type"], observed=True) + # there are 2 values of I, V, S, ...; only one is not nan -> keep it + .mean() + # if all values are nan -> drop the row (the phase does not exist) + .dropna(how="all") + .reset_index(level="branch_type") + ) + + @property + def res_transformers(self) -> pd.DataFrame: + """The load flow results of the network transformers. + + This is similar to the :attr:`res_branches` property but provides more information that + only apply to transformers. + + The results are returned as a dataframe with the following index: + - `transformer_id`: The id of the transformer. + - `phase`: The phase of the transformer (in ``{'a', 'b', 'c', 'n'}``). + + and the following columns: + - `current1`: The complex current of the transformer (in Amps) for the given phase at the + first bus. + - `current2`: The complex current of the transformer (in Amps) for the given phase at the + second bus. + - `power1`: The complex power of the transformer (in VoltAmps) for the given phase at the + first bus. + - `power2`: The complex power of the transformer (in VoltAmps) for the given phase at the + second bus. + - `potential1`: The complex potential of the first bus (in Volts) for the given phase. + - `potential2`: The complex potential of the second bus (in Volts) for the given phase. + - `max_power`: The maximum power loading (in VoltAmps) of the transformer. + """ + self._warn_invalid_results() + res_list = [] + for branch in self.branches.values(): + if not isinstance(branch, Transformer): + continue + currents1, currents2 = branch._res_currents_getter(warning=False) + powers1, powers2 = branch._res_powers_getter(warning=False) + potentials1, potentials2 = branch._res_potentials_getter(warning=False) + s_max = branch.parameters._max_power + violated = None + if s_max is not None: + violated = max(abs(sum(powers1)), abs(sum(powers2))) > s_max + res_list.extend( + { + "transformer_id": branch.id, + "phase": phase, + "current1": i1, + "current2": None, + "power1": s1, + "power2": None, + "potential1": v1, + "potential2": None, + "max_power": s_max, + "violated": violated, + } + for i1, s1, v1, phase in zip(currents1, powers1, potentials1, branch.phases1) + ) + res_list.extend( { - "phase": _PHASE_DTYPE, - "current1": complex, - "current2": complex, - "power1": complex, - "power2": complex, - "potential1": complex, - "potential2": complex, + "transformer_id": branch.id, + "phase": phase, + "current1": None, + "current2": i2, + "power1": None, + "power2": s2, + "potential1": None, + "potential2": v2, + "max_power": s_max, + "violated": violated, } + for i2, s2, v2, phase in zip(currents2, powers2, potentials2, branch.phases2) ) - .groupby(["branch_id", "phase"], observed=True) # aggregate x1 and x2 for the same phase - .mean() # 2 values; only one is not nan -> keep it - .dropna(how="all") # if all values are nan -> drop the row (the phase does not exist) + + columns = [ + "transformer_id", + "phase", + "current1", + "current2", + "power1", + "power2", + "potential1", + "potential2", + "max_power", + "violated", + ] + dtypes = {c: _DTYPES[c] for c in columns} + res = ( + pd.DataFrame.from_records(res_list, columns=columns) + .astype(dtypes) + # aggregate x1 and x2 for the same phase for I, V, S, ... + .groupby(["transformer_id", "phase", "max_power", "violated"], observed=True) + # there are 2 values of I, V, S, ...; only one is not nan -> keep it + .mean() + # if all values are nan -> drop the row (the phase does not exist) + .dropna(how="all") + .reset_index(level=["max_power", "violated"]) ) - return res_df + # move the max_power and violated columns to the end + res["max_power"] = res.pop("max_power") + res["violated"] = res.pop("violated") + return res @property def res_lines(self) -> pd.DataFrame: @@ -719,7 +930,10 @@ def res_lines(self) -> pd.DataFrame: "potential2": [], "series_losses": [], "series_current": [], + "max_current": [], + "violated": [], } + dtypes = {c: _DTYPES[c] for c in res_dict} for branch in self.branches.values(): if not isinstance(branch, Line): continue @@ -728,9 +942,11 @@ def res_lines(self) -> pd.DataFrame: powers = branch._res_powers_getter(warning=False) series_losses = branch._res_series_power_losses_getter(warning=False) series_currents = branch._res_series_currents_getter(warning=False) + i_max = branch.parameters._max_current for i1, i2, s1, s2, v1, v2, s_series, i_series, phase in zip( *currents, *powers, *potentials, series_losses, series_currents, branch.phases ): + violated = None if i_max is None else max(abs(i1), abs(i2)) > i_max res_dict["line_id"].append(branch.id) res_dict["phase"].append(phase) res_dict["current1"].append(i1) @@ -741,16 +957,60 @@ def res_lines(self) -> pd.DataFrame: res_dict["potential2"].append(v2) res_dict["series_losses"].append(s_series) res_dict["series_current"].append(i_series) - return ( - pd.DataFrame(res_dict) - .astype( - { - "phase": _PHASE_DTYPE, - **{k: complex for k in res_dict if k not in ("phase", "line_id")}, - }, - ) - .set_index(["line_id", "phase"]) - ) + res_dict["max_current"].append(i_max) + res_dict["violated"].append(violated) + res = pd.DataFrame(res_dict).astype(dtypes).set_index(["line_id", "phase"]) + return res + + @property + def res_switches(self) -> pd.DataFrame: + """The load flow results of the network switches. + + This is similar to the :attr:`res_branches` property but only apply to switches. + + The results are returned as a dataframe with the following index: + - `switch_id`: The id of the switch. + - `phase`: The phase of the switch (in ``{'a', 'b', 'c', 'n'}``). + and the following columns: + - `current1`: The complex current of the switch (in Amps) for the given phase at the + first bus. + - `current2`: The complex current of the switch (in Amps) for the given phase at the + second bus. + - `power1`: The complex power of the switch (in VoltAmps) for the given phase at the + first bus. + - `power2`: The complex power of the switch (in VoltAmps) for the given phase at the + second bus. + - `potential1`: The complex potential of the first bus (in Volts) for the given phase. + - `potential2`: The complex potential of the second bus (in Volts) for the given phase. + """ + self._warn_invalid_results() + res_dict = { + "switch_id": [], + "phase": [], + "current1": [], + "current2": [], + "power1": [], + "power2": [], + "potential1": [], + "potential2": [], + } + dtypes = {c: _DTYPES[c] for c in res_dict} + for branch in self.branches.values(): + if not isinstance(branch, Switch): + continue + potentials = branch._res_potentials_getter(warning=False) + currents = branch._res_currents_getter(warning=False) + powers = branch._res_powers_getter(warning=False) + for i1, i2, s1, s2, v1, v2, phase in zip(*currents, *powers, *potentials, branch.phases): + res_dict["switch_id"].append(branch.id) + res_dict["phase"].append(phase) + res_dict["current1"].append(i1) + res_dict["current2"].append(i2) + res_dict["power1"].append(s1) + res_dict["power2"].append(s2) + res_dict["potential1"].append(v1) + res_dict["potential2"].append(v2) + return pd.DataFrame(res_dict).astype(dtypes).set_index(["switch_id", "phase"]) @property def res_loads(self) -> pd.DataFrame: @@ -766,6 +1026,7 @@ def res_loads(self) -> pd.DataFrame: """ self._warn_invalid_results() res_dict = {"load_id": [], "phase": [], "current": [], "power": [], "potential": []} + dtypes = {c: _DTYPES[c] for c in res_dict} for load_id, load in self.loads.items(): currents = load._res_currents_getter(warning=False) powers = load._res_powers_getter(warning=False) @@ -776,12 +1037,7 @@ def res_loads(self) -> pd.DataFrame: res_dict["current"].append(i) res_dict["power"].append(s) res_dict["potential"].append(v) - res_df = ( - pd.DataFrame.from_dict(res_dict, orient="columns") - .astype({"phase": _PHASE_DTYPE, "current": complex, "power": complex, "potential": complex}) - .set_index(["load_id", "phase"]) - ) - return res_df + return pd.DataFrame(res_dict).astype(dtypes).set_index(["load_id", "phase"]) @property def res_loads_voltages(self) -> pd.DataFrame: @@ -796,17 +1052,13 @@ def res_loads_voltages(self) -> pd.DataFrame: """ self._warn_invalid_results() voltages_dict = {"load_id": [], "phase": [], "voltage": []} + dtypes = {c: _DTYPES[c] for c in voltages_dict} | {"phase": VoltagePhaseDtype} for load_id, load in self.loads.items(): for voltage, phase in zip(load._res_voltages_getter(warning=False), load.voltage_phases): voltages_dict["load_id"].append(load_id) voltages_dict["phase"].append(phase) voltages_dict["voltage"].append(voltage) - voltages_df = ( - pd.DataFrame.from_dict(voltages_dict, orient="columns") - .astype({"phase": _VOLTAGE_PHASES_DTYPE, "voltage": complex}) - .set_index(["load_id", "phase"]) - ) - return voltages_df + return pd.DataFrame(voltages_dict).astype(dtypes).set_index(["load_id", "phase"]) @property def res_loads_flexible_powers(self) -> pd.DataFrame: @@ -824,6 +1076,7 @@ def res_loads_flexible_powers(self) -> pd.DataFrame: """ self._warn_invalid_results() loads_dict = {"load_id": [], "phase": [], "power": []} + dtypes = {c: _DTYPES[c] for c in loads_dict} | {"phase": VoltagePhaseDtype} for load_id, load in self.loads.items(): if not (isinstance(load, PowerLoad) and load.is_flexible): continue @@ -831,12 +1084,7 @@ def res_loads_flexible_powers(self) -> pd.DataFrame: loads_dict["load_id"].append(load_id) loads_dict["phase"].append(phase) loads_dict["power"].append(power) - powers_df = ( - pd.DataFrame.from_dict(loads_dict, orient="columns") - .astype({"phase": _VOLTAGE_PHASES_DTYPE, "power": complex}) - .set_index(["load_id", "phase"]) - ) - return powers_df + return pd.DataFrame(loads_dict).astype(dtypes).set_index(["load_id", "phase"]) @property def res_sources(self) -> pd.DataFrame: @@ -852,6 +1100,7 @@ def res_sources(self) -> pd.DataFrame: """ self._warn_invalid_results() res_dict = {"source_id": [], "phase": [], "current": [], "power": [], "potential": []} + dtypes = {c: _DTYPES[c] for c in res_dict} for source_id, source in self.sources.items(): currents = source._res_currents_getter(warning=False) powers = source._res_powers_getter(warning=False) @@ -862,12 +1111,7 @@ def res_sources(self) -> pd.DataFrame: res_dict["current"].append(i) res_dict["power"].append(s) res_dict["potential"].append(v) - res_df = ( - pd.DataFrame.from_dict(res_dict, orient="columns") - .astype({"phase": _PHASE_DTYPE, "current": complex, "power": complex, "potential": complex}) - .set_index(["source_id", "phase"]) - ) - return res_df + return pd.DataFrame(res_dict).astype(dtypes).set_index(["source_id", "phase"]) @property def res_grounds(self) -> pd.DataFrame: @@ -880,14 +1124,12 @@ def res_grounds(self) -> pd.DataFrame: """ self._warn_invalid_results() res_dict = {"ground_id": [], "potential": []} + dtypes = {c: _DTYPES[c] for c in res_dict} for ground in self.grounds.values(): potential = ground._res_potential_getter(warning=False) res_dict["ground_id"].append(ground.id) res_dict["potential"].append(potential) - res_df = ( - pd.DataFrame.from_dict(res_dict, orient="columns").astype({"potential": complex}).set_index(["ground_id"]) - ) - return res_df + return pd.DataFrame(res_dict).astype(dtypes).set_index(["ground_id"]) @property def res_potential_refs(self) -> pd.DataFrame: @@ -901,18 +1143,14 @@ def res_potential_refs(self) -> pd.DataFrame: """ self._warn_invalid_results() res_dict = {"potential_ref_id": [], "current": []} + dtypes = {c: _DTYPES[c] for c in res_dict} for p_ref in self.potential_refs.values(): current = p_ref._res_current_getter(warning=False) res_dict["potential_ref_id"].append(p_ref.id) res_dict["current"].append(current) - res_df = ( - pd.DataFrame.from_dict(res_dict, orient="columns") - .astype({"current": complex}) - .set_index(["potential_ref_id"]) - ) - return res_df + return pd.DataFrame(res_dict).astype(dtypes).set_index(["potential_ref_id"]) - def clear_short_circuits(self): + def clear_short_circuits(self) -> None: """Remove the short-circuits of all the buses.""" for bus in self.buses.values(): bus.clear_short_circuits() @@ -1095,14 +1333,14 @@ def from_dict(cls, data: JsonDict) -> Self: potential_refs=p_refs, ) - def to_dict(self, include_geometry: bool = True) -> JsonDict: + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: """Convert the electrical network to a dictionary. Args: - include_geometry: - If False, the geometry will not be added to the network dictionary. + _lf_only: + Internal argument, please do not use. """ - return network_to_dict(self, include_geometry=include_geometry) + return network_to_dict(self, _lf_only=_lf_only) # # Results saving/loading diff --git a/roseau/load_flow/tests/test_converters.py b/roseau/load_flow/tests/test_converters.py index e67d6157..929dacc6 100644 --- a/roseau/load_flow/tests/test_converters.py +++ b/roseau/load_flow/tests/test_converters.py @@ -3,7 +3,7 @@ from pandas.testing import assert_series_equal from roseau.load_flow.converters import phasor_to_sym, series_phasor_to_sym, sym_to_phasor -from roseau.load_flow.network import _PHASE_DTYPE +from roseau.load_flow.utils import PhaseDtype def test_phasor_to_sym(): @@ -88,7 +88,7 @@ def test_series_phasor_to_sym(): [("bus1", "a"), ("bus1", "b"), ("bus1", "c"), ("bus2", "a"), ("bus2", "b"), ("bus2", "c")], names=["bus_id", "phase"], ) - index = index.set_levels(index.levels[-1].astype(_PHASE_DTYPE), level=-1) + index = index.set_levels(index.levels[-1].astype(PhaseDtype), level=-1) voltage = pd.Series([va, vb, vc, va / 2, vb / 2, vc / 2], index=index, name="voltage") seq_dtype = pd.CategoricalDtype(categories=["zero", "pos", "neg"], ordered=True) diff --git a/roseau/load_flow/tests/test_electrical_network.py b/roseau/load_flow/tests/test_electrical_network.py index 42b0fefc..7271fd6c 100644 --- a/roseau/load_flow/tests/test_electrical_network.py +++ b/roseau/load_flow/tests/test_electrical_network.py @@ -26,9 +26,9 @@ TransformerParameters, VoltageSource, ) -from roseau.load_flow.network import _PHASE_DTYPE, _VOLTAGE_PHASES_DTYPE, ElectricalNetwork +from roseau.load_flow.network import ElectricalNetwork from roseau.load_flow.units import Q_ -from roseau.load_flow.utils import console +from roseau.load_flow.utils import BranchTypeDtype, PhaseDtype, VoltagePhaseDtype, console @pytest.fixture() @@ -647,12 +647,12 @@ def test_solve_load_flow_error(small_network): assert e.value.code == RoseauLoadFlowExceptionCode.BAD_REQUEST -def test_frame(small_network): +def test_frame(small_network: ElectricalNetwork): # Buses buses_gdf = small_network.buses_frame assert isinstance(buses_gdf, gpd.GeoDataFrame) - assert buses_gdf.shape == (2, 2) - assert set(buses_gdf.columns) == {"phases", "geometry"} + assert buses_gdf.shape == (2, 4) + assert set(buses_gdf.columns) == {"phases", "min_voltage", "max_voltage", "geometry"} assert buses_gdf.index.name == "id" # Branches @@ -662,6 +662,33 @@ def test_frame(small_network): assert set(branches_gdf.columns) == {"branch_type", "phases1", "phases2", "bus1_id", "bus2_id", "geometry"} assert branches_gdf.index.name == "id" + # Transformers + transformers_gdf = small_network.transformers_frame + assert isinstance(transformers_gdf, gpd.GeoDataFrame) + assert transformers_gdf.shape == (0, 7) + assert set(transformers_gdf.columns) == { + "phases1", + "phases2", + "bus1_id", + "bus2_id", + "parameters_id", + "max_power", + "geometry", + } + assert transformers_gdf.index.name == "id" + + # Lines + lines_gdf = small_network.lines_frame + assert isinstance(lines_gdf, gpd.GeoDataFrame) + assert lines_gdf.shape == (1, 6) + assert set(lines_gdf.columns) == {"phases", "bus1_id", "bus2_id", "parameters_id", "max_current", "geometry"} + + # Switches + switches_gdf = small_network.switches_frame + assert isinstance(switches_gdf, gpd.GeoDataFrame) + assert switches_gdf.shape == (0, 4) + assert set(switches_gdf.columns) == {"phases", "bus1_id", "bus2_id", "geometry"} + # Loads loads_df = small_network.loads_frame assert isinstance(loads_df, pd.DataFrame) @@ -677,30 +704,169 @@ def test_frame(small_network): assert sources_df.index.name == "id" -def test_buses_voltages(small_network, good_json_results): +def test_frame_empty_network(monkeypatch): + # Test that we can create dataframes even if a certain element is not present in the network + monkeypatch.setattr(ElectricalNetwork, "_check_validity", lambda self, constructed: None) + monkeypatch.setattr(ElectricalNetwork, "_warn_invalid_results", lambda self: None) + empty_network = ElectricalNetwork( + buses={}, + branches={}, + loads={}, + sources={}, + grounds={}, + potential_refs={}, + ) + # Buses + buses = empty_network.buses_frame + assert buses.shape == (0, 4) + assert buses.empty + + # Branches + branches = empty_network.branches_frame + assert branches.shape == (0, 6) + assert branches.empty + + # Transformers + transformers = empty_network.transformers_frame + assert transformers.shape == (0, 7) + assert transformers.empty + + # Lines + lines = empty_network.lines_frame + assert lines.shape == (0, 6) + assert lines.empty + + # Switches + switches = empty_network.switches_frame + assert switches.shape == (0, 4) + assert switches.empty + + # Loads + loads = empty_network.loads_frame + assert loads.shape == (0, 2) + assert loads.empty + + # Sources + sources = empty_network.sources_frame + assert sources.shape == (0, 2) + assert sources.empty + + # Res buses + res_buses = empty_network.res_buses + assert res_buses.shape == (0, 1) + assert res_buses.empty + res_buses_voltages = empty_network.res_buses_voltages + assert res_buses_voltages.shape == (0, 4) + assert res_buses_voltages.empty + + # Res branches + res_branches = empty_network.res_branches + assert res_branches.shape == (0, 7) + assert res_branches.empty + + # Res transformers + res_transformers = empty_network.res_transformers + assert res_transformers.shape == (0, 8) + assert res_transformers.empty + + # Res lines + res_lines = empty_network.res_lines + assert res_lines.shape == (0, 10) + assert res_lines.empty + + # Res switches + res_switches = empty_network.res_switches + assert res_switches.shape == (0, 6) + assert res_switches.empty + + # Res loads + res_loads = empty_network.res_loads + assert res_loads.shape == (0, 3) + assert res_loads.empty + + # Res sources + res_sources = empty_network.res_sources + assert res_sources.shape == (0, 3) + assert res_sources.empty + + +def test_buses_voltages(small_network: ElectricalNetwork, good_json_results): assert isinstance(small_network, ElectricalNetwork) small_network.results_from_dict(good_json_results) + small_network.buses["bus0"].max_voltage = 21_000 + small_network.buses["bus1"].min_voltage = 20_000 voltage_records = [ - {"bus_id": "bus0", "phase": "an", "voltage": 20000.0 + 0.0j}, - {"bus_id": "bus0", "phase": "bn", "voltage": -10000.0 + -17320.508076j}, - {"bus_id": "bus0", "phase": "cn", "voltage": -10000.0 + 17320.508076j}, - {"bus_id": "bus1", "phase": "an", "voltage": 19999.949999875 + 0.0j}, - {"bus_id": "bus1", "phase": "bn", "voltage": -9999.9749999375 + -17320.464774621556j}, - {"bus_id": "bus1", "phase": "cn", "voltage": -9999.9749999375 + 17320.464774621556j}, + { + "bus_id": "bus0", + "phase": "an", + "voltage": 20000.0 + 0.0j, + "min_voltage": np.nan, + "max_voltage": 21000, + "violated": False, + }, + { + "bus_id": "bus0", + "phase": "bn", + "voltage": -10000.0 + -17320.508076j, + "min_voltage": np.nan, + "max_voltage": 21000, + "violated": False, + }, + { + "bus_id": "bus0", + "phase": "cn", + "voltage": -10000.0 + 17320.508076j, + "min_voltage": np.nan, + "max_voltage": 21000, + "violated": False, + }, + { + "bus_id": "bus1", + "phase": "an", + "voltage": 19999.949999875 + 0.0j, + "min_voltage": 20000, + "max_voltage": np.nan, + "violated": True, + }, + { + "bus_id": "bus1", + "phase": "bn", + "voltage": -9999.9749999375 + -17320.464774621556j, + "min_voltage": 20000, + "max_voltage": np.nan, + "violated": True, + }, + { + "bus_id": "bus1", + "phase": "cn", + "voltage": -9999.9749999375 + 17320.464774621556j, + "min_voltage": 20000, + "max_voltage": np.nan, + "violated": True, + }, ] - def set_index_dtype(idx: pd.MultiIndex) -> pd.MultiIndex: - return idx.set_levels(idx.levels[1].astype(_VOLTAGE_PHASES_DTYPE), level=1) - buses_voltages = small_network.res_buses_voltages - expected_buses_voltages = pd.DataFrame.from_records(voltage_records, index=["bus_id", "phase"]) - expected_buses_voltages.index = set_index_dtype(expected_buses_voltages.index) + expected_buses_voltages = ( + pd.DataFrame.from_records(voltage_records) + .astype( + { + "bus_id": str, + "phase": VoltagePhaseDtype, + "voltage": complex, + "min_voltage": float, + "max_voltage": float, + "violated": pd.BooleanDtype(), + } + ) + .set_index(["bus_id", "phase"]) + ) assert isinstance(buses_voltages, pd.DataFrame) - assert buses_voltages.shape == (6, 1) + assert buses_voltages.shape == (6, 4) assert buses_voltages.index.names == ["bus_id", "phase"] - assert list(buses_voltages.columns) == ["voltage"] + assert list(buses_voltages.columns) == ["voltage", "min_voltage", "max_voltage", "violated"] assert_frame_equal(buses_voltages, expected_buses_voltages) @@ -720,6 +886,9 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): new_net = ElectricalNetwork.from_dict(net_dict) assert_frame_equal(single_phase_network.buses_frame, new_net.buses_frame) assert_frame_equal(single_phase_network.branches_frame, new_net.branches_frame) + assert_frame_equal(single_phase_network.transformers_frame, new_net.transformers_frame) + assert_frame_equal(single_phase_network.lines_frame, new_net.lines_frame) + assert_frame_equal(single_phase_network.switches_frame, new_net.switches_frame) assert_frame_equal(single_phase_network.loads_frame, new_net.loads_frame) assert_frame_equal(single_phase_network.sources_frame, new_net.sources_frame) @@ -804,7 +973,7 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): {"bus_id": "bus1", "phase": "n", "potential": 0j}, ] ) - .astype({"phase": _PHASE_DTYPE, "potential": complex}) + .astype({"phase": PhaseDtype, "potential": complex}) .set_index(["bus_id", "phase"]), ) # Buses voltages results @@ -812,11 +981,33 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): single_phase_network.res_buses_voltages, pd.DataFrame.from_records( [ - {"bus_id": "bus0", "phase": "bn", "voltage": (19999.94999975 + 0j) - (-0.050000250001249996 + 0j)}, - {"bus_id": "bus1", "phase": "bn", "voltage": (19999.899999499998 + 0j) - (0j)}, + { + "bus_id": "bus0", + "phase": "bn", + "voltage": (19999.94999975 + 0j) - (-0.050000250001249996 + 0j), + "min_voltage": np.nan, + "max_voltage": np.nan, + "violated": None, + }, + { + "bus_id": "bus1", + "phase": "bn", + "voltage": (19999.899999499998 + 0j) - (0j), + "min_voltage": np.nan, + "max_voltage": np.nan, + "violated": None, + }, ] ) - .astype({"phase": _VOLTAGE_PHASES_DTYPE, "voltage": complex}) + .astype( + { + "phase": VoltagePhaseDtype, + "voltage": complex, + "min_voltage": float, + "max_voltage": float, + "violated": pd.BooleanDtype(), + } + ) .set_index(["bus_id", "phase"]), ) # Branches results @@ -827,6 +1018,7 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): { "branch_id": "line", "phase": "b", + "branch_type": "line", "current1": 0.005000025000117603 + 0j, "current2": -0.005000025000117603 - 0j, "power1": (19999.94999975 + 0j) * (0.005000025000117603 + 0j).conjugate(), @@ -837,6 +1029,7 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): { "branch_id": "line", "phase": "n", + "branch_type": "line", "current1": -0.005000025000125 + 0j, "current2": 0.005000025000125 - 0j, "power1": (-0.050000250001249996 + 0j) * (-0.005000025000125 + 0j).conjugate(), @@ -848,7 +1041,8 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): ) .astype( { - "phase": _PHASE_DTYPE, + "phase": PhaseDtype, + "branch_type": BranchTypeDtype, "current1": complex, "current2": complex, "power1": complex, @@ -859,8 +1053,43 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): ) .set_index(["branch_id", "phase"]), ) + + # Transformers results + pd.testing.assert_frame_equal( + single_phase_network.res_transformers, + pd.DataFrame.from_records( + [], + columns=[ + "transformer_id", + "phase", + "current1", + "current2", + "power1", + "power2", + "potential1", + "potential2", + "max_power", + "violated", + ], + ) + .astype( + { + "phase": PhaseDtype, + "current1": complex, + "current2": complex, + "power1": complex, + "power2": complex, + "potential1": complex, + "potential2": complex, + "max_power": float, + "violated": pd.BooleanDtype(), + } + ) + .set_index(["transformer_id", "phase"]), + ) # Lines results - expected_res_lines = ( + pd.testing.assert_frame_equal( + single_phase_network.res_lines, pd.DataFrame.from_records( [ { @@ -877,6 +1106,8 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): + (19999.899999499998 + 0j) * (-0.005000025000117603 - 0j).conjugate() ), "series_current": 0.005000025000117603 + 0j, + "max_current": np.nan, + "violated": None, }, { "line_id": "line", @@ -892,12 +1123,14 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): + (0j) * (0.005000025000125 - 0j).conjugate() ), "series_current": -0.005000025000125 + 0j, + "max_current": np.nan, + "violated": None, }, ] ) .astype( { - "phase": _PHASE_DTYPE, + "phase": PhaseDtype, "current1": complex, "current2": complex, "power1": complex, @@ -906,11 +1139,41 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): "potential2": complex, "series_losses": complex, "series_current": complex, + "max_current": float, + "violated": pd.BooleanDtype(), } ) - .set_index(["line_id", "phase"]) + .set_index(["line_id", "phase"]), + ) + # Switches results + pd.testing.assert_frame_equal( + single_phase_network.res_switches, + pd.DataFrame.from_records( + [], + columns=[ + "switch_id", + "phase", + "current1", + "current2", + "power1", + "power2", + "potential1", + "potential2", + ], + ) + .astype( + { + "phase": PhaseDtype, + "current1": complex, + "current2": complex, + "power1": complex, + "power2": complex, + "potential1": complex, + "potential2": complex, + } + ) + .set_index(["switch_id", "phase"]), ) - pd.testing.assert_frame_equal(single_phase_network.res_lines, expected_res_lines) # Loads results pd.testing.assert_frame_equal( single_phase_network.res_loads, @@ -932,12 +1195,12 @@ def test_single_phase_network(single_phase_network: ElectricalNetwork): }, ] ) - .astype({"phase": _PHASE_DTYPE, "current": complex, "power": complex, "potential": complex}) + .astype({"phase": PhaseDtype, "current": complex, "power": complex, "potential": complex}) .set_index(["load_id", "phase"]), ) -def test_network_elements(small_network): +def test_network_elements(small_network: ElectricalNetwork): # Add a line to the network ("bus2" constructor belongs to the network) bus1 = small_network.buses["bus1"] bus2 = Bus("bus2", phases="abcn") @@ -1112,159 +1375,447 @@ def test_network_results_warning(small_network: ElectricalNetwork, good_json_res def test_load_flow_results_frames(small_network: ElectricalNetwork, good_json_results: dict): small_network.results_from_dict(good_json_results) + small_network.buses["bus0"].min_voltage = 21_000 - def set_index_dtype(df, dtype): - df.index = df.index.set_levels(df.index.levels[1].astype(dtype), level=1) - - expected_res_buses = pd.DataFrame.from_records( - [ - {"bus_id": "bus0", "phase": "a", "potential": 20000 + 2.89120e-18j}, - {"bus_id": "bus0", "phase": "b", "potential": -10000.00000 - 17320.50807j}, - {"bus_id": "bus0", "phase": "c", "potential": -10000.00000 + 17320.50807j}, - {"bus_id": "bus0", "phase": "n", "potential": -1.34764e-12 + 2.89120e-18j}, - {"bus_id": "bus1", "phase": "a", "potential": 19999.94999 + 2.89119e-18j}, - {"bus_id": "bus1", "phase": "b", "potential": -9999.97499 - 17320.46477j}, - {"bus_id": "bus1", "phase": "c", "potential": -9999.97499 + 17320.46477j}, - {"bus_id": "bus1", "phase": "n", "potential": 0j}, - ], - index=["bus_id", "phase"], + # Buses results + expected_res_buses = ( + pd.DataFrame.from_records( + [ + {"bus_id": "bus0", "phase": "a", "potential": 20000 + 2.89120e-18j}, + {"bus_id": "bus0", "phase": "b", "potential": -10000.00000 - 17320.50807j}, + {"bus_id": "bus0", "phase": "c", "potential": -10000.00000 + 17320.50807j}, + {"bus_id": "bus0", "phase": "n", "potential": -1.34764e-12 + 2.89120e-18j}, + {"bus_id": "bus1", "phase": "a", "potential": 19999.94999 + 2.89119e-18j}, + {"bus_id": "bus1", "phase": "b", "potential": -9999.97499 - 17320.46477j}, + {"bus_id": "bus1", "phase": "c", "potential": -9999.97499 + 17320.46477j}, + {"bus_id": "bus1", "phase": "n", "potential": 0j}, + ] + ) + .astype({"bus_id": object, "phase": PhaseDtype, "potential": complex}) + .set_index(["bus_id", "phase"]) ) - set_index_dtype(expected_res_buses, _PHASE_DTYPE) assert_frame_equal(small_network.res_buses, expected_res_buses, rtol=1e-4) - expected_res_branches = pd.DataFrame.from_records( - [ - { - "branch_id": "line", - "phase": "a", - "current1": 0.00500 + 7.22799e-25j, - "current2": -0.00500 - 7.22799e-25j, - "power1": (20000 + 2.89120e-18j) * (0.00500 + 7.22799e-25j).conjugate(), - "power2": (19999.94999 + 2.89119e-18j) * (-0.00500 - 7.22799e-25j).conjugate(), - "potential1": 20000 + 2.89120e-18j, - "potential2": 19999.94999 + 2.89119e-18j, - }, - { - "branch_id": "line", - "phase": "b", - "current1": -0.00250 - 0.00433j, - "current2": 0.00250 + 0.00433j, - "power1": (-10000.00000 - 17320.50807j) * (-0.00250 - 0.00433j).conjugate(), - "power2": (-9999.97499 - 17320.46477j) * (0.00250 + 0.00433j).conjugate(), - "potential1": -10000.00000 - 17320.50807j, - "potential2": -9999.97499 - 17320.46477j, - }, + # Buses voltages results + expected_res_buses_voltages = ( + pd.DataFrame.from_records( + [ + { + "bus_id": "bus0", + "phase": "an", + "voltage": (20000 + 2.89120e-18j) - (-1.34764e-12 + 2.89120e-18j), + "min_voltage": 21_000, + "max_voltage": np.nan, + "violated": True, + }, + { + "bus_id": "bus0", + "phase": "bn", + "voltage": (-10000.00000 - 17320.50807j) - (-1.34764e-12 + 2.89120e-18j), + "min_voltage": 21_000, + "max_voltage": np.nan, + "violated": True, + }, + { + "bus_id": "bus0", + "phase": "cn", + "voltage": (-10000.00000 + 17320.50807j) - (-1.34764e-12 + 2.89120e-18j), + "min_voltage": 21_000, + "max_voltage": np.nan, + "violated": True, + }, + { + "bus_id": "bus1", + "phase": "an", + "voltage": (19999.94999 + 2.89119e-18j) - (0j), + "min_voltage": np.nan, + "max_voltage": np.nan, + "violated": None, + }, + { + "bus_id": "bus1", + "phase": "bn", + "voltage": (-9999.97499 - 17320.46477j) - (0j), + "min_voltage": np.nan, + "max_voltage": np.nan, + "violated": None, + }, + { + "bus_id": "bus1", + "phase": "cn", + "voltage": (-9999.97499 + 17320.46477j) - (0j), + "min_voltage": np.nan, + "max_voltage": np.nan, + "violated": None, + }, + ] + ) + .astype( { - "branch_id": "line", - "phase": "c", - "current1": -0.00250 + 0.00433j, - "current2": 0.00250 - 0.00433j, - "power1": (-10000.00000 + 17320.50807j) * (-0.00250 + 0.00433j).conjugate(), - "power2": (-9999.97499 + 17320.46477j) * (0.00250 - 0.00433j).conjugate(), - "potential1": -10000.00000 + 17320.50807j, - "potential2": -9999.97499 + 17320.46477j, - }, + "bus_id": object, + "phase": VoltagePhaseDtype, + "voltage": complex, + "min_voltage": float, + "max_voltage": float, + "violated": pd.BooleanDtype(), + } + ) + .set_index(["bus_id", "phase"]) + ) + assert_frame_equal(small_network.res_buses_voltages, expected_res_buses_voltages, rtol=1e-4) + + # Branches results + expected_res_branches = ( + pd.DataFrame.from_records( + [ + { + "branch_id": "line", + "phase": "a", + "branch_type": "line", + "current1": 0.00500 + 7.22799e-25j, + "current2": -0.00500 - 7.22799e-25j, + "power1": (20000 + 2.89120e-18j) * (0.00500 + 7.22799e-25j).conjugate(), + "power2": (19999.94999 + 2.89119e-18j) * (-0.00500 - 7.22799e-25j).conjugate(), + "potential1": 20000 + 2.89120e-18j, + "potential2": 19999.94999 + 2.89119e-18j, + }, + { + "branch_id": "line", + "phase": "b", + "branch_type": "line", + "current1": -0.00250 - 0.00433j, + "current2": 0.00250 + 0.00433j, + "power1": (-10000.00000 - 17320.50807j) * (-0.00250 - 0.00433j).conjugate(), + "power2": (-9999.97499 - 17320.46477j) * (0.00250 + 0.00433j).conjugate(), + "potential1": -10000.00000 - 17320.50807j, + "potential2": -9999.97499 - 17320.46477j, + }, + { + "branch_id": "line", + "phase": "c", + "branch_type": "line", + "current1": -0.00250 + 0.00433j, + "current2": 0.00250 - 0.00433j, + "power1": (-10000.00000 + 17320.50807j) * (-0.00250 + 0.00433j).conjugate(), + "power2": (-9999.97499 + 17320.46477j) * (0.00250 - 0.00433j).conjugate(), + "potential1": -10000.00000 + 17320.50807j, + "potential2": -9999.97499 + 17320.46477j, + }, + { + "branch_id": "line", + "phase": "n", + "branch_type": "line", + "current1": -1.34764e-13 + 2.89120e-19j, + "current2": 1.34764e-13 - 2.89120e-19j, + "power1": (-1.34764e-12 + 2.89120e-18j) * (-1.34764e-13 + 2.89120e-19j).conjugate(), + "power2": (0j) * (1.34764e-13 - 2.89120e-19j).conjugate(), + "potential1": -1.34764e-12 + 2.89120e-18j, + "potential2": 0j, + }, + ], + ) + .astype( { - "branch_id": "line", - "phase": "n", - "current1": -1.34764e-13 + 2.89120e-19j, - "current2": 1.34764e-13 - 2.89120e-19j, - "power1": (-1.34764e-12 + 2.89120e-18j) * (-1.34764e-13 + 2.89120e-19j).conjugate(), - "power2": (0j) * (1.34764e-13 - 2.89120e-19j).conjugate(), - "potential1": -1.34764e-12 + 2.89120e-18j, - "potential2": 0j, - }, - ], - index=["branch_id", "phase"], + "branch_id": object, + "phase": PhaseDtype, + "branch_type": BranchTypeDtype, + "current1": complex, + "current2": complex, + "power1": complex, + "power2": complex, + "potential1": complex, + "potential2": complex, + } + ) + .set_index(["branch_id", "phase"]) ) - set_index_dtype(expected_res_branches, _PHASE_DTYPE) assert_frame_equal(small_network.res_branches, expected_res_branches, rtol=1e-4) - expected_res_loads = pd.DataFrame.from_records( - [ - { - "load_id": "load", - "phase": "a", - "current": 0.00500 + 7.22802e-25j, - "power": (19999.94999 + 2.89119e-18j) * (0.00500 + 7.22802e-25j).conjugate(), - "potential": 19999.94999 + 2.89119e-18j, - }, + # Transformers results + expected_res_transformers = ( + pd.DataFrame.from_records( + [], + columns=[ + "transformer_id", + "phase", + "current1", + "current2", + "power1", + "power2", + "potential1", + "potential2", + "max_power", + "violated", + ], + ) + .astype( { - "load_id": "load", - "phase": "b", - "current": -0.00250 - 0.00433j, - "power": (-9999.97499 - 17320.46477j) * (-0.00250 - 0.00433j).conjugate(), - "potential": -9999.97499 - 17320.46477j, - }, + "transformer_id": object, + "phase": PhaseDtype, + "current1": complex, + "current2": complex, + "power1": complex, + "power2": complex, + "potential1": complex, + "potential2": complex, + "max_power": float, + "violated": pd.BooleanDtype(), + } + ) + .set_index(["transformer_id", "phase"]) + ) + assert_frame_equal(small_network.res_transformers, expected_res_transformers) + + # Lines results + expected_res_lines_records = [ + { + "line_id": "line", + "phase": "a", + "current1": 0.00500 + 7.22799e-25j, + "current2": -0.00500 - 7.22799e-25j, + "power1": (20000 + 2.89120e-18j) * (0.00500 + 7.22799e-25j).conjugate(), + "power2": (19999.94999 + 2.89119e-18j) * (-0.00500 - 7.22799e-25j).conjugate(), + "potential1": 20000 + 2.89120e-18j, + "potential2": 19999.94999 + 2.89119e-18j, + "series_losses": ( + (20000 + 2.89120e-18j) * (0.00500 + 7.22799e-25j).conjugate() + + (19999.94999 + 2.89119e-18j) * (-0.00500 - 7.22799e-25j).conjugate() + ), + "series_current": 0.00500 + 7.22799e-25j, + "max_current": np.nan, + "violated": None, + }, + { + "line_id": "line", + "phase": "b", + "current1": -0.00250 - 0.00433j, + "current2": 0.00250 + 0.00433j, + "power1": (-10000.00000 - 17320.50807j) * (-0.00250 - 0.00433j).conjugate(), + "power2": (-9999.97499 - 17320.46477j) * (0.00250 + 0.00433j).conjugate(), + "potential1": -10000.00000 - 17320.50807j, + "potential2": -9999.97499 - 17320.46477j, + "series_losses": ( + (-10000.00000 - 17320.50807j) * (-0.00250 - 0.00433j).conjugate() + + (-9999.97499 - 17320.46477j) * (0.00250 + 0.00433j).conjugate() + ), + "series_current": -0.00250 - 0.00433j, + "max_current": np.nan, + "violated": None, + }, + { + "line_id": "line", + "phase": "c", + "current1": -0.00250 + 0.00433j, + "current2": 0.00250 - 0.00433j, + "power1": (-10000.00000 + 17320.50807j) * (-0.00250 + 0.00433j).conjugate(), + "power2": (-9999.97499 + 17320.46477j) * (0.00250 - 0.00433j).conjugate(), + "potential1": -10000.00000 + 17320.50807j, + "potential2": -9999.97499 + 17320.46477j, + "series_losses": ( + (-10000.00000 + 17320.50807j) * (-0.00250 + 0.00433j).conjugate() + + (-9999.97499 + 17320.46477j) * (0.00250 - 0.00433j).conjugate() + ), + "series_current": -0.00250 + 0.00433j, + "max_current": np.nan, + "violated": None, + }, + { + "line_id": "line", + "phase": "n", + "current1": -1.34764e-13 + 2.89120e-19j, + "current2": 1.34764e-13 - 2.89120e-19j, + "power1": (-1.34764e-12 + 2.89120e-18j) * (-1.34764e-13 + 2.89120e-19j).conjugate(), + "power2": (0j) * (1.34764e-13 - 2.89120e-19j).conjugate(), + "potential1": -1.34764e-12 + 2.89120e-18j, + "potential2": 0j, + "series_losses": ( + (-1.34764e-12 + 2.89120e-18j) * (-1.34764e-13 + 2.89120e-19j).conjugate() + + (0j) * (1.34764e-13 - 2.89120e-19j).conjugate() + ), + "series_current": -1.34764e-13 + 2.89120e-19j, + "max_current": np.nan, + "violated": None, + }, + ] + expected_res_lines_dtypes = { + "line_id": object, + "phase": PhaseDtype, + "current1": complex, + "current2": complex, + "power1": complex, + "power2": complex, + "potential1": complex, + "potential2": complex, + "series_losses": complex, + "series_current": complex, + "max_current": float, + "violated": pd.BooleanDtype(), + } + expected_res_lines = ( + pd.DataFrame.from_records(expected_res_lines_records) + .astype(expected_res_lines_dtypes) + .set_index(["line_id", "phase"]) + ) + assert_frame_equal(small_network.res_lines, expected_res_lines, rtol=1e-4, atol=1e-5) + + # Lines with violated max current + small_network.branches["line"].parameters.max_current = 0.002 + expected_res_lines_violated_records = [ + d | {"max_current": 0.002, "violated": d["phase"] != "n"} for d in expected_res_lines_records + ] + expected_res_violated_lines = ( + pd.DataFrame.from_records(expected_res_lines_violated_records) + .astype(expected_res_lines_dtypes) + .set_index(["line_id", "phase"]) + ) + assert_frame_equal(small_network.res_lines, expected_res_violated_lines, rtol=1e-4, atol=1e-5) + + # Switches results + expected_res_switches = ( + pd.DataFrame.from_records( + [], + columns=[ + "switch_id", + "phase", + "current1", + "current2", + "power1", + "power2", + "potential1", + "potential2", + ], + ) + .astype( { - "load_id": "load", - "phase": "c", - "current": -0.00250 + 0.00433j, - "power": (-9999.97499 + 17320.46477j) * (-0.00250 + 0.00433j).conjugate(), - "potential": -9999.97499 + 17320.46477j, - }, + "switch_id": object, + "phase": PhaseDtype, + "current1": complex, + "current2": complex, + "power1": complex, + "power2": complex, + "potential1": complex, + "potential2": complex, + } + ) + .set_index(["switch_id", "phase"]) + ) + assert_frame_equal(small_network.res_switches, expected_res_switches) + + # Loads results + expected_res_loads = ( + pd.DataFrame.from_records( + [ + { + "load_id": "load", + "phase": "a", + "current": 0.00500 + 7.22802e-25j, + "power": (19999.94999 + 2.89119e-18j) * (0.00500 + 7.22802e-25j).conjugate(), + "potential": 19999.94999 + 2.89119e-18j, + }, + { + "load_id": "load", + "phase": "b", + "current": -0.00250 - 0.00433j, + "power": (-9999.97499 - 17320.46477j) * (-0.00250 - 0.00433j).conjugate(), + "potential": -9999.97499 - 17320.46477j, + }, + { + "load_id": "load", + "phase": "c", + "current": -0.00250 + 0.00433j, + "power": (-9999.97499 + 17320.46477j) * (-0.00250 + 0.00433j).conjugate(), + "potential": -9999.97499 + 17320.46477j, + }, + { + "load_id": "load", + "phase": "n", + "current": -1.34763e-13 + 0j, + "power": (0j) * (-1.34763e-13 + 0j).conjugate(), + "potential": 0j, + }, + ] + ) + .astype( { - "load_id": "load", - "phase": "n", - "current": -1.34763e-13 + 0j, - "power": (0j) * (-1.34763e-13 + 0j).conjugate(), - "potential": 0j, - }, - ], - index=["load_id", "phase"], + "load_id": object, + "phase": PhaseDtype, + "current": complex, + "power": complex, + "potential": complex, + } + ) + .set_index(["load_id", "phase"]) ) - set_index_dtype(expected_res_loads, _PHASE_DTYPE) assert_frame_equal(small_network.res_loads, expected_res_loads, rtol=1e-4) - expected_res_sources = pd.DataFrame.from_records( - [ - { - "source_id": "vs", - "phase": "a", - "current": -0.00500 + 0j, - "power": (20000 + 2.89120e-18j) * (-0.00500 + 0j).conjugate(), - "potential": 20000 + 2.89120e-18j, - }, - { - "source_id": "vs", - "phase": "b", - "current": 0.00250 + 0.00433j, - "power": (-10000.00000 - 17320.50807j) * (0.00250 + 0.00433j).conjugate(), - "potential": -10000.00000 - 17320.50807j, - }, - { - "source_id": "vs", - "phase": "c", - "current": 0.00250 - 0.00433j, - "power": (-10000.00000 + 17320.50807j) * (0.00250 - 0.00433j).conjugate(), - "potential": -10000.00000 + 17320.50807j, - }, + # Sources results + expected_res_sources = ( + pd.DataFrame.from_records( + [ + { + "source_id": "vs", + "phase": "a", + "current": -0.00500 + 0j, + "power": (20000 + 2.89120e-18j) * (-0.00500 + 0j).conjugate(), + "potential": 20000 + 2.89120e-18j, + }, + { + "source_id": "vs", + "phase": "b", + "current": 0.00250 + 0.00433j, + "power": (-10000.00000 - 17320.50807j) * (0.00250 + 0.00433j).conjugate(), + "potential": -10000.00000 - 17320.50807j, + }, + { + "source_id": "vs", + "phase": "c", + "current": 0.00250 - 0.00433j, + "power": (-10000.00000 + 17320.50807j) * (0.00250 - 0.00433j).conjugate(), + "potential": -10000.00000 + 17320.50807j, + }, + { + "source_id": "vs", + "phase": "n", + "current": 1.34764e-13 - 2.89121e-19j, + "power": (-1.34764e-12 + 2.89120e-18j) * (1.34764e-13 - 2.89121e-19j).conjugate(), + "potential": -1.34764e-12 + 2.89120e-18j, + }, + ] + ) + .astype( { - "source_id": "vs", - "phase": "n", - "current": 1.34764e-13 - 2.89121e-19j, - "power": (-1.34764e-12 + 2.89120e-18j) * (1.34764e-13 - 2.89121e-19j).conjugate(), - "potential": -1.34764e-12 + 2.89120e-18j, - }, - ], - index=["source_id", "phase"], + "source_id": object, + "phase": PhaseDtype, + "current": complex, + "power": complex, + "potential": complex, + } + ) + .set_index(["source_id", "phase"]) ) - set_index_dtype(expected_res_sources, _PHASE_DTYPE) assert_frame_equal(small_network.res_sources, expected_res_sources, rtol=1e-4) - expected_res_grounds = pd.DataFrame.from_records( - [ - {"ground_id": "ground", "potential": 0j}, - ], - index=["ground_id"], + # Grounds results + expected_res_grounds = ( + pd.DataFrame.from_records( + [ + {"ground_id": "ground", "potential": 0j}, + ] + ) + .astype({"ground_id": object, "potential": complex}) + .set_index(["ground_id"]) ) assert_frame_equal(small_network.res_grounds, expected_res_grounds) - expected_res_potential_refs = pd.DataFrame.from_records( - [ - {"potential_ref_id": "pref", "current": 1.08420e-18 - 2.89120e-19j}, - ], - index=["potential_ref_id"], + # Potential refs results + expected_res_potential_refs = ( + pd.DataFrame.from_records( + [ + {"potential_ref_id": "pref", "current": 1.08420e-18 - 2.89120e-19j}, + ] + ) + .astype({"potential_ref_id": object, "current": complex}) + .set_index(["potential_ref_id"]) ) assert_frame_equal(small_network.res_potential_refs, expected_res_potential_refs) @@ -1283,27 +1834,29 @@ def set_index_dtype(df, dtype): [99.99999999999994, 0.0], ] small_network.results_from_dict(good_json_results) - expected_res_flex_powers = pd.DataFrame.from_records( - [ - { - "load_id": "load", - "phase": "an", - "power": 99.99999999999994 + 0j, - }, - { - "load_id": "load", - "phase": "bn", - "power": 99.99999999999994 + 0j, - }, - { - "load_id": "load", - "phase": "cn", - "power": 99.99999999999994 + 0j, - }, - ], - index=["load_id", "phase"], + expected_res_flex_powers = ( + pd.DataFrame.from_records( + [ + { + "load_id": "load", + "phase": "an", + "power": 99.99999999999994 + 0j, + }, + { + "load_id": "load", + "phase": "bn", + "power": 99.99999999999994 + 0j, + }, + { + "load_id": "load", + "phase": "cn", + "power": 99.99999999999994 + 0j, + }, + ] + ) + .astype({"load_id": object, "phase": VoltagePhaseDtype, "power": complex}) + .set_index(["load_id", "phase"]) ) - set_index_dtype(expected_res_flex_powers, _VOLTAGE_PHASES_DTYPE) assert_frame_equal(small_network.res_loads_flexible_powers, expected_res_flex_powers, rtol=1e-4) diff --git a/roseau/load_flow/units.py b/roseau/load_flow/units.py index 24e9212c..0c497a44 100644 --- a/roseau/load_flow/units.py +++ b/roseau/load_flow/units.py @@ -12,6 +12,7 @@ .. _pint: https://pint.readthedocs.io/en/stable/getting/overview.html """ from collections.abc import Callable, Iterable +from types import GenericAlias from typing import TYPE_CHECKING, TypeVar, Union from pint import Unit, UnitRegistry @@ -32,7 +33,7 @@ Q_: TypeAlias = PlainQuantity[T] else: Q_ = ureg.Quantity - Q_.__class_getitem__ = lambda cls, *args: cls + Q_.__class_getitem__ = classmethod(GenericAlias) def ureg_wraps( @@ -40,4 +41,16 @@ def ureg_wraps( args: Union[str, Unit, None, Iterable[Union[str, Unit, None]]], strict: bool = True, ) -> Callable[[FuncT], FuncT]: + """Wraps a function to become pint-aware. + + Args: + ureg: + a UnitRegistry instance. + ret: + Units of each of the return values. Use `None` to skip argument conversion. + args: + Units of each of the input arguments. Use `None` to skip argument conversion. + strict: + Indicates that only quantities are accepted. (Default value = True) + """ return ureg.wraps(ret, args, strict) diff --git a/roseau/load_flow/utils/__init__.py b/roseau/load_flow/utils/__init__.py index b3156715..e774d8d0 100644 --- a/roseau/load_flow/utils/__init__.py +++ b/roseau/load_flow/utils/__init__.py @@ -4,7 +4,14 @@ from roseau.load_flow.utils.console import console, palette from roseau.load_flow.utils.constants import CX, DELTA_P, EPSILON_0, EPSILON_R, MU_0, MU_R, OMEGA, PI, RHO, TAN_D, F from roseau.load_flow.utils.mixins import CatalogueMixin, Identifiable, JsonMixin -from roseau.load_flow.utils.types import ConductorType, InsulatorType, LineType +from roseau.load_flow.utils.types import ( + BranchTypeDtype, + ConductorType, + InsulatorType, + LineType, + PhaseDtype, + VoltagePhaseDtype, +) __all__ = [ # Constants @@ -27,6 +34,10 @@ "LineType", "ConductorType", "InsulatorType", + # Dtypes + "PhaseDtype", + "VoltagePhaseDtype", + "BranchTypeDtype", # Console "console", "palette", diff --git a/roseau/load_flow/utils/mixins.py b/roseau/load_flow/utils/mixins.py index 6e5c82d7..9b6af540 100644 --- a/roseau/load_flow/utils/mixins.py +++ b/roseau/load_flow/utils/mixins.py @@ -53,13 +53,9 @@ def from_json(cls, path: StrPath) -> Self: return cls.from_dict(data=data) @abstractmethod - 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. - """ + def to_dict(self, *, _lf_only: bool = False) -> JsonDict: + """Return the element information as a dictionary format.""" + # _lf_only is used internally by Roseau Load Flow. Please do not use. raise NotImplementedError def to_json(self, path: StrPath) -> Path: diff --git a/roseau/load_flow/utils/types.py b/roseau/load_flow/utils/types.py index 5e2f8be0..e792f510 100644 --- a/roseau/load_flow/utils/types.py +++ b/roseau/load_flow/utils/types.py @@ -1,6 +1,7 @@ import logging from enum import Enum, auto, unique +import pandas as pd from typing_extensions import Self from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode @@ -9,6 +10,48 @@ logger = logging.getLogger(__name__) +# pandas dtypes used in the data frames +PhaseDtype = pd.CategoricalDtype(categories=["a", "b", "c", "n"], ordered=True) +"""Categorical data type used for the phase of potentials, currents, powers, etc.""" +VoltagePhaseDtype = pd.CategoricalDtype(categories=["an", "bn", "cn", "ab", "bc", "ca"], ordered=True) +"""Categorical data type used for the phase of voltages and flexible powers only.""" +BranchTypeDtype = pd.CategoricalDtype(categories=["line", "transformer", "switch"], ordered=True) +"""Categorical data type used for branch types.""" +_DTYPES = { + "bus_id": object, + "branch_id": object, + "transformer_id": object, + "line_id": object, + "switch_id": object, + "load_id": object, + "source_id": object, + "ground_id": object, + "potential_ref_id": object, + "branch_type": BranchTypeDtype, + "phase": PhaseDtype, + "current": complex, + "current1": complex, + "current2": complex, + "power": complex, + "power1": complex, + "power2": complex, + "potential": complex, + "potential1": complex, + "potential2": complex, + "voltage": complex, + "voltage1": complex, + "voltage2": complex, + "max_power": float, + "series_losses": complex, + "shunt_losses": complex, + "series_current": complex, + "max_current": float, + "min_voltage": float, + "max_voltage": float, + "violated": pd.BooleanDtype(), +} + + @unique class LineType(Enum): """The type of a line.""" From bfb14ce09e9939ed919bdad3896b4821d0550e67 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Tue, 10 Oct 2023 08:28:30 +0200 Subject: [PATCH 28/43] Add API reference to the models pages (#139) So this improves the docs of the elements by bringing the documentation of the API of an element closer to the the definition of its model. I left the comprehensive API alone which means each element class now have two pages describing its API. This is OK because the pages are auto-generated so they never get out of sync. I removed the "See Also" links from the doscstring as they point to the same page the text is displayed in now. --- doc/conf.py | 1 + doc/index.md | 3 ++- doc/models/Bus.md | 9 +++++++ doc/models/Ground.md | 9 +++++++ doc/models/Line/index.md | 13 ++++++++++ doc/models/Load/FlexibleLoad/index.md | 17 +++++++++++++ doc/models/Load/index.md | 21 ++++++++++++++++ doc/models/PotentialRef.md | 9 +++++++ doc/models/Switch.md | 11 +++++++- doc/models/Transformer/index.md | 13 ++++++++++ doc/models/VoltageSource.md | 9 +++++++ doc/usage/Getting_Started.md | 2 -- roseau/load_flow/models/buses.py | 10 +++----- roseau/load_flow/models/grounds.py | 4 --- roseau/load_flow/models/lines/lines.py | 15 +++-------- roseau/load_flow/models/lines/parameters.py | 6 +---- .../models/loads/flexible_parameters.py | 9 ------- roseau/load_flow/models/loads/loads.py | 25 ++++--------------- roseau/load_flow/models/potential_refs.py | 3 --- roseau/load_flow/models/sources.py | 6 +---- .../models/transformers/parameters.py | 6 +---- .../models/transformers/transformers.py | 8 +++--- roseau/load_flow/utils/mixins.py | 8 ++++-- 23 files changed, 137 insertions(+), 80 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index bb13e336..42280718 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -68,6 +68,7 @@ autodoc_member_order = "bysource" autodoc_typehints = "signature" autodoc_inherit_docstrings = True +autoclass_content = "both" # show both class and __init__ docstrings # -- Options for HTML output ------------------------------------------------- diff --git a/doc/index.md b/doc/index.md index 046142d1..49e1c4c7 100644 --- a/doc/index.md +++ b/doc/index.md @@ -42,7 +42,8 @@ usage/index ## Models -A description of the electrical models used for each component is available: +A description of the electrical models used for each component, an example usage, and a reference +to the API of the classes are available here: ```{toctree} --- diff --git a/doc/models/Bus.md b/doc/models/Bus.md index de3be57a..e55951cc 100644 --- a/doc/models/Bus.md +++ b/doc/models/Bus.md @@ -101,3 +101,12 @@ en.res_branches[["current1"]].transform([np.abs, ft.partial(np.angle, deg=True)] # | ('line', 'c') | 0 | 0 | # | ('line', 'n') | 0 | 0 | ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.Bus + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/Ground.md b/doc/models/Ground.md index c4f6a10c..7f222bca 100644 --- a/doc/models/Ground.md +++ b/doc/models/Ground.md @@ -147,3 +147,12 @@ en.res_buses_voltages.transform([np.abs, ft.partial(np.angle, deg=True)]) # | ('bus3', 'bc') | 385.429 | -121.026 | # | ('bus3', 'ca') | 399.18 | 118.807 | ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.Ground + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/Line/index.md b/doc/models/Line/index.md index d622f17b..874893d3 100644 --- a/doc/models/Line/index.md +++ b/doc/models/Line/index.md @@ -180,3 +180,16 @@ Parameters ShuntLine SimplifiedLine ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.LineParameters + :members: + :show-inheritance: + :no-index: +.. autoclass:: roseau.load_flow.models.Line + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/Load/FlexibleLoad/index.md b/doc/models/Load/FlexibleLoad/index.md index 9dcb9a30..6de965c3 100644 --- a/doc/models/Load/FlexibleLoad/index.md +++ b/doc/models/Load/FlexibleLoad/index.md @@ -55,3 +55,20 @@ Projection FlexibleParameter FeasibleDomain ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.Control + :members: + :show-inheritance: + :no-index: +.. autoclass:: roseau.load_flow.models.Projection + :members: + :show-inheritance: + :no-index: +.. autoclass:: roseau.load_flow.models.FlexibleParameter + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/Load/index.md b/doc/models/Load/index.md index 5e4decf0..a150851e 100644 --- a/doc/models/Load/index.md +++ b/doc/models/Load/index.md @@ -76,3 +76,24 @@ CurrentLoad PowerLoad FlexibleLoad/index ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.AbstractLoad + :members: + :show-inheritance: + :no-index: +.. autoclass:: roseau.load_flow.models.ImpedanceLoad + :members: + :show-inheritance: + :no-index: +.. autoclass:: roseau.load_flow.models.CurrentLoad + :members: + :show-inheritance: + :no-index: +.. autoclass:: roseau.load_flow.models.PowerLoad + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/PotentialRef.md b/doc/models/PotentialRef.md index 44b9965e..fb2886f6 100644 --- a/doc/models/PotentialRef.md +++ b/doc/models/PotentialRef.md @@ -47,3 +47,12 @@ from roseau.load_flow.models import Bus, PotentialRef bus = Bus(id="bus", phases="abcn") p_ref = PotentialRef(id="pref", element=bus, phase="a") ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.PotentialRef + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/Switch.md b/doc/models/Switch.md index 476474a1..efc0f6ba 100644 --- a/doc/models/Switch.md +++ b/doc/models/Switch.md @@ -84,7 +84,7 @@ en.res_branches[["current2"]].transform([np.abs, ft.partial(np.angle, deg=True)] # The two currents are equal in magnitude and opposite in phase, as expected # The two buses have the same voltages -en.res_buses_voltages.transform([np.abs, ft.partial(np.angle, deg=True)]) +en.res_buses_voltages[["voltage"]].transform([np.abs, ft.partial(np.angle, deg=True)]) # | | ('voltage', 'absolute') | ('voltage', 'angle') | # |:---------------|--------------------------:|-----------------------:| # | ('bus1', 'an') | 230.94 | 0 | @@ -94,3 +94,12 @@ en.res_buses_voltages.transform([np.abs, ft.partial(np.angle, deg=True)]) # | ('bus2', 'bn') | 230.94 | -120 | # | ('bus2', 'cn') | 230.94 | 120 | ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.Switch + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/Transformer/index.md b/doc/models/Transformer/index.md index e8d8d955..16521015 100644 --- a/doc/models/Transformer/index.md +++ b/doc/models/Transformer/index.md @@ -154,3 +154,16 @@ Single_Phase_Transformer Three_Phase_Transformer Center_Tapped_Transformer ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.TransformerParameters + :members: + :show-inheritance: + :no-index: +.. autoclass:: roseau.load_flow.models.Transformer + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/models/VoltageSource.md b/doc/models/VoltageSource.md index 7647d4d5..f37d47ea 100644 --- a/doc/models/VoltageSource.md +++ b/doc/models/VoltageSource.md @@ -111,3 +111,12 @@ un = 400 voltages = un * np.exp([0, -2j * np.pi / 3]) # Only two elements!! VoltageSource(id="vs", bus=bus, phases="abc", voltages=voltages) # Error ``` + +## API Reference + +```{eval-rst} +.. autoclass:: roseau.load_flow.models.VoltageSource + :members: + :show-inheritance: + :no-index: +``` diff --git a/doc/usage/Getting_Started.md b/doc/usage/Getting_Started.md index 00a93256..40aa587b 100644 --- a/doc/usage/Getting_Started.md +++ b/doc/usage/Getting_Started.md @@ -58,8 +58,6 @@ The following is a summary of the available elements: - `PotentialRef`: A potential reference sets the reference of potentials in the network. It can be connected to buses or grounds. -For a more detailed description of the elements, please refer to the [API reference](../autoapi/roseau/load_flow/models/index). - Let's use some of these elements to build the following network with a voltage source, a simple line and a constant power load. This network is a low voltage network (three-phase + neutral wire). diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index 8fead19a..fd8254b4 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -20,11 +20,7 @@ class Bus(Element): - """An electrical bus. - - See Also: - :doc:`Bus model documentation ` - """ + """A multi-phase electrical bus.""" allowed_phases = frozenset({"ab", "bc", "ca", "an", "bn", "cn", "abn", "bcn", "can", "abc", "abcn"}) """The allowed phases for a bus are: @@ -54,7 +50,7 @@ def __init__( phases: The phases of the bus. A string like ``"abc"`` or ``"an"`` etc. The order of the phases is important. For a full list of supported phases, see the class attribute - :attr:`Bus.allowed_phases`. + :attr:`.allowed_phases`. geometry: An optional geometry of the bus; a :class:`~shapely.Point` that represents the @@ -347,5 +343,5 @@ def short_circuits(self) -> list[dict[str, Any]]: return self._short_circuits[:] # return a copy as users should not modify the list directly def clear_short_circuits(self) -> None: - """Remove the short-circuits.""" + """Remove the short-circuits of this bus.""" self._short_circuits = [] diff --git a/roseau/load_flow/models/grounds.py b/roseau/load_flow/models/grounds.py index ca982213..ab1f12c4 100644 --- a/roseau/load_flow/models/grounds.py +++ b/roseau/load_flow/models/grounds.py @@ -30,10 +30,6 @@ class Ground(Element): To connect a ground to a line with shunt components, pass the ground object to the :class:`Line` constructor. Note that the ground connection is mandatory for shunt lines. - - - See Also: - :doc:`Ground model documentation ` """ allowed_phases = frozenset({"a", "b", "c", "n"}) diff --git a/roseau/load_flow/models/lines/lines.py b/roseau/load_flow/models/lines/lines.py index 36564fd7..606a55c5 100644 --- a/roseau/load_flow/models/lines/lines.py +++ b/roseau/load_flow/models/lines/lines.py @@ -19,11 +19,7 @@ class Switch(AbstractBranch): - """A general purpose switch branch. - - See Also: - :doc:`Switch model documentation ` - """ + """A general purpose switch branch.""" branch_type = "switch" @@ -128,11 +124,7 @@ def _check_elements(self) -> None: class Line(AbstractBranch): - """An electrical line PI model with series impedance and optional shunt admittance. - - See Also: - :doc:`Line documentation ` - """ + """An electrical line PI model with series impedance and optional shunt admittance.""" branch_type = "line" @@ -171,7 +163,8 @@ def __init__( The second bus (aka `"to_bus"`) to connect to the line. parameters: - The parameters of the line, an instance of :class:`LineParameters`. + Parameters defining the electrical model of the line. This is an instance of the + :class:`LineParameters` class and can be used by multiple lines. length: The length of the line in km. diff --git a/roseau/load_flow/models/lines/parameters.py b/roseau/load_flow/models/lines/parameters.py index f9c86e68..fad31cad 100644 --- a/roseau/load_flow/models/lines/parameters.py +++ b/roseau/load_flow/models/lines/parameters.py @@ -30,11 +30,7 @@ class LineParameters(Identifiable, JsonMixin): - """A class to store the line parameters of lines - - See Also: - :ref:`Line parameters documentation ` - """ + """Parameters that define electrical models of lines.""" _type_re = "|".join("|".join(x) for x in LineType.CODES.values()) _material_re = "|".join(x.code() for x in ConductorType) diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index e7fcb95d..ee35f2dd 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -45,9 +45,6 @@ class Control(JsonMixin): :math:`P^{\\max}_{\\mathrm{cons}}(U)`. * ``"q_u"``: control the reactive power based on the voltage :math:`Q(U)`. - - See Also: - :ref:`Control documentation ` """ _DEFAULT_ALPHA: float = 1000.0 @@ -351,9 +348,6 @@ class Projection(JsonMixin): * ``"euclidean"``: for a Euclidean projection on the feasible space; * ``"keep_p"``: for maintaining a constant P; * ``"keep_q"``: for maintaining a constant Q. - - See Also: - :ref:`Projection documentation ` """ _DEFAULT_ALPHA: float = 1000.0 @@ -453,9 +447,6 @@ class FlexibleParameter(JsonMixin): the radius of the feasible circle used by the projection For multi-phase loads, you need to use a `FlexibleParameter` instance per phase. - - See Also: - :ref:`Flexible Parameters documentation ` """ _control_class: type[Control] = Control diff --git a/roseau/load_flow/models/loads/loads.py b/roseau/load_flow/models/loads/loads.py index 428fc1f5..f4378243 100644 --- a/roseau/load_flow/models/loads/loads.py +++ b/roseau/load_flow/models/loads/loads.py @@ -20,11 +20,8 @@ class AbstractLoad(Element, ABC): """An abstract class of an electric load. The subclasses of this class can be used to depict: - * star-connected loads using a `phases` constructor argument containing a `"n"` - * delta-connected loads using a `phases` constructor argument which doesn't contain `"n"` - - See Also: - :doc:`Load documentation ` + * star-connected loads using a `phases` constructor argument containing `"n"` + * delta-connected loads using a `phases` constructor argument not containing `"n"` """ _power_load_class: type["PowerLoad"] @@ -204,11 +201,7 @@ def _results_to_dict(self, warning: bool) -> JsonDict: class PowerLoad(AbstractLoad): - """A constant power load. - - See Also: - :doc:`Power Load documentation ` - """ + """A constant power load.""" _type = "power" @@ -352,11 +345,7 @@ def _results_to_dict(self, warning: bool) -> JsonDict: class CurrentLoad(AbstractLoad): - """A constant current load. - - See Also: - :doc:`Current Load documentation ` - """ + """A constant current load.""" _type = "current" @@ -407,11 +396,7 @@ def to_dict(self, *, _lf_only: bool = False) -> JsonDict: class ImpedanceLoad(AbstractLoad): - """A constant impedance load. - - See Also: - :doc:`Impedance Load documentation ` - """ + """A constant impedance load.""" _type = "impedance" diff --git a/roseau/load_flow/models/potential_refs.py b/roseau/load_flow/models/potential_refs.py index f49f3f6d..cdca1565 100644 --- a/roseau/load_flow/models/potential_refs.py +++ b/roseau/load_flow/models/potential_refs.py @@ -21,9 +21,6 @@ class PotentialRef(Element): can be set on any bus or ground elements. If set on a bus with no neutral and without specifying the phase, the reference will be set as ``Va + Vb + Vc = 0``. For other buses, the default is ``Vn = 0``. - - See Also: - :doc:`Potential reference model documentation ` """ allowed_phases = frozenset({"a", "b", "c", "n"}) diff --git a/roseau/load_flow/models/sources.py b/roseau/load_flow/models/sources.py index 9691a05f..8f32e440 100644 --- a/roseau/load_flow/models/sources.py +++ b/roseau/load_flow/models/sources.py @@ -16,11 +16,7 @@ class VoltageSource(Element): - """A voltage source. - - See Also: - :doc:`Voltage source model documentation ` - """ + """A voltage source.""" allowed_phases = Bus.allowed_phases """The allowed phases for a voltage source are the same as for a :attr:`bus`.""" diff --git a/roseau/load_flow/models/transformers/parameters.py b/roseau/load_flow/models/transformers/parameters.py index 8717f6d2..9c68e541 100644 --- a/roseau/load_flow/models/transformers/parameters.py +++ b/roseau/load_flow/models/transformers/parameters.py @@ -21,11 +21,7 @@ class TransformerParameters(Identifiable, JsonMixin, CatalogueMixin[pd.DataFrame]): - """A class to store the parameters of the transformers. - - See Also: - :ref:`Transformer parameters documentation ` - """ + """Parameters that define electrical models of transformers.""" _EXTRACT_WINDINGS_RE = regex.compile( "(?(DEFINE)(?Pyn?)(?Pd)(?Pzn?)(?P[06])" diff --git a/roseau/load_flow/models/transformers/transformers.py b/roseau/load_flow/models/transformers/transformers.py index 4dec6691..3d73ccda 100644 --- a/roseau/load_flow/models/transformers/transformers.py +++ b/roseau/load_flow/models/transformers/transformers.py @@ -16,10 +16,7 @@ class Transformer(AbstractBranch): """A generic transformer model. - The model parameters are defined in the ``parameters``. - - See Also: - :doc:`Transformer models documentation ` + The model parameters are defined using the ``parameters`` argument. """ branch_type = "transformer" @@ -65,7 +62,8 @@ def __init__( The tap of the transformer, for example 1.02. parameters: - The parameters of the transformer. + Parameters defining the electrical model of the transformer. This is an instance of + the :class:`TransformerParameters` class and can be used by multiple transformers. phases1: The phases of the first extremity of the transformer. A string like ``"abc"`` or diff --git a/roseau/load_flow/utils/mixins.py b/roseau/load_flow/utils/mixins.py index 9b6af540..9f3c3f7d 100644 --- a/roseau/load_flow/utils/mixins.py +++ b/roseau/load_flow/utils/mixins.py @@ -54,8 +54,12 @@ def from_json(cls, path: StrPath) -> Self: @abstractmethod def to_dict(self, *, _lf_only: bool = False) -> JsonDict: - """Return the element information as a dictionary format.""" - # _lf_only is used internally by Roseau Load Flow. Please do not use. + """Return the element information as a dictionary format. + + Args: + _lf_only: + Internal argument, please do not use. + """ raise NotImplementedError def to_json(self, path: StrPath) -> Path: From d6d91d80ed19f7dfc8f70c6ccbddca930fc3be83 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Mon, 30 Oct 2023 10:37:28 +0100 Subject: [PATCH 29/43] Add python 3.12 and fix extras --- .github/workflows/ci.yml | 2 +- .github/workflows/doc.yml | 8 +- .github/workflows/pre-commit.yml | 2 +- .pre-commit-config.yaml | 6 +- poetry.lock | 1346 +++++++++++++++--------------- pyproject.toml | 32 +- 6 files changed, 724 insertions(+), 672 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7493830c..3a6e9cdc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 6f894dd8..65d867c6 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -57,20 +57,20 @@ jobs: - name: Install poetry run: pipx install poetry - - name: Set up Python 3.11 + - name: Set up Python 3.12 uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.12" cache: "poetry" - name: Install dependencies run: | - poetry env use "3.11" + poetry env use "3.12" poetry install --only doc - name: Build with Sphinx run: | - poetry env use "3.11" + poetry env use "3.12" cd doc && make html env: SPHINXBUILD: poetry run sphinx-build diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 5fa4ac0e..706a29fc 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -23,5 +23,5 @@ jobs: lfs: false - uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.12" - uses: pre-commit/action@v3.0.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 38ffe32d..4f2862b5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ exclude: ^.idea/|^conda/meta.yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-builtin-literals - id: check-json @@ -17,11 +17,11 @@ repos: hooks: - id: poetry-check - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.9.1 # keep in sync with pyproject.toml + rev: 23.10.1 # keep in sync with pyproject.toml hooks: - id: black-jupyter - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.290 # keep in sync with pyproject.toml + rev: v0.1.3 # keep in sync with pyproject.toml hooks: - id: ruff types_or: [python, pyi, jupyter] diff --git a/poetry.lock b/poetry.lock index f0bef53e..df6b3644 100644 --- a/poetry.lock +++ b/poetry.lock @@ -35,39 +35,35 @@ files = [ [[package]] name = "astroid" -version = "2.15.6" +version = "3.0.1" description = "An abstract syntax tree for Python with inference support." optional = false -python-versions = ">=3.7.2" +python-versions = ">=3.8.0" files = [ - {file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"}, - {file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"}, + {file = "astroid-3.0.1-py3-none-any.whl", hash = "sha256:7d5895c9825e18079c5aeac0572bc2e4c83205c95d416e0b4fee8bc361d2d9ca"}, + {file = "astroid-3.0.1.tar.gz", hash = "sha256:86b0bb7d7da0be1a7c4aedb7974e391b32d4ed89e33de6ed6902b4b15c97577e"}, ] [package.dependencies] -lazy-object-proxy = ">=1.4.0" typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} -wrapt = [ - {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, - {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, -] [[package]] name = "asttokens" -version = "2.4.0" +version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, - {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] [package.dependencies] six = ">=1.12.0" [package.extras] -test = ["astroid", "pytest"] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "attrs" @@ -89,15 +85,21 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte [[package]] name = "babel" -version = "2.12.1" +version = "2.13.1" description = "Internationalization utilities" optional = false python-versions = ">=3.7" files = [ - {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, - {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, + {file = "Babel-2.13.1-py3-none-any.whl", hash = "sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed"}, + {file = "Babel-2.13.1.tar.gz", hash = "sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900"}, ] +[package.dependencies] +setuptools = {version = "*", markers = "python_version >= \"3.12\""} + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + [[package]] name = "backcall" version = "0.2.0" @@ -129,33 +131,29 @@ lxml = ["lxml"] [[package]] name = "black" -version = "23.9.1" +version = "23.10.1" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"}, - {file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"}, - {file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"}, - {file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"}, - {file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"}, - {file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"}, - {file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"}, - {file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"}, - {file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"}, - {file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"}, - {file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"}, - {file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"}, - {file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"}, + {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"}, + {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"}, + {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"}, + {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"}, + {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"}, + {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"}, + {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"}, + {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"}, + {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"}, + {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"}, + {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"}, + {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"}, + {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"}, + {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"}, + {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"}, + {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"}, + {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"}, + {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"}, ] [package.dependencies] @@ -199,86 +197,101 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.3.1.tar.gz", hash = "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win32.whl", hash = "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win32.whl", hash = "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win32.whl", hash = "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win32.whl", hash = "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win32.whl", hash = "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win32.whl", hash = "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727"}, + {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, ] [[package]] @@ -460,7 +473,10 @@ files = [ ] [package.dependencies] -numpy = {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""} +numpy = [ + {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""}, + {version = ">=1.26.0rc1,<2.0", markers = "python_version >= \"3.12\""}, +] [package.extras] bokeh = ["bokeh", "selenium"] @@ -471,63 +487,63 @@ test-no-images = ["pytest", "pytest-cov", "wurlitzer"] [[package]] name = "coverage" -version = "7.3.1" +version = "7.3.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd0f7429ecfd1ff597389907045ff209c8fdb5b013d38cfa7c60728cb484b6e3"}, - {file = "coverage-7.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:966f10df9b2b2115da87f50f6a248e313c72a668248be1b9060ce935c871f276"}, - {file = "coverage-7.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0575c37e207bb9b98b6cf72fdaaa18ac909fb3d153083400c2d48e2e6d28bd8e"}, - {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:245c5a99254e83875c7fed8b8b2536f040997a9b76ac4c1da5bff398c06e860f"}, - {file = "coverage-7.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c96dd7798d83b960afc6c1feb9e5af537fc4908852ef025600374ff1a017392"}, - {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:de30c1aa80f30af0f6b2058a91505ea6e36d6535d437520067f525f7df123887"}, - {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:50dd1e2dd13dbbd856ffef69196781edff26c800a74f070d3b3e3389cab2600d"}, - {file = "coverage-7.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9c0c19f70d30219113b18fe07e372b244fb2a773d4afde29d5a2f7930765136"}, - {file = "coverage-7.3.1-cp310-cp310-win32.whl", hash = "sha256:770f143980cc16eb601ccfd571846e89a5fe4c03b4193f2e485268f224ab602f"}, - {file = "coverage-7.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdd088c00c39a27cfa5329349cc763a48761fdc785879220d54eb785c8a38520"}, - {file = "coverage-7.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74bb470399dc1989b535cb41f5ca7ab2af561e40def22d7e188e0a445e7639e3"}, - {file = "coverage-7.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:025ded371f1ca280c035d91b43252adbb04d2aea4c7105252d3cbc227f03b375"}, - {file = "coverage-7.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6191b3a6ad3e09b6cfd75b45c6aeeffe7e3b0ad46b268345d159b8df8d835f9"}, - {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7eb0b188f30e41ddd659a529e385470aa6782f3b412f860ce22b2491c89b8593"}, - {file = "coverage-7.3.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c8f0df9dfd8ff745bccff75867d63ef336e57cc22b2908ee725cc552689ec8"}, - {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eb3cd48d54b9bd0e73026dedce44773214064be93611deab0b6a43158c3d5a0"}, - {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ac3c5b7e75acac31e490b7851595212ed951889918d398b7afa12736c85e13ce"}, - {file = "coverage-7.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b4ee7080878077af0afa7238df1b967f00dc10763f6e1b66f5cced4abebb0a3"}, - {file = "coverage-7.3.1-cp311-cp311-win32.whl", hash = "sha256:229c0dd2ccf956bf5aeede7e3131ca48b65beacde2029f0361b54bf93d36f45a"}, - {file = "coverage-7.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c6f55d38818ca9596dc9019eae19a47410d5322408140d9a0076001a3dcb938c"}, - {file = "coverage-7.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5289490dd1c3bb86de4730a92261ae66ea8d44b79ed3cc26464f4c2cde581fbc"}, - {file = "coverage-7.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca833941ec701fda15414be400c3259479bfde7ae6d806b69e63b3dc423b1832"}, - {file = "coverage-7.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd694e19c031733e446c8024dedd12a00cda87e1c10bd7b8539a87963685e969"}, - {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aab8e9464c00da5cb9c536150b7fbcd8850d376d1151741dd0d16dfe1ba4fd26"}, - {file = "coverage-7.3.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d38444efffd5b056fcc026c1e8d862191881143c3aa80bb11fcf9dca9ae204"}, - {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8a07b692129b8a14ad7a37941a3029c291254feb7a4237f245cfae2de78de037"}, - {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2829c65c8faaf55b868ed7af3c7477b76b1c6ebeee99a28f59a2cb5907a45760"}, - {file = "coverage-7.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f111a7d85658ea52ffad7084088277135ec5f368457275fc57f11cebb15607f"}, - {file = "coverage-7.3.1-cp312-cp312-win32.whl", hash = "sha256:c397c70cd20f6df7d2a52283857af622d5f23300c4ca8e5bd8c7a543825baa5a"}, - {file = "coverage-7.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:5ae4c6da8b3d123500f9525b50bf0168023313963e0e2e814badf9000dd6ef92"}, - {file = "coverage-7.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca70466ca3a17460e8fc9cea7123c8cbef5ada4be3140a1ef8f7b63f2f37108f"}, - {file = "coverage-7.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f2781fd3cabc28278dc982a352f50c81c09a1a500cc2086dc4249853ea96b981"}, - {file = "coverage-7.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6407424621f40205bbe6325686417e5e552f6b2dba3535dd1f90afc88a61d465"}, - {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04312b036580ec505f2b77cbbdfb15137d5efdfade09156961f5277149f5e344"}, - {file = "coverage-7.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9ad38204887349853d7c313f53a7b1c210ce138c73859e925bc4e5d8fc18e7"}, - {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:53669b79f3d599da95a0afbef039ac0fadbb236532feb042c534fbb81b1a4e40"}, - {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:614f1f98b84eb256e4f35e726bfe5ca82349f8dfa576faabf8a49ca09e630086"}, - {file = "coverage-7.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1a317fdf5c122ad642db8a97964733ab7c3cf6009e1a8ae8821089993f175ff"}, - {file = "coverage-7.3.1-cp38-cp38-win32.whl", hash = "sha256:defbbb51121189722420a208957e26e49809feafca6afeef325df66c39c4fdb3"}, - {file = "coverage-7.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:f4f456590eefb6e1b3c9ea6328c1e9fa0f1006e7481179d749b3376fc793478e"}, - {file = "coverage-7.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f12d8b11a54f32688b165fd1a788c408f927b0960984b899be7e4c190ae758f1"}, - {file = "coverage-7.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f09195dda68d94a53123883de75bb97b0e35f5f6f9f3aa5bf6e496da718f0cb6"}, - {file = "coverage-7.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6601a60318f9c3945be6ea0f2a80571f4299b6801716f8a6e4846892737ebe4"}, - {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d156269718670d00a3b06db2288b48527fc5f36859425ff7cec07c6b367745"}, - {file = "coverage-7.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:636a8ac0b044cfeccae76a36f3b18264edcc810a76a49884b96dd744613ec0b7"}, - {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5d991e13ad2ed3aced177f524e4d670f304c8233edad3210e02c465351f785a0"}, - {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:586649ada7cf139445da386ab6f8ef00e6172f11a939fc3b2b7e7c9082052fa0"}, - {file = "coverage-7.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4aba512a15a3e1e4fdbfed2f5392ec221434a614cc68100ca99dcad7af29f3f8"}, - {file = "coverage-7.3.1-cp39-cp39-win32.whl", hash = "sha256:6bc6f3f4692d806831c136c5acad5ccedd0262aa44c087c46b7101c77e139140"}, - {file = "coverage-7.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:553d7094cb27db58ea91332e8b5681bac107e7242c23f7629ab1316ee73c4981"}, - {file = "coverage-7.3.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:220eb51f5fb38dfdb7e5d54284ca4d0cd70ddac047d750111a68ab1798945194"}, - {file = "coverage-7.3.1.tar.gz", hash = "sha256:6cb7fe1581deb67b782c153136541e20901aa312ceedaf1467dcb35255787952"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d872145f3a3231a5f20fd48500274d7df222e291d90baa2026cc5152b7ce86bf"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:310b3bb9c91ea66d59c53fa4989f57d2436e08f18fb2f421a1b0b6b8cc7fffda"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f47d39359e2c3779c5331fc740cf4bce6d9d680a7b4b4ead97056a0ae07cb49a"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa72dbaf2c2068404b9870d93436e6d23addd8bbe9295f49cbca83f6e278179c"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beaa5c1b4777f03fc63dfd2a6bd820f73f036bfb10e925fce067b00a340d0f3f"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dbc1b46b92186cc8074fee9d9fbb97a9dd06c6cbbef391c2f59d80eabdf0faa6"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:315a989e861031334d7bee1f9113c8770472db2ac484e5b8c3173428360a9148"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d1bc430677773397f64a5c88cb522ea43175ff16f8bfcc89d467d974cb2274f9"}, + {file = "coverage-7.3.2-cp310-cp310-win32.whl", hash = "sha256:a889ae02f43aa45032afe364c8ae84ad3c54828c2faa44f3bfcafecb5c96b02f"}, + {file = "coverage-7.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c0ba320de3fb8c6ec16e0be17ee1d3d69adcda99406c43c0409cb5c41788a611"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac8c802fa29843a72d32ec56d0ca792ad15a302b28ca6203389afe21f8fa062c"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89a937174104339e3a3ffcf9f446c00e3a806c28b1841c63edb2b369310fd074"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e267e9e2b574a176ddb983399dec325a80dbe161f1a32715c780b5d14b5f583a"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2443cbda35df0d35dcfb9bf8f3c02c57c1d6111169e3c85fc1fcc05e0c9f39a3"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4175e10cc8dda0265653e8714b3174430b07c1dca8957f4966cbd6c2b1b8065a"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c913b556a116b8d5f6ef834038ba983834d887d82187c8f73dec21049abd65c"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1981f785239e4e39e6444c63a98da3a1db8e971cb9ceb50a945ba6296b43f312"}, + {file = "coverage-7.3.2-cp311-cp311-win32.whl", hash = "sha256:43668cabd5ca8258f5954f27a3aaf78757e6acf13c17604d89648ecc0cc66640"}, + {file = "coverage-7.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10c39c0452bf6e694511c901426d6b5ac005acc0f78ff265dbe36bf81f808a2"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4cbae1051ab791debecc4a5dcc4a1ff45fc27b91b9aee165c8a27514dd160836"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7bba973ebee5e56fe9251300c00f1579652587a9f4a5ed8404b15a0471f216"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6e9589bd04d0461a417562649522575d8752904d35c12907d8c9dfeba588faf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d51ac2a26f71da1b57f2dc81d0e108b6ab177e7d30e774db90675467c847bbdf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:99b89d9f76070237975b315b3d5f4d6956ae354a4c92ac2388a5695516e47c84"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a"}, + {file = "coverage-7.3.2-cp312-cp312-win32.whl", hash = "sha256:289fe43bf45a575e3ab10b26d7b6f2ddb9ee2dba447499f5401cfb5ecb8196bb"}, + {file = "coverage-7.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dbc3ed60e8659bc59b6b304b43ff9c3ed858da2839c78b804973f613d3e92ed"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af3d828d2c1cbae52d34bdbb22fcd94d1ce715d95f1a012354a75e5913f1bda2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630b13e3036e13c7adc480ca42fa7afc2a5d938081d28e20903cf7fd687872e2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9eacf273e885b02a0273bb3a2170f30e2d53a6d53b72dbe02d6701b5296101c"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f17966e861ff97305e0801134e69db33b143bbfb36436efb9cfff6ec7b2fd9"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4275802d16882cf9c8b3d057a0839acb07ee9379fa2749eca54efbce1535b82"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72c0cfa5250f483181e677ebc97133ea1ab3eb68645e494775deb6a7f6f83901"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb536f0dcd14149425996821a168f6e269d7dcd2c273a8bff8201e79f5104e76"}, + {file = "coverage-7.3.2-cp38-cp38-win32.whl", hash = "sha256:307adb8bd3abe389a471e649038a71b4eb13bfd6b7dd9a129fa856f5c695cf92"}, + {file = "coverage-7.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:88ed2c30a49ea81ea3b7f172e0269c182a44c236eb394718f976239892c0a27a"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b631c92dfe601adf8f5ebc7fc13ced6bb6e9609b19d9a8cd59fa47c4186ad1ce"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d3d9df4051c4a7d13036524b66ecf7a7537d14c18a384043f30a303b146164e9"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7363d3b6a1119ef05015959ca24a9afc0ea8a02c687fe7e2d557705375c01f"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f11cc3c967a09d3695d2a6f03fb3e6236622b93be7a4b5dc09166a861be6d25"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3a4006916aa6fee7cd38db3bfc95aa9c54ebb4ffbfc47c677c8bba949ceba0a6"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9028a3871280110d6e1aa2df1afd5ef003bab5fb1ef421d6dc748ae1c8ef2ebc"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f805d62aec8eb92bab5b61c0f07329275b6f41c97d80e847b03eb894f38d083"}, + {file = "coverage-7.3.2-cp39-cp39-win32.whl", hash = "sha256:d1c88ec1a7ff4ebca0219f5b1ef863451d828cccf889c173e1253aa84b1e07ce"}, + {file = "coverage-7.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4767da59464bb593c07afceaddea61b154136300881844768037fd5e859353f"}, + {file = "coverage-7.3.2-pp38.pp39.pp310-none-any.whl", hash = "sha256:ae97af89f0fbf373400970c0a21eef5aa941ffeed90aee43650b81f7d7f47637"}, + {file = "coverage-7.3.2.tar.gz", hash = "sha256:be32ad29341b0170e795ca590e1c07e81fc061cb5b10c74ce7203491484404ef"}, ] [package.dependencies] @@ -538,15 +554,19 @@ toml = ["tomli"] [[package]] name = "cycler" -version = "0.11.0" +version = "0.12.1" description = "Composable style cycles" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, ] +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "decorator" version = "5.1.1" @@ -610,61 +630,65 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "executing" -version = "1.2.0" +version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, - {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, ] [package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] [[package]] name = "filelock" -version = "3.12.4" +version = "3.13.0" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, - {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, + {file = "filelock-3.13.0-py3-none-any.whl", hash = "sha256:a552f4fde758f4eab33191e9548f671970f8b06d436d31388c9aa1e5861a710f"}, + {file = "filelock-3.13.0.tar.gz", hash = "sha256:63c6052c82a1a24c873a549fbd39a26982e8f35a3016da231ead11a5be9dad44"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] -typing = ["typing-extensions (>=4.7.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "fiona" -version = "1.9.4.post1" +version = "1.9.5" description = "Fiona reads and writes spatial data files" optional = false python-versions = ">=3.7" files = [ - {file = "Fiona-1.9.4.post1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:d6483a20037db2209c8e9a0c6f1e552f807d03c8f42ed0c865ab500945a37c4d"}, - {file = "Fiona-1.9.4.post1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dbe158947099a83ad16f9acd3a21f50ff01114c64e2de67805e382e6b6e0083a"}, - {file = "Fiona-1.9.4.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2c7b09eecee3bb074ef8aa518cd6ab30eb663c6fdd0eff3c88d454a9746eaa"}, - {file = "Fiona-1.9.4.post1-cp310-cp310-win_amd64.whl", hash = "sha256:1da8b954f6f222c3c782bc285586ea8dd9d7e55e1bc7861da9cd772bca671660"}, - {file = "Fiona-1.9.4.post1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:c671d8832287cda397621d79c5a635d52e4631f33a8f0e6fdc732a79a93cb96c"}, - {file = "Fiona-1.9.4.post1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b633a2e550e083805c638d2ab8059c283ca112aaea8241e170c012d2ee0aa905"}, - {file = "Fiona-1.9.4.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1faa625d5202b8403471bbc9f9c96b1bf9099cfcb0ee02a80a3641d3d02383e"}, - {file = "Fiona-1.9.4.post1-cp311-cp311-win_amd64.whl", hash = "sha256:39baf11ff0e4318397e2b2197de427b4eebdc49d4a9a7c1366f8a7ed682978a4"}, - {file = "Fiona-1.9.4.post1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d93c993265f6378b23f47708c83bddb3377ca6814a1f0b5a0ae0bee9c8d72cf8"}, - {file = "Fiona-1.9.4.post1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:b0387cae39e27f338fd948b3b50b6e6ce198cc4cec257fc91660849697c69dc3"}, - {file = "Fiona-1.9.4.post1-cp37-cp37m-win_amd64.whl", hash = "sha256:450561d308d3ce7c7e30294822b1de3f4f942033b703ddd4a91a7f7f5f506ca0"}, - {file = "Fiona-1.9.4.post1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71b023ef5248ebfa5524e7a875033f7db3bbfaf634b1b5c1ae36958d1eb82083"}, - {file = "Fiona-1.9.4.post1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:74511d3755695d75cea0f4ff6f5e0c6c5d5be8e0d46dafff124c6a219e99b1eb"}, - {file = "Fiona-1.9.4.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:285f3dd4f96aa0a3955ed469f0543375b20989731b2dddc85124453f11ac62bc"}, - {file = "Fiona-1.9.4.post1-cp38-cp38-win_amd64.whl", hash = "sha256:a670ea4262cb9140445bcfc97cbfd2f508a058be342f4a97e966b8ce7696601f"}, - {file = "Fiona-1.9.4.post1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:ea7c44c15b3a653452b9b3173181490b7afc5f153b0473c145c43c0fbf90448b"}, - {file = "Fiona-1.9.4.post1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7bfb1f49e0e53f6cd7ad64ae809d72646266b37a7b9881205977408b443a8d79"}, - {file = "Fiona-1.9.4.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a585002a6385cc8ab0f66ddf3caf18711f531901906abd011a67a0cc89ab7b0"}, - {file = "Fiona-1.9.4.post1-cp39-cp39-win_amd64.whl", hash = "sha256:f5da66b723a876142937e683431bbaa5c3d81bb2ed3ec98941271bc99b7f8cd0"}, - {file = "Fiona-1.9.4.post1.tar.gz", hash = "sha256:5679d3f7e0d513035eb72e59527bb90486859af4405755dfc739138633106120"}, + {file = "fiona-1.9.5-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:5f40a40529ecfca5294260316cf987a0420c77a2f0cf0849f529d1afbccd093e"}, + {file = "fiona-1.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:374efe749143ecb5cfdd79b585d83917d2bf8ecfbfc6953c819586b336ce9c63"}, + {file = "fiona-1.9.5-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:35dae4b0308eb44617cdc4461ceb91f891d944fdebbcba5479efe524ec5db8de"}, + {file = "fiona-1.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:5b4c6a3df53bee8f85bb46685562b21b43346be1fe96419f18f70fa1ab8c561c"}, + {file = "fiona-1.9.5-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:6ad04c1877b9fd742871b11965606c6a52f40706f56a48d66a87cc3073943828"}, + {file = "fiona-1.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9fb9a24a8046c724787719e20557141b33049466145fc3e665764ac7caf5748c"}, + {file = "fiona-1.9.5-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:d722d7f01a66f4ab6cd08d156df3fdb92f0669cf5f8708ddcb209352f416f241"}, + {file = "fiona-1.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:7ede8ddc798f3d447536080c6db9a5fb73733ad8bdb190cb65eed4e289dd4c50"}, + {file = "fiona-1.9.5-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:8b098054a27c12afac4f819f98cb4d4bf2db9853f70b0c588d7d97d26e128c39"}, + {file = "fiona-1.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d9f29e9bcbb33232ff7fa98b4a3c2234db910c1dc6c4147fc36c0b8b930f2e0"}, + {file = "fiona-1.9.5-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:f1af08da4ecea5036cb81c9131946be4404245d1b434b5b24fd3871a1d4030d9"}, + {file = "fiona-1.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:c521e1135c78dec0d7774303e5a1b4c62e0efb0e602bb8f167550ef95e0a2691"}, + {file = "fiona-1.9.5-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:fce4b1dd98810cabccdaa1828430c7402d283295c2ae31bea4f34188ea9e88d7"}, + {file = "fiona-1.9.5-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:3ea04ec2d8c57b5f81a31200fb352cb3242aa106fc3e328963f30ffbdf0ff7c8"}, + {file = "fiona-1.9.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4877cc745d9e82b12b3eafce3719db75759c27bd8a695521202135b36b58c2e7"}, + {file = "fiona-1.9.5-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:ac2c250f509ec19fad7959d75b531984776517ef3c1222d1cc5b4f962825880b"}, + {file = "fiona-1.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4df21906235928faad856c288cfea0298e9647f09c9a69a230535cbc8eadfa21"}, + {file = "fiona-1.9.5-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:81d502369493687746cb8d3cd77e5ada4447fb71d513721c9a1826e4fb32b23a"}, + {file = "fiona-1.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:ce3b29230ef70947ead4e701f3f82be81082b7f37fd4899009b1445cc8fc276a"}, + {file = "fiona-1.9.5-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:8b53ce8de773fcd5e2e102e833c8c58479edd8796a522f3d83ef9e08b62bfeea"}, + {file = "fiona-1.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd2355e859a1cd24a3e485c6dc5003129f27a2051629def70036535ffa7e16a4"}, + {file = "fiona-1.9.5-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:9a2da52f865db1aff0eaf41cdd4c87a7c079b3996514e8e7a1ca38457309e825"}, + {file = "fiona-1.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:cfef6db5b779d463298b1113b50daa6c5b55f26f834dc9e37752116fa17277c1"}, + {file = "fiona-1.9.5.tar.gz", hash = "sha256:99e2604332caa7692855c2ae6ed91e1fffdf9b59449aa8032dd18e070e59a2f7"}, ] [package.dependencies] @@ -674,6 +698,7 @@ click = ">=8.0,<9.0" click-plugins = ">=1.0" cligj = ">=0.5" importlib-metadata = {version = "*", markers = "python_version < \"3.10\""} +setuptools = "*" six = "*" [package.extras] @@ -684,45 +709,53 @@ test = ["Fiona[s3]", "pytest (>=7)", "pytest-cov", "pytz"] [[package]] name = "fonttools" -version = "4.42.1" +version = "4.43.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"}, - {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"}, - {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"}, - {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"}, - {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"}, - {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"}, - {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"}, - {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"}, - {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"}, - {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"}, - {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"}, - {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"}, - {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"}, - {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"}, - {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"}, - {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"}, - {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"}, - {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"}, - {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"}, - {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"}, - {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"}, - {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"}, - {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"}, - {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"}, - {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"}, - {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"}, - {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"}, - {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"}, - {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"}, - {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"}, - {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"}, - {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"}, - {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"}, - {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"}, + {file = "fonttools-4.43.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf11e2cca121df35e295bd34b309046c29476ee739753bc6bc9d5050de319273"}, + {file = "fonttools-4.43.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10b3922875ffcba636674f406f9ab9a559564fdbaa253d66222019d569db869c"}, + {file = "fonttools-4.43.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f727c3e3d08fd25352ed76cc3cb61486f8ed3f46109edf39e5a60fc9fecf6ca"}, + {file = "fonttools-4.43.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad0b3f6342cfa14be996971ea2b28b125ad681c6277c4cd0fbdb50340220dfb6"}, + {file = "fonttools-4.43.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b7ad05b2beeebafb86aa01982e9768d61c2232f16470f9d0d8e385798e37184"}, + {file = "fonttools-4.43.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c54466f642d2116686268c3e5f35ebb10e49b0d48d41a847f0e171c785f7ac7"}, + {file = "fonttools-4.43.1-cp310-cp310-win32.whl", hash = "sha256:1e09da7e8519e336239fbd375156488a4c4945f11c4c5792ee086dd84f784d02"}, + {file = "fonttools-4.43.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cf9e974f63b1080b1d2686180fc1fbfd3bfcfa3e1128695b5de337eb9075cef"}, + {file = "fonttools-4.43.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5db46659cfe4e321158de74c6f71617e65dc92e54980086823a207f1c1c0e24b"}, + {file = "fonttools-4.43.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1952c89a45caceedf2ab2506d9a95756e12b235c7182a7a0fff4f5e52227204f"}, + {file = "fonttools-4.43.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c36da88422e0270fbc7fd959dc9749d31a958506c1d000e16703c2fce43e3d0"}, + {file = "fonttools-4.43.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bbbf8174501285049e64d174e29f9578495e1b3b16c07c31910d55ad57683d8"}, + {file = "fonttools-4.43.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d4071bd1c183b8d0b368cc9ed3c07a0f6eb1bdfc4941c4c024c49a35429ac7cd"}, + {file = "fonttools-4.43.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d21099b411e2006d3c3e1f9aaf339e12037dbf7bf9337faf0e93ec915991f43b"}, + {file = "fonttools-4.43.1-cp311-cp311-win32.whl", hash = "sha256:b84a1c00f832feb9d0585ca8432fba104c819e42ff685fcce83537e2e7e91204"}, + {file = "fonttools-4.43.1-cp311-cp311-win_amd64.whl", hash = "sha256:9a2f0aa6ca7c9bc1058a9d0b35483d4216e0c1bbe3962bc62ce112749954c7b8"}, + {file = "fonttools-4.43.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4d9740e3783c748521e77d3c397dc0662062c88fd93600a3c2087d3d627cd5e5"}, + {file = "fonttools-4.43.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:884ef38a5a2fd47b0c1291647b15f4e88b9de5338ffa24ee52c77d52b4dfd09c"}, + {file = "fonttools-4.43.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9648518ef687ba818db3fcc5d9aae27a369253ac09a81ed25c3867e8657a0680"}, + {file = "fonttools-4.43.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95e974d70238fc2be5f444fa91f6347191d0e914d5d8ae002c9aa189572cc215"}, + {file = "fonttools-4.43.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:34f713dad41aa21c637b4e04fe507c36b986a40f7179dcc86402237e2d39dcd3"}, + {file = "fonttools-4.43.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:360201d46165fc0753229afe785900bc9596ee6974833124f4e5e9f98d0f592b"}, + {file = "fonttools-4.43.1-cp312-cp312-win32.whl", hash = "sha256:bb6d2f8ef81ea076877d76acfb6f9534a9c5f31dc94ba70ad001267ac3a8e56f"}, + {file = "fonttools-4.43.1-cp312-cp312-win_amd64.whl", hash = "sha256:25d3da8a01442cbc1106490eddb6d31d7dffb38c1edbfabbcc8db371b3386d72"}, + {file = "fonttools-4.43.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8da417431bfc9885a505e86ba706f03f598c85f5a9c54f67d63e84b9948ce590"}, + {file = "fonttools-4.43.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:51669b60ee2a4ad6c7fc17539a43ffffc8ef69fd5dbed186a38a79c0ac1f5db7"}, + {file = "fonttools-4.43.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748015d6f28f704e7d95cd3c808b483c5fb87fd3eefe172a9da54746ad56bfb6"}, + {file = "fonttools-4.43.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a58eb5e736d7cf198eee94844b81c9573102ae5989ebcaa1d1a37acd04b33d"}, + {file = "fonttools-4.43.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6bb5ea9076e0e39defa2c325fc086593ae582088e91c0746bee7a5a197be3da0"}, + {file = "fonttools-4.43.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5f37e31291bf99a63328668bb83b0669f2688f329c4c0d80643acee6e63cd933"}, + {file = "fonttools-4.43.1-cp38-cp38-win32.whl", hash = "sha256:9c60ecfa62839f7184f741d0509b5c039d391c3aff71dc5bc57b87cc305cff3b"}, + {file = "fonttools-4.43.1-cp38-cp38-win_amd64.whl", hash = "sha256:fe9b1ec799b6086460a7480e0f55c447b1aca0a4eecc53e444f639e967348896"}, + {file = "fonttools-4.43.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13a9a185259ed144def3682f74fdcf6596f2294e56fe62dfd2be736674500dba"}, + {file = "fonttools-4.43.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2adca1b46d69dce4a37eecc096fe01a65d81a2f5c13b25ad54d5430ae430b13"}, + {file = "fonttools-4.43.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18eefac1b247049a3a44bcd6e8c8fd8b97f3cad6f728173b5d81dced12d6c477"}, + {file = "fonttools-4.43.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2062542a7565091cea4cc14dd99feff473268b5b8afdee564f7067dd9fff5860"}, + {file = "fonttools-4.43.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18a2477c62a728f4d6e88c45ee9ee0229405e7267d7d79ce1f5ce0f3e9f8ab86"}, + {file = "fonttools-4.43.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a7a06f8d95b7496e53af80d974d63516ffb263a468e614978f3899a6df52d4b3"}, + {file = "fonttools-4.43.1-cp39-cp39-win32.whl", hash = "sha256:10003ebd81fec0192c889e63a9c8c63f88c7d72ae0460b7ba0cd2a1db246e5ad"}, + {file = "fonttools-4.43.1-cp39-cp39-win_amd64.whl", hash = "sha256:e117a92b07407a061cde48158c03587ab97e74e7d73cb65e6aadb17af191162a"}, + {file = "fonttools-4.43.1-py3-none-any.whl", hash = "sha256:4f88cae635bfe4bbbdc29d479a297bb525a94889184bb69fa9560c2d4834ddb9"}, + {file = "fonttools-4.43.1.tar.gz", hash = "sha256:17dbc2eeafb38d5d0e865dcce16e313c58265a6d2d20081c435f84dc5a9d8212"}, ] [package.extras] @@ -776,13 +809,13 @@ shapely = ">=1.8.0" [[package]] name = "identify" -version = "2.5.29" +version = "2.5.31" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.29-py2.py3-none-any.whl", hash = "sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b"}, - {file = "identify-2.5.29.tar.gz", hash = "sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5"}, + {file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"}, + {file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"}, ] [package.extras] @@ -831,21 +864,21 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs [[package]] name = "importlib-resources" -version = "6.0.1" +version = "6.1.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.0.1-py3-none-any.whl", hash = "sha256:134832a506243891221b88b4ae1213327eea96ceb4e407a00d790bb0626f45cf"}, - {file = "importlib_resources-6.0.1.tar.gz", hash = "sha256:4359457e42708462b9626a04657c6208ad799ceb41e5c58c57ffa0e6a098a5d4"}, + {file = "importlib_resources-6.1.0-py3-none-any.whl", hash = "sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83"}, + {file = "importlib_resources-6.1.0.tar.gz", hash = "sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9"}, ] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -860,13 +893,13 @@ files = [ [[package]] name = "ipython" -version = "8.15.0" +version = "8.16.1" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" files = [ - {file = "ipython-8.15.0-py3-none-any.whl", hash = "sha256:45a2c3a529296870a97b7de34eda4a31bee16bc7bf954e07d39abe49caf8f887"}, - {file = "ipython-8.15.0.tar.gz", hash = "sha256:2baeb5be6949eeebf532150f81746f8333e2ccce02de1c7eedde3f23ed5e9f1e"}, + {file = "ipython-8.16.1-py3-none-any.whl", hash = "sha256:0852469d4d579d9cd613c220af7bf0c9cc251813e12be647cb9d463939db9b1e"}, + {file = "ipython-8.16.1.tar.gz", hash = "sha256:ad52f58fca8f9f848e256c629eff888efc0528c12fe0f8ec14f33205f23ef938"}, ] [package.dependencies] @@ -900,13 +933,13 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa [[package]] name = "jedi" -version = "0.19.0" +version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" files = [ - {file = "jedi-0.19.0-py2.py3-none-any.whl", hash = "sha256:cb8ce23fbccff0025e9386b5cf85e892f94c9b822378f8da49970471335ac64e"}, - {file = "jedi-0.19.0.tar.gz", hash = "sha256:bcf9894f1753969cbac8022a8c2eaee06bfa3724e4192470aaffe7eb6272b0c4"}, + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, ] [package.dependencies] @@ -915,7 +948,7 @@ parso = ">=0.8.3,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "jinja2" @@ -1061,51 +1094,6 @@ files = [ [package.dependencies] six = ">=1.4.1" -[[package]] -name = "lazy-object-proxy" -version = "1.9.0" -description = "A fast and thorough lazy object proxy." -optional = false -python-versions = ">=3.7" -files = [ - {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, - {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, - {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, - {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, - {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, - {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, -] - [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1320,6 +1308,24 @@ rtd = ["ipython", "pydata-sphinx-theme (==v0.13.0rc4)", "sphinx-autodoc2 (>=0.4. testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=7,<8)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx-pytest"] testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,<0.4.0)"] +[[package]] +name = "networkx" +version = "3.2.1" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.9" +files = [ + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, +] + +[package.extras] +default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "nodeenv" version = "1.8.0" @@ -1368,15 +1374,56 @@ files = [ {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, ] +[[package]] +name = "numpy" +version = "1.26.1" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"}, + {file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"}, + {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"}, + {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"}, + {file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"}, + {file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"}, + {file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"}, + {file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"}, + {file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"}, + {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"}, + {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"}, + {file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"}, + {file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"}, + {file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"}, + {file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"}, + {file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"}, + {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"}, + {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"}, + {file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"}, + {file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"}, + {file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"}, + {file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"}, + {file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"}, + {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"}, + {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"}, + {file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"}, + {file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"}, + {file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"}, + {file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"}, + {file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"}, + {file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"}, + {file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"}, +] + [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] @@ -1407,10 +1454,75 @@ files = [ {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, ] +[package.dependencies] +numpy = {version = ">=1.23.2", markers = "python_version >= \"3.11\""} +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.1" + +[package.extras] +all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] +aws = ["s3fs (>=2022.05.0)"] +clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] +compression = ["zstandard (>=0.17.0)"] +computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] +feather = ["pyarrow (>=7.0.0)"] +fss = ["fsspec (>=2022.05.0)"] +gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] +hdf5 = ["tables (>=3.7.0)"] +html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] +mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] +parquet = ["pyarrow (>=7.0.0)"] +performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] +plot = ["matplotlib (>=3.6.1)"] +postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] +spss = ["pyreadstat (>=1.1.5)"] +sql-other = ["SQLAlchemy (>=1.4.36)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.8.0)"] + +[[package]] +name = "pandas" +version = "2.1.2" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pandas-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24057459f19db9ebb02984c6fdd164a970b31a95f38e4a49cf7615b36a1b532c"}, + {file = "pandas-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6cf8fcc8a63d333970b950a7331a30544cf59b1a97baf0a7409e09eafc1ac38"}, + {file = "pandas-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ae6ffbd9d614c20d028c7117ee911fc4e266b4dca2065d5c5909e401f8ff683"}, + {file = "pandas-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff794eeb7883c5aefb1ed572e7ff533ae779f6c6277849eab9e77986e352688"}, + {file = "pandas-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02954e285e8e2f4006b6f22be6f0df1f1c3c97adbb7ed211c6b483426f20d5c8"}, + {file = "pandas-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:5b40c9f494e1f27588c369b9e4a6ca19cd924b3a0e1ef9ef1a8e30a07a438f43"}, + {file = "pandas-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:08d287b68fd28906a94564f15118a7ca8c242e50ae7f8bd91130c362b2108a81"}, + {file = "pandas-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bbd98dcdcd32f408947afdb3f7434fade6edd408c3077bbce7bd840d654d92c6"}, + {file = "pandas-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90c95abb3285d06f6e4feedafc134306a8eced93cb78e08cf50e224d5ce22e2"}, + {file = "pandas-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52867d69a54e71666cd184b04e839cff7dfc8ed0cd6b936995117fdae8790b69"}, + {file = "pandas-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d0382645ede2fde352da2a885aac28ec37d38587864c0689b4b2361d17b1d4c"}, + {file = "pandas-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:65177d1c519b55e5b7f094c660ed357bb7d86e799686bb71653b8a4803d8ff0d"}, + {file = "pandas-2.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5aa6b86802e8cf7716bf4b4b5a3c99b12d34e9c6a9d06dad254447a620437931"}, + {file = "pandas-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d594e2ce51b8e0b4074e6644758865dc2bb13fd654450c1eae51201260a539f1"}, + {file = "pandas-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3223f997b6d2ebf9c010260cf3d889848a93f5d22bb4d14cd32638b3d8bba7ad"}, + {file = "pandas-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4944dc004ca6cc701dfa19afb8bdb26ad36b9bed5bcec617d2a11e9cae6902"}, + {file = "pandas-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3f76280ce8ec216dde336e55b2b82e883401cf466da0fe3be317c03fb8ee7c7d"}, + {file = "pandas-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:7ad20d24acf3a0042512b7e8d8fdc2e827126ed519d6bd1ed8e6c14ec8a2c813"}, + {file = "pandas-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:021f09c15e1381e202d95d4a21ece8e7f2bf1388b6d7e9cae09dfe27bd2043d1"}, + {file = "pandas-2.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7f12b2de0060b0b858cfec0016e7d980ae5bae455a1746bfcc70929100ee633"}, + {file = "pandas-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c166b9bb27c1715bed94495d9598a7f02950b4749dba9349c1dd2cbf10729d"}, + {file = "pandas-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25c9976c17311388fcd953cb3d0697999b2205333f4e11e669d90ff8d830d429"}, + {file = "pandas-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:851b5afbb0d62f6129ae891b533aa508cc357d5892c240c91933d945fff15731"}, + {file = "pandas-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:e78507adcc730533619de07bfdd1c62b2918a68cd4419ea386e28abf7f6a1e5c"}, + {file = "pandas-2.1.2.tar.gz", hash = "sha256:52897edc2774d2779fbeb6880d2cfb305daa0b1a29c16b91f531a18918a6e0f3"}, +] + [package.dependencies] numpy = [ - {version = ">=1.22.4", markers = "python_version < \"3.11\""}, - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -1493,65 +1605,65 @@ files = [ [[package]] name = "pillow" -version = "10.0.1" +version = "10.1.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "Pillow-10.0.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:8f06be50669087250f319b706decf69ca71fdecd829091a37cc89398ca4dc17a"}, - {file = "Pillow-10.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50bd5f1ebafe9362ad622072a1d2f5850ecfa44303531ff14353a4059113b12d"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6a90167bcca1216606223a05e2cf991bb25b14695c518bc65639463d7db722d"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f11c9102c56ffb9ca87134bd025a43d2aba3f1155f508eff88f694b33a9c6d19"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:186f7e04248103482ea6354af6d5bcedb62941ee08f7f788a1c7707bc720c66f"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0462b1496505a3462d0f35dc1c4d7b54069747d65d00ef48e736acda2c8cbdff"}, - {file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d889b53ae2f030f756e61a7bff13684dcd77e9af8b10c6048fb2c559d6ed6eaf"}, - {file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:552912dbca585b74d75279a7570dd29fa43b6d93594abb494ebb31ac19ace6bd"}, - {file = "Pillow-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:787bb0169d2385a798888e1122c980c6eff26bf941a8ea79747d35d8f9210ca0"}, - {file = "Pillow-10.0.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fd2a5403a75b54661182b75ec6132437a181209b901446ee5724b589af8edef1"}, - {file = "Pillow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d7e91b4379f7a76b31c2dda84ab9e20c6220488e50f7822e59dac36b0cd92b1"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e9adb3f22d4c416e7cd79b01375b17159d6990003633ff1d8377e21b7f1b21"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93139acd8109edcdeffd85e3af8ae7d88b258b3a1e13a038f542b79b6d255c54"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:92a23b0431941a33242b1f0ce6c88a952e09feeea9af4e8be48236a68ffe2205"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cbe68deb8580462ca0d9eb56a81912f59eb4542e1ef8f987405e35a0179f4ea2"}, - {file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:522ff4ac3aaf839242c6f4e5b406634bfea002469656ae8358644fc6c4856a3b"}, - {file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:84efb46e8d881bb06b35d1d541aa87f574b58e87f781cbba8d200daa835b42e1"}, - {file = "Pillow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:898f1d306298ff40dc1b9ca24824f0488f6f039bc0e25cfb549d3195ffa17088"}, - {file = "Pillow-10.0.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:bcf1207e2f2385a576832af02702de104be71301c2696d0012b1b93fe34aaa5b"}, - {file = "Pillow-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d6c9049c6274c1bb565021367431ad04481ebb54872edecfcd6088d27edd6ed"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28444cb6ad49726127d6b340217f0627abc8732f1194fd5352dec5e6a0105635"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de596695a75496deb3b499c8c4f8e60376e0516e1a774e7bc046f0f48cd620ad"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2872f2d7846cf39b3dbff64bc1104cc48c76145854256451d33c5faa55c04d1a"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4ce90f8a24e1c15465048959f1e94309dfef93af272633e8f37361b824532e91"}, - {file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ee7810cf7c83fa227ba9125de6084e5e8b08c59038a7b2c9045ef4dde61663b4"}, - {file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1be1c872b9b5fcc229adeadbeb51422a9633abd847c0ff87dc4ef9bb184ae08"}, - {file = "Pillow-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:98533fd7fa764e5f85eebe56c8e4094db912ccbe6fbf3a58778d543cadd0db08"}, - {file = "Pillow-10.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:764d2c0daf9c4d40ad12fbc0abd5da3af7f8aa11daf87e4fa1b834000f4b6b0a"}, - {file = "Pillow-10.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fcb59711009b0168d6ee0bd8fb5eb259c4ab1717b2f538bbf36bacf207ef7a68"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:697a06bdcedd473b35e50a7e7506b1d8ceb832dc238a336bd6f4f5aa91a4b500"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f665d1e6474af9f9da5e86c2a3a2d2d6204e04d5af9c06b9d42afa6ebde3f21"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:2fa6dd2661838c66f1a5473f3b49ab610c98a128fc08afbe81b91a1f0bf8c51d"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:3a04359f308ebee571a3127fdb1bd01f88ba6f6fb6d087f8dd2e0d9bff43f2a7"}, - {file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:723bd25051454cea9990203405fa6b74e043ea76d4968166dfd2569b0210886a"}, - {file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:71671503e3015da1b50bd18951e2f9daf5b6ffe36d16f1eb2c45711a301521a7"}, - {file = "Pillow-10.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:44e7e4587392953e5e251190a964675f61e4dae88d1e6edbe9f36d6243547ff3"}, - {file = "Pillow-10.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:3855447d98cced8670aaa63683808df905e956f00348732448b5a6df67ee5849"}, - {file = "Pillow-10.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed2d9c0704f2dc4fa980b99d565c0c9a543fe5101c25b3d60488b8ba80f0cce1"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5bb289bb835f9fe1a1e9300d011eef4d69661bb9b34d5e196e5e82c4cb09b37"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0d3e54ab1df9df51b914b2233cf779a5a10dfd1ce339d0421748232cea9876"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2cc6b86ece42a11f16f55fe8903595eff2b25e0358dec635d0a701ac9586588f"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ca26ba5767888c84bf5a0c1a32f069e8204ce8c21d00a49c90dabeba00ce0145"}, - {file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f0b4b06da13275bc02adfeb82643c4a6385bd08d26f03068c2796f60d125f6f2"}, - {file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bc2e3069569ea9dbe88d6b8ea38f439a6aad8f6e7a6283a38edf61ddefb3a9bf"}, - {file = "Pillow-10.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:8b451d6ead6e3500b6ce5c7916a43d8d8d25ad74b9102a629baccc0808c54971"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:32bec7423cdf25c9038fef614a853c9d25c07590e1a870ed471f47fb80b244db"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cf63d2c6928b51d35dfdbda6f2c1fddbe51a6bc4a9d4ee6ea0e11670dd981e"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f6d3d4c905e26354e8f9d82548475c46d8e0889538cb0657aa9c6f0872a37aa4"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:847e8d1017c741c735d3cd1883fa7b03ded4f825a6e5fcb9378fd813edee995f"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7f771e7219ff04b79e231d099c0a28ed83aa82af91fd5fa9fdb28f5b8d5addaf"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459307cacdd4138edee3875bbe22a2492519e060660eaf378ba3b405d1c66317"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b059ac2c4c7a97daafa7dc850b43b2d3667def858a4f112d1aa082e5c3d6cf7d"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6caf3cd38449ec3cd8a68b375e0c6fe4b6fd04edb6c9766b55ef84a6e8ddf2d"}, - {file = "Pillow-10.0.1.tar.gz", hash = "sha256:d72967b06be9300fed5cfbc8b5bafceec48bf7cdc7dab66b1d2549035287191d"}, + {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, + {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, + {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, + {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, + {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, + {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, + {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, + {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, ] [package.extras] @@ -1584,13 +1696,13 @@ xarray = ["xarray"] [[package]] name = "platformdirs" -version = "3.10.0" +version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, ] [package.extras] @@ -1614,13 +1726,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.4.0" +version = "3.5.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.8" files = [ - {file = "pre_commit-3.4.0-py2.py3-none-any.whl", hash = "sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945"}, - {file = "pre_commit-3.4.0.tar.gz", hash = "sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522"}, + {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, + {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, ] [package.dependencies] @@ -1733,36 +1845,38 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pyproj" -version = "3.6.0" +version = "3.6.1" description = "Python interface to PROJ (cartographic projections and coordinate transformations library)" optional = false python-versions = ">=3.9" files = [ - {file = "pyproj-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e600f6a2771d3b41aeb2cc1efd96771ae9a01451013da1dd48ff272e7c6e34ef"}, - {file = "pyproj-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7f6cd045df29aae960391dfe06a575c110af598f1dea5add8be6ca42332b0f5"}, - {file = "pyproj-3.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:557e6592855111c84eda176ddf6b130f55d5e2b9cb1c017b8c91b69f37f474f5"}, - {file = "pyproj-3.6.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de6288b6ceabdeeac01abf627c74414822d322d8f55dc8efe4d29dedd27c5719"}, - {file = "pyproj-3.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e427ccdbb1763872416549bdfa9fa1f5f169054653c4daf674e71480cc39cf11"}, - {file = "pyproj-3.6.0-cp310-cp310-win32.whl", hash = "sha256:1283d3c1960edbb74828f5f3405b27578a9a27f7766ab6a3956f4bd851f08239"}, - {file = "pyproj-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:9de1aab71234bfd3fd648a1152519b5ee152c43113d7d8ea52590a0140129501"}, - {file = "pyproj-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:00fab048596c17572fa8980014ef117dbb2a445e6f7ba3b9ddfcc683efc598e7"}, - {file = "pyproj-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba5e7c8ddd6ed5a3f9fcf95ea80ba44c931913723de2ece841c94bb38b200c4a"}, - {file = "pyproj-3.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08dfc5c9533c78a97afae9d53b99b810a4a8f97c3be9eb2b8f323b726c736403"}, - {file = "pyproj-3.6.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18a8bdb87aeb41b60a2e91d32f623227de3569fb83b4c64b174c3a7c5b0ed3ae"}, - {file = "pyproj-3.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfe392dfc0eba2248dc08c976a72f52ff9da2bddfddfd9ff5dcf18e8e88200c7"}, - {file = "pyproj-3.6.0-cp311-cp311-win32.whl", hash = "sha256:78276c6b0c831255c97c56dff7313a3571f327a284d8ac63d6a56437a72ed0e0"}, - {file = "pyproj-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:8fbac2eb9a0e425d7d6b7c6f4ebacd675cf3bdef0c59887057b8b4b0374e7c12"}, - {file = "pyproj-3.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:95120d65cbc5983dfd877076f28dbc18b9b329cbee38ca6e217bb7a5a043c099"}, - {file = "pyproj-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:830e6de7cfe43853967afee5ef908dfd5aa72d1ec12af9b9e3fecc179886e346"}, - {file = "pyproj-3.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e342b3010b2b20134671564ff9a8c476e5e512bf589477480aded1a5813af7c8"}, - {file = "pyproj-3.6.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23787460fab85ba2f857ee60ffb2e8e21fd9bd5db9833c51c1c05b2a6d9f0be5"}, - {file = "pyproj-3.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595376e4d3bb72b7dceeccbce0f4c43053d47561f17a1ad0224407e9980ee849"}, - {file = "pyproj-3.6.0-cp39-cp39-win32.whl", hash = "sha256:4d8a9773503085eada59b6892c96ddf686ab8cf64cfdc18ad744d13ee76dfa6f"}, - {file = "pyproj-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:137a07404f937f264b11b7130cd4cfa00002dbe4333b222e8056db84849c2ea4"}, - {file = "pyproj-3.6.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2799499a4045e4fb73e44c31bdacab0593a253a7a4b6baae6fdd27d604cf9bc2"}, - {file = "pyproj-3.6.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f04f6297c615c3b17f835df2556ac8fb9b4f51f281e960437eaf0cd80e7ae26a"}, - {file = "pyproj-3.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a4d2d438b007cb1f8d5f6f308d53d7ff9a2508cff8f9da6e2a93b76ffd98aaf"}, - {file = "pyproj-3.6.0.tar.gz", hash = "sha256:a5b111865b3f0f8b77b3983f2fbe4dd6248fc09d3730295949977c8dcd988062"}, + {file = "pyproj-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab7aa4d9ff3c3acf60d4b285ccec134167a948df02347585fdd934ebad8811b4"}, + {file = "pyproj-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4bc0472302919e59114aa140fd7213c2370d848a7249d09704f10f5b062031fe"}, + {file = "pyproj-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5279586013b8d6582e22b6f9e30c49796966770389a9d5b85e25a4223286cd3f"}, + {file = "pyproj-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fafd1f3eb421694857f254a9bdbacd1eb22fc6c24ca74b136679f376f97d35"}, + {file = "pyproj-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c41e80ddee130450dcb8829af7118f1ab69eaf8169c4bf0ee8d52b72f098dc2f"}, + {file = "pyproj-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:db3aedd458e7f7f21d8176f0a1d924f1ae06d725228302b872885a1c34f3119e"}, + {file = "pyproj-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ebfbdbd0936e178091309f6cd4fcb4decd9eab12aa513cdd9add89efa3ec2882"}, + {file = "pyproj-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:447db19c7efad70ff161e5e46a54ab9cc2399acebb656b6ccf63e4bc4a04b97a"}, + {file = "pyproj-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e13c40183884ec7f94eb8e0f622f08f1d5716150b8d7a134de48c6110fee85"}, + {file = "pyproj-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65ad699e0c830e2b8565afe42bd58cc972b47d829b2e0e48ad9638386d994915"}, + {file = "pyproj-3.6.1-cp311-cp311-win32.whl", hash = "sha256:8b8acc31fb8702c54625f4d5a2a6543557bec3c28a0ef638778b7ab1d1772132"}, + {file = "pyproj-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:38a3361941eb72b82bd9a18f60c78b0df8408416f9340521df442cebfc4306e2"}, + {file = "pyproj-3.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1e9fbaf920f0f9b4ee62aab832be3ae3968f33f24e2e3f7fbb8c6728ef1d9746"}, + {file = "pyproj-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d227a865356f225591b6732430b1d1781e946893789a609bb34f59d09b8b0f8"}, + {file = "pyproj-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83039e5ae04e5afc974f7d25ee0870a80a6bd6b7957c3aca5613ccbe0d3e72bf"}, + {file = "pyproj-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb059ba3bced6f6725961ba758649261d85ed6ce670d3e3b0a26e81cf1aa8d"}, + {file = "pyproj-3.6.1-cp312-cp312-win32.whl", hash = "sha256:2d6ff73cc6dbbce3766b6c0bce70ce070193105d8de17aa2470009463682a8eb"}, + {file = "pyproj-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:7a27151ddad8e1439ba70c9b4b2b617b290c39395fa9ddb7411ebb0eb86d6fb0"}, + {file = "pyproj-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ba1f9b03d04d8cab24d6375609070580a26ce76eaed54631f03bab00a9c737b"}, + {file = "pyproj-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18faa54a3ca475bfe6255156f2f2874e9a1c8917b0004eee9f664b86ccc513d3"}, + {file = "pyproj-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd43bd9a9b9239805f406fd82ba6b106bf4838d9ef37c167d3ed70383943ade1"}, + {file = "pyproj-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50100b2726a3ca946906cbaa789dd0749f213abf0cbb877e6de72ca7aa50e1ae"}, + {file = "pyproj-3.6.1-cp39-cp39-win32.whl", hash = "sha256:9274880263256f6292ff644ca92c46d96aa7e57a75c6df3f11d636ce845a1877"}, + {file = "pyproj-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:36b64c2cb6ea1cc091f329c5bd34f9c01bb5da8c8e4492c709bda6a09f96808f"}, + {file = "pyproj-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd93c1a0c6c4aedc77c0fe275a9f2aba4d59b8acf88cebfc19fe3c430cfabf4f"}, + {file = "pyproj-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6420ea8e7d2a88cb148b124429fba8cd2e0fae700a2d96eab7083c0928a85110"}, + {file = "pyproj-3.6.1.tar.gz", hash = "sha256:44aa7c704c2b7d8fb3d483bbf75af6cb2350d30a63b144279a09b75fead501bf"}, ] [package.dependencies] @@ -1770,13 +1884,13 @@ certifi = "*" [[package]] name = "pytest" -version = "7.4.2" +version = "7.4.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, ] [package.dependencies] @@ -1904,99 +2018,99 @@ files = [ [[package]] name = "regex" -version = "2023.8.8" +version = "2023.10.3" description = "Alternative regular expression module, to replace re." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "regex-2023.8.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:88900f521c645f784260a8d346e12a1590f79e96403971241e64c3a265c8ecdb"}, - {file = "regex-2023.8.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3611576aff55918af2697410ff0293d6071b7e00f4b09e005d614686ac4cd57c"}, - {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8a0ccc8f2698f120e9e5742f4b38dc944c38744d4bdfc427616f3a163dd9de5"}, - {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c662a4cbdd6280ee56f841f14620787215a171c4e2d1744c9528bed8f5816c96"}, - {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf0633e4a1b667bfe0bb10b5e53fe0d5f34a6243ea2530eb342491f1adf4f739"}, - {file = "regex-2023.8.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:551ad543fa19e94943c5b2cebc54c73353ffff08228ee5f3376bd27b3d5b9800"}, - {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54de2619f5ea58474f2ac211ceea6b615af2d7e4306220d4f3fe690c91988a61"}, - {file = "regex-2023.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ec4b3f0aebbbe2fc0134ee30a791af522a92ad9f164858805a77442d7d18570"}, - {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ae646c35cb9f820491760ac62c25b6d6b496757fda2d51be429e0e7b67ae0ab"}, - {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca339088839582d01654e6f83a637a4b8194d0960477b9769d2ff2cfa0fa36d2"}, - {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d9b6627408021452dcd0d2cdf8da0534e19d93d070bfa8b6b4176f99711e7f90"}, - {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:bd3366aceedf274f765a3a4bc95d6cd97b130d1dda524d8f25225d14123c01db"}, - {file = "regex-2023.8.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7aed90a72fc3654fba9bc4b7f851571dcc368120432ad68b226bd593f3f6c0b7"}, - {file = "regex-2023.8.8-cp310-cp310-win32.whl", hash = "sha256:80b80b889cb767cc47f31d2b2f3dec2db8126fbcd0cff31b3925b4dc6609dcdb"}, - {file = "regex-2023.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:b82edc98d107cbc7357da7a5a695901b47d6eb0420e587256ba3ad24b80b7d0b"}, - {file = "regex-2023.8.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1e7d84d64c84ad97bf06f3c8cb5e48941f135ace28f450d86af6b6512f1c9a71"}, - {file = "regex-2023.8.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce0f9fbe7d295f9922c0424a3637b88c6c472b75eafeaff6f910494a1fa719ef"}, - {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06c57e14ac723b04458df5956cfb7e2d9caa6e9d353c0b4c7d5d54fcb1325c46"}, - {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7a9aaa5a1267125eef22cef3b63484c3241aaec6f48949b366d26c7250e0357"}, - {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b7408511fca48a82a119d78a77c2f5eb1b22fe88b0d2450ed0756d194fe7a9a"}, - {file = "regex-2023.8.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14dc6f2d88192a67d708341f3085df6a4f5a0c7b03dec08d763ca2cd86e9f559"}, - {file = "regex-2023.8.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48c640b99213643d141550326f34f0502fedb1798adb3c9eb79650b1ecb2f177"}, - {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0085da0f6c6393428bf0d9c08d8b1874d805bb55e17cb1dfa5ddb7cfb11140bf"}, - {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:964b16dcc10c79a4a2be9f1273fcc2684a9eedb3906439720598029a797b46e6"}, - {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7ce606c14bb195b0e5108544b540e2c5faed6843367e4ab3deb5c6aa5e681208"}, - {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:40f029d73b10fac448c73d6eb33d57b34607f40116e9f6e9f0d32e9229b147d7"}, - {file = "regex-2023.8.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b8e6ea6be6d64104d8e9afc34c151926f8182f84e7ac290a93925c0db004bfd"}, - {file = "regex-2023.8.8-cp311-cp311-win32.whl", hash = "sha256:942f8b1f3b223638b02df7df79140646c03938d488fbfb771824f3d05fc083a8"}, - {file = "regex-2023.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:51d8ea2a3a1a8fe4f67de21b8b93757005213e8ac3917567872f2865185fa7fb"}, - {file = "regex-2023.8.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e951d1a8e9963ea51efd7f150450803e3b95db5939f994ad3d5edac2b6f6e2b4"}, - {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704f63b774218207b8ccc6c47fcef5340741e5d839d11d606f70af93ee78e4d4"}, - {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22283c769a7b01c8ac355d5be0715bf6929b6267619505e289f792b01304d898"}, - {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91129ff1bb0619bc1f4ad19485718cc623a2dc433dff95baadbf89405c7f6b57"}, - {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de35342190deb7b866ad6ba5cbcccb2d22c0487ee0cbb251efef0843d705f0d4"}, - {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b993b6f524d1e274a5062488a43e3f9f8764ee9745ccd8e8193df743dbe5ee61"}, - {file = "regex-2023.8.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3026cbcf11d79095a32d9a13bbc572a458727bd5b1ca332df4a79faecd45281c"}, - {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:293352710172239bf579c90a9864d0df57340b6fd21272345222fb6371bf82b3"}, - {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d909b5a3fff619dc7e48b6b1bedc2f30ec43033ba7af32f936c10839e81b9217"}, - {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:3d370ff652323c5307d9c8e4c62efd1956fb08051b0e9210212bc51168b4ff56"}, - {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:b076da1ed19dc37788f6a934c60adf97bd02c7eea461b73730513921a85d4235"}, - {file = "regex-2023.8.8-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e9941a4ada58f6218694f382e43fdd256e97615db9da135e77359da257a7168b"}, - {file = "regex-2023.8.8-cp36-cp36m-win32.whl", hash = "sha256:a8c65c17aed7e15a0c824cdc63a6b104dfc530f6fa8cb6ac51c437af52b481c7"}, - {file = "regex-2023.8.8-cp36-cp36m-win_amd64.whl", hash = "sha256:aadf28046e77a72f30dcc1ab185639e8de7f4104b8cb5c6dfa5d8ed860e57236"}, - {file = "regex-2023.8.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:423adfa872b4908843ac3e7a30f957f5d5282944b81ca0a3b8a7ccbbfaa06103"}, - {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ae594c66f4a7e1ea67232a0846649a7c94c188d6c071ac0210c3e86a5f92109"}, - {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e51c80c168074faa793685656c38eb7a06cbad7774c8cbc3ea05552d615393d8"}, - {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09b7f4c66aa9d1522b06e31a54f15581c37286237208df1345108fcf4e050c18"}, - {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e73e5243af12d9cd6a9d6a45a43570dbe2e5b1cdfc862f5ae2b031e44dd95a8"}, - {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:941460db8fe3bd613db52f05259c9336f5a47ccae7d7def44cc277184030a116"}, - {file = "regex-2023.8.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f0ccf3e01afeb412a1a9993049cb160d0352dba635bbca7762b2dc722aa5742a"}, - {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2e9216e0d2cdce7dbc9be48cb3eacb962740a09b011a116fd7af8c832ab116ca"}, - {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5cd9cd7170459b9223c5e592ac036e0704bee765706445c353d96f2890e816c8"}, - {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4873ef92e03a4309b3ccd8281454801b291b689f6ad45ef8c3658b6fa761d7ac"}, - {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:239c3c2a339d3b3ddd51c2daef10874410917cd2b998f043c13e2084cb191684"}, - {file = "regex-2023.8.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1005c60ed7037be0d9dea1f9c53cc42f836188227366370867222bda4c3c6bd7"}, - {file = "regex-2023.8.8-cp37-cp37m-win32.whl", hash = "sha256:e6bd1e9b95bc5614a7a9c9c44fde9539cba1c823b43a9f7bc11266446dd568e3"}, - {file = "regex-2023.8.8-cp37-cp37m-win_amd64.whl", hash = "sha256:9a96edd79661e93327cfeac4edec72a4046e14550a1d22aa0dd2e3ca52aec921"}, - {file = "regex-2023.8.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2181c20ef18747d5f4a7ea513e09ea03bdd50884a11ce46066bb90fe4213675"}, - {file = "regex-2023.8.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a2ad5add903eb7cdde2b7c64aaca405f3957ab34f16594d2b78d53b8b1a6a7d6"}, - {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9233ac249b354c54146e392e8a451e465dd2d967fc773690811d3a8c240ac601"}, - {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920974009fb37b20d32afcdf0227a2e707eb83fe418713f7a8b7de038b870d0b"}, - {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2b6c5dfe0929b6c23dde9624483380b170b6e34ed79054ad131b20203a1a63"}, - {file = "regex-2023.8.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96979d753b1dc3b2169003e1854dc67bfc86edf93c01e84757927f810b8c3c93"}, - {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ae54a338191e1356253e7883d9d19f8679b6143703086245fb14d1f20196be9"}, - {file = "regex-2023.8.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2162ae2eb8b079622176a81b65d486ba50b888271302190870b8cc488587d280"}, - {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c884d1a59e69e03b93cf0dfee8794c63d7de0ee8f7ffb76e5f75be8131b6400a"}, - {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf9273e96f3ee2ac89ffcb17627a78f78e7516b08f94dc435844ae72576a276e"}, - {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:83215147121e15d5f3a45d99abeed9cf1fe16869d5c233b08c56cdf75f43a504"}, - {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f7454aa427b8ab9101f3787eb178057c5250478e39b99540cfc2b889c7d0586"}, - {file = "regex-2023.8.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0640913d2c1044d97e30d7c41728195fc37e54d190c5385eacb52115127b882"}, - {file = "regex-2023.8.8-cp38-cp38-win32.whl", hash = "sha256:0c59122ceccb905a941fb23b087b8eafc5290bf983ebcb14d2301febcbe199c7"}, - {file = "regex-2023.8.8-cp38-cp38-win_amd64.whl", hash = "sha256:c12f6f67495ea05c3d542d119d270007090bad5b843f642d418eb601ec0fa7be"}, - {file = "regex-2023.8.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82cd0a69cd28f6cc3789cc6adeb1027f79526b1ab50b1f6062bbc3a0ccb2dbc3"}, - {file = "regex-2023.8.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bb34d1605f96a245fc39790a117ac1bac8de84ab7691637b26ab2c5efb8f228c"}, - {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:987b9ac04d0b38ef4f89fbc035e84a7efad9cdd5f1e29024f9289182c8d99e09"}, - {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dd6082f4e2aec9b6a0927202c85bc1b09dcab113f97265127c1dc20e2e32495"}, - {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7eb95fe8222932c10d4436e7a6f7c99991e3fdd9f36c949eff16a69246dee2dc"}, - {file = "regex-2023.8.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7098c524ba9f20717a56a8d551d2ed491ea89cbf37e540759ed3b776a4f8d6eb"}, - {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b694430b3f00eb02c594ff5a16db30e054c1b9589a043fe9174584c6efa8033"}, - {file = "regex-2023.8.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2aeab3895d778155054abea5238d0eb9a72e9242bd4b43f42fd911ef9a13470"}, - {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:988631b9d78b546e284478c2ec15c8a85960e262e247b35ca5eaf7ee22f6050a"}, - {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:67ecd894e56a0c6108ec5ab1d8fa8418ec0cff45844a855966b875d1039a2e34"}, - {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:14898830f0a0eb67cae2bbbc787c1a7d6e34ecc06fbd39d3af5fe29a4468e2c9"}, - {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f2200e00b62568cfd920127782c61bc1c546062a879cdc741cfcc6976668dfcf"}, - {file = "regex-2023.8.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9691a549c19c22d26a4f3b948071e93517bdf86e41b81d8c6ac8a964bb71e5a6"}, - {file = "regex-2023.8.8-cp39-cp39-win32.whl", hash = "sha256:6ab2ed84bf0137927846b37e882745a827458689eb969028af8032b1b3dac78e"}, - {file = "regex-2023.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5543c055d8ec7801901e1193a51570643d6a6ab8751b1f7dd9af71af467538bb"}, - {file = "regex-2023.8.8.tar.gz", hash = "sha256:fcbdc5f2b0f1cd0f6a56cdb46fe41d2cce1e644e3b68832f3eeebc5fb0f7712e"}, + {file = "regex-2023.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4c34d4f73ea738223a094d8e0ffd6d2c1a1b4c175da34d6b0de3d8d69bee6bcc"}, + {file = "regex-2023.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8f4e49fc3ce020f65411432183e6775f24e02dff617281094ba6ab079ef0915"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cd1bccf99d3ef1ab6ba835308ad85be040e6a11b0977ef7ea8c8005f01a3c29"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81dce2ddc9f6e8f543d94b05d56e70d03a0774d32f6cca53e978dc01e4fc75b8"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c6b4d23c04831e3ab61717a707a5d763b300213db49ca680edf8bf13ab5d91b"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c15ad0aee158a15e17e0495e1e18741573d04eb6da06d8b84af726cfc1ed02ee"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6239d4e2e0b52c8bd38c51b760cd870069f0bdf99700a62cd509d7a031749a55"}, + {file = "regex-2023.10.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4a8bf76e3182797c6b1afa5b822d1d5802ff30284abe4599e1247be4fd6b03be"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9c727bbcf0065cbb20f39d2b4f932f8fa1631c3e01fcedc979bd4f51fe051c5"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3ccf2716add72f80714b9a63899b67fa711b654be3fcdd34fa391d2d274ce767"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:107ac60d1bfdc3edb53be75e2a52aff7481b92817cfdddd9b4519ccf0e54a6ff"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:00ba3c9818e33f1fa974693fb55d24cdc8ebafcb2e4207680669d8f8d7cca79a"}, + {file = "regex-2023.10.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f0a47efb1dbef13af9c9a54a94a0b814902e547b7f21acb29434504d18f36e3a"}, + {file = "regex-2023.10.3-cp310-cp310-win32.whl", hash = "sha256:36362386b813fa6c9146da6149a001b7bd063dabc4d49522a1f7aa65b725c7ec"}, + {file = "regex-2023.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:c65a3b5330b54103e7d21cac3f6bf3900d46f6d50138d73343d9e5b2900b2353"}, + {file = "regex-2023.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90a79bce019c442604662d17bf69df99090e24cdc6ad95b18b6725c2988a490e"}, + {file = "regex-2023.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c7964c2183c3e6cce3f497e3a9f49d182e969f2dc3aeeadfa18945ff7bdd7051"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef80829117a8061f974b2fda8ec799717242353bff55f8a29411794d635d964"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5addc9d0209a9afca5fc070f93b726bf7003bd63a427f65ef797a931782e7edc"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c148bec483cc4b421562b4bcedb8e28a3b84fcc8f0aa4418e10898f3c2c0eb9b"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d1f21af4c1539051049796a0f50aa342f9a27cde57318f2fc41ed50b0dbc4ac"}, + {file = "regex-2023.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b9ac09853b2a3e0d0082104036579809679e7715671cfbf89d83c1cb2a30f58"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ebedc192abbc7fd13c5ee800e83a6df252bec691eb2c4bedc9f8b2e2903f5e2a"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d8a993c0a0ffd5f2d3bda23d0cd75e7086736f8f8268de8a82fbc4bd0ac6791e"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:be6b7b8d42d3090b6c80793524fa66c57ad7ee3fe9722b258aec6d0672543fd0"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4023e2efc35a30e66e938de5aef42b520c20e7eda7bb5fb12c35e5d09a4c43f6"}, + {file = "regex-2023.10.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d47840dc05e0ba04fe2e26f15126de7c755496d5a8aae4a08bda4dd8d646c54"}, + {file = "regex-2023.10.3-cp311-cp311-win32.whl", hash = "sha256:9145f092b5d1977ec8c0ab46e7b3381b2fd069957b9862a43bd383e5c01d18c2"}, + {file = "regex-2023.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:b6104f9a46bd8743e4f738afef69b153c4b8b592d35ae46db07fc28ae3d5fb7c"}, + {file = "regex-2023.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff507ae210371d4b1fe316d03433ac099f184d570a1a611e541923f78f05037"}, + {file = "regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be5e22bbb67924dea15039c3282fa4cc6cdfbe0cbbd1c0515f9223186fc2ec5f"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a992f702c9be9c72fa46f01ca6e18d131906a7180950958f766c2aa294d4b41"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7434a61b158be563c1362d9071358f8ab91b8d928728cd2882af060481244c9e"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2169b2dcabf4e608416f7f9468737583ce5f0a6e8677c4efbf795ce81109d7c"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9e908ef5889cda4de038892b9accc36d33d72fb3e12c747e2799a0e806ec841"}, + {file = "regex-2023.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12bd4bc2c632742c7ce20db48e0d99afdc05e03f0b4c1af90542e05b809a03d9"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bc72c231f5449d86d6c7d9cc7cd819b6eb30134bb770b8cfdc0765e48ef9c420"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bce8814b076f0ce5766dc87d5a056b0e9437b8e0cd351b9a6c4e1134a7dfbda9"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:ba7cd6dc4d585ea544c1412019921570ebd8a597fabf475acc4528210d7c4a6f"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b0c7d2f698e83f15228ba41c135501cfe7d5740181d5903e250e47f617eb4292"}, + {file = "regex-2023.10.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5a8f91c64f390ecee09ff793319f30a0f32492e99f5dc1c72bc361f23ccd0a9a"}, + {file = "regex-2023.10.3-cp312-cp312-win32.whl", hash = "sha256:ad08a69728ff3c79866d729b095872afe1e0557251da4abb2c5faff15a91d19a"}, + {file = "regex-2023.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:39cdf8d141d6d44e8d5a12a8569d5a227f645c87df4f92179bd06e2e2705e76b"}, + {file = "regex-2023.10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4a3ee019a9befe84fa3e917a2dd378807e423d013377a884c1970a3c2792d293"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76066d7ff61ba6bf3cb5efe2428fc82aac91802844c022d849a1f0f53820502d"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe50b61bab1b1ec260fa7cd91106fa9fece57e6beba05630afe27c71259c59b"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fd88f373cb71e6b59b7fa597e47e518282455c2734fd4306a05ca219a1991b0"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ab05a182c7937fb374f7e946f04fb23a0c0699c0450e9fb02ef567412d2fa3"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dac37cf08fcf2094159922edc7a2784cfcc5c70f8354469f79ed085f0328ebdf"}, + {file = "regex-2023.10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e54ddd0bb8fb626aa1f9ba7b36629564544954fff9669b15da3610c22b9a0991"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3367007ad1951fde612bf65b0dffc8fd681a4ab98ac86957d16491400d661302"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:16f8740eb6dbacc7113e3097b0a36065a02e37b47c936b551805d40340fb9971"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f4f2ca6df64cbdd27f27b34f35adb640b5d2d77264228554e68deda54456eb11"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:39807cbcbe406efca2a233884e169d056c35aa7e9f343d4e78665246a332f597"}, + {file = "regex-2023.10.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7eece6fbd3eae4a92d7c748ae825cbc1ee41a89bb1c3db05b5578ed3cfcfd7cb"}, + {file = "regex-2023.10.3-cp37-cp37m-win32.whl", hash = "sha256:ce615c92d90df8373d9e13acddd154152645c0dc060871abf6bd43809673d20a"}, + {file = "regex-2023.10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f649fa32fe734c4abdfd4edbb8381c74abf5f34bc0b3271ce687b23729299ed"}, + {file = "regex-2023.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b98b7681a9437262947f41c7fac567c7e1f6eddd94b0483596d320092004533"}, + {file = "regex-2023.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:91dc1d531f80c862441d7b66c4505cd6ea9d312f01fb2f4654f40c6fdf5cc37a"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82fcc1f1cc3ff1ab8a57ba619b149b907072e750815c5ba63e7aa2e1163384a4"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7979b834ec7a33aafae34a90aad9f914c41fd6eaa8474e66953f3f6f7cbd4368"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef71561f82a89af6cfcbee47f0fabfdb6e63788a9258e913955d89fdd96902ab"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd829712de97753367153ed84f2de752b86cd1f7a88b55a3a775eb52eafe8a94"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00e871d83a45eee2f8688d7e6849609c2ca2a04a6d48fba3dff4deef35d14f07"}, + {file = "regex-2023.10.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:706e7b739fdd17cb89e1fbf712d9dc21311fc2333f6d435eac2d4ee81985098c"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cc3f1c053b73f20c7ad88b0d1d23be7e7b3901229ce89f5000a8399746a6e039"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f85739e80d13644b981a88f529d79c5bdf646b460ba190bffcaf6d57b2a9863"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:741ba2f511cc9626b7561a440f87d658aabb3d6b744a86a3c025f866b4d19e7f"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e77c90ab5997e85901da85131fd36acd0ed2221368199b65f0d11bca44549711"}, + {file = "regex-2023.10.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:979c24cbefaf2420c4e377ecd1f165ea08cc3d1fbb44bdc51bccbbf7c66a2cb4"}, + {file = "regex-2023.10.3-cp38-cp38-win32.whl", hash = "sha256:58837f9d221744d4c92d2cf7201c6acd19623b50c643b56992cbd2b745485d3d"}, + {file = "regex-2023.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:c55853684fe08d4897c37dfc5faeff70607a5f1806c8be148f1695be4a63414b"}, + {file = "regex-2023.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2c54e23836650bdf2c18222c87f6f840d4943944146ca479858404fedeb9f9af"}, + {file = "regex-2023.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69c0771ca5653c7d4b65203cbfc5e66db9375f1078689459fe196fe08b7b4930"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ac965a998e1388e6ff2e9781f499ad1eaa41e962a40d11c7823c9952c77123e"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c0e8fae5b27caa34177bdfa5a960c46ff2f78ee2d45c6db15ae3f64ecadde14"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c56c3d47da04f921b73ff9415fbaa939f684d47293f071aa9cbb13c94afc17d"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ef1e014eed78ab650bef9a6a9cbe50b052c0aebe553fb2881e0453717573f52"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d29338556a59423d9ff7b6eb0cb89ead2b0875e08fe522f3e068b955c3e7b59b"}, + {file = "regex-2023.10.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9c6d0ced3c06d0f183b73d3c5920727268d2201aa0fe6d55c60d68c792ff3588"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:994645a46c6a740ee8ce8df7911d4aee458d9b1bc5639bc968226763d07f00fa"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:66e2fe786ef28da2b28e222c89502b2af984858091675044d93cb50e6f46d7af"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:11175910f62b2b8c055f2b089e0fedd694fe2be3941b3e2633653bc51064c528"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:06e9abc0e4c9ab4779c74ad99c3fc10d3967d03114449acc2c2762ad4472b8ca"}, + {file = "regex-2023.10.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fb02e4257376ae25c6dd95a5aec377f9b18c09be6ebdefa7ad209b9137b73d48"}, + {file = "regex-2023.10.3-cp39-cp39-win32.whl", hash = "sha256:3b2c3502603fab52d7619b882c25a6850b766ebd1b18de3df23b2f939360e1bd"}, + {file = "regex-2023.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:adbccd17dcaff65704c856bd29951c58a1bd4b2b0f8ad6b826dbd543fe740988"}, + {file = "regex-2023.10.3.tar.gz", hash = "sha256:3fef4f844d2290ee0ba57addcec17eec9e3df73f10a2748485dfd6a3a188cc0f"}, ] [[package]] @@ -2041,13 +2155,13 @@ test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "tes [[package]] name = "rich" -version = "13.5.3" +version = "13.6.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.5.3-py3-none-any.whl", hash = "sha256:9257b468badc3d347e146a4faa268ff229039d4c2d176ab0cffb4c4fbc73d5d9"}, - {file = "rich-13.5.3.tar.gz", hash = "sha256:87b43e0543149efa1253f485cd845bb7ee54df16c9617b8a893650ab84b4acb6"}, + {file = "rich-13.6.0-py3-none-any.whl", hash = "sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245"}, + {file = "rich-13.6.0.tar.gz", hash = "sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef"}, ] [package.dependencies] @@ -2059,28 +2173,28 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.0.290" +version = "0.1.3" description = "An extremely fast Python linter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.0.290-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:0e2b09ac4213b11a3520221083866a5816616f3ae9da123037b8ab275066fbac"}, - {file = "ruff-0.0.290-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:4ca6285aa77b3d966be32c9a3cd531655b3d4a0171e1f9bf26d66d0372186767"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35e3550d1d9f2157b0fcc77670f7bb59154f223bff281766e61bdd1dd854e0c5"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d748c8bd97874f5751aed73e8dde379ce32d16338123d07c18b25c9a2796574a"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:982af5ec67cecd099e2ef5e238650407fb40d56304910102d054c109f390bf3c"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bbd37352cea4ee007c48a44c9bc45a21f7ba70a57edfe46842e346651e2b995a"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d9be6351b7889462912e0b8185a260c0219c35dfd920fb490c7f256f1d8313e"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75cdc7fe32dcf33b7cec306707552dda54632ac29402775b9e212a3c16aad5e6"}, - {file = "ruff-0.0.290-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb07f37f7aecdbbc91d759c0c09870ce0fb3eed4025eebedf9c4b98c69abd527"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2ab41bc0ba359d3f715fc7b705bdeef19c0461351306b70a4e247f836b9350ed"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:150bf8050214cea5b990945b66433bf9a5e0cef395c9bc0f50569e7de7540c86"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_i686.whl", hash = "sha256:75386ebc15fe5467248c039f5bf6a0cfe7bfc619ffbb8cd62406cd8811815fca"}, - {file = "ruff-0.0.290-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ac93eadf07bc4ab4c48d8bb4e427bf0f58f3a9c578862eb85d99d704669f5da0"}, - {file = "ruff-0.0.290-py3-none-win32.whl", hash = "sha256:461fbd1fb9ca806d4e3d5c745a30e185f7cf3ca77293cdc17abb2f2a990ad3f7"}, - {file = "ruff-0.0.290-py3-none-win_amd64.whl", hash = "sha256:f1f49f5ec967fd5778813780b12a5650ab0ebcb9ddcca28d642c689b36920796"}, - {file = "ruff-0.0.290-py3-none-win_arm64.whl", hash = "sha256:ae5a92dfbdf1f0c689433c223f8dac0782c2b2584bd502dfdbc76475669f1ba1"}, - {file = "ruff-0.0.290.tar.gz", hash = "sha256:949fecbc5467bb11b8db810a7fa53c7e02633856ee6bd1302b2f43adcd71b88d"}, + {file = "ruff-0.1.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b46d43d51f7061652eeadb426a9e3caa1e0002470229ab2fc19de8a7b0766901"}, + {file = "ruff-0.1.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b8afeb9abd26b4029c72adc9921b8363374f4e7edb78385ffaa80278313a15f9"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca3cf365bf32e9ba7e6db3f48a4d3e2c446cd19ebee04f05338bc3910114528b"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4874c165f96c14a00590dcc727a04dca0cfd110334c24b039458c06cf78a672e"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec2dd31eed114e48ea42dbffc443e9b7221976554a504767ceaee3dd38edeb8"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dc3ec4edb3b73f21b4aa51337e16674c752f1d76a4a543af56d7d04e97769613"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e3de9ed2e39160800281848ff4670e1698037ca039bda7b9274f849258d26ce"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c595193881922cc0556a90f3af99b1c5681f0c552e7a2a189956141d8666fe8"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f75e670d529aa2288cd00fc0e9b9287603d95e1536d7a7e0cafe00f75e0dd9d"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:76dd49f6cd945d82d9d4a9a6622c54a994689d8d7b22fa1322983389b4892e20"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:918b454bc4f8874a616f0d725590277c42949431ceb303950e87fef7a7d94cb3"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8859605e729cd5e53aa38275568dbbdb4fe882d2ea2714c5453b678dca83784"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0b6c55f5ef8d9dd05b230bb6ab80bc4381ecb60ae56db0330f660ea240cb0d4a"}, + {file = "ruff-0.1.3-py3-none-win32.whl", hash = "sha256:3e7afcbdcfbe3399c34e0f6370c30f6e529193c731b885316c5a09c9e4317eef"}, + {file = "ruff-0.1.3-py3-none-win_amd64.whl", hash = "sha256:7a18df6638cec4a5bd75350639b2bb2a2366e01222825562c7346674bdceb7ea"}, + {file = "ruff-0.1.3-py3-none-win_arm64.whl", hash = "sha256:12fd53696c83a194a2db7f9a46337ce06445fb9aa7d25ea6f293cf75b21aca9f"}, + {file = "ruff-0.1.3.tar.gz", hash = "sha256:3ba6145369a151401d5db79f0a47d50e470384d0d89d0d6f7fab0b589ad07c34"}, ] [[package]] @@ -2101,70 +2215,74 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar [[package]] name = "setuptools-scm" -version = "7.1.0" +version = "8.0.4" description = "the blessed package to manage your versions by scm tags" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools_scm-7.1.0-py3-none-any.whl", hash = "sha256:73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e"}, - {file = "setuptools_scm-7.1.0.tar.gz", hash = "sha256:6c508345a771aad7d56ebff0e70628bf2b0ec7573762be9960214730de278f27"}, + {file = "setuptools-scm-8.0.4.tar.gz", hash = "sha256:b5f43ff6800669595193fd09891564ee9d1d7dcb196cab4b2506d53a2e1c95c7"}, + {file = "setuptools_scm-8.0.4-py3-none-any.whl", hash = "sha256:b47844cd2a84b83b3187a5782c71128c28b4c94cad8bfb871da2784a5cb54c4f"}, ] [package.dependencies] -packaging = ">=20.0" +packaging = ">=20" setuptools = "*" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +tomli = {version = ">=1", markers = "python_version < \"3.11\""} typing-extensions = "*" [package.extras] -test = ["pytest (>=6.2)", "virtualenv (>20)"] -toml = ["setuptools (>=42)"] +docs = ["entangled-cli[rich]", "mkdocs", "mkdocs-entangled-plugin", "mkdocs-material", "mkdocstrings[python]", "pygments"] +rich = ["rich"] +test = ["build", "pytest", "rich", "wheel"] [[package]] name = "shapely" -version = "2.0.1" +version = "2.0.2" description = "Manipulation and analysis of geometric objects" optional = false python-versions = ">=3.7" files = [ - {file = "shapely-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b06d031bc64149e340448fea25eee01360a58936c89985cf584134171e05863f"}, - {file = "shapely-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9a6ac34c16f4d5d3c174c76c9d7614ec8fe735f8f82b6cc97a46b54f386a86bf"}, - {file = "shapely-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:865bc3d7cc0ea63189d11a0b1120d1307ed7a64720a8bfa5be2fde5fc6d0d33f"}, - {file = "shapely-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45b4833235b90bc87ee26c6537438fa77559d994d2d3be5190dd2e54d31b2820"}, - {file = "shapely-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce88ec79df55430e37178a191ad8df45cae90b0f6972d46d867bf6ebbb58cc4d"}, - {file = "shapely-2.0.1-cp310-cp310-win32.whl", hash = "sha256:01224899ff692a62929ef1a3f5fe389043e262698a708ab7569f43a99a48ae82"}, - {file = "shapely-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:da71de5bf552d83dcc21b78cc0020e86f8d0feea43e202110973987ffa781c21"}, - {file = "shapely-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:502e0a607f1dcc6dee0125aeee886379be5242c854500ea5fd2e7ac076b9ce6d"}, - {file = "shapely-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d3bbeefd8a6a1a1017265d2d36f8ff2d79d0162d8c141aa0d37a87063525656"}, - {file = "shapely-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f470a130d6ddb05b810fc1776d918659407f8d025b7f56d2742a596b6dffa6c7"}, - {file = "shapely-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4641325e065fd3e07d55677849c9ddfd0cf3ee98f96475126942e746d55b17c8"}, - {file = "shapely-2.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90cfa4144ff189a3c3de62e2f3669283c98fb760cfa2e82ff70df40f11cadb39"}, - {file = "shapely-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70a18fc7d6418e5aea76ac55dce33f98e75bd413c6eb39cfed6a1ba36469d7d4"}, - {file = "shapely-2.0.1-cp311-cp311-win32.whl", hash = "sha256:09d6c7763b1bee0d0a2b84bb32a4c25c6359ad1ac582a62d8b211e89de986154"}, - {file = "shapely-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:d8f55f355be7821dade839df785a49dc9f16d1af363134d07eb11e9207e0b189"}, - {file = "shapely-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:83a8ec0ee0192b6e3feee9f6a499d1377e9c295af74d7f81ecba5a42a6b195b7"}, - {file = "shapely-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a529218e72a3dbdc83676198e610485fdfa31178f4be5b519a8ae12ea688db14"}, - {file = "shapely-2.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91575d97fd67391b85686573d758896ed2fc7476321c9d2e2b0c398b628b961c"}, - {file = "shapely-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8b0d834b11be97d5ab2b4dceada20ae8e07bcccbc0f55d71df6729965f406ad"}, - {file = "shapely-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:b4f0711cc83734c6fad94fc8d4ec30f3d52c1787b17d9dca261dc841d4731c64"}, - {file = "shapely-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:05c51a29336e604c084fb43ae5dbbfa2c0ef9bd6fedeae0a0d02c7b57a56ba46"}, - {file = "shapely-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b519cf3726ddb6c67f6a951d1bb1d29691111eaa67ea19ddca4d454fbe35949c"}, - {file = "shapely-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:193a398d81c97a62fc3634a1a33798a58fd1dcf4aead254d080b273efbb7e3ff"}, - {file = "shapely-2.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e55698e0ed95a70fe9ff9a23c763acfe0bf335b02df12142f74e4543095e9a9b"}, - {file = "shapely-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f32a748703e7bf6e92dfa3d2936b2fbfe76f8ce5f756e24f49ef72d17d26ad02"}, - {file = "shapely-2.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a34a23d6266ca162499e4a22b79159dc0052f4973d16f16f990baa4d29e58b6"}, - {file = "shapely-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d173d24e85e51510e658fb108513d5bc11e3fd2820db6b1bd0522266ddd11f51"}, - {file = "shapely-2.0.1-cp38-cp38-win32.whl", hash = "sha256:3cb256ae0c01b17f7bc68ee2ffdd45aebf42af8992484ea55c29a6151abe4386"}, - {file = "shapely-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:c7eed1fb3008a8a4a56425334b7eb82651a51f9e9a9c2f72844a2fb394f38a6c"}, - {file = "shapely-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ac1dfc397475d1de485e76de0c3c91cc9d79bd39012a84bb0f5e8a199fc17bef"}, - {file = "shapely-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33403b8896e1d98aaa3a52110d828b18985d740cc9f34f198922018b1e0f8afe"}, - {file = "shapely-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2569a4b91caeef54dd5ae9091ae6f63526d8ca0b376b5bb9fd1a3195d047d7d4"}, - {file = "shapely-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a70a614791ff65f5e283feed747e1cc3d9e6c6ba91556e640636bbb0a1e32a71"}, - {file = "shapely-2.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c43755d2c46b75a7b74ac6226d2cc9fa2a76c3263c5ae70c195c6fb4e7b08e79"}, - {file = "shapely-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad81f292fffbd568ae71828e6c387da7eb5384a79db9b4fde14dd9fdeffca9a"}, - {file = "shapely-2.0.1-cp39-cp39-win32.whl", hash = "sha256:b50c401b64883e61556a90b89948297f1714dbac29243d17ed9284a47e6dd731"}, - {file = "shapely-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:bca57b683e3d94d0919e2f31e4d70fdfbb7059650ef1b431d9f4e045690edcd5"}, - {file = "shapely-2.0.1.tar.gz", hash = "sha256:66a6b1a3e72ece97fc85536a281476f9b7794de2e646ca8a4517e2e3c1446893"}, + {file = "shapely-2.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6ca8cffbe84ddde8f52b297b53f8e0687bd31141abb2c373fd8a9f032df415d6"}, + {file = "shapely-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:baa14fc27771e180c06b499a0a7ba697c7988c7b2b6cba9a929a19a4d2762de3"}, + {file = "shapely-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36480e32c434d168cdf2f5e9862c84aaf4d714a43a8465ae3ce8ff327f0affb7"}, + {file = "shapely-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef753200cbffd4f652efb2c528c5474e5a14341a473994d90ad0606522a46a2"}, + {file = "shapely-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9a41ff4323fc9d6257759c26eb1cf3a61ebc7e611e024e6091f42977303fd3a"}, + {file = "shapely-2.0.2-cp310-cp310-win32.whl", hash = "sha256:72b5997272ae8c25f0fd5b3b967b3237e87fab7978b8d6cd5fa748770f0c5d68"}, + {file = "shapely-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:34eac2337cbd67650248761b140d2535855d21b969d76d76123317882d3a0c1a"}, + {file = "shapely-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b0c052709c8a257c93b0d4943b0b7a3035f87e2d6a8ac9407b6a992d206422f"}, + {file = "shapely-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d217e56ae067e87b4e1731d0dc62eebe887ced729ba5c2d4590e9e3e9fdbd88"}, + {file = "shapely-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94ac128ae2ab4edd0bffcd4e566411ea7bdc738aeaf92c32a8a836abad725f9f"}, + {file = "shapely-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa3ee28f5e63a130ec5af4dc3c4cb9c21c5788bb13c15e89190d163b14f9fb89"}, + {file = "shapely-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:737dba15011e5a9b54a8302f1748b62daa207c9bc06f820cd0ad32a041f1c6f2"}, + {file = "shapely-2.0.2-cp311-cp311-win32.whl", hash = "sha256:45ac6906cff0765455a7b49c1670af6e230c419507c13e2f75db638c8fc6f3bd"}, + {file = "shapely-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:dc9342fc82e374130db86a955c3c4525bfbf315a248af8277a913f30911bed9e"}, + {file = "shapely-2.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:06f193091a7c6112fc08dfd195a1e3846a64306f890b151fa8c63b3e3624202c"}, + {file = "shapely-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eebe544df5c018134f3c23b6515877f7e4cd72851f88a8d0c18464f414d141a2"}, + {file = "shapely-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7e92e7c255f89f5cdf777690313311f422aa8ada9a3205b187113274e0135cd8"}, + {file = "shapely-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be46d5509b9251dd9087768eaf35a71360de6afac82ce87c636990a0871aa18b"}, + {file = "shapely-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5533a925d8e211d07636ffc2fdd9a7f9f13d54686d00577eeb11d16f00be9c4"}, + {file = "shapely-2.0.2-cp312-cp312-win32.whl", hash = "sha256:084b023dae8ad3d5b98acee9d3bf098fdf688eb0bb9b1401e8b075f6a627b611"}, + {file = "shapely-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:ea84d1cdbcf31e619d672b53c4532f06253894185ee7acb8ceb78f5f33cbe033"}, + {file = "shapely-2.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ed1e99702125e7baccf401830a3b94d810d5c70b329b765fe93451fe14cf565b"}, + {file = "shapely-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7d897e6bdc6bc64f7f65155dbbb30e49acaabbd0d9266b9b4041f87d6e52b3a"}, + {file = "shapely-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0521d76d1e8af01e712db71da9096b484f081e539d4f4a8c97342e7971d5e1b4"}, + {file = "shapely-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:5324be299d4c533ecfcfd43424dfd12f9428fd6f12cda38a4316da001d6ef0ea"}, + {file = "shapely-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:78128357a0cee573257a0c2c388d4b7bf13cb7dbe5b3fe5d26d45ebbe2a39e25"}, + {file = "shapely-2.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87dc2be34ac3a3a4a319b963c507ac06682978a5e6c93d71917618b14f13066e"}, + {file = "shapely-2.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:42997ac806e4583dad51c80a32d38570fd9a3d4778f5e2c98f9090aa7db0fe91"}, + {file = "shapely-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ccfd5fa10a37e67dbafc601c1ddbcbbfef70d34c3f6b0efc866ddbdb55893a6c"}, + {file = "shapely-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7c95d3379ae3abb74058938a9fcbc478c6b2e28d20dace38f8b5c587dde90aa"}, + {file = "shapely-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a21353d28209fb0d8cc083e08ca53c52666e0d8a1f9bbe23b6063967d89ed24"}, + {file = "shapely-2.0.2-cp38-cp38-win32.whl", hash = "sha256:03e63a99dfe6bd3beb8d5f41ec2086585bb969991d603f9aeac335ad396a06d4"}, + {file = "shapely-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:c6fd29fbd9cd76350bd5cc14c49de394a31770aed02d74203e23b928f3d2f1aa"}, + {file = "shapely-2.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f217d28ecb48e593beae20a0082a95bd9898d82d14b8fcb497edf6bff9a44d7"}, + {file = "shapely-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:394e5085b49334fd5b94fa89c086edfb39c3ecab7f669e8b2a4298b9d523b3a5"}, + {file = "shapely-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fd3ad17b64466a033848c26cb5b509625c87d07dcf39a1541461cacdb8f7e91c"}, + {file = "shapely-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d41a116fcad58048d7143ddb01285e1a8780df6dc1f56c3b1e1b7f12ed296651"}, + {file = "shapely-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dea9a0651333cf96ef5bb2035044e3ad6a54f87d90e50fe4c2636debf1b77abc"}, + {file = "shapely-2.0.2-cp39-cp39-win32.whl", hash = "sha256:b8eb0a92f7b8c74f9d8fdd1b40d395113f59bd8132ca1348ebcc1f5aece94b96"}, + {file = "shapely-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:794affd80ca0f2c536fc948a3afa90bd8fb61ebe37fe873483ae818e7f21def4"}, + {file = "shapely-2.0.2.tar.gz", hash = "sha256:1713cc04c171baffc5b259ba8531c58acc2a301707b7f021d88a15ed090649e7"}, ] [package.dependencies] @@ -2470,13 +2588,13 @@ test = ["pytest"] [[package]] name = "stack-data" -version = "0.6.2" +version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" files = [ - {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, - {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, ] [package.dependencies] @@ -2511,18 +2629,18 @@ files = [ [[package]] name = "traitlets" -version = "5.10.0" +version = "5.12.0" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.10.0-py3-none-any.whl", hash = "sha256:417745a96681fbb358e723d5346a547521f36e9bd0d50ba7ab368fff5d67aa54"}, - {file = "traitlets-5.10.0.tar.gz", hash = "sha256:f584ea209240466e66e91f3c81aa7d004ba4cf794990b0c775938a1544217cd1"}, + {file = "traitlets-5.12.0-py3-none-any.whl", hash = "sha256:81539f07f7aebcde2e4b5ab76727f53eabf18ad155c6ed7979a681411602fa47"}, + {file = "traitlets-5.12.0.tar.gz", hash = "sha256:833273bf645d8ce31dcb613c56999e2e055b1ffe6d09168a164bcd91c36d5d35"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.5.1)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "typing-extensions" @@ -2548,13 +2666,13 @@ files = [ [[package]] name = "urllib3" -version = "2.0.4" +version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.7" files = [ - {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, - {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] [package.extras] @@ -2565,13 +2683,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.5" +version = "20.24.6" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, - {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, + {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, + {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, ] [package.dependencies] @@ -2585,97 +2703,13 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "wcwidth" -version = "0.2.6" +version = "0.2.8" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, - {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, -] - -[[package]] -name = "wrapt" -version = "1.15.0" -description = "Module for decorators, wrappers and monkey patching." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, - {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, - {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, - {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, - {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, - {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, - {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, - {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, - {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, - {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, - {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, - {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, - {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, - {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, - {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, - {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, - {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, - {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, - {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, + {file = "wcwidth-0.2.8-py2.py3-none-any.whl", hash = "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704"}, + {file = "wcwidth-0.2.8.tar.gz", hash = "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4"}, ] [[package]] @@ -2693,7 +2727,11 @@ files = [ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +[extras] +graph = ["networkx"] +plot = ["matplotlib"] + [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "7463ecbe37dbd7a88a8ef0615336f51b2f3e29f898e0e3820b595483115ee5f3" +content-hash = "6af6b3c11560d3007b5d7e6e00df2226a70acaf83b5a1e2205a72e83037389a8" diff --git a/pyproject.toml b/pyproject.toml index b6c13df2..5638f543 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [ "Ali Hamdan ", "Sébastien Vallet ", "Benoît Vinot ", - "Victor Gouin ", + "Victor Gouin", ] maintainers = ["Ali Hamdan "] license = "Proprietary" @@ -28,6 +28,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering :: Physics", ] @@ -37,7 +38,11 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.dependencies] python = "^3.9" -numpy = ">=1.21.5" +numpy = [ + { version = ">=1.21.5", python = "<3.12" }, + { version = ">=1.26.0", python = ">=3.12,<3.13" }, + { version = "*", python = ">=3.13" }, +] pandas = ">=1.4.0" geopandas = ">=0.10.2" shapely = ">=2.0.0" @@ -47,8 +52,13 @@ pint = ">=0.21.0" typing-extensions = ">=4.6.2" rich = ">=13.5.1" -# Plot Extra -matplotlib = { version = "^3.7.2", extras = ["plot"] } +# Optional dependencies +matplotlib = { version = ">=3.7.2", optional = true } +networkx = { version = ">=3.0.0", optional = true } + +[tool.poetry.extras] +plot = ["matplotlib"] +graph = ["networkx"] [tool.poetry.group.test.dependencies] pytest = "^7.1.2" @@ -56,12 +66,13 @@ pytest-cov = "^4.0.0" pytest-xdist = "^3.1.0" requests-mock = "^1.9.3" coverage = { version = "^7.0.5", extras = ["toml"] } -matplotlib = "^3.7.2" +matplotlib = ">=3.7.2" +networkx = ">=3.0.0" [tool.poetry.group.dev.dependencies] pre-commit = "^3.0.0" -black = { version = "==23.9.1", extras = ["jupyter"] } # keep in sync with .pre-commit-config.yaml -ruff = "==0.0.290" # keep in sync with .pre-commit-config.yaml +black = { version = "==23.10.1", extras = ["jupyter"] } # keep in sync with .pre-commit-config.yaml +ruff = "==0.1.3" # keep in sync with .pre-commit-config.yaml [tool.poetry.group.doc.dependencies] sphinx = "^7.0.1" @@ -76,14 +87,14 @@ sphinxcontrib-bibtex = "^2.5.0" [tool.black] line-length = 120 -target-version = ["py39", "py310", "py311"] +target-version = ["py39", "py310", "py311", "py312"] [tool.ruff] line-length = 120 target-version = "py39" show-fixes = true namespace-packages = ["roseau"] -include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"] +extend-include = ["*.ipynb"] select = ["E", "F", "C90", "W", "B", "UP", "I", "RUF100", "TID", "SIM", "PT", "PIE", "N", "C4", "NPY"] unfixable = ["B"] ignore = ["E501", "B024", "N818"] @@ -135,3 +146,6 @@ directory = "htmlcov" [tool.pytest.ini_options] addopts = "--color=yes -vv -n=0" testpaths = ["roseau/load_flow/"] +filterwarnings = [ + 'ignore:.*utcfromtimestamp:DeprecationWarning:dateutil.*', # dateutil is imported by pandas, not us +] From 3e2412a87d45171ac8a6636e5f12b53764a03a62 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Mon, 30 Oct 2023 09:54:29 +0100 Subject: [PATCH 30/43] Implement networkx graphs --- conda/environment.yml | 1 + conda/meta.yaml | 1 + doc/Changelog.md | 8 +++ doc/conf.py | 2 + doc/usage/Extras.md | 33 +++++++++++ poetry.lock | 57 ++++++------------- pyproject.toml | 2 +- roseau/load_flow/models/buses.py | 25 +++++++- .../models/loads/flexible_parameters.py | 27 +++------ roseau/load_flow/models/tests/test_buses.py | 43 ++++++++++++++ roseau/load_flow/network.py | 49 +++++++++++++++- .../tests/test_electrical_network.py | 16 ++++++ roseau/load_flow/utils/_optional_deps.py | 42 ++++++++++++++ 13 files changed, 242 insertions(+), 64 deletions(-) create mode 100644 roseau/load_flow/utils/_optional_deps.py diff --git a/conda/environment.yml b/conda/environment.yml index 640acd57..1285b8e3 100644 --- a/conda/environment.yml +++ b/conda/environment.yml @@ -14,3 +14,4 @@ dependencies: - typing-extensions >=4.6.2 - rich >=13.5.1 - matplotlib >=3.7.2 + - networkx >=3.0.0 diff --git a/conda/meta.yaml b/conda/meta.yaml index 8cc7e50b..2a501fbe 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -36,6 +36,7 @@ requirements: - typing-extensions >=4.6.2 - rich >=13.5.1 - matplotlib >=3.7.2 + - networkx >=3.0.0 test: imports: diff --git a/doc/Changelog.md b/doc/Changelog.md index 845e0ce2..3d9e3092 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,14 @@ **In development** +- {gh-pr}`141` {gh-issue}`137` Add `ElectricalNetwork.to_graph()` to get a `networkx.Graph` object + representing the electrical network for graph theory studies. Install with the `"graph"` extra to + get _networkx_. + `ElectricalNetwork` also gained a new `buses_clusters` property that returns a list of sets of + IDs of buses that are connected by a line or a switch. This can be useful to isolate parts of the + network for localized analysis. For example, to study a LV subnetwork of a MV feeder. Alternatively, + to get the cluster certain bus belongs to, you can use `Bus.find_neighbors()`. +- {gh-pr}`141` Add official support for Python 3.12. This is the last release to support Python 3.9. - {gh-pr}`138` Add network constraints for analysis of the results. - Buses can define minimum and maximum voltages. Use `bus.res_violated` to see if the bus has over- or under-voltage. diff --git a/doc/conf.py b/doc/conf.py index 42280718..df28633d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -130,6 +130,8 @@ "pint": ("https://pint.readthedocs.io/en/stable/", None), "typing_extensions": ("https://typing-extensions.readthedocs.io/en/stable/", None), "rich": ("https://rich.readthedocs.io/en/stable/", None), + "matplotlib": ("https://matplotlib.org/stable/", None), + "networkx": ("https://networkx.org/documentation/stable/", None), } # -- Options for sphinx_copybutton ------------------------------------------- diff --git a/doc/usage/Extras.md b/doc/usage/Extras.md index f185bdbe..ab4b63aa 100644 --- a/doc/usage/Extras.md +++ b/doc/usage/Extras.md @@ -2,6 +2,39 @@ `roseau-load-flow` comes with some extra features that can be useful for some users. +## Graph theory + +{meth}`ElectricalNetwork.to_graph() ` can be used to +get a {class}`networkx.Graph` object from the electrical network. + +The graph contains the geometries of the buses in the nodes data and the geometries and branch +types in the edges data. + +```{note} +This method requires *networkx* which is not installed by default in pip managed installs. You can +install it with the `"graph"` extra if you are using pip: `pip install "roseau-load-flow[graph]"`. +``` + +In addition, you can use the property +{meth}`ElectricalNetwork.buses_clusters ` to +get a list of sets of IDs of buses connected by a line or a switch. For example, with a network +with a MV feeder, this property returns a list containing a set of MV buses IDs and all sets of +LV subnetworks buses IDs. If you want to get the cluster of only one bus, you can use +{meth}`Bus.find_neighbors ` + +If we take the example network from the [Getting Started page](gs-creating-network): + +```pycon +>>> set(source_bus.find_neighbors()) +{'sb', 'lb'} +>>> set(load_bus.find_neighbors()) +{'sb', 'lb'} +>>> en.buses_clusters +[{'sb', 'lb'}] +``` + +As there are no transformers between the two buses, they all belong to the same cluster. + ## Conversion to symmetrical components {mod}`roseau.load_flow.converters` contains helpers to convert between phasor and symmetrical diff --git a/poetry.lock b/poetry.lock index df6b3644..e5c3ebbb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -100,17 +100,6 @@ setuptools = {version = "*", markers = "python_version >= \"3.12\""} [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -optional = false -python-versions = "*" -files = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] - [[package]] name = "beautifulsoup4" version = "4.12.2" @@ -893,25 +882,23 @@ files = [ [[package]] name = "ipython" -version = "8.16.1" +version = "8.17.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" files = [ - {file = "ipython-8.16.1-py3-none-any.whl", hash = "sha256:0852469d4d579d9cd613c220af7bf0c9cc251813e12be647cb9d463939db9b1e"}, - {file = "ipython-8.16.1.tar.gz", hash = "sha256:ad52f58fca8f9f848e256c629eff888efc0528c12fe0f8ec14f33205f23ef938"}, + {file = "ipython-8.17.0-py3-none-any.whl", hash = "sha256:5feb75ac603a6663de233196e1beea81ec9e5042916d4e30eb42ac09adc718d8"}, + {file = "ipython-8.17.0.tar.gz", hash = "sha256:ec8023527c477910939841d4dc2348f8f843b310a504a49db7559bd6b7579953"}, ] [package.dependencies] appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" pygments = ">=2.4.0" stack-data = "*" @@ -919,17 +906,17 @@ traitlets = ">=5" typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] [[package]] name = "jedi" @@ -1592,17 +1579,6 @@ files = [ [package.dependencies] ptyprocess = ">=0.5" -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -optional = false -python-versions = "*" -files = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] - [[package]] name = "pillow" version = "10.1.0" @@ -2362,26 +2338,27 @@ test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools [[package]] name = "sphinx-autoapi" -version = "2.1.1" +version = "3.0.0" description = "Sphinx API documentation generator" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "sphinx-autoapi-2.1.1.tar.gz", hash = "sha256:fbadb96e79020d6b0ec45d888517bf816d6b587a2d340fbe1ec31135e300a6c8"}, - {file = "sphinx_autoapi-2.1.1-py2.py3-none-any.whl", hash = "sha256:d8da890477bd18e3327cafdead9d5a44a7d798476c6fa32492100e288250a5a3"}, + {file = "sphinx-autoapi-3.0.0.tar.gz", hash = "sha256:09ebd674a32b44467222b0fb8a917b97c89523f20dbf05b52cb8a3f0e15714de"}, + {file = "sphinx_autoapi-3.0.0-py2.py3-none-any.whl", hash = "sha256:ea207793cba1feff7b2ded0e29364f2995a4d157303a98603cee0ce94cea2688"}, ] [package.dependencies] anyascii = "*" -astroid = ">=2.7" +astroid = [ + {version = ">=2.7", markers = "python_version < \"3.12\""}, + {version = ">=3.0.0a1", markers = "python_version >= \"3.12\""}, +] Jinja2 = "*" PyYAML = "*" -sphinx = ">=5.2.0" +sphinx = ">=6.1.0" [package.extras] docs = ["furo", "sphinx", "sphinx-design"] -dotnet = ["sphinxcontrib-dotnetdomain"] -go = ["sphinxcontrib-golangdomain"] [[package]] name = "sphinx-basic-ng" @@ -2734,4 +2711,4 @@ plot = ["matplotlib"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "6af6b3c11560d3007b5d7e6e00df2226a70acaf83b5a1e2205a72e83037389a8" +content-hash = "a6c19e6cea5d7254d7e5dcde757eacdde2d917590885dad05fa22a2f0a1709e3" diff --git a/pyproject.toml b/pyproject.toml index 5638f543..a4458a3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ ruff = "==0.1.3" # keep in sync with .pre-commit-config.yaml sphinx = "^7.0.1" myst-parser = ">=0.16.1" sphinx-math-dollar = "^1.2.1" -sphinx-autoapi = "^2.0.0" +sphinx-autoapi = "^3.0.0" sphinx-copybutton = ">=0.5.1" sphinx-inline-tabs = ">=2022.1.2b11" furo = ">=2022.9.29" diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index fd8254b4..76825443 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -1,5 +1,5 @@ import logging -from collections.abc import Sequence +from collections.abc import Iterator, Sequence from typing import TYPE_CHECKING, Any, Optional import numpy as np @@ -253,6 +253,29 @@ def propagate_limits(self, force: bool = False) -> None: bus._min_voltage = self._min_voltage bus._max_voltage = self._max_voltage + def find_neighbors(self) -> Iterator[Id]: + """Find the buses connected to this bus via a line or switch recursively.""" + from roseau.load_flow.models.lines import Line, Switch + + visited_buses = {self.id} + yield self.id + + visited: set[Element] = set() + remaining = set(self._connected_elements) + + while remaining: + branch = remaining.pop() + visited.add(branch) + if not isinstance(branch, (Line, Switch)): + continue + for element in branch._connected_elements: + if not isinstance(element, Bus) or element.id in visited_buses: + continue + visited_buses.add(element.id) + yield element.id + to_add = set(element._connected_elements).difference(visited) + remaining.update(to_add) + # # Json Mixin interface # diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index ee35f2dd..668886bc 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -8,7 +8,7 @@ from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.typing import Authentication, ControlType, JsonDict, ProjectionType from roseau.load_flow.units import Q_, ureg_wraps -from roseau.load_flow.utils import JsonMixin +from roseau.load_flow.utils import JsonMixin, _optional_deps logger = logging.getLogger(__name__) @@ -16,19 +16,6 @@ from matplotlib.axes import Axes -def _import_matplotlib_pyplot(): - try: - import matplotlib.pyplot - except ImportError as e: - msg = ( - 'matplotlib is required for plotting. Install it with the "plot" extra using ' - '`pip install -U "roseau-load-flow[plot]"`' - ) - logger.error(msg) - raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from e - return matplotlib.pyplot - - class Control(JsonMixin): """Control class for flexible loads. @@ -1065,12 +1052,12 @@ def plot_pq( The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else the computed values). """ - plt = _import_matplotlib_pyplot() # this line first for better error handling + plt = _optional_deps.pyplot # this line first for better error handling from matplotlib import colormaps, patheffects # Get the axes if ax is None: - ax: "Axes" = plt.gca() + ax = plt.gca() # Initialise some variables if voltages_labels_mask is None: @@ -1173,11 +1160,11 @@ def plot_control_p( The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else the computed values). """ - plt = _import_matplotlib_pyplot() + plt = _optional_deps.pyplot # Get the axes if ax is None: - ax: "Axes" = plt.gca() + ax = plt.gca() # Depending on the type of the control, several options x, y, x_ticks = self._theoretical_control_data( @@ -1239,11 +1226,11 @@ def plot_control_q( The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else the computed values). """ - plt = _import_matplotlib_pyplot() + plt = _optional_deps.pyplot # Get the axes if ax is None: - ax: "Axes" = plt.gca() + ax = plt.gca() # Depending on the type of the control, several options x, y, x_ticks = self._theoretical_control_data( diff --git a/roseau/load_flow/models/tests/test_buses.py b/roseau/load_flow/models/tests/test_buses.py index fb05e427..af53c218 100644 --- a/roseau/load_flow/models/tests/test_buses.py +++ b/roseau/load_flow/models/tests/test_buses.py @@ -281,3 +281,46 @@ def test_propagate_limits(): # noqa: C901 for bus in (b1_lv, b2_lv): assert bus.min_voltage == Q_(217, "V") assert bus.max_voltage == Q_(253, "V") + + +def test_find_neighbors(): + b1_mv = Bus("b1_mv", phases="abc") + b2_mv = Bus("b2_mv", phases="abc") + b3_mv = Bus("b3_mv", phases="abc") + b4_mv = Bus("b4_mv", phases="abc") + b1_lv = Bus("b1_lv", phases="abcn") + b2_lv = Bus("b2_lv", phases="abcn") + b3_lv = Bus("b3_lv", phases="abcn") + + PotentialRef("pref_mv", element=b1_mv) + g = Ground("g") + PotentialRef("pref_lv", element=g) + + lp_mv = LineParameters("lp_mv", z_line=np.eye(3), y_shunt=0.1 * np.eye(3)) + lp_lv = LineParameters("lp_lv", z_line=np.eye(4)) + tp = TransformerParameters.from_catalogue(id="SE_Minera_A0Ak_100kVA", manufacturer="SE") + + Line("l1_mv", b1_mv, b2_mv, length=1.5, parameters=lp_mv, ground=g) + Line("l2_mv", b2_mv, b3_mv, length=2, parameters=lp_mv, ground=g) + Line("l3_mv", b2_mv, b4_mv, length=0.5, parameters=lp_mv, ground=g) # creates a loop + Switch("sw_mv", b3_mv, b4_mv) + Transformer("tr", b3_mv, b1_lv, parameters=tp) + Line("l1_lv", b1_lv, b2_lv, length=1, parameters=lp_lv) + Switch("sw_lv", b2_lv, b3_lv) + + voltages = 20_000 * np.exp([0, -2 / 3 * np.pi * 1j, 2 / 3 * np.pi * 1j]) + VoltageSource("s_mv", bus=b1_mv, voltages=voltages) + + PowerLoad("pl1_mv", bus=b2_mv, powers=[10e3, 10e3, 10e3]) + PowerLoad("pl2_mv", bus=b3_mv, powers=[10e3, 10e3, 10e3]) + PowerLoad("pl1_lv", bus=b1_lv, powers=[1e3, 1e3, 1e3]) + PowerLoad("pl2_lv", bus=b2_lv, powers=[1e3, 1e3, 1e3]) + + mv_buses = (b1_mv, b2_mv, b3_mv, b4_mv) + mv_bus_ids = sorted(b.id for b in mv_buses) + lv_buses = (b1_lv, b2_lv, b3_lv) + lv_bus_ids = sorted(b.id for b in lv_buses) + for mvb in mv_buses: + assert sorted(mvb.find_neighbors()) == mv_bus_ids + for lvb in lv_buses: + assert sorted(lvb.find_neighbors()) == lv_bus_ids diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index 8af70487..4df90e5e 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -10,7 +10,7 @@ from importlib import resources from itertools import cycle from pathlib import Path -from typing import NoReturn, Optional, TypeVar, Union +from typing import TYPE_CHECKING, NoReturn, Optional, TypeVar, Union from urllib.parse import urljoin import geopandas as gpd @@ -38,9 +38,12 @@ ) from roseau.load_flow.solvers import check_solver_params from roseau.load_flow.typing import Authentication, Id, JsonDict, Solver, StrPath -from roseau.load_flow.utils import CatalogueMixin, JsonMixin, console, palette +from roseau.load_flow.utils import CatalogueMixin, JsonMixin, _optional_deps, console, palette from roseau.load_flow.utils.types import _DTYPES, VoltagePhaseDtype +if TYPE_CHECKING: + from networkx import Graph + logger = logging.getLogger(__name__) _T = TypeVar("_T", bound=Element) @@ -441,6 +444,48 @@ def short_circuits_frame(self) -> pd.DataFrame: columns=["bus_id", "phases", "short_circuit", "ground"], ) + # + # Helpers to analyze the network + # + @property + def buses_clusters(self) -> list[set[Id]]: + """Sets of buses connected together by a line or a switch. + + This can be useful to isolate parts of the network for localized analysis. For example, to + study a LV subnetwork of a MV feeder. + + See Also: + :meth:`Bus.find_neighbors() `: Find the + buses in the same cluster as a certain bus. + """ + visited: set[Id] = set() + result: list[set[Id]] = [] + for bus in self.buses.values(): + if bus.id in visited: + continue + bus_cluster = set(bus.find_neighbors()) + visited |= bus_cluster + result.append(bus_cluster) + return result + + def to_graph(self) -> "Graph": + """Create a networkx graph from this electrical network. + + The graph contains the geometries of the buses in the nodes data and the geometries and + branch types in the edges data. + + Note: + This method requires *networkx* to be installed. You can install it with the ``"graph"`` + extra if you are using pip: ``pip install "roseau-load-flow[graph]"``. + """ + nx = _optional_deps.networkx + graph = nx.Graph() + for bus in self.buses.values(): + graph.add_node(bus.id, geom=bus.geometry) + for branch in self.branches.values(): + graph.add_edge(branch.bus1.id, branch.bus2.id, id=branch.id, type=branch.branch_type, geom=branch.geometry) + return graph + # # Method to solve a load flow # diff --git a/roseau/load_flow/tests/test_electrical_network.py b/roseau/load_flow/tests/test_electrical_network.py index 7271fd6c..0d8ef238 100644 --- a/roseau/load_flow/tests/test_electrical_network.py +++ b/roseau/load_flow/tests/test_electrical_network.py @@ -5,6 +5,7 @@ from urllib.parse import urljoin import geopandas as gpd +import networkx as nx import numpy as np import pandas as pd import pytest @@ -2093,3 +2094,18 @@ def test_print_catalogue(): with console.capture() as capture: ElectricalNetwork.print_catalogue(load_point_name=r"^winter[0-]") assert len(capture.get().split("\n")) == 2 + + +def test_to_graph(small_network: ElectricalNetwork): + g = small_network.to_graph() + assert isinstance(g, nx.Graph) + assert sorted(g.nodes) == sorted(small_network.buses) + assert sorted(g.edges) == sorted((b.bus1.id, b.bus2.id) for b in small_network.branches.values()) + + for bus in small_network.buses.values(): + node_data = g.nodes[bus.id] + assert node_data["geom"] == bus.geometry + + for branch in small_network.branches.values(): + edge_data = g.edges[branch.bus1.id, branch.bus2.id] + assert edge_data == {"id": branch.id, "type": branch.branch_type, "geom": branch.geometry} diff --git a/roseau/load_flow/utils/_optional_deps.py b/roseau/load_flow/utils/_optional_deps.py new file mode 100644 index 00000000..99be07f5 --- /dev/null +++ b/roseau/load_flow/utils/_optional_deps.py @@ -0,0 +1,42 @@ +import logging +from typing import TYPE_CHECKING, Any + +from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode + +if TYPE_CHECKING: + import networkx as networkx + from matplotlib import pyplot as pyplot + +logger = logging.getLogger(__name__) + +__all__ = [ + "pyplot", + "networkx", +] + + +def __getattr__(name: str) -> Any: + if name == "pyplot": + try: + import matplotlib.pyplot + except ImportError as e: + msg = ( + 'matplotlib is required for plotting. Install it with the "plot" extra using ' + '`pip install -U "roseau-load-flow[plot]"`' + ) + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from e + return matplotlib.pyplot + elif name == "networkx": + try: + import networkx + except ImportError as e: + msg = ( + 'networkx is not installed. Install it with the "graph" extra using ' + '`pip install -U "roseau-load-flow[graph]"`' + ) + logger.error(msg) + raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.IMPORT_ERROR) from e + return networkx + else: + raise AttributeError(f"module {__name__} has no attribute {name!r}") From a4bda7cfe3cf39d3663df1bc7c3c63e56f7b2188 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Mon, 30 Oct 2023 16:14:29 +0100 Subject: [PATCH 31/43] Rename method and clarify the text --- doc/Changelog.md | 2 +- doc/usage/Extras.md | 13 +++++++------ doc/usage/Getting_Started.md | 3 +-- roseau/load_flow/models/buses.py | 13 ++++++++----- roseau/load_flow/models/tests/test_buses.py | 6 +++--- roseau/load_flow/network.py | 4 ++-- 6 files changed, 22 insertions(+), 19 deletions(-) diff --git a/doc/Changelog.md b/doc/Changelog.md index 3d9e3092..88d090ab 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -10,7 +10,7 @@ `ElectricalNetwork` also gained a new `buses_clusters` property that returns a list of sets of IDs of buses that are connected by a line or a switch. This can be useful to isolate parts of the network for localized analysis. For example, to study a LV subnetwork of a MV feeder. Alternatively, - to get the cluster certain bus belongs to, you can use `Bus.find_neighbors()`. + to get the cluster certain bus belongs to, you can use `Bus.get_connected_buses()`. - {gh-pr}`141` Add official support for Python 3.12. This is the last release to support Python 3.9. - {gh-pr}`138` Add network constraints for analysis of the results. - Buses can define minimum and maximum voltages. Use `bus.res_violated` to see if the bus has diff --git a/doc/usage/Extras.md b/doc/usage/Extras.md index ab4b63aa..768df904 100644 --- a/doc/usage/Extras.md +++ b/doc/usage/Extras.md @@ -17,17 +17,18 @@ install it with the `"graph"` extra if you are using pip: `pip install "roseau-l In addition, you can use the property {meth}`ElectricalNetwork.buses_clusters ` to -get a list of sets of IDs of buses connected by a line or a switch. For example, with a network -with a MV feeder, this property returns a list containing a set of MV buses IDs and all sets of -LV subnetworks buses IDs. If you want to get the cluster of only one bus, you can use -{meth}`Bus.find_neighbors ` +get a list of sets of IDs of buses in galvanically isolated sections of the network. In other terms, +to get groups of buses connected by one or more lines or a switches, stopping at transformers. For +example, for a network with a MV feeder, this property returns a list containing a set of MV buses +IDs and all sets of LV subnetworks buses IDs. If you want to get the cluster of only one bus, you +can use {meth}`Bus.get_connected_buses ` If we take the example network from the [Getting Started page](gs-creating-network): ```pycon ->>> set(source_bus.find_neighbors()) +>>> set(source_bus.get_connected_buses()) {'sb', 'lb'} ->>> set(load_bus.find_neighbors()) +>>> set(load_bus.get_connected_buses()) {'sb', 'lb'} >>> en.buses_clusters [{'sb', 'lb'}] diff --git a/doc/usage/Getting_Started.md b/doc/usage/Getting_Started.md index 40aa587b..6d8de653 100644 --- a/doc/usage/Getting_Started.md +++ b/doc/usage/Getting_Started.md @@ -492,8 +492,7 @@ the limits are violated or not for the corresponding element. ```{tip} You can use the {meth}`Bus.propagate_limits() ` method to -propagate the limits from a bus to its neighboring buses, that is, buses on the same side of a -transformer. +propagate the limits from a bus to buses connected to it galvanically (i.e. via lines or switches). ``` (gs-updating-elements)= diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index 76825443..252dbdf4 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -191,15 +191,15 @@ def res_violated(self) -> Optional[bool]: return float(min(voltages)) < self._min_voltage or float(max(voltages)) > self._max_voltage def propagate_limits(self, force: bool = False) -> None: - """Propagate the voltage limits to neighbor buses. + """Propagate the voltage limits to galvanically connected buses. - Neighbor buses here refers to buses connected to this bus through lines or switches. This + Galvanically connected buses are buses connected to this bus through lines or switches. This ensures that these voltage limits are only applied to buses with the same voltage level. If a bus is connected to this bus through a transformer, the voltage limits are not propagated to that bus. If this bus does not define any voltage limits, calling this method will unset the limits - of the neighbor buses. + of the connected buses. Args: force: @@ -253,8 +253,11 @@ def propagate_limits(self, force: bool = False) -> None: bus._min_voltage = self._min_voltage bus._max_voltage = self._max_voltage - def find_neighbors(self) -> Iterator[Id]: - """Find the buses connected to this bus via a line or switch recursively.""" + def get_connected_buses(self) -> Iterator[Id]: + """Get IDs of all the buses galvanically connected to this bus. + + These are all the buses connected via one or more lines or switches to this bus. + """ from roseau.load_flow.models.lines import Line, Switch visited_buses = {self.id} diff --git a/roseau/load_flow/models/tests/test_buses.py b/roseau/load_flow/models/tests/test_buses.py index af53c218..bbe0ec2f 100644 --- a/roseau/load_flow/models/tests/test_buses.py +++ b/roseau/load_flow/models/tests/test_buses.py @@ -283,7 +283,7 @@ def test_propagate_limits(): # noqa: C901 assert bus.max_voltage == Q_(253, "V") -def test_find_neighbors(): +def test_get_connected_buses(): b1_mv = Bus("b1_mv", phases="abc") b2_mv = Bus("b2_mv", phases="abc") b3_mv = Bus("b3_mv", phases="abc") @@ -321,6 +321,6 @@ def test_find_neighbors(): lv_buses = (b1_lv, b2_lv, b3_lv) lv_bus_ids = sorted(b.id for b in lv_buses) for mvb in mv_buses: - assert sorted(mvb.find_neighbors()) == mv_bus_ids + assert sorted(mvb.get_connected_buses()) == mv_bus_ids for lvb in lv_buses: - assert sorted(lvb.find_neighbors()) == lv_bus_ids + assert sorted(lvb.get_connected_buses()) == lv_bus_ids diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index 4df90e5e..bcdc6623 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -455,7 +455,7 @@ def buses_clusters(self) -> list[set[Id]]: study a LV subnetwork of a MV feeder. See Also: - :meth:`Bus.find_neighbors() `: Find the + :meth:`Bus.get_connected_buses() `: Find the buses in the same cluster as a certain bus. """ visited: set[Id] = set() @@ -463,7 +463,7 @@ def buses_clusters(self) -> list[set[Id]]: for bus in self.buses.values(): if bus.id in visited: continue - bus_cluster = set(bus.find_neighbors()) + bus_cluster = set(bus.get_connected_buses()) visited |= bus_cluster result.append(bus_cluster) return result From 81a4f9d4f0ff29fbb5d357e8c3f20e13af13ef03 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Mon, 30 Oct 2023 16:20:43 +0100 Subject: [PATCH 32/43] One more clarification --- roseau/load_flow/network.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index bcdc6623..73eabe17 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -449,14 +449,14 @@ def short_circuits_frame(self) -> pd.DataFrame: # @property def buses_clusters(self) -> list[set[Id]]: - """Sets of buses connected together by a line or a switch. + """Sets of galvanically connected buses, i.e buses connected by lines or a switches. This can be useful to isolate parts of the network for localized analysis. For example, to study a LV subnetwork of a MV feeder. See Also: - :meth:`Bus.get_connected_buses() `: Find the - buses in the same cluster as a certain bus. + :meth:`Bus.get_connected_buses() `: Get + the buses in the same galvanically isolated section as a certain bus. """ visited: set[Id] = set() result: list[set[Id]] = [] From 2857e4396ebdd4d6f670598826bc0de981d04c5e Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Mon, 30 Oct 2023 17:53:50 +0100 Subject: [PATCH 33/43] Add voltage unbalance calculation (#142) Closes #136 Add method `res_voltage_unbalance` to 3-phase buses that calculates the voltage unbalance factor. Note that this is a method, not a property, so that we can support more standards in the future by passing arguments to this method. Voltage unbalance does not make sense for non 3-phase buses thus we raise an error with a helpful message. I also fixed the symmetrical to phasor converters to preserve the shape of the input array. --- .pre-commit-config.yaml | 2 +- .vscode/extensions.json | 3 +- .vscode/settings.json | 6 ++++ doc/Bibliography.bib | 11 ++++++++ doc/Changelog.md | 2 ++ doc/usage/Extras.md | 24 ++++++++++++++++ roseau/load_flow/converters.py | 12 +++++--- roseau/load_flow/models/buses.py | 25 ++++++++++++++++- roseau/load_flow/models/tests/test_buses.py | 31 +++++++++++++++++++++ roseau/load_flow/tests/test_converters.py | 28 +++++++++---------- 10 files changed, 123 insertions(+), 21 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4f2862b5..d6165d96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,7 +32,7 @@ repos: - id: blacken-docs entry: bash -c "blacken-docs -l 90 $(find doc/ -name '*.md')" args: [-l 90] - additional_dependencies: [black==23.9.1] # keep in sync with black above + additional_dependencies: [black==23.10.1] # keep in sync with black above - repo: https://github.com/pre-commit/mirrors-prettier rev: v3.0.3 hooks: diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 5226822d..07f32b7a 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,9 +1,10 @@ { "recommendations": [ "charliermarsh.ruff", + "esbenp.prettier-vscode", "ms-python.black-formatter", "ms-python.python", - "ms-python.vscode-pylance" + "ms-python.vscode-pylance", ], "unwantedRecommendations": [ "ms-python.flake8", // We use ruff diff --git a/.vscode/settings.json b/.vscode/settings.json index 8071bd53..5c4f517a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,4 +20,10 @@ "source.organizeImports.ruff": "explicit", }, }, + // Prettier + "prettier.printWidth": 120, + "[markdown][yaml][html][css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + } } diff --git a/doc/Bibliography.bib b/doc/Bibliography.bib index 85fd2b2a..7e9aa0b3 100644 --- a/doc/Bibliography.bib +++ b/doc/Bibliography.bib @@ -29,3 +29,14 @@ @misc{wiki:Method_Of_Image_Charges url = {http://en.wikipedia.org/w/index.php?title=Method\%20of\%20image\%20charges&oldid=1152888135}, note = "[Online; accessed 25-August-2023]" } + +@inproceedings{Girigoudar_2019, + author = {Girigoudar, Kshitij and Molzahn, Daniel K. and Roald, Line A.}, + booktitle = {2019 North American Power Symposium (NAPS)}, + title = {On The Relationships Among Different Voltage Unbalance Definitions}, + year = {2019}, + volume = {}, + number = {}, + pages = {1-6}, + doi = {10.1109/NAPS46351.2019.9000231} +} diff --git a/doc/Changelog.md b/doc/Changelog.md index 88d090ab..deb17056 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,8 @@ **In development** +- {gh-pr}`142` {gh-issue}`136` Add `Bus.res_voltage_unbalance()` method to get the Voltage Unbalance + Factor (VUF) as defined by the IEC standard IEC 61000-3-14. - {gh-pr}`141` {gh-issue}`137` Add `ElectricalNetwork.to_graph()` to get a `networkx.Graph` object representing the electrical network for graph theory studies. Install with the `"graph"` extra to get _networkx_. diff --git a/doc/usage/Extras.md b/doc/usage/Extras.md index 768df904..434d3fa9 100644 --- a/doc/usage/Extras.md +++ b/doc/usage/Extras.md @@ -135,3 +135,27 @@ the module documentation for more details. An enumeration of available conductor types can be found in the {mod}`roseau.load_flow.utils.types` module. + +## Voltage unbalance + +It is possible to calculate the voltage unbalance due to asymmetric operation. There are many +definitions of voltage unbalance (see {cite:p}`Girigoudar_2019`). In `roseau-load-flow`, you can +use the {meth}`~roseau.load_flow.models.Bus.res_voltage_unbalance` method on a 3-phase bus to get +the Voltage Unbalance Factor (VUF) as per the IEC definition: + +```{math} +VUF = \frac{|V_n|}{|V_p|} * 100 (\%) +``` + +Where $V_n$ is the negative-sequence voltage and $V_p$ is the positive-sequence voltage. + +```{note} +Other definitions of voltage unbalance could be added in the future. If you need a specific +definition, please open an issue on the GitHub repository. +``` + +## Bibliography + +```{bibliography} +:filter: docname in docnames +``` diff --git a/roseau/load_flow/converters.py b/roseau/load_flow/converters.py index 32417120..6f5c57d0 100644 --- a/roseau/load_flow/converters.py +++ b/roseau/load_flow/converters.py @@ -30,14 +30,18 @@ def phasor_to_sym(v_abc: Sequence[complex]) -> np.ndarray[complex]: """Compute the symmetrical components `(0, +, -)` from the phasor components `(a, b, c)`.""" - v_012 = _A_INV @ np.asarray(v_abc).reshape((3, 1)) - return v_012 + v_abc_array = np.asarray(v_abc) + orig_shape = v_abc_array.shape + v_012 = _A_INV @ v_abc_array.reshape((3, 1)) + return v_012.reshape(orig_shape) def sym_to_phasor(v_012: Sequence[complex]) -> np.ndarray[complex]: """Compute the phasor components `(a, b, c)` from the symmetrical components `(0, +, -)`.""" - v_abc = A @ np.asarray(v_012).reshape((3, 1)) - return v_abc + v_012_array = np.asarray(v_012) + orig_shape = v_012_array.shape + v_abc = A @ v_012_array.reshape((3, 1)) + return v_abc.reshape(orig_shape) def series_phasor_to_sym(s_abc: pd.Series) -> pd.Series: diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index 252dbdf4..928ff1e1 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -7,7 +7,7 @@ from shapely import Point from typing_extensions import Self -from roseau.load_flow.converters import calculate_voltage_phases, calculate_voltages +from roseau.load_flow.converters import calculate_voltage_phases, calculate_voltages, phasor_to_sym from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.models.core import Element from roseau.load_flow.typing import Id, JsonDict @@ -279,6 +279,29 @@ def get_connected_buses(self) -> Iterator[Id]: to_add = set(element._connected_elements).difference(visited) remaining.update(to_add) + @ureg_wraps("percent", (None,), strict=False) + def res_voltage_unbalance(self) -> Q_[float]: + """Calculate the voltage unbalance on this bus according to the IEC definition. + + Voltage Unbalance Factor: + + :math:`VUF = \\frac{|V_n|}{|V_p|} * 100 (\\%)` + + Where :math:`V_n` is the negative-sequence voltage and :math:`V_p` is the positive-sequence + voltage. + """ + # https://std.iec.ch/terms/terms.nsf/3385f156e728849bc1256e8c00278ad2/771c5188e62fade5c125793a0043f2a5?OpenDocument + if self.phases not in {"abc", "abcn"}: + msg = f"Voltage unbalance is only available for 3-phases buses, bus {self.id!r} has phases {self.phases!r}" + logger.error(msg) + raise RoseauLoadFlowException(msg, code=RoseauLoadFlowExceptionCode.BAD_PHASE) + # We use the potentials here which is equivalent to using the "line to neutral" voltages as + # defined by the standard. The standard also has this note: + # NOTE 1 Phase-to-phase voltages may also be used instead of line to neutral voltages. + potentials = self._res_potentials_getter(warning=True) + _, vp, vn = phasor_to_sym(potentials[:3]) # (0, +, -) + return abs(vn) / abs(vp) * 100 + # # Json Mixin interface # diff --git a/roseau/load_flow/models/tests/test_buses.py b/roseau/load_flow/models/tests/test_buses.py index bbe0ec2f..5fd92ff9 100644 --- a/roseau/load_flow/models/tests/test_buses.py +++ b/roseau/load_flow/models/tests/test_buses.py @@ -324,3 +324,34 @@ def test_get_connected_buses(): assert sorted(mvb.get_connected_buses()) == mv_bus_ids for lvb in lv_buses: assert sorted(lvb.get_connected_buses()) == lv_bus_ids + + +def test_res_voltage_unbalance(): + bus = Bus("b3", phases="abc") + + va = 230 + 0j + vb = 230 * np.exp(4j * np.pi / 3) + vc = 230 * np.exp(2j * np.pi / 3) + + # Balanced system + bus._res_potentials = np.array([va, vb, vc]) + assert np.isclose(bus.res_voltage_unbalance().magnitude, 0) + + # Unbalanced system + bus._res_potentials = np.array([va, vb, vb]) + assert np.isclose(bus.res_voltage_unbalance().magnitude, 100) + + # With neutral + bus = Bus("b3n", phases="abcn") + bus._res_potentials = np.array([va, vb, vc, 0]) + assert np.isclose(bus.res_voltage_unbalance().magnitude, 0) + bus._res_potentials = np.array([va, vb, vb, 0]) + assert np.isclose(bus.res_voltage_unbalance().magnitude, 100) + + # Non 3-phase bus + bus = Bus("b1", phases="an") + bus._res_potentials = np.array([va, 0]) + with pytest.raises(RoseauLoadFlowException) as e: + bus.res_voltage_unbalance() + assert e.value.code == RoseauLoadFlowExceptionCode.BAD_PHASE + assert e.value.msg == "Voltage unbalance is only available for 3-phases buses, bus 'b1' has phases 'an'" diff --git a/roseau/load_flow/tests/test_converters.py b/roseau/load_flow/tests/test_converters.py index 929dacc6..06b262c6 100644 --- a/roseau/load_flow/tests/test_converters.py +++ b/roseau/load_flow/tests/test_converters.py @@ -13,23 +13,23 @@ def test_phasor_to_sym(): vc = 230 * np.e ** (1j * 2 * np.pi / 3) # Test balanced direct system: positive sequence - expected = np.array([[0], [230], [0]], dtype=complex) + expected = np.array([0, 230, 0], dtype=complex) assert np.allclose(phasor_to_sym([va, vb, vc]), expected) # Also test numpy array input with different shapes assert np.allclose(phasor_to_sym(np.array([va, vb, vc])), expected) - assert np.allclose(phasor_to_sym(np.array([[va], [vb], [vc]])), expected) + assert np.allclose(phasor_to_sym(np.array([[va], [vb], [vc]])), expected.reshape((3, 1))) # Test balanced indirect system: negative sequence - expected = np.array([[0], [0], [230]], dtype=complex) + expected = np.array([0, 0, 230], dtype=complex) assert np.allclose(phasor_to_sym([va, vc, vb]), expected) # Test unbalanced system: zero sequence - expected = np.array([[230], [0], [0]], dtype=complex) + expected = np.array([230, 0, 0], dtype=complex) assert np.allclose(phasor_to_sym([va, va, va]), expected) # Test unbalanced system: general case va = 200 + 0j - expected = np.array([[10 * np.e ** (1j * np.pi)], [220], [10 * np.e ** (1j * np.pi)]], dtype=complex) + expected = np.array([10 * np.exp(1j * np.pi), 220, 10 * np.exp(1j * np.pi)], dtype=complex) assert np.allclose(phasor_to_sym([va, vb, vc]), expected) @@ -40,23 +40,23 @@ def test_sym_to_phasor(): vc = 230 * np.e ** (1j * 2 * np.pi / 3) # Test balanced direct system: positive sequence - expected = np.array([[va], [vb], [vc]], dtype=complex) + expected = np.array([va, vb, vc], dtype=complex) assert np.allclose(sym_to_phasor([0, va, 0]), expected) # Also test numpy array input with different shapes assert np.allclose(sym_to_phasor(np.array([0, va, 0])), expected) - assert np.allclose(sym_to_phasor(np.array([[0], [va], [0]])), expected) + assert np.allclose(sym_to_phasor(np.array([[0], [va], [0]])), expected.reshape((3, 1))) # Test balanced indirect system: negative sequence - expected = np.array([[va], [vc], [vb]], dtype=complex) + expected = np.array([va, vc, vb], dtype=complex) assert np.allclose(sym_to_phasor([0, 0, va]), expected) # Test unbalanced system: zero sequence - expected = np.array([[va], [va], [va]], dtype=complex) + expected = np.array([va, va, va], dtype=complex) assert np.allclose(sym_to_phasor([va, 0, 0]), expected) # Test unbalanced system: general case va = 200 + 0j - expected = np.array([[va], [vb], [vc]], dtype=complex) + expected = np.array([va, vb, vc], dtype=complex) assert np.allclose(sym_to_phasor([10 * np.e ** (1j * np.pi), 220, 10 * np.e ** (1j * np.pi)]), expected) @@ -66,17 +66,17 @@ def test_phasor_sym_roundtrip(): vc = 230 * np.e ** (1j * 2 * np.pi / 3) # Test balanced direct system: positive sequence - assert np.allclose(sym_to_phasor(phasor_to_sym([va, vb, vc])), np.array([[va], [vb], [vc]])) + assert np.allclose(sym_to_phasor(phasor_to_sym([va, vb, vc])), np.array([va, vb, vc])) # Test balanced indirect system: negative sequence - assert np.allclose(sym_to_phasor(phasor_to_sym([va, vc, vb])), np.array([[va], [vc], [vb]])) + assert np.allclose(sym_to_phasor(phasor_to_sym([va, vc, vb])), np.array([va, vc, vb])) # Test unbalanced system: zero sequence - assert np.allclose(sym_to_phasor(phasor_to_sym([va, va, va])), np.array([[va], [va], [va]])) + assert np.allclose(sym_to_phasor(phasor_to_sym([va, va, va])), np.array([va, va, va])) # Test unbalanced system: general case va = 200 + 0j - assert np.allclose(sym_to_phasor(phasor_to_sym([va, vb, vc])), np.array([[va], [vb], [vc]])) + assert np.allclose(sym_to_phasor(phasor_to_sym([va, vb, vc])), np.array([va, vb, vc])) def test_series_phasor_to_sym(): From 64ee52bdaa1fc537755475c06827568e8f2f2470 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Thu, 2 Nov 2023 17:01:18 +0100 Subject: [PATCH 34/43] Make the installation page more beginner friendly (#143) Closes #140 --- doc/Installation.md | 95 +++++++++++++++++++++++++++++++++++++-------- doc/conf.py | 3 ++ pyproject.toml | 1 + 3 files changed, 82 insertions(+), 17 deletions(-) diff --git a/doc/Installation.md b/doc/Installation.md index 5e86a8e7..163cf59f 100644 --- a/doc/Installation.md +++ b/doc/Installation.md @@ -1,43 +1,67 @@ # Installation -## Using `pip` +Please select one of the following installation methods that best suits your workflow. + +```{note} +If you are a beginner in Python, please note that the commands below must be executed in a +**terminal**, not in the _Python console_. This is indicated by the `$` or `C:>` prompt as opposed +to the Python console prompt `>>>`. +``` + +## 1. Using `pip` `roseau-load-flow` is available on [PyPI](https://pypi.org/project/roseau-load-flow/). It can be installed using pip with: -```console -$ python -m pip install roseau-load-flow +````{tab} Windows + +```doscon +C:> python -m pip install roseau-load-flow ``` -`````{tip} -It is recommended to work in a virtual environment to isolate your project. You can create one with: +```` + +````{tab} Linux/MacOS ```console -$ python -m venv venv +$ python -m pip install roseau-load-flow ``` -A folder named `venv` will be created. To activate the virtual environment, run: +```` + +`````{tip} +It is recommended to work in a virtual environment to isolate your project. Create and activate a virtual environment before installing the package. You can create one with: ````{tab} Windows ```doscon -C:> venv\Scripts\activate +C:> python -m venv .venv ``` ```` -````{tab} Linux +````{tab} Linux/MacOS ```console -$ source venv/bin/activate +$ python -m venv .venv +``` + +```` + +A folder named `.venv` will be created. To activate the virtual environment, run: + +````{tab} Windows + +```doscon +C:> .venv\Scripts\activate ``` ```` -````{tab} MacOS +````{tab} Linux/MacOS ```console -$ . venv/bin/activate +$ source .venv/bin/activate ``` ```` @@ -46,26 +70,63 @@ $ . venv/bin/activate To upgrade to the latest version (recommended), use: +````{tab} Windows + +```doscon +C:> python -m pip install --upgrade roseau-load-flow +``` + +```` + +````{tab} Linux/MacOS + ```console $ python -m pip install --upgrade roseau-load-flow ``` -Moreover, using the `pip` installation, some plot functions requires additional dependencies that are not installed by -default. If you need these functions, you can install the `plot` extra using +```` -```console -$ python -m pip install roseau-load-flow[plot] +Optional dependencies can be installed using the available extras. These are only needed if you use +the corresponding functions. They can be installed with the +`python -m pip install roseau-load-flow[EXTRA]` command where `EXTRA` is one of the following: + +1. `plot`: installs _matplotlib_ for the plotting functions +2. `graph` installs _networkx_ for graph theory analysis functions + +## 2. Using `pip` in Jupyter Notebooks + +If you are using Jupyter Notebooks, you can install `roseau-load-flow` directly from a notebook +cell with: + +```ipython3 +In [1]: %pip install roseau-load-flow ``` -## Using `conda` +This installs the package in the correct environment for the active notebook kernel. + +## 3. Using `conda` `roseau-load-flow` is also available on [conda-forge](https://anaconda.org/conda-forge/roseau-load-flow). It can be installed using conda with: +````{tab} Windows + +```doscon +C:> conda install -c conda-forge roseau-load-flow +``` + +```` + +````{tab} Linux/MacOS + ```console $ conda install -c conda-forge roseau-load-flow ``` +```` + +This installs the package and all its required and optional dependencies. + ```{tip} If you use *conda* to manage your project, it is recommended to use the `conda` package manager instead of `pip`. diff --git a/doc/conf.py b/doc/conf.py index df28633d..6dc536fa 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -137,6 +137,9 @@ # -- Options for sphinx_copybutton ------------------------------------------- copybutton_exclude = ".linenos, .gp, .go" copybutton_copy_empty_lines = False +# https://sphinx-copybutton.readthedocs.io/en/latest/use.html#strip-and-configure-input-prompts-for-code-cells +copybutton_prompt_text = r">>> |\.\.\. |\$ |C:> |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " +copybutton_prompt_is_regexp = True # -- Options for sphinxcontrib.googleanalytics ------------------------------- googleanalytics_id = "G-Y9QSN78RFV" diff --git a/pyproject.toml b/pyproject.toml index a4458a3d..caf66abd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ matplotlib = { version = ">=3.7.2", optional = true } networkx = { version = ">=3.0.0", optional = true } [tool.poetry.extras] +# DO NOT forget to update the installation page in the documentation when extras change plot = ["matplotlib"] graph = ["networkx"] From 790deac1c2f3b1e99b5d8af84129d5336600c042 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Thu, 2 Nov 2023 20:07:49 +0100 Subject: [PATCH 35/43] Fix typing of numpy arrays (#144) This PR fixes all annotations of numpy array and makes it explicit what type of array a function expects/returns. We were using invalid numpy array annotations in some places and didn't precise the type of the array in other places. To properly type numpy array one needs to write this notation `np.ndarray[Any, np.dtype[np.complex_]]` where the first type is the shape of the array and the second is its type. This is not practical and is why numpy introduced `numpy.typing.NDArray` which can be simply used like `NDArray[np.complex_]`. Because we use this type a lot, I added a type alias. --- roseau/load_flow/converters.py | 8 ++-- roseau/load_flow/models/branches.py | 20 +++++----- roseau/load_flow/models/buses.py | 16 ++++---- roseau/load_flow/models/lines/lines.py | 30 +++++++-------- roseau/load_flow/models/lines/parameters.py | 16 +++++--- .../models/loads/flexible_parameters.py | 37 +++++++++++-------- roseau/load_flow/models/loads/loads.py | 34 ++++++++--------- roseau/load_flow/models/sources.py | 18 ++++----- roseau/load_flow/typing.py | 22 +++++++++-- 9 files changed, 114 insertions(+), 87 deletions(-) diff --git a/roseau/load_flow/converters.py b/roseau/load_flow/converters.py index 6f5c57d0..26508bcf 100644 --- a/roseau/load_flow/converters.py +++ b/roseau/load_flow/converters.py @@ -11,6 +11,8 @@ import numpy as np import pandas as pd +from roseau.load_flow.typing import ComplexArray + ALPHA = np.exp(2 / 3 * np.pi * 1j) """complex: Phasor rotation operator `alpha`, which rotates a phasor vector counterclockwise by 120 degrees when multiplied by it.""" @@ -28,7 +30,7 @@ _A_INV = np.linalg.inv(A) -def phasor_to_sym(v_abc: Sequence[complex]) -> np.ndarray[complex]: +def phasor_to_sym(v_abc: Sequence[complex]) -> ComplexArray: """Compute the symmetrical components `(0, +, -)` from the phasor components `(a, b, c)`.""" v_abc_array = np.asarray(v_abc) orig_shape = v_abc_array.shape @@ -36,7 +38,7 @@ def phasor_to_sym(v_abc: Sequence[complex]) -> np.ndarray[complex]: return v_012.reshape(orig_shape) -def sym_to_phasor(v_012: Sequence[complex]) -> np.ndarray[complex]: +def sym_to_phasor(v_012: Sequence[complex]) -> ComplexArray: """Compute the phasor components `(a, b, c)` from the symmetrical components `(0, +, -)`.""" v_012_array = np.asarray(v_012) orig_shape = v_012_array.shape @@ -107,7 +109,7 @@ def series_phasor_to_sym(s_abc: pd.Series) -> pd.Series: return s_012 -def calculate_voltages(potentials: np.ndarray, phases: str) -> np.ndarray: +def calculate_voltages(potentials: ComplexArray, phases: str) -> ComplexArray: """Calculate the voltages between phases given the potentials of each phase. Args: diff --git a/roseau/load_flow/models/branches.py b/roseau/load_flow/models/branches.py index 08459e75..2aac6a0d 100644 --- a/roseau/load_flow/models/branches.py +++ b/roseau/load_flow/models/branches.py @@ -8,7 +8,7 @@ from roseau.load_flow.converters import calculate_voltages from roseau.load_flow.models.buses import Bus from roseau.load_flow.models.core import Element -from roseau.load_flow.typing import Id, JsonDict +from roseau.load_flow.typing import ComplexArray, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -66,7 +66,7 @@ def __init__( self.bus2 = bus2 self.geometry = geometry self._connect(bus1, bus2) - self._res_currents: Optional[tuple[np.ndarray, np.ndarray]] = None + self._res_currents: Optional[tuple[ComplexArray, ComplexArray]] = None def __repr__(self) -> str: s = f"{type(self).__name__}(id={self.id!r}, phases1={self.phases1!r}, phases2={self.phases2!r}" @@ -76,16 +76,16 @@ def __repr__(self) -> str: s += ")" return s - def _res_currents_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: + def _res_currents_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray]: return self._res_getter(value=self._res_currents, warning=warning) @property @ureg_wraps(("A", "A"), (None,), strict=False) - def res_currents(self) -> tuple[Q_[np.ndarray], Q_[np.ndarray]]: + def res_currents(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch currents (A).""" return self._res_currents_getter(warning=True) - def _res_powers_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: + def _res_powers_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray]: cur1, cur2 = self._res_currents_getter(warning) pot1, pot2 = self._res_potentials_getter(warning=False) # we warn on the previous line powers1 = pot1 * cur1.conj() @@ -94,28 +94,28 @@ def _res_powers_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: @property @ureg_wraps(("VA", "VA"), (None,), strict=False) - def res_powers(self) -> tuple[Q_[np.ndarray], Q_[np.ndarray]]: + def res_powers(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch powers (VA).""" return self._res_powers_getter(warning=True) - def _res_potentials_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: + def _res_potentials_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray]: pot1 = self.bus1._get_potentials_of(self.phases1, warning) pot2 = self.bus2._get_potentials_of(self.phases2, warning=False) # we warn on the previous line return pot1, pot2 @property @ureg_wraps(("V", "V"), (None,), strict=False) - def res_potentials(self) -> tuple[Q_[np.ndarray], Q_[np.ndarray]]: + def res_potentials(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch potentials (V).""" return self._res_potentials_getter(warning=True) - def _res_voltages_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: + def _res_voltages_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray]: pot1, pot2 = self._res_potentials_getter(warning) return calculate_voltages(pot1, self.phases1), calculate_voltages(pot2, self.phases2) @property @ureg_wraps(("V", "V"), (None,), strict=False) - def res_voltages(self) -> tuple[Q_[np.ndarray], Q_[np.ndarray]]: + def res_voltages(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch voltages (V).""" return self._res_voltages_getter(warning=True) diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index 928ff1e1..10aad31b 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -10,7 +10,7 @@ from roseau.load_flow.converters import calculate_voltage_phases, calculate_voltages, phasor_to_sym from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.models.core import Element -from roseau.load_flow.typing import Id, JsonDict +from roseau.load_flow.typing import ComplexArray, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -79,7 +79,7 @@ def __init__( self.min_voltage = min_voltage self.max_voltage = max_voltage - self._res_potentials: Optional[np.ndarray] = None + self._res_potentials: Optional[ComplexArray] = None self._short_circuits: list[dict[str, Any]] = [] def __repr__(self) -> str: @@ -87,7 +87,7 @@ def __repr__(self) -> str: @property @ureg_wraps("V", (None,), strict=False) - def potentials(self) -> Q_[np.ndarray]: + def potentials(self) -> Q_[ComplexArray]: """The potentials of the bus (V).""" return self._potentials @@ -101,22 +101,22 @@ def potentials(self, value: Sequence[complex]) -> None: self._potentials = np.asarray(value, dtype=complex) self._invalidate_network_results() - def _res_potentials_getter(self, warning: bool) -> np.ndarray: + def _res_potentials_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_potentials, warning=warning) @property @ureg_wraps("V", (None,), strict=False) - def res_potentials(self) -> Q_[np.ndarray]: + def res_potentials(self) -> Q_[ComplexArray]: """The load flow result of the bus potentials (V).""" return self._res_potentials_getter(warning=True) - def _res_voltages_getter(self, warning: bool) -> np.ndarray: + def _res_voltages_getter(self, warning: bool) -> ComplexArray: potentials = np.asarray(self._res_potentials_getter(warning=warning)) return calculate_voltages(potentials, self.phases) @property @ureg_wraps("V", (None,), strict=False) - def res_voltages(self) -> Q_[np.ndarray]: + def res_voltages(self) -> Q_[ComplexArray]: """The load flow result of the bus voltages (V). If the bus has a neutral, the voltages are phase-neutral voltages for existing phases in @@ -130,7 +130,7 @@ def voltage_phases(self) -> list[str]: """The phases of the voltages.""" return calculate_voltage_phases(self.phases) - def _get_potentials_of(self, phases: str, warning: bool) -> np.ndarray: + def _get_potentials_of(self, phases: str, warning: bool) -> ComplexArray: """Get the potentials of the given phases.""" potentials = self._res_potentials_getter(warning) return np.array([potentials[self.phases.index(p)] for p in phases]) diff --git a/roseau/load_flow/models/lines/lines.py b/roseau/load_flow/models/lines/lines.py index 606a55c5..2c7aee71 100644 --- a/roseau/load_flow/models/lines/lines.py +++ b/roseau/load_flow/models/lines/lines.py @@ -12,7 +12,7 @@ from roseau.load_flow.models.grounds import Ground from roseau.load_flow.models.lines.parameters import LineParameters from roseau.load_flow.models.sources import VoltageSource -from roseau.load_flow.typing import Id, JsonDict +from roseau.load_flow.typing import ComplexArray, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -275,13 +275,13 @@ def parameters(self, value: LineParameters) -> None: @property @ureg_wraps("ohm", (None,), strict=False) - def z_line(self) -> Q_[np.ndarray]: + def z_line(self) -> Q_[ComplexArray]: """Impedance of the line in Ohm""" return self.parameters._z_line * self._length @property @ureg_wraps("S", (None,), strict=False) - def y_shunt(self) -> Q_[np.ndarray]: + def y_shunt(self) -> Q_[ComplexArray]: """Shunt admittance of the line in Siemens""" return self.parameters._y_shunt * self._length @@ -296,33 +296,33 @@ def max_current(self) -> Optional[Q_[float]]: def with_shunt(self) -> bool: return self.parameters.with_shunt - def _res_series_values_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: + def _res_series_values_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray]: pot1, pot2 = self._res_potentials_getter(warning) # V du_line = pot1 - pot2 i_line = np.linalg.inv(self.z_line.m_as("ohm")) @ du_line # Zₗ x Iₗ = ΔU -> I = Zₗ⁻¹ x ΔU return du_line, i_line - def _res_series_currents_getter(self, warning: bool) -> np.ndarray: + def _res_series_currents_getter(self, warning: bool) -> ComplexArray: _, i_line = self._res_series_values_getter(warning) return i_line @property @ureg_wraps("A", (None,), strict=False) - def res_series_currents(self) -> Q_[np.ndarray]: + def res_series_currents(self) -> Q_[ComplexArray]: """Get the current in the series elements of the line (A).""" return self._res_series_currents_getter(warning=True) - def _res_series_power_losses_getter(self, warning: bool) -> np.ndarray: + def _res_series_power_losses_getter(self, warning: bool) -> ComplexArray: du_line, i_line = self._res_series_values_getter(warning) return du_line * i_line.conj() # Sₗ = ΔU.Iₗ* @property @ureg_wraps("VA", (None,), strict=False) - def res_series_power_losses(self) -> Q_[np.ndarray]: + def res_series_power_losses(self) -> Q_[ComplexArray]: """Get the power losses in the series elements of the line (VA).""" return self._res_series_power_losses_getter(warning=True) - def _res_shunt_values_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: + def _res_shunt_values_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray, ComplexArray, ComplexArray]: assert self.with_shunt, "This method only works when there is a shunt" assert self.ground is not None pot1, pot2 = self._res_potentials_getter(warning) @@ -333,7 +333,7 @@ def _res_shunt_values_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarra i2_shunt = (y_shunt @ pot2 - yg * vg) / 2 return pot1, pot2, i1_shunt, i2_shunt - def _res_shunt_currents_getter(self, warning: bool) -> tuple[np.ndarray, np.ndarray]: + def _res_shunt_currents_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray]: if not self.with_shunt: zeros = np.zeros(len(self.phases), dtype=complex) return zeros[:], zeros[:] @@ -342,11 +342,11 @@ def _res_shunt_currents_getter(self, warning: bool) -> tuple[np.ndarray, np.ndar @property @ureg_wraps(("A", "A"), (None,), strict=False) - def res_shunt_currents(self) -> tuple[Q_[np.ndarray], Q_[np.ndarray]]: + def res_shunt_currents(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """Get the currents in the shunt elements of the line (A).""" return self._res_shunt_currents_getter(warning=True) - def _res_shunt_power_losses_getter(self, warning: bool) -> np.ndarray: + def _res_shunt_power_losses_getter(self, warning: bool) -> ComplexArray: if not self.with_shunt: return np.zeros(len(self.phases), dtype=complex) pot1, pot2, cur1, cur2 = self._res_shunt_values_getter(warning) @@ -354,18 +354,18 @@ def _res_shunt_power_losses_getter(self, warning: bool) -> np.ndarray: @property @ureg_wraps("VA", (None,), strict=False) - def res_shunt_power_losses(self) -> Q_[np.ndarray]: + def res_shunt_power_losses(self) -> Q_[ComplexArray]: """Get the power losses in the shunt elements of the line (VA).""" return self._res_shunt_power_losses_getter(warning=True) - def _res_power_losses_getter(self, warning: bool) -> np.ndarray: + def _res_power_losses_getter(self, warning: bool) -> ComplexArray: series_losses = self._res_series_power_losses_getter(warning) shunt_losses = self._res_shunt_power_losses_getter(warning=False) # we warn on the previous line return series_losses + shunt_losses @property @ureg_wraps("VA", (None,), strict=False) - def res_power_losses(self) -> Q_[np.ndarray]: + def res_power_losses(self) -> Q_[ComplexArray]: """Get the power losses in the line (VA).""" return self._res_power_losses_getter(warning=True) diff --git a/roseau/load_flow/models/lines/parameters.py b/roseau/load_flow/models/lines/parameters.py index fad31cad..a6294b2f 100644 --- a/roseau/load_flow/models/lines/parameters.py +++ b/roseau/load_flow/models/lines/parameters.py @@ -8,7 +8,7 @@ from typing_extensions import Self from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.typing import Id, JsonDict +from roseau.load_flow.typing import ComplexArray, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps from roseau.load_flow.utils import ( CX, @@ -41,7 +41,11 @@ class LineParameters(Identifiable, JsonMixin): @ureg_wraps(None, (None, None, "ohm/km", "S/km", "A"), strict=False) def __init__( - self, id: Id, z_line: np.ndarray, y_shunt: Optional[np.ndarray] = None, max_current: Optional[float] = None + self, + id: Id, + z_line: ComplexArray, + y_shunt: Optional[ComplexArray] = None, + max_current: Optional[float] = None, ) -> None: """LineParameters constructor. @@ -89,12 +93,12 @@ def __eq__(self, other: object) -> bool: @property @ureg_wraps("ohm/km", (None,), strict=False) - def z_line(self) -> Q_[np.ndarray]: + def z_line(self) -> Q_[ComplexArray]: return self._z_line @property @ureg_wraps("S/km", (None,), strict=False) - def y_shunt(self) -> Q_[np.ndarray]: + def y_shunt(self) -> Q_[ComplexArray]: return self._y_shunt @property @@ -183,7 +187,7 @@ def _sym_to_zy( xpn: Optional[float] = None, bn: Optional[float] = None, bpn: Optional[float] = None, - ) -> tuple[np.ndarray, np.ndarray]: + ) -> tuple[ComplexArray, ComplexArray]: """Create impedance and admittance matrix from a symmetrical model. Args: @@ -364,7 +368,7 @@ def _geometry_to_zy( section_neutral: float, height: float, external_diameter: float, - ) -> tuple[np.ndarray, np.ndarray]: + ) -> tuple[ComplexArray, ComplexArray]: """Create impedance and admittance matrix using a geometric model. Args: diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index 668886bc..b92ffc3f 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -3,10 +3,11 @@ from typing import TYPE_CHECKING, NoReturn, Optional import numpy as np +from numpy.typing import NDArray from typing_extensions import Self from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.typing import Authentication, ControlType, JsonDict, ProjectionType +from roseau.load_flow.typing import Authentication, ComplexArray, ControlType, JsonDict, ProjectionType from roseau.load_flow.units import Q_, ureg_wraps from roseau.load_flow.utils import JsonMixin, _optional_deps @@ -963,8 +964,12 @@ def results_from_dict(self, data: JsonDict) -> NoReturn: # @ureg_wraps("VA", (None, None, "V", "VA", None), strict=False) def compute_powers( - self, auth: Authentication, voltages: np.ndarray[float], power: complex, solve_kwargs: Optional[JsonDict] = None - ) -> Q_[np.ndarray[complex]]: + self, + auth: Authentication, + voltages: NDArray[np.float_], + power: complex, + solve_kwargs: Optional[JsonDict] = None, + ) -> Q_[ComplexArray]: """Compute the flexible powers for different voltages (norms) Args: @@ -986,8 +991,8 @@ def compute_powers( return self._compute_powers(auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs) def _compute_powers( - self, auth: Authentication, voltages: np.ndarray[float], power: complex, solve_kwargs: Optional[JsonDict] - ) -> np.ndarray[complex]: + self, auth: Authentication, voltages: NDArray[np.float_], power: complex, solve_kwargs: Optional[JsonDict] + ) -> ComplexArray: from roseau.load_flow import Bus, ElectricalNetwork, PotentialRef, PowerLoad, VoltageSource # Format the input @@ -1016,13 +1021,13 @@ def _compute_powers( def plot_pq( self, auth: Authentication, - voltages: np.ndarray[float], + voltages: NDArray[np.float_], power: complex, ax: Optional["Axes"] = None, solve_kwargs: Optional[JsonDict] = None, - voltages_labels_mask: Optional[np.ndarray[bool]] = None, - res_flexible_powers: Optional[np.ndarray[complex]] = None, - ) -> tuple["Axes", np.ndarray[complex]]: + voltages_labels_mask: Optional[NDArray[np.bool_]] = None, + res_flexible_powers: Optional[ComplexArray] = None, + ) -> tuple["Axes", ComplexArray]: """Plot the "trajectory" of the flexible powers (in the (P, Q) plane) for the provided voltages and theoretical power. @@ -1129,12 +1134,12 @@ def plot_pq( def plot_control_p( self, auth: Authentication, - voltages: np.ndarray[float], + voltages: NDArray[np.float_], power: complex, ax: Optional["Axes"] = None, solve_kwargs: Optional[JsonDict] = None, - res_flexible_powers: Optional[np.ndarray[complex]] = None, - ) -> tuple["Axes", np.ndarray[complex]]: + res_flexible_powers: Optional[ComplexArray] = None, + ) -> tuple["Axes", ComplexArray]: """Plot the flexible active power consumed (or produced) for the provided voltages and theoretical power. Args: @@ -1195,12 +1200,12 @@ def plot_control_p( def plot_control_q( self, auth: Authentication, - voltages: np.ndarray[float], + voltages: NDArray[np.float_], power: complex, ax: Optional["Axes"] = None, solve_kwargs: Optional[JsonDict] = None, - res_flexible_powers: Optional[np.ndarray[complex]] = None, - ) -> tuple["Axes", np.ndarray[complex]]: + res_flexible_powers: Optional[ComplexArray] = None, + ) -> tuple["Axes", ComplexArray]: """Plot the flexible reactive power consumed (or produced) for the provided voltages and theoretical power. Args: @@ -1263,7 +1268,7 @@ def plot_control_q( @staticmethod def _theoretical_control_data( control: Control, v_min: float, v_max: float, power: float, s_max: float - ) -> tuple[np.ndarray[float], np.ndarray[float], np.ndarray[object]]: + ) -> tuple[NDArray[np.float_], NDArray[np.float_], NDArray[np.object_]]: """Helper to get data for the different plots of the class. It provides the theoretical control curve abscissas and ordinates values. It also provides ticks for the abscissa axis. diff --git a/roseau/load_flow/models/loads/loads.py b/roseau/load_flow/models/loads/loads.py index f4378243..fbe0e582 100644 --- a/roseau/load_flow/models/loads/loads.py +++ b/roseau/load_flow/models/loads/loads.py @@ -10,7 +10,7 @@ from roseau.load_flow.models.buses import Bus from roseau.load_flow.models.core import Element from roseau.load_flow.models.loads.flexible_parameters import FlexibleParameter -from roseau.load_flow.typing import Id, JsonDict +from roseau.load_flow.typing import ComplexArray, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -79,7 +79,7 @@ def __init__(self, id: Id, bus: Bus, *, phases: Optional[str] = None, **kwargs: self._size = len(set(phases) - {"n"}) # Results - self._res_currents: Optional[np.ndarray] = None + self._res_currents: Optional[ComplexArray] = None def __repr__(self) -> str: bus_id = self.bus.id if self.bus is not None else None @@ -95,16 +95,16 @@ def voltage_phases(self) -> list[str]: """The phases of the load voltages.""" return calculate_voltage_phases(self.phases) - def _res_currents_getter(self, warning: bool) -> np.ndarray: + def _res_currents_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_currents, warning=warning) @property @ureg_wraps("A", (None,), strict=False) - def res_currents(self) -> Q_[np.ndarray]: + def res_currents(self) -> Q_[ComplexArray]: """The load flow result of the load currents (A).""" return self._res_currents_getter(warning=True) - def _validate_value(self, value: Sequence[complex]) -> np.ndarray: + def _validate_value(self, value: Sequence[complex]) -> ComplexArray: if len(value) != self._size: msg = f"Incorrect number of {self._type}s: {len(value)} instead of {self._size}" logger.error(msg) @@ -118,34 +118,34 @@ def _validate_value(self, value: Sequence[complex]) -> np.ndarray: raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_Z_VALUE) return np.asarray(value, dtype=complex) - def _res_potentials_getter(self, warning: bool) -> np.ndarray: + def _res_potentials_getter(self, warning: bool) -> ComplexArray: self._raise_disconnected_error() return self.bus._get_potentials_of(self.phases, warning) @property @ureg_wraps("V", (None,), strict=False) - def res_potentials(self) -> Q_[np.ndarray]: + def res_potentials(self) -> Q_[ComplexArray]: """The load flow result of the load potentials (V).""" return self._res_potentials_getter(warning=True) - def _res_voltages_getter(self, warning: bool) -> np.ndarray: + def _res_voltages_getter(self, warning: bool) -> ComplexArray: potentials = self._res_potentials_getter(warning) return calculate_voltages(potentials, self.phases) @property @ureg_wraps("V", (None,), strict=False) - def res_voltages(self) -> Q_[np.ndarray]: + def res_voltages(self) -> Q_[ComplexArray]: """The load flow result of the load voltages (V).""" return self._res_voltages_getter(warning=True) - def _res_powers_getter(self, warning: bool) -> np.ndarray: + def _res_powers_getter(self, warning: bool) -> ComplexArray: curs = self._res_currents_getter(warning) pots = self._res_potentials_getter(warning=False) # we warn on the previous line return pots * curs.conj() @property @ureg_wraps("VA", (None,), strict=False) - def res_powers(self) -> Q_[np.ndarray]: + def res_powers(self) -> Q_[ComplexArray]: """The load flow result of the load powers (VA).""" return self._res_powers_getter(warning=True) @@ -254,7 +254,7 @@ def __init__( self._flexible_params = flexible_params self.powers = powers - self._res_flexible_powers: Optional[np.ndarray] = None + self._res_flexible_powers: Optional[ComplexArray] = None @property def flexible_params(self) -> Optional[list[FlexibleParameter]]: @@ -266,7 +266,7 @@ def is_flexible(self) -> bool: @property @ureg_wraps("VA", (None,), strict=False) - def powers(self) -> Q_[np.ndarray]: + def powers(self) -> Q_[ComplexArray]: """The powers of the load (VA).""" return self._powers @@ -305,12 +305,12 @@ def powers(self, value: Sequence[complex]) -> None: self._powers = value self._invalidate_network_results() - def _res_flexible_powers_getter(self, warning: bool) -> np.ndarray: + def _res_flexible_powers_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_flexible_powers, warning=warning) @property @ureg_wraps("VA", (None,), strict=False) - def res_flexible_powers(self) -> Q_[np.ndarray]: + def res_flexible_powers(self) -> Q_[ComplexArray]: """The load flow result of the load flexible powers (VA).""" return self._res_flexible_powers_getter(warning=True) @@ -375,7 +375,7 @@ def __init__( @property @ureg_wraps("A", (None,), strict=False) - def currents(self) -> Q_[np.ndarray]: + def currents(self) -> Q_[ComplexArray]: """The currents of the load (Amps).""" return self._currents @@ -426,7 +426,7 @@ def __init__( @property @ureg_wraps("ohm", (None,), strict=False) - def impedances(self) -> Q_[np.ndarray]: + def impedances(self) -> Q_[ComplexArray]: """The impedances of the load (Ohms).""" return self._impedances diff --git a/roseau/load_flow/models/sources.py b/roseau/load_flow/models/sources.py index 8f32e440..27492b13 100644 --- a/roseau/load_flow/models/sources.py +++ b/roseau/load_flow/models/sources.py @@ -9,7 +9,7 @@ from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.models.buses import Bus from roseau.load_flow.models.core import Element -from roseau.load_flow.typing import Id, JsonDict +from roseau.load_flow.typing import ComplexArray, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -74,7 +74,7 @@ def __init__( self.voltages = voltages # Results - self._res_currents: Optional[np.ndarray] = None + self._res_currents: Optional[ComplexArray] = None def __repr__(self) -> str: bus_id = self.bus.id if self.bus is not None else None @@ -85,7 +85,7 @@ def __repr__(self) -> str: @property @ureg_wraps("V", (None,), strict=False) - def voltages(self) -> Q_[np.ndarray]: + def voltages(self) -> Q_[ComplexArray]: """The voltages of the source (V).""" return self._voltages @@ -104,33 +104,33 @@ def voltage_phases(self) -> list[str]: """The phases of the source voltages.""" return calculate_voltage_phases(self.phases) - def _res_currents_getter(self, warning: bool) -> np.ndarray: + def _res_currents_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_currents, warning=warning) @property @ureg_wraps("A", (None,), strict=False) - def res_currents(self) -> Q_[np.ndarray]: + def res_currents(self) -> Q_[ComplexArray]: """The load flow result of the source currents (A).""" return self._res_currents_getter(warning=True) - def _res_potentials_getter(self, warning: bool) -> np.ndarray: + def _res_potentials_getter(self, warning: bool) -> ComplexArray: self._raise_disconnected_error() return self.bus._get_potentials_of(self.phases, warning) @property @ureg_wraps("V", (None,), strict=False) - def res_potentials(self) -> Q_[np.ndarray]: + def res_potentials(self) -> Q_[ComplexArray]: """The load flow result of the source potentials (V).""" return self._res_potentials_getter(warning=True) - def _res_powers_getter(self, warning: bool) -> np.ndarray: + def _res_powers_getter(self, warning: bool) -> ComplexArray: curs = self._res_currents_getter(warning) pots = self._res_potentials_getter(warning=False) # we warn on the previous line return pots * curs.conj() @property @ureg_wraps("VA", (None,), strict=False) - def res_powers(self) -> Q_[np.ndarray]: + def res_powers(self) -> Q_[ComplexArray]: """The load flow result of the source powers (VA).""" return self._res_powers_getter(warning=True) diff --git a/roseau/load_flow/typing.py b/roseau/load_flow/typing.py index 1e3f97a3..31a5cb33 100644 --- a/roseau/load_flow/typing.py +++ b/roseau/load_flow/typing.py @@ -28,10 +28,16 @@ .. class:: Authentication Valid authentication types. + +.. class:: ComplexArray + + A numpy array of complex numbers. """ import os from typing import Any, Literal, Union +import numpy as np +from numpy.typing import NDArray from requests.auth import HTTPBasicAuth from typing_extensions import TypeAlias @@ -42,6 +48,16 @@ ProjectionType: TypeAlias = Literal["euclidean", "keep_p", "keep_q"] Solver: TypeAlias = Literal["newton", "newton_goldstein"] Authentication: TypeAlias = Union[tuple[str, str], HTTPBasicAuth] - - -__all__ = ["Id", "JsonDict", "StrPath", "ControlType", "ProjectionType", "Solver", "Authentication"] +ComplexArray: TypeAlias = NDArray[np.complex_] + + +__all__ = [ + "Id", + "JsonDict", + "StrPath", + "ControlType", + "ProjectionType", + "Solver", + "Authentication", + "ComplexArray", +] From c30202a139fd68a6a89c01c2621eea990be47c4d Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Fri, 17 Nov 2023 10:43:15 +0200 Subject: [PATCH 36/43] Improve the typing of pint wrapped method (#147) This PR improves the user facing types of parameters of methods wrapped with pint wrappers. Inside the methods, the types of parameters that accept either a quantity or a unitless value become incorrect but users of these methods now get the correct types. This means we accept a little bit of wrong types in our internal code for the benefit of our users. Until the Python type system have a "Map" type support, this is our best option. --- roseau/load_flow/converters.py | 12 +- roseau/load_flow/models/branches.py | 4 +- roseau/load_flow/models/buses.py | 29 +-- roseau/load_flow/models/lines/lines.py | 10 +- roseau/load_flow/models/lines/parameters.py | 89 ++++----- .../models/loads/flexible_parameters.py | 172 ++++++++++-------- roseau/load_flow/models/loads/loads.py | 32 ++-- roseau/load_flow/models/sources.py | 18 +- .../load_flow/models/tests/test_branches.py | 4 +- .../models/transformers/parameters.py | 18 +- roseau/load_flow/network.py | 43 +++-- roseau/load_flow/typing.py | 55 +++++- roseau/load_flow/units.py | 13 +- 13 files changed, 287 insertions(+), 212 deletions(-) diff --git a/roseau/load_flow/converters.py b/roseau/load_flow/converters.py index 26508bcf..1ebeafe3 100644 --- a/roseau/load_flow/converters.py +++ b/roseau/load_flow/converters.py @@ -23,7 +23,7 @@ [1, ALPHA**2, ALPHA], [1, ALPHA, ALPHA**2], ], - dtype=complex, + dtype=np.complex128, ) """numpy.ndarray[complex]: "A" matrix: transformation matrix from phasor to symmetrical components.""" @@ -32,7 +32,7 @@ def phasor_to_sym(v_abc: Sequence[complex]) -> ComplexArray: """Compute the symmetrical components `(0, +, -)` from the phasor components `(a, b, c)`.""" - v_abc_array = np.asarray(v_abc) + v_abc_array = np.array(v_abc) orig_shape = v_abc_array.shape v_012 = _A_INV @ v_abc_array.reshape((3, 1)) return v_012.reshape(orig_shape) @@ -40,7 +40,7 @@ def phasor_to_sym(v_abc: Sequence[complex]) -> ComplexArray: def sym_to_phasor(v_012: Sequence[complex]) -> ComplexArray: """Compute the phasor components `(a, b, c)` from the symmetrical components `(0, +, -)`.""" - v_012_array = np.asarray(v_012) + v_012_array = np.array(v_012) orig_shape = v_012_array.shape v_abc = A @ v_012_array.reshape((3, 1)) return v_abc.reshape(orig_shape) @@ -124,13 +124,13 @@ def calculate_voltages(potentials: ComplexArray, phases: str) -> ComplexArray: Otherwise, the voltages are Phase-Phase. Example: - >>> potentials = 230 * np.array([1, np.exp(-2j*np.pi/3), np.exp(2j*np.pi/3), 0], dtype=complex) + >>> potentials = 230 * np.array([1, np.exp(-2j*np.pi/3), np.exp(2j*np.pi/3), 0], dtype=np.complex128) >>> calculate_voltages(potentials, "abcn") array([ 230. +0.j , -115.-199.18584287j, -115.+199.18584287j]) - >>> potentials = np.array([230, 230 * np.exp(-2j*np.pi/3)], dtype=complex) + >>> potentials = np.array([230, 230 * np.exp(-2j*np.pi/3)], dtype=np.complex128) >>> calculate_voltages(potentials, "ab") array([345.+199.18584287j]) - >>> calculate_voltages(np.array([230, 0], dtype=complex), "an") + >>> calculate_voltages(np.array([230, 0], dtype=np.complex128), "an") array([230.+0.j]) """ assert len(potentials) == len(phases), "Number of potentials must match number of phases." diff --git a/roseau/load_flow/models/branches.py b/roseau/load_flow/models/branches.py index 2aac6a0d..6e515fee 100644 --- a/roseau/load_flow/models/branches.py +++ b/roseau/load_flow/models/branches.py @@ -140,8 +140,8 @@ def to_dict(self, *, _lf_only: bool = False) -> JsonDict: return res def results_from_dict(self, data: JsonDict) -> None: - currents1 = np.array([complex(i[0], i[1]) for i in data["currents1"]], dtype=complex) - currents2 = np.array([complex(i[0], i[1]) for i in data["currents2"]], dtype=complex) + currents1 = np.array([complex(i[0], i[1]) for i in data["currents1"]], dtype=np.complex128) + currents2 = np.array([complex(i[0], i[1]) for i in data["currents2"]], dtype=np.complex128) self._res_currents = (currents1, currents2) def _results_to_dict(self, warning: bool) -> JsonDict: diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index 10aad31b..e2347db7 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -1,6 +1,6 @@ import logging -from collections.abc import Iterator, Sequence -from typing import TYPE_CHECKING, Any, Optional +from collections.abc import Iterator +from typing import TYPE_CHECKING, Any, Optional, Union import numpy as np import pandas as pd @@ -10,7 +10,7 @@ from roseau.load_flow.converters import calculate_voltage_phases, calculate_voltages, phasor_to_sym from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.models.core import Element -from roseau.load_flow.typing import ComplexArray, Id, JsonDict +from roseau.load_flow.typing import ComplexArray, ComplexArrayLike1D, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -36,7 +36,7 @@ def __init__( *, phases: str, geometry: Optional[Point] = None, - potentials: Optional[Sequence[complex]] = None, + potentials: Optional[ComplexArrayLike1D] = None, min_voltage: Optional[float] = None, max_voltage: Optional[float] = None, **kwargs: Any, @@ -57,15 +57,20 @@ def __init__( x-y coordinates of the bus. potentials: - An optional list of initial potentials of each phase of the bus. + An optional array-like of initial potentials of each phase of the bus. If given, + these potentials are used as the starting point of the load flow computation. + Either complex values (V) or a :class:`Quantity ` of + complex values. min_voltage: An optional minimum voltage of the bus (V). It is not used in the load flow. It must be a phase-neutral voltage if the bus has a neutral, phase-phase otherwise. + Either a float (V) or a :class:`Quantity ` of float. max_voltage: An optional maximum voltage of the bus (V). It is not used in the load flow. It must be a phase-neutral voltage if the bus has a neutral, phase-phase otherwise. + Either a float (V) or a :class:`Quantity ` of float. """ super().__init__(id, **kwargs) self._check_phases(id, phases=phases) @@ -88,17 +93,17 @@ def __repr__(self) -> str: @property @ureg_wraps("V", (None,), strict=False) def potentials(self) -> Q_[ComplexArray]: - """The potentials of the bus (V).""" + """An array of initial potentials of the bus (V).""" return self._potentials @potentials.setter @ureg_wraps(None, (None, "V"), strict=False) - def potentials(self, value: Sequence[complex]) -> None: + def potentials(self, value: ComplexArrayLike1D) -> None: if len(value) != len(self.phases): msg = f"Incorrect number of potentials: {len(value)} instead of {len(self.phases)}" logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_POTENTIALS_SIZE) - self._potentials = np.asarray(value, dtype=complex) + self._potentials = np.array(value, dtype=np.complex128) self._invalidate_network_results() def _res_potentials_getter(self, warning: bool) -> ComplexArray: @@ -111,7 +116,7 @@ def res_potentials(self) -> Q_[ComplexArray]: return self._res_potentials_getter(warning=True) def _res_voltages_getter(self, warning: bool) -> ComplexArray: - potentials = np.asarray(self._res_potentials_getter(warning=warning)) + potentials = np.array(self._res_potentials_getter(warning=warning)) return calculate_voltages(potentials, self.phases) @property @@ -142,7 +147,7 @@ def min_voltage(self) -> Optional[Q_[float]]: @min_voltage.setter @ureg_wraps(None, (None, "V"), strict=False) - def min_voltage(self, value: Optional[float]) -> None: + def min_voltage(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and self._max_voltage is not None and value > self._max_voltage: msg = ( f"Cannot set min voltage of bus {self.id!r} to {value} V as it is higher than its " @@ -161,7 +166,7 @@ def max_voltage(self) -> Optional[Q_[float]]: @max_voltage.setter @ureg_wraps(None, (None, "V"), strict=False) - def max_voltage(self, value: Optional[float]) -> None: + def max_voltage(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and self._min_voltage is not None and value < self._min_voltage: msg = ( f"Cannot set max voltage of bus {self.id!r} to {value} V as it is lower than its " @@ -334,7 +339,7 @@ def to_dict(self, *, _lf_only: bool = False) -> JsonDict: return res def results_from_dict(self, data: JsonDict) -> None: - self._res_potentials = np.array([complex(v[0], v[1]) for v in data["potentials"]], dtype=complex) + self._res_potentials = np.array([complex(v[0], v[1]) for v in data["potentials"]], dtype=np.complex128) def _results_to_dict(self, warning: bool) -> JsonDict: return { diff --git a/roseau/load_flow/models/lines/lines.py b/roseau/load_flow/models/lines/lines.py index 2c7aee71..3fe052af 100644 --- a/roseau/load_flow/models/lines/lines.py +++ b/roseau/load_flow/models/lines/lines.py @@ -1,6 +1,6 @@ import logging import warnings -from typing import Any, Optional +from typing import Any, Optional, Union import numpy as np from shapely import LineString, Point @@ -144,7 +144,7 @@ def __init__( bus2: Bus, *, parameters: LineParameters, - length: float, + length: Union[float, Q_[float]], phases: Optional[str] = None, ground: Optional[Ground] = None, geometry: Optional[LineString] = None, @@ -231,7 +231,7 @@ def length(self) -> Q_[float]: @length.setter @ureg_wraps(None, (None, "km"), strict=False) - def length(self, value: float) -> None: + def length(self, value: Union[float, Q_[float]]) -> None: if value <= 0: msg = f"A line length must be greater than 0. {value:.2f} km provided." logger.error(msg) @@ -335,7 +335,7 @@ def _res_shunt_values_getter(self, warning: bool) -> tuple[ComplexArray, Complex def _res_shunt_currents_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray]: if not self.with_shunt: - zeros = np.zeros(len(self.phases), dtype=complex) + zeros = np.zeros(len(self.phases), dtype=np.complex128) return zeros[:], zeros[:] _, _, cur1, cur2 = self._res_shunt_values_getter(warning) return cur1, cur2 @@ -348,7 +348,7 @@ def res_shunt_currents(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: def _res_shunt_power_losses_getter(self, warning: bool) -> ComplexArray: if not self.with_shunt: - return np.zeros(len(self.phases), dtype=complex) + return np.zeros(len(self.phases), dtype=np.complex128) pot1, pot2, cur1, cur2 = self._res_shunt_values_getter(warning) return pot1 * cur1.conj() + pot2 * cur2.conj() diff --git a/roseau/load_flow/models/lines/parameters.py b/roseau/load_flow/models/lines/parameters.py index a6294b2f..53a0f68f 100644 --- a/roseau/load_flow/models/lines/parameters.py +++ b/roseau/load_flow/models/lines/parameters.py @@ -1,6 +1,6 @@ import logging import re -from typing import NoReturn, Optional +from typing import NoReturn, Optional, Union import numpy as np import numpy.linalg as nplin @@ -8,7 +8,7 @@ from typing_extensions import Self from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.typing import ComplexArray, Id, JsonDict +from roseau.load_flow.typing import ComplexArray, ComplexArrayLike2D, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps from roseau.load_flow.utils import ( CX, @@ -43,8 +43,8 @@ class LineParameters(Identifiable, JsonMixin): def __init__( self, id: Id, - z_line: ComplexArray, - y_shunt: Optional[ComplexArray] = None, + z_line: ComplexArrayLike2D, + y_shunt: Optional[ComplexArrayLike2D] = None, max_current: Optional[float] = None, ) -> None: """LineParameters constructor. @@ -63,13 +63,13 @@ def __init__( An optional maximum current loading of the line (A). It is not used in the load flow. """ super().__init__(id) - self._z_line = np.asarray(z_line, dtype=complex) + self._z_line = np.array(z_line, dtype=np.complex128) if y_shunt is None: self._with_shunt = False - self._y_shunt = np.zeros_like(z_line, dtype=complex) + self._y_shunt = np.zeros_like(self._z_line, dtype=np.complex128) else: self._with_shunt = not np.allclose(y_shunt, 0) - self._y_shunt = np.asarray(y_shunt, dtype=complex) + self._y_shunt = np.array(y_shunt, dtype=np.complex128) self.max_current = max_current self._check_matrix() @@ -112,7 +112,7 @@ def max_current(self) -> Optional[Q_[float]]: @max_current.setter @ureg_wraps(None, (None, "A"), strict=False) - def max_current(self, value: Optional[float]) -> None: + def max_current(self, value: Optional[Union[float, Q_[float]]]) -> None: self._max_current = value @classmethod @@ -122,15 +122,15 @@ def max_current(self, value: Optional[float]) -> None: def from_sym( cls, id: Id, - z0: complex, - z1: complex, - y0: complex, - y1: complex, - zn: Optional[complex] = None, - xpn: Optional[float] = None, - bn: Optional[float] = None, - bpn: Optional[float] = None, - max_current: Optional[float] = None, + z0: Union[complex, Q_[complex]], + z1: Union[complex, Q_[complex]], + y0: Union[complex, Q_[complex]], + y1: Union[complex, Q_[complex]], + zn: Optional[Union[complex, Q_[complex]]] = None, + xpn: Optional[Union[float, Q_[float]]] = None, + bn: Optional[Union[float, Q_[float]]] = None, + bpn: Optional[Union[float, Q_[float]]] = None, + max_current: Optional[Union[float, Q_[float]]] = None, ) -> Self: """Create line parameters from a symmetric model. @@ -245,8 +245,8 @@ def _sym_to_zy( # If all the neutral data have not been filled, the matrix is a 3x3 matrix if any_neutral_na: # No neutral data so retrieve a 3x3 matrix - z_line = np.array([[zs, zm, zm], [zm, zs, zm], [zm, zm, zs]], dtype=complex) - y_shunt = np.array([[ys, ym, ym], [ym, ys, ym], [ym, ym, ys]], dtype=complex) + z_line = np.array([[zs, zm, zm], [zm, zs, zm], [zm, zm, zs]], dtype=np.complex128) + y_shunt = np.array([[ys, ym, ym], [ym, ys, ym], [ym, ym, ys]], dtype=np.complex128) else: # Build the complex # zn: Neutral series impedance (ohm/km) @@ -259,16 +259,16 @@ def _sym_to_zy( f"The line model {id!r} does not have neutral elements. It will be modelled as a 3 wires line " f"instead." ) - z_line = np.array([[zs, zm, zm], [zm, zs, zm], [zm, zm, zs]], dtype=complex) - y_shunt = np.array([[ys, ym, ym], [ym, ys, ym], [ym, ym, ys]], dtype=complex) + z_line = np.array([[zs, zm, zm], [zm, zs, zm], [zm, zm, zs]], dtype=np.complex128) + y_shunt = np.array([[ys, ym, ym], [ym, ys, ym], [ym, ym, ys]], dtype=np.complex128) else: z_line = np.array( [[zs, zm, zm, zpn], [zm, zs, zm, zpn], [zm, zm, zs, zpn], [zpn, zpn, zpn, zn]], - dtype=complex, + dtype=np.complex128, ) y_shunt = np.array( [[ys, ym, ym, ypn], [ym, ys, ym, ypn], [ym, ym, ys, ypn], [ypn, ypn, ypn, yn]], - dtype=complex, + dtype=np.complex128, ) # Check the validity of the resulting matrices @@ -304,11 +304,11 @@ def from_geometry( line_type: LineType, conductor_type: ConductorType, insulator_type: InsulatorType, - section: float, - section_neutral: float, - height: float, - external_diameter: float, - max_current: Optional[float] = None, + section: Union[float, Q_[float]], + section_neutral: Union[float, Q_[float]], + height: Union[float, Q_[float]], + external_diameter: Union[float, Q_[float]], + max_current: Optional[Union[float, Q_[float]]] = None, ) -> Self: """Create line parameters from its geometry. @@ -448,7 +448,7 @@ def _geometry_to_zy( raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_LINE_TYPE) # Distance computation - sections = np.array([section, section, section, section_neutral], dtype=float) * 1e-6 # surfaces (m2) + sections = np.array([section, section, section, section_neutral], dtype=np.float64) * 1e-6 # surfaces (m2) radius = np.sqrt(sections / PI) # radius (m) gmr = radius * np.exp(-0.25) # geometric mean radius (m) # distance between two wires (m) @@ -460,13 +460,13 @@ def _geometry_to_zy( distance_prim = np.sqrt(np.einsum("ijk,ijk->ij", diff, diff)) # Useful matrices - mask_diagonal = np.eye(4, dtype=bool) + mask_diagonal = np.eye(4, dtype=np.bool_) mask_off_diagonal = ~mask_diagonal - minus = -np.ones((4, 4), dtype=float) + minus = -np.ones((4, 4), dtype=np.float64) np.fill_diagonal(minus, 1) # Electrical parameters - r = RHO[conductor_type].m_as("ohm*m") / sections * np.eye(4, dtype=float) * 1e3 # resistance (ohm/km) + r = RHO[conductor_type].m_as("ohm*m") / sections * np.eye(4, dtype=np.float64) * 1e3 # resistance (ohm/km) distance[mask_diagonal] = gmr inductance = MU_0.m_as("H/m") / (2 * PI) * np.log(1 / distance) * 1e3 # H/m->H/km distance[mask_diagonal] = radius @@ -474,10 +474,10 @@ def _geometry_to_zy( # Extract the conductivity and the capacities from the lambda (potential coefficients) lambda_inv = nplin.inv(lambdas) * 1e3 # capacities (F/km) - c = np.zeros((4, 4), dtype=float) # capacities (F/km) + c = np.zeros((4, 4), dtype=np.float64) # capacities (F/km) c[mask_diagonal] = np.einsum("ij,ij->i", lambda_inv, minus) c[mask_off_diagonal] = -lambda_inv[mask_off_diagonal] - g = np.zeros((4, 4), dtype=float) # conductance (S/km) + g = np.zeros((4, 4), dtype=np.float64) # conductance (S/km) omega = OMEGA.m_as("rad/s") g[mask_diagonal] = TAN_D[insulator_type].magnitude * np.einsum("ii->i", c) * omega @@ -486,7 +486,7 @@ def _geometry_to_zy( y = g + c * omega * 1j # Compute the shunt admittance matrix from the admittance matrix - y_shunt = np.zeros((4, 4), dtype=complex) + y_shunt = np.zeros((4, 4), dtype=np.complex128) y_shunt[mask_diagonal] = np.einsum("ij->i", y) y_shunt[mask_off_diagonal] = -y[mask_off_diagonal] @@ -497,10 +497,10 @@ def _geometry_to_zy( def from_name_lv( cls, name: str, - section_neutral: Optional[float] = None, - height: Optional[float] = None, - external_diameter: Optional[float] = None, - max_current: Optional[float] = None, + section_neutral: Optional[Union[float, Q_[float]]] = None, + height: Optional[Union[float, Q_[float]]] = None, + external_diameter: Optional[Union[float, Q_[float]]] = None, + max_current: Optional[Union[float, Q_[float]]] = None, ) -> Self: """Method to get the electrical parameters of a LV line from its canonical name. Some hypothesis will be made: the section of the neutral is the same as the other sections, the height and @@ -559,7 +559,8 @@ def from_name_lv( ) @classmethod - def from_name_mv(cls, name: str, max_current: Optional[float] = None) -> Self: + @ureg_wraps(None, (None, None, "A"), strict=False) + def from_name_mv(cls, name: str, max_current: Optional[Union[float, Q_[float]]] = None) -> Self: """Method to get the electrical parameters of a MV line from its canonical name. Args: @@ -603,8 +604,8 @@ def from_name_mv(cls, name: str, max_current: Optional[float] = None) -> Self: b = (c_b1 + c_b2 * section) * 1e-4 * OMEGA b = b.to("S/km") - z_line = (r + x * 1j) * np.eye(3, dtype=float) # in ohms/km - y_shunt = b * 1j * np.eye(3, dtype=float) # in siemens/km + z_line = (r + x * 1j) * np.eye(3, dtype=np.float64) # in ohms/km + y_shunt = b * 1j * np.eye(3, dtype=np.float64) # in siemens/km return cls(name, z_line=z_line, y_shunt=y_shunt, max_current=max_current) # @@ -621,8 +622,8 @@ def from_dict(cls, data: JsonDict) -> Self: Returns: The created line parameters. """ - z_line = np.asarray(data["z_line"][0]) + 1j * np.asarray(data["z_line"][1]) - y_shunt = np.asarray(data["y_shunt"][0]) + 1j * np.asarray(data["y_shunt"][1]) if "y_shunt" in data else None + z_line = np.array(data["z_line"][0]) + 1j * np.array(data["z_line"][1]) + y_shunt = np.array(data["y_shunt"][0]) + 1j * np.array(data["y_shunt"][1]) if "y_shunt" in data else None return cls(id=data["id"], z_line=z_line, y_shunt=y_shunt, max_current=data.get("max_current")) def to_dict(self, *, _lf_only: bool = False) -> JsonDict: diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index b92ffc3f..44579c16 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -1,13 +1,20 @@ import logging import warnings -from typing import TYPE_CHECKING, NoReturn, Optional +from typing import TYPE_CHECKING, NoReturn, Optional, Union import numpy as np from numpy.typing import NDArray from typing_extensions import Self from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.typing import Authentication, ComplexArray, ControlType, JsonDict, ProjectionType +from roseau.load_flow.typing import ( + Authentication, + ComplexArray, + ComplexArrayLike1D, + ControlType, + JsonDict, + ProjectionType, +) from roseau.load_flow.units import Q_, ureg_wraps from roseau.load_flow.utils import JsonMixin, _optional_deps @@ -41,11 +48,11 @@ class Control(JsonMixin): def __init__( self, type: ControlType, - u_min: float, - u_down: float, - u_up: float, - u_max: float, - alpha: float = _DEFAULT_ALPHA, + u_min: Union[float, Q_[float]], + u_down: Union[float, Q_[float]], + u_up: Union[float, Q_[float]], + u_max: Union[float, Q_[float]], + alpha: Union[float, Q_[float]] = _DEFAULT_ALPHA, ) -> None: """Control constructor. @@ -181,7 +188,9 @@ def constant(cls) -> Self: @classmethod @ureg_wraps(None, (None, "V", "V", None), strict=False) - def p_max_u_production(cls, u_up: float, u_max: float, alpha: float = _DEFAULT_ALPHA) -> Self: + def p_max_u_production( + cls, u_up: Union[float, Q_[float]], u_max: Union[float, Q_[float]], alpha: float = _DEFAULT_ALPHA + ) -> Self: """Create a control of the type ``"p_max_u_production"``. See Also: @@ -210,7 +219,9 @@ def p_max_u_production(cls, u_up: float, u_max: float, alpha: float = _DEFAULT_A @classmethod @ureg_wraps(None, (None, "V", "V", None), strict=False) - def p_max_u_consumption(cls, u_min: float, u_down: float, alpha: float = _DEFAULT_ALPHA) -> Self: + def p_max_u_consumption( + cls, u_min: Union[float, Q_[float]], u_down: Union[float, Q_[float]], alpha: float = _DEFAULT_ALPHA + ) -> Self: """Create a control of the type ``"p_max_u_consumption"``. See Also: @@ -239,7 +250,14 @@ def p_max_u_consumption(cls, u_min: float, u_down: float, alpha: float = _DEFAUL @classmethod @ureg_wraps(None, (None, "V", "V", "V", "V", None), strict=False) - def q_u(cls, u_min: float, u_down: float, u_up: float, u_max: float, alpha: float = _DEFAULT_ALPHA) -> Self: + def q_u( + cls, + u_min: Union[float, Q_[float]], + u_down: Union[float, Q_[float]], + u_up: Union[float, Q_[float]], + u_max: Union[float, Q_[float]], + alpha: float = _DEFAULT_ALPHA, + ) -> Self: """Create a control of the type ``"q_u"``. See Also: @@ -446,9 +464,9 @@ def __init__( control_p: Control, control_q: Control, projection: Projection, - s_max: float, - q_min: Optional[float] = None, - q_max: Optional[float] = None, + s_max: Union[float, Q_[float]], + q_min: Optional[Union[float, Q_[float]]] = None, + q_max: Optional[Union[float, Q_[float]]] = None, ) -> None: """FlexibleParameter constructor. @@ -490,7 +508,7 @@ def s_max(self) -> Q_[float]: @s_max.setter @ureg_wraps(None, (None, "VA"), strict=False) - def s_max(self, value: float) -> None: + def s_max(self, value: Union[float, Q_[float]]) -> None: if value <= 0: s_max = Q_(value, "VA") msg = f"'s_max' must be greater than 0 but {s_max:P#~} was provided." @@ -512,7 +530,7 @@ def q_min(self) -> Q_[float]: @q_min.setter @ureg_wraps(None, (None, "VAr"), strict=False) - def q_min(self, value: Optional[float]) -> None: + def q_min(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and value < -self._s_max: q_min = Q_(value, "VAr") msg = f"'q_min' must be greater than -s_max ({-self.s_max:P#~}) but {q_min:P#~} was provided." @@ -533,7 +551,7 @@ def q_max(self) -> Q_[float]: @q_max.setter @ureg_wraps(None, (None, "VAr"), strict=False) - def q_max(self, value: Optional[float]) -> None: + def q_max(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and value > self._s_max: q_max = Q_(value, "VAr") msg = f"'q_max' must be less than s_max ({self.s_max:P#~}) but {q_max:P#~} was provided." @@ -564,9 +582,9 @@ def constant(cls) -> Self: @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None), strict=False) def p_max_u_production( cls, - u_up: float, - u_max: float, - s_max: float, + u_up: Union[float, Q_[float]], + u_max: Union[float, Q_[float]], + s_max: Union[float, Q_[float]], alpha_control: float = Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, @@ -620,9 +638,9 @@ def p_max_u_production( @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None), strict=False) def p_max_u_consumption( cls, - u_min: float, - u_down: float, - s_max: float, + u_min: Union[float, Q_[float]], + u_down: Union[float, Q_[float]], + s_max: Union[float, Q_[float]], alpha_control: float = Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, @@ -673,13 +691,13 @@ def p_max_u_consumption( @ureg_wraps(None, (None, "V", "V", "V", "V", "VA", "Var", "Var", None, None, None, None), strict=False) def q_u( cls, - u_min: float, - u_down: float, - u_up: float, - u_max: float, - s_max: float, - q_min: Optional[float] = None, - q_max: Optional[float] = None, + u_min: Union[float, Q_[float]], + u_down: Union[float, Q_[float]], + u_up: Union[float, Q_[float]], + u_max: Union[float, Q_[float]], + s_max: Union[float, Q_[float]], + q_min: Optional[Union[float, Q_[float]]] = None, + q_max: Optional[Union[float, Q_[float]]] = None, alpha_control: float = Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, @@ -747,15 +765,15 @@ def q_u( @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None), strict=False) def pq_u_production( cls, - up_up: float, - up_max: float, - uq_min: float, - uq_down: float, - uq_up: float, - uq_max: float, - s_max: float, - q_min: Optional[float] = None, - q_max: Optional[float] = None, + up_up: Union[float, Q_[float]], + up_max: Union[float, Q_[float]], + uq_min: Union[float, Q_[float]], + uq_down: Union[float, Q_[float]], + uq_up: Union[float, Q_[float]], + uq_max: Union[float, Q_[float]], + s_max: Union[float, Q_[float]], + q_min: Optional[Union[float, Q_[float]]] = None, + q_max: Optional[Union[float, Q_[float]]] = None, alpha_control=Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj=Projection._DEFAULT_ALPHA, @@ -834,16 +852,16 @@ def pq_u_production( @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None), strict=False) def pq_u_consumption( cls, - up_min: float, - up_down: float, - uq_min: float, - uq_down: float, - uq_up: float, - uq_max: float, - s_max: float, - q_min: Optional[float] = None, - q_max: Optional[float] = None, - alpha_control: float = Control._DEFAULT_ALPHA, + up_min: Union[float, Q_[float]], + up_down: Union[float, Q_[float]], + uq_min: Union[float, Q_[float]], + uq_down: Union[float, Q_[float]], + uq_up: Union[float, Q_[float]], + uq_max: Union[float, Q_[float]], + s_max: Union[float, Q_[float]], + q_min: Optional[Union[float, Q_[float]]] = None, + q_max: Optional[Union[float, Q_[float]]] = None, + alpha_control: Union[float, Q_[float]] = Control._DEFAULT_ALPHA, type_proj: ProjectionType = Projection._DEFAULT_TYPE, alpha_proj: float = Projection._DEFAULT_ALPHA, epsilon_proj: float = Projection._DEFAULT_EPSILON, @@ -966,8 +984,8 @@ def results_from_dict(self, data: JsonDict) -> NoReturn: def compute_powers( self, auth: Authentication, - voltages: NDArray[np.float_], - power: complex, + voltages: ComplexArrayLike1D, + power: Union[complex, Q_[complex]], solve_kwargs: Optional[JsonDict] = None, ) -> Q_[ComplexArray]: """Compute the flexible powers for different voltages (norms) @@ -991,14 +1009,14 @@ def compute_powers( return self._compute_powers(auth=auth, voltages=voltages, power=power, solve_kwargs=solve_kwargs) def _compute_powers( - self, auth: Authentication, voltages: NDArray[np.float_], power: complex, solve_kwargs: Optional[JsonDict] + self, auth: Authentication, voltages: ComplexArrayLike1D, power: complex, solve_kwargs: Optional[JsonDict] ) -> ComplexArray: from roseau.load_flow import Bus, ElectricalNetwork, PotentialRef, PowerLoad, VoltageSource # Format the input if solve_kwargs is None: solve_kwargs = {} - voltages = np.array(np.abs(voltages), dtype=float) + voltages = np.array(np.abs(voltages), dtype=np.float64) # Simple network bus = Bus(id="bus", phases="an") @@ -1015,14 +1033,14 @@ def _compute_powers( en.solve_load_flow(auth=auth, **solve_kwargs) res_flexible_powers.append(load.res_flexible_powers.m_as("VA")[0]) - return np.array(res_flexible_powers, dtype=complex) + return np.array(res_flexible_powers, dtype=np.complex128) @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, None, "VA"), strict=False) def plot_pq( self, auth: Authentication, - voltages: NDArray[np.float_], - power: complex, + voltages: Union[NDArray[np.float64], Q_[NDArray[np.float64]]], + power: Union[complex, Q_[complex]], ax: Optional["Axes"] = None, solve_kwargs: Optional[JsonDict] = None, voltages_labels_mask: Optional[NDArray[np.bool_]] = None, @@ -1051,7 +1069,7 @@ def plot_pq( A mask to activate the plot of voltages labels. By default, no voltages annotations. res_flexible_powers: - If None, is provided, the `res_flexible_powers` are computed. Other + If None is provided, the `res_flexible_powers` are computed. Otherwise, the provided values are used. Returns: The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else @@ -1066,9 +1084,9 @@ def plot_pq( # Initialise some variables if voltages_labels_mask is None: - voltages_labels_mask = np.zeros_like(voltages, dtype=bool) + voltages_labels_mask = np.zeros_like(voltages, dtype=np.bool_) else: - voltages_labels_mask = np.array(voltages_labels_mask, dtype=bool) + voltages_labels_mask = np.array(voltages_labels_mask, dtype=np.bool_) s_max = self._s_max v_min = voltages.min() v_max = voltages.max() @@ -1134,8 +1152,8 @@ def plot_pq( def plot_control_p( self, auth: Authentication, - voltages: NDArray[np.float_], - power: complex, + voltages: Union[NDArray[np.float64], Q_[NDArray[np.float64]]], + power: Union[complex, Q_[complex]], ax: Optional["Axes"] = None, solve_kwargs: Optional[JsonDict] = None, res_flexible_powers: Optional[ComplexArray] = None, @@ -1159,7 +1177,7 @@ def plot_control_p( The keywords arguments of the :meth:`~roseau.load_flow.ElectricalNetwork.solve_load_flow` method. res_flexible_powers: - If None, is provided, the `res_flexible_powers` are computed. Other + If None is provided, the `res_flexible_powers` are computed. Otherwise, the provided values are used. Returns: The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else @@ -1200,8 +1218,8 @@ def plot_control_p( def plot_control_q( self, auth: Authentication, - voltages: NDArray[np.float_], - power: complex, + voltages: Union[NDArray[np.float64], Q_[NDArray[np.float64]]], + power: Union[complex, Q_[complex]], ax: Optional["Axes"] = None, solve_kwargs: Optional[JsonDict] = None, res_flexible_powers: Optional[ComplexArray] = None, @@ -1225,7 +1243,7 @@ def plot_control_q( The keywords arguments of the :meth:`~roseau.load_flow.ElectricalNetwork.solve_load_flow` method res_flexible_powers: - If None, is provided, the `res_flexible_powers` are computed. Other + If None is provided, the `res_flexible_powers` are computed. Otherwise, the provided values are used. Returns: The axis on which the plot has been drawn and the resulting flexible powers (the input if not `None` else @@ -1268,7 +1286,7 @@ def plot_control_q( @staticmethod def _theoretical_control_data( control: Control, v_min: float, v_max: float, power: float, s_max: float - ) -> tuple[NDArray[np.float_], NDArray[np.float_], NDArray[np.object_]]: + ) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.object_]]: """Helper to get data for the different plots of the class. It provides the theoretical control curve abscissas and ordinates values. It also provides ticks for the abscissa axis. @@ -1293,27 +1311,27 @@ def _theoretical_control_data( """ # Depending on the type of the control, several options if control.type == "constant": - x = np.array([v_min, v_max], dtype=float) - y = np.array([power, power], dtype=float) - x_ticks = np.array([f"{v_min:.1f}", f"{v_max:.1f}"], dtype=object) + x = np.array([v_min, v_max], dtype=np.float64) + y = np.array([power, power], dtype=np.float64) + x_ticks = np.array([f"{v_min:.1f}", f"{v_max:.1f}"], dtype=np.object_) elif control.type == "p_max_u_production": u_up = control._u_up u_max = control._u_max - x = np.array([u_up, u_max, v_min, v_max], dtype=float) - y = np.zeros_like(x, dtype=float) + x = np.array([u_up, u_max, v_min, v_max], dtype=np.float64) + y = np.zeros_like(x, dtype=np.float64) y[x < u_up] = -s_max mask = np.logical_and(u_up <= x, x < u_max) y[mask] = -s_max * (x[mask] - u_max) / (u_up - u_max) y[x >= u_max] = 0 x_ticks = np.array( [f"{u_up:.1f}\n$U^{{\\mathrm{{up}}}}$", f"{u_max:.1f}\n$U^{{\\max}}$", f"{v_min:.1f}", f"{v_max:.1f}"], - dtype=object, + dtype=np.object_, ) elif control.type == "p_max_u_consumption": u_min = control._u_min u_down = control._u_down - x = np.array([u_min, u_down, v_min, v_max], dtype=float) - y = np.zeros_like(x, dtype=float) + x = np.array([u_min, u_down, v_min, v_max], dtype=np.float64) + y = np.zeros_like(x, dtype=np.float64) y[x < u_min] = 0 y[x >= u_down] = s_max mask = np.logical_and(u_min <= x, x < u_down) @@ -1325,15 +1343,15 @@ def _theoretical_control_data( f"{v_min:.1f}", f"{v_max:.1f}", ], - dtype=object, + dtype=np.object_, ) elif control.type == "q_u": u_min = control._u_min u_down = control._u_down u_up = control._u_up u_max = control._u_max - x = np.array([u_min, u_down, u_up, u_max, v_min, v_max], dtype=float) - y = np.zeros_like(x, dtype=float) + x = np.array([u_min, u_down, u_up, u_max, v_min, v_max], dtype=np.float64) + y = np.zeros_like(x, dtype=np.float64) y[x < u_min] = -s_max mask = np.logical_and(u_min <= x, x < u_down) y[mask] = -s_max * (x[mask] - u_down) / (u_min - u_down) @@ -1350,7 +1368,7 @@ def _theoretical_control_data( f"{v_min:.1f}", f"{v_max:.1f}", ], - dtype=object, + dtype=np.object_, ) else: # pragma: no-cover msg = f"Unsupported control type {control.type!r}" diff --git a/roseau/load_flow/models/loads/loads.py b/roseau/load_flow/models/loads/loads.py index fbe0e582..b178b767 100644 --- a/roseau/load_flow/models/loads/loads.py +++ b/roseau/load_flow/models/loads/loads.py @@ -1,6 +1,5 @@ import logging from abc import ABC -from collections.abc import Sequence from typing import Any, Literal, Optional import numpy as np @@ -10,7 +9,7 @@ from roseau.load_flow.models.buses import Bus from roseau.load_flow.models.core import Element from roseau.load_flow.models.loads.flexible_parameters import FlexibleParameter -from roseau.load_flow.typing import ComplexArray, Id, JsonDict +from roseau.load_flow.typing import ComplexArray, ComplexArrayLike1D, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -104,7 +103,7 @@ def res_currents(self) -> Q_[ComplexArray]: """The load flow result of the load currents (A).""" return self._res_currents_getter(warning=True) - def _validate_value(self, value: Sequence[complex]) -> ComplexArray: + def _validate_value(self, value: ComplexArrayLike1D) -> ComplexArray: if len(value) != self._size: msg = f"Incorrect number of {self._type}s: {len(value)} instead of {self._size}" logger.error(msg) @@ -116,7 +115,7 @@ def _validate_value(self, value: Sequence[complex]) -> ComplexArray: msg = f"An impedance of the load {self.id!r} is null" logger.error(msg) raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_Z_VALUE) - return np.asarray(value, dtype=complex) + return np.array(value, dtype=np.complex128) def _res_potentials_getter(self, warning: bool) -> ComplexArray: self._raise_disconnected_error() @@ -190,7 +189,7 @@ def from_dict(cls, data: JsonDict) -> "AbstractLoad": raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_LOAD_TYPE) def results_from_dict(self, data: JsonDict) -> None: - self._res_currents = np.array([complex(i[0], i[1]) for i in data["currents"]], dtype=complex) + self._res_currents = np.array([complex(i[0], i[1]) for i in data["currents"]], dtype=np.complex128) def _results_to_dict(self, warning: bool) -> JsonDict: return { @@ -210,7 +209,7 @@ def __init__( id: Id, bus: Bus, *, - powers: Sequence[complex], + powers: ComplexArrayLike1D, phases: Optional[str] = None, flexible_params: Optional[list[FlexibleParameter]] = None, **kwargs: Any, @@ -225,7 +224,8 @@ def __init__( The bus to connect the load to. powers: - List of power for each phase (VA). + An array-like of the powers for each phase component. Either complex values (VA) + or a :class:`Quantity ` of complex values. phases: The phases of the load. A string like ``"abc"`` or ``"an"`` etc. The order of the @@ -272,7 +272,7 @@ def powers(self) -> Q_[ComplexArray]: @powers.setter @ureg_wraps(None, (None, "VA"), strict=False) - def powers(self, value: Sequence[complex]) -> None: + def powers(self, value: ComplexArrayLike1D) -> None: value = self._validate_value(value) if self.is_flexible: for power, fp in zip(value, self._flexible_params): @@ -332,7 +332,7 @@ def to_dict(self, *, _lf_only: bool = False) -> JsonDict: def results_from_dict(self, data: JsonDict) -> None: super().results_from_dict(data=data) if self.is_flexible: - self._res_flexible_powers = np.array([complex(p[0], p[1]) for p in data["powers"]], dtype=complex) + self._res_flexible_powers = np.array([complex(p[0], p[1]) for p in data["powers"]], dtype=np.complex128) def _results_to_dict(self, warning: bool) -> JsonDict: if self.is_flexible: @@ -350,7 +350,7 @@ class CurrentLoad(AbstractLoad): _type = "current" def __init__( - self, id: Id, bus: Bus, *, currents: Sequence[complex], phases: Optional[str] = None, **kwargs: Any + self, id: Id, bus: Bus, *, currents: ComplexArrayLike1D, phases: Optional[str] = None, **kwargs: Any ) -> None: """CurrentLoad constructor. @@ -362,7 +362,8 @@ def __init__( The bus to connect the load to. currents: - List of currents for each phase (Amps). + An array-like of the currents for each phase component. Either complex values (A) + or a :class:`Quantity ` of complex values. phases: The phases of the load. A string like ``"abc"`` or ``"an"`` etc. The order of the @@ -381,7 +382,7 @@ def currents(self) -> Q_[ComplexArray]: @currents.setter @ureg_wraps(None, (None, "A"), strict=False) - def currents(self, value: Sequence[complex]) -> None: + def currents(self, value: ComplexArrayLike1D) -> None: self._currents = self._validate_value(value) self._invalidate_network_results() @@ -401,7 +402,7 @@ class ImpedanceLoad(AbstractLoad): _type = "impedance" def __init__( - self, id: Id, bus: Bus, *, impedances: Sequence[complex], phases: Optional[str] = None, **kwargs: Any + self, id: Id, bus: Bus, *, impedances: ComplexArrayLike1D, phases: Optional[str] = None, **kwargs: Any ) -> None: """ImpedanceLoad constructor. @@ -413,7 +414,8 @@ def __init__( The bus to connect the load to. impedances: - List of impedances for each phase (Ohms). + An array-like of the impedances for each phase component. Either complex values + (Ohms) or a :class:`Quantity ` of complex values. phases: The phases of the load. A string like ``"abc"`` or ``"an"`` etc. The order of the @@ -432,7 +434,7 @@ def impedances(self) -> Q_[ComplexArray]: @impedances.setter @ureg_wraps(None, (None, "ohm"), strict=False) - def impedances(self, impedances: Sequence[complex]) -> None: + def impedances(self, impedances: ComplexArrayLike1D) -> None: self._impedances = self._validate_value(impedances) self._invalidate_network_results() diff --git a/roseau/load_flow/models/sources.py b/roseau/load_flow/models/sources.py index 27492b13..819a78b7 100644 --- a/roseau/load_flow/models/sources.py +++ b/roseau/load_flow/models/sources.py @@ -1,5 +1,4 @@ import logging -from collections.abc import Sequence from typing import Any, Optional import numpy as np @@ -9,7 +8,7 @@ from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.models.buses import Bus from roseau.load_flow.models.core import Element -from roseau.load_flow.typing import ComplexArray, Id, JsonDict +from roseau.load_flow.typing import ComplexArray, ComplexArrayLike1D, Id, JsonDict from roseau.load_flow.units import Q_, ureg_wraps logger = logging.getLogger(__name__) @@ -23,7 +22,7 @@ class VoltageSource(Element): _floating_neutral_allowed: bool = False def __init__( - self, id: Id, bus: Bus, *, voltages: Sequence[complex], phases: Optional[str] = None, **kwargs: Any + self, id: Id, bus: Bus, *, voltages: ComplexArrayLike1D, phases: Optional[str] = None, **kwargs: Any ) -> None: """Voltage source constructor. @@ -35,9 +34,10 @@ def __init__( The bus of the voltage source. voltages: - The voltages of the source. They will be fixed on the connected bus. If the source - has a neutral connection, the voltages are the phase-to-neutral voltages, otherwise - they are the phase-to-phase voltages. + An array-like of the voltages of the source. They will be set on the connected bus. + If the source has a neutral connection, the voltages are considered phase-to-neutral + voltages, otherwise they are the phase-to-phase voltages. Either complex values (V) + or a :class:`Quantity ` of complex values. phases: The phases of the source. A string like ``"abc"`` or ``"an"`` etc. The order of the @@ -91,12 +91,12 @@ def voltages(self) -> Q_[ComplexArray]: @voltages.setter @ureg_wraps(None, (None, "V"), strict=False) - def voltages(self, voltages: Sequence[complex]) -> None: + def voltages(self, voltages: ComplexArrayLike1D) -> None: if len(voltages) != self._size: msg = f"Incorrect number of voltages: {len(voltages)} instead of {self._size}" logger.error(msg) raise RoseauLoadFlowException(msg, code=RoseauLoadFlowExceptionCode.BAD_VOLTAGES_SIZE) - self._voltages = np.asarray(voltages, dtype=complex) + self._voltages = np.array(voltages, dtype=np.complex128) self._invalidate_network_results() @property @@ -167,7 +167,7 @@ def to_dict(self, *, _lf_only: bool = False) -> JsonDict: } def results_from_dict(self, data: JsonDict) -> None: - self._res_currents = np.array([complex(i[0], i[1]) for i in data["currents"]], dtype=complex) + self._res_currents = np.array([complex(i[0], i[1]) for i in data["currents"]], dtype=np.complex128) def _results_to_dict(self, warning: bool) -> JsonDict: return { diff --git a/roseau/load_flow/models/tests/test_branches.py b/roseau/load_flow/models/tests/test_branches.py index 1b0bebf6..72f7829e 100644 --- a/roseau/load_flow/models/tests/test_branches.py +++ b/roseau/load_flow/models/tests/test_branches.py @@ -225,9 +225,9 @@ def test_powers_equal(network_with_results): def test_lines_results(phases, z_line, y_shunt, len_line, bus_pot, line_cur, ground_pot, expected_pow): bus1 = Bus("bus1", phases=phases["bus1"]) bus2 = Bus("bus2", phases=phases["bus2"]) - y_shunt = np.asarray(y_shunt, dtype=complex) if y_shunt is not None else None + y_shunt = np.array(y_shunt, dtype=np.complex128) if y_shunt is not None else None ground = Ground("gnd") - lp = LineParameters("lp", z_line=np.asarray(z_line, dtype=complex), y_shunt=y_shunt) + lp = LineParameters("lp", z_line=np.array(z_line, dtype=np.complex128), y_shunt=y_shunt) line = Line( "line", bus1, diff --git a/roseau/load_flow/models/transformers/parameters.py b/roseau/load_flow/models/transformers/parameters.py index 9c68e541..2e389a0a 100644 --- a/roseau/load_flow/models/transformers/parameters.py +++ b/roseau/load_flow/models/transformers/parameters.py @@ -42,14 +42,14 @@ def __init__( self, id: Id, type: str, - uhv: float, - ulv: float, - sn: float, - p0: float, - i0: float, - psc: float, - vsc: float, - max_power: Optional[float] = None, + uhv: Union[float, Q_[float]], + ulv: Union[float, Q_[float]], + sn: Union[float, Q_[float]], + p0: Union[float, Q_[float]], + i0: Union[float, Q_[float]], + psc: Union[float, Q_[float]], + vsc: Union[float, Q_[float]], + max_power: Optional[Union[float, Q_[float]]] = None, ) -> None: """TransformerParameters constructor. @@ -204,7 +204,7 @@ def max_power(self) -> Optional[Q_[float]]: @max_power.setter @ureg_wraps(None, (None, "VA"), strict=False) - def max_power(self, value: Optional[float]) -> None: + def max_power(self, value: Optional[Union[float, Q_[float]]]) -> None: self._max_power = value @ureg_wraps(("ohm", "S", "", None), (None,), strict=False) diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py index 73eabe17..72c2d162 100644 --- a/roseau/load_flow/network.py +++ b/roseau/load_flow/network.py @@ -6,7 +6,7 @@ import re import textwrap import warnings -from collections.abc import Sized +from collections.abc import Mapping, Sized from importlib import resources from itertools import cycle from pathlib import Path @@ -37,7 +37,7 @@ VoltageSource, ) from roseau.load_flow.solvers import check_solver_params -from roseau.load_flow.typing import Authentication, Id, JsonDict, Solver, StrPath +from roseau.load_flow.typing import Authentication, Id, JsonDict, MapOrSeq, Solver, StrPath from roseau.load_flow.utils import CatalogueMixin, JsonMixin, _optional_deps, console, palette from roseau.load_flow.utils.types import _DTYPES, VoltagePhaseDtype @@ -46,7 +46,7 @@ logger = logging.getLogger(__name__) -_T = TypeVar("_T", bound=Element) +_E = TypeVar("_E", bound=Element) class ElectricalNetwork(JsonMixin, CatalogueMixin[JsonDict]): @@ -153,12 +153,12 @@ class ElectricalNetwork(JsonMixin, CatalogueMixin[JsonDict]): # def __init__( self, - buses: Union[list[Bus], dict[Id, Bus]], - branches: Union[list[AbstractBranch], dict[Id, AbstractBranch]], - loads: Union[list[AbstractLoad], dict[Id, AbstractLoad]], - sources: Union[list[VoltageSource], dict[Id, VoltageSource]], - grounds: Union[list[Ground], dict[Id, Ground]], - potential_refs: Union[list[PotentialRef], dict[Id, PotentialRef]], + buses: MapOrSeq[Bus], + branches: MapOrSeq[AbstractBranch], + loads: MapOrSeq[AbstractLoad], + sources: MapOrSeq[VoltageSource], + grounds: MapOrSeq[Ground], + potential_refs: MapOrSeq[PotentialRef], **kwargs, ) -> None: self.buses = self._elements_as_dict(buses, RoseauLoadFlowExceptionCode.BAD_BUS_ID) @@ -194,25 +194,24 @@ def count_repr(__o: Sized, /, singular: str, plural: Optional[str] = None) -> st ) @staticmethod - def _elements_as_dict( - elements: Union[list[_T], dict[Id, _T]], error_code: RoseauLoadFlowExceptionCode - ) -> dict[Id, _T]: - """Convert a list of elements to a dictionary of elements with their IDs as keys.""" + def _elements_as_dict(elements: MapOrSeq[_E], error_code: RoseauLoadFlowExceptionCode) -> dict[Id, _E]: + """Convert a sequence or a mapping of elements to a dictionary of elements with their IDs as keys.""" typ = error_code.name.removeprefix("BAD_").removesuffix("_ID").replace("_", " ") - if isinstance(elements, dict): + elements_dict: dict[Id, _E] = {} + if isinstance(elements, Mapping): for element_id, element in elements.items(): if element.id != element_id: msg = f"{typ.capitalize()} ID mismatch: {element_id!r} != {element.id!r}." logger.error(msg) raise RoseauLoadFlowException(msg, code=error_code) - return elements - elements_dict: dict[Id, _T] = {} - for element in elements: - if element.id in elements_dict: - msg = f"Duplicate ID for an {typ.lower()} in this network: {element.id!r}." - logger.error(msg) - raise RoseauLoadFlowException(msg, code=error_code) - elements_dict[element.id] = element + elements_dict[element_id] = element + else: + for element in elements: + if element.id in elements_dict: + msg = f"Duplicate ID for an {typ.lower()} in this network: {element.id!r}." + logger.error(msg) + raise RoseauLoadFlowException(msg, code=error_code) + elements_dict[element.id] = element return elements_dict @classmethod diff --git a/roseau/load_flow/typing.py b/roseau/load_flow/typing.py index 31a5cb33..fc202af2 100644 --- a/roseau/load_flow/typing.py +++ b/roseau/load_flow/typing.py @@ -1,9 +1,14 @@ """ Type Aliases used by Roseau Load Flow. +.. warning:: + + Types defined in this module are not part of the public API. You can use these types in your + code, but they are not guaranteed to be stable. + .. class:: Id - The type of the identifier of an element. + The type of the identifier of an element. An element's ID can be an integer or a string. .. class:: JsonDict @@ -11,15 +16,15 @@ .. class:: StrPath - The accepted type for files of roseau.load_flow.io. + The accepted type for file paths in roseau.load_flow. This is a string or a path-like object. .. class:: ControlType - Available types of control for flexible loads. + Available control types for flexible loads. .. class:: ProjectionType - Available types of projections for flexible loads control. + Available projections types for flexible loads control. .. class:: Solver @@ -27,20 +32,39 @@ .. class:: Authentication - Valid authentication types. + Valid authentication types used to connect to the Roseau Load Flow solver API. + +.. class:: MapOrSeq + + A mapping from element IDs to elements or a sequence of elements of unique IDs. .. class:: ComplexArray A numpy array of complex numbers. + +.. class:: ComplexArrayLike1D + + A 1D array-like of complex numbers or a quantity of complex numbers. An array-like is a + sequence or a numpy array. + +.. class:: ComplexArrayLike2D + + A 2D array-like of complex numbers or a quantity of complex numbers. An array-like is a + sequence or a numpy array. """ import os -from typing import Any, Literal, Union +from collections.abc import Mapping, Sequence +from typing import Any, Literal, TypeVar, Union import numpy as np from numpy.typing import NDArray from requests.auth import HTTPBasicAuth from typing_extensions import TypeAlias +from roseau.load_flow.units import Q_ + +T = TypeVar("T") + Id: TypeAlias = Union[int, str] JsonDict: TypeAlias = dict[str, Any] StrPath: TypeAlias = Union[str, os.PathLike[str]] @@ -48,7 +72,21 @@ ProjectionType: TypeAlias = Literal["euclidean", "keep_p", "keep_q"] Solver: TypeAlias = Literal["newton", "newton_goldstein"] Authentication: TypeAlias = Union[tuple[str, str], HTTPBasicAuth] -ComplexArray: TypeAlias = NDArray[np.complex_] +MapOrSeq: TypeAlias = Union[Mapping[Id, T], Sequence[T]] +ComplexArray: TypeAlias = NDArray[np.complex128] +# TODO: improve the types below when shape-typing becomes supported +ComplexArrayLike1D: TypeAlias = Union[ + ComplexArray, + Q_[ComplexArray], + Q_[Sequence[complex]], + Sequence[Union[complex, Q_[complex]]], +] +ComplexArrayLike2D: TypeAlias = Union[ + ComplexArray, + Q_[ComplexArray], + Q_[Sequence[Sequence[complex]]], + Sequence[Sequence[Union[complex, Q_[complex]]]], +] __all__ = [ @@ -59,5 +97,8 @@ "ProjectionType", "Solver", "Authentication", + "MapOrSeq", "ComplexArray", + "ComplexArrayLike1D", + "ComplexArrayLike2D", ] diff --git a/roseau/load_flow/units.py b/roseau/load_flow/units.py index 0c497a44..a1e5ec51 100644 --- a/roseau/load_flow/units.py +++ b/roseau/load_flow/units.py @@ -3,11 +3,20 @@ .. class:: ureg - The :class:`~pint.UnitRegistry` object to use in this project. + The :class:`pint.UnitRegistry` object to use in this project. You should not need to use it + directly. .. class:: Q_ - The :class:`~pint.Quantity` class to use in this project. + The :class:`pint.Quantity` class to use in this project. You can use it to provide quantities + in units different from the default ones. For example, to create a constant power load of 1 MVA, + you can do: + + >>> load = lf.PowerLoad("load", bus=bus, powers=Q_([1, 1, 1], "MVA")) + + which is equivalent to: + + >>> load = lf.PowerLoad("load", bus=bus, powers=[1000000, 1000000, 1000000]) # in VA .. _pint: https://pint.readthedocs.io/en/stable/getting/overview.html """ From 57eff2aa37174ed986244cccdeba159d68690f44 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Fri, 17 Nov 2023 16:27:52 +0200 Subject: [PATCH 37/43] Deprecate `LineParameters.from_name_lv` method (#148) This is part of #122. We deprecate this method now so that we can remove it completely in a later release. --- doc/Changelog.md | 2 ++ doc/usage/Connecting_Elements.md | 11 +++++++++- doc/usage/Flexible_Loads.md | 11 +++++++++- doc/usage/Short_Circuit.md | 22 +++++++++++++++++-- roseau/load_flow/models/lines/parameters.py | 10 ++++++++- .../models/tests/test_line_parameters.py | 8 ++++--- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/doc/Changelog.md b/doc/Changelog.md index deb17056..74a08479 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,8 @@ **In development** +- {gh-pr}`148` {gh-issue}`122` deprecate `LineParameters.from_name_lv()` in favor of the more generic + `LineParameters.from_geometry()`. The method will be removed in a future release. - {gh-pr}`142` {gh-issue}`136` Add `Bus.res_voltage_unbalance()` method to get the Voltage Unbalance Factor (VUF) as defined by the IEC standard IEC 61000-3-14. - {gh-pr}`141` {gh-issue}`137` Add `ElectricalNetwork.to_graph()` to get a `networkx.Graph` object diff --git a/doc/usage/Connecting_Elements.md b/doc/usage/Connecting_Elements.md index 36fb6430..4c27df69 100644 --- a/doc/usage/Connecting_Elements.md +++ b/doc/usage/Connecting_Elements.md @@ -118,7 +118,16 @@ Creating a line connecting the `load_bus` (belonging to the network `en`) and ou belong to a network) will propagate the network to the new elements. ```pycon ->>> lp_u_al_240 = LineParameters.from_name_lv("U_AL_240") +>>> lp_u_al_240 = LineParameters.from_geometry( +... "U_AL_240", +... line_type=LineType.UNDERGROUND, +... conductor_type=ConductorType.AL, +... insulator_type=InsulatorType.PVC, +... section=240, +... section_neutral=240, +... height=Q_(-1.5, "m"), +... external_diameter=Q_(40, "mm"), +... ) >>> new_line = Line( ... id="new_line", ... bus1=load_bus, diff --git a/doc/usage/Flexible_Loads.md b/doc/usage/Flexible_Loads.md index 40291107..1b4a11ef 100644 --- a/doc/usage/Flexible_Loads.md +++ b/doc/usage/Flexible_Loads.md @@ -56,7 +56,16 @@ a Delta-Wye transformer and a small LV network. ... ) >>> # Add the LV network elements -... lp = LineParameters.from_name_lv("U_AL_150") +... lp = LineParameters.from_geometry( +... "U_AL_150", +... line_type=LineType.UNDERGROUND, +... conductor_type=ConductorType.AL, +... insulator_type=InsulatorType.PVC, +... section=150, +... section_neutral=150, +... height=Q_(-1.5, "m"), +... external_diameter=Q_(40, "mm"), +... ) ... bus1 = Bus(id="bus1", phases="abcn") ... bus2 = Bus(id="bus2", phases="abcn") ... load_bus1 = Bus(id="load_bus1", phases="abcn") diff --git a/doc/usage/Short_Circuit.md b/doc/usage/Short_Circuit.md index 196794ec..8c8a8e5b 100644 --- a/doc/usage/Short_Circuit.md +++ b/doc/usage/Short_Circuit.md @@ -31,11 +31,29 @@ is impossible. ... vs = VoltageSource(id="vs", bus=source_bus, phases="abcn", voltages=source_voltages) >>> # Add LV lines -... lp1 = LineParameters.from_name_lv("U_AL_240") +... lp1 = LineParameters.from_geometry( +... "U_AL_240", +... line_type=LineType.UNDERGROUND, +... conductor_type=ConductorType.AL, +... insulator_type=InsulatorType.PVC, +... section=240, +... section_neutral=240, +... height=Q_(-1.5, "m"), +... external_diameter=Q_(40, "mm"), +... ) ... line1 = Line( ... id="line1", bus1=source_bus, bus2=bus1, parameters=lp1, length=1.0, ground=ground ... ) -... lp2 = LineParameters.from_name_lv("U_AL_150") +... lp2 = LineParameters.from_geometry( +... "U_AL_150", +... line_type=LineType.UNDERGROUND, +... conductor_type=ConductorType.AL, +... insulator_type=InsulatorType.PVC, +... section=150, +... section_neutral=150, +... height=Q_(-1.5, "m"), +... external_diameter=Q_(40, "mm"), +... ) ... line2 = Line(id="line2", bus1=bus1, bus2=bus2, parameters=lp2, length=2.0, ground=ground) >>> # Create network diff --git a/roseau/load_flow/models/lines/parameters.py b/roseau/load_flow/models/lines/parameters.py index 53a0f68f..ca44b702 100644 --- a/roseau/load_flow/models/lines/parameters.py +++ b/roseau/load_flow/models/lines/parameters.py @@ -5,7 +5,7 @@ import numpy as np import numpy.linalg as nplin import pandas as pd -from typing_extensions import Self +from typing_extensions import Self, deprecated from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode from roseau.load_flow.typing import ComplexArray, ComplexArrayLike2D, Id, JsonDict @@ -493,6 +493,11 @@ def _geometry_to_zy( return z_line, y_shunt @classmethod + @deprecated( + "The method LineParameters.from_name_lv() is deprecated and will be removed in a future " + "version. Use LineParameters.from_geometry() instead.", + category=FutureWarning, + ) @ureg_wraps(None, (None, None, "mm²", "m", "mm", "A"), strict=False) def from_name_lv( cls, @@ -524,6 +529,9 @@ def from_name_lv( Returns: The corresponding line parameters. + + .. deprecated:: 0.6.0 + Use :meth:`LineParameters.from_geometry` instead. """ match = cls._REGEXP_LINE_TYPE_NAME.fullmatch(string=name) if not match: diff --git a/roseau/load_flow/models/tests/test_line_parameters.py b/roseau/load_flow/models/tests/test_line_parameters.py index 92d0f3bf..85b517b7 100644 --- a/roseau/load_flow/models/tests/test_line_parameters.py +++ b/roseau/load_flow/models/tests/test_line_parameters.py @@ -314,17 +314,19 @@ def test_sym(): def test_from_name_lv(): - with pytest.raises(RoseauLoadFlowException) as e: + with pytest.raises(RoseauLoadFlowException) as e, pytest.warns(FutureWarning): LineParameters.from_name_lv("totoS_Al_150") assert "The line type name does not follow the syntax rule." in e.value.msg assert e.value.code == RoseauLoadFlowExceptionCode.BAD_TYPE_NAME_SYNTAX - lp = LineParameters.from_name_lv("S_AL_150") + with pytest.warns(FutureWarning): + lp = LineParameters.from_name_lv("S_AL_150") assert lp.z_line.shape == (4, 4) assert lp.y_shunt.shape == (4, 4) assert (lp.z_line.real >= 0).all().all() - lp2 = LineParameters.from_name_lv("U_AL_150") + with pytest.warns(FutureWarning): + lp2 = LineParameters.from_name_lv("U_AL_150") npt.assert_allclose(lp2.z_line.m_as("ohm/km"), lp.z_line.m_as("ohm/km")) npt.assert_allclose(lp2.y_shunt.m_as("S/km"), lp.y_shunt.m_as("S/km"), rtol=1e-4) From 8e658ac0cccefdac1520f5cc75b7cba906f0a1c8 Mon Sep 17 00:00:00 2001 From: Saelyos Date: Fri, 17 Nov 2023 15:28:20 +0100 Subject: [PATCH 38/43] Add custom pint wrapper --- roseau/load_flow/models/branches.py | 8 +- roseau/load_flow/models/buses.py | 14 +- roseau/load_flow/models/grounds.py | 2 +- roseau/load_flow/models/lines/lines.py | 18 +-- roseau/load_flow/models/lines/parameters.py | 18 +-- .../models/loads/flexible_parameters.py | 48 +++--- roseau/load_flow/models/loads/loads.py | 22 +-- roseau/load_flow/models/potential_refs.py | 2 +- roseau/load_flow/models/sources.py | 10 +- .../models/transformers/parameters.py | 24 +-- roseau/load_flow/tests/test_wrapper.py | 105 ++++++++++++ roseau/load_flow/units.py | 6 +- roseau/load_flow/wrapper.py | 152 ++++++++++++++++++ 13 files changed, 342 insertions(+), 87 deletions(-) create mode 100644 roseau/load_flow/tests/test_wrapper.py create mode 100644 roseau/load_flow/wrapper.py diff --git a/roseau/load_flow/models/branches.py b/roseau/load_flow/models/branches.py index 6e515fee..ea5fb888 100644 --- a/roseau/load_flow/models/branches.py +++ b/roseau/load_flow/models/branches.py @@ -80,7 +80,7 @@ def _res_currents_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArra return self._res_getter(value=self._res_currents, warning=warning) @property - @ureg_wraps(("A", "A"), (None,), strict=False) + @ureg_wraps(("A", "A"), (None,)) def res_currents(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch currents (A).""" return self._res_currents_getter(warning=True) @@ -93,7 +93,7 @@ def _res_powers_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArray] return powers1, powers2 @property - @ureg_wraps(("VA", "VA"), (None,), strict=False) + @ureg_wraps(("VA", "VA"), (None,)) def res_powers(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch powers (VA).""" return self._res_powers_getter(warning=True) @@ -104,7 +104,7 @@ def _res_potentials_getter(self, warning: bool) -> tuple[ComplexArray, ComplexAr return pot1, pot2 @property - @ureg_wraps(("V", "V"), (None,), strict=False) + @ureg_wraps(("V", "V"), (None,)) def res_potentials(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch potentials (V).""" return self._res_potentials_getter(warning=True) @@ -114,7 +114,7 @@ def _res_voltages_getter(self, warning: bool) -> tuple[ComplexArray, ComplexArra return calculate_voltages(pot1, self.phases1), calculate_voltages(pot2, self.phases2) @property - @ureg_wraps(("V", "V"), (None,), strict=False) + @ureg_wraps(("V", "V"), (None,)) def res_voltages(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """The load flow result of the branch voltages (V).""" return self._res_voltages_getter(warning=True) diff --git a/roseau/load_flow/models/buses.py b/roseau/load_flow/models/buses.py index e2347db7..b84b256b 100644 --- a/roseau/load_flow/models/buses.py +++ b/roseau/load_flow/models/buses.py @@ -91,13 +91,13 @@ def __repr__(self) -> str: return f"{type(self).__name__}(id={self.id!r}, phases={self.phases!r})" @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def potentials(self) -> Q_[ComplexArray]: """An array of initial potentials of the bus (V).""" return self._potentials @potentials.setter - @ureg_wraps(None, (None, "V"), strict=False) + @ureg_wraps(None, (None, "V")) def potentials(self, value: ComplexArrayLike1D) -> None: if len(value) != len(self.phases): msg = f"Incorrect number of potentials: {len(value)} instead of {len(self.phases)}" @@ -110,7 +110,7 @@ def _res_potentials_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_potentials, warning=warning) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def res_potentials(self) -> Q_[ComplexArray]: """The load flow result of the bus potentials (V).""" return self._res_potentials_getter(warning=True) @@ -120,7 +120,7 @@ def _res_voltages_getter(self, warning: bool) -> ComplexArray: return calculate_voltages(potentials, self.phases) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def res_voltages(self) -> Q_[ComplexArray]: """The load flow result of the bus voltages (V). @@ -146,7 +146,7 @@ def min_voltage(self) -> Optional[Q_[float]]: return None if self._min_voltage is None else Q_(self._min_voltage, "V") @min_voltage.setter - @ureg_wraps(None, (None, "V"), strict=False) + @ureg_wraps(None, (None, "V")) def min_voltage(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and self._max_voltage is not None and value > self._max_voltage: msg = ( @@ -165,7 +165,7 @@ def max_voltage(self) -> Optional[Q_[float]]: return None if self._max_voltage is None else Q_(self._max_voltage, "V") @max_voltage.setter - @ureg_wraps(None, (None, "V"), strict=False) + @ureg_wraps(None, (None, "V")) def max_voltage(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and self._min_voltage is not None and value < self._min_voltage: msg = ( @@ -284,7 +284,7 @@ def get_connected_buses(self) -> Iterator[Id]: to_add = set(element._connected_elements).difference(visited) remaining.update(to_add) - @ureg_wraps("percent", (None,), strict=False) + @ureg_wraps("percent", (None,)) def res_voltage_unbalance(self) -> Q_[float]: """Calculate the voltage unbalance on this bus according to the IEC definition. diff --git a/roseau/load_flow/models/grounds.py b/roseau/load_flow/models/grounds.py index ab1f12c4..083534af 100644 --- a/roseau/load_flow/models/grounds.py +++ b/roseau/load_flow/models/grounds.py @@ -53,7 +53,7 @@ def _res_potential_getter(self, warning: bool) -> complex: return self._res_getter(self._res_potential, warning) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def res_potential(self) -> Q_[complex]: """The load flow result of the ground potential (V).""" return self._res_potential_getter(warning=True) diff --git a/roseau/load_flow/models/lines/lines.py b/roseau/load_flow/models/lines/lines.py index 3fe052af..6a0a4d3e 100644 --- a/roseau/load_flow/models/lines/lines.py +++ b/roseau/load_flow/models/lines/lines.py @@ -225,12 +225,12 @@ def __init__( self._connect(self.ground) @property - @ureg_wraps("km", (None,), strict=False) + @ureg_wraps("km", (None,)) def length(self) -> Q_[float]: return self._length @length.setter - @ureg_wraps(None, (None, "km"), strict=False) + @ureg_wraps(None, (None, "km")) def length(self, value: Union[float, Q_[float]]) -> None: if value <= 0: msg = f"A line length must be greater than 0. {value:.2f} km provided." @@ -274,13 +274,13 @@ def parameters(self, value: LineParameters) -> None: self._invalidate_network_results() @property - @ureg_wraps("ohm", (None,), strict=False) + @ureg_wraps("ohm", (None,)) def z_line(self) -> Q_[ComplexArray]: """Impedance of the line in Ohm""" return self.parameters._z_line * self._length @property - @ureg_wraps("S", (None,), strict=False) + @ureg_wraps("S", (None,)) def y_shunt(self) -> Q_[ComplexArray]: """Shunt admittance of the line in Siemens""" return self.parameters._y_shunt * self._length @@ -307,7 +307,7 @@ def _res_series_currents_getter(self, warning: bool) -> ComplexArray: return i_line @property - @ureg_wraps("A", (None,), strict=False) + @ureg_wraps("A", (None,)) def res_series_currents(self) -> Q_[ComplexArray]: """Get the current in the series elements of the line (A).""" return self._res_series_currents_getter(warning=True) @@ -317,7 +317,7 @@ def _res_series_power_losses_getter(self, warning: bool) -> ComplexArray: return du_line * i_line.conj() # Sₗ = ΔU.Iₗ* @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def res_series_power_losses(self) -> Q_[ComplexArray]: """Get the power losses in the series elements of the line (VA).""" return self._res_series_power_losses_getter(warning=True) @@ -341,7 +341,7 @@ def _res_shunt_currents_getter(self, warning: bool) -> tuple[ComplexArray, Compl return cur1, cur2 @property - @ureg_wraps(("A", "A"), (None,), strict=False) + @ureg_wraps(("A", "A"), (None,)) def res_shunt_currents(self) -> tuple[Q_[ComplexArray], Q_[ComplexArray]]: """Get the currents in the shunt elements of the line (A).""" return self._res_shunt_currents_getter(warning=True) @@ -353,7 +353,7 @@ def _res_shunt_power_losses_getter(self, warning: bool) -> ComplexArray: return pot1 * cur1.conj() + pot2 * cur2.conj() @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def res_shunt_power_losses(self) -> Q_[ComplexArray]: """Get the power losses in the shunt elements of the line (VA).""" return self._res_shunt_power_losses_getter(warning=True) @@ -364,7 +364,7 @@ def _res_power_losses_getter(self, warning: bool) -> ComplexArray: return series_losses + shunt_losses @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def res_power_losses(self) -> Q_[ComplexArray]: """Get the power losses in the line (VA).""" return self._res_power_losses_getter(warning=True) diff --git a/roseau/load_flow/models/lines/parameters.py b/roseau/load_flow/models/lines/parameters.py index ca44b702..a2776fe9 100644 --- a/roseau/load_flow/models/lines/parameters.py +++ b/roseau/load_flow/models/lines/parameters.py @@ -39,7 +39,7 @@ class LineParameters(Identifiable, JsonMixin): rf"^({_type_re})_({_material_re})_{_section_re}$", flags=re.IGNORECASE ) - @ureg_wraps(None, (None, None, "ohm/km", "S/km", "A"), strict=False) + @ureg_wraps(None, (None, None, "ohm/km", "S/km", "A")) def __init__( self, id: Id, @@ -92,12 +92,12 @@ def __eq__(self, other: object) -> bool: ) @property - @ureg_wraps("ohm/km", (None,), strict=False) + @ureg_wraps("ohm/km", (None,)) def z_line(self) -> Q_[ComplexArray]: return self._z_line @property - @ureg_wraps("S/km", (None,), strict=False) + @ureg_wraps("S/km", (None,)) def y_shunt(self) -> Q_[ComplexArray]: return self._y_shunt @@ -111,14 +111,12 @@ def max_current(self) -> Optional[Q_[float]]: return None if self._max_current is None else Q_(self._max_current, "A") @max_current.setter - @ureg_wraps(None, (None, "A"), strict=False) + @ureg_wraps(None, (None, "A")) def max_current(self, value: Optional[Union[float, Q_[float]]]) -> None: self._max_current = value @classmethod - @ureg_wraps( - None, (None, None, "ohm/km", "ohm/km", "S/km", "S/km", "ohm/km", "ohm/km", "S/km", "S/km", "A"), strict=False - ) + @ureg_wraps(None, (None, None, "ohm/km", "ohm/km", "S/km", "S/km", "ohm/km", "ohm/km", "S/km", "S/km", "A")) def from_sym( cls, id: Id, @@ -297,7 +295,7 @@ def _sym_to_zy( return z_line, y_shunt @classmethod - @ureg_wraps(None, (None, None, None, None, None, "mm**2", "mm**2", "m", "m", "A"), strict=False) + @ureg_wraps(None, (None, None, None, None, None, "mm**2", "mm**2", "m", "m", "A")) def from_geometry( cls, id: Id, @@ -498,7 +496,7 @@ def _geometry_to_zy( "version. Use LineParameters.from_geometry() instead.", category=FutureWarning, ) - @ureg_wraps(None, (None, None, "mm²", "m", "mm", "A"), strict=False) + @ureg_wraps(None, (None, None, "mm²", "m", "mm", "A")) def from_name_lv( cls, name: str, @@ -567,7 +565,7 @@ def from_name_lv( ) @classmethod - @ureg_wraps(None, (None, None, "A"), strict=False) + @ureg_wraps(None, (None, None, "A")) def from_name_mv(cls, name: str, max_current: Optional[Union[float, Q_[float]]] = None) -> Self: """Method to get the electrical parameters of a MV line from its canonical name. diff --git a/roseau/load_flow/models/loads/flexible_parameters.py b/roseau/load_flow/models/loads/flexible_parameters.py index 44579c16..d687fbae 100644 --- a/roseau/load_flow/models/loads/flexible_parameters.py +++ b/roseau/load_flow/models/loads/flexible_parameters.py @@ -44,7 +44,7 @@ class Control(JsonMixin): _DEFAULT_ALPHA: float = 1000.0 - @ureg_wraps(None, (None, None, "V", "V", "V", "V", None), strict=False) + @ureg_wraps(None, (None, None, "V", "V", "V", "V", None)) def __init__( self, type: ControlType, @@ -152,25 +152,25 @@ def _check_values(self) -> None: raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_CONTROL_VALUE) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def u_min(self) -> Q_[float]: """The minimum voltage i.e. the one the control reached the maximum action.""" return self._u_min @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def u_down(self) -> Q_[float]: """The voltage which starts to trigger the control (lower value).""" return self._u_down @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def u_up(self) -> Q_[float]: """TThe voltage which starts to trigger the control (upper value).""" return self._u_up @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def u_max(self) -> Q_[float]: """The maximum voltage i.e. the one the control reached its maximum action.""" return self._u_max @@ -187,7 +187,7 @@ def constant(cls) -> Self: return cls(type="constant", u_min=0.0, u_down=0.0, u_up=0.0, u_max=0.0) @classmethod - @ureg_wraps(None, (None, "V", "V", None), strict=False) + @ureg_wraps(None, (None, "V", "V", None)) def p_max_u_production( cls, u_up: Union[float, Q_[float]], u_max: Union[float, Q_[float]], alpha: float = _DEFAULT_ALPHA ) -> Self: @@ -218,7 +218,7 @@ def p_max_u_production( return cls(type="p_max_u_production", u_min=0.0, u_down=0.0, u_up=u_up, u_max=u_max, alpha=alpha) @classmethod - @ureg_wraps(None, (None, "V", "V", None), strict=False) + @ureg_wraps(None, (None, "V", "V", None)) def p_max_u_consumption( cls, u_min: Union[float, Q_[float]], u_down: Union[float, Q_[float]], alpha: float = _DEFAULT_ALPHA ) -> Self: @@ -249,7 +249,7 @@ def p_max_u_consumption( return cls(type="p_max_u_consumption", u_min=u_min, u_down=u_down, u_up=0.0, u_max=0.0, alpha=alpha) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", None)) def q_u( cls, u_min: Union[float, Q_[float]], @@ -458,7 +458,7 @@ class FlexibleParameter(JsonMixin): _control_class: type[Control] = Control _projection_class: type[Projection] = Projection - @ureg_wraps(None, (None, None, None, None, "VA", "VAr", "VAr"), strict=False) + @ureg_wraps(None, (None, None, None, None, "VA", "VAr", "VAr")) def __init__( self, control_p: Control, @@ -501,13 +501,13 @@ def __init__( self.q_max = q_max @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def s_max(self) -> Q_[float]: """The apparent power of the flexible load (VA). It is the radius of the feasible circle.""" return self._s_max @s_max.setter - @ureg_wraps(None, (None, "VA"), strict=False) + @ureg_wraps(None, (None, "VA")) def s_max(self, value: Union[float, Q_[float]]) -> None: if value <= 0: s_max = Q_(value, "VA") @@ -523,13 +523,13 @@ def s_max(self, value: Union[float, Q_[float]]) -> None: self._q_min = -self._s_max @property - @ureg_wraps("VAr", (None,), strict=False) + @ureg_wraps("VAr", (None,)) def q_min(self) -> Q_[float]: """The minimum reactive power of the flexible load (VAr).""" return self._q_min if self._q_min is not None else -self._s_max @q_min.setter - @ureg_wraps(None, (None, "VAr"), strict=False) + @ureg_wraps(None, (None, "VAr")) def q_min(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and value < -self._s_max: q_min = Q_(value, "VAr") @@ -544,13 +544,13 @@ def q_min(self, value: Optional[Union[float, Q_[float]]]) -> None: self._q_min = value @property - @ureg_wraps("VAr", (None,), strict=False) + @ureg_wraps("VAr", (None,)) def q_max(self) -> Q_[float]: """The maximum reactive power of the flexible load (VAr).""" return self._q_max if self._q_max is not None else self._s_max @q_max.setter - @ureg_wraps(None, (None, "VAr"), strict=False) + @ureg_wraps(None, (None, "VAr")) def q_max(self, value: Optional[Union[float, Q_[float]]]) -> None: if value is not None and value > self._s_max: q_max = Q_(value, "VAr") @@ -579,7 +579,7 @@ def constant(cls) -> Self: ) @classmethod - @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None)) def p_max_u_production( cls, u_up: Union[float, Q_[float]], @@ -635,7 +635,7 @@ def p_max_u_production( ) @classmethod - @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "VA", None, None, None, None)) def p_max_u_consumption( cls, u_min: Union[float, Q_[float]], @@ -688,7 +688,7 @@ def p_max_u_consumption( ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "VA", "Var", "Var", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "VA", "Var", "Var", None, None, None, None)) def q_u( cls, u_min: Union[float, Q_[float]], @@ -762,7 +762,7 @@ def q_u( ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None)) def pq_u_production( cls, up_up: Union[float, Q_[float]], @@ -849,7 +849,7 @@ def pq_u_production( ) @classmethod - @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None), strict=False) + @ureg_wraps(None, (None, "V", "V", "V", "V", "V", "V", "VA", "VAr", "VAr", None, None, None, None)) def pq_u_consumption( cls, up_min: Union[float, Q_[float]], @@ -980,7 +980,7 @@ def results_from_dict(self, data: JsonDict) -> NoReturn: # # Equivalent Python method # - @ureg_wraps("VA", (None, None, "V", "VA", None), strict=False) + @ureg_wraps("VA", (None, None, "V", "VA", None)) def compute_powers( self, auth: Authentication, @@ -1035,7 +1035,7 @@ def _compute_powers( return np.array(res_flexible_powers, dtype=np.complex128) - @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, None, "VA"), strict=False) + @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, None, "VA")) def plot_pq( self, auth: Authentication, @@ -1148,7 +1148,7 @@ def plot_pq( return ax, res_flexible_powers - @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, "VA"), strict=False) + @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, "VA")) def plot_control_p( self, auth: Authentication, @@ -1214,7 +1214,7 @@ def plot_control_p( return ax, res_flexible_powers - @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, "VA"), strict=False) + @ureg_wraps((None, "VA"), (None, None, "V", "VA", None, None, "VA")) def plot_control_q( self, auth: Authentication, diff --git a/roseau/load_flow/models/loads/loads.py b/roseau/load_flow/models/loads/loads.py index b178b767..dd92dc4d 100644 --- a/roseau/load_flow/models/loads/loads.py +++ b/roseau/load_flow/models/loads/loads.py @@ -98,7 +98,7 @@ def _res_currents_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_currents, warning=warning) @property - @ureg_wraps("A", (None,), strict=False) + @ureg_wraps("A", (None,)) def res_currents(self) -> Q_[ComplexArray]: """The load flow result of the load currents (A).""" return self._res_currents_getter(warning=True) @@ -122,7 +122,7 @@ def _res_potentials_getter(self, warning: bool) -> ComplexArray: return self.bus._get_potentials_of(self.phases, warning) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def res_potentials(self) -> Q_[ComplexArray]: """The load flow result of the load potentials (V).""" return self._res_potentials_getter(warning=True) @@ -132,7 +132,7 @@ def _res_voltages_getter(self, warning: bool) -> ComplexArray: return calculate_voltages(potentials, self.phases) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def res_voltages(self) -> Q_[ComplexArray]: """The load flow result of the load voltages (V).""" return self._res_voltages_getter(warning=True) @@ -143,7 +143,7 @@ def _res_powers_getter(self, warning: bool) -> ComplexArray: return pots * curs.conj() @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def res_powers(self) -> Q_[ComplexArray]: """The load flow result of the load powers (VA).""" return self._res_powers_getter(warning=True) @@ -265,13 +265,13 @@ def is_flexible(self) -> bool: return self._flexible_params is not None @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def powers(self) -> Q_[ComplexArray]: """The powers of the load (VA).""" return self._powers @powers.setter - @ureg_wraps(None, (None, "VA"), strict=False) + @ureg_wraps(None, (None, "VA")) def powers(self, value: ComplexArrayLike1D) -> None: value = self._validate_value(value) if self.is_flexible: @@ -309,7 +309,7 @@ def _res_flexible_powers_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_flexible_powers, warning=warning) @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def res_flexible_powers(self) -> Q_[ComplexArray]: """The load flow result of the load flexible powers (VA).""" return self._res_flexible_powers_getter(warning=True) @@ -375,13 +375,13 @@ def __init__( self.currents = currents # handles size checks and unit conversion @property - @ureg_wraps("A", (None,), strict=False) + @ureg_wraps("A", (None,)) def currents(self) -> Q_[ComplexArray]: """The currents of the load (Amps).""" return self._currents @currents.setter - @ureg_wraps(None, (None, "A"), strict=False) + @ureg_wraps(None, (None, "A")) def currents(self, value: ComplexArrayLike1D) -> None: self._currents = self._validate_value(value) self._invalidate_network_results() @@ -427,13 +427,13 @@ def __init__( self.impedances = impedances @property - @ureg_wraps("ohm", (None,), strict=False) + @ureg_wraps("ohm", (None,)) def impedances(self) -> Q_[ComplexArray]: """The impedances of the load (Ohms).""" return self._impedances @impedances.setter - @ureg_wraps(None, (None, "ohm"), strict=False) + @ureg_wraps(None, (None, "ohm")) def impedances(self, impedances: ComplexArrayLike1D) -> None: self._impedances = self._validate_value(impedances) self._invalidate_network_results() diff --git a/roseau/load_flow/models/potential_refs.py b/roseau/load_flow/models/potential_refs.py index cdca1565..daba1a7f 100644 --- a/roseau/load_flow/models/potential_refs.py +++ b/roseau/load_flow/models/potential_refs.py @@ -68,7 +68,7 @@ def _res_current_getter(self, warning: bool) -> complex: return self._res_getter(self._res_current, warning) @property - @ureg_wraps("A", (None,), strict=False) + @ureg_wraps("A", (None,)) def res_current(self) -> Q_[complex]: """The sum of the currents (A) of the connection associated to the potential reference. diff --git a/roseau/load_flow/models/sources.py b/roseau/load_flow/models/sources.py index 819a78b7..49a5e7bc 100644 --- a/roseau/load_flow/models/sources.py +++ b/roseau/load_flow/models/sources.py @@ -84,13 +84,13 @@ def __repr__(self) -> str: ) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def voltages(self) -> Q_[ComplexArray]: """The voltages of the source (V).""" return self._voltages @voltages.setter - @ureg_wraps(None, (None, "V"), strict=False) + @ureg_wraps(None, (None, "V")) def voltages(self, voltages: ComplexArrayLike1D) -> None: if len(voltages) != self._size: msg = f"Incorrect number of voltages: {len(voltages)} instead of {self._size}" @@ -108,7 +108,7 @@ def _res_currents_getter(self, warning: bool) -> ComplexArray: return self._res_getter(value=self._res_currents, warning=warning) @property - @ureg_wraps("A", (None,), strict=False) + @ureg_wraps("A", (None,)) def res_currents(self) -> Q_[ComplexArray]: """The load flow result of the source currents (A).""" return self._res_currents_getter(warning=True) @@ -118,7 +118,7 @@ def _res_potentials_getter(self, warning: bool) -> ComplexArray: return self.bus._get_potentials_of(self.phases, warning) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def res_potentials(self) -> Q_[ComplexArray]: """The load flow result of the source potentials (V).""" return self._res_potentials_getter(warning=True) @@ -129,7 +129,7 @@ def _res_powers_getter(self, warning: bool) -> ComplexArray: return pots * curs.conj() @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def res_powers(self) -> Q_[ComplexArray]: """The load flow result of the source powers (VA).""" return self._res_powers_getter(warning=True) diff --git a/roseau/load_flow/models/transformers/parameters.py b/roseau/load_flow/models/transformers/parameters.py index 2e389a0a..31ec8d07 100644 --- a/roseau/load_flow/models/transformers/parameters.py +++ b/roseau/load_flow/models/transformers/parameters.py @@ -37,7 +37,7 @@ class TransformerParameters(Identifiable, JsonMixin, CatalogueMixin[pd.DataFrame ) """The pattern to extract the winding of the primary and of the secondary of the transformer.""" - @ureg_wraps(None, (None, None, None, "V", "V", "VA", "W", "", "W", "", "VA"), strict=False) + @ureg_wraps(None, (None, None, None, "V", "V", "VA", "W", "", "W", "", "VA")) def __init__( self, id: Id, @@ -156,43 +156,43 @@ def __eq__(self, other: object) -> bool: ) @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def uhv(self) -> Q_[float]: """Phase-to-phase nominal voltages of the high voltages side (V)""" return self._uhv @property - @ureg_wraps("V", (None,), strict=False) + @ureg_wraps("V", (None,)) def ulv(self) -> Q_[float]: """Phase-to-phase nominal voltages of the low voltages side (V)""" return self._ulv @property - @ureg_wraps("VA", (None,), strict=False) + @ureg_wraps("VA", (None,)) def sn(self) -> Q_[float]: """The nominal power of the transformer (VA)""" return self._sn @property - @ureg_wraps("W", (None,), strict=False) + @ureg_wraps("W", (None,)) def p0(self) -> Q_[float]: """Losses during off-load test (W)""" return self._p0 @property - @ureg_wraps("", (None,), strict=False) + @ureg_wraps("", (None,)) def i0(self) -> Q_[float]: """Current during off-load test (%)""" return self._i0 @property - @ureg_wraps("W", (None,), strict=False) + @ureg_wraps("W", (None,)) def psc(self) -> Q_[float]: """Losses during short-circuit test (W)""" return self._psc @property - @ureg_wraps("", (None,), strict=False) + @ureg_wraps("", (None,)) def vsc(self) -> Q_[float]: """Voltages on LV side during short-circuit test (%)""" return self._vsc @@ -203,11 +203,11 @@ def max_power(self) -> Optional[Q_[float]]: return None if self._max_power is None else Q_(self._max_power, "VA") @max_power.setter - @ureg_wraps(None, (None, "VA"), strict=False) + @ureg_wraps(None, (None, "VA")) def max_power(self, value: Optional[Union[float, Q_[float]]]) -> None: self._max_power = value - @ureg_wraps(("ohm", "S", "", None), (None,), strict=False) + @ureg_wraps(("ohm", "S", "", None), (None,)) def to_zyk(self) -> tuple[Q_[complex], Q_[complex], Q_[float], float]: """Compute the transformer parameters ``z2``, ``ym``, ``k`` and ``orientation`` mandatory for some models. @@ -315,7 +315,7 @@ def catalogue_data(cls) -> pd.DataFrame: return pd.read_csv(cls.catalogue_path() / "Catalogue.csv") @classmethod - @ureg_wraps(None, (None, None, None, None, None, None, "VA", "V", "V"), strict=False) + @ureg_wraps(None, (None, None, None, None, None, None, "VA", "V", "V")) def from_catalogue( cls, id: Optional[Union[str, re.Pattern[str]]] = None, @@ -460,7 +460,7 @@ def from_catalogue( return cls.from_json(path=path) @classmethod - @ureg_wraps(None, (None, None, None, None, None, None, "VA", "V", "V"), strict=False) + @ureg_wraps(None, (None, None, None, None, None, None, "VA", "V", "V")) def print_catalogue( cls, id: Optional[Union[str, re.Pattern[str]]] = None, diff --git a/roseau/load_flow/tests/test_wrapper.py b/roseau/load_flow/tests/test_wrapper.py new file mode 100644 index 00000000..89f5c9d2 --- /dev/null +++ b/roseau/load_flow/tests/test_wrapper.py @@ -0,0 +1,105 @@ +import operator + +import pytest +from pint import DimensionalityError + +from roseau.load_flow import ureg +from roseau.load_flow.units import ureg_wraps + + +def test_wraps(): + def func(x): + return x + + with pytest.raises(TypeError): + ureg_wraps((3 * ureg.meter, [None])) + with pytest.raises(TypeError): + ureg_wraps((None, [3 * ureg.meter])) + + f0 = ureg_wraps(None, [None])(func) + assert f0(3.0) == 3.0 + + f0 = ureg_wraps(None, None)(func) + assert f0(3.0) == 3.0 + + f1 = ureg_wraps(None, ["meter"])(func) + assert f1(3.0 * ureg.centimeter) == 0.03 + assert f1(3.0 * ureg.meter) == 3.0 + with pytest.raises(DimensionalityError): + f1(3 * ureg.second) + + f1b = ureg_wraps(None, [ureg.meter])(func) + assert f1b(3.0 * ureg.centimeter) == 0.03 + assert f1b(3.0 * ureg.meter) == 3.0 + with pytest.raises(DimensionalityError): + f1b(3 * ureg.second) + + f1c = ureg_wraps("meter", [ureg.meter])(func) + assert f1c(3.0 * ureg.centimeter) == 0.03 * ureg.meter + assert f1c(3.0 * ureg.meter) == 3.0 * ureg.meter + with pytest.raises(DimensionalityError): + f1c(3 * ureg.second) + + f1d = ureg_wraps(ureg.meter, [ureg.meter])(func) + assert f1d(3.0 * ureg.centimeter) == 0.03 * ureg.meter + assert f1d(3.0 * ureg.meter) == 3.0 * ureg.meter + with pytest.raises(DimensionalityError): + f1d(3 * ureg.second) + + f1 = ureg_wraps(None, "meter")(func) + assert f1(3.0 * ureg.centimeter) == 0.03 + assert f1(3.0 * ureg.meter) == 3.0 + with pytest.raises(DimensionalityError): + f1(3 * ureg.second) + + f2 = ureg_wraps("centimeter", ["meter"])(func) + assert f2(3.0 * ureg.centimeter) == 0.03 * ureg.centimeter + assert f2(3.0 * ureg.meter) == 3 * ureg.centimeter + assert f2(3) == 3 * ureg.centimeter + + gfunc = operator.add + + g0 = ureg_wraps(None, [None, None])(gfunc) + assert g0(3, 1) == 4 + + g1 = ureg_wraps(None, ["meter", "centimeter"])(gfunc) + assert g1(3 * ureg.meter, 1 * ureg.centimeter) == 4 + assert g1(3 * ureg.meter, 1 * ureg.meter) == 3 + 100 + + def hfunc(x, y): + return x, y + + h0 = ureg_wraps(None, [None, None])(hfunc) + assert h0(3, 1) == (3, 1) + + h1 = ureg_wraps(["meter", "centimeter"], [None, None])(hfunc) + assert h1(3, 1) == [3 * ureg.meter, 1 * ureg.cm] + + h2 = ureg_wraps(("meter", "centimeter"), [None, None])(hfunc) + assert h2(3, 1) == (3 * ureg.meter, 1 * ureg.cm) + + h3 = ureg_wraps((None,), (None, None))(hfunc) + assert h3(3, 1) == (3, 1) + + def kfunc(a, /, b, c=5, *, d=6): + return a, b, c, d + + k1 = ureg_wraps((None,), (None, None, None, None))(kfunc) + assert k1(1, 2, 3, d=4) == (1, 2, 3, 4) + assert k1(1, 2, c=3, d=4) == (1, 2, 3, 4) + assert k1(1, b=2, c=3, d=4) == (1, 2, 3, 4) + assert k1(1, d=4, b=2, c=3) == (1, 2, 3, 4) + assert k1(1, 2, c=3) == (1, 2, 3, 6) + assert k1(1, 2, d=4) == (1, 2, 5, 4) + assert k1(1, 2) == (1, 2, 5, 6) + + k2 = ureg_wraps((None,), ("meter", "centimeter", "meter", "centimeter"))(kfunc) + assert k2(1 * ureg.meter, 2 * ureg.centimeter, 3 * ureg.meter, d=4 * ureg.centimeter) == (1, 2, 3, 4) + + def lfunc(a): + return a[0] + + l1 = ureg_wraps("centimeter", ("meter",))(lfunc) + assert l1([1, 2]) == 1 * ureg.centimeter + assert l1([1, 2] * ureg.meter) == 1 * ureg.centimeter + assert l1([1 * ureg.meter, 2 * ureg.meter]) == 1 * ureg.centimeter diff --git a/roseau/load_flow/units.py b/roseau/load_flow/units.py index a1e5ec51..c05896ff 100644 --- a/roseau/load_flow/units.py +++ b/roseau/load_flow/units.py @@ -28,6 +28,8 @@ from pint.facets.plain import PlainQuantity from typing_extensions import TypeAlias +from roseau.load_flow.wrapper import wraps + T = TypeVar("T") FuncT = TypeVar("FuncT", bound=Callable) @@ -53,8 +55,6 @@ def ureg_wraps( """Wraps a function to become pint-aware. Args: - ureg: - a UnitRegistry instance. ret: Units of each of the return values. Use `None` to skip argument conversion. args: @@ -62,4 +62,4 @@ def ureg_wraps( strict: Indicates that only quantities are accepted. (Default value = True) """ - return ureg.wraps(ret, args, strict) + return wraps(ureg, ret, args) diff --git a/roseau/load_flow/wrapper.py b/roseau/load_flow/wrapper.py new file mode 100644 index 00000000..98f76252 --- /dev/null +++ b/roseau/load_flow/wrapper.py @@ -0,0 +1,152 @@ +import collections +import functools +from collections.abc import Iterable +from inspect import Parameter, Signature, signature +from itertools import zip_longest +from typing import Any, Callable, Optional, TypeVar, Union + +from pint import Quantity, Unit +from pint.registry import UnitRegistry +from pint.util import to_units_container + +T = TypeVar("T") +FuncT = TypeVar("FuncT", bound=Callable) + + +def _parse_wrap_args(args: Iterable[Optional[Union[str, Unit]]]) -> Callable: + """Create a converter function for the wrapper""" + # Arguments which have units. + unit_args_ndx = set() + + # _to_units_container + args_as_uc = [to_units_container(arg) for arg in args] + + # Check for references in args, remove None values + for ndx_, arg in enumerate(args_as_uc): + if arg is not None: + unit_args_ndx.add(ndx_) + + def _converter(ureg: UnitRegistry, sig: Signature, values: list[Any], kw: dict[Any]): + len_initial_values = len(values) + + # pack kwargs + for i, param_name in enumerate(sig.parameters): + if i >= len_initial_values: + values.append(kw[param_name]) + + # convert arguments + for ndx in unit_args_ndx: + if isinstance(values[ndx], ureg.Quantity): + values[ndx] = ureg.convert(values[ndx].magnitude, values[ndx].units, args_as_uc[ndx]) + elif isinstance(values[ndx], collections.abc.MutableSequence): + for i, val in enumerate(values[ndx]): + if isinstance(val, ureg.Quantity): + values[ndx][i] = ureg.convert(val.magnitude, val.units, args_as_uc[ndx]) + + # unpack kwargs + for i, param_name in enumerate(sig.parameters): + if i >= len_initial_values: + kw[param_name] = values[i] + + return values[:len_initial_values], kw + + return _converter + + +def _apply_defaults(sig: Signature, args: tuple[Any], kwargs: dict[Any]) -> tuple[list[Any], dict[Any]]: + """Apply default keyword arguments. + + Named keywords may have been left blank. This function applies the default + values so that every argument is defined. + """ + for i, param in enumerate(sig.parameters.values()): + if i >= len(args) and param.default != Parameter.empty and param.name not in kwargs: + kwargs[param.name] = param.default + return list(args), kwargs + + +def wraps( + ureg: UnitRegistry, + ret: Optional[Union[str, Unit, Iterable[Optional[Union[str, Unit]]]]], + args: Optional[Union[str, Unit, Iterable[Optional[Union[str, Unit]]]]], +) -> Callable[[FuncT], FuncT]: + """Wraps a function to become pint-aware. + + Use it when a function requires a numerical value but in some specific + units. The wrapper function will take a pint quantity, convert to the units + specified in `args` and then call the wrapped function with the resulting + magnitude. + + The value returned by the wrapped function will be converted to the units + specified in `ret`. + + Args: + ureg: + A UnitRegistry instance. + + ret: + Units of each of the return values. Use `None` to skip argument conversion. + + args: + Units of each of the input arguments. Use `None` to skip argument conversion. + + Returns: + The wrapper function. + + Raises: + TypeError + if the number of given arguments does not match the number of function parameters. + if any of the provided arguments is not a unit a string or Quantity + """ + if not isinstance(args, (list, tuple)): + args = (args,) + + for arg in args: + if arg is not None and not isinstance(arg, (ureg.Unit, str)): + raise TypeError(f"wraps arguments must by of type str or Unit, not {type(arg)} ({arg})") + + converter = _parse_wrap_args(args) + + is_ret_container = isinstance(ret, (list, tuple)) + if is_ret_container: + for arg in ret: + if arg is not None and not isinstance(arg, (ureg.Unit, str)): + raise TypeError(f"wraps 'ret' argument must by of type str or Unit, not {type(arg)} ({arg})") + ret = ret.__class__([to_units_container(arg, ureg) for arg in ret]) + else: + if ret is not None and not isinstance(ret, (ureg.Unit, str)): + raise TypeError(f"wraps 'ret' argument must by of type str or Unit, not {type(ret)} ({ret})") + ret = to_units_container(ret, ureg) + + def decorator(func: Callable[..., Any]) -> Callable[..., Quantity]: + sig = signature(func) + count_params = len(sig.parameters) + if len(args) != count_params: + raise TypeError(f"{func.__name__} takes {count_params} parameters, but {len(args)} units were passed") + + assigned = tuple(attr for attr in functools.WRAPPER_ASSIGNMENTS if hasattr(func, attr)) + updated = tuple(attr for attr in functools.WRAPPER_UPDATES if hasattr(func, attr)) + + @functools.wraps(func, assigned=assigned, updated=updated) + def wrapper(*values, **kw) -> Quantity: + values, kw = _apply_defaults(sig, values, kw) + + # In principle, the values are used as is + # When then extract the magnitudes when needed. + new_values, new_kw = converter(ureg, sig, values, kw) + + result = func(*new_values, **new_kw) + + if is_ret_container: + return ret.__class__( + res if unit is None else ureg.Quantity(res, unit) for unit, res in zip_longest(ret, result) + ) + + if ret is None: + return result + + return ureg.Quantity(result, ret) + + return wrapper + + return decorator From e10880d6c167d134ae2bdde9dbfa9e4135755caf Mon Sep 17 00:00:00 2001 From: Saelyos Date: Fri, 17 Nov 2023 16:04:45 +0100 Subject: [PATCH 39/43] Update changelog --- doc/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Changelog.md b/doc/Changelog.md index 74a08479..75870b35 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,6 +4,7 @@ **In development** +- {gh-pr}`149` {gh-issue}`145` Add custom pint wrapper for better handling of pint arrays. - {gh-pr}`148` {gh-issue}`122` deprecate `LineParameters.from_name_lv()` in favor of the more generic `LineParameters.from_geometry()`. The method will be removed in a future release. - {gh-pr}`142` {gh-issue}`136` Add `Bus.res_voltage_unbalance()` method to get the Voltage Unbalance From 94073bdbb4337e47a8f5b68cf7de7fb12d7b8fec Mon Sep 17 00:00:00 2001 From: Saelyos Date: Fri, 17 Nov 2023 16:11:35 +0100 Subject: [PATCH 40/43] Make wrapper private, minor changes --- roseau/load_flow/{wrapper.py => _wrapper.py} | 26 +++++++++----------- roseau/load_flow/units.py | 2 +- 2 files changed, 12 insertions(+), 16 deletions(-) rename roseau/load_flow/{wrapper.py => _wrapper.py} (86%) diff --git a/roseau/load_flow/wrapper.py b/roseau/load_flow/_wrapper.py similarity index 86% rename from roseau/load_flow/wrapper.py rename to roseau/load_flow/_wrapper.py index 98f76252..3f0153f7 100644 --- a/roseau/load_flow/wrapper.py +++ b/roseau/load_flow/_wrapper.py @@ -1,6 +1,5 @@ -import collections import functools -from collections.abc import Iterable +from collections.abc import Iterable, MutableSequence from inspect import Parameter, Signature, signature from itertools import zip_longest from typing import Any, Callable, Optional, TypeVar, Union @@ -15,16 +14,11 @@ def _parse_wrap_args(args: Iterable[Optional[Union[str, Unit]]]) -> Callable: """Create a converter function for the wrapper""" - # Arguments which have units. - unit_args_ndx = set() - # _to_units_container args_as_uc = [to_units_container(arg) for arg in args] # Check for references in args, remove None values - for ndx_, arg in enumerate(args_as_uc): - if arg is not None: - unit_args_ndx.add(ndx_) + unit_args_ndx = {ndx for ndx, arg in enumerate(args_as_uc) if arg is not None} def _converter(ureg: UnitRegistry, sig: Signature, values: list[Any], kw: dict[Any]): len_initial_values = len(values) @@ -36,12 +30,13 @@ def _converter(ureg: UnitRegistry, sig: Signature, values: list[Any], kw: dict[A # convert arguments for ndx in unit_args_ndx: - if isinstance(values[ndx], ureg.Quantity): - values[ndx] = ureg.convert(values[ndx].magnitude, values[ndx].units, args_as_uc[ndx]) - elif isinstance(values[ndx], collections.abc.MutableSequence): - for i, val in enumerate(values[ndx]): + value = values[ndx] + if isinstance(value, ureg.Quantity): + values[ndx] = ureg.convert(value.magnitude, value.units, args_as_uc[ndx]) + elif isinstance(value, MutableSequence): + for i, val in enumerate(value): if isinstance(val, ureg.Quantity): - values[ndx][i] = ureg.convert(val.magnitude, val.units, args_as_uc[ndx]) + value[i] = ureg.convert(val.magnitude, val.units, args_as_uc[ndx]) # unpack kwargs for i, param_name in enumerate(sig.parameters): @@ -53,14 +48,15 @@ def _converter(ureg: UnitRegistry, sig: Signature, values: list[Any], kw: dict[A return _converter -def _apply_defaults(sig: Signature, args: tuple[Any], kwargs: dict[Any]) -> tuple[list[Any], dict[Any]]: +def _apply_defaults(sig: Signature, args: tuple[Any], kwargs: dict[str, Any]) -> tuple[list[Any], dict[str, Any]]: """Apply default keyword arguments. Named keywords may have been left blank. This function applies the default values so that every argument is defined. """ + n = len(args) for i, param in enumerate(sig.parameters.values()): - if i >= len(args) and param.default != Parameter.empty and param.name not in kwargs: + if i >= n and param.default != Parameter.empty and param.name not in kwargs: kwargs[param.name] = param.default return list(args), kwargs diff --git a/roseau/load_flow/units.py b/roseau/load_flow/units.py index c05896ff..f580f0e9 100644 --- a/roseau/load_flow/units.py +++ b/roseau/load_flow/units.py @@ -28,7 +28,7 @@ from pint.facets.plain import PlainQuantity from typing_extensions import TypeAlias -from roseau.load_flow.wrapper import wraps +from roseau.load_flow._wrapper import wraps T = TypeVar("T") FuncT = TypeVar("FuncT", bound=Callable) From b29d47d12ffc7fd153ff5954a7593a93a609d522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 28 Nov 2023 17:42:02 +0100 Subject: [PATCH 41/43] Use ruff formatter --- .pre-commit-config.yaml | 16 +- poetry.lock | 1211 ++++++++++++--------------------------- pyproject.toml | 7 +- 3 files changed, 376 insertions(+), 858 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d6165d96..c7a8257c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,19 +13,17 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/python-poetry/poetry - rev: 1.6.0 + rev: 1.7.0 hooks: - id: poetry-check - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.10.1 # keep in sync with pyproject.toml - hooks: - - id: black-jupyter - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.1.3 # keep in sync with pyproject.toml + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.6 # keep in sync with pyproject.toml hooks: - id: ruff types_or: [python, pyi, jupyter] - args: [--fix, --exit-non-zero-on-fix] + args: [--fix] + - id: ruff-format + types_or: [python, pyi, jupyter] - repo: https://github.com/adamchainz/blacken-docs rev: 1.16.0 hooks: @@ -34,7 +32,7 @@ repos: args: [-l 90] additional_dependencies: [black==23.10.1] # keep in sync with black above - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.3 + rev: v3.1.0 hooks: - id: prettier args: ["--print-width", "120"] diff --git a/poetry.lock b/poetry.lock index e5c3ebbb..2d058cdc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "alabaster" @@ -22,17 +22,6 @@ files = [ {file = "anyascii-0.3.2.tar.gz", hash = "sha256:9d5d32ef844fe225b8bc7cba7f950534fae4da27a9bf3a6bea2cb0ea46ce4730"}, ] -[[package]] -name = "appnope" -version = "0.1.3" -description = "Disable App Nap on macOS >= 10.9" -optional = false -python-versions = "*" -files = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, -] - [[package]] name = "astroid" version = "3.0.1" @@ -47,24 +36,6 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} -[[package]] -name = "asttokens" -version = "2.4.1" -description = "Annotate AST trees with source code positions" -optional = false -python-versions = "*" -files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, -] - -[package.dependencies] -six = ">=1.12.0" - -[package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] - [[package]] name = "attrs" version = "23.1.0" @@ -118,59 +89,15 @@ soupsieve = ">1.2" html5lib = ["html5lib"] lxml = ["lxml"] -[[package]] -name = "black" -version = "23.10.1" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"}, - {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"}, - {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"}, - {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"}, - {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"}, - {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"}, - {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"}, - {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"}, - {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"}, - {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"}, - {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"}, - {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"}, -] - -[package.dependencies] -click = ">=8.0.0" -ipython = {version = ">=7.8.0", optional = true, markers = "extra == \"jupyter\""} -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tokenize-rt = {version = ">=3.2.0", optional = true, markers = "extra == \"jupyter\""} -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "certifi" -version = "2023.7.22" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] @@ -186,101 +113,101 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.1" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.1.tar.gz", hash = "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-win32.whl", hash = "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-win32.whl", hash = "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-win32.whl", hash = "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-win32.whl", hash = "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-win32.whl", hash = "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-win32.whl", hash = "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727"}, - {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] @@ -344,135 +271,66 @@ files = [ [[package]] name = "contourpy" -version = "1.1.0" -description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false -python-versions = ">=3.8" -files = [ - {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, - {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, - {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, - {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, - {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, - {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, - {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, - {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, - {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, - {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, - {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, -] - -[package.dependencies] -numpy = ">=1.16" - -[package.extras] -bokeh = ["bokeh", "selenium"] -docs = ["furo", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] -test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] - -[[package]] -name = "contourpy" -version = "1.1.1" +version = "1.2.0" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, - {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, - {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, - {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, - {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, - {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, - {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, - {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, - {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, - {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, - {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, - {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, - {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, - {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, - {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, - {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, - {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, - {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, + {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, + {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, + {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, + {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, + {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, + {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, + {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, + {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, + {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, ] [package.dependencies] -numpy = [ - {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""}, - {version = ">=1.26.0rc1,<2.0", markers = "python_version >= \"3.12\""}, -] +numpy = ">=1.20,<2.0" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" @@ -556,17 +414,6 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] -[[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -optional = false -python-versions = ">=3.5" -files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] - [[package]] name = "distlib" version = "0.3.7" @@ -591,13 +438,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -617,29 +464,15 @@ files = [ [package.extras] testing = ["hatch", "pre-commit", "pytest", "tox"] -[[package]] -name = "executing" -version = "2.0.1" -description = "Get the currently executing AST node of a frame, and other information" -optional = false -python-versions = ">=3.5" -files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, -] - -[package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] - [[package]] name = "filelock" -version = "3.13.0" +version = "3.13.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.0-py3-none-any.whl", hash = "sha256:a552f4fde758f4eab33191e9548f671970f8b06d436d31388c9aa1e5861a710f"}, - {file = "filelock-3.13.0.tar.gz", hash = "sha256:63c6052c82a1a24c873a549fbd39a26982e8f35a3016da231ead11a5be9dad44"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] [package.extras] @@ -698,57 +531,57 @@ test = ["Fiona[s3]", "pytest (>=7)", "pytest-cov", "pytz"] [[package]] name = "fonttools" -version = "4.43.1" +version = "4.45.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.43.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf11e2cca121df35e295bd34b309046c29476ee739753bc6bc9d5050de319273"}, - {file = "fonttools-4.43.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10b3922875ffcba636674f406f9ab9a559564fdbaa253d66222019d569db869c"}, - {file = "fonttools-4.43.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f727c3e3d08fd25352ed76cc3cb61486f8ed3f46109edf39e5a60fc9fecf6ca"}, - {file = "fonttools-4.43.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad0b3f6342cfa14be996971ea2b28b125ad681c6277c4cd0fbdb50340220dfb6"}, - {file = "fonttools-4.43.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b7ad05b2beeebafb86aa01982e9768d61c2232f16470f9d0d8e385798e37184"}, - {file = "fonttools-4.43.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c54466f642d2116686268c3e5f35ebb10e49b0d48d41a847f0e171c785f7ac7"}, - {file = "fonttools-4.43.1-cp310-cp310-win32.whl", hash = "sha256:1e09da7e8519e336239fbd375156488a4c4945f11c4c5792ee086dd84f784d02"}, - {file = "fonttools-4.43.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cf9e974f63b1080b1d2686180fc1fbfd3bfcfa3e1128695b5de337eb9075cef"}, - {file = "fonttools-4.43.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5db46659cfe4e321158de74c6f71617e65dc92e54980086823a207f1c1c0e24b"}, - {file = "fonttools-4.43.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1952c89a45caceedf2ab2506d9a95756e12b235c7182a7a0fff4f5e52227204f"}, - {file = "fonttools-4.43.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c36da88422e0270fbc7fd959dc9749d31a958506c1d000e16703c2fce43e3d0"}, - {file = "fonttools-4.43.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bbbf8174501285049e64d174e29f9578495e1b3b16c07c31910d55ad57683d8"}, - {file = "fonttools-4.43.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d4071bd1c183b8d0b368cc9ed3c07a0f6eb1bdfc4941c4c024c49a35429ac7cd"}, - {file = "fonttools-4.43.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d21099b411e2006d3c3e1f9aaf339e12037dbf7bf9337faf0e93ec915991f43b"}, - {file = "fonttools-4.43.1-cp311-cp311-win32.whl", hash = "sha256:b84a1c00f832feb9d0585ca8432fba104c819e42ff685fcce83537e2e7e91204"}, - {file = "fonttools-4.43.1-cp311-cp311-win_amd64.whl", hash = "sha256:9a2f0aa6ca7c9bc1058a9d0b35483d4216e0c1bbe3962bc62ce112749954c7b8"}, - {file = "fonttools-4.43.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4d9740e3783c748521e77d3c397dc0662062c88fd93600a3c2087d3d627cd5e5"}, - {file = "fonttools-4.43.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:884ef38a5a2fd47b0c1291647b15f4e88b9de5338ffa24ee52c77d52b4dfd09c"}, - {file = "fonttools-4.43.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9648518ef687ba818db3fcc5d9aae27a369253ac09a81ed25c3867e8657a0680"}, - {file = "fonttools-4.43.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95e974d70238fc2be5f444fa91f6347191d0e914d5d8ae002c9aa189572cc215"}, - {file = "fonttools-4.43.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:34f713dad41aa21c637b4e04fe507c36b986a40f7179dcc86402237e2d39dcd3"}, - {file = "fonttools-4.43.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:360201d46165fc0753229afe785900bc9596ee6974833124f4e5e9f98d0f592b"}, - {file = "fonttools-4.43.1-cp312-cp312-win32.whl", hash = "sha256:bb6d2f8ef81ea076877d76acfb6f9534a9c5f31dc94ba70ad001267ac3a8e56f"}, - {file = "fonttools-4.43.1-cp312-cp312-win_amd64.whl", hash = "sha256:25d3da8a01442cbc1106490eddb6d31d7dffb38c1edbfabbcc8db371b3386d72"}, - {file = "fonttools-4.43.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8da417431bfc9885a505e86ba706f03f598c85f5a9c54f67d63e84b9948ce590"}, - {file = "fonttools-4.43.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:51669b60ee2a4ad6c7fc17539a43ffffc8ef69fd5dbed186a38a79c0ac1f5db7"}, - {file = "fonttools-4.43.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748015d6f28f704e7d95cd3c808b483c5fb87fd3eefe172a9da54746ad56bfb6"}, - {file = "fonttools-4.43.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a58eb5e736d7cf198eee94844b81c9573102ae5989ebcaa1d1a37acd04b33d"}, - {file = "fonttools-4.43.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6bb5ea9076e0e39defa2c325fc086593ae582088e91c0746bee7a5a197be3da0"}, - {file = "fonttools-4.43.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5f37e31291bf99a63328668bb83b0669f2688f329c4c0d80643acee6e63cd933"}, - {file = "fonttools-4.43.1-cp38-cp38-win32.whl", hash = "sha256:9c60ecfa62839f7184f741d0509b5c039d391c3aff71dc5bc57b87cc305cff3b"}, - {file = "fonttools-4.43.1-cp38-cp38-win_amd64.whl", hash = "sha256:fe9b1ec799b6086460a7480e0f55c447b1aca0a4eecc53e444f639e967348896"}, - {file = "fonttools-4.43.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13a9a185259ed144def3682f74fdcf6596f2294e56fe62dfd2be736674500dba"}, - {file = "fonttools-4.43.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2adca1b46d69dce4a37eecc096fe01a65d81a2f5c13b25ad54d5430ae430b13"}, - {file = "fonttools-4.43.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18eefac1b247049a3a44bcd6e8c8fd8b97f3cad6f728173b5d81dced12d6c477"}, - {file = "fonttools-4.43.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2062542a7565091cea4cc14dd99feff473268b5b8afdee564f7067dd9fff5860"}, - {file = "fonttools-4.43.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18a2477c62a728f4d6e88c45ee9ee0229405e7267d7d79ce1f5ce0f3e9f8ab86"}, - {file = "fonttools-4.43.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a7a06f8d95b7496e53af80d974d63516ffb263a468e614978f3899a6df52d4b3"}, - {file = "fonttools-4.43.1-cp39-cp39-win32.whl", hash = "sha256:10003ebd81fec0192c889e63a9c8c63f88c7d72ae0460b7ba0cd2a1db246e5ad"}, - {file = "fonttools-4.43.1-cp39-cp39-win_amd64.whl", hash = "sha256:e117a92b07407a061cde48158c03587ab97e74e7d73cb65e6aadb17af191162a"}, - {file = "fonttools-4.43.1-py3-none-any.whl", hash = "sha256:4f88cae635bfe4bbbdc29d479a297bb525a94889184bb69fa9560c2d4834ddb9"}, - {file = "fonttools-4.43.1.tar.gz", hash = "sha256:17dbc2eeafb38d5d0e865dcce16e313c58265a6d2d20081c435f84dc5a9d8212"}, + {file = "fonttools-4.45.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:45fa321c458ea29224067700954ec44493ae869b47e7c5485a350a149a19fb53"}, + {file = "fonttools-4.45.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0dc7617d96b1e668eea9250e1c1fe62d0c78c3f69573ce7e3332cc40e6d84356"}, + {file = "fonttools-4.45.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ed3bda541e86725f6b4e1b94213f13ed1ae51a5a1f167028534cedea38c010"}, + {file = "fonttools-4.45.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f4a5870e3b56788fb196da8cf30d0dfd51a76dc3b907861d018165f76ae4c2"}, + {file = "fonttools-4.45.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a3c11d9687479f01eddef729aa737abcdea0a44fdaffb62a930a18892f186c9b"}, + {file = "fonttools-4.45.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:316cec50581e844c3ab69d7c82455b54c7cf18236b2f09e722faf665fbfcac58"}, + {file = "fonttools-4.45.1-cp310-cp310-win32.whl", hash = "sha256:e2277cba9f0b525e30de2a9ad3cb4219aa4bc697230c1645666b0deee9f914f0"}, + {file = "fonttools-4.45.1-cp310-cp310-win_amd64.whl", hash = "sha256:1b9e9ad2bcded9a1431afaa57c8d3c39143ac1f050862d66bddd863c515464a2"}, + {file = "fonttools-4.45.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff6a698bdd435d24c379f6e8a54908cd9bb7dda23719084d56bf8c87709bf3bd"}, + {file = "fonttools-4.45.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c980d60cd6ec1376206fe55013d166e5627ad0b149b5c81e74eaa913ab6134f"}, + {file = "fonttools-4.45.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a12dee6523c02ca78aeedd0a5e12bfa9b7b29896350edd5241542897b072ae23"}, + {file = "fonttools-4.45.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37cd1ced6efb3dd6fe82e9f9bf92fd74ac58a5aefc284045f59ecd517a5fb9ab"}, + {file = "fonttools-4.45.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e3d24248221bd7151dfff0d88b1b5da02dccd7134bd576ce8888199827bbaa19"}, + {file = "fonttools-4.45.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba6c23591427844dfb0a13658f1718489de75de6a46b64234584c0d17573162d"}, + {file = "fonttools-4.45.1-cp311-cp311-win32.whl", hash = "sha256:cebcddbe9351b67166292b4f71ffdbfcce01ba4b07d4267824eb46b277aeb19a"}, + {file = "fonttools-4.45.1-cp311-cp311-win_amd64.whl", hash = "sha256:f22eb69996a0bd49f76bdefb30be54ce8dbb89a0d1246874d610f05c2aa2e69e"}, + {file = "fonttools-4.45.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:794de93e83297db7b4943f2431e206d8b1ea69cb3ae14638a49cc50332bf0db8"}, + {file = "fonttools-4.45.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4ba17822a6681d06849078daaf6e03eccc9f467efe7c4c60280e28a78e8e5df9"}, + {file = "fonttools-4.45.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e50f794d09df0675da8d9dbd7c66bfcab2f74a708343aabcad41936d26556891"}, + {file = "fonttools-4.45.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b07b857d4f9de3199a8c3d1b1bf2078c0f37447891ca1a8d9234106b9a27aff"}, + {file = "fonttools-4.45.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:777ba42b94a27bb7fb2b4082522fccfd345667c32a56011e1c3e105979af5b79"}, + {file = "fonttools-4.45.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:21e96b99878348c74aa58059b8578d7586f9519cbcdadacf56486737038aa043"}, + {file = "fonttools-4.45.1-cp312-cp312-win32.whl", hash = "sha256:5cbf02cda8465b69769d07385f5d11e7bba19954e7787792f46fe679ec755ebb"}, + {file = "fonttools-4.45.1-cp312-cp312-win_amd64.whl", hash = "sha256:800e354e0c3afaeb8d9552769773d02f228e98c37b8cb03041157c3d0687cffc"}, + {file = "fonttools-4.45.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6eb2c54f7a07c92108daabcf02caf31df97825738db02a28270633946bcda4d0"}, + {file = "fonttools-4.45.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43a3d267334109ff849c37cf3629476b5feb392ef1d2e464a167b83de8cd599c"}, + {file = "fonttools-4.45.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e1aefc2bf3c43e0f33f995f828a7bbeff4adc9393a7760b11456dbcf14388f6"}, + {file = "fonttools-4.45.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f53a19dcdd5737440839b8394eeebb35da9ec8109f7926cb6456639b5b58e47"}, + {file = "fonttools-4.45.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a17706b9cc24b27721613fe5773d93331ab7f0ecaca9955aead89c6b843d3a7"}, + {file = "fonttools-4.45.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fb36e5f40191274a95938b40c0a1fa7f895e36935aea8709e1d6deff0b2d0d4f"}, + {file = "fonttools-4.45.1-cp38-cp38-win32.whl", hash = "sha256:46eabddec12066829b8a1efe45ae552ba2f1796981ecf538d5f68284c354c589"}, + {file = "fonttools-4.45.1-cp38-cp38-win_amd64.whl", hash = "sha256:b6de2f0fcd3302fb82f94801002cb473959e998c14c24ec28234adb674aed345"}, + {file = "fonttools-4.45.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:392d0e3cc23daee910193625f7cf1b387aff9dd5b6f1a5f4a925680acb6dcbc2"}, + {file = "fonttools-4.45.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b9544b1346d99848ac0e9b05b5d45ee703d7562fc4c9c48cf4b781de9632e57"}, + {file = "fonttools-4.45.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8717db3e4895e4820ade64ea379187738827ee60748223cb0438ef044ee208c6"}, + {file = "fonttools-4.45.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e29d5f298d616a93a4c5963682dc6cc8cc09f6d89cad2c29019fc5fb3b4d9472"}, + {file = "fonttools-4.45.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cb472905da3049960e80fc1cf808231880d79727a8410e156bf3e5063a1c574f"}, + {file = "fonttools-4.45.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ba299f1fbaa2a1e33210aaaf6fa816d4059e4d3cfe2ae9871368d4ab548c1c6a"}, + {file = "fonttools-4.45.1-cp39-cp39-win32.whl", hash = "sha256:105099968b58a5b4cef6f3eb409db8ea8578b302a9d05e23fecba1b8b0177b5f"}, + {file = "fonttools-4.45.1-cp39-cp39-win_amd64.whl", hash = "sha256:847f3f49dd3423e5a678c098e2ba92c7f4955d4aab3044f6a507b0bb0ecb07e0"}, + {file = "fonttools-4.45.1-py3-none-any.whl", hash = "sha256:3bdd7dfca8f6c9f4779384064027e8477ad6a037d6a327b09381f43e0247c6f3"}, + {file = "fonttools-4.45.1.tar.gz", hash = "sha256:6e441286d55fe7ec7c4fb36812bf914924813776ff514b744b510680fc2733f2"}, ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "scipy"] lxml = ["lxml (>=4.0,<5)"] @@ -758,7 +591,7 @@ repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.0.0)"] +unicode = ["unicodedata2 (>=15.1.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] @@ -780,13 +613,13 @@ sphinx-basic-ng = "*" [[package]] name = "geopandas" -version = "0.14.0" +version = "0.14.1" description = "Geographic pandas extensions" optional = false python-versions = ">=3.9" files = [ - {file = "geopandas-0.14.0-py3-none-any.whl", hash = "sha256:a402a565e727642cb44a500c911f226eea26c1b1247c6586827031e3d7a9403a"}, - {file = "geopandas-0.14.0.tar.gz", hash = "sha256:ea6c031889e1e1888aecaa6e182ca620d78f63551c49b3002a998bcbb280531f"}, + {file = "geopandas-0.14.1-py3-none-any.whl", hash = "sha256:ed5a7cae7874bfc3238fb05e0501cc1760e1b7b11e5b76ecad29da644ca305da"}, + {file = "geopandas-0.14.1.tar.gz", hash = "sha256:4853ff89ecb6d1cfc43e7b3671092c8160e8a46a3dd7368f25906283314e42bb"}, ] [package.dependencies] @@ -798,13 +631,13 @@ shapely = ">=1.8.0" [[package]] name = "identify" -version = "2.5.31" +version = "2.5.32" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"}, - {file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"}, + {file = "identify-2.5.32-py2.py3-none-any.whl", hash = "sha256:0b7656ef6cba81664b783352c73f8c24b39cf82f926f78f4550eda928e5e0545"}, + {file = "identify-2.5.32.tar.gz", hash = "sha256:5d9979348ec1a21c768ae07e0a652924538e8bce67313a73cb0f681cf08ba407"}, ] [package.extras] @@ -812,13 +645,13 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -853,13 +686,13 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs [[package]] name = "importlib-resources" -version = "6.1.0" +version = "6.1.1" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.0-py3-none-any.whl", hash = "sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83"}, - {file = "importlib_resources-6.1.0.tar.gz", hash = "sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9"}, + {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, + {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, ] [package.dependencies] @@ -880,63 +713,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "ipython" -version = "8.17.0" -description = "IPython: Productive Interactive Computing" -optional = false -python-versions = ">=3.9" -files = [ - {file = "ipython-8.17.0-py3-none-any.whl", hash = "sha256:5feb75ac603a6663de233196e1beea81ec9e5042916d4e30eb42ac09adc718d8"}, - {file = "ipython-8.17.0.tar.gz", hash = "sha256:ec8023527c477910939841d4dc2348f8f843b310a504a49db7559bd6b7579953"}, -] - -[package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -colorama = {version = "*", markers = "sys_platform == \"win32\""} -decorator = "*" -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} -jedi = ">=0.16" -matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" -pygments = ">=2.4.0" -stack-data = "*" -traitlets = ">=5" -typing-extensions = {version = "*", markers = "python_version < \"3.10\""} - -[package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] -black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] -kernel = ["ipykernel"] -nbconvert = ["nbconvert"] -nbformat = ["nbformat"] -notebook = ["ipywidgets", "notebook"] -parallel = ["ipyparallel"] -qtconsole = ["qtconsole"] -test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] - -[[package]] -name = "jedi" -version = "0.19.1" -description = "An autocompletion tool for Python that can be used for text editors." -optional = false -python-versions = ">=3.6" -files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, -] - -[package.dependencies] -parso = ">=0.8.3,<0.9.0" - -[package.extras] -docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] -qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] - [[package]] name = "jinja2" version = "3.1.2" @@ -1132,6 +908,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -1166,39 +952,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.0" +version = "3.8.2" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c4940bad88a932ddc69734274f6fb047207e008389489f2b6f77d9ca485f0e7a"}, - {file = "matplotlib-3.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a33bd3045c7452ca1fa65676d88ba940867880e13e2546abb143035fa9072a9d"}, - {file = "matplotlib-3.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea6886e93401c22e534bbfd39201ce8931b75502895cfb115cbdbbe2d31f287"}, - {file = "matplotlib-3.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d670b9348e712ec176de225d425f150dc8e37b13010d85233c539b547da0be39"}, - {file = "matplotlib-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7b37b74f00c4cb6af908cb9a00779d97d294e89fd2145ad43f0cdc23f635760c"}, - {file = "matplotlib-3.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:0e723f5b96f3cd4aad99103dc93e9e3cdc4f18afdcc76951f4857b46f8e39d2d"}, - {file = "matplotlib-3.8.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5dc945a9cb2deb7d197ba23eb4c210e591d52d77bf0ba27c35fc82dec9fa78d4"}, - {file = "matplotlib-3.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8b5a1bf27d078453aa7b5b27f52580e16360d02df6d3dc9504f3d2ce11f6309"}, - {file = "matplotlib-3.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f25ffb6ad972cdffa7df8e5be4b1e3cadd2f8d43fc72085feb1518006178394"}, - {file = "matplotlib-3.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee482731c8c17d86d9ddb5194d38621f9b0f0d53c99006275a12523ab021732"}, - {file = "matplotlib-3.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:36eafe2128772195b373e1242df28d1b7ec6c04c15b090b8d9e335d55a323900"}, - {file = "matplotlib-3.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:061ee58facb3580cd2d046a6d227fb77e9295599c5ec6ad069f06b5821ad1cfc"}, - {file = "matplotlib-3.8.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3cc3776836d0f4f22654a7f2d2ec2004618d5cf86b7185318381f73b80fd8a2d"}, - {file = "matplotlib-3.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c49a2bd6981264bddcb8c317b6bd25febcece9e2ebfcbc34e7f4c0c867c09dc"}, - {file = "matplotlib-3.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ed11654fc83cd6cfdf6170b453e437674a050a452133a064d47f2f1371f8d3"}, - {file = "matplotlib-3.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dae97fdd6996b3a25da8ee43e3fc734fff502f396801063c6b76c20b56683196"}, - {file = "matplotlib-3.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:87df75f528020a6299f76a1d986c0ed4406e3b2bd44bc5e306e46bca7d45e53e"}, - {file = "matplotlib-3.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:90d74a95fe055f73a6cd737beecc1b81c26f2893b7a3751d52b53ff06ca53f36"}, - {file = "matplotlib-3.8.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c3499c312f5def8f362a2bf761d04fa2d452b333f3a9a3f58805273719bf20d9"}, - {file = "matplotlib-3.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31e793c8bd4ea268cc5d3a695c27b30650ec35238626961d73085d5e94b6ab68"}, - {file = "matplotlib-3.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d5ee602ef517a89d1f2c508ca189cfc395dd0b4a08284fb1b97a78eec354644"}, - {file = "matplotlib-3.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5de39dc61ca35342cf409e031f70f18219f2c48380d3886c1cf5ad9f17898e06"}, - {file = "matplotlib-3.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:dd386c80a98b5f51571b9484bf6c6976de383cd2a8cd972b6a9562d85c6d2087"}, - {file = "matplotlib-3.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:f691b4ef47c7384d0936b2e8ebdeb5d526c81d004ad9403dfb9d4c76b9979a93"}, - {file = "matplotlib-3.8.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0b11f354aae62a2aa53ec5bb09946f5f06fc41793e351a04ff60223ea9162955"}, - {file = "matplotlib-3.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f54b9fb87ca5acbcdd0f286021bedc162e1425fa5555ebf3b3dfc167b955ad9"}, - {file = "matplotlib-3.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:60a6e04dfd77c0d3bcfee61c3cd335fff1b917c2f303b32524cd1235e194ef99"}, - {file = "matplotlib-3.8.0.tar.gz", hash = "sha256:df8505e1c19d5c2c26aff3497a7cbd3ccfc2e97043d1e4db3e76afa399164b69"}, + {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, + {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, + {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, + {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, + {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, + {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, + {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, + {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, + {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, + {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, + {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, ] [package.dependencies] @@ -1206,27 +992,12 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} -kiwisolver = ">=1.0.1" +kiwisolver = ">=1.3.1" numpy = ">=1.21,<2" packaging = ">=20.0" -pillow = ">=6.2.0" +pillow = ">=8" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" -setuptools_scm = ">=7" - -[[package]] -name = "matplotlib-inline" -version = "0.1.6" -description = "Inline Matplotlib backend for Jupyter" -optional = false -python-versions = ">=3.5" -files = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, -] - -[package.dependencies] -traitlets = "*" [[package]] name = "mdit-py-plugins" @@ -1258,17 +1029,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - [[package]] name = "myst-parser" version = "2.0.0" @@ -1329,77 +1089,47 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.25.2" +version = "1.26.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, - {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, - {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, - {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, - {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, - {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, - {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, - {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, - {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, - {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, - {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, - {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, -] - -[[package]] -name = "numpy" -version = "1.26.1" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = "<3.13,>=3.9" -files = [ - {file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"}, - {file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"}, - {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"}, - {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"}, - {file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"}, - {file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"}, - {file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"}, - {file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"}, - {file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"}, - {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"}, - {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"}, - {file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"}, - {file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"}, - {file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"}, - {file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"}, - {file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"}, - {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"}, - {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"}, - {file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"}, - {file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"}, - {file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"}, - {file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"}, - {file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"}, - {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"}, - {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"}, - {file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"}, - {file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"}, - {file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"}, - {file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"}, - {file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"}, - {file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"}, - {file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"}, + {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, + {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, + {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, + {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, + {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, + {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, + {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, + {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, + {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, + {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, + {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, + {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, + {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, + {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, + {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, + {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, + {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, + {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, + {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, + {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, + {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, + {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, + {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, + {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, + {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, + {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, + {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, + {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, + {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, + {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, + {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, + {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, + {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, ] [[package]] @@ -1415,94 +1145,36 @@ files = [ [[package]] name = "pandas" -version = "2.1.0" -description = "Powerful data structures for data analysis, time series, and statistics" -optional = false -python-versions = ">=3.9" -files = [ - {file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"}, - {file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"}, - {file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"}, - {file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"}, - {file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"}, - {file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"}, - {file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"}, - {file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"}, - {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, -] - -[package.dependencies] -numpy = {version = ">=1.23.2", markers = "python_version >= \"3.11\""} -python-dateutil = ">=2.8.2" -pytz = ">=2020.1" -tzdata = ">=2022.1" - -[package.extras] -all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] -aws = ["s3fs (>=2022.05.0)"] -clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] -compression = ["zstandard (>=0.17.0)"] -computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] -consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] -feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2022.05.0)"] -gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] -hdf5 = ["tables (>=3.7.0)"] -html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] -mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] -parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] -plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] -spss = ["pyreadstat (>=1.1.5)"] -sql-other = ["SQLAlchemy (>=1.4.36)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.8.0)"] - -[[package]] -name = "pandas" -version = "2.1.2" +version = "2.1.3" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24057459f19db9ebb02984c6fdd164a970b31a95f38e4a49cf7615b36a1b532c"}, - {file = "pandas-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6cf8fcc8a63d333970b950a7331a30544cf59b1a97baf0a7409e09eafc1ac38"}, - {file = "pandas-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ae6ffbd9d614c20d028c7117ee911fc4e266b4dca2065d5c5909e401f8ff683"}, - {file = "pandas-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff794eeb7883c5aefb1ed572e7ff533ae779f6c6277849eab9e77986e352688"}, - {file = "pandas-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02954e285e8e2f4006b6f22be6f0df1f1c3c97adbb7ed211c6b483426f20d5c8"}, - {file = "pandas-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:5b40c9f494e1f27588c369b9e4a6ca19cd924b3a0e1ef9ef1a8e30a07a438f43"}, - {file = "pandas-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:08d287b68fd28906a94564f15118a7ca8c242e50ae7f8bd91130c362b2108a81"}, - {file = "pandas-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bbd98dcdcd32f408947afdb3f7434fade6edd408c3077bbce7bd840d654d92c6"}, - {file = "pandas-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90c95abb3285d06f6e4feedafc134306a8eced93cb78e08cf50e224d5ce22e2"}, - {file = "pandas-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52867d69a54e71666cd184b04e839cff7dfc8ed0cd6b936995117fdae8790b69"}, - {file = "pandas-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d0382645ede2fde352da2a885aac28ec37d38587864c0689b4b2361d17b1d4c"}, - {file = "pandas-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:65177d1c519b55e5b7f094c660ed357bb7d86e799686bb71653b8a4803d8ff0d"}, - {file = "pandas-2.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5aa6b86802e8cf7716bf4b4b5a3c99b12d34e9c6a9d06dad254447a620437931"}, - {file = "pandas-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d594e2ce51b8e0b4074e6644758865dc2bb13fd654450c1eae51201260a539f1"}, - {file = "pandas-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3223f997b6d2ebf9c010260cf3d889848a93f5d22bb4d14cd32638b3d8bba7ad"}, - {file = "pandas-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4944dc004ca6cc701dfa19afb8bdb26ad36b9bed5bcec617d2a11e9cae6902"}, - {file = "pandas-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3f76280ce8ec216dde336e55b2b82e883401cf466da0fe3be317c03fb8ee7c7d"}, - {file = "pandas-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:7ad20d24acf3a0042512b7e8d8fdc2e827126ed519d6bd1ed8e6c14ec8a2c813"}, - {file = "pandas-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:021f09c15e1381e202d95d4a21ece8e7f2bf1388b6d7e9cae09dfe27bd2043d1"}, - {file = "pandas-2.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7f12b2de0060b0b858cfec0016e7d980ae5bae455a1746bfcc70929100ee633"}, - {file = "pandas-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c166b9bb27c1715bed94495d9598a7f02950b4749dba9349c1dd2cbf10729d"}, - {file = "pandas-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25c9976c17311388fcd953cb3d0697999b2205333f4e11e669d90ff8d830d429"}, - {file = "pandas-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:851b5afbb0d62f6129ae891b533aa508cc357d5892c240c91933d945fff15731"}, - {file = "pandas-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:e78507adcc730533619de07bfdd1c62b2918a68cd4419ea386e28abf7f6a1e5c"}, - {file = "pandas-2.1.2.tar.gz", hash = "sha256:52897edc2774d2779fbeb6880d2cfb305daa0b1a29c16b91f531a18918a6e0f3"}, + {file = "pandas-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acf08a73b5022b479c1be155d4988b72f3020f308f7a87c527702c5f8966d34f"}, + {file = "pandas-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3cc4469ff0cf9aa3a005870cb49ab8969942b7156e0a46cc3f5abd6b11051dfb"}, + {file = "pandas-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35172bff95f598cc5866c047f43c7f4df2c893acd8e10e6653a4b792ed7f19bb"}, + {file = "pandas-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59dfe0e65a2f3988e940224e2a70932edc964df79f3356e5f2997c7d63e758b4"}, + {file = "pandas-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0296a66200dee556850d99b24c54c7dfa53a3264b1ca6f440e42bad424caea03"}, + {file = "pandas-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:465571472267a2d6e00657900afadbe6097c8e1dc43746917db4dfc862e8863e"}, + {file = "pandas-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04d4c58e1f112a74689da707be31cf689db086949c71828ef5da86727cfe3f82"}, + {file = "pandas-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7fa2ad4ff196768ae63a33f8062e6838efed3a319cf938fdf8b95e956c813042"}, + {file = "pandas-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4441ac94a2a2613e3982e502ccec3bdedefe871e8cea54b8775992485c5660ef"}, + {file = "pandas-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ded6ff28abbf0ea7689f251754d3789e1edb0c4d0d91028f0b980598418a58"}, + {file = "pandas-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca5680368a5139d4920ae3dc993eb5106d49f814ff24018b64d8850a52c6ed2"}, + {file = "pandas-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:de21e12bf1511190fc1e9ebc067f14ca09fccfb189a813b38d63211d54832f5f"}, + {file = "pandas-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a5d53c725832e5f1645e7674989f4c106e4b7249c1d57549023ed5462d73b140"}, + {file = "pandas-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7cf4cf26042476e39394f1f86868d25b265ff787c9b2f0d367280f11afbdee6d"}, + {file = "pandas-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72c84ec1b1d8e5efcbff5312abe92bfb9d5b558f11e0cf077f5496c4f4a3c99e"}, + {file = "pandas-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f539e113739a3e0cc15176bf1231a553db0239bfa47a2c870283fd93ba4f683"}, + {file = "pandas-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc77309da3b55732059e484a1efc0897f6149183c522390772d3561f9bf96c00"}, + {file = "pandas-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:08637041279b8981a062899da0ef47828df52a1838204d2b3761fbd3e9fcb549"}, + {file = "pandas-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b99c4e51ef2ed98f69099c72c75ec904dd610eb41a32847c4fcbc1a975f2d2b8"}, + {file = "pandas-2.1.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7ea8ae8004de0381a2376662c0505bb0a4f679f4c61fbfd122aa3d1b0e5f09d"}, + {file = "pandas-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd76d67ca2d48f56e2db45833cf9d58f548f97f61eecd3fdc74268417632b8a"}, + {file = "pandas-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1329dbe93a880a3d7893149979caa82d6ba64a25e471682637f846d9dbc10dd2"}, + {file = "pandas-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:321ecdb117bf0f16c339cc6d5c9a06063854f12d4d9bc422a84bb2ed3207380a"}, + {file = "pandas-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:11a771450f36cebf2a4c9dbd3a19dfa8c46c4b905a3ea09dc8e556626060fe71"}, + {file = "pandas-2.1.3.tar.gz", hash = "sha256:22929f84bca106921917eb73c1521317ddd0a4c71b395bcf767a106e3494209f"}, ] [package.dependencies] @@ -1516,7 +1188,7 @@ pytz = ">=2020.1" tzdata = ">=2022.1" [package.extras] -all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] +all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] aws = ["s3fs (>=2022.05.0)"] clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] compression = ["zstandard (>=0.17.0)"] @@ -1536,49 +1208,9 @@ plot = ["matplotlib (>=3.6.1)"] postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] spss = ["pyreadstat (>=1.1.5)"] sql-other = ["SQLAlchemy (>=1.4.36)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.8.0)"] -[[package]] -name = "parso" -version = "0.8.3" -description = "A Python Parser" -optional = false -python-versions = ">=3.6" -files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, -] - -[package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] - -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, -] - -[[package]] -name = "pexpect" -version = "4.8.0" -description = "Pexpect allows easy control of interactive console applications." -optional = false -python-versions = "*" -files = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - [[package]] name = "pillow" version = "10.1.0" @@ -1672,13 +1304,13 @@ xarray = ["xarray"] [[package]] name = "platformdirs" -version = "3.11.0" +version = "4.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, ] [package.extras] @@ -1718,45 +1350,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "prompt-toolkit" -version = "3.0.39" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, -] - -[package.dependencies] -wcwidth = "*" - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "pure-eval" -version = "0.2.2" -description = "Safely evaluate AST nodes without side effects" -optional = false -python-versions = "*" -files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, -] - -[package.extras] -tests = ["pytest"] - [[package]] name = "pybtex" version = "0.24.0" @@ -1793,17 +1386,18 @@ pybtex = ">=0.16" [[package]] name = "pygments" -version = "2.16.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyparsing" @@ -1900,13 +1494,13 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-xdist" -version = "3.3.1" +version = "3.5.0" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.3.1.tar.gz", hash = "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93"}, - {file = "pytest_xdist-3.3.1-py3-none-any.whl", hash = "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"}, + {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"}, + {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"}, ] [package.dependencies] @@ -1955,6 +1549,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1962,8 +1557,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1980,6 +1582,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1987,6 +1590,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -2131,13 +1735,13 @@ test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "tes [[package]] name = "rich" -version = "13.6.0" +version = "13.7.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.6.0-py3-none-any.whl", hash = "sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245"}, - {file = "rich-13.6.0.tar.gz", hash = "sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef"}, + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, ] [package.dependencies] @@ -2149,68 +1753,46 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.1.3" -description = "An extremely fast Python linter, written in Rust." +version = "0.1.6" +description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b46d43d51f7061652eeadb426a9e3caa1e0002470229ab2fc19de8a7b0766901"}, - {file = "ruff-0.1.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b8afeb9abd26b4029c72adc9921b8363374f4e7edb78385ffaa80278313a15f9"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca3cf365bf32e9ba7e6db3f48a4d3e2c446cd19ebee04f05338bc3910114528b"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4874c165f96c14a00590dcc727a04dca0cfd110334c24b039458c06cf78a672e"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec2dd31eed114e48ea42dbffc443e9b7221976554a504767ceaee3dd38edeb8"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dc3ec4edb3b73f21b4aa51337e16674c752f1d76a4a543af56d7d04e97769613"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e3de9ed2e39160800281848ff4670e1698037ca039bda7b9274f849258d26ce"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c595193881922cc0556a90f3af99b1c5681f0c552e7a2a189956141d8666fe8"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f75e670d529aa2288cd00fc0e9b9287603d95e1536d7a7e0cafe00f75e0dd9d"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:76dd49f6cd945d82d9d4a9a6622c54a994689d8d7b22fa1322983389b4892e20"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:918b454bc4f8874a616f0d725590277c42949431ceb303950e87fef7a7d94cb3"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8859605e729cd5e53aa38275568dbbdb4fe882d2ea2714c5453b678dca83784"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0b6c55f5ef8d9dd05b230bb6ab80bc4381ecb60ae56db0330f660ea240cb0d4a"}, - {file = "ruff-0.1.3-py3-none-win32.whl", hash = "sha256:3e7afcbdcfbe3399c34e0f6370c30f6e529193c731b885316c5a09c9e4317eef"}, - {file = "ruff-0.1.3-py3-none-win_amd64.whl", hash = "sha256:7a18df6638cec4a5bd75350639b2bb2a2366e01222825562c7346674bdceb7ea"}, - {file = "ruff-0.1.3-py3-none-win_arm64.whl", hash = "sha256:12fd53696c83a194a2db7f9a46337ce06445fb9aa7d25ea6f293cf75b21aca9f"}, - {file = "ruff-0.1.3.tar.gz", hash = "sha256:3ba6145369a151401d5db79f0a47d50e470384d0d89d0d6f7fab0b589ad07c34"}, + {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703"}, + {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462"}, + {file = "ruff-0.1.6-py3-none-win32.whl", hash = "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a"}, + {file = "ruff-0.1.6-py3-none-win_amd64.whl", hash = "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33"}, + {file = "ruff-0.1.6-py3-none-win_arm64.whl", hash = "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc"}, + {file = "ruff-0.1.6.tar.gz", hash = "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184"}, ] [[package]] name = "setuptools" -version = "68.2.2" +version = "69.0.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, - {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "setuptools-scm" -version = "8.0.4" -description = "the blessed package to manage your versions by scm tags" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-scm-8.0.4.tar.gz", hash = "sha256:b5f43ff6800669595193fd09891564ee9d1d7dcb196cab4b2506d53a2e1c95c7"}, - {file = "setuptools_scm-8.0.4-py3-none-any.whl", hash = "sha256:b47844cd2a84b83b3187a5782c71128c28b4c94cad8bfb871da2784a5cb54c4f"}, -] - -[package.dependencies] -packaging = ">=20" -setuptools = "*" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} -typing-extensions = "*" - -[package.extras] -docs = ["entangled-cli[rich]", "mkdocs", "mkdocs-entangled-plugin", "mkdocs-material", "mkdocstrings[python]", "pygments"] -rich = ["rich"] -test = ["build", "pytest", "rich", "wheel"] - [[package]] name = "shapely" version = "2.0.2" @@ -2563,36 +2145,6 @@ Sphinx = ">=5" lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] -[[package]] -name = "stack-data" -version = "0.6.3" -description = "Extract data from python stack frames and tracebacks for informative displays" -optional = false -python-versions = "*" -files = [ - {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, - {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, -] - -[package.dependencies] -asttokens = ">=2.1.0" -executing = ">=1.2.0" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] - -[[package]] -name = "tokenize-rt" -version = "5.2.0" -description = "A wrapper around the stdlib `tokenize` which roundtrips." -optional = false -python-versions = ">=3.8" -files = [ - {file = "tokenize_rt-5.2.0-py2.py3-none-any.whl", hash = "sha256:b79d41a65cfec71285433511b50271b05da3584a1da144a0752e9c621a285289"}, - {file = "tokenize_rt-5.2.0.tar.gz", hash = "sha256:9fe80f8a5c1edad2d3ede0f37481cc0cc1538a2f442c9c2f9e4feacd2792d054"}, -] - [[package]] name = "tomli" version = "2.0.1" @@ -2604,21 +2156,6 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[[package]] -name = "traitlets" -version = "5.12.0" -description = "Traitlets Python configuration system" -optional = false -python-versions = ">=3.8" -files = [ - {file = "traitlets-5.12.0-py3-none-any.whl", hash = "sha256:81539f07f7aebcde2e4b5ab76727f53eabf18ad155c6ed7979a681411602fa47"}, - {file = "traitlets-5.12.0.tar.gz", hash = "sha256:833273bf645d8ce31dcb613c56999e2e055b1ffe6d09168a164bcd91c36d5d35"}, -] - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] - [[package]] name = "typing-extensions" version = "4.8.0" @@ -2643,52 +2180,40 @@ files = [ [[package]] name = "urllib3" -version = "2.0.7" +version = "2.1.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.6" +version = "20.24.7" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, - {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, + {file = "virtualenv-20.24.7-py3-none-any.whl", hash = "sha256:a18b3fd0314ca59a2e9f4b556819ed07183b3e9a3702ecfe213f593d44f7b3fd"}, + {file = "virtualenv-20.24.7.tar.gz", hash = "sha256:69050ffb42419c91f6c1284a7b24e0475d793447e35929b488bf6a0aade39353"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] -[[package]] -name = "wcwidth" -version = "0.2.8" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = "*" -files = [ - {file = "wcwidth-0.2.8-py2.py3-none-any.whl", hash = "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704"}, - {file = "wcwidth-0.2.8.tar.gz", hash = "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4"}, -] - [[package]] name = "zipp" version = "3.17.0" @@ -2711,4 +2236,4 @@ plot = ["matplotlib"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a6c19e6cea5d7254d7e5dcde757eacdde2d917590885dad05fa22a2f0a1709e3" +content-hash = "ed57186be9cfa88d048a30d9d37120cd0ecbbebd74197bc207235f1cb88b05ab" diff --git a/pyproject.toml b/pyproject.toml index caf66abd..dbb200b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,8 +72,7 @@ networkx = ">=3.0.0" [tool.poetry.group.dev.dependencies] pre-commit = "^3.0.0" -black = { version = "==23.10.1", extras = ["jupyter"] } # keep in sync with .pre-commit-config.yaml -ruff = "==0.1.3" # keep in sync with .pre-commit-config.yaml +ruff = "==0.1.6" # keep in sync with .pre-commit-config.yaml [tool.poetry.group.doc.dependencies] sphinx = "^7.0.1" @@ -86,10 +85,6 @@ furo = ">=2022.9.29" sphinxcontrib-googleanalytics = ">=0.3" sphinxcontrib-bibtex = "^2.5.0" -[tool.black] -line-length = 120 -target-version = ["py39", "py310", "py311", "py312"] - [tool.ruff] line-length = 120 target-version = "py39" From 240226f4b859e2f8330e5bfb09445fd5cd828fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Tue, 28 Nov 2023 17:48:07 +0100 Subject: [PATCH 42/43] Bump version --- conda/meta.yaml | 2 +- doc/Changelog.md | 2 -- doc/conf.py | 4 ++-- doc/models/Load/FlexibleLoad/FeasibleDomain.md | 4 ++-- pyproject.toml | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/conda/meta.yaml b/conda/meta.yaml index 2a501fbe..3ce83ce7 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,6 +1,6 @@ # prettier-ignore {% set name = "roseau-load-flow" %} -{% set version = "0.5.0" %} +{% set version = "0.6.0" %} package: name: "{{ name|lower }}" diff --git a/doc/Changelog.md b/doc/Changelog.md index 75870b35..6eea5d84 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -2,8 +2,6 @@ ## Version 0.6.0 -**In development** - - {gh-pr}`149` {gh-issue}`145` Add custom pint wrapper for better handling of pint arrays. - {gh-pr}`148` {gh-issue}`122` deprecate `LineParameters.from_name_lv()` in favor of the more generic `LineParameters.from_geometry()`. The method will be removed in a future release. diff --git a/doc/conf.py b/doc/conf.py index 6dc536fa..098cb6b9 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -22,8 +22,8 @@ # author = "Benoît Vinot" # The full version, including alpha/beta/rc tags -version = "0.5" -release = "0.5.0" +version = "0.6" +release = "0.6.0" # -- General configuration --------------------------------------------------- diff --git a/doc/models/Load/FlexibleLoad/FeasibleDomain.md b/doc/models/Load/FlexibleLoad/FeasibleDomain.md index 2231381a..103ca4ad 100644 --- a/doc/models/Load/FlexibleLoad/FeasibleDomain.md +++ b/doc/models/Load/FlexibleLoad/FeasibleDomain.md @@ -168,8 +168,8 @@ that allows to compute the resulting powers of the control at different voltage theoretical power. In the following example, we define a flexible parameter with a $P(U)$ control, a constant $P$ -projection, and a $5kVA$ maximum power. We want to know what would the control produce for all -voltages between 205 V and 255 V if given a theoretical power of $-2.5 + j$ kVA. +projection, and a 5 kVA maximum power. We want to know what would the control produce for all +voltages between 205 V and 255 V if given a theoretical power of $-2.5 + 1j$ kVA. ```python import numpy as np diff --git a/pyproject.toml b/pyproject.toml index dbb200b9..30f2f876 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "roseau-load-flow" -version = "0.5.0" +version = "0.6.0" description = "Highly capable three-phase load flow solver" authors = [ "Ali Hamdan ", From 25aaeb622e18889daaf76174c6dde1e1f68693b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Vinot?= Date: Wed, 29 Nov 2023 11:27:48 +0100 Subject: [PATCH 43/43] Correction of the list of authors --- pyproject.toml | 3 ++- roseau/load_flow/__about__.py | 10 +++++++++- roseau/load_flow/__init__.py | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 30f2f876..9004aaad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ authors = [ "Ali Hamdan ", "Sébastien Vallet ", "Benoît Vinot ", + "Florent Cadoux ", "Victor Gouin", ] maintainers = ["Ali Hamdan "] @@ -143,5 +144,5 @@ directory = "htmlcov" addopts = "--color=yes -vv -n=0" testpaths = ["roseau/load_flow/"] filterwarnings = [ - 'ignore:.*utcfromtimestamp:DeprecationWarning:dateutil.*', # dateutil is imported by pandas, not us + 'ignore:.*utcfromtimestamp:DeprecationWarning:dateutil.*', # dateutil is imported by pandas, not us ] diff --git a/roseau/load_flow/__about__.py b/roseau/load_flow/__about__.py index 230c8ffe..ce864993 100644 --- a/roseau/load_flow/__about__.py +++ b/roseau/load_flow/__about__.py @@ -1,4 +1,12 @@ -__author__ = "Benoît Vinot, Victor Gouin, Florent Cadoux, Sébastien Vallet, Ali Hamdan" +__authors__ = ", ".join( + ( + "Ali Hamdan ", + "Sébastien Vallet ", + "Benoît Vinot ", + "Florent Cadoux ", + "Victor Gouin", + ) +) __copyright__ = "Roseau Technologies 2018--2023" __credits__ = "Roseau Technologies" __license__ = "Proprietary" diff --git a/roseau/load_flow/__init__.py b/roseau/load_flow/__init__.py index e94310f2..c00522f4 100644 --- a/roseau/load_flow/__init__.py +++ b/roseau/load_flow/__init__.py @@ -8,7 +8,7 @@ import importlib.metadata from roseau.load_flow.__about__ import ( - __author__, + __authors__, __copyright__, __credits__, __email__, @@ -46,7 +46,7 @@ __version__ = importlib.metadata.version("roseau-load-flow") __all__ = [ - "__author__", + "__authors__", "__copyright__", "__credits__", "__email__",