Skip to content

Commit 1629de8

Browse files
committed
Get rid of repetitive code, make one util function for all elements being converted as sym_load
Signed-off-by: furqan463 <[email protected]>
1 parent 05f6a32 commit 1629de8

File tree

3 files changed

+95
-130
lines changed

3 files changed

+95
-130
lines changed

src/power_grid_model_io/converters/pandapower_converter.py

Lines changed: 26 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -342,13 +342,13 @@ def _create_output_data(self):
342342
self._pp_buses_output()
343343
self._pp_lines_output()
344344
self._pp_ext_grids_output()
345-
self._pp_loads_output()
345+
self._pp_load_elements_output(element="load", symmetric=True)
346+
self._pp_load_elements_output(element="ward", symmetric=True)
347+
self._pp_load_elements_output(element="motor", symmetric=True)
346348
self._pp_shunts_output()
347349
self._pp_trafos_output()
348350
self._pp_sgens_output()
349351
self._pp_trafos3w_output()
350-
self._pp_ward_output()
351-
self._pp_motor_output()
352352
self._pp_asym_gens_output()
353353
self._pp_asym_loads_output()
354354
# Switches derive results from branches pp_output_data and pgm_output_data of links. Hence, placed in the end.
@@ -361,17 +361,15 @@ def _create_output_data_3ph(self):
361361
angle in degrees
362362
"""
363363
# TODO create output_data_3ph for trafos3w
364-
# Although Pandapower itself did not implmenet res_shunt_3ph
365-
# Since results are avaiable in PGM output, these should be converted.
366364
self._pp_buses_output_3ph()
367365
self._pp_lines_output_3ph()
368366
self._pp_ext_grids_output_3ph()
369-
self._pp_loads_output_3ph()
367+
self._pp_load_elements_output(element="load", symmetric=False)
368+
self._pp_load_elements_output(element="ward", symmetric=False)
369+
self._pp_load_elements_output(element="motor", symmetric=False)
370370
self._pp_shunts_output_3ph()
371371
self._pp_trafos_output_3ph()
372372
self._pp_sgens_output_3ph()
373-
self._pp_ward_output_3ph()
374-
self._pp_motor_output_3ph()
375373
self._pp_asym_gens_output_3ph()
376374
self._pp_asym_loads_output_3ph()
377375

@@ -1563,64 +1561,37 @@ def _pp_asym_gens_output(self):
15631561

15641562
self.pp_output_data["res_asymmetric_sgen"] = pp_output_asym_gens
15651563

1566-
def _pp_loads_output(self):
1564+
def _pp_load_elements_output(self, element, symmetric):
15671565
"""
1568-
This function converts a power-grid-model Symmetrical Load output array to a Load Dataframe of PandaPower.
1569-
1570-
Returns:
1571-
a PandaPower Dataframe for the Load component
1566+
Utility function to convert output of elements represented as load
1567+
in power grid model.
1568+
element: "load", "motor" or "ward"
1569+
symmetric: True or False
15721570
"""
1573-
load_id_names = ["const_power", "const_impedance", "const_current"]
1574-
assert "res_load" not in self.pp_output_data
1575-
1576-
if (
1577-
ComponentType.sym_load not in self.pgm_output_data
1578-
or self.pgm_output_data[ComponentType.sym_load].size == 0
1579-
or ("load", load_id_names[0]) not in self.idx
1580-
):
1581-
return
1582-
1583-
# Store the results, while assuring that we are not overwriting any data
1584-
assert "res_load" not in self.pp_output_data
1585-
self.pp_output_data["res_load"] = self._pp_load_result_accumulate(
1586-
pp_component_name="load", load_id_names=load_id_names
1587-
)
1588-
1589-
def _pp_ward_output(self):
1590-
load_id_names = ["ward_const_power_load", "ward_const_impedance_load"]
1591-
assert "res_ward" not in self.pp_output_data
1592-
1593-
if (
1594-
ComponentType.sym_load not in self.pgm_output_data
1595-
or self.pgm_output_data[ComponentType.sym_load].size == 0
1596-
or ("ward", load_id_names[0]) not in self.idx
1597-
):
1598-
return
1599-
1600-
accumulated_loads = self._pp_load_result_accumulate(pp_component_name="ward", load_id_names=load_id_names)
1601-
# TODO Find a better way for mapping vm_pu from bus
1602-
# accumulated_loads["vm_pu"] = np.nan
1603-
1604-
# Store the results, while assuring that we are not overwriting any data
1605-
assert "res_ward" not in self.pp_output_data
1606-
self.pp_output_data["res_ward"] = accumulated_loads
1571+
if symmetric:
1572+
res_table = "res_" + element
1573+
else:
1574+
res_table = "res_" + element + "_3ph"
16071575

1608-
def _pp_motor_output(self):
1609-
load_id_names = ["motor_load"]
1576+
if element == "load":
1577+
load_id_names = ["const_power", "const_impedance", "const_current"]
1578+
elif element == "ward":
1579+
load_id_names = ["ward_const_power_load", "ward_const_impedance_load"]
1580+
elif element == "motor":
1581+
load_id_names = ["motor_load"]
16101582

1611-
assert "res_motor" not in self.pp_output_data
1583+
assert res_table not in self.pp_output_data
16121584

16131585
if (
16141586
ComponentType.sym_load not in self.pgm_output_data
16151587
or self.pgm_output_data[ComponentType.sym_load].size == 0
1616-
or ("motor", load_id_names[0]) not in self.idx
1588+
or (element, load_id_names[0]) not in self.idx
16171589
):
16181590
return
1619-
16201591
# Store the results, while assuring that we are not overwriting any data
1621-
assert "res_motor" not in self.pp_output_data
1622-
self.pp_output_data["res_motor"] = self._pp_load_result_accumulate(
1623-
pp_component_name="motor", load_id_names=load_id_names
1592+
assert res_table not in self.pp_output_data
1593+
self.pp_output_data[res_table] = self._pp_load_result_accumulate(
1594+
pp_component_name=element, load_id_names=load_id_names
16241595
)
16251596

16261597
def _pp_load_result_accumulate(self, pp_component_name: str, load_id_names: List[str]) -> pd.DataFrame:
@@ -2134,64 +2105,6 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
21342105
assert "res_trafo_3ph" not in self.pp_output_data
21352106
self.pp_output_data["res_trafo_3ph"] = pp_output_trafos_3ph
21362107

2137-
def _pp_loads_output_3ph(self):
2138-
"""
2139-
This function converts a power-grid-model Symmetrical Load output array to a Load Dataframe of PandaPower.
2140-
2141-
Returns:
2142-
a PandaPower Dataframe for the Load component
2143-
"""
2144-
load_id_names = ["const_power", "const_impedance", "const_current"]
2145-
if (
2146-
ComponentType.sym_load not in self.pgm_output_data
2147-
or self.pgm_output_data[ComponentType.sym_load].size == 0
2148-
or ("load", load_id_names[0]) not in self.idx
2149-
):
2150-
return
2151-
2152-
# Store the results, while assuring that we are not overwriting any data
2153-
assert "res_load_3ph" not in self.pp_output_data
2154-
self.pp_output_data["res_load_3ph"] = self._pp_load_result_accumulate(
2155-
pp_component_name="load", load_id_names=load_id_names
2156-
)
2157-
2158-
def _pp_ward_output_3ph(self):
2159-
# TODO: Create Unit tests
2160-
load_id_names = ["ward_const_power_load", "ward_const_impedance_load"]
2161-
if (
2162-
ComponentType.sym_load not in self.pgm_output_data
2163-
or self.pgm_output_data[ComponentType.sym_load].size == 0
2164-
or ("ward", load_id_names[0]) not in self.idx
2165-
):
2166-
return
2167-
2168-
# TODO Find a better way for mapping vm_pu from bus
2169-
# accumulated_loads["vm_pu"] = np.nan
2170-
# Store the results, while assuring that we are not overwriting any data
2171-
assert "res_ward_3ph" not in self.pp_output_data
2172-
self.pp_output_data["res_ward_3ph"] = self._pp_load_result_accumulate(
2173-
pp_component_name="ward", load_id_names=load_id_names
2174-
)
2175-
2176-
def _pp_motor_output_3ph(self):
2177-
# TODO: Create unit tests
2178-
load_id_names = ["motor_load"]
2179-
2180-
assert "res_motor_3ph" not in self.pp_output_data
2181-
2182-
if (
2183-
ComponentType.sym_load not in self.pgm_output_data
2184-
or self.pgm_output_data[ComponentType.sym_load].size == 0
2185-
or ("motor", load_id_names[0]) not in self.idx
2186-
):
2187-
return
2188-
2189-
# Store the results, while assuring that we are not overwriting any data
2190-
assert "res_motor" not in self.pp_output_data
2191-
self.pp_output_data["res_motor_3ph"] = self._pp_load_result_accumulate(
2192-
pp_component_name="motor", load_id_names=load_id_names
2193-
)
2194-
21952108
def _pp_shunts_output_3ph(self):
21962109
"""
21972110
This function converts a power-grid-model Shunt output array to a Shunt Dataframe of PandaPower.

tests/unit/converters/test_pandapower_converter_output.py

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# SPDX-License-Identifier: MPL-2.0
44

55
from typing import Callable, List
6-
from unittest.mock import ANY, MagicMock, patch
6+
from unittest.mock import ANY, MagicMock, call, patch
77

88
import numpy as np
99
import pandas as pd
@@ -38,11 +38,14 @@ def test_create_output_data():
3838
converter._pp_sgens_output.assert_called_once_with()
3939
converter._pp_trafos_output.assert_called_once_with()
4040
converter._pp_trafos3w_output.assert_called_once_with()
41-
converter._pp_loads_output.assert_called_once_with()
41+
expected_calls = [
42+
call(element="load", symmetric=True),
43+
call(element="ward", symmetric=True),
44+
call(element="motor", symmetric=True),
45+
]
46+
converter._pp_load_elements_output.assert_has_calls(expected_calls)
4247
converter._pp_asym_loads_output.assert_called_once_with()
4348
converter._pp_asym_gens_output.assert_called_once_with()
44-
converter._pp_motor_output.assert_called_once_with()
45-
converter._pp_ward_output.assert_called_once_with()
4649
converter._pp_switches_output.assert_called_once_with()
4750

4851

@@ -60,7 +63,12 @@ def test_create_output_data_3ph():
6063
converter._pp_ext_grids_output_3ph.assert_called_once_with()
6164
converter._pp_sgens_output_3ph.assert_called_once_with()
6265
converter._pp_trafos_output_3ph.assert_called_once_with()
63-
converter._pp_loads_output_3ph.assert_called_once_with()
66+
expected_calls = [
67+
call(element="load", symmetric=False),
68+
call(element="ward", symmetric=False),
69+
call(element="motor", symmetric=False),
70+
]
71+
converter._pp_load_elements_output.assert_has_calls(expected_calls)
6472
converter._pp_asym_loads_output_3ph.assert_called_once_with()
6573
converter._pp_asym_gens_output_3ph.assert_called_once_with()
6674

@@ -75,18 +83,13 @@ def test_create_output_data_3ph():
7583
(PandaPowerConverter._pp_sgens_output, "sym_gen"),
7684
(PandaPowerConverter._pp_trafos_output, "transformer"),
7785
(PandaPowerConverter._pp_trafos3w_output, "three_winding_transformer"),
78-
(PandaPowerConverter._pp_loads_output, "sym_load"),
79-
(PandaPowerConverter._pp_asym_loads_output, "asym_load"),
8086
(PandaPowerConverter._pp_asym_gens_output, "asym_gen"),
81-
(PandaPowerConverter._pp_ward_output, "ward"),
82-
(PandaPowerConverter._pp_motor_output, "motor"),
8387
(PandaPowerConverter._pp_switches_output, "link"),
8488
(PandaPowerConverter._pp_buses_output_3ph, "node"),
8589
(PandaPowerConverter._pp_lines_output_3ph, "line"),
8690
(PandaPowerConverter._pp_ext_grids_output_3ph, "source"),
8791
(PandaPowerConverter._pp_sgens_output_3ph, "sym_gen"),
8892
(PandaPowerConverter._pp_trafos_output_3ph, "transformer"),
89-
(PandaPowerConverter._pp_loads_output_3ph, "sym_load"),
9093
(PandaPowerConverter._pp_asym_loads_output_3ph, "asym_load"),
9194
(PandaPowerConverter._pp_asym_gens_output_3ph, "asym_gen"),
9295
],
@@ -109,6 +112,34 @@ def test_create_pp_output_object__empty(create_fn: Callable[[PandaPowerConverter
109112
mock_df.assert_not_called()
110113

111114

115+
@pytest.mark.parametrize(
116+
("create_fn", "element", "symmetric", "table"),
117+
[
118+
(PandaPowerConverter._pp_load_elements_output, "load", True, "sym_load"),
119+
(PandaPowerConverter._pp_load_elements_output, "ward", True, "ward"),
120+
(PandaPowerConverter._pp_load_elements_output, "motor", True, "motor"),
121+
],
122+
)
123+
def test_create_pp_output_object_with_params__empty(
124+
create_fn: Callable[[PandaPowerConverter, str, bool], None], element: str, symmetric: bool, table: str
125+
):
126+
# Arrange: No table
127+
converter = PandaPowerConverter()
128+
129+
# Act / Assert
130+
with patch("power_grid_model_io.converters.pandapower_converter.pd.DataFrame") as mock_df:
131+
create_fn(converter, element, symmetric)
132+
mock_df.assert_not_called()
133+
134+
# Arrange: Empty table
135+
converter.pgm_output_data[table] = np.array([]) # type: ignore
136+
137+
# Act / Assert
138+
with patch("power_grid_model_io.converters.pandapower_converter.pd.DataFrame") as mock_df:
139+
create_fn(converter, element, symmetric)
140+
mock_df.assert_not_called()
141+
142+
112143
def test_output_bus(converter):
113144
# Arrange
114145
mock_pgm_array = MagicMock()
@@ -532,15 +563,34 @@ def test_pp_load_result_accumulate__asym():
532563

533564

534565
@pytest.mark.parametrize(
535-
("output_fn", "table", "load_id_names", "result_suffix"),
566+
("output_fn", "element", "symmetric", "table", "load_id_names", "result_suffix"),
536567
[
537-
(PandaPowerConverter._pp_loads_output, "load", ["const_power", "const_impedance", "const_current"], ""),
538-
(PandaPowerConverter._pp_motor_output, "motor", ["motor_load"], ""),
539-
(PandaPowerConverter._pp_loads_output_3ph, "load", ["const_power", "const_impedance", "const_current"], "_3ph"),
568+
(
569+
PandaPowerConverter._pp_load_elements_output,
570+
"load",
571+
True,
572+
"load",
573+
["const_power", "const_impedance", "const_current"],
574+
"",
575+
),
576+
(PandaPowerConverter._pp_load_elements_output, "motor", True, "motor", ["motor_load"], ""),
577+
(
578+
PandaPowerConverter._pp_load_elements_output,
579+
"load",
580+
False,
581+
"load",
582+
["const_power", "const_impedance", "const_current"],
583+
"_3ph",
584+
),
540585
],
541586
)
542587
def test_output_load_types(
543-
output_fn: Callable[[PandaPowerConverter], None], table: str, load_id_names: List[str], result_suffix: str
588+
output_fn: Callable[[PandaPowerConverter, str, bool], None],
589+
element: str,
590+
symmetric: bool,
591+
table: str,
592+
load_id_names: List[str],
593+
result_suffix: str,
544594
):
545595
# Arrange
546596
converter = PandaPowerConverter()
@@ -551,7 +601,7 @@ def test_output_load_types(
551601
converter._pp_load_result_accumulate = MagicMock() # type: ignore
552602

553603
# Act
554-
output_fn(converter)
604+
output_fn(converter, element, symmetric)
555605

556606
# Assert
557607
converter._pp_load_result_accumulate.assert_called_once_with(pp_component_name=table, load_id_names=load_id_names)
@@ -570,7 +620,7 @@ def test_output_load_ward():
570620
converter._pp_load_result_accumulate = MagicMock()
571621

572622
# Act
573-
converter._pp_ward_output()
623+
converter._pp_load_elements_output(element="ward", symmetric=True)
574624

575625
# Assert
576626
converter._pp_load_result_accumulate.assert_called_once_with(pp_component_name="ward", load_id_names=load_id_names)

tests/validation/converters/test_pandapower_converter_output.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ def run_pf_asym_with_pgm(net):
357357
net[table] = output_tables[table]
358358

359359
net = pp_networks.ieee_european_lv_asymmetric()
360+
pp.create_load(net, 50, 0.1, 0.05)
360361
run_pf_asym_with_pgm(net)
361362
s_ext_grid, s_load, s_loss = _get_total_powers_3ph(net)
362363
assert np.isclose(s_ext_grid, (s_load + s_loss))
@@ -430,6 +431,7 @@ def run_pf_sym_with_pgm(net):
430431
net[table] = output_tables[table]
431432

432433
net = pp_networks.ieee_european_lv_asymmetric()
434+
pp.create_load(net, 50, 0.1, 0.05)
433435
run_pf_sym_with_pgm(net)
434436
s_ext_grid, s_load, s_loss = _get_total_powers(net)
435437
assert np.isclose(s_ext_grid, (s_load + s_loss))

0 commit comments

Comments
 (0)