A power flow calculation on a pandapower network can fail to converge (or fail to run at all) for a vast variety of reasons, which often makes debugging difficult, annoying and time consuming. To help with that, the diagnostic function automatically checks pandapower networks for the most common issues leading to errors. It provides logging output and diagnoses with a controllable level of detail.
To demonstrate the usage of the diagnostic function we will use a very basic exemplary pandapower network with several flaws.
There will be no further explenation on how to create pandapower networks since there's a separate tutorial available in this regard.
# imports the pandapower module
import pandapower as pp
# defines a function that creates an example network, which will be used a lot in this tutorial
# run this code first in order for the examples to work
def faulty_example_network():
net = pp.create_empty_network()
pp.create_bus(net, name = "110 kV bar", vn_kv = 110, type = 'b', in_service = 'True')
pp.create_bus(net, name = "20 kV bar", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 2", vn_kv = 30, type = 'b')
pp.create_bus(net, name = "bus 3", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 4", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 5", vn_kv = -20, type = 'b')
pp.create_bus(net, name = "bus 6", vn_kv = 20, type = 'b')
pp.create_ext_grid(net, 0, vm_pu = 1)
pp.create_line(net, name = "line 0", from_bus = 1, to_bus = 2, length_km = 0, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 1", from_bus = 2, to_bus = 3, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 2", from_bus = 3, to_bus = 4, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 3", from_bus = 4, to_bus = 5, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 4", from_bus = 5, to_bus = 6, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 5", from_bus = 6, to_bus = 1, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_transformer_from_parameters(net, hv_bus = 1, lv_bus = 0, i0_percent= 0.038, pfe_kw = 11.6,
vscr_percent = 0.322, sn_kva = 40000.0, vn_lv_kv = 22.0,
vn_hv_kv = 110.0, vsc_percent = 17.8)
pp.create_load(net, 2, p_kw = -1000, q_kvar = 200, name = "load 0")
pp.create_load(net, 3, p_kw = 1000, q_kvar = 200, name = "load 1")
pp.create_load(net, 4, p_kw = 1000, q_kvar = 200, name = "load 2")
pp.create_load(net, 5, p_kw = 1000, q_kvar = 200, name = "load 3")
pp.create_load(net, 6, p_kw = 1000, q_kvar = 200, name = "load 4")
pp.create_switch(net, bus = 1, element = 0, et = 'l')
pp.create_switch(net, bus = 2, element = 0, et = 'l')
pp.create_switch(net, bus = 2, element = 1, et = 'l')
pp.create_switch(net, bus = 3, element = 1, et = 'l')
pp.create_switch(net, bus = 3, element = 2, et = 'l')
pp.create_switch(net, bus = 4, element = 2, et = 'l')
pp.create_switch(net, bus = 4, element = 3, et = 'l', closed = 0)
pp.create_switch(net, bus = 5, element = 3, et = 'l')
pp.create_switch(net, bus = 5, element = 4, et = 'l', closed = 0)
pp.create_switch(net, bus = 6, element = 4, et = 'l', closed = 0)
pp.create_switch(net, bus = 6, element = 5, et = 'l')
pp.create_switch(net, bus = 1, element = 5, et = 'l')
return net
# creates the example network
faulty_net = faulty_example_network()
pp.runpp(faulty_net)
--------------------------------------------------------------------------- LoadflowNotConverged Traceback (most recent call last) <ipython-input-2-4b18200ac97b> in <module>() 1 # creates the example network 2 faulty_net = faulty_example_network() ----> 3 pp.runpp(faulty_net) D:\Python\pandapower\pandapower\run.py in runpp(net, init, calculate_voltage_angles, tolerance_kva, trafo_model, trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs) 94 95 _runpppf(net, init, ac, calculate_voltage_angles, tolerance_kva, trafo_model, ---> 96 trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs) 97 98 D:\Python\pandapower\pandapower\run.py in _runpppf(net, init, ac, calculate_voltage_angles, tolerance_kva, trafo_model, trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs) 178 # raise if PF was not successful. If DC -> success is always 1 179 if result["success"] != 1: --> 180 raise LoadflowNotConverged("Loadflow did not converge!") 181 else: 182 net["_ppc"] = result LoadflowNotConverged: Loadflow did not converge!
As you can see there is at least one error in our network that prevents the load flow calculation from running properly.
# diagnoses the faulty network
pp.diagnostic(faulty_net)
_____________ PANDAPOWER DIAGNOSTIC TOOL _____________ Checking for invalid_values... bus: Invalid value found: 'bus 5' with attribute 'vn_kv' = -20.0 (data type: <class 'numpy.float64'>). Valid input needs to be >0. line: Invalid value found: 'line 0' with attribute 'length_km' = 0.0 (data type: <class 'numpy.float64'>). Valid input needs to be >0. SUMMARY: 2 invalid values found. -------- Checking switch configuration... Power flow still does not converge with all switches closed. -------- Checking for lines with impedance close to zero... Line 0: length_km: 0.0, r_ohm_per_km: 0.208, x_ohm_per_km: 0.08. Impedance is close to zero. If a direct connection between two buses was intended, please use a bus-bus-switch instead. SUMMARY: 1 line(s) with impedance close to zero found. -------- Checking for components with deviating nominal voltages... Trafo(s) [0]: hv and lv connectors seem to be swapped SUMMARY: 1 components(s) with deviating nominal voltages found -------- Checking for elements without a connection to an external grid... Disconnected section found, consisting of the following elements: switches: [7, 8] buses: [5] lines: [3] loads: [3] Disconnected section found, consisting of the following elements: isolated_lines: [4] SUMMARY: 6 disconnected element(s) found. -------- Checking for usage of wrong reference system... Found load 0: 'load 0' with p_kw = -1000.0. In load reference system p_kw should be positive. SUMMARY: Found 1 load(s) with negative p_kw. In load reference system, p_kw should be positive. If the intention was to model a constant generation, please use an sgen instead. -------- Checking for overload... Overload check failed: Power flow still does not converge with load scaled down to 0.1 percent. Overload check failed: Power flow still does not converge with generation scaled down to 0.1 percent. -------- Checking for connections of different voltage levels... line 0 connects bus 1: 20 kV bar (vn_kv = 20.0) and bus 2: bus 2 (vn_kv = 30.0) line 1 connects bus 2: bus 2 (vn_kv = 30.0) and bus 3: bus 3 (vn_kv = 20.0) line 3 connects bus 4: bus 4 (vn_kv = 20.0) and bus 5: bus 5 (vn_kv = -20.0) line 4 connects bus 5: bus 5 (vn_kv = -20.0) and bus 6: bus 6 (vn_kv = 20.0) SUMMARY: 4 element(s) that connect different voltage levels found. -------- _____________ END OF PANDAPOWER DIAGNOSTIC _____________
{'different_voltage_levels_connected': {'lines': [0, 1, 3, 4]}, 'disconnected_elements': [{'buses': [5], 'lines': [3], 'loads': [3], 'switches': [7, 8]}, {'isolated_lines': [4]}], 'invalid_values': {'bus': [(5, 'vn_kv', -20.0, '>0')], 'line': [(0, 'length_km', 0.0, '>0')]}, 'lines_with_impedance_close_to_zero': [0], 'nominal_voltages_dont_match': {'trafo': {'hv_lv_swapped': [0]}}, 'overload': {'generation': 'uncertain', 'load': 'uncertain'}, 'wrong_reference_system': {'loads': [0]}, 'wrong_switch_configuration': 'uncertain'}
For a more compact report, there a two options that can be passed as arguments to the diagnostic function:
warnings_only = True : only positive check results (errors found) will be in the report
detailed_report = False: only error summaries, no detailed error descriptions
The default setting is:
diagnostic(net, warnings_only = False, detailed_report = True)
# report with warnings_only
pp.diagnostic(faulty_net, warnings_only = True)
_____________ PANDAPOWER DIAGNOSTIC TOOL _____________ Checking for invalid_values... bus: Invalid value found: 'bus 5' with attribute 'vn_kv' = -20.0 (data type: <class 'numpy.float64'>). Valid input needs to be >0. line: Invalid value found: 'line 0' with attribute 'length_km' = 0.0 (data type: <class 'numpy.float64'>). Valid input needs to be >0. SUMMARY: 2 invalid values found. -------- Checking switch configuration... Power flow still does not converge with all switches closed. -------- Checking for lines with impedance close to zero... Line 0: length_km: 0.0, r_ohm_per_km: 0.208, x_ohm_per_km: 0.08. Impedance is close to zero. If a direct connection between two buses was intended, please use a bus-bus-switch instead. SUMMARY: 1 line(s) with impedance close to zero found. -------- Checking for components with deviating nominal voltages... Trafo(s) [0]: hv and lv connectors seem to be swapped SUMMARY: 1 components(s) with deviating nominal voltages found -------- Checking for elements without a connection to an external grid... Disconnected section found, consisting of the following elements: switches: [7, 8] buses: [5] lines: [3] loads: [3] Disconnected section found, consisting of the following elements: isolated_lines: [4] SUMMARY: 6 disconnected element(s) found. -------- Checking for usage of wrong reference system... Found load 0: 'load 0' with p_kw = -1000.0. In load reference system p_kw should be positive. SUMMARY: Found 1 load(s) with negative p_kw. In load reference system, p_kw should be positive. If the intention was to model a constant generation, please use an sgen instead. -------- Checking for overload... Overload check failed: Power flow still does not converge with load scaled down to 0.1 percent. Overload check failed: Power flow still does not converge with generation scaled down to 0.1 percent. -------- Checking for connections of different voltage levels... line 0 connects bus 1: 20 kV bar (vn_kv = 20.0) and bus 2: bus 2 (vn_kv = 30.0) line 1 connects bus 2: bus 2 (vn_kv = 30.0) and bus 3: bus 3 (vn_kv = 20.0) line 3 connects bus 4: bus 4 (vn_kv = 20.0) and bus 5: bus 5 (vn_kv = -20.0) line 4 connects bus 5: bus 5 (vn_kv = -20.0) and bus 6: bus 6 (vn_kv = 20.0) SUMMARY: 4 element(s) that connect different voltage levels found. -------- _____________ END OF PANDAPOWER DIAGNOSTIC _____________
{'different_voltage_levels_connected': {'lines': [0, 1, 3, 4]}, 'disconnected_elements': [{'buses': [5], 'lines': [3], 'loads': [3], 'switches': [7, 8]}, {'isolated_lines': [4]}], 'invalid_values': {'bus': [(5, 'vn_kv', -20.0, '>0')], 'line': [(0, 'length_km', 0.0, '>0')]}, 'lines_with_impedance_close_to_zero': [0], 'nominal_voltages_dont_match': {'trafo': {'hv_lv_swapped': [0]}}, 'overload': {'generation': 'uncertain', 'load': 'uncertain'}, 'wrong_reference_system': {'loads': [0]}, 'wrong_switch_configuration': 'uncertain'}
# report with summaries only
pp.diagnostic(faulty_net, report_style="compact")
_____________ PANDAPOWER DIAGNOSTIC TOOL _____________ invalid_values: bus: bus 5: 'vn_kv' = -20.0 (restriction: >0) line: line 0: 'length_km' = 0.0 (restriction: >0) -------- wrong_switch_configuration: Power flow still does not converge with all switches closed. -------- lines_with_impedance_close_to_zero: line 0: length_km: 0.0; r_ohm_per_km: 0.208; x_ohm_per_km: 0.08 -------- nominal_voltages_dont_match: trafo: hv_lv_swapped: [0] -------- disconnected_elements: disonnected_section: {'switches': [7, 8], 'buses': [5], 'lines': [3], 'loads': [3]} disonnected_section: {'isolated_lines': [4]} -------- wrong_reference_system: loads [0]: wrong reference system. -------- overload: power flow still does not converge after load downscaling. power flow still does not converge after generation downscaling. -------- different_voltage_levels_connected: lines: line 0: buses [1, 2] line 1: buses [2, 3] line 3: buses [4, 5] line 4: buses [5, 6] -------- _____________ END OF PANDAPOWER DIAGNOSTIC _____________
{'different_voltage_levels_connected': {'lines': [0, 1, 3, 4]}, 'disconnected_elements': [{'buses': [5], 'lines': [3], 'loads': [3], 'switches': [7, 8]}, {'isolated_lines': [4]}], 'invalid_values': {'bus': [(5, 'vn_kv', -20.0, '>0')], 'line': [(0, 'length_km', 0.0, '>0')]}, 'lines_with_impedance_close_to_zero': [0], 'nominal_voltages_dont_match': {'trafo': {'hv_lv_swapped': [0]}}, 'overload': {'generation': 'uncertain', 'load': 'uncertain'}, 'wrong_reference_system': {'loads': [0]}, 'wrong_switch_configuration': 'uncertain'}
# diagnoses the faulty network
pp.diagnostic(faulty_net)
_____________ PANDAPOWER DIAGNOSTIC TOOL _____________ Checking for invalid_values... bus: Invalid value found: 'bus 5' with attribute 'vn_kv' = -20.0 (data type: <class 'numpy.float64'>). Valid input needs to be >0. line: Invalid value found: 'line 0' with attribute 'length_km' = 0.0 (data type: <class 'numpy.float64'>). Valid input needs to be >0. SUMMARY: 2 invalid values found. -------- Checking switch configuration... Power flow still does not converge with all switches closed. -------- Checking for lines with impedance close to zero... Line 0: length_km: 0.0, r_ohm_per_km: 0.208, x_ohm_per_km: 0.08. Impedance is close to zero. If a direct connection between two buses was intended, please use a bus-bus-switch instead. SUMMARY: 1 line(s) with impedance close to zero found. -------- Checking for components with deviating nominal voltages... Trafo(s) [0]: hv and lv connectors seem to be swapped SUMMARY: 1 components(s) with deviating nominal voltages found -------- Checking for elements without a connection to an external grid... Disconnected section found, consisting of the following elements: switches: [7, 8] buses: [5] lines: [3] loads: [3] Disconnected section found, consisting of the following elements: isolated_lines: [4] SUMMARY: 6 disconnected element(s) found. -------- Checking for usage of wrong reference system... Found load 0: 'load 0' with p_kw = -1000.0. In load reference system p_kw should be positive. SUMMARY: Found 1 load(s) with negative p_kw. In load reference system, p_kw should be positive. If the intention was to model a constant generation, please use an sgen instead. -------- Checking for overload... Overload check failed: Power flow still does not converge with load scaled down to 0.1 percent. Overload check failed: Power flow still does not converge with generation scaled down to 0.1 percent. -------- Checking for connections of different voltage levels... line 0 connects bus 1: 20 kV bar (vn_kv = 20.0) and bus 2: bus 2 (vn_kv = 30.0) line 1 connects bus 2: bus 2 (vn_kv = 30.0) and bus 3: bus 3 (vn_kv = 20.0) line 3 connects bus 4: bus 4 (vn_kv = 20.0) and bus 5: bus 5 (vn_kv = -20.0) line 4 connects bus 5: bus 5 (vn_kv = -20.0) and bus 6: bus 6 (vn_kv = 20.0) SUMMARY: 4 element(s) that connect different voltage levels found. -------- _____________ END OF PANDAPOWER DIAGNOSTIC _____________
{'different_voltage_levels_connected': {'lines': [0, 1, 3, 4]}, 'disconnected_elements': [{'buses': [5], 'lines': [3], 'loads': [3], 'switches': [7, 8]}, {'isolated_lines': [4]}], 'invalid_values': {'bus': [(5, 'vn_kv', -20.0, '>0')], 'line': [(0, 'length_km', 0.0, '>0')]}, 'lines_with_impedance_close_to_zero': [0], 'nominal_voltages_dont_match': {'trafo': {'hv_lv_swapped': [0]}}, 'overload': {'generation': 'uncertain', 'load': 'uncertain'}, 'wrong_reference_system': {'loads': [0]}, 'wrong_switch_configuration': 'uncertain'}
Bus 5, lines 3, 4 and load 3 are isolated by open switches. To fix that, we close switches 8 and 9.
faulty_net.switch.closed.loc[8, 9] = 1
Lines 0, 1, 3 and 4 connect different voltage levels. Apparently bus 2 (30 kV) and bus 5 (-20 kV) have wrong voltage levels values. We change that to 20 kV.
faulty_net.bus.vn_kv.loc[2, 5] = 20
Line 0 is 0 km long (and therefore its impedance is 0 ohm). We change the length to 1 km.
faulty_net.line.length_km.at[0] = 1
We fix that by swapping the hv and lv connectors of trafo 0 back.
faulty_net.trafo.hv_bus.at[0] = 0
faulty_net.trafo.lv_bus.at[0] = 1
The value for the attribute 'in_service' of bus 0 is a string although it is supposed to be a boolean. We fix that.
faulty_net.bus.in_service.at[0] = True
Load 0 has a p_kw value of -1000. Since pandapower uses the load reference system, the value should either be positive or an sgen should be used. We assume the former and change the value to 1000.
faulty_net.load.p_kw.at[0] = 1000
# new diagnosis to check, whether we fixed all errors
pp.diagnostic(faulty_net)
_____________ PANDAPOWER DIAGNOSTIC TOOL _____________ _____________ END OF PANDAPOWER DIAGNOSTIC _____________
{}
Apparently, all errors have been fixed. So we can try again to run a loadflow calculation.
pp.runpp(faulty_net)
faulty_net
This pandapower network includes the following parameter tables: - bus (7 elements) - load (5 elements) - ext_grid (1 elements) - switch (12 elements) - trafo (1 elements) - line (6 elements) and the following results tables: - res_bus (7 elements) - res_trafo (1 elements) - res_load (5 elements) - res_ext_grid (1 elements) - res_line (6 elements)
Now the loadflow calculation runs without problems.
Other errors the diagnostic function can help to identify, are networks with too much load or wrong switch configurations. The function automatically checks, if the loadflow converges with all loads and generation scaled down to 0.1% or with all switches closed.
# imports the pandapower module
import pandapower as pp
# defines a function that creates an example network
# run this code first in order for the examples to work
def overload_example_network():
net = pp.create_empty_network()
pp.create_bus(net, name = "110 kV bar", vn_kv = 110, type = 'b')
pp.create_bus(net, name = "20 kV bar", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 2", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 3", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 4", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 5", vn_kv = 20, type = 'b')
pp.create_bus(net, name = "bus 6", vn_kv = 20, type = 'b')
pp.create_ext_grid(net, 0, vm_pu = 1)
pp.create_line(net, name = "line 0", from_bus = 1, to_bus = 2, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 1", from_bus = 2, to_bus = 3, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 2", from_bus = 3, to_bus = 4, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 3", from_bus = 4, to_bus = 5, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 4", from_bus = 5, to_bus = 6, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_line(net, name = "line 5", from_bus = 6, to_bus = 1, length_km = 1, std_type = "NAYY 4x150 SE")
pp.create_transformer_from_parameters(net, hv_bus = 0, lv_bus = 1, i0_percent= 0.038, pfe_kw = 11.6,
vscr_percent = 0.322, sn_kva = 40000.0, vn_lv_kv = 22.0,
vn_hv_kv = 110.0, vsc_percent = 17.8)
pp.create_load(net, 2, p_kw = 100000, q_kvar = 200, name = "load 0")
pp.create_load(net, 3, p_kw = 100000, q_kvar = 200, name = "load 1")
pp.create_load(net, 4, p_kw = 100000, q_kvar = 200, name = "load 2")
pp.create_load(net, 5, p_kw = 100000, q_kvar = 200, name = "load 3")
pp.create_load(net, 6, p_kw = 100000, q_kvar = 200, name = "load 4")
pp.create_switch(net, bus = 1, element = 0, et = 'l')
pp.create_switch(net, bus = 2, element = 0, et = 'l')
pp.create_switch(net, bus = 2, element = 1, et = 'l')
pp.create_switch(net, bus = 3, element = 1, et = 'l')
pp.create_switch(net, bus = 3, element = 2, et = 'l')
pp.create_switch(net, bus = 4, element = 2, et = 'l')
pp.create_switch(net, bus = 4, element = 3, et = 'l', closed = 0)
pp.create_switch(net, bus = 5, element = 3, et = 'l')
pp.create_switch(net, bus = 5, element = 4, et = 'l')
pp.create_switch(net, bus = 6, element = 4, et = 'l')
pp.create_switch(net, bus = 6, element = 5, et = 'l')
pp.create_switch(net, bus = 1, element = 5, et = 'l')
return net
overload_net = overload_example_network()
pp.runpp(overload_net)
--------------------------------------------------------------------------- LoadflowNotConverged Traceback (most recent call last) <ipython-input-16-82b187456412> in <module>() 1 overload_net = overload_example_network() ----> 2 pp.runpp(overload_net) D:\Python\pandapower\pandapower\run.py in runpp(net, init, calculate_voltage_angles, tolerance_kva, trafo_model, trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs) 94 95 _runpppf(net, init, ac, calculate_voltage_angles, tolerance_kva, trafo_model, ---> 96 trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs) 97 98 D:\Python\pandapower\pandapower\run.py in _runpppf(net, init, ac, calculate_voltage_angles, tolerance_kva, trafo_model, trafo_loading, enforce_q_lims, suppress_warnings, Numba, **kwargs) 178 # raise if PF was not successful. If DC -> success is always 1 179 if result["success"] != 1: --> 180 raise LoadflowNotConverged("Loadflow did not converge!") 181 else: 182 net["_ppc"] = result LoadflowNotConverged: Loadflow did not converge!
pp.diagnostic(overload_net, warnings_only = True)
_____________ PANDAPOWER DIAGNOSTIC TOOL _____________ Checking for overload... Possibly overload found: power flow converges with load scaled down to 0.1 percent. Overload check failed: Power flow still does not converge with generation scaled down to 0.1 percent. -------- Checking switch configuration... Power flow still does not converge with all switches closed. -------- _____________ END OF PANDAPOWER DIAGNOSTIC _____________
{'overload': {'generation': 'uncertain', 'load': True}, 'wrong_switch_configuration': 'uncertain'}
As you can see, with loads scaled down, the loadflow converges, which helps to isolate the problem.