Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/power_grid_model_ds/_core/model/arrays/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@
"""

from power_grid_model_ds._core.model.arrays.pgm_arrays import (
AsymCurrentSensorArray,
AsymLineArray,
AsymPowerSensorArray,
AsymVoltageSensorArray,
Branch3Array,
BranchArray,
GenericBranchArray,
IdArray,
LineArray,
LinkArray,
NodeArray,
SourceArray,
SymCurrentSensorArray,
SymGenArray,
SymLoadArray,
SymPowerSensorArray,
Expand All @@ -25,18 +30,23 @@
)

__all__ = [
"AsymPowerSensorArray",
"AsymVoltageSensorArray",
"AsymCurrentSensorArray",
"Branch3Array",
"BranchArray",
"GenericBranchArray",
"IdArray",
"LineArray",
"LinkArray",
"NodeArray",
"SourceArray",
"SymLoadArray",
"SymGenArray",
"SymCurrentSensorArray",
"SymPowerSensorArray",
"SymVoltageSensorArray",
"AsymLineArray",
"ThreeWindingTransformerArray",
"TransformerArray",
"TransformerTapRegulatorArray",
Expand Down
31 changes: 30 additions & 1 deletion src/power_grid_model_ds/_core/model/arrays/pgm_arrays.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
from power_grid_model_ds._core.model.arrays.base.array import FancyArray
from power_grid_model_ds._core.model.dtypes.appliances import Source, SymGen, SymLoad
from power_grid_model_ds._core.model.dtypes.branches import (
AsymLine,
Branch,
Branch3,
GenericBranch,
Line,
Link,
ThreeWindingTransformer,
Expand All @@ -23,7 +25,14 @@
from power_grid_model_ds._core.model.dtypes.id import Id
from power_grid_model_ds._core.model.dtypes.nodes import Node
from power_grid_model_ds._core.model.dtypes.regulators import TransformerTapRegulator
from power_grid_model_ds._core.model.dtypes.sensors import AsymVoltageSensor, SymPowerSensor, SymVoltageSensor
from power_grid_model_ds._core.model.dtypes.sensors import (
AsymCurrentSensor,
AsymPowerSensor,
AsymVoltageSensor,
SymCurrentSensor,
SymPowerSensor,
SymVoltageSensor,
)

# pylint: disable=missing-class-docstring

Expand Down Expand Up @@ -99,6 +108,14 @@ class TransformerArray(Transformer, BranchArray):
pass


class GenericBranchArray(GenericBranch, BranchArray):
pass


class AsymLineArray(AsymLine, BranchArray):
pass


class Branch3Array(IdArray, Branch3):
def as_branches(self) -> BranchArray:
"""Convert Branch3Array to BranchArray."""
Expand Down Expand Up @@ -138,5 +155,17 @@ class SymVoltageSensorArray(IdArray, SymVoltageSensor):
pass


class SymCurrentSensorArray(IdArray, SymCurrentSensor):
pass


class AsymPowerSensorArray(IdArray, AsymPowerSensor):
pass


class AsymVoltageSensorArray(IdArray, AsymVoltageSensor):
pass


class AsymCurrentSensorArray(IdArray, AsymCurrentSensor):
pass
44 changes: 44 additions & 0 deletions src/power_grid_model_ds/_core/model/dtypes/branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@ class Line(Branch):
i_n: NDArray[np.float64] # rated current


class GenericBranch(Branch):
"""GenericBranch data type (generic_branch in power-grid-model)

Off-nominal ratio k and phase shift theta are modelled explicitly. Rated power sn optional.
The impedance (r1, x1) and admittance (g1, b1) are given wrt the to-side.
"""

r1: NDArray[np.float64] # positive-sequence resistance
x1: NDArray[np.float64] # positive-sequence reactance
g1: NDArray[np.float64] # positive-sequence conductance
b1: NDArray[np.float64] # positive-sequence susceptance


class Transformer(Branch):
"""Transformer data type"""

Expand Down Expand Up @@ -115,3 +128,34 @@ class ThreeWindingTransformer(Branch3):
pk_12_max: NDArray[np.float64]
pk_13_max: NDArray[np.float64]
pk_23_max: NDArray[np.float64]


class AsymLine(Branch):
"""Asymmetric Line data type (asym_line in power-grid-model)

Supports 3 or 4 phase (with neutral) resistance / reactance matrices and optional capacitance matrix
or sequence capacitances c0/c1. If c_* matrix is omitted, c0 & c1 may be specified instead.
Only include fields; validation logic handled elsewhere (not implemented here yet).
"""

# Resistance matrix entries (series)
r_aa: NDArray[np.float64]
r_ba: NDArray[np.float64]
r_bb: NDArray[np.float64]
r_ca: NDArray[np.float64]
r_cb: NDArray[np.float64]
r_cc: NDArray[np.float64]

# Reactance matrix entries (series)
x_aa: NDArray[np.float64]
x_ba: NDArray[np.float64]
x_bb: NDArray[np.float64]
x_ca: NDArray[np.float64]
x_cb: NDArray[np.float64]
x_cc: NDArray[np.float64]

# Alternative sequence capacitances
c0: NDArray[np.float64]
c1: NDArray[np.float64]

i_n: NDArray[np.float64] # rated current
32 changes: 32 additions & 0 deletions src/power_grid_model_ds/_core/model/dtypes/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ class SymPowerSensor(GenericPowerSensor):
q_sigma: NDArray[np.float64] # std of reactive power


class AsymPowerSensor(GenericPowerSensor):
"""AsymPowerSensor data type"""

p_measured: NDArray3[np.float64] # measured active power
q_measured: NDArray3[np.float64] # measured reactive power
p_sigma: NDArray3[np.float64] # std of active power
q_sigma: NDArray3[np.float64] # std of reactive power


class GenericVoltageSensor(Sensor):
"""Base class for voltage sensor data type"""

Expand All @@ -61,3 +70,26 @@ class AsymVoltageSensor(GenericVoltageSensor):
u_sigma: NDArray3[np.float64] # std of 3 voltages
u_measured: NDArray3[np.float64] # measured 3 voltages
u_angle_measured: NDArray3[np.float64] # measured 3 phases


class GenericCurrentSensor(Sensor):
"""Base class for current sensor data type"""

measured_terminal_type: NDArray[np.int32]
angle_measurement_type: NDArray[np.int32]
i_sigma: NDArray[np.float64]
i_angle_sigma: NDArray[np.float64]


class SymCurrentSensor(GenericCurrentSensor):
"""SymCurrentSensor data type"""

i_measured: NDArray[np.float64]
i_angle_measured: NDArray[np.float64]


class AsymCurrentSensor(GenericCurrentSensor):
"""AsymCurrentSensor data type"""

i_measured: NDArray3[np.float64]
i_angle_measured: NDArray3[np.float64]
20 changes: 17 additions & 3 deletions src/power_grid_model_ds/_core/model/grids/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@

from power_grid_model_ds._core import fancypy as fp
from power_grid_model_ds._core.model.arrays import (
AsymCurrentSensorArray,
AsymLineArray,
AsymPowerSensorArray,
AsymVoltageSensorArray,
Branch3Array,
BranchArray,
GenericBranchArray,
LineArray,
LinkArray,
NodeArray,
SourceArray,
SymCurrentSensorArray,
SymGenArray,
SymLoadArray,
SymPowerSensorArray,
Expand Down Expand Up @@ -72,6 +77,8 @@ class Grid(FancyArrayContainer):
three_winding_transformer: ThreeWindingTransformerArray
line: LineArray
link: LinkArray
generic_branch: GenericBranchArray
asym_line: AsymLineArray

source: SourceArray
sym_load: SymLoadArray
Expand All @@ -83,7 +90,10 @@ class Grid(FancyArrayContainer):
# sensors
sym_power_sensor: SymPowerSensorArray
sym_voltage_sensor: SymVoltageSensorArray
sym_current_sensor: SymCurrentSensorArray
asym_power_sensor: AsymPowerSensorArray
asym_voltage_sensor: AsymVoltageSensorArray
asym_current_sensor: AsymCurrentSensorArray

def __str__(self) -> str:
"""String representation of the grid.
Expand Down Expand Up @@ -114,8 +124,12 @@ def __str__(self) -> str:
suffix_str = f"{suffix_str},link"
elif branch.id in self.line.id:
pass # no suffix needed
elif branch.id in self.generic_branch.id:
suffix_str = f"{suffix_str},generic_branch"
elif branch.id in self.asym_line.id:
suffix_str = f"{suffix_str},asym_line"
else:
raise ValueError(f"Branch {branch.id} is not a transformer, link or line")
raise ValueError(f"Branch {branch.id} is not a transformer, link, line, generic_branch or asym_line")

grid_str += f"{from_node_str} {to_node_str} {suffix_str}\n"
return grid_str
Expand All @@ -141,7 +155,7 @@ def branch_arrays(self) -> list[BranchArray]:
return branch_arrays

def get_typed_branches(self, branch_ids: list[int] | npt.NDArray[np.int32]) -> BranchArray:
"""Find a matching LineArray, LinkArray or TransformerArray for the given branch_ids
"""Find a matching Branch-subtype array for the given branch_ids

Raises:
ValueError:
Expand All @@ -162,7 +176,7 @@ def reverse_branches(self, branches: BranchArray):
"""Reverse the direction of the branches."""
if not branches.size:
return
if not isinstance(branches, (LineArray, LinkArray, TransformerArray)):
if not isinstance(branches, (LineArray, LinkArray, TransformerArray, GenericBranchArray, AsymLineArray)):
try:
branches = self.get_typed_branches(branches.id)
except ValueError:
Expand Down
8 changes: 8 additions & 0 deletions src/power_grid_model_ds/arrays.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
# SPDX-License-Identifier: MPL-2.0

from power_grid_model_ds._core.model.arrays import (
AsymCurrentSensorArray,
AsymLineArray,
AsymVoltageSensorArray,
Branch3Array,
BranchArray,
GenericBranchArray,
IdArray,
LineArray,
LinkArray,
NodeArray,
SourceArray,
SymCurrentSensorArray,
SymGenArray,
SymLoadArray,
SymPowerSensorArray,
Expand All @@ -26,6 +30,8 @@
"BranchArray",
"LinkArray",
"LineArray",
"GenericBranchArray",
"AsymLineArray",
"TransformerArray",
"Branch3Array",
"ThreeWindingTransformerArray",
Expand All @@ -34,6 +40,8 @@
"SymLoadArray",
"TransformerTapRegulatorArray",
"AsymVoltageSensorArray",
"AsymCurrentSensorArray",
"SymPowerSensorArray",
"SymVoltageSensorArray",
"SymCurrentSensorArray",
]
24 changes: 5 additions & 19 deletions tests/unit/model/arrays/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from numpy.typing import NDArray

from power_grid_model_ds._core import fancypy as fp
from power_grid_model_ds._core.model.arrays import AsymVoltageSensorArray, SymPowerSensorArray
from power_grid_model_ds._core.model.arrays import AsymVoltageSensorArray
from power_grid_model_ds._core.model.arrays.base.array import FancyArray
from power_grid_model_ds._core.model.arrays.base.errors import ArrayDefinitionError
from power_grid_model_ds._core.model.constants import EMPTY_ID
Expand Down Expand Up @@ -232,27 +232,13 @@ def test_initialization_from_args_with_extra_columns():
assert "undefined" not in array.dtype.names


def test_sensor_array():
test_len = 2
# test proper intiliazation of a SensorArray
pow_sens = SymPowerSensorArray.empty(test_len)
sym_pow_fields = [
"measured_object",
"measured_terminal_type",
"power_sigma",
"p_measured",
"p_sigma",
"q_measured",
"q_sigma",
]
for field in sym_pow_fields:
assert field in pow_sens.dtype.fields

def test_asymmetric_sensor_array():
array_length = 2
# test if asymmetric array has NDArray3 fields, i.e. with 3 floats per element (one per phase)
asym_volt_sens = AsymVoltageSensorArray.empty(test_len)
asym_volt_sens = AsymVoltageSensorArray.empty(array_length)
nd3_fields = ["u_sigma", "u_measured", "u_angle_measured"]
for field in nd3_fields:
assert asym_volt_sens[field].shape == (test_len, 3)
assert asym_volt_sens[field].shape == (array_length, 3)


def test_inherit_defaults_from_multiple_parents():
Expand Down
23 changes: 14 additions & 9 deletions tests/unit/model/grids/test_grid_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,25 @@ def test_initialize_empty_grid(grid: Grid):
assert isinstance(grid, Grid)
fields = dataclasses.asdict(grid).keys()
assert {
"link",
"sym_load",
"sym_power_sensor",
"source",
"_id_counter",
"transformer_tap_regulator",
"asym_current_sensor",
"asym_line",
"asym_power_sensor",
"asym_voltage_sensor",
"three_winding_transformer",
"transformer",
"node",
"generic_branch",
"graphs",
"line",
"link",
"node",
"source",
"sym_current_sensor",
"sym_gen",
"graphs",
"sym_load",
"sym_power_sensor",
"sym_voltage_sensor",
"three_winding_transformer",
"transformer",
"transformer_tap_regulator",
} == set(fields)


Expand Down