From a6f42a90a9282608d59a472b3209042c1e2b43c7 Mon Sep 17 00:00:00 2001 From: mvogt Date: Mon, 4 Sep 2023 13:45:20 +0200 Subject: [PATCH 1/6] fix which repairs set_line_geodata if the net doesn't have geodata for every bus. --- pandapower/plotting/plotting_toolbox.py | 39 +++++++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/pandapower/plotting/plotting_toolbox.py b/pandapower/plotting/plotting_toolbox.py index 4fa31e790..62aac15d2 100644 --- a/pandapower/plotting/plotting_toolbox.py +++ b/pandapower/plotting/plotting_toolbox.py @@ -124,7 +124,7 @@ def get_index_array(indices, net_table_indices): def coords_from_node_geodata(element_indices, from_nodes, to_nodes, node_geodata, table_name, - node_name="Bus", ignore_zero_length=True): + node_name="Bus", ignore_zero_length=True, replace_missing_coords=False): """ Auxiliary function to get the node coordinates for a number of branches with respective from and to nodes. The branch elements for which there is no geodata available are not included in @@ -144,6 +144,7 @@ def coords_from_node_geodata(element_indices, from_nodes, to_nodes, node_geodata :type node_name: str, default "Bus" :param ignore_zero_length: States if branches should be left out, if their length is zero, i.e.\ from_node_coords = to_node_coords + :param replace_missing_coords: States when no coords are available, they will be replaced with the geometric mean :type ignore_zero_length: bool, default True :return: Return values are:\ - coords (list) - list of branch coordinates of shape (N, (2, 2))\ @@ -154,18 +155,41 @@ def coords_from_node_geodata(element_indices, from_nodes, to_nodes, node_geodata & np.isin(to_nodes, node_geodata.index.values) elements_with_geo = np.array(element_indices)[have_geo] fb_with_geo, tb_with_geo = from_nodes[have_geo], to_nodes[have_geo] + elements_without_geo = set(element_indices) - set(elements_with_geo) + + if replace_missing_coords: + a = np.log(node_geodata.loc[fb_with_geo, ["x"]]) + b = np.log(node_geodata.loc[fb_with_geo, ["y"]]) + replacement_x = np.exp(a.mean()).values[0] + replacement_y = np.exp(b.mean()).values[0] + max_i = max(max(from_nodes), max(to_nodes)) + 1 + + ng = pd.DataFrame(index=range(max_i), columns=node_geodata.columns) + ng.loc[from_nodes[have_geo]] = node_geodata.loc[from_nodes[have_geo]] + ng.loc[to_nodes[have_geo]] = node_geodata.loc[to_nodes[have_geo]] + ng['x'] = ng['x'].fillna(replacement_x) + ng['y'] = ng['y'].fillna(replacement_y) + + fb_with_geo = from_nodes + tb_with_geo = to_nodes + + logger.warning("Replacing coords for %s" % (len(elements_without_geo))) + elements_with_geo = np.array(element_indices) + else: + ng = node_geodata + coords = [[(x_from, y_from), (x_to, y_to)] for x_from, y_from, x_to, y_to - in np.concatenate([node_geodata.loc[fb_with_geo, ["x", "y"]].values, - node_geodata.loc[tb_with_geo, ["x", "y"]].values], axis=1) + in np.concatenate([ng.loc[fb_with_geo, ["x", "y"]].values, + ng.loc[tb_with_geo, ["x", "y"]].values], axis=1) if not ignore_zero_length or not (x_from == x_to and y_from == y_to)] - elements_without_geo = set(element_indices) - set(elements_with_geo) + if len(elements_without_geo) > 0: logger.warning("No coords found for %s %s. %s geodata is missing for those %s!" % (table_name + "s", elements_without_geo, node_name, table_name + "s")) return coords, elements_with_geo -def set_line_geodata_from_bus_geodata(net, line_index=None, overwrite=False): +def set_line_geodata_from_bus_geodata(net, line_index=None, overwrite=False, replace_missing_coords=False, ignore_zero_length=True): """ Sets coordinates in net.line_geodata based on the from_bus and to_bus x,y coordinates in net.bus_geodata @@ -182,7 +206,10 @@ def set_line_geodata_from_bus_geodata(net, line_index=None, overwrite=False): from_nodes=net.line.loc[line_index, 'from_bus'].values, to_nodes=net.line.loc[line_index, 'to_bus'].values, node_geodata=net.bus_geodata, - table_name="line_geodata", node_name="bus_geodata") + table_name="line_geodata", + node_name="bus_geodata", + replace_missing_coords=replace_missing_coords, + ignore_zero_length=ignore_zero_length) net.line_geodata = net.line_geodata.reindex(net.line.index) net.line_geodata.loc[line_index_successful, 'coords'] = coords From f13d9bf9c84411cfc1811b10813f8e409c6a3e8b Mon Sep 17 00:00:00 2001 From: hkoertge Date: Wed, 11 Oct 2023 15:32:50 +0200 Subject: [PATCH 2/6] added line to CHANGELOG.rst --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8090b0ecd..13f5237ae 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -28,6 +28,7 @@ Change Log - [FIXED] powerfactory2pandapower-converter error if a line has two identical coordinates - [ADDED] logger messages about the probabilistic load flow calculation (simultaneities) in the powerfactory2pandapower-converter for low voltage loads - [ADDED] matplotlib v3.8.0 support (fixed :code:`plotting_colormaps.ipynb`) +- [FIXED] bug in plotting_toolbox.py (fixed :code:`coords_from_node_geodata` and :code:`set_line_geodata_from_bus_geodata`) [2.13.1] - 2023-05-12 From 75501cc4c1a219ef8c134c0c1fe3bfb8c4947624 Mon Sep 17 00:00:00 2001 From: hkoertge Date: Thu, 12 Oct 2023 09:19:29 +0200 Subject: [PATCH 3/6] fixed issue in coords_from_node_geodata. ignore_zero_length lead to assignment error in set_line_geodata_from_bus_geodata. --- pandapower/plotting/plotting_toolbox.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pandapower/plotting/plotting_toolbox.py b/pandapower/plotting/plotting_toolbox.py index 62aac15d2..7dade9a37 100644 --- a/pandapower/plotting/plotting_toolbox.py +++ b/pandapower/plotting/plotting_toolbox.py @@ -178,15 +178,18 @@ def coords_from_node_geodata(element_indices, from_nodes, to_nodes, node_geodata else: ng = node_geodata - coords = [[(x_from, y_from), (x_to, y_to)] for x_from, y_from, x_to, y_to - in np.concatenate([ng.loc[fb_with_geo, ["x", "y"]].values, - ng.loc[tb_with_geo, ["x", "y"]].values], axis=1) - if not ignore_zero_length or not (x_from == x_to and y_from == y_to)] + coordinates = np.concatenate([ng.loc[fb_with_geo, ["x", "y"]].values, ng.loc[tb_with_geo, ["x", "y"]].values], axis=1) + zero_length = [(not ignore_zero_length or not (x_from == x_to and y_from == y_to)) + for x_from, y_from, x_to, y_to in coordinates] + coordinates = coordinates[zero_length] + coords = [[(x_from, y_from), (x_to, y_to)] for x_from, y_from, x_to, y_to in coordinates] if len(elements_without_geo) > 0: logger.warning("No coords found for %s %s. %s geodata is missing for those %s!" % (table_name + "s", elements_without_geo, node_name, table_name + "s")) - return coords, elements_with_geo + if not all(zero_length): + logger.warning(f"Skipping zero length {table_name}s {elements_with_geo[[not b for b in zero_length]]}.") + return coords, elements_with_geo[zero_length] def set_line_geodata_from_bus_geodata(net, line_index=None, overwrite=False, replace_missing_coords=False, ignore_zero_length=True): @@ -198,7 +201,8 @@ def set_line_geodata_from_bus_geodata(net, line_index=None, overwrite=False, rep :param overwrite: whether the existing coordinates in net.line_geodata must be overwritten :return: None """ - line_index = line_index if line_index is not None else net.line.index + if not line_index: + line_index = net.line.index if not overwrite: line_index = np.setdiff1d(line_index, net.line_geodata.index) @@ -213,6 +217,7 @@ def set_line_geodata_from_bus_geodata(net, line_index=None, overwrite=False, rep net.line_geodata = net.line_geodata.reindex(net.line.index) net.line_geodata.loc[line_index_successful, 'coords'] = coords + net.line_geodata.dropna(inplace=True) # drop lines without coords num_failed = len(line_index) - len(line_index_successful) if num_failed > 0: From 4c86a1336e37ba23fa83685d24725f19a43da748 Mon Sep 17 00:00:00 2001 From: Steffen Meinecke Date: Wed, 5 Jun 2024 17:45:53 +0200 Subject: [PATCH 4/6] tiny fix --- pandapower/plotting/collections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandapower/plotting/collections.py b/pandapower/plotting/collections.py index 13609b569..095791338 100644 --- a/pandapower/plotting/collections.py +++ b/pandapower/plotting/collections.py @@ -499,7 +499,7 @@ def _get_coords_from_geojson(gj_str): return None if use_bus_geodata is False and line_geodata is None and ( - "geo" not in net.line.columns or net.line.geo.empty): + "geo" not in net.line.columns or net.line.geo.isnul().all()): # if bus geodata is available, but no line geodata logger.warning("use_bus_geodata is automatically set to True, since net.line.geo is empty.") use_bus_geodata = True From eaacef8318aeb83e7dc07124cecc84c055947cda Mon Sep 17 00:00:00 2001 From: Steffen Meinecke Date: Tue, 11 Jun 2024 14:22:34 +0200 Subject: [PATCH 5/6] fix missing l in isnull() --- pandapower/plotting/collections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandapower/plotting/collections.py b/pandapower/plotting/collections.py index 710617fae..59ab8ecac 100644 --- a/pandapower/plotting/collections.py +++ b/pandapower/plotting/collections.py @@ -499,7 +499,7 @@ def _get_coords_from_geojson(gj_str): return None if use_bus_geodata is False and line_geodata is None and ( - "geo" not in net.line.columns or net.line.geo.isnul().all()): + "geo" not in net.line.columns or net.line.geo.isnull().all()): # if bus geodata is available, but no line geodata logger.warning("use_bus_geodata is automatically set to True, since net.line.geo is empty.") use_bus_geodata = True From 9d3429ced033a717f071ba68a6f083d874d34450 Mon Sep 17 00:00:00 2001 From: Steffen Meinecke Date: Tue, 11 Jun 2024 14:22:45 +0200 Subject: [PATCH 6/6] avoid pandas FutureWarnings --- pandapower/test/shortcircuit/test_gen.py | 8 ++++---- pandapower/test/shortcircuit/test_iec60909_4.py | 12 ++++++------ .../test/shortcircuit/test_meshing_detection.py | 2 +- pandapower/test/toolbox/test_comparison.py | 8 ++++---- .../test/toolbox/test_grid_modification.py | 16 ++++++++-------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pandapower/test/shortcircuit/test_gen.py b/pandapower/test/shortcircuit/test_gen.py index 37809375e..01dae4855 100644 --- a/pandapower/test/shortcircuit/test_gen.py +++ b/pandapower/test/shortcircuit/test_gen.py @@ -3,7 +3,7 @@ # Copyright (c) 2016-2024 by University of Kassel and Fraunhofer Institute for Energy Economics # and Energy System Technology (IEE), Kassel. All rights reserved. - +import copy import pandas as pd import pytest @@ -85,15 +85,15 @@ def test_gen_ext_grid_same_bus(): net = pp.create_empty_network() b = pp.create_bus(net, 110) - net1 = net.deepcopy() + net1 = copy.deepcopy(net) pp.create_ext_grid(net1, b, s_sc_max_mva=1000, rx_max=0.4) sc.calc_sc(net1) - net2 = net.deepcopy() + net2 = copy.deepcopy(net) pp.create_gen(net2, b, 0, sn_mva=50, vn_kv=115, xdss_pu=0.2, rdss_ohm=20, cos_phi=0.8, pg_percent=0) sc.calc_sc(net2) - net3 = net1.deepcopy() + net3 = copy.deepcopy(net1) pp.create_gen(net3, b, 0, sn_mva=50, vn_kv=115, xdss_pu=0.2, rdss_ohm=20, cos_phi=0.8, pg_percent=0) sc.calc_sc(net3) diff --git a/pandapower/test/shortcircuit/test_iec60909_4.py b/pandapower/test/shortcircuit/test_iec60909_4.py index 843913c93..c32d3861b 100644 --- a/pandapower/test/shortcircuit/test_iec60909_4.py +++ b/pandapower/test/shortcircuit/test_iec60909_4.py @@ -327,10 +327,10 @@ def test_iec_60909_4_3ph_small_with_gen(): def test_iec_60909_4_3ph_small_with_gen_xward(): net = iec_60909_4_small(with_xward=True) sc.calc_sc(net, fault="3ph", case="max", ip=True, tk_s=0.1, kappa_method="C") - + ikss_pf = [40.6422, 31.6394, 16.7409, 33.2808] assert np.allclose(net.res_bus_sc.ikss_ka.values[:4], np.array(ikss_pf), atol=1e-3) - + def test_iec_60909_4_3ph_small_gen_only(): net = iec_60909_4_small_gen_only() @@ -364,7 +364,7 @@ def test_iec_60909_4_3ph_2gen_no_ps_detection(): net.gen.at[0, "in_service"] = False net.gen = net.gen.query("in_service") sc.calc_sc(net, fault="3ph", case="max", ip=True, tk_s=0.1, kappa_method="C") - + ikss_pf = [1.8460, 1.6715, 6.8953, 39.5042] assert np.allclose(net.res_bus_sc.ikss_ka[:4].values, np.array(ikss_pf), atol=1e-3) @@ -463,11 +463,11 @@ def test_iec_60909_4_1ph(): def test_detect_power_station_units(): net = iec_60909_4() - net.gen.power_station_trafo[:] = None + net.gen.power_station_trafo.loc[:] = None detect_power_station_unit(net) assert np.all(net.gen.power_station_trafo.values[[0, 1]] == np.array([0, 1])) - net.gen.power_station_trafo[:] = None + net.gen.power_station_trafo.loc[:] = None detect_power_station_unit(net, mode="trafo") assert np.all(net.gen.power_station_trafo.values[[0, 1]] == np.array([0, 1])) @@ -483,7 +483,7 @@ def test_vde_232(): net = vde_232() sc.calc_sc(net, fault="3ph", case="max", ip=True, tk_s=0.1, kappa_method="C") - + if __name__ == '__main__': pytest.main([__file__, "-xs"]) diff --git a/pandapower/test/shortcircuit/test_meshing_detection.py b/pandapower/test/shortcircuit/test_meshing_detection.py index e017391a8..1b50cf856 100644 --- a/pandapower/test/shortcircuit/test_meshing_detection.py +++ b/pandapower/test/shortcircuit/test_meshing_detection.py @@ -17,7 +17,7 @@ def meshed_grid(): net = pp.from_json(os.path.join(pp.pp_dir, "test", "shortcircuit", "sc_test_meshed_grid.json")) bid = pp.create_bus(net, vn_kv=10.) pp.create_switch(net, net.ext_grid.bus.iloc[0], bid, et="b") - net.ext_grid.bus.iloc[0] = bid + net.ext_grid.loc[net.ext_grid.index[0], "bus"] = bid pp.create_bus(net, vn_kv=0.4, in_service=False) return net diff --git a/pandapower/test/toolbox/test_comparison.py b/pandapower/test/toolbox/test_comparison.py index d412ff826..f4a7b4a37 100644 --- a/pandapower/test/toolbox/test_comparison.py +++ b/pandapower/test/toolbox/test_comparison.py @@ -34,7 +34,7 @@ def test_nets_equal(): net = copy.deepcopy(original) # detecting alternated value - net["load"]["p_mw"][net["load"].index[0]] += 0.1 + net["load"].loc[net["load"].index[0], "p_mw"] += 0.1 assert not pandapower.toolbox.nets_equal(original, net) assert not pandapower.toolbox.nets_equal(net, original) net = copy.deepcopy(original) @@ -46,14 +46,14 @@ def test_nets_equal(): net = copy.deepcopy(original) # not detecting alternated value if difference is beyond tolerance - net["load"]["p_mw"][net["load"].index[0]] += 0.0001 + net["load"].loc[net["load"].index[0], "p_mw"] += 0.0001 assert pandapower.toolbox.nets_equal(original, net, atol=0.1) assert pandapower.toolbox.nets_equal(net, original, atol=0.1) # check controllers original.trafo.tap_side = original.trafo.tap_side.fillna("hv") - net1 = original.deepcopy() - net2 = original.deepcopy() + net1 = copy.deepcopy(original) + net2 = copy.deepcopy(original) pp.control.ContinuousTapControl(net1, 0, 1.0) pp.control.ContinuousTapControl(net2, 0, 1.0) c1 = net1.controller.at[0, "object"] diff --git a/pandapower/test/toolbox/test_grid_modification.py b/pandapower/test/toolbox/test_grid_modification.py index 216e99c3b..7c5a09255 100644 --- a/pandapower/test/toolbox/test_grid_modification.py +++ b/pandapower/test/toolbox/test_grid_modification.py @@ -847,8 +847,8 @@ def test_repl_to_line_with_switch(): pp.create_switch(net, bus=bus, element=REPL, closed=False, et="l", type="LBS") # calculate runpp with REPL - net.line.in_service[testindex] = False - net.line.in_service[REPL] = True + net.line.in_service.loc[testindex] = False + net.line.in_service.loc[REPL] = True pp.runpp(net) fbus_repl = net.res_bus.loc[fbus] @@ -860,9 +860,9 @@ def test_repl_to_line_with_switch(): # get ne line impedances new_idx = pp.repl_to_line(net, testindex, std, in_service=True) # activate new idx line - net.line.in_service[REPL] = False - net.line.in_service[testindex] = True - net.line.in_service[new_idx] = True + net.line.in_service.loc[REPL] = False + net.line.in_service.loc[testindex] = True + net.line.in_service.loc[new_idx] = True pp.runpp(net) # compare lf results fbus_ne = net.res_bus.loc[fbus] @@ -880,9 +880,9 @@ def test_repl_to_line_with_switch(): assert np.isclose(qloss_repl, qloss_ne) # and reset to unreinforced state again - net.line.in_service[testindex] = True - net.line.in_service[new_idx] = False - net.line.in_service[REPL] = False + net.line.in_service.loc[testindex] = True + net.line.in_service.loc[new_idx] = False + net.line.in_service.loc[REPL] = False def test_merge_parallel_line():