Skip to content
Closed
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
18 changes: 3 additions & 15 deletions src/power_grid_model_ds/_core/fancypy.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import numpy as np

from power_grid_model_ds._core.utils.misc import array_equal_with_nan

if TYPE_CHECKING:
from power_grid_model_ds._core.model.arrays.base.array import FancyArray

Expand Down Expand Up @@ -49,18 +51,4 @@ def array_equal(array1: "FancyArray", array2: "FancyArray", equal_nan: bool = Tr


def _array_equal_with_nan(array1: "FancyArray", array2: "FancyArray") -> bool:
# np.array_equal does not work with NaN values in structured arrays, so we need to compare column by column.
# related issue: https://github.com/numpy/numpy/issues/21539

if array1.columns != array2.columns:
return False

for column in array1.columns:
column_dtype = array1.dtype[column]
if np.issubdtype(column_dtype, np.str_):
if not np.array_equal(array1[column], array2[column]):
return False
continue
if not np.array_equal(array1[column], array2[column], equal_nan=True):
return False
return True
return array_equal_with_nan(array1.data, array2.data)
19 changes: 19 additions & 0 deletions src/power_grid_model_ds/_core/model/grids/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,25 @@ def set_feeder_ids(self):
set_is_feeder(grid=self)
set_feeder_ids(grid=self)

@classmethod
def from_pgm_data(cls, pgm_data: dict[str, npt.NDArray], load_graphs: bool = True) -> "Grid":
"""Initialize the grid from PowerGridModel input data.

Args:
pgm_data (dict[str, npt.NDArray]): The PowerGridModel input data.
"""
new_grid = cls.empty()
for array_name, array_data in pgm_data.items():
pgm_array_class = getattr(new_grid, array_name).__class__
pgm_array = pgm_array_class(array_data)
setattr(new_grid, array_name, pgm_array)

new_grid._id_counter = new_grid.max_id

if load_graphs:
new_grid.graphs = GraphContainer.from_arrays(new_grid)
return new_grid


def _add_branch_array(branch: BranchArray | Branch3Array, grid: Grid):
"""Add a branch array to the grid"""
Expand Down
21 changes: 21 additions & 0 deletions src/power_grid_model_ds/_core/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,24 @@ def get_inherited_attrs(cls: Type, *private_attributes):
retrieved_attributes[private_attr] = attr_dict

return retrieved_attributes


def array_equal_with_nan(array1: np.ndarray, array2: np.ndarray) -> bool:
"""Compare two structured arrays for equality, treating NaN values as equal.

np.array_equal does not work with NaN values in structured arrays, so we need to compare column by column.
related issue: https://github.com/numpy/numpy/issues/21539
"""
if array1.dtype.names != array2.dtype.names:
return False

columns: Sequence[str] = array1.dtype.names
for column in columns:
column_dtype = array1.dtype[column]
if np.issubdtype(column_dtype, np.str_):
if not np.array_equal(array1[column], array2[column]):
return False
continue
if not np.array_equal(array1[column], array2[column], equal_nan=True):
return False
return True
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def display_selected_element(node_data, edge_data):

def _to_data_table(data: dict[str, Any]):
columns = data.keys()
data_table = dash_table.DataTable(
data_table = dash_table.DataTable( # type: ignore[attr-defined]
data=[data], columns=[{"name": key, "id": key} for key in columns], editable=False
)
return data_table
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
placeholder="Select layout",
value="",
clearable=False,
options=[{"label": name.capitalize(), "value": name} for name in LAYOUT_OPTIONS],
options=[{"label": name.capitalize(), "value": name} for name in LAYOUT_OPTIONS], # type: ignore
style={"width": "200px"},
),
style={"margin": "0 20px 0 10px"},
Expand Down
10 changes: 10 additions & 0 deletions tests/integration/loadflow/test_power_grid_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
)
from power_grid_model_ds._core.model.arrays.pgm_arrays import TransformerTapRegulatorArray
from power_grid_model_ds._core.model.grids.base import Grid
from power_grid_model_ds._core.utils.misc import array_equal_with_nan
from tests.unit.model.grids.test_custom_grid import CustomGrid

# pylint: disable=missing-function-docstring,missing-class-docstring
Expand Down Expand Up @@ -605,3 +606,12 @@ def test_create_extended_grid_without_default_from_input_data(self, input_data_p

with pytest.raises(ValueError, match="Missing required columns: {'extra_field'}"):
core_interface.create_grid_from_input_data()


def test_convert_from_and_to_pgm_data(input_data_pgm):
grid = Grid.from_pgm_data(input_data_pgm)
pgm = PowerGridModelInterface(grid=grid)
pgm.create_input_from_grid()

for array_name in pgm.input_data.keys():
assert array_equal_with_nan(pgm.input_data[array_name], input_data_pgm[array_name])
7 changes: 7 additions & 0 deletions tests/unit/model/grids/test_grid_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,10 @@ def test_from_txt_file(self, tmp_path: Path):
assert 1 == grid.branches.filter(to_status=0).size
assert 1 == grid.transformer.size
np.testing.assert_array_equal([14, 10, 11, 12, 13, 15, 16, 17], grid.branches.id)


def test_from_pgm_input_data(input_data_pgm):
grid = Grid.from_pgm_data(input_data_pgm)
assert grid.node.size == 3
assert grid.line.size == 2
grid.check_ids()
Loading