powergrid_synth

The main package for PowerGridSynth.

This package contains submodules for generating, analyzing, and exporting synthetic power grids, organized into three subpackages:

  • core: shared utilities (analysis, comparison, visualization, etc.)

  • transmission: CLC-based transmission grid synthesis pipeline

  • distribution: Schweitzer-based distribution feeder synthesis pipeline

Submodules

Package Contents

class powergrid_synth.BusTypeAllocator(graph, entropy_model=0, bus_type_ratio=None)[source]

Assigns bus types (Generator, Load, Connection) to a raw power grid topology using an Artificial Immune System (AIS) optimization algorithm.

The method, from Elyas and Wang (2016), exploits the observed non-trivial correlations between bus types and topology metrics (node degree, clustering coefficient) in realistic grids. A bus type entropy measure quantifies these correlations, and a target entropy \(W^*\) is derived from a scaling property fitted to real-world systems. The AIS then searches for an assignment whose entropy matches \(W^*\).

The pipeline is:

  1. Determine target bus type ratios \((r_G, r_L, r_C)\) from network size.

  2. Estimate \(W^*\) via Monte Carlo sampling of random assignments and the scaling relation \(W^* = \mu + \sigma \cdot d(N)\).

  3. Run AIS optimization (clonal selection, hypermutation, receptor editing) to find an assignment \(\mathbb{T}\) such that \(|W(\mathbb{T}) - W^*| < \epsilon\).

Two entropy definitions are supported:

  • Model 0 (\(W_0\)): standard entropy of bus/link type ratios. \(\mu\) is stable across network sizes.

  • Model 1 (\(W_1\)): generalized entropy weighted by \(N\) and \(M\). \(\mu\) grows with network size, giving better discrimination in large grids.

Parameters:
  • graph (nx.Graph) – NetworkX graph representing the grid topology (nodes and edges only; no bus type attributes required yet).

  • entropy_model (int) – Selects the entropy definition: 0 for \(W_0\), 1 for \(W_1\).

  • bus_type_ratio (list of float or None) – Optional target ratios [Gen, Load, Conn]. Values are normalized to sum to 1. If None, default ratios are chosen based on N.

References

_calculate_bus_ratios(assignment)[source]

Compute actual bus type ratios from an assignment vector.

Parameters:

assignment (np.ndarray) – Bus type vector of shape (N,) with values in {1, 2, 3}.

Returns:

[r_G, r_L, r_C] — actual ratios computed from the assignment.

Return type:

list of float

_calculate_entropy_score(bus_ratios, link_ratios)[source]

Compute the bus type entropy \(W\) for a given assignment.

Model 0 (\(W_0\)):

\[W_0 = -\sum_{k=1}^{3} r_k \ln r_k -\sum_{i,j=1}^{3} R_{ij} \ln R_{ij}\]

Model 1 (\(W_1\)):

\[W_1 = -\sum_{k=1}^{3} \ln(r_k) \cdot N_k -\sum_{i,j=1}^{3} \ln(R_{ij}) \cdot M_{ij}\]

where \(N_k = r_k \cdot N\) and \(M_{ij} = R_{ij} \cdot M\).

Parameters:
  • bus_ratios (list of float) – [r_G, r_L, r_C] — bus type ratios (should reflect the actual assignment, not necessarily the target ratios).

  • link_ratios (list of float) – [R_GG, R_LL, R_CC, R_GL, R_GC, R_LC].

Returns:

Entropy score \(W\).

Return type:

float

Compute ratios of the 6 link (edge) types for a given assignment.

Each edge is classified by the sorted pair of its endpoint types: GG (1,1), LL (2,2), CC (3,3), GL (1,2), GC (1,3), LC (2,3). The ratio is \(R_{ij} = M_{ij} / M\).

Parameters:

assignment (np.ndarray) – Bus type vector of shape (N,).

Returns:

[R_GG, R_LL, R_CC, R_GL, R_GC, R_LC].

Return type:

list of float

_estimate_w_star(monte_carlo_iters=2000)[source]

Estimate the target entropy \(W^*\) via Monte Carlo sampling.

Generates monte_carlo_iters random bus type assignments (with fixed target ratios), computes their entropies, and fits a normal distribution \(\mathcal{N}(\mu, \sigma^2)\). The target entropy is then:

\[W^* = \mu + \sigma \cdot d(N)\]

where \(d(N)\) is the piecewise scaling function from _get_d_parameter().

Parameters:

monte_carlo_iters (int, optional) – Number of random samples (default 2000).

Returns:

  • w_star (float) – Target entropy value.

  • std_w (float) – Standard deviation of the Monte Carlo entropy samples.

Return type:

Tuple[float, float]

_generate_random_assignment()[source]

Generate a random bus type assignment vector of length \(N\).

Types: 1 = Generator, 2 = Load, 3 = Connection. The counts are determined by self.ratio_types. Connection buses are preferentially placed on non-leaf nodes (degree > 1) to reflect the hub-like role of connection buses in realistic grids.

Returns:

Integer array of shape (N,) with values in {1, 2, 3}.

Return type:

np.ndarray

_get_d_parameter(n)[source]

Compute the normalized distance parameter \(d(N)\) for estimating the target entropy \(W^*\).

The piecewise scaling functions were fitted to realistic grids by Elyas and Wang (2016). For entropy model 0:

\[\begin{split}d_0(N) = \begin{cases} -1.39 \ln N + 6.79 & \text{if } \ln N \le 8 \\ -6.003 \times 10^{-14} (\ln N)^{15.48} & \text{if } \ln N > 8 \end{cases}\end{split}\]

For entropy model 1:

\[\begin{split}d_1(N) = \begin{cases} -1.748 \ln N + 8.576 & \text{if } \ln N \le 8 \\ -6.053 \times 10^{-22} (\ln N)^{24.1} & \text{if } \ln N > 8 \end{cases}\end{split}\]

Note

The \(d_0\) linear-segment coefficients here (-1.39, 6.79) follow the MATLAB SynGrid implementation and differ from the values in the paper (-1.721, 8).

Parameters:

n (int) – Network size.

Returns:

The distance parameter \(d(N)\).

Return type:

float

_get_ratios(n)[source]

Return default bus type ratios [Gen, Load, Conn] based on network size, derived from realistic reference systems.

  • \(N < 2000\)[0.23, 0.55, 0.22] (IEEE-300-like)

  • \(2000 \le N < 10000\)[0.33, 0.44, 0.23] (NYISO-like)

  • \(N \ge 10000\)[0.20, 0.40, 0.40] (WECC-like)

Parameters:

n (int) – Network size (number of buses).

Returns:

[r_G, r_L, r_C] summing to 1.0.

Return type:

list of float

_normalize_ratio(ratio)[source]

Normalize a user-supplied bus type ratio to sum to 1.0.

Parameters:

ratio (list of float) – Three values [Gen, Load, Conn].

Returns:

Normalized ratios summing to 1.0.

Return type:

list of float

Raises:

ValueError – If ratio does not contain exactly 3 positive values.

allocate(max_iter=100, population_size=20)[source]

Run the AIS optimization to find a bus type assignment.

Implements the Clonal Selection Principle:

  1. Monte Carlo estimation of \(W^*\) and convergence threshold \(\epsilon\) (see _estimate_w_star()).

  2. Initialize a population of K random assignments.

  3. Iterate until max_iter or best_error < epsilon:

    1. Evaluate fitness \(|W^* - W(\mathbb{T})|\) for each individual.

    2. Clonal selection — top-ranked individuals produce more clones: \(N_c = \text{round}(\beta \cdot s / r)\) where r is the rank.

    3. Hypermutation — clones are mutated with intensity proportional to their parent’s rank (worse → more mutations).

    4. Receptor editing — inject 10% fresh random solutions to maintain diversity and avoid local optima.

    5. Selection — combine elite, mutated clones, and fresh solutions; keep the top K.

  4. Return the best assignment found.

Parameters:
  • max_iter (int, optional) – Maximum number of AIS iterations (default 100).

  • population_size (int, optional) – Number of individuals surviving each generation (default 20).

Returns:

Mapping from node ID to bus type label ('Gen', 'Load', or 'Conn').

Return type:

dict[int, str]

plot_entropy_pdf(figsize=(10, 6))[source]

Plot the empirical PDF of entropy samples from the Monte Carlo estimation, with a fitted normal distribution overlay.

Must be called after allocate() or _estimate_w_star() so that self.w_samples is populated.

Parameters:

figsize (tuple of int, optional) – Figure size (width, height) in inches.

class powergrid_synth.CapacityAllocator(graph, ref_sys_id=1)[source]

Assigns generation capacities (PgMax) to generator buses in the grid.

Implements the three-stage methodology from Elyas et al. (2017):

  1. Total generation: Compute the aggregate generation capacity from a scaling law fitted to realistic grids: log Pg_tot(N) = -0.21 * log^2(N) + 2.06 * log(N) + 0.66.

  2. Individual capacities: Sample N_g individual capacities from an exponential distribution (with ~1% super-large outliers to capture the observed heavy tail).

  3. Correlated assignment: Assign capacities to generator buses using a 14x14 empirical 2D probability table (Tab_2D_Pgmax) that encodes the joint distribution of normalized capacity and normalized nodal degree. This preserves the observed Pearson correlation rho(P_bar, k_bar) in [0.25, 0.5] between capacity and degree.

Reference systems with pre-computed Tab_2D_Pgmax tables are available for NYISO-2935 (id=1), WECC-16944 (id=2), and a third system (id=3). A heuristic diagonal-bias table (id=0) is provided as a fallback.

Parameters:
  • graph (nx.Graph) – NetworkX graph with 'bus_type' node attributes already set (by BusTypeAllocator).

  • ref_sys_id (int) – Reference system for statistical tables (0=heuristic, 1=NYISO-2935, 2=WECC-16944, 3=additional reference).

References

_assignment_logic(norm_deg_pairs, norm_caps, tab_2d)[source]

Assign normalized capacities to buses via 2D-binning (Stage 3).

This implements the correlated assignment algorithm from Elyas et al. (2017) that preserves the empirical joint distribution of normalized capacity and normalized nodal degree. The steps are:

  1. Scale 2D table to counts: multiply tab_2d by N_g and round to integer targets n_rc for each (capacity-class r, degree-class c) cell. Adjust rounding so that the total equals N_g exactly.

  2. Compute marginals: column sums give degree-bin targets; row sums give capacity-bin targets.

  3. Bin by degree: sort generators by normalized degree, partition into 14 degree bins according to column-sum targets.

  4. Bin by capacity: sort normalized capacities, partition into 14 capacity bins according to row-sum targets.

  5. Nested assignment loop: for each degree bin c = 1..14 and each capacity bin r = 14..1 (high to low): randomly sample n_rc capacities from capacity bin r (without replacement) and assign them to unassigned generators in degree bin c.

  6. Reassemble all bins into the output array.

Parameters:
  • norm_deg_pairs (np.ndarray) – Shape (N_g, 2) — columns are [NodeID, NormalizedDegree].

  • norm_caps (np.ndarray) – Shape (N_g,) — normalized capacity values in [0, 1].

  • tab_2d (np.ndarray) – A 14x14 joint-probability matrix (rows=capacity classes, columns=degree classes).

Returns:

Shape (N_g, 3) — columns are [NodeID, NormalizedDegree, NormalizedCapacity].

Return type:

np.ndarray

_generate_heuristic_tab_2d()[source]

Generate a heuristic 14x14 joint-probability table as a fallback.

When no reference system data is selected (ref_sys_id=0), this method produces a synthetic table using a Gaussian-decay diagonal bias: weight(r, c) = exp(-0.5 * |r - c|), where rows represent capacity classes and columns represent degree classes (both ordered low-to-high). The matrix is normalized to sum to 1.

This simulates the positive correlation between nodal degree and generation capacity observed in realistic grids, without relying on empirical data from a specific reference system.

Returns:

A 14x14 probability matrix (sums to 1).

Return type:

np.ndarray

_get_default_tab_2d()[source]

Return the Tab_2D_Pgmax table for the selected reference system.

The table is a 14x14 matrix representing the empirical joint PDF Pr((P_bar_gn_max, k_bar_n) in A) discretized into 14 capacity classes (rows, low-to-high) and 14 nodal-degree classes (columns, low-to-high). Tables for real reference systems are loaded from reference_data.get_reference_stats() (ported from the MATLAB SynGrid file sg_refsys_stat.m).

Returns:

A 14x14 probability matrix.

Return type:

np.ndarray

_initial_generation_distribution(total_gen)[source]

Sample individual generation capacities from the empirical distribution.

Following Elyas et al. (2017), more than 99% of generation units in realistic grids follow an exponential distribution. About 1% have extremely large capacities that fall outside the exponential range.

The procedure is:

  1. Draw N_g samples from Exp(mu) where mu = total_gen / N_g.

  2. Replace ~1% of the samples with “super-large” values drawn uniformly from [max(P), 3 * max(P)].

  3. If the sum deviates more than 5% above or 10% below total_gen, rescale all values proportionally.

  4. Normalize by the maximum capacity.

Parameters:

total_gen (float) – Target total generation capacity (MW).

Returns:

  • p_caps (np.ndarray) – Raw (possibly rescaled) capacity values, shape (N_g,).

  • max_r_pgmax (float) – Maximum capacity value, used for normalization.

  • normalized_r_pgmax (np.ndarray) – Capacities normalized to [0, 1] by dividing by max_r_pgmax.

Return type:

Tuple[numpy.ndarray, float, numpy.ndarray]

allocate(tab_2d=None)[source]

Run the full generation-capacity allocation pipeline.

Executes the three-stage methodology from Elyas et al. (2017):

  1. Compute total generation capacity from the scaling law: Pg_tot = 10^(-0.21 * log10(N)^2 + 2.06 * log10(N) + 0.66).

  2. Sample individual capacities, normalize them and the generator nodal degrees by their respective maxima so that both lie in [0, 1]: P_bar = P / max(P), k_bar = k / max(k).

  3. Assign normalized capacities to generator buses via 2D binning using Tab_2D_Pgmax.

  4. Denormalize: Pg_max = P_bar * max(P).

Parameters:

tab_2d (np.ndarray or None, optional) – Custom 14x14 probability matrix. If None, the default table for the selected ref_sys_id is used.

Returns:

Mapping from generator node ID to its assigned capacity Pg_max (MW).

Return type:

dict[int, float]

class powergrid_synth.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.GenerationDispatcher(graph, ref_sys_id=1)[source]

Assign active-power dispatch to each generator bus.

The algorithm follows Sadeghian et al. (2018) (Section III):

  1. Uncommitted units (10–20 %): \(\alpha = 0\), selected via targets drawn from Uniform[0, 0.6].

  2. Partially committed units (40–50 %): selected via exponential distribution on capacity; dispatch factors assigned through a 2-D bin-matching table Tab_2D_Pg (\(14 \times 10\)).

  3. Fully committed units (remainder): \(\alpha = 1\).

  4. Balancing loop: iteratively adjusts dispatch to match total load within 1 % tolerance.

Parameters:
  • graph (networkx.Graph) – Power grid graph. Generator nodes must have 'bus_type' == 'Gen' and 'pg_max' (MW) attributes. Load nodes must have 'pl' (MW).

  • ref_sys_id (int, optional) – Reference system for statistical tables (1 = NYISO-2935, 2 = WECC-16994, 3 = additional reference). Default is 1.

alpha_mod

Loading-level flag from the reference system. When 0 all alphas are Uniform[0, 1]; otherwise 0.5 % receive negative dispatch (e.g., pumped-storage hydro).

Type:

int

mu_committed

Exponential-distribution parameter for committed-unit capacities.

Type:

float

tab_2d_pg

2-D empirical PMF table (14 capacity bins × 10 alpha bins).

Type:

numpy.ndarray

_assign_alphas(units, alphas)[source]

Assign dispatch factors to committed units via 2-D bin matching.

Units are sorted by normalised capacity and alphas by value, then distributed into bins defined by Tab_2D_Pg (14 capacity bins \(\times\) 10 alpha bins). Within each bin, units and alphas are paired randomly (high-to-low bin traversal). Any leftovers are paired sequentially as a fallback.

This reproduces the empirical joint distribution \(f(\bar{P}_{g}^{\max}, \alpha)\) from the reference system (Sadeghian et al., 2018, Table I).

Parameters:
  • units (numpy.ndarray, shape (n, 2)) – [bus_id, normalised_capacity].

  • alphas (numpy.ndarray, shape (n, 1)) – Dispatch-factor values from _generate_alphas().

Returns:

[bus_id, normalised_capacity, alpha].

Return type:

numpy.ndarray, shape (m, 3)

_generate_alphas(n_comm)[source]

Generate dispatch factors for partially committed units.

When alpha_mod == 0 (e.g. NYISO), all \(\alpha\) values are drawn from Uniform[0, 1]. When alpha_mod != 0 (e.g. WECC), 99.5 % are Uniform[0, 1] and 0.5 % are negative, representing reverse dispatch such as pumped-storage hydro.

Parameters:

n_comm (int) – Number of committed units requiring \(\alpha\) values.

Returns:

Dispatch-factor values.

Return type:

numpy.ndarray, shape (n_comm, 1)

_select_committed(norm_pg_max, total_units_count)[source]

Select generators to be partially committed (\(0 < \alpha < 1\)).

Selects 40–50 % of total generator count. 99 % of these are chosen by matching to targets drawn from an exponential distribution with parameter \(\mu_{\text{committed}}\); the remaining 1 % are drawn from the extreme tail Uniform[0.5, 1.0], capturing super-large units (Sadeghian et al., 2018, Sec. III-A).

Parameters:
  • norm_pg_max (numpy.ndarray, shape (n, 2)) – Remaining units after uncommitted selection: [bus_id, normalised_capacity].

  • total_units_count (int) – Original total number of generator units (before any selection).

Returns:

  • committed (numpy.ndarray, shape (m, 2)) – Committed units: [bus_id, norm_cap].

  • remaining (numpy.ndarray, shape (n-m, 2)) – Units not selected (will become fully committed).

Return type:

Tuple[numpy.ndarray, numpy.ndarray]

_select_uncommitted(norm_pg_max)[source]

Select generators to be uncommitted (\(\alpha = 0\)).

Randomly selects 10–20 % of total generator units. Target capacities are drawn from Uniform[0, 0.6] and the unit whose normalised capacity is closest to each target is selected. This reproduces the empirical observation that uncommitted units tend to be small or medium-size (Sadeghian et al., 2018, Sec. III).

Parameters:

norm_pg_max (numpy.ndarray, shape (n, 2)) – Array with columns [bus_id, normalised_capacity].

Returns:

  • uncommitted (numpy.ndarray, shape (m, 3)) – Uncommitted units: [bus_id, norm_cap, alpha=0].

  • remaining (numpy.ndarray, shape (n-m, 2)) – Units not selected.

Return type:

Tuple[numpy.ndarray, numpy.ndarray]

dispatch()[source]

Run the full generation dispatch pipeline.

Implements the algorithm of Sadeghian et al. (2018):

  1. Collect generator buses and normalise capacities by \(P^{\max}_{g_{\max}}\).

  2. Partition generators into uncommitted (\(\alpha = 0\)), partially committed (\(0 < \alpha < 1\)), and fully committed (\(\alpha = 1\)).

  3. Assign dispatch factors to partially committed units via the 2-D bin-matching table Tab_2D_Pg.

  4. Iteratively balance total generation against total load (1 % tolerance, up to 50 iterations) by scaling committed \(\alpha\) values and toggling uncommitted / full-load units on or off.

  5. Convert normalised dispatch back to MW: \(P_{g_i} = \alpha_i \cdot \bar{P}_{g_i}^{\max} \cdot P^{\max}_{g_{\max}}\).

Returns:

Mapping of generator bus ID to dispatched active power (MW).

Return type:

dict

class powergrid_synth.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.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.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.InputConfigurator(seed=None)[source]

Generate detailed input sequences for PowerGridGenerator from high-level parameters.

This is “operation mode II”, where the user specifies only the number of nodes, average degree, diameter, and distribution type for each voltage level, rather than providing explicit degree sequences. The configurator uses DegreeDistributionOptimizer to fit distribution parameters and then samples degree sequences.

See Section 6 of Aksoy et al. (2018) for the synthetic input generation guidelines.

Parameters:

seed (int or None, optional) – Random seed for reproducibility. Default is None.

_generate_optimized_degrees(n_nodes, avg_degree, max_degree, dist_type)[source]

Generate a degree sequence by optimizing DGLN or DPL parameters.

First calls DegreeDistributionOptimizer.optimize() to find the distribution parameters matching avg_degree and max_degree, then samples n_nodes degrees from the resulting PDF.

Parameters:
  • n_nodes (int) – Number of nodes in the same-voltage subgraph.

  • avg_degree (float) – Target average degree \(\bar{d}\).

  • max_degree (int) – Maximum degree \(d_{\max}\) (PDF support is 1..max_degree).

  • dist_type (str) – 'dgln' for generalized log-normal or 'dpl' for power law.

Returns:

Sampled degree sequence of length n_nodes.

Return type:

list of int

_generate_poisson_degrees(n_nodes, avg_degree)[source]

Generate a degree sequence from a Poisson distribution.

Parameters:
  • n_nodes (int) – Number of nodes.

  • avg_degree (float) – Mean of the Poisson distribution \(\lambda = \bar{d}\).

Returns:

Sampled degree sequence of length n_nodes.

Return type:

list of int

_generate_transformer_simple(n_nodes, prob)[source]

Generate binary transformer degrees (simple probabilistic model).

Each node independently gets transformer degree 0 or 1 with probability 1 - prob and prob, respectively.

Parameters:
  • n_nodes (int) – Number of nodes.

  • prob (float) – Probability that a node participates in a transformer edge.

Returns:

Transformer degree list (0 or 1 per node).

Return type:

list of int

_generate_transformer_stars(n_i, n_j, c=0.174, gamma=4.15)[source]

Generate transformer degrees using the disjoint k-stars model.

Follows Section 6.2 of Aksoy et al. (2018):

  1. Number of star centres: \(h(n_i, n_j) = c \cdot \min(n_i, n_j)\) with \(c \approx 0.174\).

  2. Star sizes sampled from a discrete power law \(P(k) \propto k^{-\gamma}\) with \(\gamma \approx 4.15\).

  3. Each star is randomly assigned a centre in level i or j.

  4. Degree lists are padded with zeros and shuffled.

Parameters:
  • n_i (int) – Number of nodes in the two voltage levels.

  • n_j (int) – Number of nodes in the two voltage levels.

  • c (float, optional) – Coefficient for the number of active star centres. Default is 0.174 (paper optimum).

  • gamma (float, optional) – Power-law exponent for star sizes. Default is 4.15 (paper optimum, Section 6.2).

Returns:

(t_i, t_j) — transformer degree sequences for levels i and j, each of length n_i and n_j respectively.

Return type:

tuple of (list of int, list of int)

create_params(levels, inter_connections)[source]

Generate the full parameter set for PowerGridGenerator.generate_grid().

Parameters:
  • levels (list of dict) –

    One dict per voltage level with keys:

    • 'n' (int): number of nodes.

    • 'avg_k' (float): target average degree.

    • 'diam' (int): target diameter.

    • 'dist_type' (str): 'dgln', 'dpl', or 'poisson'.

    • 'max_k' (int, optional): maximum degree (default: min(n - 1, 50)). For 'dpl' the paper suggests \(d_{\max} \approx 1.517\,n^{1/4}\); for 'dgln' \(\bar{d} \approx 2.425 \pm 0.185\) is consistent across subgraphs (Section 6.1 of Aksoy et al., 2018).

  • inter_connections (dict) –

    Mapping (i, j) -> config for transformer connections. Config is either:

    • {'type': 'k-stars', 'c': 0.174, 'gamma': 4.15}

    • {'type': 'simple', 'p_i_j': float, 'p_j_i': float}

Returns:

Keys 'degrees_by_level', 'diameters_by_level', and 'transformer_degrees', ready to be unpacked into PowerGridGenerator.generate_grid().

Return type:

dict

class powergrid_synth.LoadAllocator(graph, ref_sys_id=1)[source]

Assigns active power loads (PL) to load buses in the grid.

Implements the load-setting methodology from Elyas et al. (2017), which mirrors the generation-capacity approach in CapacityAllocator:

  1. Total load: Compute an aggregate load target, either from a deterministic scaling formula or as a fraction (light / medium / heavy) of the total installed generation capacity.

  2. Individual loads: Sample N_l individual loads from an exponential distribution (with ~1% super-large outliers).

  3. Correlated assignment: Assign loads to load buses using a 14x14 empirical 2D probability table (Tab_2D_load) that encodes the joint distribution of normalized load demand and normalized nodal degree.

Reference systems with pre-computed Tab_2D_load tables are available for NYISO-2935 (id=1), WECC-16944 (id=2), and a third system (id=3). A heuristic diagonal-bias table (id=0) is provided as a fallback.

Parameters:
  • graph (nx.Graph) – NetworkX graph with 'bus_type' and (for non-deterministic loading levels) 'pg_max' node attributes already set.

  • ref_sys_id (int) – Reference system for statistical tables (0=heuristic, 1=NYISO-2935, 2=WECC-16944, 3=additional reference).

References

_assignment_logic(norm_deg_pairs, norm_vals, tab_2d)[source]

Assign normalized values to buses via 2D-binning.

Shared logic with CapacityAllocator._assignment_logic(). See that method’s docstring for the full algorithm description. In brief:

  1. Scale the 14x14 probability table to integer target counts.

  2. Derive degree-bin (column sums) and value-bin (row sums) targets.

  3. Sort buses by normalized degree, partition into 14 bins.

  4. Sort normalized values, partition into 14 bins.

  5. For each (degree bin, value bin) pair—iterating degree bins 1→14, value bins 14→1—randomly assign the target count of values to unassigned buses.

Parameters:
  • norm_deg_pairs (np.ndarray) – Shape (N, 2) — columns are [NodeID, NormalizedDegree].

  • norm_vals (np.ndarray) – Shape (N,) — normalized load values in [0, 1].

  • tab_2d (np.ndarray) – A 14x14 joint-probability matrix (rows=value classes, columns=degree classes).

Returns:

Shape (N, 3) — columns are [NodeID, NormalizedDegree, NormalizedValue].

Return type:

np.ndarray

_calculate_total_load(loading_level, total_gen_capacity)[source]

Compute the total system load target.

Four strategies are supported, following Elyas et al. (2017):

  • 'D'Deterministic: scaling formula fitted to realistic grids: Pl_tot = 10^(-0.2 * log10(N)^2 + 1.98 * log10(N) + 0.58).

  • 'L'Light loading: 30–40% of total generation capacity.

  • 'M'Medium loading: 50–60% of total generation capacity.

  • 'H'Heavy loading: 70–80% of total generation capacity.

Parameters:
  • loading_level (str) – One of 'D', 'L', 'M', 'H'.

  • total_gen_capacity (float) – Sum of all generator pg_max values (MW). Only used when loading_level is not 'D'.

Returns:

Total system load target (MW).

Return type:

float

Raises:

ValueError – If loading_level is not one of the four valid options.

_get_tab_2d_load()[source]

Return the Tab_2D_load table for the selected reference system.

The table is a 14x14 matrix representing the empirical joint PDF Pr((P_bar_ln, k_bar_n) in A) discretized into 14 load-demand classes (rows, low-to-high) and 14 nodal-degree classes (columns, low-to-high). When ref_sys_id=0, a heuristic table with Gaussian-decay diagonal bias exp(-0.5 * |r - c|) is generated instead.

Returns:

A 14x14 probability matrix (sums to 1).

Return type:

np.ndarray

_initial_load_distribution(total_load)[source]

Sample individual load demands from the empirical distribution.

Mirrors CapacityAllocator._initial_generation_distribution(). More than 99% of load demands follow an exponential distribution; ~1% are replaced by super-large outliers drawn uniformly from [max(P), 3 * max(P)]. If the sum deviates more than 5% above or 10% below total_load, all values are rescaled proportionally.

Parameters:

total_load (float) – Target aggregate load (MW).

Returns:

  • p_loads (np.ndarray) – Raw (possibly rescaled) load values, shape (N_l,).

  • max_r_pl (float) – Maximum load value, used for normalization.

  • normalized_r_pl (np.ndarray) – Loads normalized to [0, 1] by dividing by max_r_pl.

Return type:

Tuple[numpy.ndarray, float, numpy.ndarray]

allocate(loading_level='H')[source]

Run the full load-allocation pipeline.

Executes the three-stage methodology (analogous to CapacityAllocator.allocate()):

  1. Compute total system load from loading_level strategy.

  2. Sample individual loads, normalize them and the load-bus nodal degrees by their respective maxima: P_bar = P / max(P), k_bar = k / max(k).

  3. Assign normalized loads to load buses via 2D binning using Tab_2D_load.

  4. Denormalize: PL = P_bar * max(P).

Parameters:

loading_level (str, optional) –

Loading strategy (default 'H'):

  • 'D' — deterministic scaling formula.

  • 'L' — light (30–40% of generation capacity).

  • 'M' — medium (50–60% of generation capacity).

  • 'H' — heavy (70–80% of generation capacity).

Returns:

Mapping from load node ID to its assigned active power load (MW).

Return type:

dict[int, float]

allocate_reactive(active_loads, pf_min=0.85, pf_max=0.97)[source]

Derive reactive power loads from active loads using power factors.

For each load bus, a power factor is sampled uniformly from [pf_min, pf_max] (lagging) and the reactive load is computed as ql = pl * tan(arccos(pf)).

Theory reference: https://www.phasetophase.nl/book/book_2_9.html#_9.5.2

Parameters:
  • active_loads (dict[int, float]) – Mapping from load node ID to active power load (MW), as returned by allocate().

  • pf_min (float, optional) – Minimum power factor (default 0.85).

  • pf_max (float, optional) – Maximum power factor (default 0.97).

Returns:

Mapping from load node ID to reactive power load (Mvar).

Return type:

dict[int, float]

class powergrid_synth.PowerGridGenerator(seed=None)[source]

Generative model for an entire power grid graph on k voltage levels.

Implements Algorithm 4 (CLCStars) from Aksoy et al. (2018). Phase 1 generates each same-voltage subgraph via the CLC model, and Phase 2 inserts transformer edges via the random-star model.

Parameters:

seed (int or None, optional) – Random seed for reproducibility. Default is None.

_generate_subgraphs(k, degrees_by_level, diameters_by_level, level_offsets, level_node_counts, all_edges)[source]

Generate same-voltage subgraphs (Phase 1) for all k levels.

For each voltage level, runs Preprocessor.run_setup() followed by EdgeCreator.generate_edges(), converting local node IDs to global IDs using cumulative offsets.

Parameters:
  • k (int) – Number of voltage levels.

  • degrees_by_level (list of list of int) – Desired degree sequences, one per voltage level.

  • diameters_by_level (list of int) – Desired diameters, one per voltage level.

  • level_offsets (list of int) – Mutated in place — filled with the global node-ID offset for each level.

  • level_node_counts (list of int) – Mutated in place — filled with the actual node count (after degree-sequence inflation) for each level.

  • all_edges (dict) – Mutated in place{(u, v): {'type': 'line'}} entries are added for each generated edge.

Example

1# Level 0 generated (5 nodes) -> Local IDs: 0, 1, 2, 3, 4
2level_offsets[0] = 0
3current_global_offset becomes 5
4
5# Level 1 generated (3 nodes) -> Local IDs: 0, 1, 2
6# We shift them by current_global_offset (5):
7# Global IDs: 5, 6, 7
8level_offsets[1] = 5
9current_global_offset becomes 8
_generate_transformer_connections(k, transformer_degrees, level_node_counts, level_offsets, all_edges)[source]

Insert transformer edges between voltage levels (Phase 2).

For each pair of levels (i, j), runs TransformerConnector.generate_transformer_edges() and converts local node IDs to global IDs.

Parameters:
  • k (int) – Number of voltage levels.

  • transformer_degrees (dict) – Mapping (i, j) -> (t_i_j, t_j_i) of transformer degree lists.

  • level_node_counts (list of int) – Actual node counts per level (from Phase 1).

  • level_offsets (list of int) – Global node-ID offsets per level (from Phase 1).

  • all_edges (dict) – Mutated in place{(u, v): {'type': 'transformer'}} entries are added.

generate_grid(degrees_by_level, diameters_by_level, transformer_degrees, keep_lcc=False)[source]

Generate a multi-level power grid graph (CLCStars, Algorithm 4).

Runs Phase 1 (CLC for each voltage level) and Phase 2 (random-star transformer edges for each pair of levels), then combines results.

Parameters:
  • degrees_by_level (list of list of int) – Desired degree sequences \(\mathbf{d}^{X_1},\dots,\mathbf{d}^{X_k}\), one per voltage level.

  • diameters_by_level (list of int) – Desired diameters \(\delta^{X_1},\dots,\delta^{X_k}\), one per voltage level.

  • transformer_degrees (dict) – Mapping (i, j) -> (t_i_j, t_j_i) where t_i_j is the transformer degree list for level-i nodes toward level j, and t_j_i is the reverse.

  • keep_lcc (bool, optional) – If True, return only the largest connected component with contiguous node IDs. Default is False.

Returns:

The generated grid graph with voltage_level node attributes and type ('line' or 'transformer') edge attributes.

Return type:

PowerGridGraph

class powergrid_synth.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.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]

class powergrid_synth.TransmissionLineAllocator(graph, ref_sys_id=1)[source]

Allocate impedance and capacity limits to transmission lines.

The algorithm follows Sadeghian et al. (2018) and the SynGrid MATLAB toolbox (sg_line.m, sg_flow_lim.m):

  1. Impedance generation — magnitudes \(Z\) from LogNormal(\(\mu\), \(\sigma\)), angles \(\varphi\) from a Lévy stable distribution \(S(\alpha_s, \beta_s, \gamma_s, \delta_s)\). Then \(X = Z \sin\varphi\), \(R = Z \cos\varphi\).

  2. DCPF-based swapping — sort impedances ascending and flows descending, then randomly swap ~20–30 % of assignments to introduce variance while preserving the negative correlation between impedance and flow.

  3. (Optional) Topology refinement — iteratively add low-impedance lines between max angle-difference bus pairs and remove weak high-\(X\) lines until the angle spread is below a size-dependent threshold.

  4. Capacity assignment — gauge ratios \(\beta_l = F_l / F_l^{\max}\) from Exponential(\(\mu_\beta\)) with overload injection; assigned via 2-D table Tab_2D_FlBeta. Capacity limits: \(F_l^{\max} = F_l / \beta_l\).

Parameters:
  • graph (networkx.Graph) – Power grid graph with nodal generation/load attributes.

  • ref_sys_id (int, optional) – Reference system (1 = NYISO-2935, 2 = WECC-16994). Default 1.

stab_params

Lévy stable parameters \([\alpha_s, \beta_s, \gamma_s, \delta_s]\).

Type:

list of float

tab_fl_beta

2-D empirical PMF table for flow–beta assignment.

Type:

numpy.ndarray

mu_beta

Mean of the exponential distribution for \(\beta\).

Type:

float

overload_b

Fraction of lines assigned overload (\(\beta > 1\)).

Type:

float

_assign_betas(flows, betas)[source]

Assign gauge ratios to lines via 2-D bin matching.

Uses the empirical PMF Tab_2D_FlBeta to reproduce the joint distribution \(f(\bar{F}_l, \beta_l)\) from the reference system. Lines are sorted by normalised flow and betas by value, then paired randomly within matching bins (high-to-low traversal).

Parameters:
  • flows (numpy.ndarray, shape (m, 2)) – [line_index, normalised_flow].

  • betas (numpy.ndarray, shape (m,)) – Sorted gauge-ratio values from _generate_beta().

Returns:

[line_index, normalised_flow, beta].

Return type:

numpy.ndarray, shape (m, 3)

_generate_beta(num_lines)[source]

Generate gauge ratios from an exponential distribution.

Draws \(\beta \sim \mathrm{Exp}(\mu_\beta)\) and resamples values exceeding 1.0. A fraction overload_b of lines are then injected with \(\beta \in (1.0, 1.2]\) to model bottleneck / overloaded lines (Sadeghian et al., 2018, Sec. IV).

Parameters:

num_lines (int) – Number of transmission lines.

Returns:

Sorted gauge-ratio values.

Return type:

numpy.ndarray, shape (num_lines,)

_generate_phi(num_lines)[source]

Generate line angles from a Lévy stable distribution.

Draws \(\varphi \sim S(\alpha_s, \beta_s, \gamma_s, \delta_s)\) and clips to \([0.01, 89.99]\) degrees. Out-of-range samples are resampled up to 20 times before a hard clip.

Parameters:

num_lines (int) – Number of transmission lines.

Returns:

Line angle in degrees for each branch.

Return type:

numpy.ndarray, shape (num_lines,)

_refine_topology()[source]

Refine grid topology to reduce phase-angle spread.

Iteratively tightens the electrical diameter of the network (ported from sg_flow_lim.m):

  1. Compute the DCPF and measure \(\Delta\theta_{\max} = \max(\theta) - \min(\theta)\).

  2. If \(\Delta\theta_{\max} > TT + 2\) with \(TT = 10^{0.3196 \log_{10} N + 0.8324}\), add a low-impedance edge between the bus pair with the largest angle difference.

  3. Remove a random high-\(X\) edge (top 20 %) whose end-point degrees are both \(\ge 3\), preserving graph connectivity.

  4. Repeat for up to 10 iterations.

allocate(refine_topology=False)[source]

Run the full transmission-line allocation pipeline.

Executes the seven-step procedure:

  1. Draw impedance magnitudes \(Z \sim \text{LogNormal}(\mu, \sigma)\), clipped to [0.001, 0.5] p.u.

  2. Generate angles \(\varphi\) (Lévy stable), compute \(X = Z\sin\varphi\), \(R = Z\cos\varphi\).

  3. Iterative DCPF swapping: sort \(Z\) ascending / flows descending, randomly swap ~20–30 % of assignments.

  4. (Optional) Topology refinement via _refine_topology().

  5. Final DCPF to obtain converged flows.

  6. Generate and assign gauge ratios (\(\beta\)) via _generate_beta() and _assign_betas().

  7. Set capacity limits: \(F_l^{\max} = F_l / \beta_l\) with a minimum-capacity fallback (5 + 100 · rand MW when \(\le 2\)).

Parameters:

refine_topology (bool, optional) – If True, run topology refinement after step 3. Default is False.

Returns:

Mapping (u, v) edge tuple to capacity limit (MW).

Return type:

dict

powergrid_synth.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.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