Skip to content

Commit d10f0d5

Browse files
authored
Merge branch 'main' into feature/resolve-validation-test-warnings
Signed-off-by: Martijn Govers <[email protected]>
2 parents 728380a + cbad605 commit d10f0d5

19 files changed

+9812
-91
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ dev = [
4747
"ruff",
4848
"pydantic>2", # Used in unit tests
4949
"pandapower>2.11.1",
50+
"lxml", # missing pandapower dependency
5051
]
5152
examples = [
5253
"power-grid-model>1.9.80",

src/power_grid_model_io/converters/pandapower_converter.py

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88

99
import logging
1010
from functools import lru_cache
11+
from importlib.metadata import PackageNotFoundError, version
1112
from typing import Dict, List, MutableMapping, Optional, Tuple, Type
1213

1314
import numpy as np
1415
import pandas as pd
1516
import structlog
17+
from packaging.version import Version
1618
from power_grid_model import (
1719
Branch3Side,
1820
BranchSide,
@@ -34,6 +36,20 @@
3436

3537
logger = structlog.get_logger(__file__)
3638

39+
PP_COMPATIBILITY_VERSION_3_2_0 = Version("3.2.0")
40+
try:
41+
PP_CONVERSION_VERSION = Version(version("pandapower"))
42+
except PackageNotFoundError:
43+
PP_CONVERSION_VERSION = PP_COMPATIBILITY_VERSION_3_2_0 # assume latest compatible version by default
44+
45+
46+
def get_loss_params_3ph():
47+
if PP_CONVERSION_VERSION < PP_COMPATIBILITY_VERSION_3_2_0:
48+
loss_params = ["p_a_l_mw", "q_a_l_mvar", "p_b_l_mw", "q_b_l_mvar", "p_c_l_mw", "q_c_l_mvar"]
49+
else:
50+
loss_params = ["pl_a_mw", "ql_a_mvar", "pl_b_mw", "ql_b_mvar", "pl_c_mw", "ql_c_mvar"]
51+
return loss_params
52+
3753

3854
# pylint: disable=too-many-instance-attributes
3955
class PandaPowerConverter(BaseConverter[PandaPowerData]):
@@ -631,34 +647,53 @@ def _create_pgm_input_sym_loads(self):
631647
data_type=DatasetType.input, component_type=ComponentType.sym_load, shape=3 * n_loads
632648
)
633649

634-
const_i_multiplier = (
635-
self._get_pp_attr("load", "const_i_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
636-
)
637-
const_z_multiplier = (
638-
self._get_pp_attr("load", "const_z_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
639-
)
640-
const_p_multiplier = (1e6 - const_i_multiplier - const_z_multiplier) * scaling
650+
if PP_CONVERSION_VERSION < PP_COMPATIBILITY_VERSION_3_2_0:
651+
const_i_p_multiplier = (
652+
self._get_pp_attr("load", "const_i_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
653+
)
654+
const_z_p_multiplier = (
655+
self._get_pp_attr("load", "const_z_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
656+
)
657+
const_p_multiplier = (1e6 - const_i_p_multiplier - const_z_p_multiplier) * scaling
658+
const_q_multiplier = const_p_multiplier
659+
const_i_q_multiplier = const_i_p_multiplier
660+
const_z_q_multiplier = const_z_p_multiplier
661+
else:
662+
const_i_p_multiplier = (
663+
self._get_pp_attr("load", "const_i_p_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
664+
)
665+
const_z_p_multiplier = (
666+
self._get_pp_attr("load", "const_z_p_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
667+
)
668+
const_p_multiplier = (1e6 - const_i_p_multiplier - const_z_p_multiplier) * scaling
669+
const_i_q_multiplier = (
670+
self._get_pp_attr("load", "const_i_q_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
671+
)
672+
const_z_q_multiplier = (
673+
self._get_pp_attr("load", "const_z_q_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
674+
)
675+
const_q_multiplier = (1e6 - const_i_q_multiplier - const_z_q_multiplier) * scaling
641676

642677
pgm_sym_loads["id"][:n_loads] = self._generate_ids("load", pp_loads.index, name="const_power")
643678
pgm_sym_loads["node"][:n_loads] = self._get_pgm_ids("bus", bus)
644679
pgm_sym_loads["status"][:n_loads] = in_service
645680
pgm_sym_loads["type"][:n_loads] = LoadGenType.const_power
646681
pgm_sym_loads["p_specified"][:n_loads] = const_p_multiplier * p_mw
647-
pgm_sym_loads["q_specified"][:n_loads] = const_p_multiplier * q_mvar
682+
pgm_sym_loads["q_specified"][:n_loads] = const_q_multiplier * q_mvar
648683

649684
pgm_sym_loads["id"][n_loads : 2 * n_loads] = self._generate_ids("load", pp_loads.index, name="const_impedance")
650685
pgm_sym_loads["node"][n_loads : 2 * n_loads] = self._get_pgm_ids("bus", bus)
651686
pgm_sym_loads["status"][n_loads : 2 * n_loads] = in_service
652687
pgm_sym_loads["type"][n_loads : 2 * n_loads] = LoadGenType.const_impedance
653-
pgm_sym_loads["p_specified"][n_loads : 2 * n_loads] = const_z_multiplier * p_mw
654-
pgm_sym_loads["q_specified"][n_loads : 2 * n_loads] = const_z_multiplier * q_mvar
688+
pgm_sym_loads["p_specified"][n_loads : 2 * n_loads] = const_z_p_multiplier * p_mw
689+
pgm_sym_loads["q_specified"][n_loads : 2 * n_loads] = const_z_q_multiplier * q_mvar
655690

656691
pgm_sym_loads["id"][-n_loads:] = self._generate_ids("load", pp_loads.index, name="const_current")
657692
pgm_sym_loads["node"][-n_loads:] = self._get_pgm_ids("bus", bus)
658693
pgm_sym_loads["status"][-n_loads:] = in_service
659694
pgm_sym_loads["type"][-n_loads:] = LoadGenType.const_current
660-
pgm_sym_loads["p_specified"][-n_loads:] = const_i_multiplier * p_mw
661-
pgm_sym_loads["q_specified"][-n_loads:] = const_i_multiplier * q_mvar
695+
pgm_sym_loads["p_specified"][-n_loads:] = const_i_p_multiplier * p_mw
696+
pgm_sym_loads["q_specified"][-n_loads:] = const_i_q_multiplier * q_mvar
662697

663698
assert ComponentType.sym_load not in self.pgm_input_data
664699
self.pgm_input_data[ComponentType.sym_load] = pgm_sym_loads
@@ -1843,6 +1878,7 @@ def _pp_lines_output_3ph(self):
18431878
i_from = (pgm_output_lines["p_from"] + 1j * pgm_output_lines["q_from"]) / u_complex.iloc[from_nodes, :]
18441879
i_to = (pgm_output_lines["p_to"] + 1j * pgm_output_lines["q_to"]) / u_complex.iloc[to_nodes, :]
18451880

1881+
loss_params = get_loss_params_3ph()
18461882
pp_output_lines_3ph = pd.DataFrame(
18471883
columns=[
18481884
"p_a_from_mw",
@@ -1857,12 +1893,12 @@ def _pp_lines_output_3ph(self):
18571893
"q_b_to_mvar",
18581894
"p_c_to_mw",
18591895
"q_c_to_mvar",
1860-
"p_a_l_mw",
1861-
"q_a_l_mvar",
1862-
"p_b_l_mw",
1863-
"q_b_l_mvar",
1864-
"p_c_l_mw",
1865-
"q_c_l_mvar",
1896+
loss_params[0],
1897+
loss_params[1],
1898+
loss_params[2],
1899+
loss_params[3],
1900+
loss_params[4],
1901+
loss_params[5],
18661902
"i_a_from_ka",
18671903
"i_b_from_ka",
18681904
"i_c_from_ka",
@@ -1895,12 +1931,12 @@ def _pp_lines_output_3ph(self):
18951931
pp_output_lines_3ph["q_b_to_mvar"] = pgm_output_lines["q_to"][:, 1] * 1e-6
18961932
pp_output_lines_3ph["p_c_to_mw"] = pgm_output_lines["p_to"][:, 2] * 1e-6
18971933
pp_output_lines_3ph["q_c_to_mvar"] = pgm_output_lines["q_to"][:, 2] * 1e-6
1898-
pp_output_lines_3ph["p_a_l_mw"] = (pgm_output_lines["p_from"][:, 0] + pgm_output_lines["p_to"][:, 0]) * 1e-6
1899-
pp_output_lines_3ph["q_a_l_mvar"] = (pgm_output_lines["q_from"][:, 0] + pgm_output_lines["q_to"][:, 0]) * 1e-6
1900-
pp_output_lines_3ph["p_b_l_mw"] = (pgm_output_lines["p_from"][:, 1] + pgm_output_lines["p_to"][:, 1]) * 1e-6
1901-
pp_output_lines_3ph["q_b_l_mvar"] = (pgm_output_lines["q_from"][:, 1] + pgm_output_lines["q_to"][:, 1]) * 1e-6
1902-
pp_output_lines_3ph["p_c_l_mw"] = (pgm_output_lines["p_from"][:, 2] + pgm_output_lines["p_to"][:, 2]) * 1e-6
1903-
pp_output_lines_3ph["q_c_l_mvar"] = (pgm_output_lines["q_from"][:, 2] + pgm_output_lines["q_to"][:, 2]) * 1e-6
1934+
pp_output_lines_3ph[loss_params[0]] = (pgm_output_lines["p_from"][:, 0] + pgm_output_lines["p_to"][:, 0]) * 1e-6
1935+
pp_output_lines_3ph[loss_params[1]] = (pgm_output_lines["q_from"][:, 0] + pgm_output_lines["q_to"][:, 0]) * 1e-6
1936+
pp_output_lines_3ph[loss_params[2]] = (pgm_output_lines["p_from"][:, 1] + pgm_output_lines["p_to"][:, 1]) * 1e-6
1937+
pp_output_lines_3ph[loss_params[3]] = (pgm_output_lines["q_from"][:, 1] + pgm_output_lines["q_to"][:, 1]) * 1e-6
1938+
pp_output_lines_3ph[loss_params[4]] = (pgm_output_lines["p_from"][:, 2] + pgm_output_lines["p_to"][:, 2]) * 1e-6
1939+
pp_output_lines_3ph[loss_params[5]] = (pgm_output_lines["q_from"][:, 2] + pgm_output_lines["q_to"][:, 2]) * 1e-6
19041940
pp_output_lines_3ph["i_a_from_ka"] = pgm_output_lines["i_from"][:, 0] * 1e-3
19051941
pp_output_lines_3ph["i_b_from_ka"] = pgm_output_lines["i_from"][:, 1] * 1e-3
19061942
pp_output_lines_3ph["i_c_from_ka"] = pgm_output_lines["i_from"][:, 2] * 1e-3
@@ -2023,6 +2059,7 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20232059

20242060
loading = np.maximum(np.maximum(loading_a_percent, loading_b_percent), loading_c_percent)
20252061

2062+
loss_params = get_loss_params_3ph()
20262063
pp_output_trafos_3ph = pd.DataFrame(
20272064
columns=[
20282065
"p_a_hv_mw",
@@ -2037,12 +2074,12 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20372074
"q_b_lv_mvar",
20382075
"p_c_lv_mw",
20392076
"q_c_lv_mvar",
2040-
"p_a_l_mw",
2041-
"q_a_l_mvar",
2042-
"p_b_l_mw",
2043-
"q_b_l_mvar",
2044-
"p_c_l_mw",
2045-
"q_c_l_mvar",
2077+
loss_params[0],
2078+
loss_params[1],
2079+
loss_params[2],
2080+
loss_params[3],
2081+
loss_params[4],
2082+
loss_params[5],
20462083
"i_a_hv_ka",
20472084
"i_a_lv_ka",
20482085
"i_b_hv_ka",
@@ -2068,22 +2105,22 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20682105
pp_output_trafos_3ph["q_b_lv_mvar"] = pgm_output_transformers["q_to"][:, 1] * 1e-6
20692106
pp_output_trafos_3ph["p_c_lv_mw"] = pgm_output_transformers["p_to"][:, 2] * 1e-6
20702107
pp_output_trafos_3ph["q_c_lv_mvar"] = pgm_output_transformers["q_to"][:, 2] * 1e-6
2071-
pp_output_trafos_3ph["p_a_l_mw"] = (
2108+
pp_output_trafos_3ph[loss_params[0]] = (
20722109
pgm_output_transformers["p_from"][:, 0] + pgm_output_transformers["p_to"][:, 0]
20732110
) * 1e-6
2074-
pp_output_trafos_3ph["q_a_l_mvar"] = (
2111+
pp_output_trafos_3ph[loss_params[1]] = (
20752112
pgm_output_transformers["q_from"][:, 0] + pgm_output_transformers["q_to"][:, 0]
20762113
) * 1e-6
2077-
pp_output_trafos_3ph["p_b_l_mw"] = (
2114+
pp_output_trafos_3ph[loss_params[2]] = (
20782115
pgm_output_transformers["p_from"][:, 1] + pgm_output_transformers["p_to"][:, 1]
20792116
) * 1e-6
2080-
pp_output_trafos_3ph["q_b_l_mvar"] = (
2117+
pp_output_trafos_3ph[loss_params[3]] = (
20812118
pgm_output_transformers["q_from"][:, 1] + pgm_output_transformers["q_to"][:, 1]
20822119
) * 1e-6
2083-
pp_output_trafos_3ph["p_c_l_mw"] = (
2120+
pp_output_trafos_3ph[loss_params[4]] = (
20842121
pgm_output_transformers["p_from"][:, 2] + pgm_output_transformers["p_to"][:, 2]
20852122
) * 1e-6
2086-
pp_output_trafos_3ph["q_c_l_mvar"] = (
2123+
pp_output_trafos_3ph[loss_params[5]] = (
20872124
pgm_output_transformers["q_from"][:, 2] + pgm_output_transformers["q_to"][:, 2]
20882125
) * 1e-6
20892126
pp_output_trafos_3ph["i_a_hv_ka"] = pgm_output_transformers["i_from"][:, 0] * 1e-3
@@ -2393,7 +2430,7 @@ def get_switch_states(self, pp_table: str) -> pd.DataFrame:
23932430
else:
23942431
raise KeyError(f"Can't get switch states for {pp_table}")
23952432

2396-
component = self.pp_input_data[pp_table]
2433+
component = self.pp_input_data[pp_table].copy()
23972434
component["index"] = component.index
23982435

23992436
# Select the appropriate switches and columns

tests/data/pandapower/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!--
2+
SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
3+
4+
SPDX-License-Identifier: MPL-2.0
5+
-->
6+
# Pandapower release 3.2.0
7+
8+
`pandapower` made following breaking changes to its release 3.2.0:
9+
10+
1. `Load` attributes have been changed:
11+
* `const_i_percent` replaced with `const_i_p_percent` and `const_i_q_percent`
12+
* `const_z_percent` replaced with `const_z_p_percent` and `const_z_q_percent`
13+
2. loss attributes in 3ph load flow for `res_line_3ph` and `res_trafo_3ph` have been changed:
14+
* `p_a_l_mw` changed to `pl_a_mw` and same for other phases
15+
* `q_a_l_mvar` changed to `ql_a_mvar` and same for other phases
16+
17+
In order to maintain backward compatibility, data files compatible with both `pandapower` versions have been moved
18+
to separate folders **v3.1.2** and **v3.2.0**.

0 commit comments

Comments
 (0)