Skip to content

Commit

Permalink
Move important modules to top-level (#304)
Browse files Browse the repository at this point in the history
This PR re-organizes the `utils` subpackage. The important modules are
moved to top-level while internal modules are kept in `utils`.

This is to separate modules that are meant for user use from modules
that are meant for internal use. This way we are able to exclude the
internal modules from the documentation and make using the important
modules easier at the same time.

Old modules are deprecated and will be removed in a future version.
  • Loading branch information
alihamdan authored Dec 31, 2024
1 parent 6e3fd78 commit f187513
Show file tree
Hide file tree
Showing 47 changed files with 1,023 additions and 824 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ on:
env:
CI: true
UV_SYSTEM_PYTHON: 1
COVERAGE_CORE: sysmon

jobs:
build:
Expand Down
6 changes: 6 additions & 0 deletions doc/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ og:description: See what's new in the latest release of Roseau Load Flow !

## Unreleased

- {gh-pr}`304` Add top-level modules `rlf.constants` and `rlf.types`. The old modules in the `utils`
package are deprecated and will be removed in a future release. The `utils` package is for internal
use only and should not be considered stable.
- {gh-pr}`304` Add top-level module `rlf.sym` for symmetrical components utilities. The `sym_to_phasor`,
`phasor_to_sym` and `series_phasor_to_sym` functions are moved from the `rlf.converters` module to
this module. The old functions are deprecated and will be removed in a future release.
- {gh-pr}`303` Fix missing `voltage_level` in `en.res_buses_voltages` when the buses define nominal
voltage but not voltage limits.
- {gh-pr}`303` Add `rlf.SQRT3` constant for the square root of 3. It can be useful for the conversion
Expand Down
11 changes: 10 additions & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,16 @@

# -- Options for AutoAPI -------------------------------------------------
autoapi_dirs = ["../roseau"]
autoapi_ignore = ["**/tests/**", "**/conftest.py", "__about__.py"]
autoapi_ignore = [
# Tests
"**/tests/**",
"**/conftest.py",
# Cruft
"**/roseau/load_flow/__about__.py",
# Internal utilities
"**/roseau/load_flow/utils/**",
"**/roseau/load_flow/io/**",
]
autoapi_options = ["members", "show-inheritance", "show-module-summary", "imported-members"]
autoapi_python_class_content = "both" # without this, the __init__ docstring is not shown
autoapi_python_use_implicit_namespaces = True
Expand Down
60 changes: 33 additions & 27 deletions doc/usage/Extras.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ If we take the example network from the [Getting Started page](gs-creating-netwo

As there are no transformers between the two buses, they all belong to the same cluster.

## Conversion to symmetrical components
## 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:
{mod}`roseau.load_flow.sym` contains helpers to work with 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
>>> import roseau.load_flow as rlf
>>> 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 = rlf.sym.phasor_to_sym(v)
>>> v_sym
array([[ 8.52651283e-14-1.42108547e-14j],
[ 2.30000000e+02+4.19109192e-14j],
Expand All @@ -80,8 +80,7 @@ You can also convert pandas Series to symmetrical components. If we take the exa
[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"])
>>> rlf.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
Expand All @@ -92,14 +91,14 @@ sb zero 9.947598e-14-1.421085e-14j
Name: voltage, dtype: complex128
```

_Roseau Load Flow_ also provides useful helpers to create three-phase balanced quantities by only
The `rlf.sym` module also provides useful helpers to create three-phase balanced quantities by only
providing the magnitude of the quantities. For example, to create a three-phase balanced positive
sequence voltage:

```pycon
>>> import numpy as np
>>> import roseau.load_flow as rlf
>>> V = 230 * rlf.PositiveSequence
>>> V = 230 * rlf.sym.PositiveSequence
>>> V
array([ 230. +0.j , -115.-199.18584287j, -115.+199.18584287j])
>>> np.abs(V)
Expand All @@ -108,64 +107,71 @@ array([230., 230., 230.])
array([ 0., -120., 120.])
```

Similarly, you can use `rlf.NegativeSequence` and `rlf.ZeroSequence` to create negative-sequence
and zero-sequence quantities respectively.
Similarly, you can use `rlf.sym.NegativeSequence` and `rlf.sym.ZeroSequence` to create negative-sequence
and zero-sequence quantities respectively. Because these are so common, you can also access them
directly from the top-level module as `rlf.PositiveSequence`, etc.

## Potentials to voltages conversion

{mod}`roseau.load_flow.converters` also contains helpers to convert a vector of potentials to a
vector of voltages. Example:
{mod}`roseau.load_flow.converters` 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
>>> import roseau.load_flow as rlf
>>> 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)
>>> rlf.converters.calculate_voltages(potentials, phases)
array([ 230. +0.j , -115.-199.18584287j, -115.+199.18584287j]) <Unit('volt')>
```

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])
>>> rlf.converters.calculate_voltages(potentials[:-1], phases[:-1])
array([ 345.+199.18584287j, 0.-398.37168574j, -345.+199.18584287j]) <Unit('volt')>
```

To get the phases of the voltage, you can use `calculate_voltage_phases`:

```pycon
>>> calculate_voltage_phases(phases)
>>> rlf.converters.calculate_voltage_phases(phases)
['an', 'bn', 'cn']
```

Of course these functions work with arbitrary phases:

```pycon
>>> calculate_voltages(potentials[:2], phases[:2])
>>> rlf.converters.calculate_voltages(potentials[:2], phases[:2])
array([345.+199.18584287j]) <Unit('volt')>
>>> calculate_voltage_phases(phases[:2])
>>> rlf.converters.calculate_voltage_phases(phases[:2])
['ab']
>>> calculate_voltage_phases("abc")
>>> rlf.converters.calculate_voltage_phases("abc")
['ab', 'bc', 'ca']
>>> calculate_voltage_phases("bc")
>>> rlf.converters.calculate_voltage_phases("bc")
['bc']
>>> calculate_voltage_phases("bcn")
>>> rlf.converters.calculate_voltage_phases("bcn")
['bn', 'cn']
```

## Constants

{mod}`roseau.load_flow.utils.constants` contains some common constants like the resistivity
and permeability of common materials in addition to other useful constants. Please refer to
the module documentation for more details.
{mod}`roseau.load_flow.constants` contains some common mathematical and physical constants like the
resistivity and permeability of common materials in addition to other useful constants. Please refer
to the module documentation for more details. An enumeration of available materials can be found in
the {mod}`roseau.load_flow.types` module.

Some commonly used constants can be accessed directly from the top-level module for convenience.
Notable top-level constants:

An enumeration of available materials can be found in the {mod}`roseau.load_flow.utils.types`
module.
- `rlf.SQRT3`: the square root of 3. Useful for converting between phase-to-phase and phase-to-neutral
voltages.
- `rlf.ALPHA`: the alpha constant. Rotates a complex number by 120°.
- `rlf.ALPHA2`: the alpha constant squared. Rotates a complex number by 240° (or -120°).

## Voltage unbalance

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ docstring-code-format = true
"*.ipynb" = ["E402", "F403", "F405"]

[tool.coverage.run]
branch = true
branch = false
omit = ["roseau/load_flow/__about__.py"]
plugins = ["coverage_conditional_plugin"]

Expand Down
15 changes: 9 additions & 6 deletions roseau/load_flow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import importlib.metadata
from typing import Any

from roseau.load_flow import converters
from roseau.load_flow import constants, converters, plotting, sym
from roseau.load_flow.__about__ import (
__authors__,
__copyright__,
Expand All @@ -20,6 +20,7 @@
__status__,
__url__,
)
from roseau.load_flow.constants import SQRT3
from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode
from roseau.load_flow.license import License, activate_license, deactivate_license, get_license
from roseau.load_flow.models import (
Expand All @@ -43,10 +44,10 @@
VoltageSource,
)
from roseau.load_flow.network import ElectricalNetwork
from roseau.load_flow.sym import ALPHA, ALPHA2, NegativeSequence, PositiveSequence, ZeroSequence
from roseau.load_flow.types import Insulator, LineType, Material
from roseau.load_flow.units import Q_, ureg
from roseau.load_flow.utils import Insulator, LineType, Material, constants
from roseau.load_flow.utils._versions import show_versions
from roseau.load_flow.utils.constants import ALPHA, ALPHA2, SQRT3, NegativeSequence, PositiveSequence, ZeroSequence
from roseau.load_flow.utils import show_versions

__version__ = importlib.metadata.version("roseau-load-flow")

Expand All @@ -63,6 +64,8 @@
"show_versions",
"converters",
"constants",
"plotting",
"sym",
# Electrical Network
"ElectricalNetwork",
# Buses
Expand Down Expand Up @@ -119,12 +122,12 @@ def __getattr__(name: str) -> Any:
if name in deprecated_classes and name not in globals():
import warnings

from roseau.load_flow.utils._exceptions import find_stack_level
from roseau.load_flow.utils.exceptions import find_stack_level

new_class = deprecated_classes[name]
warnings.warn(
f"The `{name}` class is deprecated. Use `{new_class.__name__}` instead.",
category=DeprecationWarning,
category=FutureWarning,
stacklevel=find_stack_level(),
)
globals()[name] = new_class
Expand Down
1 change: 1 addition & 0 deletions roseau/load_flow/_compat.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Cannot move to utils because of circular imports
import sys
from enum import Enum

Expand Down
2 changes: 1 addition & 1 deletion roseau/load_flow/_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode
from roseau.load_flow.license import activate_license, get_license
from roseau.load_flow.typing import JsonDict, Solver
from roseau.load_flow.utils._exceptions import find_stack_level
from roseau.load_flow.utils import find_stack_level
from roseau.load_flow_engine.cy_engine import CyAbstractSolver, CyBackwardForward, CyNewton, CyNewtonGoldstein

logger = logging.getLogger(__name__)
Expand Down
Loading

0 comments on commit f187513

Please sign in to comment.