Getting Started¶
Installation¶
The package requires Python 3.11+. Runtime dependencies are numpy,
scipy, pandas, openpyxl, and click.
To run the test suite, install the dev extras:
To build this documentation site locally, install the docs extras:
The 9-bus worked example¶
The MATLAB toolbox ships an Example_9bus.m demo that eliminates buses
[1, 5, 8] from the standard MATPOWER 9-bus case. simplenet
reproduces the same behavior:
from simplenet import reduce_network
from simplenet.io import load_m, dump_xlsx
case = load_m("matlab/NetworkReduction2/test_9bus_case.m")
result = reduce_network(case, excluded_bus_ids=[1, 5, 8])
print(result.summary)
# Reduction process start
# Preprocess data
# ...
# 6 buses in reduced model
# 7 branches in reduced model, including 4 equivalent lines
# 3 generators in reduced model
# External generator on bus 1 is moved to 4
dump_xlsx(result.reduced_case, "case9_reduced.xlsx", summary=result.summary)
The reduced model has:
- 6 retained buses:
{2, 3, 4, 6, 7, 9} - 4 equivalent branches between bus pairs
(2,7),(2,9),(4,6),(7,9), each carrying circuit number99 - Generator originally on bus 1 moved to bus 4
These expectations are baked into the regression test
tests/test_9bus_reduction.py.
Driving the TAMU WECC workflow¶
The TAMU instructions tell users to:
- Populate the matrices in
matlab2.xlsx(Bus / Gen / Branch / GenCost / Gentype / Genfuel / Bus Names sheets). - Edit
case_ACTIVSg10kCopy2.mto point at that workbook (which the MATLAB code already does viareadmatrix). - Run
reduction_test.mwith a chosenexcluded_nodes_<N>.csv.
simplenet collapses those three steps into one call:
from simplenet.io import load_xlsx, load_excluded_nodes, dump_xlsx
from simplenet import reduce_network
case = load_xlsx("matlab/matlab2_WECC.xlsx")
excluded = load_excluded_nodes("excluded_nodes_550.csv")
result = reduce_network(case, excluded, pf_flag=True)
dump_xlsx(result.reduced_case, "Result_excluded_nodes_550.xlsx",
summary=result.summary)
load_xlsx reads the same Bus / Gen / Branch / GenCost / Gentype /
Genfuel / Bus Names sheets that case_ACTIVSg10kCopy2.m reads, and is
robust to optional header rows in the numeric sheets.
load_excluded_nodes accepts a one-column CSV with or without a
ExcludedNodes header row (the format used by the
expected_output sample).
Starting from a PSS/E .RAW file¶
If the upstream source for your case is a PSS/E v33 raw file (the
format the TAMU ACTIVSg10k.RAW / ACTIVSg70k.RAW synthetic grids
ship in), simplenet reads it directly — no MATPOWER /
psse2mpc conversion step is needed:
from simplenet.io import load_raw
from simplenet import reduce_network
case = load_raw("ACTIVSg10k.RAW")
result = reduce_network(case, excluded_bus_ids=[...])
load_raw populates bus / generator /
branch matrices using the MATPOWER v2 column conventions. Two-winding
transformers become branches with their tap ratio and phase shift;
three-winding transformers expand into a synthetic star bus plus
three equivalent branches (matching MATPOWER's psse2mpc).
Switched-shunt initial setpoints are folded into each bus's Bs.
PSS/E sections that the DC reduction does not need (HVDC / VSC lines,
FACTS, impedance correction, multi-section line groupings, etc.) are
parsed defensively and otherwise ignored.
Using a pypower-style dict¶
If you already have a case represented as a pypower-style dict you can skip the file I/O:
from simplenet import PowerCase, reduce_network
mpc = {
"baseMVA": 100.0,
"bus": [...], # 13+ column numeric matrix
"gen": [...], # 21+ column numeric matrix
"branch": [...], # 13+ column numeric matrix
}
case = PowerCase.from_pypower(mpc)
result = reduce_network(case, excluded_bus_ids=[...])
reduced_dict = result.reduced_case.to_pypower()
Inspecting the result¶
ReductionResult has six fields:
| Field | Description |
|---|---|
reduced_case |
The reduced PowerCase |
link |
Nx2 array of [original_bus_id, mapped_bus_id] for every bus that participated in gen placement |
bcirc |
Per-branch circuit numbers; equivalent branches use eq_bcirc_value (typically 99) |
boundary_buses |
Retained-bus IDs adjacent to the eliminated set |
summary |
Human-readable diary string mirroring MATLAB's diary output |
preprocess_stats |
Counts of isolated buses / OOS branches / generators dropped at the preprocessing stage |
Solving DC power flow on the reduced model¶
simplenet ships a self-contained DC power flow that you can use to
sanity-check the reduced model:
from simplenet import run_dcpf
import numpy as np
reduced_pf = run_dcpf(result.reduced_case)
print(np.rad2deg(reduced_pf.theta)) # bus angles in degrees
For the 9-bus example the reduced-model angles match the full-model angles for retained buses up to the slack-bus shift (the full model's slack — bus 1 — was eliminated, so the reduced model auto-promotes the first PV bus to slack). See Algorithm for details.