"x": dist.loc[net.bus.index.values].values, "y": voltages.loc[net.bus.index.values].values }, index=net.bus.index) return bgd if __name__ == "__main__": import pandapower as pp import pandapower.networks as nw import pandas as pd import networkx as nx import plotting net = nw.mv_oberrhein() pp.runpp(net) mg = top.create_nxgraph(net, respect_switches=True) feeders = list( top.connected_components(mg, notravbuses=set(net.trafo.lv_bus.values))) lines_with_open_switches = set( net.switch.query("not closed and et == 'l'").element.values) fig, axs = plt.subplots(2) for bgd, ax in zip( [net.bus_geodata, voltage_profile_to_bus_geodata(net)], axs): for color, f in zip(["C0", "C1", "C2", "C3"], feeders): l = set(net.line.index[net.line.from_bus.isin( f)]) - lines_with_open_switches c = plotting.create_line_collection(net, lines=l, use_bus_geodata=True,
def example_multivoltage(): """ Returns the multivoltage example network from the pandapower tutorials. OUTPUT: net - multivoltage example network EXAMPLE: >>> import pandapower.networks >>> net = pandapower.networks.example_multivoltage() """ net = pp.create_empty_network() # --- Busses # HV # Double busbar pp.create_bus(net, name='Double Busbar 1', vn_kv=380, type='b') pp.create_bus(net, name='Double Busbar 2', vn_kv=380, type='b') for i in range(10): pp.create_bus(net, name='Bus DB T%s' % i, vn_kv=380, type='n') for i in range(1, 5): pp.create_bus(net, name='Bus DB %s' % i, vn_kv=380, type='n') # Single busbar pp.create_bus(net, name='Single Busbar', vn_kv=110, type='b') for i in range(1, 6): pp.create_bus(net, name='Bus SB %s' % i, vn_kv=110, type='n') for i in range(1, 6): for j in [1, 2]: pp.create_bus(net, name='Bus SB T%s.%s' % (i, j), vn_kv=110, type='n') # Remaining for i in range(1, 5): pp.create_bus(net, name='Bus HV%s' % i, vn_kv=110, type='n') # MV pp.create_bus(net, name='Bus MV0 20kV', vn_kv=20, type='n') for i in range(8): pp.create_bus(net, name='Bus MV%s' % i, vn_kv=10, type='n') # LV pp.create_bus(net, name='Bus LV0', vn_kv=0.4, type='n') for i in range(1, 6): pp.create_bus(net, name='Bus LV1.%s' % i, vn_kv=0.4, type='m') for i in range(1, 5): pp.create_bus(net, name='Bus LV2.%s' % i, vn_kv=0.4, type='m') pp.create_bus(net, name='Bus LV2.2.1', vn_kv=0.4, type='m') pp.create_bus(net, name='Bus LV2.2.2', vn_kv=0.4, type='m') # --- Lines # HV hv_lines = pd.DataFrame() hv_lines['line_name'] = ['HV Line%s' % i for i in range(1, 7)] hv_lines['from_bus'] = [ 'Bus SB 2', 'Bus HV1', 'Bus HV2', 'Bus HV1', 'Bus HV3', 'Bus SB 3' ] hv_lines['to_bus'] = [ 'Bus HV1', 'Bus HV2', 'Bus HV4', 'Bus HV4', 'Bus HV4', 'Bus HV3' ] hv_lines['std_type'] = '184-AL1/30-ST1A 110.0' hv_lines['length'] = [30, 20, 30, 15, 25, 30] hv_lines['parallel'] = [1, 1, 1, 1, 1, 2] for _, hv_line in hv_lines.iterrows(): from_bus = pp.get_element_index(net, "bus", hv_line.from_bus) to_bus = pp.get_element_index(net, "bus", hv_line.to_bus) pp.create_line(net, from_bus, to_bus, length_km=hv_line.length, std_type=hv_line.std_type, name=hv_line.line_name, parallel=hv_line.parallel) # MV mv_lines = pd.DataFrame() mv_lines['line_name'] = ['MV Line%s' % i for i in range(1, 9)] mv_lines['from_bus'] = ['Bus MV%s' % i for i in list(range(7)) + [0]] mv_lines['to_bus'] = ['Bus MV%s' % i for i in list(range(1, 8)) + [7]] mv_lines['length'] = 1.5 mv_lines['std_type'] = 'NA2XS2Y 1x185 RM/25 12/20 kV' for _, mv_line in mv_lines.iterrows(): from_bus = pp.get_element_index(net, "bus", mv_line.from_bus) to_bus = pp.get_element_index(net, "bus", mv_line.to_bus) pp.create_line(net, from_bus, to_bus, length_km=mv_line.length, std_type=mv_line.std_type, name=mv_line.line_name) # LV lv_lines = pd.DataFrame() lv_line_idx = [ '1.1', '1.2', '1.3', '1.4', '1.6', '2.1', '2.2', '2.3', '2.4', '2.2.1', '2.2.2' ] lv_lines['line_name'] = ['LV Line%s' % i for i in lv_line_idx] lv_line_idx = [ '0', '1.1', '1.2', '1.3', '1.4', '0', '2.1', '2.2', '2.3', '2.2', '2.2.1' ] lv_lines['from_bus'] = ['Bus LV%s' % i for i in lv_line_idx] lv_line_idx = [ '1.1', '1.2', '1.3', '1.4', '1.5', '2.1', '2.2', '2.3', '2.4', '2.2.1', '2.2.2' ] lv_lines['to_bus'] = ['Bus LV%s' % i for i in lv_line_idx] lv_lines['length'] = [0.08] * 5 + [0.12] * 6 lv_lines['std_type'] = ['NAYY 4x120 SE'] * 7 + ['15-AL1/3-ST1A 0.4'] * 4 for _, lv_line in lv_lines.iterrows(): from_bus = pp.get_element_index(net, "bus", lv_line.from_bus) to_bus = pp.get_element_index(net, "bus", lv_line.to_bus) pp.create_line(net, from_bus, to_bus, length_km=lv_line.length, std_type=lv_line.std_type, name=lv_line.line_name) # --- Transformer hv_bus = pp.get_element_index(net, "bus", "Bus DB 2") lv_bus = pp.get_element_index(net, "bus", "Bus SB 1") pp.create_transformer_from_parameters(net, hv_bus, lv_bus, sn_kva=300000, vn_hv_kv=380, vn_lv_kv=110, vscr_percent=0.06, vsc_percent=8, pfe_kw=0, i0_percent=0, tp_pos=0, shift_degree=0, name='EHV-HV-Trafo') hv_bus = pp.get_element_index(net, "bus", "Bus MV4") lv_bus = pp.get_element_index(net, "bus", "Bus LV0") pp.create_transformer_from_parameters(net, hv_bus, lv_bus, sn_kva=400, vn_hv_kv=10, vn_lv_kv=0.4, vscr_percent=1.325, vsc_percent=4, pfe_kw=0.95, i0_percent=0.2375, tp_side="hv", tp_mid=0, tp_min=-2, tp_max=2, tp_st_percent=2.5, tp_pos=0, shift_degree=150, name='MV-LV-Trafo') # Trafo3w hv_bus = pp.get_element_index(net, "bus", "Bus HV2") mv_bus = pp.get_element_index(net, "bus", "Bus MV0 20kV") lv_bus = pp.get_element_index(net, "bus", "Bus MV0") pp.create_transformer3w_from_parameters(net, hv_bus, mv_bus, lv_bus, vn_hv_kv=110, vn_mv_kv=20, vn_lv_kv=10, sn_hv_kva=40000, sn_mv_kva=15000, sn_lv_kva=25000, vsc_hv_percent=10.1, vsc_mv_percent=10.1, vsc_lv_percent=10.1, vscr_hv_percent=0.266667, vscr_mv_percent=0.033333, vscr_lv_percent=0.04, pfe_kw=0, i0_percent=0, shift_mv_degree=30, shift_lv_degree=30, tp_side="hv", tp_mid=0, tp_min=-8, tp_max=8, tp_st_percent=1.25, tp_pos=0, name='HV-MV-MV-Trafo') # --- Static generators # HV pp.create_sgen(net, pp.get_element_index(net, "bus", 'Bus SB 5'), p_kw=-20000, q_kvar=-4000, sn_kva=45000, type='WP', name='Wind Park') # MV mv_sgens = pd.DataFrame() mv_sgens['sgen_name'] = [ 'Biogas plant', 'Further MV Generator', 'Industry Generator', 'PV Park' ] mv_sgens['bus'] = ['Bus MV6', 'Bus MV0', 'Bus MV0 20kV', 'Bus MV5'] mv_sgens['p'] = [-500, -500, -15000, -2000] mv_sgens['q'] = [0, -50, -3000, -100] mv_sgens['sn'] = [750, 1000, 20000, 5000] mv_sgens['type'] = ['SGEN', 'SGEN', 'SGEN', 'PV'] for _, sgen in mv_sgens.iterrows(): bus_idx = pp.get_element_index(net, "bus", sgen.bus) pp.create_sgen(net, bus_idx, p_kw=sgen.p, q_kvar=sgen.q, sn_kva=sgen.sn, type=sgen.type, name=sgen.sgen_name) # LV lv_sgens = pd.DataFrame() lv_sgens['sgen_name'] = ['PV'] + ['PV(%s)' % i for i in range(1, 6)] lv_sgens['bus'] = [ 'Bus LV%s' % i for i in ['1.1', '1.3', '2.3', '2.4', '2.2.1', '2.2.2'] ] lv_sgens['p'] = [-6, -5, -5, -5, -5, -5] lv_sgens['q'] = 0 lv_sgens['sn'] = [12, 10, 10, 10, 10, 10] lv_sgens['type'] = 'PV' for _, sgen in lv_sgens.iterrows(): bus_idx = pp.get_element_index(net, "bus", sgen.bus) pp.create_sgen(net, bus_idx, p_kw=sgen.p, q_kvar=sgen.q, sn_kva=sgen.sn, type=sgen.type, name=sgen.sgen_name) # --- Loads # HV hv_loads = pd.DataFrame() hv_loads['load_name'] = ['MV Net %s' % i for i in range(5)] hv_loads['bus'] = ['Bus SB 4', 'Bus HV1', 'Bus HV2', 'Bus HV3', 'Bus HV4'] hv_loads['p'] = 38000 hv_loads['q'] = 6000 for _, load in hv_loads.iterrows(): bus_idx = pp.get_element_index(net, "bus", load.bus) pp.create_load(net, bus_idx, p_kw=load.p, q_kvar=load.q, name=load.load_name) # MV mv_loads = pd.DataFrame() mv_loads['load_name'] = ['Further MV-Rings', 'Industry Load' ] + ['LV Net %s' % i for i in [1, 2, 3, 5, 6, 7]] mv_loads['bus'] = ['Bus MV0', 'Bus MV0 20kV' ] + ['Bus MV%s' % i for i in [1, 2, 3, 5, 6, 7]] mv_loads['p'] = [6000, 18000, 400, 400, 400, 400, 400, 400] mv_loads['q'] = [2000, 4000, 100, 60, 60, 60, 60, 60] for _, load in mv_loads.iterrows(): bus_idx = pp.get_element_index(net, "bus", load.bus) pp.create_load(net, bus_idx, p_kw=load.p, q_kvar=load.q, name=load.load_name) # LV lv_loads = pd.DataFrame() idx = ['', '(1)', '(2)', '(3)', '(4)', '(5)'] lv_loads['load_name'] = ['Further LV-Feeders Load'] + [ 'Residential Load%s' % i for i in idx[0:5] ] + ['Rural Load%s' % i for i in idx[0:6]] lv_loads['bus'] = [ 'Bus LV%s' % i for i in [ '0', '1.1', '1.2', '1.3', '1.4', '1.5', '2.1', '2.2', '2.3', '2.4', '2.2.1', '2.2.2' ] ] lv_loads['p'] = [100] + [10] * 11 lv_loads['q'] = [10] + [3] * 11 for _, load in lv_loads.iterrows(): bus_idx = pp.get_element_index(net, "bus", load.bus) pp.create_load(net, bus_idx, p_kw=load.p, q_kvar=load.q, name=load.load_name) # --- Other # Shunt pp.create_shunt(net, pp.get_element_index(net, "bus", 'Bus HV1'), p_kw=0, q_kvar=-960, name='Shunt') # ExtGrids pp.create_ext_grid(net, pp.get_element_index(net, "bus", 'Double Busbar 1'), vm_pu=1.03, va_degree=0, name='External grid', s_sc_max_mva=10000, rx_max=0.1, rx_min=0.1) # Gen pp.create_gen(net, pp.get_element_index(net, "bus", 'Bus HV4'), vm_pu=1.03, p_kw=-1e5, name='Gas turbine') # Impedance pp.create_impedance(net, pp.get_element_index(net, "bus", 'Bus HV3'), pp.get_element_index(net, "bus", 'Bus HV1'), rft_pu=0.074873, xft_pu=0.198872, sn_kva=100000, name='Impedance') # xwards pp.create_xward(net, pp.get_element_index(net, "bus", 'Bus HV3'), ps_kw=23942, qs_kvar=-12241.87, pz_kw=2814.571, qz_kvar=0, r_ohm=0, x_ohm=12.18951, vm_pu=1.02616, name='XWard 1') pp.create_xward(net, pp.get_element_index(net, "bus", 'Bus HV1'), ps_kw=3776, qs_kvar=-7769.979, pz_kw=9174.917, qz_kvar=0, r_ohm=0, x_ohm=50.56217, vm_pu=1.024001, name='XWard 2') # --- Switches # HV # Bus-bus switches hv_bus_sw = pd.DataFrame() hv_bus_sw['bus_name'] = ['DB DS%s' % i for i in range(14)] + \ ['DB CB%s' % i for i in range(5)] + \ ['SB DS%s.%s' % (i, j) for i in range(1, 6) for j in range(1, 3)] + \ ['SB CB%s' % i for i in range(1, 6)] hv_bus_sw['from_bus'] = ['Double Busbar %s' % i for i in [2, 1, 2, 1, 2, 1, 2, 1, 2, 1]] + \ ['Bus DB T%s' % i for i in [2, 4, 6, 8, 0, 3, 5, 7, 9]] + \ ['Bus SB T1.1', 'Single Busbar', 'Bus SB T2.1', 'Single Busbar', 'Bus SB T3.1', 'Single Busbar', 'Bus SB T4.1', 'Single Busbar', 'Bus SB T5.1', 'Single Busbar'] + \ ['Bus SB T%s.2' % i for i in range(1, 6)] hv_bus_sw['to_bus'] = ['Bus DB %s' % i for i in ['T0', 'T1', 'T3', 'T3', 'T5', 'T5', 'T7', 'T7', 'T9', 'T9', '1', '2', '3', '4', 'T1', 'T2', 'T4', 'T6', 'T8']] + \ ['Bus SB %s' % i for i in ['1', 'T1.2', '2', 'T2.2', '3', 'T3.2', '4', 'T4.2', '5', 'T5.2']] + \ ['Bus SB T%s.1' % i for i in range(1, 6)] hv_bus_sw['type'] = ['DS'] * 14 + ['CB'] * 5 + ['DS'] * 10 + ['CB'] * 5 hv_bus_sw['et'] = 'b' hv_bus_sw['closed'] = [ bool(i) for i in [1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1] + [1] * 15 ] for _, switch in hv_bus_sw.iterrows(): from_bus = pp.get_element_index(net, "bus", switch.from_bus) to_bus = pp.get_element_index(net, "bus", switch.to_bus) pp.create_switch(net, from_bus, to_bus, et=switch.et, closed=switch.closed, type=switch.type, name=switch.bus_name) # Bus-Line switches hv_buses = net.bus[(net.bus.vn_kv == 380) | (net.bus.vn_kv == 110)].index hv_ls = net.line[(net.line.from_bus.isin(hv_buses)) & (net.line.to_bus.isin(hv_buses))] for _, line in hv_ls.iterrows(): for bus in [line.from_bus, line.to_bus]: pp.create_switch(net, bus, line.name, et='l', closed=True, type='LBS', name='Switch %s - %s' % (net.bus.name.at[bus], line['name'])) # MV # Bus-line switches mv_buses = net.bus[(net.bus.vn_kv == 10) | (net.bus.vn_kv == 20)].index mv_ls = net.line[(net.line.from_bus.isin(mv_buses)) & (net.line.to_bus.isin(mv_buses))] for _, line in mv_ls.iterrows(): for bus in [line.from_bus, line.to_bus]: pp.create_switch(net, bus, line.name, et='l', closed=True, type='LBS', name='Switch %s - %s' % (net.bus.name.at[bus], line['name'])) open_switch_id = net.switch[( net.switch.name == 'Switch Bus MV5 - MV Line5')].index net.switch.closed.loc[open_switch_id] = False # LV # Bus-line switches lv_buses = net.bus[net.bus.vn_kv == 0.4].index lv_ls = net.line[(net.line.from_bus.isin(lv_buses)) & (net.line.to_bus.isin(lv_buses))] for _, line in lv_ls.iterrows(): for bus in [line.from_bus, line.to_bus]: pp.create_switch(net, bus, line.name, et='l', closed=True, type='LBS', name='Switch %s - %s' % (net.bus.name.at[bus], line['name'])) # Trafoswitches # HV pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus DB 2'), pp.get_element_index(net, "trafo", 'EHV-HV-Trafo'), et='t', closed=True, type='LBS', name='Switch DB2 - EHV-HV-Trafo') pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus SB 1'), pp.get_element_index(net, "trafo", 'EHV-HV-Trafo'), et='t', closed=True, type='LBS', name='Switch SB1 - EHV-HV-Trafo') # LV pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus MV4'), pp.get_element_index(net, "trafo", 'MV-LV-Trafo'), et='t', closed=True, type='LBS', name='Switch MV4 - MV-LV-Trafo') pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus LV0'), pp.get_element_index(net, "trafo", 'MV-LV-Trafo'), et='t', closed=True, type='LBS', name='Switch LV0 - MV-LV-Trafo') # --- Powerflow # run power flow and generate result tables pp.runpp(net, init='dc', calculate_voltage_angles=True, Numba=False) return net
def test_init_slack_with_multiple_transformers(angles=True): np.random.seed(123) net = pp.create_empty_network() pp.create_bus(net, 220, index=0) pp.create_bus(net, 110, index=1) pp.create_bus(net, 110, index=2) pp.create_bus(net, 110, index=3) pp.create_bus(net, 10, index=4) pp.create_bus(net, 10, index=5) pp.create_bus(net, 10, index=6) pp.create_bus(net, 10, index=7, in_service=False) pp.create_transformer(net, 3, 7, std_type="63 MVA 110/10 kV", in_service=False) pp.create_transformer(net, 3, 4, std_type="63 MVA 110/10 kV") pp.create_transformer(net, 0, 1, std_type="100 MVA 220/110 kV") pp.create_line(net, 1, 2, 2.0, std_type="N2XS(FL)2Y 1x120 RM/35 64/110 kV") pp.create_line(net, 1, 3, 2.0, std_type="N2XS(FL)2Y 1x120 RM/35 64/110 kV") pp.create_line(net, 4, 5, 2.0, std_type="NA2XS2Y 1x95 RM/25 12/20 kV") pp.create_line(net, 5, 6, 2.0, std_type="NA2XS2Y 1x95 RM/25 12/20 kV") pp.create_load(net, 2, 5000, 3300) pp.create_load(net, 5, 900, 500) pp.create_load(net, 6, 700, 300) pp.create_ext_grid(net, bus=0, vm_pu=1.04, va_degree=10., name="Slack 220 kV") pp.runpp(net, calculate_voltage_angles=angles) for bus, row in net.res_bus[net.bus.in_service == True].iterrows(): pp.create_measurement(net, "v", "bus", row.vm_pu * r(0.01), 0.01, bus) if row.p_kw != 0.: continue pp.create_measurement(net, "p", "bus", -row.p_kw * r(), max(1.0, abs(0.03 * row.p_kw)), bus) pp.create_measurement(net, "q", "bus", -row.q_kvar * r(), max(1.0, abs(0.03 * row.q_kvar)), bus) pp.create_measurement(net, "p", "line", net.res_line.p_from_kw[0], 10., bus=1, element=0) pp.create_measurement(net, "q", "line", net.res_line.q_from_kvar[0], 10., bus=1, element=0) pp.create_measurement(net, "p", "line", net.res_line.p_from_kw[2], 10., bus=4, element=2) pp.create_measurement(net, "q", "line", net.res_line.q_from_kvar[2], 10., bus=4, element=2) pp.create_measurement(net, "p", "line", net.res_line.p_from_kw[3], 10., bus=5, element=3) pp.create_measurement(net, "q", "line", net.res_line.q_from_kvar[3], 10., bus=5, element=3) success = estimate(net, init='slack', calculate_voltage_angles=angles) # pretty high error for vm_pu (half percent!) assert success assert (np.nanmax( np.abs(net.res_bus.vm_pu.values - net.res_bus_est.vm_pu.values)) < 0.006) assert (np.nanmax( np.abs(net.res_bus.va_degree.values - net.res_bus_est.va_degree.values)) < 0.006)
def test_3bus_with_transformer(): np.random.seed(12) # 1. Create network net = pp.create_empty_network() pp.create_bus(net, name="bus1", vn_kv=10.) pp.create_bus(net, name="bus2", vn_kv=10.) pp.create_bus(net, name="bus3", vn_kv=10.) pp.create_bus(net, name="bus4", vn_kv=110.) pp.create_ext_grid(net, bus=3, vm_pu=1.01) pp.create_line_from_parameters(net, 0, 1, 1, r_ohm_per_km=.01, x_ohm_per_km=.03, c_nf_per_km=0., max_i_ka=1) pp.create_line_from_parameters(net, 0, 2, 1, r_ohm_per_km=.02, x_ohm_per_km=.05, c_nf_per_km=0., max_i_ka=1) pp.create_line_from_parameters(net, 1, 2, 1, r_ohm_per_km=.03, x_ohm_per_km=.08, c_nf_per_km=0., max_i_ka=1) pp.create_transformer(net, 3, 0, std_type="25 MVA 110/10 kV") pp.create_load(net, 1, 450, 300) pp.create_load(net, 2, 350, 200) pp.runpp(net, calculate_voltage_angles=True) pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[0], .004), .004, bus=0) pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[1], .004), .004, bus=1) pp.create_measurement(net, "v", "bus", r2(net.res_bus.vm_pu.iloc[3], .004), .004, bus=3) pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_kw.iloc[1], 10), 10, bus=1) pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_kvar.iloc[1], 10), 10, bus=1) pp.create_measurement(net, "p", "bus", -r2(net.res_bus.p_kw.iloc[2], 10), 10, bus=2) pp.create_measurement(net, "q", "bus", -r2(net.res_bus.q_kvar.iloc[2], 10), 10, bus=2) pp.create_measurement(net, "p", "bus", 0., 1.0, bus=0) pp.create_measurement(net, "q", "bus", 0., 1.0, bus=0) pp.create_measurement(net, "p", "line", r2(net.res_line.p_from_kw.iloc[0], 8), 8, 0, 0) pp.create_measurement(net, "p", "line", r2(net.res_line.p_from_kw.iloc[1], 8), 8, 0, 1) pp.create_measurement(net, "p", "transformer", r2(net.res_trafo.p_hv_kw.iloc[0], 10), 10, bus=3, element=0) # transformer meas. pp.create_measurement(net, "q", "transformer", r2(net.res_trafo.q_hv_kvar.iloc[0], 10), 10, bus=3, element=0) # at hv side # 2. Do state estimation success = estimate(net, init='slack', tolerance=5e-5, maximum_iterations=10, calculate_voltage_angles=True) v_result = net.res_bus_est.vm_pu.values delta_result = net.res_bus_est.va_degree.values diff_v = net.res_bus.vm_pu.values - v_result diff_delta = net.res_bus.va_degree.values - delta_result assert success assert (np.nanmax(abs(diff_v)) < 6e-4) assert (np.nanmax(abs(diff_delta)) < 1.4e-4) # Backwards check. Use state estimation results for power flow and check for equality net.load.drop(net.load.index, inplace=True) net.ext_grid.vm_pu = net.res_bus_est.vm_pu.iloc[net.ext_grid.bus.iloc[0]] pp.create_load(net, 0, net.res_bus_est.p_kw.iloc[0], net.res_bus_est.q_kvar.iloc[0]) pp.create_load(net, 1, net.res_bus_est.p_kw.iloc[1], net.res_bus_est.q_kvar.iloc[1]) pp.create_load(net, 2, net.res_bus_est.p_kw.iloc[2], net.res_bus_est.q_kvar.iloc[2]) _compare_pf_and_se_results(net)
def assert_init_results(net): pp.runpp(net, init="auto") assert net._ppc["iterations"] > 0 pp.runpp(net, init="results") assert net._ppc["iterations"] == 0
def test_zip_loads_gridcal(): # Tests newton power flow considering zip loads against GridCal's pf result # Results used for benchmarking are obtained using GridCal with the following code: # from GridCal.grid.CalculationEngine import * # # np.set_printoptions(precision=4) # grid = MultiCircuit() # # # Add buses # bus1 = Bus('Bus 1', vnom=20) # # bus1.controlled_generators.append(ControlledGenerator('Slack Generator', voltage_module=1.0)) # grid.add_bus(bus1) # # bus2 = Bus('Bus 2', vnom=20) # bus2.loads.append(Load('load 2', # power=0.2 * complex(40, 20), # impedance=1 / (0.40 * (40. - 20.j)), # current=np.conj(0.40 * (40. + 20.j)) / (20 * np.sqrt(3)), # )) # grid.add_bus(bus2) # # bus3 = Bus('Bus 3', vnom=20) # bus3.loads.append(Load('load 3', power=complex(25, 15))) # grid.add_bus(bus3) # # bus4 = Bus('Bus 4', vnom=20) # bus4.loads.append(Load('load 4', power=complex(40, 20))) # grid.add_bus(bus4) # # bus5 = Bus('Bus 5', vnom=20) # bus5.loads.append(Load('load 5', power=complex(50, 20))) # grid.add_bus(bus5) # # # add branches (Lines in this case) # grid.add_branch(Branch(bus1, bus2, 'line 1-2', r=0.05, x=0.11, b=0.02)) # # grid.add_branch(Branch(bus1, bus3, 'line 1-3', r=0.05, x=0.11, b=0.02)) # # grid.add_branch(Branch(bus1, bus5, 'line 1-5', r=0.03, x=0.08, b=0.02)) # # grid.add_branch(Branch(bus2, bus3, 'line 2-3', r=0.04, x=0.09, b=0.02)) # # grid.add_branch(Branch(bus2, bus5, 'line 2-5', r=0.04, x=0.09, b=0.02)) # # grid.add_branch(Branch(bus3, bus4, 'line 3-4', r=0.06, x=0.13, b=0.03)) # # grid.add_branch(Branch(bus4, bus5, 'line 4-5', r=0.04, x=0.09, b=0.02)) # # grid.compile() # # print('Ybus:\n', grid.circuits[0].power_flow_input.Ybus.todense()) # # options = PowerFlowOptions(SolverType.NR, robust=False) # power_flow = PowerFlow(grid, options) # power_flow.run() # # print('\n\n', grid.name) # print('\t|V|:', abs(grid.power_flow_results.voltage)) # print('\tVang:', np.rad2deg(np.angle(grid.power_flow_results.voltage))) vm_pu_gridcal = np.array( [1., 0.9566486349, 0.9555640318, 0.9340468428, 0.9540542172]) va_degree_gridcal = np.array( [0., -2.3717973886, -2.345654238, -3.6303651197, -2.6713716569]) Ybus_gridcal = np.array( [[ 10.9589041096 - 25.9973972603j, -3.4246575342 + 7.5342465753j, -3.4246575342 + 7.5342465753j, 0.0000000000 + 0.j, -4.1095890411 + 10.9589041096j ], [ -3.4246575342 + 7.5342465753j, 11.8320802147 - 26.1409476063j, -4.1237113402 + 9.2783505155j, 0.0000000000 + 0.j, -4.1237113402 + 9.2783505155j ], [ -3.4246575342 + 7.5342465753j, -4.1237113402 + 9.2783505155j, 10.4751981427 - 23.1190605054j, -2.9268292683 + 6.3414634146j, 0.0000000000 + 0.j ], [ 0.0000000000 + 0.j, 0.0000000000 + 0.j, -2.9268292683 + 6.3414634146j, 7.0505406085 - 15.5948139301j, -4.1237113402 + 9.2783505155j ], [ -4.1095890411 + 10.9589041096j, -4.1237113402 + 9.2783505155j, 0.0000000000 + 0.j, -4.1237113402 + 9.2783505155j, 12.3570117215 - 29.4856051405j ]]) losses_gridcal = 4.69773448916 - 2.710430515j abs_path = os.path.join(pp.pp_dir, 'networks', 'power_system_test_case_jsons', 'case5_demo_gridcal.json') net = pp.from_json(abs_path) pp.runpp(net, voltage_depend_loads=True, recycle=None) # Test Ybus matrix Ybus_pp = net["_ppc"]['internal']['Ybus'].todense() bus_ord = net["_pd2ppc_lookups"]["bus"] Ybus_pp = Ybus_pp[bus_ord, :][:, bus_ord] assert np.allclose(Ybus_pp, Ybus_gridcal) # Test Results assert np.allclose(net.res_bus.vm_pu, vm_pu_gridcal) assert np.allclose(net.res_bus.va_degree, va_degree_gridcal) # Test losses losses_pp = net.res_bus.p_mw.sum() + 1.j * net.res_bus.q_mvar.sum() assert np.isclose(losses_gridcal, -losses_pp / 1.e3) # Test bfsw algorithm pp.runpp(net, voltage_depend_loads=True, algorithm='bfsw') assert np.allclose(net.res_bus.vm_pu, vm_pu_gridcal) assert np.allclose(net.res_bus.va_degree, va_degree_gridcal)
# LV pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus MV4'), pp.get_element_index(net, "trafo", 'MV-LV-Trafo'), et='t', closed=True, type='LBS', name='Switch MV4 - MV-LV-Trafo') pp.create_switch(net, pp.get_element_index(net, "bus", 'Bus LV0'), pp.get_element_index(net, "trafo", 'MV-LV-Trafo'), et='t', closed=True, type='LBS', name='Switch LV0 - MV-LV-Trafo') ########################################################################### # Powerflow ########################################################################### # run power flow and generate result tables pp.runpp(net, init='dc', calculate_voltage_angles=True, Numba=False) return net if __name__ == '__main__': net = example_simple() pp.runpp(net, calculate_voltage_angles=True, init="dc") pp.runpp(net, calculate_voltage_angles=True, init="results")
name="A", slack=True, in_service=True) pp.create_gen(net, p_mw=150.0, max_q_mvar=9999.0, min_q_mvar=-9990.0, sn_mva=200., bus=F, vm_pu=1.0, name="F", slack=False, in_service=True) # List of Switches: # List of controllers: init_va_degree_list = [] init_vm_pu_list = [] # Run power flow if len(init_va_degree_list) > 0 and len(init_vm_pu_list) > 0: pp.runpp(net, init_va_degree=init_va_degree_list, init_vm_pu=init_vm_pu_list) else: pp.runpp(net) print(net.res_bus) # bus results
def test_convert_format(): # TODO what is this thing testing ? net = pp.from_pickle(os.path.join(pp.pp_dir, "test", "api", "old_net.p")) pp.runpp(net) assert net.converged
def run(loops=10): ''' Runs the Tabu Search Parameters ---------- loops : int, optional The number of loops that the Tabu Search should execute. Default is 10. Returns ------- list A list with dicts containing the results and the parameters for each step of the loop. The dicts has the following form: {'time': float, # The time elapsed 'best': list, # The best solution found 'total_i': int, # The total iterations 'i_best': int, # The iteration of the best solution 'fault': list, # The list with the fault points 'i_local': int, # The amout of loops of the local search 'itm': int, # The loops for reset the search with ITM 'max_i': # The max loops for stop the search } ''' results = list() for step in range(loops): print( color.yellow( '\n\nLOOP #%d ---------------------------------------------' % (step + 1), 'bold')) # Extra variables elapsed_time = 0 # DEFINING GLOBAL VARIABLES AND PARAMETERS -------------- # For single-sourced models, use the lines of code below: # ------------------------------------------------------- # Getting the test model #net = models.network33bus() # Getting the power source name (it works only for one-sourced nets) #source = net.bus['name'][int(net.ext_grid['bus'])] # Getting the initial topology #top = tools.create_topology(net) # Getting the indexes of the bridge lines between the source (bus0) and # the first fork #bridges = tools.bridge_lines(top, source) # For multiple-sourced models, use the lines of code below: # --------------------------------------------------------- net = models.network10bus() # Defines the power source name source = 'bus1' # Creating a multi-sourced topology top = tools.create_multisourced_topology(net) # Adding the abstract edges to the topology top.add_abstract_edge('bus0', 'bus1') #top.add_abstract_edge('bus1', 'bus2') # Defining manually the bridge lines according to the model bridges = [0, 1] # --------------------------------------------------------- # The variable that controls the loop stop = False # Creating the tabu-list tabu = TabuList(max_length=int( 0.2 * len(net.line))) #int(20% of the number of lines) # Getting the probability vector for the initial state of the net prob_vector = tools.get_lines_probability(top, source) # Defining the fault points fault = [3] # Applying the fault points tools.set_faults(top, fault) # Limit for voltage variation #v_variation = 0.18 v_variation = 0.05 # Limit for current variation i_variation = 0.0 # Best solution (starting with the initial solution) best = top.get_edge_states() # Number of solutions generated per iteration n_solutions = int(0.2 * len(net.line)) # Iteration number (starting with 0) iteration = 1 # The IT memory memory = [0 for _ in range(len(net.line))] # Stores the last iteration that improve the best solution improved = iteration # Limiar of frequence that determines if a component will stay in the # solution after the reset of the search by the ITM frequence = 0.6 # A flag that indicates if the search was restarted once reset = False # The number of max iterations before reset the search with IT memory max_reset = 25 # Maximum limit of iterations without improvement of the best solution # found (termination criteria) max_i = 50 # Maximum iterations to local search max_local = 10 # ------------------------------------------------------- # MAIN LOOP --------------------------------------------- print('Starting loop...') print('Initial solution:', top.get_edge_states()) # Stores the initial time begin = time.time() while not stop: # List of generated neighbors (solutions) neighbors = list() # The iteration-selected solution selected = top.get_edge_states() # Neighborhood generation --------------------------- print(color.blue('Iteration #%d' % iteration)) print('Generating neighbors...') # Making `n_solutions` neihgbors for k in range(n_solutions): print(' Generating neighbor %d/%d' % (k + 1, n_solutions)) # Generating the neighbor components sol = list() for i in range(len(net.line)): c = selected[i] if c == 1: if tools.draw(prob_vector[i]): c = 0 else: if tools.draw(0.5): c = 1 # Making solution sol.append(c) # Local search #print(' Performing local search...') local_search = [sol] + [ tools.swap_1_0(sol.copy()) for _ in range(max_local) ] # Activating the bridge lines and removing fault points for i in range(len(local_search)): local_search[i] = tools.set_value(local_search[i], bridges, 1) local_search[i] = tools.set_value(local_search[i], fault, 0) #print(' Removing cycles...') # Removing cycles for i in range(len(local_search)): top.set_edge_states(local_search[i]) for cycle in top.cycles(source, search='bfs'): #print(color.magenta(' The topology has cycles. Fixing it...')) top.deactivate_edge( top.get_edge_index(cycle[0], cycle[1])) # Update the solution removing its cycles local_search[i] = top.get_edge_states() #print(' Running the power flow...') valid_solutions = list() for solution in local_search: # Setting the solution in the network switching top.set_edge_states(solution) tools.make_switch_operations(top.get_edge_states(), net) try: # Running powerflow pp.runpp(net) # Checking voltage constraints for index, voltage in enumerate(net.res_bus['vm_pu'], start=0): if abs( 1 - voltage ) > v_variation: # out of the voltage constraints #print(color.magenta(' Bus out of voltage contraints. Fixing it...')) bus = top.get_vertex_name(index) for adjacent in top.get_adjacent(bus): top.deactivate_edge( top.get_edge_index(bus, adjacent)) # Passing the topology alterations to the network tools.make_switch_operations(top.get_edge_states(), net) # Running the power flow again pp.runpp(net) # Checking current constraints for index, current in enumerate( net.res_line['loading_percent'], start=0): if current > 100 * ( 1 + i_variation ): # out of the current constraints #print(color.magenta(' Line out of current limits. Fixing it...')) top.deactivate_edge(index) # Saving the generated solution in the valid solution list valid_solutions.append(top.get_edge_states()) except (pp.powerflow.LoadflowNotConverged): print( color.red( ' ### Power flow not converged. Ignoring the solution.' )) continue # Getting the best of local search if valid_solutions != []: neighbors.append( tools.best_of(valid_solutions, top, source)) # --------------------------------------------------- # Neighbor selection -------------------------------- print('Selecting the neighbor...') if neighbors != []: best_of_iteration = tools.best_of(neighbors, top, source) while len(neighbors) != 0: selected = tools.best_of(neighbors, top, source) neighbors.remove(selected) if tabu.is_tabu(selected): print( ' TABU: This solution is in tabu list. Applying aspiration criteria...' ) # Aspiration criteria if not tools.draw(0.3): print(' Result: REFUSED') continue print(' Result: ACCEPTED') if len(neighbors) == 0: print( ' All solutions is in tabu list. Selecting the best found.' ) selected = best_of_iteration.copy() tabu.add(best_of_iteration) top.set_edge_states(best_of_iteration) break tabu.add(selected.copy()) top.set_edge_states(selected) print(' Solution selected.') break else: # Case no valid solutions were generated, select the same # previous iteration solution top.set_edge_states(selected) # Comparing the selected solution with the best solution found #print(' Comparing the selected solution with the best solution found...') if best != []: sel = tools.best_of([selected, best], top, source) if sel != best and tools.value_of_solution( selected, net) > tools.value_of_solution(best, net): print( color.green( 'IMPROVEMENT: Improving solution at iteration %d.' % iteration, 'bold')) best = sel.copy() improved = iteration else: best = selected.copy() # --------------------------------------------------- # Intermediate-term memory -------------------------- print('Saving the solution in the intermediate-term memory...') for i in range(len(selected)): memory[i] += selected[i] if not reset and iteration - improved >= max_reset: print(color.yellow('RESETING SEARCH -------------------')) print('Reseting the search with intermediate-term memory.') reset = True mcc = list() for value in memory: if value / iteration > frequence: mcc.append(1) else: mcc.append(0) # Activating the bridge lines and removing fault points mcc = tools.set_value(mcc, bridges, 1) mcc = tools.set_value(mcc, fault, 0) print('Most common components:', mcc) selected = mcc.copy() top.set_edge_states(selected) # --------------------------------------------------- # Checking termination criteria --------------------- #print('Selected:', selected) #print('Best:', best) iteration += 1 # The TS stops whether it reaches the max iterarion or find a # optimal solution if iteration - improved > max_i or tools.value_of_solution( best, net) == len(net.bus.values): stop = True elapsed_time = time.time() - begin print(color.yellow('Elapsed time: %f s' % elapsed_time)) print(color.yellow('Best solution found: %s' % best, 'bold')) # --------------------------------------------------- # ------------------------------------------------------- results.append({ 'time': elapsed_time, 'best': best, 'total_i': iteration, 'i_best': improved, 'fault': fault, 'i_local': max_local, 'itm': max_reset, 'max_i': max_i, }) return results
def test_repl_to_line_with_switch(): """ Same test as above, but this time in comparison to actual replacement """ net = nw.example_multivoltage() pp.runpp(net) for testindex in net.line.index: if net.line.in_service.loc[testindex]: # todo print weg print("testing line " + str(testindex)) line = net.line.loc[testindex] fbus = line.from_bus tbus = line.to_bus len = line.length_km if "184-AL1/30-ST1A" in net.line.std_type.loc[testindex]: std = "243-AL1/39-ST1A 110.0" elif "NA2XS2Y" in net.line.std_type.loc[testindex]: std = "NA2XS2Y 1x240 RM/25 6/10 kV" elif "NAYY" in net.line.std_type.loc[testindex]: std = "NAYY 4x150 SE" elif " 15-AL1/3-ST1A" in net.line.std_type.loc[testindex]: std = "24-AL1/4-ST1A 0.4" # create an oos line at the same buses REPL = pp.create_line(net, from_bus=fbus, to_bus=tbus, length_km=len, std_type=std) for bus in fbus, tbus: if bus in net.switch[(net.switch.closed == False) & (net.switch.element == testindex)].bus.values: 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 pp.runpp(net) fbus_repl = net.res_bus.loc[fbus] tbus_repl = net.res_bus.loc[tbus] ploss_repl = (net.res_line.loc[REPL].p_from_mw - net.res_line.loc[REPL].p_to_mw ) qloss_repl =(net.res_line.loc[REPL].q_from_mvar - net.res_line.loc[REPL].q_to_mvar ) # get ne line impedances new_idx = tb.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 pp.runpp(net) # compare lf results fbus_ne = net.res_bus.loc[fbus] tbus_ne = net.res_bus.loc[tbus] ploss_ne = (net.res_line.loc[testindex].p_from_mw - net.res_line.loc[testindex].p_to_mw)+\ (net.res_line.loc[new_idx].p_from_mw - net.res_line.loc[new_idx].p_to_mw) qloss_ne = (net.res_line.loc[testindex].q_from_mvar - net.res_line.loc[testindex].q_to_mvar )+\ (net.res_line.loc[new_idx].q_from_mvar - net.res_line.loc[new_idx].q_to_mvar) assert_series_equal(fbus_repl, fbus_ne, atol=1e-2) assert_series_equal(tbus_repl, tbus_ne) assert np.isclose(ploss_repl,ploss_ne, atol=1e-5) 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
import pandapower.networks as nw1 import pandapower as pp from pandapower.plotting import simple_plot, simple_plotly, pf_res_plotly net1 = nw1.mv_oberrhein() pp.runpp(net1) print(net1.res_bus) highest = net1.res_bus.vm_pu.max() print(highest) highest_ones = net1.res_bus.loc[net1.res_bus.vm_pu > 1.02] print(highest_ones) lines = net1.res_line.loc[net1.res_line.loading_percent > 50.] print(lines) simple_plot(net1) simple_plotly(net1) print()
def test_convenience_create_functions(): net = pp.create_empty_network() b1 = pp.create_bus(net, 110.) b2 = pp.create_bus(net, 110.) b3 = pp.create_bus(net, 20) pp.create_ext_grid(net, b1) pp.create_line_from_parameters(net, b1, b2, length_km=20., r_ohm_per_km=0.0487, x_ohm_per_km=0.1382301, c_nf_per_km=160., max_i_ka=0.664) l0 = pp.create_load_from_cosphi(net, b2, 10e3, 0.95, "ind", name="load") pp.runpp(net, init="flat") assert net.load.p_kw.at[l0] == 9.5e3 assert net.load.q_kvar.at[l0] > 0 assert np.sqrt(net.load.p_kw.at[l0]**2 + net.load.q_kvar.at[l0]**2) == 10e3 assert np.isclose(net.res_bus.vm_pu.at[b2], 0.99990833838) assert net.load.name.at[l0] == "load" sh0 = pp.create_shunt_as_capacitor(net, b2, 10e3, loss_factor=0.01, name="shunt") pp.runpp(net, init="flat") assert np.isclose(net.res_shunt.q_kvar.at[sh0], -10, 043934174e3) assert np.isclose(net.res_shunt.p_kw.at[sh0], 100.43933665) assert np.isclose(net.res_bus.vm_pu.at[b2], 1.0021942964) assert net.shunt.name.at[sh0] == "shunt" sg0 = pp.create_sgen_from_cosphi(net, b2, 5e3, 0.95, "cap", name="sgen") pp.runpp(net, init="flat") assert np.sqrt(net.sgen.p_kw.at[sg0]**2 + net.sgen.q_kvar.at[sg0]**2) == 5e3 assert net.sgen.p_kw.at[sg0] == -4.75e3 assert net.sgen.q_kvar.at[sg0] < 0 assert np.isclose(net.res_bus.vm_pu.at[b2], 1.0029376578) assert net.sgen.name.at[sg0] == "sgen" tol = 1e-6 sind = pp.create_series_reactor_as_impedance(net, b1, b2, r_ohm=100, x_ohm=200, sn_kva=100) assert net.impedance.at[sind, 'rft_pu'] - 8.264463e-04 < tol assert net.impedance.at[sind, 'xft_pu'] - 0.001653 < tol tid = pp.create_transformer_from_parameters(net, hv_bus=b2, lv_bus=b3, sn_kva=100, vn_hv_kv=110, vn_lv_kv=20, vscr_percent=5, vsc_percent=20, pfe_kw=1, i0_percent=1) pp.create_load(net, b3, 100) assert net.trafo.at[tid, 'df'] == 1 pp.runpp(net) tr_l = net.res_trafo.at[tid, 'loading_percent'] net.trafo.at[tid, 'df'] = 2 pp.runpp(net) tr_l_2 = net.res_trafo.at[tid, 'loading_percent'] assert tr_l == tr_l_2 * 2 net.trafo.at[tid, 'df'] = 0 with pytest.raises(UserWarning): pp.runpp(net)
def load_grid(self, path=None, filename=None): """ Demonstration on how you can load a powergrid and then initialize the proper grid2op attributes. The only thing we have to do here is to "order" the objects in each substation. Note that we don't even do it implicitly here (relying on default grid2op ordering). The only decision we had to make was concerning "grid2op powerlines" which represents both "pandapower transformers" and "pandapower powerlines". We decided that: - powerline are "before" trafo (so in the grid2op line id I will put first all powerlines, then all trafo) - grid2op "origin" side will be "from" side for pandapower powerline and "hv" side for pandapower trafo - grid2op "extremity" side will be "to" side for pandapower powerline and "lv" side for pandapower trafo .. note:: We use one "trick" here. Pandapower grid (as it will be the case for most format) will have one "bus" per substation. For grid2op, we want at least 2 busbar per substation. So we simply copy and paste the grid. And we will deactivate the busbar that are not connected (no element connected to it). This "coding" allows for easily mapping the bus id (each bus is represented with an id in pandapower) and whether its busbar 1 or busbar 2 (grid2op side). More precisely: busbar 1 of substation with id `sub_id` will have id `sub_id` and busbar 2 of the same substation will have id `sub_id + n_sub` (recall that n_sub is the number of substation on the grid). This "coding" is not optimal in the ram it takes. But we recommend you to adopt a similar one. It's pretty easy to change the topology using this trick, much easier than if you rely on "switches" for example. (But of course you can still use switches if you really want to) """ # first, handles different kind of path: if path is None and filename is None: raise RuntimeError( "You must provide at least one of path or file to load a powergrid." ) if path is None: full_path = filename elif filename is None: full_path = path else: full_path = os.path.join(path, filename) if not os.path.exists(full_path): raise RuntimeError( "There is no powergrid at \"{}\"".format(full_path)) # then load the grid located at the full path and store it in `self._grid` # raise an exception if it can't be loaded try: with warnings.catch_warnings(): # remove deprecationg warnings for old version of pandapower warnings.filterwarnings("ignore", category=DeprecationWarning) self._grid = pp.from_json(full_path) except Exception as exc_: raise BackendError( f"Impossible to load the powergrid located at \"{full_path}\". Please " f"check the file exist and that the file represent a valid pandapower " f"grid. For your information, the error is:\n{exc_}") ###################################################################### # this part is due to the "modeling" of the topology FOR THIS EXAMPLE # remember (see docstring of this function) that we "duplicate the buses" to code more easily the # topology modification (instead of relying on the `switches`) # first we remember the number of substation self.n_sub = self._grid.bus.shape[0] # and then we duplicate the bus add_topo = copy.deepcopy(self._grid.bus) add_topo.index += add_topo.shape[0] add_topo["in_service"] = False self._grid.bus = pd.concat((self._grid.bus, add_topo)) self._nb_real_line_pandapower = self._grid.line.shape[0] # i do a powerflow to initialize the "results" dataframes # this last step is internal to pandapower pp.runpp(self._grid, check_connectivity=False) ###################################################################### # and now we initialize the number of each of the elements self.n_line = self._grid.line.shape[0] + self._grid.trafo.shape[ 0] # trafo are powerline for grid2op ! self.n_gen = self._grid.gen.shape[0] self.n_load = self._grid.load.shape[0] # self.n_sub # already initialize above # initialize the number of elements per substation # now export to grid2op the substation to which objects are connected self.load_to_subid = copy.deepcopy(self._grid.load["bus"]) self.gen_to_subid = copy.deepcopy(self._grid.gen["bus"]) # here we just decide (but that is a convention we could have done it differently) # that "origin side" (grid2op) corresponds to "from_bus" from pandapower line and "hv_bus" for # pandapower trafo. self.line_or_to_subid = np.concatenate( (copy.deepcopy(self._grid.line["from_bus"]), copy.deepcopy(self._grid.trafo["hv_bus"]))) self.line_ex_to_subid = np.concatenate( (copy.deepcopy(self._grid.line["to_bus"]), copy.deepcopy(self._grid.trafo["lv_bus"]))) # and now we don't forget to initialize the rest self._compute_pos_big_topo() # we highly recommend you to call this ! # and now the thermal limit self.thermal_limit_a = 1000 * np.concatenate( (self._grid.line["max_i_ka"].values, self._grid.trafo["sn_mva"].values / (np.sqrt(3) * self._grid.trafo["vn_hv_kv"].values))) self.thermal_limit_a = self.thermal_limit_a.astype(dt_float) # NB: this instance of backend is here for academic purpose only. For clarity, it does not handle # neither shunt nor storage unit. self.shunts_data_available = False self.set_no_storage()
# Copyright (c) 2020, RTE (https://www.rte-france.com) # See AUTHORS.txt # This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0. # If a copy of the Mozilla Public License, version 2.0 was not distributed with this file, # you can obtain one at http://mozilla.org/MPL/2.0/. # SPDX-License-Identifier: MPL-2.0 # This file is part of PyKLU2Grid, PyKLU2Grid a implements a c++ backend targeting the Grid2Op platform. import pandapower as pp import pandapower.networks as pn grid = pn.case30() grid = pn.case118() pp.runpp(grid, numba=False)
if type(q2) is float or type(q2) is int: load_3 = pp.create_load(net = net, bus = bus_3, p_mw = p_load_2, q_mvar = q2*p_load_2, name = "load 3") elif q2: load_3 = pp.create_load(net = net, bus = bus_3, p_mw = p_load_2, q_mvar = q_load_2, name = "load 3") else: load_3 = pp.create_load(net = net, bus = bus_3, p_mw = p_load_2, name = "load 3") #load_3 = pp.create_load(net = net, bus = bus_3, p_mw = p_tot - p_load_1, q_mvar = q_load_2, name = "load 3") if modus == 2: gen_1 = pp.create_gen(net = net, bus = bus_0, p_mw = p_gen_1, vm_pu = 1, slack = True) else: gen_1 = pp.create_gen(net = net, bus = bus_1, p_mw = p_gen_1, vm_pu = 1, slack = True) # Run the network pp.runpp(net, max_iteration = max_iteration, tolerance_mva = 1e-10) iterations[i] = net["_ppc"]["iterations"] vm_pu_res[:, i] = net["res_bus"].loc[:, "vm_pu"] va_degree_res[:, i] = net["res_bus"].loc[:, "va_degree"] p_mw_res[:, i] = net["res_bus"].loc[:, "p_mw"] q_mvar_res[:, i] = net["res_bus"].loc[:, "q_mvar"] i += 1 if nr_of_nodes == 4: extra_index = 1 else: extra_index = 0
for pq in pqs.itertuples(index=True, name='Pandas'): bus_num = getattr(pq, "bus_num") p_mw = getattr(pq, "active_power") q_mvar = getattr(pq, "reactive_power") pq_num = getattr(pq, "Index") pp.create_load(net, bus_num-1, p_mw=p_mw, q_mvar=q_mvar, name='Load %s' % pq_num) print(net.load) # show loads table ### PQgen ### pqgens = pd.read_csv('data/PQgen.csv',names=['bus_num','power_rating','voltage_rating','active_power','reactive_power', 'v_max','v_min','conv_imp','area'],index_col=False) for pqgen in pqgens.itertuples(index=True, name='Pandas'): bus_num = getattr(pqgen, "bus_num") try: mask=pqs[pqs['bus_num']==bus_num].index.tolist()[0] raise ValueError("Attention static gens and loads at the same bus. Manually modify database") except: p_mw = getattr(pqgen, "active_power") q_mvar = getattr(pqgen, "reactive_power") sn_mva = getattr(pqgen, "power_rating") pqgen_num = getattr(pqgen, "Index") pp.create_sgen(net, bus_num-1, p_mw=p_mw, q_mvar=q_mvar, sn_mva=sn_mva, name='StatGen %s' % pqgen_num) #pp.create_load(net, bus_num-1, p_mw=p_mw, q_mvar=q_mvar, name='StatGen %s' % pqgen_num) print(net.sgen) # show static gen table ### Diagnosis ### pp.diagnostic(net, report_style='detailed', warnings_only=False, return_result_dict=True, overload_scaling_factor=0.001, min_r_ohm=0.001, min_x_ohm=0.001, min_r_pu=1e-05, min_x_pu=1e-05, nom_voltage_tolerance=0.3, numba_tolerance=1e-05) ### Run Power Flow ### pp.runpp(net, algorithm="iwamoto_nr", calculate_voltage_angles="auto", init="dc", check_connectivity=True, v_debug=True) #, init_vm_pu=True, init_va_degree=True print(net)
def test_pp_initialization(): net = pp.create_empty_network() b1 = pp.create_bus(net, vn_kv=0.4) b2 = pp.create_bus(net, vn_kv=0.4) pp.create_ext_grid(net, b1, vm_pu=0.7) pp.create_line(net, b1, b2, 0.5, std_type="NAYY 4x50 SE", index=4) pp.create_load(net, b2, p_mw=0.01) pp.runpp(net, init_va_degree="flat", init_vm_pu=1.02) assert net._ppc["iterations"] == 5 pp.runpp(net, init_va_degree="dc", init_vm_pu=0.8) assert net._ppc["iterations"] == 4 pp.runpp(net, init_va_degree="flat", init_vm_pu=np.array([0.75, 0.7])) assert net._ppc["iterations"] == 3 pp.runpp(net, init_va_degree="dc", init_vm_pu=[0.75, 0.7]) assert net._ppc["iterations"] == 3 pp.runpp(net, init_va_degree="flat", init_vm_pu="auto") assert net._ppc["iterations"] == 3 pp.runpp(net, init_va_degree="dc") assert net._ppc["iterations"] == 3
def runpf(self, is_dc=False): """ Run a power flow on the underlying _grid. This implements an optimization of the powerflow computation: if the number of buses has not changed between two calls, the previous results are re used. This speeds up the computation in case of "do nothing" action applied. """ # print("I called runpf") conv = True nb_bus = self.get_nb_active_bus() try: with warnings.catch_warnings(): # remove the warning if _grid non connex. And it that case load flow as not converged warnings.filterwarnings("ignore", category=scipy.sparse.linalg.MatrixRankWarning) warnings.filterwarnings("ignore", category=RuntimeWarning) if self._nb_bus_before is None: self._pf_init = "dc" elif nb_bus == self._nb_bus_before: self._pf_init = "results" else: self._pf_init = "auto" if is_dc: pp.rundcpp(self._grid, check_connectivity=False) self._nb_bus_before = None # if dc i start normally next time i call an ac powerflow else: pp.runpp(self._grid, check_connectivity=False, init=self._pf_init, numba=numba_) if self._grid.res_gen.isnull().values.any(): # TODO see if there is a better way here # sometimes pandapower does not detect divergence and put Nan. raise pp.powerflow.LoadflowNotConverged self.load_p[:], self.load_q[:], self.load_v[:] = self._loads_info() if not is_dc: if not np.all(np.isfinite(self.load_v)): # TODO see if there is a better way here # some loads are disconnected: it's a game over case! raise pp.powerflow.LoadflowNotConverged self.line_status[:] = self._get_line_status() # I retrieve the data once for the flows, so has to not re read multiple dataFrame self.p_or[:] = self._aux_get_line_info("p_from_mw", "p_hv_mw") self.q_or[:] = self._aux_get_line_info("q_from_mvar", "q_hv_mvar") self.v_or[:] = self._aux_get_line_info("vm_from_pu", "vm_hv_pu") self.a_or[:] = self._aux_get_line_info("i_from_ka", "i_hv_ka") * 1000 self.a_or[~np.isfinite(self.a_or)] = 0. self.v_or[~np.isfinite(self.v_or)] = 0. # it seems that pandapower does not take into account disconencted powerline for their voltage self.v_or[~self.line_status] = 0. self.v_ex[~self.line_status] = 0. self.p_ex[:] = self._aux_get_line_info("p_to_mw", "p_lv_mw") self.q_ex[:] = self._aux_get_line_info("q_to_mvar", "q_lv_mvar") self.v_ex[:] = self._aux_get_line_info("vm_to_pu", "vm_lv_pu") self.a_ex[:] = self._aux_get_line_info("i_to_ka", "i_lv_ka") * 1000 self.a_ex[~np.isfinite(self.a_ex)] = 0. self.v_ex[~np.isfinite(self.v_ex)] = 0. self.v_or[:] *= self.lines_or_pu_to_kv self.v_ex[:] *= self.lines_ex_pu_to_kv self.prod_p[:], self.prod_q[:], self.prod_v[:] = self._gens_info() # for attr_nm in ["load_p", "load_q", "load_v", "p_or", "q_or", "v_or", "a_or", "p_ex", "q_ex", # "v_ex", "a_ex", "prod_p", "prod_q", "prod_v"]: # setattr(self, attr_nm, getattr(self, attr_nm).astype(dt_float)) self._nb_bus_before = None self._grid._ppc["gen"][self._iref_slack, 1] = 0. return self._grid.converged except pp.powerflow.LoadflowNotConverged: # of the powerflow has not converged, results are Nan self.p_or[:] = np.NaN self.q_or[:] = np.NaN self.v_or[:] = np.NaN self.a_or[:] = np.NaN self.p_ex[:] = np.NaN self.q_ex[:] = np.NaN self.v_ex[:] = np.NaN self.a_ex[:] = np.NaN self.prod_p[:] = np.NaN self.prod_q[:] = np.NaN self.prod_v[:] = np.NaN self.load_p[:] = np.NaN self.load_q[:] = np.NaN self.load_v[:] = np.NaN self._nb_bus_before = None return False
def test_line_temperature(): net = four_loads_with_branches_out() r_init = net.line.r_ohm_per_km.values.copy() # r_ohm_per_km is not in line results by default pp.runpp(net) v_init = net.res_bus.vm_pu.values.copy() va_init = net.res_bus.va_degree.values.copy() assert "r_ohm_per_km" not in net.res_line.columns # no temperature adjustment performed if not explicitly set in options/arguments to runpp net.line["temperature_degree_celsius"] = 20 pp.runpp(net) assert "r_ohm_per_km" not in net.res_line.columns assert np.allclose(net.res_bus.vm_pu, v_init, rtol=0, atol=1e-16) assert np.allclose(net.res_bus.va_degree, va_init, rtol=0, atol=1e-16) # argument in runpp is considered pp.runpp(net, consider_line_temperature=True) assert "r_ohm_per_km" in net.res_line.columns assert np.allclose(net.res_line.r_ohm_per_km, r_init, rtol=0, atol=1e-16) assert np.allclose(net.res_bus.vm_pu, v_init, rtol=0, atol=1e-16) assert np.allclose(net.res_bus.va_degree, va_init, rtol=0, atol=1e-16) # check results of r adjustment, check that user_pf_options works, alpha is 4e-3 by default t = np.arange(0, 80, 10) net.line.temperature_degree_celsius = t pp.set_user_pf_options(net, consider_line_temperature=True) pp.runpp(net) alpha = 4e-3 r_temp = r_init * (1 + alpha * (t - 20)) assert np.allclose(net.res_line.r_ohm_per_km, r_temp, rtol=0, atol=1e-16) assert not np.allclose(net.res_bus.vm_pu, v_init, rtol=0, atol=1e-4) assert not np.allclose(net.res_bus.va_degree, va_init, rtol=0, atol=1e-2) # check reults with user-defined alpha alpha = np.arange(3e-3, 5e-3, 2.5e-4) net.line['alpha'] = alpha pp.runpp(net) r_temp = r_init * (1 + alpha * (t - 20)) assert np.allclose(net.res_line.r_ohm_per_km, r_temp, rtol=0, atol=1e-16) assert not np.allclose(net.res_bus.vm_pu, v_init, rtol=0, atol=1e-4) assert not np.allclose(net.res_bus.va_degree, va_init, rtol=0, atol=1e-2) # not anymore in net if not considered pp.set_user_pf_options(net, overwrite=True) pp.runpp(net) assert np.allclose(net.res_bus.vm_pu, v_init, rtol=0, atol=1e-16) assert np.allclose(net.res_bus.va_degree, va_init, rtol=0, atol=1e-16) assert "r_ohm_per_km" not in net.res_line.columns
def load_grid(self, path=None, filename=None): """ .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ Load the _grid, and initialize all the member of the class. Note that in order to perform topological modification of the substation of the underlying powergrid, some buses are added to the test case loaded. They are set as "out of service" unless a topological action acts on these specific substations. """ if path is None and filename is None: raise RuntimeError( "You must provide at least one of path or file to load a powergrid." ) if path is None: full_path = filename elif filename is None: full_path = path else: full_path = os.path.join(path, filename) if not os.path.exists(full_path): raise RuntimeError( "There is no powergrid at \"{}\"".format(full_path)) with warnings.catch_warnings(): # remove deprecationg warnings for old version of pandapower warnings.filterwarnings("ignore", category=DeprecationWarning) self._grid = pp.from_json(full_path) # add the slack bus that is often not modeled as a generator, but i need it for this backend to work bus_gen_added = None i_ref = None self._iref_slack = None self._id_bus_added = None pp.runpp(self._grid, numba=numba_) if np.all(~self._grid.gen["slack"]): # there are not defined slack bus on the data, i need to hack it up a little bit pd2ppc = self._grid._pd2ppc_lookups[ "bus"] # pd2ppc[pd_id] = ppc_id ppc2pd = np.argsort(pd2ppc) # ppc2pd[ppc_id] = pd_id for i, el in enumerate(self._grid._ppc['gen'][:, 0]): if int(el) not in self._grid._pd2ppc_lookups["bus"][ self._grid.gen["bus"].values]: if bus_gen_added is not None: raise RuntimeError( "Impossible to recognize the powergrid") bus_gen_added = ppc2pd[int(el)] i_ref = i break self._iref_slack = i_ref self._id_bus_added = self._grid.gen.shape[0] # see https://matpower.org/docs/ref/matpower5.0/idx_gen.html for details on the comprehension of self._grid._ppc pp.create_gen(self._grid, bus_gen_added, p_mw=self._grid._ppc['gen'][i_ref, 1], vm_pu=self._grid._ppc['gen'][i_ref, 5], min_p_mw=self._grid._ppc['gen'][i_ref, 9], max_p_mw=self._grid._ppc['gen'][i_ref, 8], max_q_mvar=self._grid._ppc['gen'][i_ref, 3], min_q_mvar=self._grid._ppc['gen'][i_ref, 4], slack=True, controllable=True) else: self.slack_id = np.where(self._grid.gen["slack"])[0] pp.runpp(self._grid, numba=numba_) self.__nb_bus_before = self._grid.bus.shape[0] self.__nb_powerline = self._grid.line.shape[0] self._init_bus_load = self.cst_1 * self._grid.load["bus"].values self._init_bus_gen = self.cst_1 * self._grid.gen["bus"].values self._init_bus_lor = self.cst_1 * self._grid.line["from_bus"].values self._init_bus_lex = self.cst_1 * self._grid.line["to_bus"].values t_for = self.cst_1 * self._grid.trafo["hv_bus"].values t_fex = self.cst_1 * self._grid.trafo["lv_bus"].values self._init_bus_lor = np.concatenate( (self._init_bus_lor, t_for)).astype(np.int) self._init_bus_lex = np.concatenate( (self._init_bus_lex, t_fex)).astype(np.int) self._grid["ext_grid"]["va_degree"] = 0.0 # this has the effect to divide by 2 the active power in the added generator, if this generator and the "slack bus" # one are connected to the same bus. # if not, it must not be done. So basically, i create a vector for which p and q for generator must be multiply self._fact_mult_gen = np.ones(self._grid.gen.shape[0]) # self._fact_mult_gen[-1] += 1 # now extract the powergrid self.n_line = copy.deepcopy(self._grid.line.shape[0]) + copy.deepcopy( self._grid.trafo.shape[0]) if "name" in self._grid.line.columns and not self._grid.line[ "name"].isnull().values.any(): self.name_line = [name for name in self._grid.line["name"]] else: self.name_line = [ '{from_bus}_{to_bus}_{id_powerline_me}'.format( **row, id_powerline_me=i) for i, (_, row) in enumerate(self._grid.line.iterrows()) ] if "name" in self._grid.trafo.columns and not self._grid.trafo[ "name"].isnull().values.any(): self.name_line += [ name_traf for name_traf in self._grid.trafo["name"] ] else: transfo = [('{hv_bus}'.format(**row), '{lv_bus}'.format(**row)) for i, (_, row) in enumerate(self._grid.trafo.iterrows())] transfo = [sorted(el) for el in transfo] self.name_line += [ '{}_{}_{}'.format(*el, i + self._grid.line.shape[0]) for i, el in enumerate(transfo) ] self.name_line = np.array(self.name_line) self.n_gen = copy.deepcopy(self._grid.gen.shape[0]) if "name" in self._grid.gen.columns and not self._grid.gen[ "name"].isnull().values.any(): self.name_gen = [name_g for name_g in self._grid.gen["name"]] else: self.name_gen = [ "gen_{bus}_{index_gen}".format(**row, index_gen=i) for i, (_, row) in enumerate(self._grid.gen.iterrows()) ] self.name_gen = np.array(self.name_gen) self.n_load = copy.deepcopy(self._grid.load.shape[0]) if "name" in self._grid.load.columns and not self._grid.load[ "name"].isnull().values.any(): self.name_load = [nl for nl in self._grid.load["name"]] else: self.name_load = [ "load_{bus}_{index_gen}".format(**row, index_gen=i) for i, (_, row) in enumerate(self._grid.load.iterrows()) ] self.name_load = np.array(self.name_load) self.n_sub = copy.deepcopy(self._grid.bus.shape[0]) self.name_sub = [ "sub_{}".format(i) for i, row in self._grid.bus.iterrows() ] self.name_sub = np.array(self.name_sub) # number of elements per substation self.sub_info = np.zeros(self.n_sub, dtype=dt_int) self.load_to_subid = np.zeros(self.n_load, dtype=dt_int) self.gen_to_subid = np.zeros(self.n_gen, dtype=dt_int) self.line_or_to_subid = np.zeros(self.n_line, dtype=dt_int) self.line_ex_to_subid = np.zeros(self.n_line, dtype=dt_int) self.load_to_sub_pos = np.zeros(self.n_load, dtype=dt_int) self.gen_to_sub_pos = np.zeros(self.n_gen, dtype=dt_int) self.line_or_to_sub_pos = np.zeros(self.n_line, dtype=dt_int) self.line_ex_to_sub_pos = np.zeros(self.n_line, dtype=dt_int) pos_already_used = np.zeros(self.n_sub, dtype=dt_int) self._what_object_where = [[] for _ in range(self.n_sub)] # self._grid.line.sort_index(inplace=True) # self._grid.trafo.sort_index(inplace=True) # self._grid.gen.sort_index(inplace=True) # self._grid.load.sort_index(inplace=True) for i, (_, row) in enumerate(self._grid.line.iterrows()): sub_or_id = int(row["from_bus"]) sub_ex_id = int(row["to_bus"]) self.sub_info[sub_or_id] += 1 self.sub_info[sub_ex_id] += 1 self.line_or_to_subid[i] = sub_or_id self.line_ex_to_subid[i] = sub_ex_id self.line_or_to_sub_pos[i] = pos_already_used[sub_or_id] pos_already_used[sub_or_id] += 1 self.line_ex_to_sub_pos[i] = pos_already_used[sub_ex_id] pos_already_used[sub_ex_id] += 1 self._what_object_where[sub_or_id].append(("line", "from_bus", i)) self._what_object_where[sub_ex_id].append(("line", "to_bus", i)) lag_transfo = self._grid.line.shape[0] self._number_true_line = copy.deepcopy(self._grid.line.shape[0]) for i, (_, row) in enumerate(self._grid.trafo.iterrows()): sub_or_id = int(row["hv_bus"]) sub_ex_id = int(row["lv_bus"]) self.sub_info[sub_or_id] += 1 self.sub_info[sub_ex_id] += 1 self.line_or_to_subid[i + lag_transfo] = sub_or_id self.line_ex_to_subid[i + lag_transfo] = sub_ex_id self.line_or_to_sub_pos[i + lag_transfo] = pos_already_used[sub_or_id] pos_already_used[sub_or_id] += 1 self.line_ex_to_sub_pos[i + lag_transfo] = pos_already_used[sub_ex_id] pos_already_used[sub_ex_id] += 1 self._what_object_where[sub_or_id].append(("trafo", "hv_bus", i)) self._what_object_where[sub_ex_id].append(("trafo", "lv_bus", i)) for i, (_, row) in enumerate(self._grid.gen.iterrows()): sub_id = int(row["bus"]) self.sub_info[sub_id] += 1 self.gen_to_subid[i] = sub_id self.gen_to_sub_pos[i] = pos_already_used[sub_id] pos_already_used[sub_id] += 1 self._what_object_where[sub_id].append(("gen", "bus", i)) for i, (_, row) in enumerate(self._grid.load.iterrows()): sub_id = int(row["bus"]) self.sub_info[sub_id] += 1 self.load_to_subid[i] = sub_id self.load_to_sub_pos[i] = pos_already_used[sub_id] pos_already_used[sub_id] += 1 self._what_object_where[sub_id].append(("load", "bus", i)) self.dim_topo = np.sum(self.sub_info) self._compute_pos_big_topo() # utilities for imeplementing apply_action self._corresp_name_fun = {} self._get_vector_inj = {} self._get_vector_inj[ "load_p"] = self._load_grid_load_p_mw #lambda grid: grid.load["p_mw"] self._get_vector_inj[ "load_q"] = self._load_grid_load_q_mvar #lambda grid: grid.load["q_mvar"] self._get_vector_inj[ "prod_p"] = self._load_grid_gen_p_mw #lambda grid: grid.gen["p_mw"] self._get_vector_inj[ "prod_v"] = self._load_grid_gen_vm_pu #lambda grid: grid.gen["vm_pu"] # "hack" to handle topological changes, for now only 2 buses per substation add_topo = copy.deepcopy(self._grid.bus) add_topo.index += add_topo.shape[0] add_topo["in_service"] = False self._grid.bus = pd.concat((self._grid.bus, add_topo)) self.load_pu_to_kv = self._grid.bus["vn_kv"][ self.load_to_subid].values.astype(dt_float) self.prod_pu_to_kv = self._grid.bus["vn_kv"][ self.gen_to_subid].values.astype(dt_float) self.lines_or_pu_to_kv = self._grid.bus["vn_kv"][ self.line_or_to_subid].values.astype(dt_float) self.lines_ex_pu_to_kv = self._grid.bus["vn_kv"][ self.line_ex_to_subid].values.astype(dt_float) self.thermal_limit_a = 1000 * np.concatenate( (self._grid.line["max_i_ka"].values, self._grid.trafo["sn_mva"].values / (np.sqrt(3) * self._grid.trafo["vn_hv_kv"].values))) self.thermal_limit_a = self.thermal_limit_a.astype(dt_float) self.p_or = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.q_or = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.v_or = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.a_or = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.p_ex = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.q_ex = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.v_ex = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.a_ex = np.full(self.n_line, dtype=dt_float, fill_value=np.NaN) self.line_status = np.full(self.n_line, dtype=dt_bool, fill_value=np.NaN) self.load_p = np.full(self.n_load, dtype=dt_float, fill_value=np.NaN) self.load_q = np.full(self.n_load, dtype=dt_float, fill_value=np.NaN) self.load_v = np.full(self.n_load, dtype=dt_float, fill_value=np.NaN) self.prod_p = np.full(self.n_gen, dtype=dt_float, fill_value=np.NaN) self.prod_v = np.full(self.n_gen, dtype=dt_float, fill_value=np.NaN) self.prod_q = np.full(self.n_gen, dtype=dt_float, fill_value=np.NaN) self._nb_bus_before = None # shunts data self.n_shunt = self._grid.shunt.shape[0] self.shunt_to_subid = np.zeros(self.n_shunt, dtype=dt_int) - 1 name_shunt = [] for i, (_, row) in enumerate(self._grid.shunt.iterrows()): bus = int(row["bus"]) name_shunt.append( "shunt_{bus}_{index_shunt}".format(**row, index_shunt=i)) self.shunt_to_subid[i] = bus self.name_shunt = np.array(name_shunt) self._sh_vnkv = self._grid.bus["vn_kv"][ self.shunt_to_subid].values.astype(dt_float) self.shunts_data_available = True # store the topoid -> objid self._big_topo_to_obj = [(None, None) for _ in range(self.dim_topo)] nm_ = "load" for load_id, pos_big_topo in enumerate(self.load_pos_topo_vect): self._big_topo_to_obj[pos_big_topo] = (load_id, nm_) nm_ = "gen" for gen_id, pos_big_topo in enumerate(self.gen_pos_topo_vect): self._big_topo_to_obj[pos_big_topo] = (gen_id, nm_) nm_ = "lineor" for l_id, pos_big_topo in enumerate(self.line_or_pos_topo_vect): self._big_topo_to_obj[pos_big_topo] = (l_id, nm_) nm_ = "lineex" for l_id, pos_big_topo in enumerate(self.line_ex_pos_topo_vect): self._big_topo_to_obj[pos_big_topo] = (l_id, nm_) # store the topoid -> objid self._big_topo_to_backend = [(None, None, None) for _ in range(self.dim_topo)] for load_id, pos_big_topo in enumerate(self.load_pos_topo_vect): self._big_topo_to_backend[pos_big_topo] = (load_id, load_id, 0) for gen_id, pos_big_topo in enumerate(self.gen_pos_topo_vect): self._big_topo_to_backend[pos_big_topo] = (gen_id, gen_id, 1) for l_id, pos_big_topo in enumerate(self.line_or_pos_topo_vect): if l_id < self.__nb_powerline: self._big_topo_to_backend[pos_big_topo] = (l_id, l_id, 2) else: self._big_topo_to_backend[pos_big_topo] = (l_id, l_id - self.__nb_powerline, 3) for l_id, pos_big_topo in enumerate(self.line_ex_pos_topo_vect): if l_id < self.__nb_powerline: self._big_topo_to_backend[pos_big_topo] = (l_id, l_id, 4) else: self._big_topo_to_backend[pos_big_topo] = (l_id, l_id - self.__nb_powerline, 5) self._topo_vect = self._get_topo_vect() # Create a deep copy of itself in the initial state pp_backend_initial_state = copy.deepcopy(self) # Store it under super private attribute self.__pp_backend_initial_state = pp_backend_initial_state
import pandapower as pp #create empty net net = pp.create_empty_network() #create buses bus1 = pp.create_bus(net, vn_kv=20., name="Bus 1") bus2 = pp.create_bus(net, vn_kv=0.4, name="Bus 2") bus3 = pp.create_bus(net, vn_kv=0.4, name="Bus 3") #create bus elements pp.create_ext_grid(net, bus=bus1, vm_pu=1.02, name="Grid Connection") pp.create_load(net, bus=bus3, p_mw=0.100, q_mvar=0.05, name="Load") #create branch elements trafo = pp.create_transformer(net, hv_bus=bus1, lv_bus=bus2, std_type="0.4 MVA 20/0.4 kV", name="Trafo") line = pp.create_line(net, from_bus=bus2, to_bus=bus3, length_km=0.1, std_type="NAYY 4x50 SE", name="Line") pp.runpp(net) #Power Flow print(net.res_bus) print(net.res_line) net.res_trafo print(net.res_bus)
def runpf(self, is_dc=False): """ .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ Run a power flow on the underlying _grid. This implements an optimization of the powerflow computation: if the number of buses has not changed between two calls, the previous results are re used. This speeds up the computation in case of "do nothing" action applied. """ conv = True nb_bus = self.get_nb_active_bus() try: with warnings.catch_warnings(): # remove the warning if _grid non connex. And it that case load flow as not converged warnings.filterwarnings( "ignore", category=scipy.sparse.linalg.MatrixRankWarning) warnings.filterwarnings("ignore", category=RuntimeWarning) if self._nb_bus_before is None: self._pf_init = "dc" elif nb_bus == self._nb_bus_before: self._pf_init = "results" else: self._pf_init = "auto" if np.any(~self._grid.load["in_service"]): # TODO see if there is a better way here -> do not handle this here, but rather in Backend._next_grid_state raise pp.powerflow.LoadflowNotConverged("Isolated load") if np.any(~self._grid.gen["in_service"]): # TODO see if there is a better way here -> do not handle this here, but rather in Backend._next_grid_state raise pp.powerflow.LoadflowNotConverged("Isolated gen") if is_dc: pp.rundcpp(self._grid, check_connectivity=False) self._nb_bus_before = None # if dc i start normally next time i call an ac powerflow else: pp.runpp(self._grid, check_connectivity=False, init=self._pf_init, numba=numba_) # stores the computation time if "_ppc" in self._grid: if "et" in self._grid["_ppc"]: self.comp_time += self._grid["_ppc"]["et"] if self._grid.res_gen.isnull().values.any(): # TODO see if there is a better way here -> do not handle this here, but rather in Backend._next_grid_state # sometimes pandapower does not detect divergence and put Nan. raise pp.powerflow.LoadflowNotConverged("Isolated gen") self.prod_p[:], self.prod_q[:], self.prod_v[:] = self._gens_info( ) self.load_p[:], self.load_q[:], self.load_v[:] = self._loads_info( ) if not is_dc: if not np.all(np.isfinite(self.load_v)): # TODO see if there is a better way here # some loads are disconnected: it's a game over case! raise pp.powerflow.LoadflowNotConverged( "Isolated load") else: # fix voltages magnitude that are always "nan" for dc case # self._grid.res_bus["vm_pu"] is always nan when computed in DC self.load_v[:] = self.load_pu_to_kv # TODO # need to assign the correct value when a generator is present at the same bus # TODO optimize this ugly loop for l_id in range(self.n_load): if self.load_to_subid[l_id] in self.gen_to_subid: ind_gens = np.where(self.gen_to_subid == self.load_to_subid[l_id])[0] for g_id in ind_gens: if self._topo_vect[self.load_pos_topo_vect[ l_id]] == self._topo_vect[ self.load_pos_topo_vect[g_id]]: self.load_v[l_id] = self.prod_v[g_id] break self.line_status[:] = self._get_line_status() # I retrieve the data once for the flows, so has to not re read multiple dataFrame self.p_or[:] = self._aux_get_line_info("p_from_mw", "p_hv_mw") self.q_or[:] = self._aux_get_line_info("q_from_mvar", "q_hv_mvar") self.v_or[:] = self._aux_get_line_info("vm_from_pu", "vm_hv_pu") self.a_or[:] = self._aux_get_line_info("i_from_ka", "i_hv_ka") * 1000 self.a_or[~np.isfinite(self.a_or)] = 0. self.v_or[~np.isfinite(self.v_or)] = 0. self.p_ex[:] = self._aux_get_line_info("p_to_mw", "p_lv_mw") self.q_ex[:] = self._aux_get_line_info("q_to_mvar", "q_lv_mvar") self.v_ex[:] = self._aux_get_line_info("vm_to_pu", "vm_lv_pu") self.a_ex[:] = self._aux_get_line_info("i_to_ka", "i_lv_ka") * 1000 self.a_ex[~np.isfinite(self.a_ex)] = 0. self.v_ex[~np.isfinite(self.v_ex)] = 0. # it seems that pandapower does not take into account disconencted powerline for their voltage self.v_or[~self.line_status] = 0. self.v_ex[~self.line_status] = 0. self.v_or[:] *= self.lines_or_pu_to_kv self.v_ex[:] *= self.lines_ex_pu_to_kv self._nb_bus_before = None self._grid._ppc["gen"][self._iref_slack, 1] = 0. self._topo_vect[:] = self._get_topo_vect() return self._grid.converged except pp.powerflow.LoadflowNotConverged as exc_: # of the powerflow has not converged, results are Nan self._reset_all_nan() return False
def validate_from_ppc( ppc_net, net, pf_type="runpp", max_diff_values={ "bus_vm_pu": 1e-6, "bus_va_degree": 1e-5, "branch_p_mw": 1e-6, "branch_q_mvar": 1e-6, "gen_p_mw": 1e-6, "gen_q_mvar": 1e-6 }, run=True): """ This function validates the pypower case files to pandapower net structure conversion via a \ comparison of loadflow calculation results. (Hence the opf cost conversion is not validated.) INPUT: **ppc_net** - The pypower case file, which must already contain the pypower powerflow results or pypower must be importable. **net** - The pandapower network. OPTIONAL: **pf_type** ("runpp", string) - Type of validated power flow. Possible are ("runpp", "rundcpp", "runopp", "rundcopp") **max_diff_values** - Dict of maximal allowed difference values. The keys must be 'vm_pu', 'va_degree', 'p_branch_mw', 'q_branch_mvar', 'p_gen_mw' and 'q_gen_mvar' and the values floats. **run** (True, bool or list of two bools) - changing the value to False avoids trying to run (optimal) loadflows. Giving a list of two bools addresses first pypower and second pandapower. OUTPUT: **conversion_success** - conversion_success is returned as False if pypower or pandapower cannot calculate a powerflow or if the maximum difference values (max_diff_values ) cannot be hold. EXAMPLE: import pandapower.converter as pc net = cv.from_ppc(ppc_net, f_hz=50) conversion_success = cv.validate_from_ppc(ppc_net, net) NOTE: The user has to take care that the loadflow results already are included in the provided \ ppc_net or pypower is importable. """ # check in case of optimal powerflow comparison whether cost information exist if "opp" in pf_type: if not (len(net.polynomial_cost) | len(net.piecewise_linear_cost)): if "gencost" in ppc_net: if not len(ppc_net["gencost"]): logger.debug( 'ppc and pandapower net do not include cost information.' ) return True else: logger.error( 'The pandapower net does not include cost information.' ) return False else: logger.debug( 'ppc and pandapower net do not include cost information.') return True # guarantee run parameter as list, for pypower and pandapower (optimal) powerflow run run = [run, run] if isinstance(run, bool) else run # --- check pypower powerflow success, if possible if pypower_import and run[0]: try: if pf_type == "runpp": ppc_net = runpf.runpf(ppc_net, ppopt)[0] elif pf_type == "rundcpp": ppc_net = rundcpf.rundcpf(ppc_net, ppopt)[0] elif pf_type == "runopp": ppc_net = runopf.runopf(ppc_net, ppopt) elif pf_type == "rundcopp": ppc_net = rundcopf.rundcopf(ppc_net, ppopt) else: raise ValueError("The pf_type %s is unknown" % pf_type) except: logger.debug("The pypower run did not work.") ppc_success = True if 'success' in ppc_net.keys(): if ppc_net['success'] != 1: ppc_success = False logger.error( "The given ppc data indicates an unsuccessful pypower powerflow: " + "'ppc_net['success'] != 1'") if (ppc_net['branch'].shape[1] < 17): ppc_success = False logger.error( "The shape of given ppc data indicates missing pypower powerflow results." ) # --- try to run a pandapower powerflow if run[1]: if pf_type == "runpp": try: pp.runpp(net, init="dc", calculate_voltage_angles=True, trafo_model="pi") except pp.LoadflowNotConverged: try: pp.runpp(net, calculate_voltage_angles=True, init="flat", trafo_model="pi") except pp.LoadflowNotConverged: try: pp.runpp(net, trafo_model="pi", calculate_voltage_angles=False) if "bus_va_degree" in max_diff_values.keys(): max_diff_values[ "bus_va_degree"] = 1e2 if max_diff_values[ "bus_va_degree"] < 1e2 else max_diff_values[ "bus_va_degree"] logger.info("voltage_angles could be calculated.") except pp.LoadflowNotConverged: logger.error( 'The pandapower powerflow does not converge.') elif pf_type == "rundcpp": try: pp.rundcpp(net, trafo_model="pi") except pp.LoadflowNotConverged: logger.error('The pandapower dc powerflow does not converge.') elif pf_type == "runopp": try: pp.runopp(net, init="flat", calculate_voltage_angles=True) except pp.OPFNotConverged: try: pp.runopp(net, init="pf", calculate_voltage_angles=True) except (pp.OPFNotConverged, pp.LoadflowNotConverged, KeyError): try: pp.runopp(net, init="flat", calculate_voltage_angles=False) logger.info("voltage_angles could be calculated.") if "bus_va_degree" in max_diff_values.keys(): max_diff_values[ "bus_va_degree"] = 1e2 if max_diff_values[ "bus_va_degree"] < 1e2 else max_diff_values[ "bus_va_degree"] except pp.OPFNotConverged: try: pp.runopp(net, init="pf", calculate_voltage_angles=False) if "bus_va_degree" in max_diff_values.keys(): max_diff_values[ "bus_va_degree"] = 1e2 if max_diff_values[ "bus_va_degree"] < 1e2 else max_diff_values[ "bus_va_degree"] logger.info("voltage_angles could be calculated.") except (pp.OPFNotConverged, pp.LoadflowNotConverged, KeyError): logger.error( 'The pandapower optimal powerflow does not converge.' ) elif pf_type == "rundcopp": try: pp.rundcopp(net) except pp.LoadflowNotConverged: logger.error( 'The pandapower dc optimal powerflow does not converge.') else: raise ValueError("The pf_type %s is unknown" % pf_type) # --- prepare powerflow result comparison by reordering pp results as they are in ppc results if not ppc_success: return False if "opp" in pf_type: if not net.OPF_converged: return elif not net.converged: return False # --- store pypower powerflow results ppc_res = dict.fromkeys(ppc_elms) ppc_res["branch"] = ppc_net['branch'][:, 13:17] ppc_res["bus"] = ppc_net['bus'][:, 7:9] ppc_res["gen"] = ppc_net['gen'][:, 1:3] # --- pandapower bus result table pp_res = dict.fromkeys(ppc_elms) pp_res["bus"] = array(net.res_bus.sort_index()[['vm_pu', 'va_degree']]) # --- pandapower gen result table pp_res["gen"] = zeros([1, 2]) # consideration of parallel generators via storing how much generators have been considered # each node # if in ppc is only one gen -> numpy initially uses one dim array -> change to two dim array if len(ppc_net["gen"].shape) == 1: ppc_net["gen"] = array(ppc_net["gen"], ndmin=2) GENS = DataFrame(ppc_net['gen'][:, [0]].astype(int)) GEN_uniq = GENS.drop_duplicates() already_used_gen = Series(zeros(GEN_uniq.shape[0]).astype(int), index=[int(v) for v in GEN_uniq.values]) change_q_compare = [] for i, j in GENS.iterrows(): current_bus_type, current_bus_idx, same_bus_gen_idx, first_same_bus_in_service_gen_idx, \ last_same_bus_in_service_gen_idx = _gen_bus_info(ppc_net, i) if current_bus_type == 3 and i == first_same_bus_in_service_gen_idx: pp_res["gen"] = append( pp_res["gen"], array(net.res_ext_grid[net.ext_grid.bus == current_bus_idx][[ 'p_mw', 'q_mvar' ]]).reshape((1, 2)), 0) elif current_bus_type == 2 and i == first_same_bus_in_service_gen_idx: pp_res["gen"] = append( pp_res["gen"], array(net.res_gen[net.gen.bus == current_bus_idx][[ 'p_mw', 'q_mvar' ]]).reshape((1, 2)), 0) else: pp_res["gen"] = append( pp_res["gen"], array(net.res_sgen[net.sgen.bus == current_bus_idx][[ 'p_mw', 'q_mvar' ]])[already_used_gen.at[int(j)]].reshape((1, 2)), 0) already_used_gen.at[int(j)] += 1 change_q_compare += [int(j)] pp_res["gen"] = pp_res["gen"][1:, :] # delete initial zero row # --- pandapower branch result table pp_res["branch"] = zeros([1, 4]) # consideration of parallel branches via storing how often branches were considered # each node-to-node-connection try: init1 = concat([net.line.from_bus, net.line.to_bus], axis=1, sort=True).drop_duplicates() init2 = concat([net.trafo.hv_bus, net.trafo.lv_bus], axis=1, sort=True).drop_duplicates() except TypeError: # legacy pandas < 0.21 init1 = concat([net.line.from_bus, net.line.to_bus], axis=1).drop_duplicates() init2 = concat([net.trafo.hv_bus, net.trafo.lv_bus], axis=1).drop_duplicates() init1['hv_bus'] = nan init1['lv_bus'] = nan init2['from_bus'] = nan init2['to_bus'] = nan try: already_used_branches = concat([init1, init2], axis=0, sort=True) except TypeError: # pandas < 0.21 legacy already_used_branches = concat([init1, init2], axis=0) already_used_branches['number'] = zeros( [already_used_branches.shape[0], 1]).astype(int) BRANCHES = DataFrame(ppc_net['branch'][:, [0, 1, 8, 9]]) for i in BRANCHES.index: from_bus = pp.get_element_index(net, 'bus', name=int(ppc_net['branch'][i, 0])) to_bus = pp.get_element_index(net, 'bus', name=int(ppc_net['branch'][i, 1])) from_vn_kv = ppc_net['bus'][from_bus, 9] to_vn_kv = ppc_net['bus'][to_bus, 9] ratio = BRANCHES[2].at[i] angle = BRANCHES[3].at[i] # from line results if (from_vn_kv == to_vn_kv) & ((ratio == 0) | (ratio == 1)) & (angle == 0): pp_res["branch"] = append( pp_res["branch"], array(net.res_line[(net.line.from_bus == from_bus) & (net.line.to_bus == to_bus)][[ 'p_from_mw', 'q_from_mvar', 'p_to_mw', 'q_to_mvar' ]]) [int(already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)].values)].reshape( 1, 4), 0) already_used_branches.number.loc[ (already_used_branches.from_bus == from_bus) & (already_used_branches.to_bus == to_bus)] += 1 # from trafo results else: if from_vn_kv >= to_vn_kv: pp_res["branch"] = append( pp_res["branch"], array(net.res_trafo[(net.trafo.hv_bus == from_bus) & (net.trafo.lv_bus == to_bus)] [['p_hv_mw', 'q_hv_mvar', 'p_lv_mw', 'q_lv_mvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == from_bus) & (already_used_branches.lv_bus == to_bus)] += 1 else: # switch hv-lv-connection of pypower connection buses pp_res["branch"] = append( pp_res["branch"], array(net.res_trafo[(net.trafo.hv_bus == to_bus) & (net.trafo.lv_bus == from_bus)] [['p_lv_mw', 'q_lv_mvar', 'p_hv_mw', 'q_hv_mvar' ]])[int(already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)]. values)].reshape(1, 4), 0) already_used_branches.number.loc[ (already_used_branches.hv_bus == to_bus) & (already_used_branches.lv_bus == from_bus)] += 1 pp_res["branch"] = pp_res["branch"][1:, :] # delete initial zero row # --- do the powerflow result comparison diff_res = dict.fromkeys(ppc_elms) diff_res["bus"] = ppc_res["bus"] - pp_res["bus"] diff_res["bus"][:, 1] -= diff_res["bus"][0, 1] # remove va_degree offset diff_res["branch"] = ppc_res["branch"] - pp_res["branch"] diff_res["gen"] = ppc_res["gen"] - pp_res["gen"] # comparison of buses with several generator units only as q sum for i in GEN_uniq.loc[GEN_uniq[0].isin(change_q_compare)].index: next_is = GEN_uniq.index[GEN_uniq.index > i] if len(next_is) > 0: next_i = next_is[0] else: next_i = GENS.index[-1] + 1 if (next_i - i) > 1: diff_res["gen"][i:next_i, 1] = sum(diff_res["gen"][i:next_i, 1]) # logger info logger.debug( "Maximum voltage magnitude difference between pypower and pandapower: " "%.2e pu" % max_(abs(diff_res["bus"][:, 0]))) logger.debug( "Maximum voltage angle difference between pypower and pandapower: " "%.2e degree" % max_(abs(diff_res["bus"][:, 1]))) logger.debug( "Maximum branch flow active power difference between pypower and pandapower: " "%.2e MW" % max_(abs(diff_res["branch"][:, [0, 2]]))) logger.debug( "Maximum branch flow reactive power difference between pypower and " "pandapower: %.2e MVAr" % max_(abs(diff_res["branch"][:, [1, 3]]))) logger.debug( "Maximum active power generation difference between pypower and pandapower: " "%.2e MW" % max_(abs(diff_res["gen"][:, 0]))) logger.debug( "Maximum reactive power generation difference between pypower and pandapower: " "%.2e MVAr" % max_(abs(diff_res["gen"][:, 1]))) if _validate_diff_res(diff_res, {"bus_vm_pu": 1e-3, "bus_va_degree": 1e-3, "branch_p_mw": 1e-6, "branch_q_mvar": 1e-6}) and \ (max_(abs(diff_res["gen"])) > 1e-1).any(): logger.debug( "The active/reactive power generation difference possibly results " "because of a pypower error. Please validate " "the results via pypower loadflow." ) # this occurs e.g. at ppc case9 # give a return if isinstance(max_diff_values, dict): return _validate_diff_res(diff_res, max_diff_values) else: logger.debug("'max_diff_values' must be a dict.")
def test_transformer3w_phase_shift(): test_ref = ((0.9995, -31.003), (0.9996, -60.764)) test_tap_pos = { 'hv': ((0.9615, -31.466), (0.9617, -61.209)), 'mv': ((1.0389, -30.620), (0.9996, -60.764)), 'lv': ((0.9995, -31.003), (1.039, -60.381)) } test_tap_neg = { 'hv': ((1.0405, -30.511), (1.0406, -60.291)), 'mv': ((0.9602, -31.417), (0.9996, -60.764)), 'lv': ((0.9995, -31.003), (0.9603, -61.178)) } for side in ["hv", "mv", "lv"]: net = pp.create_empty_network() b1 = pp.create_bus(net, vn_kv=110.) pp.create_ext_grid(net, b1) b2 = pp.create_bus(net, vn_kv=20.) pp.create_load(net, b2, 1e4) b3 = pp.create_bus(net, vn_kv=0.4) pp.create_load(net, b3, 1e3) pp.create_transformer3w_from_parameters(net, hv_bus=b1, mv_bus=b2, lv_bus=b3, vn_hv_kv=110, vn_mv_kv=20, vn_lv_kv=0.4, sn_hv_kva=40000, sn_mv_kva=30000, sn_lv_kva=10000, vsc_hv_percent=5, vsc_mv_percent=5, vsc_lv_percent=5, vscr_hv_percent=0.1, vscr_mv_percent=0.1, vscr_lv_percent=0.1, pfe_kw=0, i0_percent=0.1, shift_mv_degree=30, shift_lv_degree=60, tp_side=side, tp_st_percent=2, tp_st_degree=10, tp_pos=0, tp_mid=0, tp_min=-2, tp_max=2) pp.runpp(net, init="dc", calculate_voltage_angles=True) assert np.isclose(net.res_bus.vm_pu.at[b2], test_ref[0][0], rtol=1e-4) assert np.isclose(net.res_bus.va_degree.at[b2], test_ref[0][1], rtol=1e-4) assert np.isclose(net.res_bus.vm_pu.at[b3], test_ref[1][0], rtol=1e-4) assert np.isclose(net.res_bus.va_degree.at[b3], test_ref[1][1], rtol=1e-4) net.trafo3w.tp_pos.at[0] = 2 pp.runpp(net, init="dc", calculate_voltage_angles=True) assert np.isclose(net.res_bus.vm_pu.at[b2], test_tap_pos[side][0][0], rtol=1e-4) assert np.isclose(net.res_bus.va_degree.at[b2], test_tap_pos[side][0][1], rtol=1e-4) assert np.isclose(net.res_bus.vm_pu.at[b3], test_tap_pos[side][1][0], rtol=1e-4) assert np.isclose(net.res_bus.va_degree.at[b3], test_tap_pos[side][1][1], rtol=1e-4) net.trafo3w.tp_pos.at[0] = -2 pp.runpp(net, init="dc", calculate_voltage_angles=True) assert np.isclose(net.res_bus.vm_pu.at[b2], test_tap_neg[side][0][0], rtol=1e-4) assert np.isclose(net.res_bus.va_degree.at[b2], test_tap_neg[side][0][1], rtol=1e-4) assert np.isclose(net.res_bus.vm_pu.at[b3], test_tap_neg[side][1][0], rtol=1e-4) assert np.isclose(net.res_bus.va_degree.at[b3], test_tap_neg[side][1][1], rtol=1e-4)
def runpp_with_consistency_checks(net, **kwargs): pp.runpp(net, **kwargs) consistency_checks(net) return True
def result_test_network(): for net in result_test_network_generator(): pass pp.runpp(net, trafo_model="t", trafo_loading="current") return net
# -*- coding: utf-8 -*- # Copyright (c) 2016-2021 by University of Kassel and Fraunhofer Institute for Energy Economics # and Energy System Technology (IEE), Kassel. All rights reserved. # Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. import pandapower.networks as nw import pandapower as pp import pandapower.control as control import os net = nw.example_multivoltage() control.DiscreteTapControl(net, 1, 1.02, 1.03) pp.runpp(net, run_control=True) pp.to_json(net, os.path.join("old_versions", "example_%s.json" % pp.__version__))
def test_pandapower_case(): #more complicated examples like #net = pandapower.networks.example_simple() #can be used once the import of e.g. switches is perfected #create empty net net = pp.create_empty_network() #create buses b1 = pp.create_bus(net, vn_kv=20., name="Bus 1") b2 = pp.create_bus(net, vn_kv=0.4, name="Bus 2") b3 = pp.create_bus(net, vn_kv=0.4, name="Bus 3") #create bus elements pp.create_ext_grid(net, bus=b1, vm_pu=1.02, name="Grid Connection") pp.create_load(net, bus=b3, p_mw=0.1, q_mvar=0.05, name="Load") #create branch elements tid = pp.create_transformer(net, hv_bus=b1, lv_bus=b2, std_type="0.4 MVA 20/0.4 kV", name="Trafo") pp.create_line(net, from_bus=b2, to_bus=b3, length_km=0.1, name="Line", std_type="NAYY 4x50 SE") #because of phase angles, need to init with DC pp.runpp(net, calculate_voltage_angles=True, init="dc") n = pypsa.Network() n.import_from_pandapower_net(net) #seed PF with LPF solution because of phase angle jumps n.lpf() n.pf(use_seed=True) #use same index for everything net.res_bus.index = net.bus.name.values net.res_line.index = net.line.name.values #compare bus angles np.testing.assert_array_almost_equal( n.buses_t.v_ang.loc["now"] * 180 / np.pi, net.res_bus.va_degree) #compare bus voltage magnitudes np.testing.assert_array_almost_equal(n.buses_t.v_mag_pu.loc["now"], net.res_bus.vm_pu) #compare bus active power (NB: pandapower uses load signs) np.testing.assert_array_almost_equal(n.buses_t.p.loc["now"], -net.res_bus.p_mw) #compare bus active power (NB: pandapower uses load signs) np.testing.assert_array_almost_equal(n.buses_t.q.loc["now"], -net.res_bus.q_mvar) #compare branch flows np.testing.assert_array_almost_equal(n.lines_t.p0.loc["now"], net.res_line.p_from_mw) np.testing.assert_array_almost_equal(n.lines_t.p1.loc["now"], net.res_line.p_to_mw) np.testing.assert_array_almost_equal(n.lines_t.q0.loc["now"], net.res_line.q_from_mvar) np.testing.assert_array_almost_equal(n.lines_t.q1.loc["now"], net.res_line.q_to_mvar) np.testing.assert_array_almost_equal(n.transformers_t.p0.loc["now"], net.res_trafo.p_hv_mw) np.testing.assert_array_almost_equal(n.transformers_t.p1.loc["now"], net.res_trafo.p_lv_mw) np.testing.assert_array_almost_equal(n.transformers_t.q0.loc["now"], net.res_trafo.q_hv_mvar) np.testing.assert_array_almost_equal(n.transformers_t.q1.loc["now"], net.res_trafo.q_lv_mvar)
def test_pandapower_case(): #more complicated examples like #net = pandapower.networks.example_simple() #can be used once the import of e.g. switches is perfected #create empty net net = pp.create_empty_network() #create buses b1 = pp.create_bus(net, vn_kv=20., name="Bus 1") b2 = pp.create_bus(net, vn_kv=0.4, name="Bus 2") b3 = pp.create_bus(net, vn_kv=0.4, name="Bus 3") #create bus elements pp.create_ext_grid(net, bus=b1, vm_pu=1.02, name="Grid Connection") pp.create_load(net, bus=b3, p_kw=100, q_kvar=50, name="Load") #create branch elements tid = pp.create_transformer(net, hv_bus=b1, lv_bus=b2, std_type="0.4 MVA 20/0.4 kV", name="Trafo") pp.create_line(net, from_bus=b2, to_bus=b3, length_km=0.1, name="Line", std_type="NAYY 4x50 SE") #because of phase angles, need to init with DC pp.runpp(net,calculate_voltage_angles=True,init="dc") n = pypsa.Network() n.import_from_pandapower_net(net) #seed PF with LPF solution because of phase angle jumps n.lpf() n.pf(use_seed=True) #use same index for everything net.res_bus.index = net.bus.name.values net.res_line.index = net.line.name.values #compare bus angles np.testing.assert_array_almost_equal(n.buses_t.v_ang.loc["now"]*180/np.pi,net.res_bus.va_degree) #compare bus voltage magnitudes np.testing.assert_array_almost_equal(n.buses_t.v_mag_pu.loc["now"],net.res_bus.vm_pu) #compare bus active power (NB: pandapower uses load signs) np.testing.assert_array_almost_equal(n.buses_t.p.loc["now"],-net.res_bus.p_kw/1e3) #compare bus active power (NB: pandapower uses load signs) np.testing.assert_array_almost_equal(n.buses_t.q.loc["now"],-net.res_bus.q_kvar/1e3) #compare branch flows np.testing.assert_array_almost_equal(n.lines_t.p0.loc["now"],net.res_line.p_from_kw/1e3) np.testing.assert_array_almost_equal(n.lines_t.p1.loc["now"],net.res_line.p_to_kw/1e3) np.testing.assert_array_almost_equal(n.lines_t.q0.loc["now"],net.res_line.q_from_kvar/1e3) np.testing.assert_array_almost_equal(n.lines_t.q1.loc["now"],net.res_line.q_to_kvar/1e3) np.testing.assert_array_almost_equal(n.transformers_t.p0.loc["now"],net.res_trafo.p_hv_kw/1e3) np.testing.assert_array_almost_equal(n.transformers_t.p1.loc["now"],net.res_trafo.p_lv_kw/1e3) np.testing.assert_array_almost_equal(n.transformers_t.q0.loc["now"],net.res_trafo.q_hv_kvar/1e3) np.testing.assert_array_almost_equal(n.transformers_t.q1.loc["now"],net.res_trafo.q_lv_kvar/1e3)
def test_convert_format(): folder = os.path.abspath(os.path.dirname(pp.__file__)) net = pp.from_pickle(os.path.join(folder, "test", "api", "old_net.p")) pp.runpp(net) assert net.converged