Skip to content

Commit 5437421

Browse files
authored
Merge pull request #320 from furqan463/main
Pandapower converter: fix 3-Ph transformer loading Calculation
2 parents 693358b + 6788b51 commit 5437421

File tree

9 files changed

+3649
-278
lines changed

9 files changed

+3649
-278
lines changed

src/power_grid_model_io/converters/pandapower_converter.py

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def _parse_data(
9999
self.idx_lookup = {}
100100
self.next_idx = 0
101101

102-
# Set pandas data
102+
# Set pandapower data
103103
self.pp_input_data = data
104104

105105
# Convert
@@ -360,6 +360,9 @@ def _create_output_data_3ph(self):
360360
Furthermore, creates a global node lookup table, which stores nodes' voltage magnitude per unit and the voltage
361361
angle in degrees
362362
"""
363+
# TODO create output_data_3ph for remaining components
364+
# Although Pandapower itself did not implmenet res_shunt_3ph
365+
# Since results are avaiable in PGM output, these should be converted.
363366
self._pp_buses_output_3ph()
364367
self._pp_lines_output_3ph()
365368
self._pp_ext_grids_output_3ph()
@@ -376,6 +379,7 @@ def _create_pgm_input_nodes(self):
376379
Returns:
377380
a power-grid-model structured array for the Node component
378381
"""
382+
# TODO handle out-of-service buses, either here or in get_switch_states
379383
pp_busses = self.pp_input_data["bus"]
380384

381385
if pp_busses.empty:
@@ -422,11 +426,12 @@ def _create_pgm_input_lines(self):
422426
pgm_lines["x1"] = self._get_pp_attr("line", "x_ohm_per_km", expected_type="f8") * multiplier
423427
pgm_lines["c1"] = c_nf_per_km * length_km * parallel * 1e-9
424428
# The formula for tan1 = R_1 / Xc_1 = (g * 1e-6) / (2 * pi * f * c * 1e-9) = g / (2 * pi * f * c * 1e-3)
425-
pgm_lines["tan1"] = (
426-
self._get_pp_attr("line", "g_us_per_km", expected_type="f8", default=0)
427-
/ c_nf_per_km
428-
/ (2 * np.pi * self.system_frequency * 1e-3)
429+
pgm_lines["tan1"] = np.divide(
430+
self._get_pp_attr("line", "g_us_per_km", expected_type="f8", default=0),
431+
c_nf_per_km * (2 * np.pi * self.system_frequency * 1e-3),
432+
where=c_nf_per_km != 0.0,
429433
)
434+
pgm_lines["tan1"][np.equal(c_nf_per_km, 0.0)] = 0.0
430435
pgm_lines["i_n"] = (
431436
(self._get_pp_attr("line", "max_i_ka", expected_type="f8", default=np.nan) * 1e3)
432437
* self._get_pp_attr("line", "df", expected_type="f8", default=1)
@@ -435,11 +440,12 @@ def _create_pgm_input_lines(self):
435440
pgm_lines["r0"] = self._get_pp_attr("line", "r0_ohm_per_km", expected_type="f8", default=np.nan) * multiplier
436441
pgm_lines["x0"] = self._get_pp_attr("line", "x0_ohm_per_km", expected_type="f8", default=np.nan) * multiplier
437442
pgm_lines["c0"] = c0_nf_per_km * length_km * parallel * 1e-9
438-
pgm_lines["tan0"] = (
439-
self._get_pp_attr("line", "g0_us_per_km", expected_type="f8", default=0)
440-
/ c0_nf_per_km
441-
/ (2 * np.pi * self.system_frequency * 1e-3)
443+
pgm_lines["tan0"] = np.divide(
444+
self._get_pp_attr("line", "g0_us_per_km", expected_type="f8", default=0),
445+
c0_nf_per_km * (2 * np.pi * self.system_frequency * 1e-3),
446+
where=c0_nf_per_km != 0.0,
442447
)
448+
pgm_lines["tan0"][np.equal(c0_nf_per_km, 0.0)] = 0.0
443449
assert ComponentType.line not in self.pgm_input_data
444450
self.pgm_input_data[ComponentType.line] = pgm_lines
445451

@@ -755,7 +761,10 @@ def _create_pgm_input_transformers(self): # pylint: disable=too-many-statements
755761
valid = np.logical_and(np.not_equal(sn_mva, 0.0), np.isfinite(sn_mva))
756762
mag_g = np.divide(pfe, sn_mva * 1000, where=valid)
757763
mag_g[np.logical_not(valid)] = np.nan
758-
rx_mag = mag_g / np.sqrt(i_no_load * i_no_load * 1e-4 - mag_g * mag_g)
764+
z_squared = i_no_load * i_no_load * 1e-4 - mag_g * mag_g
765+
valid = np.logical_and(np.greater(z_squared, 0), np.isfinite(z_squared))
766+
rx_mag = np.divide(mag_g, np.sqrt(z_squared, where=valid), where=valid)
767+
rx_mag[np.logical_not(valid)] = np.inf
759768
# positive and zero sequence magnetising impedance must be equal.
760769
# mag0_percent = z0mag / z0.
761770
checks = {
@@ -1382,7 +1391,9 @@ def _pp_trafos_output(self):
13821391
if self.trafo_loading == "current":
13831392
ui_from = pgm_output_transformers["i_from"] * pgm_input_transformers["u1"]
13841393
ui_to = pgm_output_transformers["i_to"] * pgm_input_transformers["u2"]
1385-
loading = np.maximum(ui_from, ui_to) / pgm_input_transformers["sn"] * loading_multiplier * 1e2
1394+
loading = (
1395+
(np.sqrt(3) * np.maximum(ui_from, ui_to) / pgm_input_transformers["sn"]) * loading_multiplier * 1e2
1396+
)
13861397
elif self.trafo_loading == "power":
13871398
loading = pgm_output_transformers["loading"] * loading_multiplier * 1e2
13881399
else:
@@ -1704,14 +1715,16 @@ def join_currents(table: str, bus_name: str, i_name: str) -> pd.DataFrame:
17041715
)
17051716
pp_switches_output = pp_switches_output[["i_ka"]]
17061717
pp_switches_output.set_index(pp_switches_output_index, inplace=True)
1707-
pp_switches_output["loading_percent"] = np.nan
17081718

17091719
# For et=b, ie bus to bus switches, links are created. get result from them
17101720
if not links_absent:
17111721
links = self.pgm_output_data[ComponentType.link]
17121722
# For links, i_from = i_to = i_ka / 1e3
17131723
link_ids = self._get_pp_ids("switch", links["id"], "b2b_switches")
17141724
pp_switches_output.loc[link_ids, "i_ka"] = links["i_from"] * 1e-3
1725+
in_ka = self.pp_input_data["switch"]["in_ka"].values
1726+
pp_switches_output["loading_percent"] = np.nan
1727+
pp_switches_output["loading_percent"] = np.divide(pp_switches_output["i_ka"], in_ka, where=in_ka != 0)
17151728

17161729
assert "res_switch" not in self.pp_output_data
17171730
self.pp_output_data["res_switch"] = pp_switches_output
@@ -1942,7 +1955,10 @@ def _pp_lines_output_3ph(self):
19421955
pp_output_lines_3ph["loading_c_percent"] = (
19431956
np.maximum(pp_output_lines_3ph["i_c_from_ka"], pp_output_lines_3ph["i_c_to_ka"]) / pgm_input_lines["i_n"]
19441957
) * 1e5
1945-
pp_output_lines_3ph["loading_percent"] = pgm_output_lines["loading"] * 1e2
1958+
pp_output_lines_3ph["loading_percent"] = np.maximum(
1959+
np.maximum(pp_output_lines_3ph["loading_a_percent"], pp_output_lines_3ph["loading_b_percent"]),
1960+
pp_output_lines_3ph["loading_c_percent"],
1961+
)
19461962

19471963
assert "res_line_3ph" not in self.pp_output_data
19481964
self.pp_output_data["res_line_3ph"] = pp_output_lines_3ph
@@ -2017,38 +2033,29 @@ def _pp_trafos_output_3ph(self): # pylint: disable=too-many-statements
20172033
# Only derating factor used here. Sn is already being multiplied by parallel
20182034
loading_multiplier = pp_input_transformers["df"] * 1e2
20192035
if self.trafo_loading == "current":
2020-
ui_from = pgm_output_transformers["i_from"] * pgm_input_transformers["u1"]
2021-
ui_to = pgm_output_transformers["i_to"] * pgm_input_transformers["u2"]
2022-
loading_a_percent = np.maximum(ui_from[:, 0], ui_to[:, 0]) / pgm_input_transformers["sn"]
2023-
loading_b_percent = np.maximum(ui_from[:, 1], ui_to[:, 1]) / pgm_input_transformers["sn"]
2024-
loading_c_percent = np.maximum(ui_from[:, 2], ui_to[:, 2]) / pgm_input_transformers["sn"]
2025-
loading = np.maximum(np.sum(ui_from, axis=1), np.sum(ui_to, axis=1)) / pgm_input_transformers["sn"]
2036+
ui_from = pgm_output_transformers["i_from"] * pgm_input_transformers["u1"][:, None]
2037+
ui_to = pgm_output_transformers["i_to"] * pgm_input_transformers["u2"][:, None]
2038+
loading_a_percent = np.sqrt(3) * np.maximum(ui_from[:, 0], ui_to[:, 0]) / pgm_input_transformers["sn"]
2039+
loading_b_percent = np.sqrt(3) * np.maximum(ui_from[:, 1], ui_to[:, 1]) / pgm_input_transformers["sn"]
2040+
loading_c_percent = np.sqrt(3) * np.maximum(ui_from[:, 2], ui_to[:, 2]) / pgm_input_transformers["sn"]
20262041
elif self.trafo_loading == "power":
2027-
loading_a_percent = (
2028-
np.maximum(
2029-
pgm_output_transformers["s_from"][:, 0],
2030-
pgm_output_transformers["s_to"][:, 0],
2031-
)
2032-
/ pgm_output_transformers["s_n"]
2033-
)
2034-
loading_b_percent = (
2035-
np.maximum(
2036-
pgm_output_transformers["s_from"][:, 1],
2037-
pgm_output_transformers["s_to"][:, 1],
2038-
)
2039-
/ pgm_output_transformers["s_n"]
2040-
)
2041-
loading_c_percent = (
2042-
np.maximum(
2043-
pgm_output_transformers["s_from"][:, 2],
2044-
pgm_output_transformers["s_to"][:, 2],
2045-
)
2046-
/ pgm_output_transformers["s_n"]
2047-
)
2048-
loading = pgm_output_transformers["loading"]
2042+
loading_a_percent = np.maximum(
2043+
pgm_output_transformers["s_from"][:, 0],
2044+
pgm_output_transformers["s_to"][:, 0],
2045+
) / (pgm_input_transformers["sn"] / 3)
2046+
loading_b_percent = np.maximum(
2047+
pgm_output_transformers["s_from"][:, 1],
2048+
pgm_output_transformers["s_to"][:, 1],
2049+
) / (pgm_input_transformers["sn"] / 3)
2050+
loading_c_percent = np.maximum(
2051+
pgm_output_transformers["s_from"][:, 2],
2052+
pgm_output_transformers["s_to"][:, 2],
2053+
) / (pgm_input_transformers["sn"] / 3)
20492054
else:
20502055
raise ValueError(f"Invalid transformer loading type: {str(self.trafo_loading)}")
20512056

2057+
loading = np.maximum(np.maximum(loading_a_percent, loading_b_percent), loading_c_percent)
2058+
20522059
pp_output_trafos_3ph = pd.DataFrame(
20532060
columns=[
20542061
"p_a_hv_mw",

0 commit comments

Comments
 (0)