Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
110 changes: 72 additions & 38 deletions src/power_grid_model_io/converters/pandapower_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

import logging
from functools import lru_cache
from importlib.metadata import version
from typing import Dict, List, MutableMapping, Optional, Tuple, Type

import numpy as np
import pandas as pd
import structlog
from packaging.version import Version
from power_grid_model import (
Branch3Side,
BranchSide,
Expand All @@ -34,6 +36,17 @@

logger = structlog.get_logger(__file__)

pp_curr_version = Version(version("pandapower"))
pp_ref_version = Version("3.1.2")


def get_loss_params_3ph():
if pp_curr_version <= pp_ref_version:
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"]
else:
loss_params = ["pl_a_mw", "ql_a_mvar", "pl_b_mw", "ql_b_mvar", "pl_c_mw", "ql_c_mvar"]
return loss_params


# pylint: disable=too-many-instance-attributes
class PandaPowerConverter(BaseConverter[PandaPowerData]):
Expand Down Expand Up @@ -631,34 +644,53 @@ def _create_pgm_input_sym_loads(self):
data_type=DatasetType.input, component_type=ComponentType.sym_load, shape=3 * n_loads
)

const_i_multiplier = (
self._get_pp_attr("load", "const_i_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_z_multiplier = (
self._get_pp_attr("load", "const_z_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_p_multiplier = (1e6 - const_i_multiplier - const_z_multiplier) * scaling
if pp_curr_version <= pp_ref_version:
const_i_p_multiplier = (
self._get_pp_attr("load", "const_i_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_z_p_multiplier = (
self._get_pp_attr("load", "const_z_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_p_multiplier = (1e6 - const_i_p_multiplier - const_z_p_multiplier) * scaling
const_q_multiplier = const_p_multiplier
const_i_q_multiplier = const_i_p_multiplier
const_z_q_multiplier = const_z_p_multiplier
else:
const_i_p_multiplier = (
self._get_pp_attr("load", "const_i_p_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_z_p_multiplier = (
self._get_pp_attr("load", "const_z_p_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_p_multiplier = (1e6 - const_i_p_multiplier - const_z_p_multiplier) * scaling
const_i_q_multiplier = (
self._get_pp_attr("load", "const_i_q_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_z_q_multiplier = (
self._get_pp_attr("load", "const_z_q_percent", expected_type="f8", default=0) * scaling * (1e-2 * 1e6)
)
const_q_multiplier = (1e6 - const_i_q_multiplier - const_z_q_multiplier) * scaling

pgm_sym_loads["id"][:n_loads] = self._generate_ids("load", pp_loads.index, name="const_power")
pgm_sym_loads["node"][:n_loads] = self._get_pgm_ids("bus", bus)
pgm_sym_loads["status"][:n_loads] = in_service
pgm_sym_loads["type"][:n_loads] = LoadGenType.const_power
pgm_sym_loads["p_specified"][:n_loads] = const_p_multiplier * p_mw
pgm_sym_loads["q_specified"][:n_loads] = const_p_multiplier * q_mvar
pgm_sym_loads["q_specified"][:n_loads] = const_q_multiplier * q_mvar

pgm_sym_loads["id"][n_loads : 2 * n_loads] = self._generate_ids("load", pp_loads.index, name="const_impedance")
pgm_sym_loads["node"][n_loads : 2 * n_loads] = self._get_pgm_ids("bus", bus)
pgm_sym_loads["status"][n_loads : 2 * n_loads] = in_service
pgm_sym_loads["type"][n_loads : 2 * n_loads] = LoadGenType.const_impedance
pgm_sym_loads["p_specified"][n_loads : 2 * n_loads] = const_z_multiplier * p_mw
pgm_sym_loads["q_specified"][n_loads : 2 * n_loads] = const_z_multiplier * q_mvar
pgm_sym_loads["p_specified"][n_loads : 2 * n_loads] = const_z_p_multiplier * p_mw
pgm_sym_loads["q_specified"][n_loads : 2 * n_loads] = const_z_q_multiplier * q_mvar

pgm_sym_loads["id"][-n_loads:] = self._generate_ids("load", pp_loads.index, name="const_current")
pgm_sym_loads["node"][-n_loads:] = self._get_pgm_ids("bus", bus)
pgm_sym_loads["status"][-n_loads:] = in_service
pgm_sym_loads["type"][-n_loads:] = LoadGenType.const_current
pgm_sym_loads["p_specified"][-n_loads:] = const_i_multiplier * p_mw
pgm_sym_loads["q_specified"][-n_loads:] = const_i_multiplier * q_mvar
pgm_sym_loads["p_specified"][-n_loads:] = const_i_p_multiplier * p_mw
pgm_sym_loads["q_specified"][-n_loads:] = const_i_q_multiplier * q_mvar

assert ComponentType.sym_load not in self.pgm_input_data
self.pgm_input_data[ComponentType.sym_load] = pgm_sym_loads
Expand Down Expand Up @@ -769,7 +801,7 @@ def _create_pgm_input_transformers(self): # pylint: disable=too-many-statements
checks = {
"vk0_percent": np.allclose(vk_percent, vk0_percent) or np.isnan(vk0_percent).all(),
"vkr0_percent": np.allclose(vkr_percent, vkr0_percent) or np.isnan(vkr0_percent).all(),
"mag0_percent": np.allclose(i_no_load * 1e-2, 1e4 / (vk0_percent * mag0_percent))
"mag0_percent": np.allclose(i_no_load * 1e-2, (vk0_percent * mag0_percent) * 1e-4)
or np.isnan(mag0_percent).all(),
"mag0_rx": np.allclose(rx_mag, mag0_rx) or np.isnan(mag0_rx).all(),
"si0_hv_partial": np.isnan(
Expand Down Expand Up @@ -1846,6 +1878,7 @@ def _pp_lines_output_3ph(self):
i_from = (pgm_output_lines["p_from"] + 1j * pgm_output_lines["q_from"]) / u_complex.iloc[from_nodes, :]
i_to = (pgm_output_lines["p_to"] + 1j * pgm_output_lines["q_to"]) / u_complex.iloc[to_nodes, :]

loss_params = get_loss_params_3ph()
pp_output_lines_3ph = pd.DataFrame(
columns=[
"p_a_from_mw",
Expand All @@ -1860,12 +1893,12 @@ def _pp_lines_output_3ph(self):
"q_b_to_mvar",
"p_c_to_mw",
"q_c_to_mvar",
"p_a_l_mw",
"q_a_l_mvar",
"p_b_l_mw",
"q_b_l_mvar",
"p_c_l_mw",
"q_c_l_mvar",
loss_params[0],
loss_params[1],
loss_params[2],
loss_params[3],
loss_params[4],
loss_params[5],
"i_a_from_ka",
"i_b_from_ka",
"i_c_from_ka",
Expand Down Expand Up @@ -1898,12 +1931,12 @@ def _pp_lines_output_3ph(self):
pp_output_lines_3ph["q_b_to_mvar"] = pgm_output_lines["q_to"][:, 1] * 1e-6
pp_output_lines_3ph["p_c_to_mw"] = pgm_output_lines["p_to"][:, 2] * 1e-6
pp_output_lines_3ph["q_c_to_mvar"] = pgm_output_lines["q_to"][:, 2] * 1e-6
pp_output_lines_3ph["p_a_l_mw"] = (pgm_output_lines["p_from"][:, 0] + pgm_output_lines["p_to"][:, 0]) * 1e-6
pp_output_lines_3ph["q_a_l_mvar"] = (pgm_output_lines["q_from"][:, 0] + pgm_output_lines["q_to"][:, 0]) * 1e-6
pp_output_lines_3ph["p_b_l_mw"] = (pgm_output_lines["p_from"][:, 1] + pgm_output_lines["p_to"][:, 1]) * 1e-6
pp_output_lines_3ph["q_b_l_mvar"] = (pgm_output_lines["q_from"][:, 1] + pgm_output_lines["q_to"][:, 1]) * 1e-6
pp_output_lines_3ph["p_c_l_mw"] = (pgm_output_lines["p_from"][:, 2] + pgm_output_lines["p_to"][:, 2]) * 1e-6
pp_output_lines_3ph["q_c_l_mvar"] = (pgm_output_lines["q_from"][:, 2] + pgm_output_lines["q_to"][:, 2]) * 1e-6
pp_output_lines_3ph[loss_params[0]] = (pgm_output_lines["p_from"][:, 0] + pgm_output_lines["p_to"][:, 0]) * 1e-6
pp_output_lines_3ph[loss_params[1]] = (pgm_output_lines["q_from"][:, 0] + pgm_output_lines["q_to"][:, 0]) * 1e-6
pp_output_lines_3ph[loss_params[2]] = (pgm_output_lines["p_from"][:, 1] + pgm_output_lines["p_to"][:, 1]) * 1e-6
pp_output_lines_3ph[loss_params[3]] = (pgm_output_lines["q_from"][:, 1] + pgm_output_lines["q_to"][:, 1]) * 1e-6
pp_output_lines_3ph[loss_params[4]] = (pgm_output_lines["p_from"][:, 2] + pgm_output_lines["p_to"][:, 2]) * 1e-6
pp_output_lines_3ph[loss_params[5]] = (pgm_output_lines["q_from"][:, 2] + pgm_output_lines["q_to"][:, 2]) * 1e-6
pp_output_lines_3ph["i_a_from_ka"] = pgm_output_lines["i_from"][:, 0] * 1e-3
pp_output_lines_3ph["i_b_from_ka"] = pgm_output_lines["i_from"][:, 1] * 1e-3
pp_output_lines_3ph["i_c_from_ka"] = pgm_output_lines["i_from"][:, 2] * 1e-3
Expand Down Expand Up @@ -2026,6 +2059,7 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements

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

loss_params = get_loss_params_3ph()
pp_output_trafos_3ph = pd.DataFrame(
columns=[
"p_a_hv_mw",
Expand All @@ -2040,12 +2074,12 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
"q_b_lv_mvar",
"p_c_lv_mw",
"q_c_lv_mvar",
"p_a_l_mw",
"q_a_l_mvar",
"p_b_l_mw",
"q_b_l_mvar",
"p_c_l_mw",
"q_c_l_mvar",
loss_params[0],
loss_params[1],
loss_params[2],
loss_params[3],
loss_params[4],
loss_params[5],
"i_a_hv_ka",
"i_a_lv_ka",
"i_b_hv_ka",
Expand All @@ -2071,22 +2105,22 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
pp_output_trafos_3ph["q_b_lv_mvar"] = pgm_output_transformers["q_to"][:, 1] * 1e-6
pp_output_trafos_3ph["p_c_lv_mw"] = pgm_output_transformers["p_to"][:, 2] * 1e-6
pp_output_trafos_3ph["q_c_lv_mvar"] = pgm_output_transformers["q_to"][:, 2] * 1e-6
pp_output_trafos_3ph["p_a_l_mw"] = (
pp_output_trafos_3ph[loss_params[0]] = (
pgm_output_transformers["p_from"][:, 0] + pgm_output_transformers["p_to"][:, 0]
) * 1e-6
pp_output_trafos_3ph["q_a_l_mvar"] = (
pp_output_trafos_3ph[loss_params[1]] = (
pgm_output_transformers["q_from"][:, 0] + pgm_output_transformers["q_to"][:, 0]
) * 1e-6
pp_output_trafos_3ph["p_b_l_mw"] = (
pp_output_trafos_3ph[loss_params[2]] = (
pgm_output_transformers["p_from"][:, 1] + pgm_output_transformers["p_to"][:, 1]
) * 1e-6
pp_output_trafos_3ph["q_b_l_mvar"] = (
pp_output_trafos_3ph[loss_params[3]] = (
pgm_output_transformers["q_from"][:, 1] + pgm_output_transformers["q_to"][:, 1]
) * 1e-6
pp_output_trafos_3ph["p_c_l_mw"] = (
pp_output_trafos_3ph[loss_params[4]] = (
pgm_output_transformers["p_from"][:, 2] + pgm_output_transformers["p_to"][:, 2]
) * 1e-6
pp_output_trafos_3ph["q_c_l_mvar"] = (
pp_output_trafos_3ph[loss_params[5]] = (
pgm_output_transformers["q_from"][:, 2] + pgm_output_transformers["q_to"][:, 2]
) * 1e-6
pp_output_trafos_3ph["i_a_hv_ka"] = pgm_output_transformers["i_from"][:, 0] * 1e-3
Expand Down Expand Up @@ -2396,7 +2430,7 @@ def get_switch_states(self, pp_table: str) -> pd.DataFrame:
else:
raise KeyError(f"Can't get switch states for {pp_table}")

component = self.pp_input_data[pp_table]
component = self.pp_input_data[pp_table].copy()
component["index"] = component.index

# Select the appropriate switches and columns
Expand Down
17 changes: 17 additions & 0 deletions tests/data/pandapower/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!--
SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
SPDX-License-Identifier: MPL-2.0
-->
# Pandapower release 3.1.3

`pandapower` made following breaking changes to its release 3.1.3;
1. `Load` attributes have been changed:
* `const_i_percent` replaced with `const_i_p_percent` and `const_i_q_percent`
* `const_z_percent` replaced with `const_z_p_percent` and `const_z_q_percent`
2. loss attributes in 3ph load flow for `res_line_3ph` and `res_trafo_3ph` have been changed:
* `p_a_l_mw` changed to `pl_a_mw` and same for other phases
* `q_a_l_mvar` changed to `ql_a_mvar` and same for other phases

In order to maintain backward compatibility, data files compatible with both `pandapower` versions have been moved
to separate folders **v3.1.2** and **v3.1.3**.
37 changes: 33 additions & 4 deletions tests/data/pandapower/pp_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import pandapower as pp

from power_grid_model_io.converters.pandapower_converter import pp_curr_version, pp_ref_version


@lru_cache
def pp_net() -> pp.pandapowerNet:
Expand Down Expand Up @@ -51,9 +53,23 @@ def pp_net() -> pp.pandapowerNet:
pp.create_line(
net, index=101, from_bus=103, to_bus=102, length_km=1.23, parallel=2, df=0.2, std_type="NAYY 4x150 SE"
)
pp.create_load(
net, index=101, bus=103, p_mw=2.5, q_mvar=0.24, const_i_percent=26.0, const_z_percent=51.0, cos_phi=2
)
if pp_curr_version <= pp_ref_version:
pp.create_load(
net, index=101, bus=103, p_mw=2.5, q_mvar=0.24, const_i_percent=26.0, const_z_percent=51.0, cos_phi=2
)
else:
pp.create_load(
net,
index=101,
bus=103,
p_mw=2.5,
q_mvar=0.24,
const_i_p_percent=26.0,
const_i_q_percent=26.0,
const_z_p_percent=51.0,
const_z_q_percent=51.0,
cos_phi=2,
)
pp.create_switch(net, index=101, et="l", bus=103, element=101, closed=True)
pp.create_switch(net, index=3021, et="b", bus=101, element=106, closed=True)
pp.create_switch(net, index=321, et="t", bus=101, element=101, closed=True)
Expand Down Expand Up @@ -173,7 +189,20 @@ def pp_net_3ph() -> pp.pandapowerNet:
c0_nf_per_km=261.0,
max_i_ka=0.27,
)
pp.create_load(net, index=101, bus=103, p_mw=2.5, q_mvar=0.24, const_i_percent=0.0, const_z_percent=0)
if pp_curr_version <= pp_ref_version:
pp.create_load(net, index=101, bus=103, p_mw=2.5, q_mvar=0.24, const_i_percent=0.0, const_z_percent=0)
else:
pp.create_load(
net,
index=101,
bus=103,
p_mw=2.5,
q_mvar=0.24,
const_i_p_percent=0.0,
const_i_q_percent=0.0,
const_z_p_percent=0,
const_z_q_percnet=0,
)
pp.create_switch(net, index=101, et="l", bus=103, element=101, closed=True)
pp.create_switch(net, index=3021, et="b", bus=101, element=106, closed=True)
pp.create_switch(net, index=321, et="t", bus=101, element=0, closed=True)
Expand Down
File renamed without changes.
Loading
Loading