powergrid_synth.transmission.generation_dispatcher
Generation dispatch for synthetic power grids.
This module implements the generation dispatch algorithm from Sadeghian et al. (2018). It partitions generator units into three groups — uncommitted (\(\alpha = 0\)), partially committed (\(0 < \alpha < 1\)), and fully committed (\(\alpha \approx 1\)) — then assigns participation factors (dispatch factors) and iteratively balances total generation against total load. The dispatch factor is defined as
The correlation between normalised capacity and dispatch factor is
reproduced via a 2-D empirical PMF table (Tab_2D_Pg).
Ported from the SynGrid MATLAB function sg_gen_dist.m.
Module Contents
- class powergrid_synth.transmission.generation_dispatcher.GenerationDispatcher(graph, ref_sys_id=1)[source]
Assign active-power dispatch to each generator bus.
The algorithm follows Sadeghian et al. (2018) (Section III):
Uncommitted units (10–20 %): \(\alpha = 0\), selected via targets drawn from Uniform[0, 0.6].
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\)).Fully committed units (remainder): \(\alpha = 1\).
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]. Whenalpha_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):
Collect generator buses and normalise capacities by \(P^{\max}_{g_{\max}}\).
Partition generators into uncommitted (\(\alpha = 0\)), partially committed (\(0 < \alpha < 1\)), and fully committed (\(\alpha = 1\)).
Assign dispatch factors to partially committed units via the 2-D bin-matching table
Tab_2D_Pg.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.
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