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
8 changes: 8 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,18 @@
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean? The SourceArray is already supported right?

Copy link
Member

@Thijss Thijss Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are currently missing a few defaulted input values compared to the PGM docs, or am I mistaken?

Copy link
Member

@Thijss Thijss Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps easier to leave out the columns with defaults for GenericBranch after all? That way we are consistent across arrays


from power_grid_model_ds._core.model.arrays.pgm_arrays import (
AsymCurrentSensorArray,
AsymLineArray,
AsymVoltageSensorArray,
Branch3Array,
BranchArray,
GenericBranchArray,
IdArray,
LineArray,
LinkArray,
NodeArray,
SourceArray,
SymCurrentSensorArray,
SymGenArray,
SymLoadArray,
SymPowerSensorArray,
Expand All @@ -26,17 +30,21 @@

__all__ = [
"AsymVoltageSensorArray",
"AsymCurrentSensorArray",
"Branch3Array",
"BranchArray",
"GenericBranchArray",
"IdArray",
"LineArray",
"LinkArray",
"NodeArray",
"SourceArray",
"SymLoadArray",
"SymGenArray",
"SymCurrentSensorArray",
"SymPowerSensorArray",
"SymVoltageSensorArray",
"AsymLineArray",
"ThreeWindingTransformerArray",
"TransformerArray",
"TransformerTapRegulatorArray",
Expand Down
26 changes: 25 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,13 @@
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,
AsymVoltageSensor,
SymCurrentSensor,
SymPowerSensor,
SymVoltageSensor,
)

# pylint: disable=missing-class-docstring

Expand Down Expand Up @@ -99,6 +107,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 @@ -140,3 +156,11 @@ class SymVoltageSensorArray(IdArray, SymVoltageSensor):

class AsymVoltageSensorArray(IdArray, AsymVoltageSensor):
pass


class SymCurrentSensorArray(IdArray, SymCurrentSensor):
pass


class AsymCurrentSensorArray(IdArray, AsymCurrentSensor):
pass
53 changes: 53 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,28 @@ 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
k: NDArray[np.float64] # off-nominal ratio
theta: NDArray[np.float64] # angle shift (radian)
sn: NDArray[np.float64] # rated power

_defaults = {
"k": 1.0,
"theta": 0.0,
"sn": 0.0,
}


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

Expand Down Expand Up @@ -115,3 +137,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
23 changes: 23 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 @@ -61,3 +61,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]
18 changes: 15 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,17 @@

from power_grid_model_ds._core import fancypy as fp
from power_grid_model_ds._core.model.arrays import (
AsymCurrentSensorArray,
AsymLineArray,
AsymVoltageSensorArray,
Branch3Array,
BranchArray,
GenericBranchArray,
LineArray,
LinkArray,
NodeArray,
SourceArray,
SymCurrentSensorArray,
SymGenArray,
SymLoadArray,
SymPowerSensorArray,
Expand Down Expand Up @@ -72,6 +76,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 @@ -84,6 +90,8 @@ class Grid(FancyArrayContainer):
sym_power_sensor: SymPowerSensorArray
sym_voltage_sensor: SymVoltageSensorArray
asym_voltage_sensor: AsymVoltageSensorArray
sym_current_sensor: SymCurrentSensorArray
asym_current_sensor: AsymCurrentSensorArray

def __str__(self) -> str:
"""String representation of the grid.
Expand Down Expand Up @@ -114,8 +122,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 +153,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 +174,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",
]
4 changes: 4 additions & 0 deletions tests/unit/model/grids/test_grid_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ def test_initialize_empty_grid(grid: Grid):
"_id_counter",
"transformer_tap_regulator",
"asym_voltage_sensor",
"sym_current_sensor",
"asym_current_sensor",
"three_winding_transformer",
"transformer",
"node",
"line",
"generic_branch",
"asym_line",
"sym_gen",
"graphs",
"sym_voltage_sensor",
Expand Down
Loading