diff --git a/README.md b/README.md
index f1f385a5..59dc35ad 100644
--- a/README.md
+++ b/README.md
@@ -4,22 +4,33 @@
![pre-commit](https://github.com/RoseauTechnologies/Roseau_Load_Flow/actions/workflows/pre-commit.yml/badge.svg)
[![Documentation Status](https://readthedocs.org/projects/roseau-load-flow/badge/?version=latest)](https://roseau-load-flow.readthedocs.io/en/latest/?badge=latest)
-_Roseau Load Flow_ is a highly capable three-phase load flow solver with an ergonomic Python API
-for unbalanced power flow analysis.
+_Roseau Load Flow_ is a powerful multi-phase load flow solver for unbalanced power flow analysis that
+offers:
+
+- Multi-phase, unbalanced power flow analysis
+- Performance optimized solver written in C++
+- A catalogue of real-world transformer and line models
+- An ergonomic object-oriented Python interface
+- A comprehensive documentation with code examples
+- Real-world distribution network data samples in the library (with more available on request)
+
+In addition to the following _unique_ set of features:
+
+- Support for floating neutrals for loads and sources
+- Four-wire multi-phase modelling with no Kron's reduction, no transformations, no assumptions on the
+ network topology and no implicit earthing everywhere
+- Support for flexible, voltage-dependent, loads directly in the Newton algorithm for better convergence
This project is compatible with Python version 3.10 and newer. The
[installation instructions](https://roseau-load-flow.roseautechnologies.com/Installation.html)
-will guide you through the installation process. If you are new to _Roseau Load Flow_, we recommend you start with the
+will guide you through the installation process. If you are new to _Roseau Load Flow_, we recommend
+you start with the
[getting started tutorial](https://roseau-load-flow.roseautechnologies.com/usage/Getting_Started.html).
You can find the complete documentation at https://roseau-load-flow.roseautechnologies.com/.
-> [!IMPORTANT]
-> Starting with version 0.7.0, Roseau Load Flow is no longer supplied as a SaaS. The software is now
-> available as a standalone Python library.
-
## License
-The project is _partially_ open source but using the solver requires a license. The license key
+This project is _partially_ open source but using the solver requires a license. The license key
`A8C6DA-9405FB-E74FB9-C71C3C-207661-V3` can be used free of charge with networks containing up to 10
buses. To obtain a personal or commercial license, please contact us
at [contact@roseautechnologies.com](mailto:contact@roseautechnologies.com).
@@ -32,21 +43,25 @@ Read more at [License](https://roseau-load-flow.roseautechnologies.com/License.h
## Network data
-With this library, there is a sample of 20 low-voltage and 20 medium-voltage feeders included for an easy
-start! Each network is given with its summer and winter load point. At _Roseau Technologies_, we are able to provide
-the major part of the French medium and low voltage networks. For more information, please contact us at
-contact@roseautechnologies.com.
+_Roseau Load Flow_ ships with a sample of 20 low-voltage and 20 medium-voltage feeder networks. Each
+network is provided with its summer and winter load points. At _Roseau Technologies_, we can provide
+the major part of the French medium and low voltage networks on demand. For more information, please
+contact us at contact@roseautechnologies.com.
-![Catalogue of networks](https://github.com/RoseauTechnologies/Roseau_Load_Flow/blob/main/doc/_static/Network/Catalogue.png?raw=True)
+
+
+
## Bug reports / Feature requests
-If you find a bug or have a feature request, please open an issue on
+For bug reports, feature requests, or questions, please open an issue on
[GitHub](https://github.com/RoseauTechnologies/Roseau_Load_Flow/issues)
## Credits
This software is developed by [Roseau Technologies](https://www.roseautechnologies.com/en).
+
+Follow us on:
[![Linkedin](https://i.stack.imgur.com/gVE0j.png) LinkedIn](https://www.linkedin.com/company/roseau-technologies/)
[![GitHub](https://i.stack.imgur.com/tskMh.png) GitHub](https://github.com/RoseauTechnologies)
diff --git a/doc/Changelog.md b/doc/Changelog.md
index 4d616d26..159f4006 100644
--- a/doc/Changelog.md
+++ b/doc/Changelog.md
@@ -19,71 +19,88 @@ og:description: See what's new in the latest release of Roseau Load Flow !
## Unreleased
+This release adds official support for Python 3.13 and adds a new experimental backward-forward solver.
+
+### Breaking changes
+
+- The `min_voltage` and `max_voltage` of `Bus` have been replaced by `nominal_voltage` (phase-to-phase,
+ in V), a `min_voltage_level` (unitless) and a `max_voltage_level` (unitless).
+- The `type` parameter of `TransformerParameters` constructors becomes `vg` for vector group. Replace
+ `type="single"` by `vg="Ii0"` and `type="center"` by `vg="Iii0"`.
+- The `type` attribute of `TransformerParameters` now returns `three-phase`, `single-phase` or
+ `center-tapped`. Use `TransformerParameters.vg` to get the vector group.
+- The names of the transformers in the catalogue have been modified to add voltage levels and vector
+ groups. Use `rlf.TransformerParameters.get_catalogue()` to see the updated catalogue.
+- The `max_current`, `section`, `insulator_type` and `conductor_type` parameters of the `LineParameters`
+ class are renamed to `ampacities`, `sections`, `insulators` and `materials` respectively. The new
+ parameters accept arrays of values, one per conductor.
+- The enumeration `InsulatorType.UNKNOWN` is removed. Please use `None` if the insulator is unknown.
+- The definition of constant-current loads is modified to be the magnitudes of the currents and their
+ phase shift from the voltages instead of the absolute phase shift. Currents should no longer be
+ rotated by 120° to be in sync with the voltages.
+
+### Deprecations
+
+- The enumerated classes `InsulatorType` and `ConductorType` are renamed to `Insulator` and `Material`
+ respectively. Their old names are deprecated and will be removed in a future release.
+- The deprecated method `LineParameters.from_name_mv` is removed.
+
+### Detailed changes
+
+- {gh-pr}`293` Fixed `loading` calculation for lines and transformers
- {gh-pr}`291` Fixed several bugs in JSON serialization and deserialization.
-- {gh-pr}`289` Improve the `TransformerParameters` class and the transformers catalogue
+- {gh-pr}`289` {gh-issue}`264` Improve the `TransformerParameters` class and the transformers catalogue
- Add 15kV transformers to the catalogue (SE and FT)
- Add single-phase transformers to the catalogue (Schneider Imprego)
- Add step-up transformers to the catalogue (Cahors "Serie Jaune")
- Use the correct LV side no-load voltage as defined in the datasheets (some 400V became 410V)
- Revert {gh-pr}`282` to keep the IEC 600076 names `uhv` and `ulv` for the transformer voltages.
-
- **BREAKING CHANGES**:
-
- Replace the `type` parameter of `TransformerParameters` constructors by `vg` for vector group.
- `TransformerParameters.type` now returns `three-phase`, `single-phase` or `center-tapped`. Use
`TransformerParameters.vg` to get vector group.
- Modify the names of the transformers in the catalogue to add voltage levels and vector groups
-- {gh-pr}`285` {gh-issue}`279` **BREAKING CHANGE**: Add limits on assets. It is now possible to define a maximum
- loading for lines and transformers. It generates some indirect consequences:
+- {gh-pr}`285` {gh-issue}`279` Add maximum loading for lines and transformers.
- - The constructors of `Transformer` and `Line` now accept an unitless `max_loading` parameter equal to 1 (=100% of
- the ampacities for lines and of the nominal power for transformers) by default.
+ - The constructors of `Transformer` and `Line` now accept a unitless `max_loading` parameter equal
+ to 1 (=100%) by default.
- The parameter `max_currents` of `LineParameters` is now called `ampacities`.
- - The class `Line` has a `max_currents` property that retrieves the maximal admissible currents (in Amps) for each
- conductor taking into account the ampacities of the `LineParameters` and the `max_loading` of the `Line`.
- - The `res_violated` methods of `Transformer` and `Line` take into account this `max_loading`.
- - The `Line` and `Transformer` classes have a new `res_loading` method to compute the loading according to the
- maximum loading and the ampacities (for `Line`) or the nominal power (for the `Transformer`).
+ - The `Line` class gained a new property `max_currents` that returns the maximal admissible currents
+ (in Amps) for each conductor: `line.max_current = line.parameters.ampacity * line.max_loading`.
+ - The `res_violated` property of `Transformer` and `Line` now take into account this `max_loading`.
+ - The `Line` and `Transformer` classes have a new `res_loading` property to compute the loading of
+ the element:
+ - `line.res_loading = line.res_currents / line.parameters.ampacities`
+ - `transformer.res_loading = sum(transformer.res_powers) / transformer.parameters.sn`
- {gh-pr}`286` The deprecated method `LineParameters.from_name_mv` is removed.
-- {gh-pr}`283` **BREAKING CHANGE**: Several changes related to the `LineParameters`:
-
- - The `LineParameters` class changed:
-
- - The parameter `max_current` is renamed `max_currents` and now accepts an array of maximal currents (one per
- conductor).
- - The parameter `section` is renamed `sections` and now accepts an array of sections (one per conductor).
- - The parameter `insulator_type` is renamed `insulators` and now accepts an array of insulators (one per conductor).
- - The parameter `conductor_type` is renamed `materials` and now accepts an array of materials (one per conductor).
- - The class method `from_geometry` now accepts several additional arguments related to the neutral
- (`material_neutral`, `insulator_neutral`, `max_current_neutral`)
-
- - The enumerated classes `InsulatorType` and `ConductorType` are renamed `Insulator` and `Material`. Their old
- names are deprecated and will be removed in a future release.
+- {gh-pr}`283` Several changes related to the `LineParameters`:
+
+ - The `max_current`, `section`, `insulator_type` and `conductor_type` parameters are renamed to
+ `max_currents`, `sections`, `insulators` and `materials` respectively. The new parameters accept
+ arrays of values, one per conductor.
+ - The class method `from_geometry` now accepts several additional arguments related to the neutral
+ (`material_neutral`, `insulator_neutral`, `max_current_neutral`)
+ - The enumerated classes `InsulatorType` and `ConductorType` are renamed to `Insulator` and `Material`.
+ Their old names are deprecated and will be removed in a future release.
- The insulator `UNKNOWN` is removed. Please use `None` if the insulator is unknown.
- The insulator `NONE` is added. It must be used to describe conductors without insulator.
- - The catalogue has now several additional columns related to the neutral parameters (resistance, reactance,
- susceptance, material, insulator, maximal current). The `get_catalogue` and the `from_catalogue` methods have
- been changed to accept filter on the columns (`material_neutral`, `insulator_neutral`, `section_neutral`)
+ - The catalogue has now several additional columns related to the neutral parameters (resistance,
+ reactance, susceptance, material, insulator, maximal current). The `get_catalogue` and the
+ `from_catalogue` methods have been changed to accept filter on the columns (`material_neutral`,
+ `insulator_neutral`, `section_neutral`)
-- {gh-pr}`282` **BREAKING CHANGE**: Rename the parameters of the class `TransformerParameters`: `uhv` becomes `up`
- (for **p**rimary side) and `ulv` becomes `us` (for **s**econdary side). In addition, `up` doesn't need to be
- greater than `us` anymore.
- {gh-pr}`281` Add official support for Python 3.13.
-- {gh-issue}`278` {gh-pr}`280` **BREAKING CHANGE**: the `Bus` constructor now accepts a nominal voltage
- (phase-to-phase, in V), a `min_voltage_level` (unitless) and a `max_voltage_level` (unitless). These
- arguments replace `min_voltage` and `max_voltage`. The `Bus` class now has some additional properties:
-
- - `res_voltage_levels`: it retrieves the voltage levels of the bus according to the provided phase-to-phase nominal
- voltage;
- - `min_voltage_level` and `max_voltage_level`: these properties retrieve the minimum and maximum voltage levels;
- - `min_voltage` and `max_voltage`: these properties (that existed before) now compute the minimum and maximum
- voltages (in V) from the nominal voltage and the minimum and maximum levels.
-
- The file format also changed to take into account these changes. If a `min_voltage` or `max_voltage` existed in a
- file of a previous version, they are lost when upgrading the file.
+- {gh-issue}`278` {gh-pr}`280` Modify the `Bus` voltage limits:
+
+ - The `min_voltage` and `max_voltage` parameters and attributes of `Bus` have been replaced by
+ `nominal_voltage` (phase-to-phase, in V), a `min_voltage_level` (unitless) and a `max_voltage_level`
+ (unitless).
+ - `Bus` gained a new property `res_voltage_levels` that returns the voltage levels of the bus
+ as a percentage of the nominal voltage;
+ - The JSON file format also changed to take into account these changes. If a `min_voltage` or
+ `max_voltage` existed in a file of a previous version, they are lost when upgrading the file.
- {gh-pr}`277` Fix the definition of constant current loads to be the magnitudes of the currents
and their phase shift from the voltages instead of the absolute phase shift. Currents should no
diff --git a/doc/index.md b/doc/index.md
index 2d7c8b01..13b534b1 100644
--- a/doc/index.md
+++ b/doc/index.md
@@ -15,15 +15,31 @@ myst:
# Welcome to the Roseau Load Flow documentation
-`Roseau Load Flow` is a load flow solver capable of modeling 3-phase unbalanced power systems with
-a wide variety of models for lines, transformers, loads, and sources. This software is developed
-by [Roseau Technologies](https://www.roseautechnologies.com/en).
+_Roseau Load Flow_ is a powerful multi-phase load flow solver for unbalanced power flow analysis that
+offers:
+
+- Multi-phase, unbalanced power flow analysis
+- Performance optimized solver written in C++
+- A catalogue of real-world transformer and line models
+- An ergonomic object-oriented Python interface
+- A comprehensive documentation with code examples
+- Real-world distribution network data samples in the library (with more available on request)
+
+In addition to the following _unique_ set of features:
+
+- Support for floating neutrals for loads and sources
+- Four-wire multi-phase modelling with no Kron's reduction, no transformations, no assumptions on the
+ network topology and no implicit earthing everywhere
+- Support for flexible, voltage-dependent, loads directly in the Newton algorithm for better convergence
+
+This software is developed by [Roseau Technologies](https://www.roseautechnologies.com/en).
-With this library, there is a sample of 20 low-voltage and 20 medium-voltage feeders included for an easy
-start! Each network is given with its summer and winter load point. At _Roseau Technologies_, we are able to provide
-the major part of the French medium and low voltage networks. For more information, please contact us at
+_Roseau Load Flow_ ships with a sample of 20 low-voltage and 20 medium-voltage feeder networks. Each
+network is provided with its summer and winter load points. At _Roseau Technologies_, we can provide
+the major part of the French medium and low voltage networks on demand. For more information, please
+contact us at
[contact@roseautechnologies.com](mailto:contact@roseautechnologies.com).
diff --git a/roseau/load_flow/models/lines/lines.py b/roseau/load_flow/models/lines/lines.py
index 5523bb91..66d7994d 100644
--- a/roseau/load_flow/models/lines/lines.py
+++ b/roseau/load_flow/models/lines/lines.py
@@ -251,7 +251,7 @@ def max_loading(self, value: float | Q_[float]) -> None:
msg = f"Maximum loading must be positive: {value} was provided."
logger.error(msg)
raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_MAX_LOADING_VALUE)
- self._max_loading = value
+ self._max_loading: float = value
@property
def ampacities(self) -> Q_[FloatArray] | None:
@@ -345,28 +345,21 @@ def res_power_losses(self) -> Q_[ComplexArray]:
@property
def res_loading(self) -> Q_[FloatArray] | None:
- """Get the loading of the line (unitless)."""
- amp = self._parameters._ampacities
- if amp is None:
+ """The loading of the line (unitless) if ``self.parameters.ampacities`` is set, else ``None``."""
+ if (amp := self._parameters._ampacities) is None:
return None
currents1, currents2 = self._res_currents_getter(warning=True)
- i_max = amp * self._max_loading
- return Q_(np.maximum(abs(currents1), abs(currents2)) / i_max, "")
+ return Q_(np.maximum(abs(currents1), abs(currents2)) / amp, "")
@property
def res_violated(self) -> bool | None:
- """Whether the line current exceeds the maximal current of the line (computed with the parameters' ampacities
- and the maximal loading of the line itself).
+ """Whether the line current loading exceeds its maximal loading.
- Returns ``None`` if the ampacities or the `max_loading` is not set are not set.
+ Returns ``None`` if the ``self.parameters.ampacities`` is not set.
"""
- amp = self._parameters._ampacities
- if amp is None:
+ if (loading := self.res_loading) is None:
return None
- currents1, currents2 = self._res_currents_getter(warning=True)
- i_max = amp * self._max_loading
- # True if any phase is overloaded
- return bool((np.maximum(abs(currents1), abs(currents2)) > i_max).any())
+ return bool((loading.m > self._max_loading).any())
#
# Json Mixin interface
diff --git a/roseau/load_flow/models/tests/test_lines.py b/roseau/load_flow/models/tests/test_lines.py
index 2ebfc450..4dfd4a6d 100644
--- a/roseau/load_flow/models/tests/test_lines.py
+++ b/roseau/load_flow/models/tests/test_lines.py
@@ -169,7 +169,7 @@ def test_res_violated():
line.max_loading = Q_(50, "%")
assert line.max_loading.m == 0.5
assert line.res_violated is True
- np.testing.assert_allclose(line.res_loading.m, 10 / (11 * 0.5))
+ np.testing.assert_allclose(line.res_loading.m, 10 / 11)
# Two violations
lp.ampacities = 9
diff --git a/roseau/load_flow/models/tests/test_transformers.py b/roseau/load_flow/models/tests/test_transformers.py
index 70b4ed49..3f8d216f 100644
--- a/roseau/load_flow/models/tests/test_transformers.py
+++ b/roseau/load_flow/models/tests/test_transformers.py
@@ -65,12 +65,12 @@ def test_res_violated():
# Two violations
transformer.max_loading = 4 / 5
assert transformer.res_violated is True
- np.testing.assert_allclose(transformer.res_loading.m, 0.8 * 20 * 3 / 40)
+ np.testing.assert_allclose(transformer.res_loading.m, 0.8 * 20 * 3 / 50)
# Primary side violation
transformer.max_loading = Q_(45, "%")
assert transformer.res_violated is True
- np.testing.assert_allclose(transformer.res_loading.m, 0.8 * 20 * 3 / (50 * 0.45))
+ np.testing.assert_allclose(transformer.res_loading.m, 0.8 * 20 * 3 / 50)
# Secondary side violation
transformer.max_loading = 1
diff --git a/roseau/load_flow/models/transformers/transformers.py b/roseau/load_flow/models/transformers/transformers.py
index 13fd97e3..99465b13 100644
--- a/roseau/load_flow/models/transformers/transformers.py
+++ b/roseau/load_flow/models/transformers/transformers.py
@@ -185,7 +185,7 @@ def max_loading(self, value: float | Q_[float]) -> None:
msg = f"Maximum loading must be positive: {value} was provided."
logger.error(msg)
raise RoseauLoadFlowException(msg=msg, code=RoseauLoadFlowExceptionCode.BAD_MAX_LOADING_VALUE)
- self._max_loading = value
+ self._max_loading: float = value
@property
def sn(self) -> Q_[float]:
@@ -321,28 +321,18 @@ def res_power_losses(self) -> Q_[complex]:
return sum(powers1) + sum(powers2)
@property
- def res_loading(self) -> Q_[float] | None:
+ @ureg_wraps("", (None,))
+ def res_loading(self) -> Q_[float]:
"""Get the loading of the transformer (unitless)."""
sn = self._parameters._sn
- if sn is None:
- return None
powers1, powers2 = self._res_powers_getter(warning=True)
- s_max = sn * self._max_loading
- return Q_(max(abs(powers1.sum()), abs(powers2.sum())) / s_max, "")
+ return max(abs(powers1.sum()), abs(powers2.sum())) / sn
@property
- def res_violated(self) -> bool | None:
- """Whether the transformer power exceeds the maximum power (loading > max_loading).
-
- Returns ``None`` if the maximum power is not set.
- """
- sn = self._parameters._sn
- if sn is None:
- return None
- powers1, powers2 = self._res_powers_getter(warning=True)
- s_max = sn * self._max_loading
+ def res_violated(self) -> bool:
+ """Whether the transformer power loading exceeds its maximal loading."""
# True if either the primary or secondary is overloaded
- return bool((abs(powers1.sum()) > s_max) or (abs(powers2.sum()) > s_max))
+ return bool(self.res_loading.m > self._max_loading)
#
# Json Mixin interface
diff --git a/roseau/load_flow/network.py b/roseau/load_flow/network.py
index b6e1a6b0..969f2cc8 100644
--- a/roseau/load_flow/network.py
+++ b/roseau/load_flow/network.py
@@ -813,8 +813,7 @@ def res_lines(self) -> pd.DataFrame:
loading_array = None
violated_array = None
else:
- i_max = ampacities * max_loading
- loading_array = np.maximum(abs(currents1), abs(currents2)) / i_max
+ loading_array = np.maximum(abs(currents1), abs(currents2)) / ampacities
violated_array = loading_array > max_loading
for k, (i1, i2, s1, s2, v1, v2, s_series, i_series, phase) in enumerate(
zip(
@@ -905,13 +904,8 @@ def res_transformers(self) -> pd.DataFrame:
powers2 = potentials2 * currents2.conj()
sn = transformer.parameters._sn
max_loading = transformer._max_loading
- if sn is None:
- violated = None
- loading = None
- else:
- s_max = sn * max_loading
- loading = max(abs(powers1.sum()), abs(powers2.sum())) / s_max
- violated = loading > max_loading
+ loading = max(abs(powers1.sum()), abs(powers2.sum())) / sn
+ violated = loading > max_loading
for phase in transformer._all_phases:
if phase in transformer.phases1:
idx1 = transformer.phases1.index(phase)