Skip to content

Commit fe83bf2

Browse files
committed
add new validation test + cleanup
Signed-off-by: Martijn Govers <[email protected]>
1 parent 72d4578 commit fe83bf2

File tree

4 files changed

+136
-30
lines changed

4 files changed

+136
-30
lines changed

src/power_grid_model_io/converters/pandapower_converter.py

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,35 +2026,26 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20262026
loading_a_percent = np.sqrt(3) * np.maximum(ui_from[:, 0], ui_to[:, 0]) / pgm_input_transformers["sn"]
20272027
loading_b_percent = np.sqrt(3) * np.maximum(ui_from[:, 1], ui_to[:, 1]) / pgm_input_transformers["sn"]
20282028
loading_c_percent = np.sqrt(3) * np.maximum(ui_from[:, 2], ui_to[:, 2]) / pgm_input_transformers["sn"]
2029-
# To make it consistent with PandaPower, overall loading will be calculated as max of above 3.
2030-
loading = np.maximum(np.maximum(loading_a_percent, loading_b_percent), loading_c_percent)
20312029
elif self.trafo_loading == "power":
2032-
loading_a_percent = (
2033-
np.maximum(
2034-
pgm_output_transformers["s_from"][:, 0],
2035-
pgm_output_transformers["s_to"][:, 0],
2036-
)
2037-
/ (pgm_input_transformers["sn"] / 3)
2038-
)
2039-
loading_b_percent = (
2040-
np.maximum(
2041-
pgm_output_transformers["s_from"][:, 1],
2042-
pgm_output_transformers["s_to"][:, 1],
2043-
)
2044-
/ (pgm_input_transformers["sn"] / 3)
2045-
)
2046-
loading_c_percent = (
2047-
np.maximum(
2048-
pgm_output_transformers["s_from"][:, 2],
2049-
pgm_output_transformers["s_to"][:, 2],
2050-
)
2051-
/ (pgm_input_transformers["sn"] / 3)
2052-
)
2053-
# To make it consistent with PandaPower, overall loading will be calculated as max of above 3.
2054-
loading = np.maximum(np.maximum(loading_a_percent, loading_b_percent), loading_c_percent)
2030+
loading_a_percent = np.maximum(
2031+
pgm_output_transformers["s_from"][:, 0],
2032+
pgm_output_transformers["s_to"][:, 0],
2033+
) / (pgm_input_transformers["sn"] / 3)
2034+
loading_b_percent = np.maximum(
2035+
pgm_output_transformers["s_from"][:, 1],
2036+
pgm_output_transformers["s_to"][:, 1],
2037+
) / (pgm_input_transformers["sn"] / 3)
2038+
loading_c_percent = np.maximum(
2039+
pgm_output_transformers["s_from"][:, 2],
2040+
pgm_output_transformers["s_to"][:, 2],
2041+
) / (pgm_input_transformers["sn"] / 3)
20552042
else:
20562043
raise ValueError(f"Invalid transformer loading type: {str(self.trafo_loading)}")
20572044

2045+
# PGM returns the average loading over the cable, but PandaPower returns the maximum of the per-phase loading.
2046+
# To make it consistent with PandaPower, overall loading will be calculated as max of above 3.
2047+
loading = np.maximum(np.maximum(loading_a_percent, loading_b_percent), loading_c_percent)
2048+
20582049
pp_output_trafos_3ph = pd.DataFrame(
20592050
columns=[
20602051
"p_a_hv_mw",

tests/data/pandapower/pp_validation.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,48 @@ def pp_net_3ph() -> pp.pandapowerNet:
192192
# )
193193

194194
return net
195+
196+
197+
def pp_net_3ph_minimal_trafo():
198+
net = pp.create_empty_network("test", f_hz=50)
199+
pp.create_bus(net, 11, "source")
200+
pp.create_bus(net, 11, "TF_HT")
201+
pp.create_bus(net, 0.4, "TF_LT")
202+
203+
pp.create_ext_grid(net, 0, 1.0, 0, s_sc_max_mva=100, rx_max=0.1, x0x_max=1, r0x0_max=0.1)
204+
pp.create_line_from_parameters(
205+
net,
206+
0,
207+
1,
208+
2,
209+
0.33,
210+
0.34,
211+
0.001,
212+
600,
213+
r0_ohm_per_km=0.66,
214+
x0_ohm_per_km=0.65,
215+
c0_nf_per_km=0.001,
216+
g_us_per_km=0,
217+
g0_us_per_km=0,
218+
)
219+
pp.create_transformer_from_parameters(
220+
net,
221+
1,
222+
2,
223+
1,
224+
11,
225+
0.415,
226+
0,
227+
4,
228+
0,
229+
0.01,
230+
-30,
231+
vector_group="Dyn",
232+
vk0_percent=4,
233+
vkr0_percent=0,
234+
mag0_percent=100,
235+
mag0_rx=0,
236+
si0_hv_partial=0.9,
237+
)
238+
pp.create_asymmetric_load(net, 2, 0.2, 0.19, 0.195, 0.05, 0.045, 0.035, 0, type="wye")
239+
return net

tests/unit/converters/test_pandapower_converter_output.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,10 @@ def test_output_trafos_3ph__power(converter):
10341034
converter._pp_trafos_output_3ph()
10351035

10361036
# retrieval
1037-
mock_pgm_array.__getitem__.assert_any_call("loading")
1037+
assert "loading" not in mock_pgm_array.__getitem__.call_args_list, (
1038+
"The convention for loading differs between PGM and PP and the PGM loading therefore should not be used "
1039+
"for conversion to PP."
1040+
)
10381041

10391042
# result
10401043
converter.pp_output_data.__setitem__.assert_called_once_with("res_trafo_3ph", mock_pp_df.return_value)

tests/validation/converters/test_pandapower_converter_output.py

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from power_grid_model_io.converters import PandaPowerConverter
1616
from power_grid_model_io.converters.pandapower_converter import PandaPowerData
1717

18-
from ...data.pandapower.pp_validation import pp_net, pp_net_3ph
18+
from ...data.pandapower.pp_validation import pp_net, pp_net_3ph, pp_net_3ph_minimal_trafo
1919
from ..utils import component_attributes_df, load_json_single_dataset
2020

2121
pp = pytest.importorskip("pandapower", reason="pandapower is not installed")
@@ -51,10 +51,8 @@ def load_and_convert_pgm_data_3ph() -> PandaPowerData:
5151
"""
5252
Load and convert the power_grid_model results
5353
"""
54-
data, extra_info = load_json_single_dataset(PGM_ASYM_OUTPUT_FILE, data_type="asym_output")
55-
# trafo_loading = "power", as validation data is based on power based loading
54+
data, _ = load_json_single_dataset(PGM_ASYM_OUTPUT_FILE, data_type="asym_output")
5655
converter = PandaPowerConverter(trafo_loading="power")
57-
# if pp_input_data is not present in converter, some convert functions may fail.
5856
converter.load_input_data(load_validation_data_3ph(), make_extra_info=False)
5957
return converter.convert(data=data)
6058

@@ -129,6 +127,74 @@ def test_generate_output_3ph(): # TODO: REMOVE THIS FUNCTION
129127
json_converter.save(data=output_data_asym, extra_info=extra_info)
130128

131129

130+
def test_output_trafos_3ph__power__with_comparison():
131+
import numpy as np
132+
133+
def check_result(net):
134+
v_hv = net.trafo.vn_hv_kv
135+
v_lv = net.trafo.vn_lv_kv
136+
i_max_hv = np.divide(net.trafo.sn_mva, v_hv * np.sqrt(3)) * 1e3
137+
i_max_lv = np.divide(net.trafo.sn_mva, v_lv * np.sqrt(3)) * 1e3
138+
139+
i_a_hv = net.res_trafo_3ph.loc[:, "i_a_hv_ka"] * 1000
140+
i_b_hv = net.res_trafo_3ph.loc[:, "i_b_hv_ka"] * 1000
141+
i_c_hv = net.res_trafo_3ph.loc[:, "i_c_hv_ka"] * 1000
142+
143+
i_a_lv = net.res_trafo_3ph.loc[:, "i_a_lv_ka"] * 1000
144+
i_b_lv = net.res_trafo_3ph.loc[:, "i_b_lv_ka"] * 1000
145+
i_c_lv = net.res_trafo_3ph.loc[:, "i_c_lv_ka"] * 1000
146+
147+
np.testing.assert_allclose(
148+
np.maximum(i_a_hv / i_max_hv, i_a_lv / i_max_lv) * 100, net.res_trafo_3ph.loading_a_percent
149+
)
150+
np.testing.assert_allclose(
151+
np.maximum(i_b_hv / i_max_hv, i_b_lv / i_max_lv) * 100, net.res_trafo_3ph.loading_b_percent
152+
)
153+
np.testing.assert_allclose(
154+
np.maximum(i_c_hv / i_max_hv, i_c_lv / i_max_lv) * 100, net.res_trafo_3ph.loading_c_percent
155+
)
156+
157+
def compare_result(actual, expected, *, rtol):
158+
np.testing.assert_allclose(actual.trafo.vn_hv_kv, expected.trafo.vn_hv_kv, rtol=rtol)
159+
np.testing.assert_allclose(actual.trafo.vn_lv_kv, expected.trafo.vn_lv_kv, rtol=rtol)
160+
np.testing.assert_allclose(actual.trafo.sn_mva, expected.trafo.sn_mva, rtol=rtol)
161+
np.testing.assert_allclose(
162+
actual.res_trafo_3ph.loc[:, "i_a_hv_ka"], expected.res_trafo_3ph.loc[:, "i_a_hv_ka"], rtol=rtol
163+
)
164+
np.testing.assert_allclose(
165+
actual.res_trafo_3ph.loc[:, "i_b_hv_ka"], expected.res_trafo_3ph.loc[:, "i_b_hv_ka"], rtol=rtol
166+
)
167+
np.testing.assert_allclose(
168+
actual.res_trafo_3ph.loc[:, "i_c_hv_ka"], expected.res_trafo_3ph.loc[:, "i_c_hv_ka"], rtol=rtol
169+
)
170+
np.testing.assert_allclose(
171+
actual.res_trafo_3ph.loc[:, "i_a_lv_ka"], expected.res_trafo_3ph.loc[:, "i_a_lv_ka"], rtol=rtol
172+
)
173+
np.testing.assert_allclose(
174+
actual.res_trafo_3ph.loc[:, "i_b_lv_ka"], expected.res_trafo_3ph.loc[:, "i_b_lv_ka"], rtol=rtol
175+
)
176+
np.testing.assert_allclose(
177+
actual.res_trafo_3ph.loc[:, "i_c_lv_ka"], expected.res_trafo_3ph.loc[:, "i_c_lv_ka"], rtol=rtol
178+
)
179+
np.testing.assert_allclose(
180+
actual.res_trafo_3ph.loading_a_percent, expected.res_trafo_3ph.loading_a_percent, rtol=rtol
181+
)
182+
np.testing.assert_allclose(
183+
actual.res_trafo_3ph.loading_b_percent, expected.res_trafo_3ph.loading_b_percent, rtol=rtol
184+
)
185+
np.testing.assert_allclose(
186+
actual.res_trafo_3ph.loading_c_percent, expected.res_trafo_3ph.loading_c_percent, rtol=rtol
187+
)
188+
189+
pgm_net = pp_net_3ph_minimal_trafo()
190+
pp_net = pp_net_3ph_minimal_trafo()
191+
pp.runpp_pgm(pgm_net, symmetric=False)
192+
pp.runpp_3ph(pp_net)
193+
check_result(pgm_net)
194+
check_result(pp_net)
195+
compare_result(pgm_net, pp_net, rtol=0.04)
196+
197+
132198
def test_output_data(output_data: Tuple[PandaPowerData, PandaPowerData]):
133199
"""
134200
Unit test to preload the expected and actual data
@@ -166,6 +232,7 @@ def test_attributes(output_data: Tuple[PandaPowerData, PandaPowerData], componen
166232
# Assert
167233
pd.testing.assert_series_equal(actual_values, expected_values, atol=5e-4, rtol=1e-4)
168234

235+
169236
# The following test only works for those components where valid data is returned by
170237
# load_and_convert_pgm_data_3ph. since this is failing for trafo_output_3ph (returning
171238
# from first "if", this function's output is not being tested currently.

0 commit comments

Comments
 (0)