vp.power.contingency
N-1 contingency analysis: every branch and generator outage solved by AC power flow, with DC PTDF/LODF screening.
Part of the distribution vipyr; it runs from a checkout of the
repository. Planned on PyPI as pip install vipyr.
vp.power.contingency takes each element of the contingency list out of
service in turn, solves the AC power flow again by Newton's method from the
base-case voltages, and lists every branch above its rating and every bus
outside its voltage band. Branch loading is |S| at the more loaded end,
in MVA, against rate A in the base case and rate B after an outage (a
rating of 0 is no limit). An outage that splits the network takes the
buses cut off from the reference out of service with their load, and
reports them as islanded.
Beside the AC results it returns the DC model's power transfer and line outage distribution factors (PTDF, LODF) and the post-outage flows they estimate, the linear screen that decides which outages need an AC solve.
Signature
vp.power.contingency(case, *, contingencies='n-1', limits=None, screen=0.9, tol=1e-08, max_it=10) Parameters
- case : str | dict, required
- A case as vp.power.runpf takes it, or a .raw path.
- contingencies : str | list, default
'n-1' - 'n-1' (every branch and generator in service), 'branches', 'gens', or a list of ('branch', k) and ('gen', g), rows of the case from 0.
- limits : dict, default
None - Vmin, vmax (base case), vmin_post, vmax_post (after an outage), rate_pre, rate_post ('A', 'B' or 'C'); defaults 0.95, 1.05, 0.90, 1.10, 'A', 'B'.
- screen : float, default
0.9 - The DC screen flags a post-outage flow above this fraction of rate_post.
- tol : float, default
1e-08 - The power flow's mismatch tolerance, per unit.
- max_it : int, default
10 - Newton iterations per solve.
Returns
A frozen ContingencyResult. Iterating it gives the fields below in order; it also has
params, tests, log and check().
- kinds : ndarray[int64]
- Per contingency: 1 a branch, 2 a generator.
- elems : ndarray[int64]
- Per contingency: the branch or generator row.
- converged : ndarray[bool]
- Per row (the base case first): whether the AC flow converged.
- iterations : ndarray[int64]
- Per row: Newton iterations from the warm start.
- islanded : ndarray[int64]
- Per row: buses left without a path to the reference.
- lost_mw : ndarray[float64]
- Per row: the load on those buses, MW.
- flows : ndarray[float64]
- Rows x branches: |S| at the more loaded end, MVA (NaN where no convergence).
- vm : ndarray[float64]
- Rows x buses: voltage magnitude, per unit (0 on an islanded bus).
- violations : ndarray[float64]
- One row per violation: contingency (-1 the base case), kind (1 thermal, 2 low voltage, 3 high voltage, 4 no convergence), branch or bus row, value, limit, percent.
- dc_flows : ndarray[float64]
- Contingencies x branches: the DC estimate by LODF and PTDF, MW.
- dc_flagged : ndarray[bool]
- Contingencies x branches: DC flow above screen times rate_post.
- ptdf : ndarray[float64]
- Branches x buses: the DC power transfer distribution factors.
- lodf : ndarray[float64]
- Branches x branches: the DC line outage distribution factors.
- bridges : ndarray[int64]
- Branches whose outage islands part of the network.
- success : bool
- Whether the base case converged.
Raises
- ValueError
- An unknown method, a case name that is not shipped, or a case dict without baseMVA, bus, gen and branch.
- module.VivStop
- The case has no bus that can be the reference, or every generator is at a reactive limit.
- TypeError
- An argument of the wrong type, or an unknown keyword.
- vipyr.VivBuildError
- An ImportError: no C compiler, or the program's C does not build.
Notes
LODF. With H = PTDF A^T (A the branch-bus incidence matrix), the flow moved onto branch l by the outage of branch k is with . A branch with is a bridge: its outage islands buses.
References
- NERC, TPL-001-5.1 Transmission System Planning Performance Requirements (category P1, single contingency)
- A. J. Wood, B. F. Wollenberg, G. B. Sheble, Power Generation, Operation, and Control, 3rd ed., Wiley (2014), chapter 7 (contingency analysis, distribution factors)
Examples
import vipyr as vp
r = vp.power.contingency("case30")
print(r.converged.all(), r.violations.shape, r.islanded.max())
assert r.check() True (62, 6) 1Each example ran as written when these pages were generated, and the output shown is what it printed.
Checked against
- Reference
- PYPOWER 5.1.21's runpf, one outage at a time (brute force), on case30, case118 and case300: branch |S| to 2 × 10−8 MVA and Vm to 7 × 10−11 over every outage both solve, the same 23 outages of case300 diverge in both; pandapower 3.5.6's run_contingency on from_ppc's network (case30, case118): the per-bus lowest and highest Vm over all outages to 2 × 10−9; the LODF estimate equals a full DC re-solve to 10−9 MW (lib/power/compare_study.py, lib/power/COMPARISON.md).
Credits
- The methods follow MATPOWER's (BSD-3-Clause). The test cases are MATPOWER's case files, each with its source named in its header.
Source
- Viv: lib/power/contingency.viv
- Viv: lib/power/api.viv
- Viv: lib/power/pf.viv