This site is version 0.0.1. Most of the code on this site is drafted by an agent and needs review. I apologize for the AI-speak, we are working on rewriting it!
viv-lang.org

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

  1. NERC, TPL-001-5.1 Transmission System Planning Performance Requirements (category P1, single contingency)
  2. 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) 1

Each 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