def wrong_switch_configuration(net): """ Checks, if a loadflow calculation converges. If not, checks, if the switch configuration is the reason for that by closing all switches INPUT: **net** (PandapowerNet) - variable that contains a pandapower network RETURN: **check_result** (boolean) EXAMPLE: import misc misc.check_wrong_switch_configuration(net) """ switch_configuration = copy.deepcopy(net.switch.closed) try: runpp(net) except: try: net.switch.closed = 1 runpp(net) net.switch.closed = switch_configuration return True except: net.switch.closed = switch_configuration return 'uncertain'
def impedance_values_close_to_zero(net, min_r_ohm, min_x_ohm, min_r_pu, min_x_pu): """ Checks, if there are lines, xwards or impedances with an impedance value close to zero. INPUT: **net** (pandapowerNet) - pandapower network OUTPUT: **implausible_lines** (list) - list that contains the indices of all lines with an impedance value of zero. """ check_results = [] implausible_elements = {} line = net.line[((net.line.r_ohm_per_km * net.line.length_km) <= min_r_ohm) | ((net.line.x_ohm_per_km * net.line.length_km) <= min_x_ohm) & net.line.in_service].index xward = net.xward[(net.xward.r_ohm <= min_r_ohm) | (net.xward.x_ohm <= min_x_ohm) & net.xward.in_service].index impedance = net.impedance[(net.impedance.rft_pu <= min_r_pu) | (net.impedance.xft_pu <= min_x_pu) | (net.impedance.rtf_pu <= min_r_pu) | (net.impedance.xtf_pu <= min_x_pu) & net.impedance.in_service].index if len(line) > 0: implausible_elements['line'] = list(line) if len(xward) > 0: implausible_elements['xward'] = list(xward) if len(impedance) > 0: implausible_elements['impedance'] = list(impedance) check_results.append(implausible_elements) # checks if loadflow converges when implausible lines or impedances are replaced by switches if ("line" in implausible_elements) or ("impedance" in implausible_elements): switch_copy = copy.deepcopy(net.switch) line_copy = copy.deepcopy(net.line) impedance_copy = copy.deepcopy(net.impedance) try: runpp(net) except: try: for key in implausible_elements: if key == 'xward': continue implausible_idx = implausible_elements[key] net[key].in_service.loc[implausible_idx] = False for idx in implausible_idx: pp.create_switch(net, net[key].from_bus.at[idx], net[key].to_bus.at[idx], et="b") runpp(net) switch_replacement = True except: switch_replacement = False check_results.append({"loadflow_converges_with_switch_replacement": switch_replacement}) net.switch = switch_copy net.line = line_copy net.impedance = impedance_copy if implausible_elements: return check_results
def wrong_switch_configuration(net): """ Checks, if a loadflow calculation converges. If not, checks, if the switch configuration is the reason for that by closing all switches INPUT: **net** (pandapowerNet) - pandapower network OUTPUT: **check_result** (boolean) """ switch_configuration = copy.deepcopy(net.switch.closed) try: runpp(net) except (ValueError, LoadflowNotConverged): try: net.switch.closed = 1 runpp(net) net.switch.closed = switch_configuration return True except LoadflowNotConverged: net.switch.closed = switch_configuration return 'uncertain'
def numba_comparison(net, numba_tolerance): """ Compares the results of loadflows with numba=True vs. numba=False. INPUT: **net** (pandapowerNet) - pandapower network OPTIONAL: **tol** (float, 1e-5) - Maximum absolute deviation allowed between numba=True/False results. OUTPUT: **check_result** (dict) - Absolute deviations between numba=True/False results. """ check_results = {} try: runpp(net, numba=True) except LoadflowNotConverged: pass if net.converged: try: result_numba_true = copy.deepcopy(net) runpp(net, numba=False) result_numba_false = copy.deepcopy(net) res_keys = [ key for key in result_numba_true.keys() if (key in [ 'res_bus', 'res_ext_grid', 'res_gen', 'res_impedance', 'res_line', 'res_load', 'res_sgen', 'res_shunt', 'res_trafo', 'res_trafo3w', 'res_ward', 'res_xward' ]) ] for key in res_keys: diffs = abs(result_numba_true[key] - result_numba_false[key]) > numba_tolerance if any(diffs.any()): if (key not in check_results.keys()): check_results[key] = {} for col in diffs.columns: if (col not in check_results[key].keys()) and ( diffs.any()[col]): check_results[key][col] = {} numba_true = result_numba_true[key][col][ diffs[col]] numba_false = result_numba_false[key][col][ diffs[col]] check_results[key][col] = abs(numba_true - numba_false) except LoadflowNotConverged: pass if check_results: return check_results
def overload(net, overload_scaling_factor): """ Checks, if a loadflow calculation converges. If not, checks, if an overload is the reason for that by scaling down the loads, gens and sgens to 0.1%. INPUT: **net** (pandapowerNet) - pandapower network OUTPUT: **check_results** (dict) - dict with the results of the overload check Format: {'load_overload': True/False 'generation_overload', True/False} """ check_result = {} load_scaling = copy.deepcopy(net.load.scaling) gen_scaling = copy.deepcopy(net.gen.scaling) sgen_scaling = copy.deepcopy(net.sgen.scaling) try: runpp(net) except LoadflowNotConverged: check_result['load'] = False check_result['generation'] = False try: net.load.scaling = overload_scaling_factor runpp(net) check_result['load'] = True except: net.load.scaling = load_scaling try: net.gen.scaling = overload_scaling_factor net.sgen.scaling = overload_scaling_factor runpp(net) check_result['generation'] = True except: net.sgen.scaling = sgen_scaling net.gen.scaling = gen_scaling try: net.load.scaling = overload_scaling_factor net.gen.scaling = overload_scaling_factor net.sgen.scaling = overload_scaling_factor runpp(net) check_result['generation'] = True check_result['load'] = True except: pass net.sgen.scaling = sgen_scaling net.gen.scaling = gen_scaling net.load.scaling = load_scaling if check_result: return check_result
def overload(net, overload_scaling_factor): """ Checks, if a loadflow calculation converges. If not, checks, if an overload is the reason for that by scaling down the loads, gens and sgens to 0.1%. INPUT: **net** (PandapowerNet) - variable that contains a pandapower network RETURN: **check_results** (dict) - dict with the results of the overload check Format: {'load_overload': True/False/uncertain 'generation_overload', True/False/uncertain} EXAMPLE: import misc misc.check_overload(net) """ check_result = {} load_scaling = copy.deepcopy(net.load.scaling) gen_scaling = copy.deepcopy(net.gen.scaling) sgen_scaling = copy.deepcopy(net.sgen.scaling) try: runpp(net) except: try: net.load.scaling = overload_scaling_factor runpp(net) net.load.scaling = load_scaling check_result['load'] = True except: net.load.scaling = load_scaling check_result['load'] = 'uncertain' try: net.gen.scaling = overload_scaling_factor net.sgen.scaling = overload_scaling_factor runpp(net) net.gen.scaling = gen_scaling net.gen.scaling = sgen_scaling check_result['generation'] = True except: net.gen.scaling = gen_scaling check_result['generation'] = 'uncertain' if check_result: return check_result
def pf_res_plotly(net, cmap="Jet", use_line_geodata=None, on_map=False, projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=2, bus_size=10, climits_volt=(0.9, 1.1), climits_load=(0, 100), cpos_volt=1.0, cpos_load=1.1, filename="temp-plot.html", auto_open=True): """ Plots a pandapower network in plotly using colormap for coloring lines according to line loading and buses according to voltage in p.u. If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial INPUT: **net** - The pandapower format network. If none is provided, mv_oberrhein() will be plotted as an example OPTIONAL: **respect_switches** (bool, False) - Respect switches when artificial geodata is created **cmap** (str, True) - name of the colormap **colors_dict** (dict, None) - by default 6 basic colors from default collor palette is used. Otherwise, user can define a dictionary in the form: voltage_kv : color **on_map** (bool, False) - enables using mapbox plot in plotly. If provided geodata are not real geo-coordinates in lon/lat form, on_map will be set to False. **projection** (String, None) - defines a projection from which network geo-data will be transformed to lat-long. For each projection a string can be found at http://spatialreference.org/ref/epsg/ **map_style** (str, 'basic') - enables using mapbox plot in plotly - 'streets' - 'bright' - 'light' - 'dark' - 'satellite' **figsize** (float, 1) - aspectratio is multiplied by it in order to get final image size **aspectratio** (tuple, 'auto') - when 'auto' it preserves original aspect ratio of the network geodata any custom aspectration can be given as a tuple, e.g. (1.2, 1) **line_width** (float, 1.0) - width of lines **bus_size** (float, 10.0) - size of buses to plot. **climits_volt** (tuple, (0.9, 1.0)) - limits of the colorbar for voltage **climits_load** (tuple, (0, 100)) - limits of the colorbar for line_loading **cpos_volt** (float, 1.0) - position of the bus voltage colorbar **cpos_load** (float, 1.1) - position of the loading percent colorbar **filename** (str, "temp-plot.html") - filename / path to plot to. Should end on `*.html` **auto_open** (bool, True) - automatically open plot in browser OUTPUT: **figure** (graph_objs._figure.Figure) figure object """ version_check() if 'res_bus' not in net or net.get('res_bus').shape[0] == 0: logger.warning('There are no Power Flow results. A Newton-Raphson power flow will be executed.') runpp(net) # create geocoord if none are available if 'line_geodata' not in net: net.line_geodata = pd.DataFrame(columns=['coords']) if 'bus_geodata' not in net: net.bus_geodata = pd.DataFrame(columns=["x", "y"]) if len(net.line_geodata) == 0 and len(net.bus_geodata) == 0: logger.warning("No or insufficient geodata available --> Creating artificial coordinates." + " This may take some time") create_generic_coordinates(net, respect_switches=True) if on_map: logger.warning("Map plots not available with artificial coordinates and will be disabled!") on_map = False for geo_type in ["bus_geodata", "line_geodata"]: dupl_geo_idx = pd.Series(net[geo_type].index)[pd.Series( net[geo_type].index).duplicated()] if len(dupl_geo_idx): if len(dupl_geo_idx) > 20: logger.warning("In net.%s are %i duplicated " % (geo_type, len(dupl_geo_idx)) + "indices. That can cause troubles for draw_traces()") else: logger.warning("In net.%s are the following duplicated " % geo_type + "indices. That can cause troubles for draw_traces(): " + str( dupl_geo_idx)) # check if geodata are real geographycal lat/lon coordinates using geopy if on_map and projection is not None: geo_data_to_latlong(net, projection=projection) # ----- Buses ------ # initializating bus trace # hoverinfo which contains name and pf results precision = 3 hoverinfo = ( net.bus.name.astype(str) + '<br />' + 'V_m = ' + net.res_bus.vm_pu.round(precision).astype(str) + ' pu' + '<br />' + 'V_m = ' + (net.res_bus.vm_pu * net.bus.vn_kv.round(2)).round(precision).astype(str) + ' kV' + '<br />' + 'V_a = ' + net.res_bus.va_degree.round(precision).astype(str) + ' deg').tolist() hoverinfo = pd.Series(index=net.bus.index, data=hoverinfo) bus_trace = create_bus_trace(net, net.bus.index, size=bus_size, infofunc=hoverinfo, cmap=cmap, cbar_title='Bus Voltage [pu]', cmin=climits_volt[0], cmax=climits_volt[1], cpos=cpos_volt) # ----- Lines ------ # if bus geodata is available, but no line geodata # if bus geodata is available, but no line geodata cmap_lines = 'jet' if cmap == 'Jet' else cmap if use_line_geodata is None: use_line_geodata = False if len(net.line_geodata) == 0 else True elif use_line_geodata and len(net.line_geodata) == 0: logger.warning("No or insufficient line geodata available --> only bus geodata will be used.") use_line_geodata = False # hoverinfo which contains name and pf results hoverinfo = ( net.line.name.astype(str) + '<br />' + 'I = ' + net.res_line.loading_percent.round(precision).astype(str) + ' %' + '<br />' + 'I_from = ' + net.res_line.i_from_ka.round(precision).astype(str) + ' kA' + '<br />' + 'I_to = ' + net.res_line.i_to_ka.round(precision).astype(str) + ' kA' + '<br />').tolist() hoverinfo = pd.Series(index=net.line.index, data=hoverinfo) line_traces = create_line_trace(net, use_line_geodata=use_line_geodata, respect_switches=True, width=line_width, infofunc=hoverinfo, cmap=cmap_lines, cmap_vals=net.res_line['loading_percent'].values, cmin=climits_load[0], cmax=climits_load[1], cbar_title='Line Loading [%]', cpos=cpos_load) # ----- Trafos ------ # hoverinfo which contains name and pf results hoverinfo = ( net.trafo.name.astype(str) + '<br />' + 'I = ' + net.res_trafo.loading_percent.round(precision).astype(str) + ' %' + '<br />' + 'I_hv = ' + net.res_trafo.i_hv_ka.round(precision).astype(str) + ' kA' + '<br />' + 'I_lv = ' + net.res_trafo.i_lv_ka.round(precision).astype(str) + ' kA' + '<br />').tolist() hoverinfo = pd.Series(index=net.trafo.index, data=hoverinfo) trafo_traces = create_trafo_trace(net, width=line_width * 1.5, infofunc=hoverinfo, cmap=cmap_lines, cmin=0, cmax=100) # ----- Ext grid ------ # get external grid from create_bus_trace marker_type = 'circle' if on_map else 'square' ext_grid_trace = create_bus_trace(net, buses=net.ext_grid.bus, color='grey', size=bus_size * 2, trace_name='external_grid', patch_type=marker_type) return draw_traces(line_traces + trafo_traces + ext_grid_trace + bus_trace, showlegend=False, aspectratio=aspectratio, on_map=on_map, map_style=map_style, figsize=figsize, filename=filename, auto_open=auto_open)
def pf_res_plotly(net, cmap='Jet', use_line_geodata=None, on_map=False, projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=2, bus_size=10): """ Plots a pandapower network in plotly using colormap for coloring lines according to line loading and buses according to voltage in p.u. If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial INPUT: **net** - The pandapower format network. If none is provided, mv_oberrhein() will be plotted as an example OPTIONAL: **respect_switches** (bool, False) - Respect switches when artificial geodata is created *cmap** (str, True) - name of the colormap *colors_dict** (dict, None) - by default 6 basic colors from default collor palette is used. Otherwise, user can define a dictionary in the form: voltage_kv : color **on_map** (bool, False) - enables using mapbox plot in plotly If provided geodata are not real geo-coordinates in lon/lat form, on_map will be set to False. **projection** (String, None) - defines a projection from which network geo-data will be transformed to lat-long. For each projection a string can be found at http://spatialreference.org/ref/epsg/ **map_style** (str, 'basic') - enables using mapbox plot in plotly - 'streets' - 'bright' - 'light' - 'dark' - 'satellite' **figsize** (float, 1) - aspectratio is multiplied by it in order to get final image size **aspectratio** (tuple, 'auto') - when 'auto' it preserves original aspect ratio of the network geodata any custom aspectration can be given as a tuple, e.g. (1.2, 1) **line_width** (float, 1.0) - width of lines **bus_size** (float, 10.0) - size of buses to plot. """ if 'res_bus' not in net or net.get('res_bus').shape[0] == 0: logger.warning( 'There are no Power Flow results. A Newton-Raphson power flow will be executed.' ) runpp(net) # create geocoord if none are available if 'line_geodata' not in net: net.line_geodata = pd.DataFrame(columns=['coords']) if 'bus_geodata' not in net: net.bus_geodata = pd.DataFrame(columns=["x", "y"]) if len(net.line_geodata) == 0 and len(net.bus_geodata) == 0: logger.warning( "No or insufficient geodata available --> Creating artificial coordinates." + " This may take some time") create_generic_coordinates(net, respect_switches=True) if on_map == True: logger.warning( "Map plots not available with artificial coordinates and will be disabled!" ) on_map = False # check if geodata are real geographycal lat/lon coordinates using geopy if on_map and projection is not None: geo_data_to_latlong(net, projection=projection) # ----- Buses ------ # initializating bus trace idx = net.line.index # hoverinfo which contains name and pf results hoverinfo = (net.bus['name'] + '<br>' + 'U = ' + net.res_bus.loc[idx, 'vm_pu'].astype(str) + ' pu' + '<br>' + 'U = ' + (net.res_bus.loc[idx, 'vm_pu'] * net.bus.vn_kv).astype(str) + ' kV' + '<br>' + 'ang = ' + net.res_bus.loc[idx, 'va_degree'].astype(str) + ' deg').tolist() bus_trace = create_bus_trace(net, net.bus.index, size=bus_size, infofunc=hoverinfo, cmap=cmap, cbar_title='Bus Voltage [pu]', cmin=0.9, cmax=1.1) # ----- Lines ------ # if bus geodata is available, but no line geodata # if bus geodata is available, but no line geodata cmap_lines = 'jet' if cmap is 'Jet' else cmap if use_line_geodata is None: use_line_geodata = False if len(net.line_geodata) == 0 else True elif use_line_geodata and len(net.line_geodata) == 0: logger.warning( "No or insufficient line geodata available --> only bus geodata will be used." ) use_line_geodata = False idx = net.line.index # hoverinfo which contains name and pf results hoverinfo = (net.line['name'] + '<br>' + 'I = ' + net.res_line.loc[idx, 'loading_percent'].astype(str) + ' %' + '<br>' + 'I_from = ' + net.res_line.loc[idx, 'i_from_ka'].astype(str) + ' kA' + '<br>' + 'I_to = ' + net.res_line.loc[idx, 'i_to_ka'].astype(str) + ' kA' + '<br>').tolist() line_traces = create_line_trace( net, use_line_geodata=use_line_geodata, respect_switches=True, width=line_width, infofunc=hoverinfo, cmap=cmap_lines, cmap_vals=net.res_line.loc[:, 'loading_percent'].values, cmin=0, cmax=100, cbar_title='Line Loading [%]') line_center_trace = [] if use_line_geodata == False: line_center_trace = create_edge_center_trace(line_traces, infofunc=hoverinfo) # ----- Trafos ------ idx = net.trafo.index # hoverinfo which contains name and pf results hoverinfo = (net.trafo['name'] + '<br>' + 'I = ' + net.res_trafo.loc[idx, 'loading_percent'].astype(str) + ' %' + '<br>' + 'I_hv = ' + net.res_trafo.loc[idx, 'i_hv_ka'].astype(str) + ' kA' + '<br>' + 'I_lv = ' + net.res_trafo.loc[idx, 'i_lv_ka'].astype(str) + ' kA' + '<br>').tolist() trafo_traces = create_trafo_trace(net, width=line_width * 1.5, infofunc=hoverinfo, cmap=cmap_lines, cmin=0, cmax=100) trafo_center_trace = [] if use_line_geodata == False: trafo_center_trace = create_edge_center_trace(trafo_traces, infofunc=hoverinfo) # ----- Ext grid ------ # get external grid from create_bus_trace marker_type = 'circle' if on_map else 'square' ext_grid_trace = create_bus_trace(net, buses=net.ext_grid.bus, color='grey', size=bus_size * 2, trace_name='external_grid', patch_type=marker_type) draw_traces(line_traces + trafo_traces + ext_grid_trace + bus_trace + line_center_trace + trafo_center_trace, showlegend=False, aspectratio=aspectratio, on_map=on_map, map_style=map_style, figsize=figsize)