PandaPower conversion

This example illustrates conversion from PandaPower to power-grid-model input data. We can then calculate power-flow with it or convert to a different formats like PGM JSON.

1. Load the PandaPower Data

For this example we will construct a minimal pandapower network.

  (ext_grid #1)      shunt - [104]  - trafo_3w - [105] - (sym_gen + asym_gen + asym_load + ward + motor)
   |                                    |
  [101] ---trafo- [102] ------------- [103]
   |                                    |
  -/-                               (load #31)
   |
  [106]
import pandapower as pp

def pandapower_simple_grid():
    net = pp.create_empty_network(f_hz=50)
    pp.create_bus(net, index=101, vn_kv=110)
    pp.create_bus(net, index=102, vn_kv=20)
    pp.create_bus(net, index=103, vn_kv=20)
    pp.create_bus(net, index=104, vn_kv=30.1)
    pp.create_bus(net, index=105, vn_kv=60)
    pp.create_bus(net, index=106, vn_kv=110)
    pp.create_ext_grid(net, index=1, in_service=True, bus=101, vm_pu=1, s_sc_max_mva=1e10, rx_max=0, va_degree=0)
    pp.create_transformer_from_parameters(net,index=101,hv_bus=101,lv_bus=102,i0_percent=3.0,pfe_kw=11.6,vkr_percent=10.22,sn_mva=40,vn_lv_kv=20.0,vn_hv_kv=110.0,vk_percent=17.8,vector_group="Dyn",shift_degree=30,tap_side="hv",tap_pos=2,tap_min=-1,tap_max=3,tap_step_percent=2,tap_neutral=1,parallel=2,)
    pp.create_line(net, index=101, from_bus=103, to_bus=102, length_km=1.23, parallel=2, df=0.2, std_type="NAYY 4x150 SE")
    pp.create_load(net, index=101, bus=103, p_mw=2.5, q_mvar=0.24, const_i_percent=26.0, const_z_percent=51.0, cos_phi=2)
    pp.create_switch(net, index=101, et="l", bus=103, element=101, closed=True)
    pp.create_switch(net, index=3021, et="b", bus=101, element=106, closed=True)
    pp.create_switch(net, index=321, et="t", bus=101, element=101, closed=True)
    pp.create_shunt(net, index=1201, in_service=True, bus=104, p_mw=0.1, q_mvar=0.55, step=3)
    pp.create_sgen(net, index=31, bus=105, p_mw=1.21, q_mvar=0.81)
    pp.create_asymmetric_sgen(net, index=32, bus=105, p_a_mw=0.1, p_b_mw=0.2, p_c_mw=3, q_a_mvar=0.01, q_b_mvar=0.01, q_c_mvar=0.01)
    pp.create_asymmetric_load(net, index=33, bus=105, p_a_mw=0.1, p_b_mw=0.2, p_c_mw=3, q_a_mvar=0.01, q_b_mvar=0.01, q_c_mvar=0.01)
    pp.create_ward(net, index=34, bus=105, ps_mw=0.1, qs_mvar=0.1, pz_mw=0.1, qz_mvar=0.1)
    pp.create_motor(net, bus=105, index=12, pn_mech_mw=0.1, cos_phi=0.9, loading_percent=80, efficiency_percent=90, scaling=0.8)
    pp.create_transformer3w_from_parameters(net,index=102,hv_bus=103,mv_bus=105,lv_bus=104,in_service=True,vn_hv_kv=20.0,vn_mv_kv=60.0,vn_lv_kv=30.1,sn_hv_mva=40,sn_mv_mva=100,sn_lv_mva=50,vk_hv_percent=10,vk_mv_percent=11,vk_lv_percent=12,vkr_hv_percent=1,vkr_mv_percent=2,vkr_lv_percent=4,i0_percent=0.1,pfe_kw=10,vector_group="Dyny",shift_mv_degree=30,shift_lv_degree=30,tap_side="lv",tap_pos=2,tap_min=1,tap_max=3,tap_step_percent=3,tap_neutral=2)
    return net

Instantiate the converter. Optionally provide the std_types dictionary to the converter as an additional argument.

The pandapower net can either have all parameters present in the respective component dataframes or it can have a type attribute which refers to std_types. The converter looks up the parameters from the respective component dataframes as the first priority. If they are not available here, it gets them from the std_types.

Then use load_input_data() to load the data and convert it to power-grid-model data. The additional information that is not used in the powerflow calculation but may be useful to link the results to the source data is stored in extra_info.

%%capture cap --no-stderr

from power_grid_model_io.converters import PandaPowerConverter

pp_net = pandapower_simple_grid()
converter = PandaPowerConverter(std_types=pp_net.std_types)
input_data, extra_info = converter.load_input_data(pp_net)

Let’s investigate the data we have converted, for one of the components: lines

import pandas as pd

# The node data is stored as a numpy structured array in input_data["line"]
display(input_data["line"])

# We can use pandas to display the data in a convenient tabular format
display(pd.DataFrame(input_data["line"]))

# The original indices are stored in the extra_data dictionary
display({i: extra_info[i] for i in input_data["line"]["id"]})
array([(6, 2, 1, 1, 1, 0.12792, 0.0492, 6.4206e-07, 0., nan, nan, nan, nan, 108.)],
      dtype={'names': ['id', 'from_node', 'to_node', 'from_status', 'to_status', 'r1', 'x1', 'c1', 'tan1', 'r0', 'x0', 'c0', 'tan0', 'i_n'], 'formats': ['<i4', '<i4', '<i4', 'i1', 'i1', '<f8', '<f8', '<f8', '<f8', '<f8', '<f8', '<f8', '<f8', '<f8'], 'offsets': [0, 4, 8, 12, 13, 16, 24, 32, 40, 48, 56, 64, 72, 80], 'itemsize': 88, 'aligned': True})
id from_node to_node from_status to_status r1 x1 c1 tan1 r0 x0 c0 tan0 i_n
0 6 2 1 1 1 0.12792 0.0492 6.420600e-07 0.0 NaN NaN NaN NaN 108.0
{6: {'id_reference': {'table': 'line', 'index': 101},
  'from_node': 2,
  'to_node': 1}}

2. Validate the data

Before we run a power flow calculation, it is wise validate the data. The most basic method is to use assert_valid_input_data(), which will raise a ValueError when the data is invalid. For more details on data validation, please consult the validation Example.

from power_grid_model import CalculationType
from power_grid_model.validation import assert_valid_input_data

assert_valid_input_data(input_data, calculation_type=CalculationType.power_flow, symmetric=True)

3. Run the calculation

Run powerflow calculation with the input_data and show the results for nodes.

from power_grid_model import PowerGridModel

pgm = PowerGridModel(input_data=input_data)
output_data = pgm.calculate_power_flow()

display(pd.DataFrame(output_data["node"]))
id energized u_pu u u_angle
0 0 1 1.000000 109999.999962 -1.798666e-10
1 1 1 0.973746 19474.919873 -5.239008e-01
2 2 1 0.973014 19460.275746 -5.237224e-01
3 3 1 0.969550 29183.446690 -1.045187e+00
4 4 1 0.971998 58319.874965 -1.044829e+00
5 5 1 1.000000 109999.999962 -1.798666e-10

Cross referencing objects

The converter has generated unique numerical IDs for all the components in the pandapower net, in fact for some special components like loads , multiple PGM components have been created, each with their own numerical ID. To find out which component belongs to which id, some helper functions have been defined:

print("PGM object #4:", converter.lookup_id(4))

print("Trafo with index=101:", converter.get_id("trafo", 101))
PGM object #4: {'table': 'bus', 'index': 105}
Trafo with index=101: 12

Saving the data as a JSON file

The data can be stored in a json file using the PgmJsonConverter. The file will be saved in the destination_file path supplied in the constructor.

from power_grid_model_io.converters import PgmJsonConverter
    
input_file = "data/pandapower/example_simple_input.json"
output_file = "data/pandapower/example_simple_output.json"

PgmJsonConverter(destination_file=input_file).save(data=input_data, extra_info=extra_info)
PgmJsonConverter(destination_file=output_file).save(data=output_data, extra_info=extra_info)

For debugging purposes, let’s check the output JSON. Notice that the node names are added to the nodes data.

from pathlib import Path
from IPython.display import display, Markdown

with Path(input_file).open() as json_file:
    display(Markdown(f"<pre style='max-height: 160px; white-space: pre'>{json_file.read()}</div>"))

with Path(output_file).open() as json_file:
    display(Markdown(f"<pre style='max-height: 160px; white-space: pre'>{json_file.read()}</div>"))
{
  "node":
    [
      {"id": 0, "u_rated": 110000.0, "id_reference": {"table": "bus", "index": 101}},
      {"id": 1, "u_rated": 20000.0, "id_reference": {"table": "bus", "index": 102}},
      {"id": 2, "u_rated": 20000.0, "id_reference": {"table": "bus", "index": 103}},
      {"id": 3, "u_rated": 30100.0, "id_reference": {"table": "bus", "index": 104}},
      {"id": 4, "u_rated": 60000.0, "id_reference": {"table": "bus", "index": 105}},
      {"id": 5, "u_rated": 110000.0, "id_reference": {"table": "bus", "index": 106}}
    ],
  "line":
    [
      {"id": 6, "from_node": 2, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.12792, "x1": 0.0492, "c1": 6.4206e-07, "tan1": 0.0, "i_n": 108.0, "id_reference": {"table": "line", "index": 101}}
    ],
  "source":
    [
      {"id": 7, "node": 0, "status": 1, "u_ref": 1.0, "u_ref_angle": 0.0, "sk": 1e+16, "rx_ratio": 0.0, "id_reference": {"table": "ext_grid", "index": 1}}
    ],
  "sym_load":
    [
      {"id": 8, "node": 2, "status": 1, "type": 0, "p_specified": 575000.0, "q_specified": 55200.0, "id_reference": {"table": "load", "name": "const_power", "index": 101}},
      {"id": 9, "node": 2, "status": 1, "type": 1, "p_specified": 1275000.0, "q_specified": 122400.0, "id_reference": {"table": "load", "name": "const_impedance", "index": 101}},
      {"id": 10, "node": 2, "status": 1, "type": 2, "p_specified": 650000.0, "q_specified": 62400.0, "id_reference": {"table": "load", "name": "const_current", "index": 101}},
      {"id": 18, "node": 4, "status": 1, "type": 0, "p_specified": 100000.0, "q_specified": 100000.0, "id_reference": {"table": "ward", "name": "ward_const_power_load", "index": 34}},
      {"id": 19, "node": 4, "status": 1, "type": 1, "p_specified": 100000.0, "q_specified": 100000.0, "id_reference": {"table": "ward", "name": "ward_const_impedance_load", "index": 34}},
      {"id": 20, "node": 4, "status": 1, "type": 0, "p_specified": 71111.11111111111, "q_specified": 34440.68301069173, "id_reference": {"table": "motor", "name": "motor_load", "index": 12}}
    ],
  "shunt":
    [
      {"id": 11, "node": 3, "status": 1, "g1": 0.00033112217304444763, "b1": -0.001821171951744462, "id_reference": {"table": "shunt", "index": 1201}}
    ],
  "transformer":
    [
      {"id": 12, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "u1": 110000.0, "u2": 20000.0, "sn": 80000000.0, "uk": 0.17800000000000002, "pk": 8176000.0, "i0": 0.03, "p0": 23200.0, "winding_from": 2, "winding_to": 1, "clock": 1, "tap_side": 0, "tap_pos": 2, "tap_min": -1, "tap_max": 3, "tap_nom": 1, "tap_size": 2200.0, "id_reference": {"table": "trafo", "index": 101}}
    ],
  "sym_gen":
    [
      {"id": 13, "node": 4, "status": 1, "type": 0, "p_specified": 1210000.0, "q_specified": 810000.0, "id_reference": {"table": "sgen", "index": 31}}
    ],
  "three_winding_transformer":
    [
      {"id": 14, "node_1": 2, "node_2": 4, "node_3": 3, "status_1": 1, "status_2": 1, "status_3": 1, "u1": 20000.0, "u2": 60000.0, "u3": 30100.0, "sn_1": 40000000.0, "sn_2": 100000000.0, "sn_3": 50000000.0, "uk_12": 0.1, "uk_13": 0.12, "uk_23": 0.11, "pk_12": 400000.0, "pk_13": 1600000.0, "pk_23": 1000000.0, "i0": 0.001, "p0": 10000.0, "winding_1": 2, "winding_2": 1, "winding_3": 0, "clock_12": 1, "clock_13": 1, "tap_side": 2, "tap_pos": 2, "tap_min": 1, "tap_max": 3, "tap_nom": 2, "tap_size": 903.0, "id_reference": {"table": "trafo3w", "index": 102}}
    ],
  "link":
    [
      {"id": 15, "from_node": 0, "to_node": 5, "from_status": 1, "to_status": 1, "id_reference": {"table": "switch", "name": "bus_to_bus", "index": 3021}}
    ],
  "asym_load":
    [
      {"id": 16, "node": 4, "status": 1, "type": 0, "p_specified": [100000.0, 200000.0, 3000000.0], "q_specified": [10000.0, 10000.0, 10000.0], "id_reference": {"table": "asymmetric_load", "index": 33}}
    ],
  "asym_gen":
    [
      {"id": 17, "node": 4, "status": 1, "type": 0, "p_specified": [100000.0, 200000.0, 3000000.0], "q_specified": [10000.0, 10000.0, 10000.0], "id_reference": {"table": "asymmetric_sgen", "index": 32}}
    ]
}
{
  "asym_gen":
    [
      {"id": 17, "energized": 1, "p": 3300000.0000000005, "q": 30000.000000000004, "i": 32.670416687651056, "s": 3300136.36081905, "pf": 0.9999586802470745, "id_reference": {"table": "asymmetric_sgen", "index": 32}, "node": 4}
    ],
  "asym_load":
    [
      {"id": 16, "energized": 1, "p": 3300000.0000000005, "q": 30000.000000000004, "i": 32.670416687651056, "s": 3300136.36081905, "pf": 0.9999586802470745, "id_reference": {"table": "asymmetric_load", "index": 33}, "node": 4}
    ],
  "line":
    [
      {"id": 6, "energized": 1, "loading": 0.5930290459172566, "p_from": -1763554.1135053905, "q_from": -1245081.6865976173, "i_from": 64.0471369590637, "s_from": 2158784.7316401307, "p_to": 1765096.6771171533, "q_to": 1169229.7700732222, "i_to": 62.767063741949805, "s_to": 2117230.39246925, "id_reference": {"table": "line", "index": 101}, "from_node": 2, "to_node": 1}
    ],
  "link":
    [
      {"id": 15, "energized": 1, "loading": 0.0, "p_from": 0.0, "q_from": -0.0, "i_from": 0.0, "s_from": 0.0, "p_to": 0.0, "q_to": -0.0, "i_to": 0.0, "s_to": 0.0, "id_reference": {"table": "switch", "name": "bus_to_bus", "index": 3021}, "from_node": 0, "to_node": 5}
    ],
  "node":
    [
      {"id": 0, "energized": 1, "u_pu": 0.9999999996523372, "u": 109999.99996175709, "u_angle": -1.798666001063812e-10, "id_reference": {"table": "bus", "index": 101}},
      {"id": 1, "energized": 1, "u_pu": 0.97374599364253, "u": 19474.9198728506, "u_angle": -0.5239008142519944, "id_reference": {"table": "bus", "index": 102}},
      {"id": 2, "energized": 1, "u_pu": 0.9730137872763268, "u": 19460.275745526535, "u_angle": -0.5237223960629773, "id_reference": {"table": "bus", "index": 103}},
      {"id": 3, "energized": 1, "u_pu": 0.9695497239124967, "u": 29183.44668976615, "u_angle": -1.04518706304991, "id_reference": {"table": "bus", "index": 104}},
      {"id": 4, "energized": 1, "u_pu": 0.9719979160849105, "u": 58319.87496509463, "u_angle": -1.044828700708015, "id_reference": {"table": "bus", "index": 105}},
      {"id": 5, "energized": 1, "u_pu": 0.9999999996523372, "u": 109999.99996175709, "u_angle": -1.798666001063812e-10, "id_reference": {"table": "bus", "index": 106}}
    ],
  "shunt":
    [
      {"id": 11, "energized": 1, "p": 282008.0001416396, "q": 1551044.0007790178, "i": 31.188122375690188, "s": 1576472.6462886913, "pf": 0.17888543819998318, "id_reference": {"table": "shunt", "index": 1201}, "node": 3}
    ],
  "source":
    [
      {"id": 7, "energized": 1, "p": 1798666.0004384827, "q": 3476627.872944676, "i": 20.545012571488463, "s": 3914350.6163946516, "pf": 0.4595055928063901, "id_reference": {"table": "ext_grid", "index": 1}, "node": 0}
    ],
  "sym_gen":
    [
      {"id": 13, "energized": 1, "p": 1210000.0, "q": 810000.0, "i": 14.414885714493, "s": 1456090.6565183362, "pf": 0.8309922150680065, "id_reference": {"table": "sgen", "index": 31}, "node": 4}
    ],
  "sym_load":
    [
      {"id": 8, "energized": 1, "p": 575000.0, "q": 55200.0, "i": 17.13761141048308, "s": 577643.5232909652, "pf": 0.9954236078405164, "id_reference": {"table": "load", "name": "const_power", "index": 101}, "node": 2},
      {"id": 9, "energized": 1, "p": 1207113.6835430216, "q": 115882.91362013007, "i": 35.977469977108086, "s": 1212663.3063904808, "pf": 0.9954236078405161, "id_reference": {"table": "load", "name": "const_impedance", "index": 101}, "node": 2},
      {"id": 10, "energized": 1, "p": 632458.9617296124, "q": 60716.06032604279, "i": 18.850149424695108, "s": 635366.6486790245, "pf": 0.9954236078405163, "id_reference": {"table": "load", "name": "const_current", "index": 101}, "node": 2},
      {"id": 18, "energized": 1, "p": 99999.99999999999, "q": 99999.99999999999, "i": 1.4000314325372134, "s": 141421.3562373095, "pf": 0.7071067811865475, "id_reference": {"table": "ward", "name": "ward_const_power_load", "index": 34}, "node": 4},
      {"id": 19, "energized": 1, "p": 94477.99488734086, "q": 94477.99488734086, "i": 1.3227216252536735, "s": 133612.0617154934, "pf": 0.7071067811865475, "id_reference": {"table": "ward", "name": "ward_const_impedance_load", "index": 34}, "node": 4},
      {"id": 20, "energized": 1, "p": 71111.11111111111, "q": 34440.68301069173, "i": 0.7821998773897324, "s": 79012.34567901235, "pf": 0.9, "id_reference": {"table": "motor", "name": "motor_load", "index": 12}, "node": 4}
    ],
  "three_winding_transformer":
    [
      {"id": 14, "energized": 1, "loading": 0.03152945292576947, "p_1": -651018.5317680555, "q_1": 1013282.7126517809, "i_1": 35.73216058618558, "s_1": 1204394.8623538653, "p_2": 944410.894001629, "q_2": 581081.3221020879, "i_2": 10.977386752839678, "s_2": 1108858.6202058704, "p_3": -282008.00014178595, "q_3": -1551044.0007787698, "i_3": 31.18812237568588, "s_3": 1576472.6462884734, "id_reference": {"table": "trafo3w", "index": 102}, "node_1": 2, "node_2": 4, "node_3": 3}
    ],
  "transformer":
    [
      {"id": 12, "energized": 1, "loading": 0.04892939318768632, "p_from": 1798665.9834270997, "q_from": 3476628.8259518775, "i_from": 20.545016973103277, "s_from": 3914351.4550149054, "p_to": -1765096.6771171836, "q_to": -1169229.7700735242, "i_to": 62.76706374195551, "s_to": 2117230.3924694424, "id_reference": {"table": "trafo", "index": 101}, "from_node": 0, "to_node": 1}
    ]
}