Open In Colab

PEGASE 9241 large-scale test

[1]:
import pandapower as pp
import pandapower.networks as pn
import pandas as pd
import numpy as np
import networkx as nx

from powergrid_synth import (
    PowerGridGenerator,
    BusTypeAllocator,
    GraphComparator,
    CapacityAllocator,
    LoadAllocator,
    GenerationDispatcher,
    TransmissionLineAllocator,
    pandapower_to_nx,
    nx_to_pandapower,
    extract_topology_params_from_graph,
)

Load the PEGASE 9241 grid using pandapower

[2]:
# 1. Load Real Grid and Convert
print("\n[1] Loading Reference Grid (PEGASE 9241)...")
net_real = pn.case9241pegase()
graph_real = pandapower_to_nx(net_real)
base_kv_list = graph_real.graph['base_kv_map']
print(f"Loaded {graph_real.number_of_nodes()} nodes and {graph_real.number_of_edges()} edges.")

[1] Loading Reference Grid (PEGASE 9241)...
Loaded 9241 nodes and 14207 edges.

Generate a synthetic grid

Extract Topology Characteristics from Graph

[3]:
print("\n[2] Analyzing Reference Topology...")
params = extract_topology_params_from_graph(graph_real)

[2] Analyzing Reference Topology...
Extracting topology parameters...

PowerGridGenerator

[4]:
# 3. Generate Synthetic Grid
print("\n[3] Generating Synthetic Clone...")
gen = PowerGridGenerator(seed=53)
synthetic_graph = gen.generate_grid(
    degrees_by_level=params['degrees_by_level'],
    diameters_by_level=params['diameters_by_level'],
    transformer_degrees=params['transformer_degrees'],
    keep_lcc=True
)

[3] Generating Synthetic Clone...
--- Starting Generation for 9 Voltage Levels ---
Generating Level 0...
  -> Level 0 Complete. Nodes: 5, Edges: 2
Generating Level 1...
  -> Level 1 Complete. Nodes: 144, Edges: 174
Generating Level 2...
  -> Level 2 Complete. Nodes: 2085, Edges: 2846
Generating Level 3...
  -> Level 3 Complete. Nodes: 4, Edges: 0
Generating Level 4...
  -> Level 4 Complete. Nodes: 3759, Edges: 4721
Generating Level 5...
  -> Level 5 Complete. Nodes: 838, Edges: 1013
Generating Level 6...
  -> Level 6 Complete. Nodes: 1854, Edges: 2031
Generating Level 7...
  -> Level 7 Complete. Nodes: 14, Edges: 3
Generating Level 8...
  -> Level 8 Complete. Nodes: 2077, Edges: 2555
Generating Transformer Connections...
  -> Connecting Level 0 <-> Level 2
  -> Connecting Level 0 <-> Level 3
  -> Connecting Level 1 <-> Level 2
  -> Connecting Level 1 <-> Level 5
  -> Connecting Level 2 <-> Level 3
  -> Connecting Level 2 <-> Level 4
  -> Connecting Level 2 <-> Level 6
  -> Connecting Level 2 <-> Level 7
  -> Connecting Level 2 <-> Level 8
  -> Connecting Level 3 <-> Level 4
  -> Connecting Level 4 <-> Level 6
  -> Connecting Level 4 <-> Level 7
  -> Connecting Level 4 <-> Level 8
  -> Connecting Level 6 <-> Level 8
Filtering for Largest Connected Component (LCC)...
  -> Kept 9282 nodes (removed 1498 isolated nodes)

Analysis

[5]:
# 5. Compare using the Library Module
print("\n[5] Running Comparative Analysis...")
comparator = GraphComparator(
    synth_graph=synthetic_graph,
    ref_graph=graph_real,
    synth_label="Synthetic",
    ref_label="PEGASE 9241"
)

[5] Running Comparative Analysis...
[6]:
comparator.plot_degree_comparison(log_scale=True, fig_size=(6,4), show_lines=True,)
../_images/examples_Pegase9241Test_12_0.png
[7]:
comparator.print_level_metrics()

============================================================
LEVEL 0 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes         1           3
             Edges         0           2
           Density  0.000000    0.666667
        Connected?       Yes         Yes
    Diameter (LCC)         0           2
Avg Path Len (LCC)    0.0000      1.3333
    Avg Clustering    0.0000      0.0000
      Transitivity    0.0000      0.0000
============================================================


============================================================
LEVEL 1 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes       135         126
             Edges       174         174
           Density  0.019237    0.022095
        Connected?        No         Yes
    Diameter (LCC)        19          17
Avg Path Len (LCC)    7.4254      6.8424
    Avg Clustering    0.1246      0.0789
      Transitivity    0.1392      0.0845
============================================================


============================================================
LEVEL 2 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes      1911        1814
             Edges      2842        2706
           Density  0.001557    0.001646
        Connected?        No          No
    Diameter (LCC)        77          73
Avg Path Len (LCC)   26.8720     24.5088
    Avg Clustering    0.1081      0.1066
      Transitivity    0.1239      0.2654
============================================================


============================================================
LEVEL 3 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes         1           2
             Edges         0           1
           Density  0.000000    1.000000
        Connected?       Yes         Yes
    Diameter (LCC)         0           1
Avg Path Len (LCC)    0.0000      1.0000
    Avg Clustering    0.0000      0.0000
      Transitivity    0.0000      0.0000
============================================================


============================================================
LEVEL 4 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes      3206        3185
             Edges      4683        4503
           Density  0.000912    0.000888
        Connected?        No          No
    Diameter (LCC)       129         127
Avg Path Len (LCC)   45.6479     47.7528
    Avg Clustering    0.1069      0.1236
      Transitivity    0.1174      0.4383
============================================================


============================================================
LEVEL 5 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes       707         728
             Edges       999         939
           Density  0.004003    0.003548
        Connected?        No          No
    Diameter (LCC)        48          44
Avg Path Len (LCC)   16.9501     17.4357
    Avg Clustering    0.1033      0.1142
      Transitivity    0.1133      0.1120
============================================================


============================================================
LEVEL 6 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes      1491        1530
             Edges      2004        1803
           Density  0.001804    0.001541
        Connected?        No          No
    Diameter (LCC)        82          78
Avg Path Len (LCC)   28.5089     25.8628
    Avg Clustering    0.0865      0.0561
      Transitivity    0.1037      0.1589
============================================================


============================================================
LEVEL 7 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes         7          10
             Edges         2           3
           Density  0.095238    0.066667
        Connected?        No          No
    Diameter (LCC)         1           1
Avg Path Len (LCC)    1.0000      1.0000
    Avg Clustering    0.0000      0.0000
      Transitivity    0.0000      0.0000
============================================================


============================================================
LEVEL 8 COMPARISON
============================================================
            Metric Synthetic PEGASE 9241
             Nodes      1823        1843
             Edges      2530        2323
           Density  0.001523    0.001369
        Connected?        No          No
    Diameter (LCC)        39          34
Avg Path Len (LCC)   15.4623     15.0676
    Avg Clustering    0.0297      0.1030
      Transitivity    0.0368      0.0899
============================================================

[8]:
comparator.compare_degree_distributions()

=================================================================
DEGREE DISTRIBUTION COMPARISON  (KS & Relative Hausdorff)
=================================================================
  Level KS Statistic RH Distance
Level 0       1.0000      1.0000
Level 1       0.1873      0.1250
Level 2       0.0957      0.2353
Level 3       1.0000      1.0000
Level 4       0.0876      0.2000
Level 5       0.0995      0.2000
Level 6       0.1382      0.1333
Level 7       0.0286      0.0000
Level 8       0.2133      0.1667
=================================================================

Note that the large KS/RH values come from the ill-posed degree distributions on the corresponding voltage levels.

Bus type assignment

[9]:
# 4. Allocate Bus Types
print("\n[4] Allocating Bus Types via AIS...")
allocator = BusTypeAllocator(synthetic_graph, entropy_model=0, bus_type_ratio=[80,60,0])
bus_types = allocator.allocate(max_iter=50)
nx.set_node_attributes(synthetic_graph, bus_types, name="bus_type")

[4] Allocating Bus Types via AIS...
Starting Bus Type Allocation (N=9282, M=14947)...
  Target Entropy Score (W*): 1.5717, Std Dev: 0.0031
  Iter 0: Best Error = 0.132178
  Iter 10: Best Error = 0.127606
  Iter 20: Best Error = 0.125055
  Iter 30: Best Error = 0.122702
  Iter 40: Best Error = 0.120258
[10]:
from collections import Counter

counts = Counter(bus_types.values())
total = sum(counts.values())
print(f"-----> Assignment Complete:")
print(f"       Generators: {counts['Gen']} ({counts['Gen']/total:.1%})")
print(f"       Loads:      {counts['Load']} ({counts['Load']/total:.1%})")
print(f"       Connectors: {counts['Conn']} ({counts['Conn']/total:.1%})")
-----> Assignment Complete:
       Generators: 5368 (57.8%)
       Loads:      3914 (42.2%)
       Connectors: 0 (0.0%)

Generation capacities and load settings

[11]:
print("\n[6] Allocating Capacity...")
cap_allocator = CapacityAllocator(synthetic_graph)
capacities = cap_allocator.allocate()
total_cap = sum(capacities.values())
print(f"Total Generation: {total_cap:.2f} MW")
nx.set_node_attributes(synthetic_graph, capacities, name="pg_max")

[6] Allocating Capacity...
Allocating Capacity for 5368 generators.
Total System Capacity Target: 336886.73 MW using Reference System 1
Total Generation: 336886.73 MW
[12]:
# Check top 10 generators
sorted_gens = sorted(capacities.items(), key=lambda x: x[1], reverse=True)
print("\nTop 5 Generators by Capacity:")
for node, cap in sorted_gens[:5]:
    print(f"  Node {node}: {cap:.2f} MW (Degree: {synthetic_graph.degree(node)})")

Top 5 Generators by Capacity:
  Node 6692: 1701.77 MW (Degree: 4)
  Node 7595: 1682.40 MW (Degree: 4)
  Node 7059: 1630.22 MW (Degree: 4)
  Node 8270: 1628.88 MW (Degree: 4)
  Node 8099: 1622.55 MW (Degree: 4)
[13]:
print("\n[7] Allocating Loads ...")
load_allocator = LoadAllocator(synthetic_graph, ref_sys_id=1)
loads = load_allocator.allocate(loading_level='H')

nx.set_node_attributes(synthetic_graph, loads, name="pl")

total_load = sum(loads.values())
print(f"Total Load: {total_load:.2f} MW")
print(f"System Loading: {total_load/total_cap:.1%}")

[7] Allocating Loads ...
Allocating Loads for 3914 load buses.
Total System Load Target: 241698.38 MW (Level: H)
Total Load: 241698.38 MW
System Loading: 71.7%
[14]:
print("\n[8] Dispatching Generation...")
dispatcher = GenerationDispatcher(synthetic_graph, ref_sys_id=1)
dispatch = dispatcher.dispatch()
nx.set_node_attributes(synthetic_graph, dispatch, name="pg")
total_gen = sum(dispatch.values())
print(f"-> Total Power Dispatched: {total_gen:.2f} MW")
print(f"-> Generation Reserve: { total_cap - total_gen:.2f} MW")

[8] Dispatching Generation...
-> Total Power Dispatched: 138527.01 MW
-> Generation Reserve: 198359.73 MW
[15]:
print("\n[9] Allocating Transmission Lines (Impedance & Capacity)...")
trans_allocator = TransmissionLineAllocator(synthetic_graph, ref_sys_id=1)
line_caps = trans_allocator.allocate()

total_lines = len(line_caps)
avg_cap = sum(line_caps.values()) / total_lines if total_lines > 0 else 0
print(f"-> Allocated {total_lines} Lines")
print(f"-> Average Line Capacity: {avg_cap:.2f} MVA")

[9] Allocating Transmission Lines (Impedance & Capacity)...
-> Allocated 14947 Lines
-> Average Line Capacity: 347.97 MVA

Convert to pandapower network

[16]:
synthetic_net = nx_to_pandapower(synthetic_graph, base_kv_map=base_kv_list)
synthetic_net
[16]:
This pandapower network includes the following parameter tables:
   - bus (9282 elements)
   - load (3914 elements)
   - gen (5367 elements)
   - ext_grid (1 element)
   - line (13234 elements)
   - trafo (1713 elements)
[17]:
pp.rundcpp(synthetic_net)
synthetic_net
[17]:
This pandapower network includes the following parameter tables:
   - bus (9282 elements)
   - load (3914 elements)
   - gen (5367 elements)
   - ext_grid (1 element)
   - line (13234 elements)
   - trafo (1713 elements)
 and the following results tables:
   - res_bus (9282 elements)
   - res_line (13234 elements)
   - res_trafo (1713 elements)
   - res_ext_grid (1 element)
   - res_load (3914 elements)
   - res_gen (5367 elements)

Compatible with pandapower

pandapower provides Newton-Raphson AC (pp.runpp) and linear DC (pp.rundcpp) power-flow solvers, and export to JSON, Excel, SQLite, Pickle.

Note: pp.runpp (AC) may not converge for large synthetic grids; pp.rundcpp (DC) always works. For AC power flow on large grids, use pypowsybl’s run_ac solver instead (shown below).

Compatible with PowSyBl

pypowsybl provides AC and DC load-flow solvers (run_ac, run_dc), interactive grid visualisation, and export to CGMES, XIIDM, MATPOWER, PSS/E, UCTE, AMPL, BIIDM, JIIDM.

Supported data export formats

PowerGridSynth provides a unified GridExporter class that wraps the built-in export functions of pandapower and pypowsybl, supporting 12+ industry-standard data formats out of the box.

Via

Formats

Methods

pandapower

JSON, Excel, SQLite, Pickle

to_json(), to_excel(), to_sqlite(), to_pickle()

pypowsybl

CGMES, XIIDM, MATPOWER, PSS/E, UCTE, AMPL, BIIDM, JIIDM

to_cgmes(), to_matpower(), to_psse(), to_pypowsybl(format=...)

[18]:
from powergrid_synth import GridExporter

exporter = GridExporter(synthetic_graph, base_kv_map=base_kv_list)

# --- pandapower-based exports ---
exporter.to_json("output/pegase9241_syn.json")

# --- pypowsybl-based exports ---
exporter.to_cgmes("output/pegase9241_syn_cgmes")
exporter.to_matpower("output/pegase9241_syn")
exporter.to_psse("output/pegase9241_syn")
exporter.to_pypowsybl("output/pegase9241_syn.xiidm", format="XIIDM")
-> pandapower JSON export: output/pegase9241_syn.json
-> pypowsybl CGMES export: output/pegase9241_syn_cgmes
-> pypowsybl MATPOWER export: output/pegase9241_syn
-> pypowsybl PSS/E export: output/pegase9241_syn
-> pypowsybl XIIDM export: output/pegase9241_syn.xiidm
[19]:
import pypowsybl as ppl
[20]:
from powergrid_synth import pandapower_to_pypowsybl
[21]:
ppl_net = pandapower_to_pypowsybl(synthetic_net)
[22]:
ppl_net
[22]:
Network(id=network, name=network, case_date=2026-04-14 11:44:49.021000+00:00, forecast_distance=0:00:00, source_format=)
[23]:
ppl.loadflow.run_ac(ppl_net)
[23]:
[ComponentResult(connected_component_num=0, synchronous_component_num=0, status=MAX_ITERATION_REACHED, status_text=Reached Newton-Raphson max iterations limit, iteration_count=16, reference_bus_id='sub_6692_0', slack_bus_results=[SlackBusResult(id='sub_6692_0', active_power_mismatch=19861584.66239525)], distributed_active_power=0.0)]