powergrid_synth.core

Core utilities shared by both transmission and distribution synthesis pipelines.

Submodules

Package Contents

class powergrid_synth.core.DCPowerFlow(graph)[source]

Lightweight DC Power Flow (DCPF) solver.

Solves the linearised power flow equations

\[\mathbf{P} = \mathbf{B}\,\boldsymbol{\theta}, \qquad F_{ij} = \frac{\theta_i - \theta_j}{x_{ij}}\]

where \(\mathbf{B}\) is the bus susceptance matrix, \(\boldsymbol{\theta}\) the vector of voltage angles (radians), \(\mathbf{P}\) the vector of net real-power injections (per-unit on a 100 MVA base), and \(F_{ij}\) the real-power flow on branch \((i, j)\).

The slack bus (reference angle \(\theta = 0\)) is chosen as the bus hosting the largest generator. The solver uses a sparse direct factorisation via scipy.sparse.linalg.spsolve.

This class is used by TransmissionLineAllocator to compute the flow distribution needed for impedance swapping and capacity assignment, following the methodology of Sadeghian et al. (2018).

Parameters:

graph (networkx.Graph) – Power grid graph. Each edge must have an 'x' attribute (per-unit reactance). Each node may have 'pg' (generation MW) and 'pl' (load MW) attributes.

See also

powergrid_synth.transmission.TransmissionLineAllocator

Uses DCPF for impedance swapping and capacity assignment.

run()[source]

Execute the DC power flow and return branch flows and bus angles.

Algorithm

  1. Build the susceptance matrix \(\mathbf{B}\) from branch reactances: \(B_{ij} = -1/x_{ij}\), \(B_{ii} = \sum_j 1/x_{ij}\).

  2. Form the net injection vector \(P_i = (P_{g_i} - P_{L_i}) / S_{\text{base}}\).

  3. Select the slack bus (largest generator), remove its row/column, and solve \(\mathbf{B}_{\text{red}}\, \boldsymbol{\theta}_{\text{red}} = \mathbf{P}_{\text{red}}\).

  4. Compute branch flows \(F_{ij} = (\theta_i - \theta_j) / x_{ij} \times S_{\text{base}}\) (MW).

returns:
  • flows (dict[tuple[int, int], float]) – Branch power flows in MW, keyed by (u, v) node pairs.

  • angles (dict[int, float]) – Bus voltage angles in radians, keyed by node id.

class powergrid_synth.core.DistributionGrid(incoming_graph_data=None, **attr)[source]

Bases: PowerGridGraph

Graph representation of a radial distribution feeder.

Inherits from PowerGridGraph and adds convenience properties for radial-tree distribution grids annotated with hop distances, node types, and cable parameters (Schweitzer et al. 2017 format).

classmethod from_nx(G)[source]

Create a DistributionGrid from any NetworkX graph.

All node, edge, and graph attributes are copied.

Parameters:

G (networkx.Graph)

Return type:

DistributionGrid

nodes_at_hop(h)[source]

Return list of nodes at the given hop distance.

Parameters:

h (int)

Return type:

list

nodes_by_type(node_type)[source]

Return list of nodes with the given node_type attribute.

Parameters:

node_type (str) – One of 'load', 'injection', or 'intermediate'.

Return type:

list

property is_radial: bool

True if the graph is a connected tree.

Return type:

bool

property max_hop: int

Maximum hop distance in the feeder.

Return type:

int

property root

Return the root node (hop distance 0).

property total_gen_mw: float

Total real-power generation (MW) across all injection nodes.

Return type:

float

property total_load_mw: float

Total real-power load (MW) across all load nodes.

Return type:

float

class powergrid_synth.core.GraphComparator(synth_graph, ref_graph, synth_label='Synthetic', ref_label='Reference (Real)')[source]

Compares a synthetic power grid against a reference (real-world) graph. Provides tabular metric comparisons and visual distribution overlaps, both globally and per voltage level.

Parameters:
  • synth_graph (networkx.Graph)

  • ref_graph (networkx.Graph)

  • synth_label (str)

  • ref_label (str)

_get_comparison_data(graph1, graph2)[source]

Helper to generate the dataframe for two specific graphs.

Parameters:
  • graph1 (networkx.Graph)

  • graph2 (networkx.Graph)

Return type:

pandas.DataFrame

compare_degree_distributions(show_pvalue=False)[source]

Computes Kolmogorov-Smirnov (KS) and Relative Hausdorff (RH) statistics between the degree distributions of the synthetic and reference graphs, per voltage level. Prints and returns the results table.

Parameters:

show_pvalue (bool) – If True, include the KS p-value column. Default False.

Returns:

pd.DataFrame with columns Level, KS Statistic, RH Distance (and KS p-value if show_pvalue is True).

Return type:

pandas.DataFrame

plot_all_levels_comparison(log_scale=True)[source]

Plots degree comparison for all common voltage levels in a single figure.

Parameters:

log_scale (bool)

plot_degree_comparison(synth_graph=None, ref_graph=None, ax=None, log_scale=True, fig_size=(8, 5), show_lines=False, title='Degree Distribution Comparison')[source]

Plots overlaid degree distributions.

Parameters:
  • synth_graph (Optional[networkx.Graph]) – Custom synthetic graph (or None for self.synth_graph).

  • ref_graph (Optional[networkx.Graph]) – Custom reference graph (or None for self.ref_graph).

  • ax (Optional[matplotlib.pyplot.Axes]) – Matplotlib axis to plot on. If None, creates new figure.

  • log_scale (bool) – Whether to use log-log scale (default True).

  • title (str) – Title for the plot.

  • fig_size (Tuple)

  • show_lines (bool)

plot_level_topology_comparison(figsize=(15, 10))[source]

Plots side-by-side bar comparisons for topology metrics per voltage level: Nodes, Edges, Diameter, Avg Path Length, Avg Clustering.

Parameters:

figsize (Tuple[int, int])

print_level_metrics()[source]

Iterates through voltage levels found in both graphs and prints metrics. Does NOT plot.

print_metric_comparison(synth_graph=None, ref_graph=None, title='GRAPH COMPARISON REPORT')[source]

Prints a side-by-side table of topological metrics.

Parameters:
  • synth_graph (Optional[networkx.Graph])

  • ref_graph (Optional[networkx.Graph])

  • title (str)

run_full_comparison(log_scale=True)[source]

Runs global comparison followed by per-level comparison.

Parameters:

log_scale (bool)

class powergrid_synth.core.GridAnalyzer(graph)[source]

A class to perform topological analysis on power grid graphs. Can be used for both synthetic and real-world grids.

Parameters:

graph (nx.Graph) – The networkx graph object representing the power grid.

analyze()[source]

Prints a comprehensive text summary of the grid.

get_basic_stats()[source]

Returns fundamental counts (nodes, edges, density).

Returns:

A dictionary containing ‘num_nodes’, ‘num_edges’, and ‘density’.

Return type:

Dict[str, Any]

get_clustering_metrics()[source]

Calculates global and average local clustering coefficients.

Return type:

Dict[str, float]

get_path_metrics()[source]

Calculates path-based metrics: Diameter and Average Shortest Path Length.

Return type:

Dict[str, Any]

plot_degree_distribution(ax=None, log_scale=True, figsize=(6, 4), title='Degree Distribution')[source]

Plots the degree distribution.

Parameters:
  • ax (Optional[matplotlib.pyplot.Axes]) – Matplotlib axes to plot on. If None, creates a new figure.

  • log_scale (bool) – If True, plots log-log. If False, plots linear histogram.

  • figsize (tuple) – Size of figure if creating a new one.

  • title (str) – Title of the plot.

class powergrid_synth.core.GridVisualizer[source]

Visualization module for synthetic power grids. Allows plotting the grid with different layouts including Yifan Hu, Kamada-Kawai, and Voltage Layered.

_create_interactive_window(graph, title, figsize)[source]

Helper to create a figure with a Dropdown menu for layout selection.

Parameters:
  • graph (networkx.Graph)

  • title (str)

  • figsize (Tuple[int, int])

_draw_bus_types_on_ax(ax, graph, layout_name, title, legend_loc='center left', legend_bbox=(1, 0.5), bbox_transform=None, show_impedance=False)[source]

Helper to draw bus type visualization on a specific axis.

Parameters:
  • graph (networkx.Graph)

  • layout_name (str)

  • title (str)

  • show_impedance (bool)

_draw_edges_impedance(ax, grid, pos, alpha=0.8)[source]

Helper to draw edges colored by impedance.

_draw_graph_on_ax(ax, graph, layout_name, title, show_labels, legend_loc='upper right', legend_bbox=None, bbox_transform=None, show_impedance=False)[source]

Helper to draw graph on a specific axis.

Parameters:

show_impedance (bool)

_find_tree_root(tree)[source]

Find the best root for a tree: prefer lowest voltage_level, then highest degree.

Parameters:

tree (networkx.Graph)

Return type:

Any

_get_layered_layout(graph)[source]

Custom layout: Places nodes in horizontal bands based on voltage level.

Parameters:

graph (networkx.Graph)

Return type:

Dict[int, numpy.ndarray]

_get_node_colors(graph)[source]

Assigns colors to nodes based on their ‘voltage_level’ attribute.

Parameters:

graph (networkx.Graph)

Return type:

List[Any]

_hierarchical_tree_layout(graph, layer_sep=1.0, node_sep=1.0)[source]

Hierarchical top-down layout suitable for tree/forest graphs.

Root at the top, children below. Handles disconnected forests by placing each component side-by-side.

Parameters:
  • graph (networkx.Graph)

  • layer_sep (float)

  • node_sep (float)

Return type:

Dict[Any, numpy.ndarray]

_radial_tree_layout(graph, radius_step=1.0)[source]

Radial layout suitable for tree/forest graphs.

Root at the center, each BFS layer on a concentric circle. Handles disconnected forests by rotating each component into its own sector.

Parameters:
  • graph (networkx.Graph)

  • radius_step (float)

Return type:

Dict[Any, numpy.ndarray]

_yifan_hu_layout(G, iterations=100, k=None)[source]

Implementation of the Yifan Hu force-directed layout algorithm.

Parameters:
  • G (networkx.Graph)

  • iterations (int)

  • k (Optional[float])

Return type:

Dict[int, numpy.ndarray]

plot_bus_types(graph, layout='kamada_kawai', title='Bus Type Visualization', show_impedance=False, figsize=(12, 10))[source]

Visualizes the grid coloring nodes by their Bus Type (Static). Option to show impedance on edges.

Parameters:
  • graph (networkx.Graph)

  • layout (str)

  • title (str)

  • show_impedance (bool)

  • figsize (Tuple[int, int])

plot_grid(graph, layout='kamada_kawai', title='Grid', show_labels=False, show_bus_types=False, show_impedance=False, figsize=(12, 10))[source]

Static plot function for grid topology. Options allow overlaying bus types or impedance features.

Parameters:
  • graph (networkx.Graph)

  • layout (str)

  • title (str)

  • show_labels (bool)

  • show_bus_types (bool)

  • show_impedance (bool)

  • figsize (Tuple[int, int])

plot_impedance(grid, layout='kamada_kawai', title='Transmission Line Impedance', figsize=(12, 10))[source]

Plots the grid with edges colored by their impedance magnitude (Z). Blue = Low Impedance (Strong), Red = High Impedance (Weak).

Parameters:
  • grid (networkx.Graph)

  • layout (str)

  • title (str)

  • figsize (Tuple[int, int])

plot_interactive(graph, title='Interactive Grid', figsize=(14, 10))[source]

Opens an interactive window for the full grid.

Parameters:
  • graph (networkx.Graph)

  • title (str)

  • figsize (Tuple[int, int])

plot_interactive_bus_types(graph, title='Interactive Bus Type Visualization', figsize=(14, 10))[source]

Opens an interactive window for Bus Type Visualization with layout selection.

Parameters:
  • graph (networkx.Graph)

  • title (str)

  • figsize (Tuple[int, int])

plot_interactive_voltage_level(graph, level, title=None, figsize=(12, 10))[source]

Opens an interactive window for a specific voltage level.

Parameters:
  • graph (networkx.Graph)

  • level (int)

  • title (Optional[str])

  • figsize (Tuple[int, int])

plot_load_gen_bubbles(grid, layout='kamada_kawai', title='Generation vs Load', show_impedance=False, figsize=(12, 10))[source]

Bubble plot showing generation and load magnitudes. Generators are blue squares, Loads are red circles. Size is proportional to capacity/load. Optionally plots impedance on edges.

Parameters:
  • grid (networkx.Graph)

  • layout (str)

  • title (str)

  • show_impedance (bool)

  • figsize (Tuple[int, int])

plot_subgraphs(grid, layout='kamada_kawai', title='Subgraphs by Voltage Level', show_impedance=False, figsize=(15, 5))[source]

Plots subgraphs for each voltage level side-by-side (max 3 per row).

Parameters:
  • grid (nx.Graph) – The main power grid graph.

  • layout (str) – Layout algorithm to use.

  • title (str) – Main title for the figure.

  • show_impedance (bool) – Whether to color edges by impedance.

  • figsize (Tuple[int, int]) – Base size for the figure (width, height for one row). Height will scale with the number of rows.

class powergrid_synth.core.HierarchicalAnalyzer(graph)[source]

A wrapper class that manages analysis for multi-level power grids. It can perform a global analysis and then iterate through each voltage level to perform subgraph analysis.

Parameters:

graph (networkx.Graph)

plot_all_levels(log_scale=True)[source]

Plots degree distributions for all voltage levels in a single figure (subplots).

Parameters:

log_scale (bool) – If True, uses log-log scale. If False, uses linear scale.

run_full_report(log_scale=True)[source]

Convenience method to run analysis and plotting. :param log_scale: Whether to plot the multi-level figure in log scale.

Parameters:

log_scale (bool)

run_global_analysis()[source]

Runs the GridAnalyzer on the entire graph.

run_level_analysis()[source]

Detects all voltage levels in the graph, extracts the subgraph for each, and runs the GridAnalyzer (stats only) on those subgraphs.

class powergrid_synth.core.PowerGridGraph(incoming_graph_data=None, **attr)[source]

Bases: networkx.Graph

Custom NetworkX Graph for Power Grids. Extends nx.Graph to support subgraph extraction by voltage level.

level(voltage_level)[source]

Returns a subgraph view containing only nodes at the specified voltage level.

Parameters:

voltage_level (int) – The voltage level index (e.g., 0, 1).

Returns:

A subgraph view of the grid.

Return type:

nx.Graph

class powergrid_synth.core.TransmissionGrid(incoming_graph_data=None, **attr)[source]

Bases: PowerGridGraph

Graph representation of a transmission-level power grid.

Inherits from PowerGridGraph and adds convenience methods specific to meshed, multi-voltage-level transmission networks.

property n_levels: int

Number of distinct voltage levels.

Return type:

int

property voltage_levels: list[int]

Sorted list of distinct voltage levels present in the grid.

Return type:

list[int]

powergrid_synth.core.extract_topology_params_from_graph(G)[source]

Extract CLC model inputs from an existing power grid graph.

This is “operation mode I”, where the generator is configured to mimic an existing reference grid. The function extracts per-level degree sequences and diameters (Phase 1 inputs), as well as pairwise transformer degree sequences (Phase 2 inputs).

Parameters:

G (networkx.Graph) – Power grid graph with a 'voltage_level' attribute on every node.

Returns:

'degrees_by_level'list of list of int

Intra-level degree sequences (one per voltage level, ordered by ascending voltage label).

'diameters_by_level'list of int

Diameter of the largest connected component of each same-voltage subgraph.

'transformer_degrees'dict

{(i, j): (deg_i_to_j, deg_j_to_i)} for each pair of voltage levels that has at least one transformer edge.

Return type:

dict

powergrid_synth.core.get_reference_stats(ref_sys_id)[source]

Returns the statistical parameters for a specified reference system.

Ported from ‘sg_refsys_stat.m’ (SynGrid).

Parameters:

ref_sys_id (int) – 1, 2, or 3.

Returns:

Dictionary containing statistical tables and parameters.

Return type:

dict