Skip to content

Commit f57f1db

Browse files
authored
Merge pull request #333 from furqan463/new_pp
Pandapower converter: Fix compatibility issues with upcoming pandapower release.
2 parents 5e64578 + be7a362 commit f57f1db

18 files changed

+9810
-92
lines changed

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
@@ -1846,6 +1881,7 @@ def _pp_lines_output_3ph(self):
18461881
i_from = (pgm_output_lines["p_from"] + 1j * pgm_output_lines["q_from"]) / u_complex.iloc[from_nodes, :]
18471882
i_to = (pgm_output_lines["p_to"] + 1j * pgm_output_lines["q_to"]) / u_complex.iloc[to_nodes, :]
18481883

1884+
loss_params = get_loss_params_3ph()
18491885
pp_output_lines_3ph = pd.DataFrame(
18501886
columns=[
18511887
"p_a_from_mw",
@@ -1860,12 +1896,12 @@ def _pp_lines_output_3ph(self):
18601896
"q_b_to_mvar",
18611897
"p_c_to_mw",
18621898
"q_c_to_mvar",
1863-
"p_a_l_mw",
1864-
"q_a_l_mvar",
1865-
"p_b_l_mw",
1866-
"q_b_l_mvar",
1867-
"p_c_l_mw",
1868-
"q_c_l_mvar",
1899+
loss_params[0],
1900+
loss_params[1],
1901+
loss_params[2],
1902+
loss_params[3],
1903+
loss_params[4],
1904+
loss_params[5],
18691905
"i_a_from_ka",
18701906
"i_b_from_ka",
18711907
"i_c_from_ka",
@@ -1898,12 +1934,12 @@ def _pp_lines_output_3ph(self):
18981934
pp_output_lines_3ph["q_b_to_mvar"] = pgm_output_lines["q_to"][:, 1] * 1e-6
18991935
pp_output_lines_3ph["p_c_to_mw"] = pgm_output_lines["p_to"][:, 2] * 1e-6
19001936
pp_output_lines_3ph["q_c_to_mvar"] = pgm_output_lines["q_to"][:, 2] * 1e-6
1901-
pp_output_lines_3ph["p_a_l_mw"] = (pgm_output_lines["p_from"][:, 0] + pgm_output_lines["p_to"][:, 0]) * 1e-6
1902-
pp_output_lines_3ph["q_a_l_mvar"] = (pgm_output_lines["q_from"][:, 0] + pgm_output_lines["q_to"][:, 0]) * 1e-6
1903-
pp_output_lines_3ph["p_b_l_mw"] = (pgm_output_lines["p_from"][:, 1] + pgm_output_lines["p_to"][:, 1]) * 1e-6
1904-
pp_output_lines_3ph["q_b_l_mvar"] = (pgm_output_lines["q_from"][:, 1] + pgm_output_lines["q_to"][:, 1]) * 1e-6
1905-
pp_output_lines_3ph["p_c_l_mw"] = (pgm_output_lines["p_from"][:, 2] + pgm_output_lines["p_to"][:, 2]) * 1e-6
1906-
pp_output_lines_3ph["q_c_l_mvar"] = (pgm_output_lines["q_from"][:, 2] + pgm_output_lines["q_to"][:, 2]) * 1e-6
1937+
pp_output_lines_3ph[loss_params[0]] = (pgm_output_lines["p_from"][:, 0] + pgm_output_lines["p_to"][:, 0]) * 1e-6
1938+
pp_output_lines_3ph[loss_params[1]] = (pgm_output_lines["q_from"][:, 0] + pgm_output_lines["q_to"][:, 0]) * 1e-6
1939+
pp_output_lines_3ph[loss_params[2]] = (pgm_output_lines["p_from"][:, 1] + pgm_output_lines["p_to"][:, 1]) * 1e-6
1940+
pp_output_lines_3ph[loss_params[3]] = (pgm_output_lines["q_from"][:, 1] + pgm_output_lines["q_to"][:, 1]) * 1e-6
1941+
pp_output_lines_3ph[loss_params[4]] = (pgm_output_lines["p_from"][:, 2] + pgm_output_lines["p_to"][:, 2]) * 1e-6
1942+
pp_output_lines_3ph[loss_params[5]] = (pgm_output_lines["q_from"][:, 2] + pgm_output_lines["q_to"][:, 2]) * 1e-6
19071943
pp_output_lines_3ph["i_a_from_ka"] = pgm_output_lines["i_from"][:, 0] * 1e-3
19081944
pp_output_lines_3ph["i_b_from_ka"] = pgm_output_lines["i_from"][:, 1] * 1e-3
19091945
pp_output_lines_3ph["i_c_from_ka"] = pgm_output_lines["i_from"][:, 2] * 1e-3
@@ -2026,6 +2062,7 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20262062

20272063
loading = np.maximum(np.maximum(loading_a_percent, loading_b_percent), loading_c_percent)
20282064

2065+
loss_params = get_loss_params_3ph()
20292066
pp_output_trafos_3ph = pd.DataFrame(
20302067
columns=[
20312068
"p_a_hv_mw",
@@ -2040,12 +2077,12 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20402077
"q_b_lv_mvar",
20412078
"p_c_lv_mw",
20422079
"q_c_lv_mvar",
2043-
"p_a_l_mw",
2044-
"q_a_l_mvar",
2045-
"p_b_l_mw",
2046-
"q_b_l_mvar",
2047-
"p_c_l_mw",
2048-
"q_c_l_mvar",
2080+
loss_params[0],
2081+
loss_params[1],
2082+
loss_params[2],
2083+
loss_params[3],
2084+
loss_params[4],
2085+
loss_params[5],
20492086
"i_a_hv_ka",
20502087
"i_a_lv_ka",
20512088
"i_b_hv_ka",
@@ -2071,22 +2108,22 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20712108
pp_output_trafos_3ph["q_b_lv_mvar"] = pgm_output_transformers["q_to"][:, 1] * 1e-6
20722109
pp_output_trafos_3ph["p_c_lv_mw"] = pgm_output_transformers["p_to"][:, 2] * 1e-6
20732110
pp_output_trafos_3ph["q_c_lv_mvar"] = pgm_output_transformers["q_to"][:, 2] * 1e-6
2074-
pp_output_trafos_3ph["p_a_l_mw"] = (
2111+
pp_output_trafos_3ph[loss_params[0]] = (
20752112
pgm_output_transformers["p_from"][:, 0] + pgm_output_transformers["p_to"][:, 0]
20762113
) * 1e-6
2077-
pp_output_trafos_3ph["q_a_l_mvar"] = (
2114+
pp_output_trafos_3ph[loss_params[1]] = (
20782115
pgm_output_transformers["q_from"][:, 0] + pgm_output_transformers["q_to"][:, 0]
20792116
) * 1e-6
2080-
pp_output_trafos_3ph["p_b_l_mw"] = (
2117+
pp_output_trafos_3ph[loss_params[2]] = (
20812118
pgm_output_transformers["p_from"][:, 1] + pgm_output_transformers["p_to"][:, 1]
20822119
) * 1e-6
2083-
pp_output_trafos_3ph["q_b_l_mvar"] = (
2120+
pp_output_trafos_3ph[loss_params[3]] = (
20842121
pgm_output_transformers["q_from"][:, 1] + pgm_output_transformers["q_to"][:, 1]
20852122
) * 1e-6
2086-
pp_output_trafos_3ph["p_c_l_mw"] = (
2123+
pp_output_trafos_3ph[loss_params[4]] = (
20872124
pgm_output_transformers["p_from"][:, 2] + pgm_output_transformers["p_to"][:, 2]
20882125
) * 1e-6
2089-
pp_output_trafos_3ph["q_c_l_mvar"] = (
2126+
pp_output_trafos_3ph[loss_params[5]] = (
20902127
pgm_output_transformers["q_from"][:, 2] + pgm_output_transformers["q_to"][:, 2]
20912128
) * 1e-6
20922129
pp_output_trafos_3ph["i_a_hv_ka"] = pgm_output_transformers["i_from"][:, 0] * 1e-3
@@ -2396,7 +2433,7 @@ def get_switch_states(self, pp_table: str) -> pd.DataFrame:
23962433
else:
23972434
raise KeyError(f"Can't get switch states for {pp_table}")
23982435

2399-
component = self.pp_input_data[pp_table]
2436+
component = self.pp_input_data[pp_table].copy()
24002437
component["index"] = component.index
24012438

24022439
# 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)