Contingency Analysis¶
See the module pypsa.contingency
.
Contingency analysis is concerned with the behaviour of the power system after contingencies such as the outage of particular branches. Only branch outages and the resulting effects on linear power flow are considered here; extensions for nonlinear power flow and generator outages may be added in the future.
Branch Outage Distribution Factors (BODF)¶
sub_network.caculate_BODF()
calculates the matrix of Branch Outage
Distribution Factors (BODF) and stores it as
sub_network.BODF
. (BODF are also called Line Outage Distribution
Factors (LODF) in the literature, but in PyPSA other passive branches
such as transformers are also included.)
The BODF gives the change of flow on the branches in the network following a branch outage, based on the linear power flow.
For the outage of branch \(c\), let \(f_b\) be the flows before the outage and \(f_b^{(c)}\) be the flows after the outage. Then the BODF is defined by
The BODF can be computed fairly directly from the Power Transfer Distribution Factors (PTDF). First build the branch PTDF \(BPTDF\) from the PTDF and incidence matrix \(K\)
\(BPTDF_{bc}\) gives the change in flow on branch \(b\) if a unit of power is injected at the frombus of branch \(c\) and withdrawn from the tobus of branch \(c\). If branch \(b\) is the only branch connecting two regions, then \(BPTDF_{bb} = 1\), since the power can only flow between the two ends of the branch through the branch itself.
The offdiagonal entries of the BODF \(b \neq c\) are given by:
If \(c\) is the only branch connecting two regions, so that the regions become disconnected after the outage of \(c\), then \(BPTDF_{cc} = 1\) and \(BODF_{bc}\) becomes singular; this case must be treated separately since, for example, each region will need its own slack.
The diagonal entries of the BODF are simply:

SubNetwork.
calculate_BODF
(skip_pre=False)¶ Calculate the Branch Outage Distribution Factor (BODF) for sub_network.
Sets sub_network.BODF as a (dense) numpy array.
The BODF is a num_branch x num_branch 2d array.
For the outage of branch l, the new flow on branch k is given in terms of the flow before the outage
f_k^after = f_k^before + BODF_{kl} f_l^before
Note that BODF_{ll} = 1.
 Parameters
sub_network (pypsa.SubNetwork) –
skip_pre (bool, default False) – Skip the preliminary step of computing the PTDF.
Examples
>>> sub_network.caculate_BODF()
Linear Power Flow Contingency Analysis¶
network.lpf_contingency(snapshot, branch_outages)
computes a base
case linear power flow (LPF) with no outages for snapshot
, and
then cycles through the list of branches in branch_outages
and
computes the line flows after the outage of that branch using the BODF.

Network.
lpf_contingency
(snapshots=None, branch_outages=None)¶ Computes linear power flow for a selection of branch outages.
 Parameters
snapshots (listlikesingle snapshot) – A subset or an elements of network.snapshots on which to run the power flow, defaults to network.snapshots NB: currently this only works for a single snapshot
branch_outages (listlike) – A list of passive branches which are to be tested for outages. If None, it’s take as all network.passive_branches_i()
 Returns
p0 – num_passive_branch x num_branch_outages DataFrame of new power flows
 Return type
pandas.DataFrame
Examples
>>> network.lpf_contingency(snapshot, branch_outages)
SecurityConstrained Linear Optimal Power Flow (SCLOPF)¶
The SecurityConstrained Linear Optimal Power Flow (SCLOPF) builds on the Linear Optimal Power Flow (LOPF) described in Optimal Power Flow by including additional constraints that branches may not become overloaded after the outage of a selection of branches.
The SCLOPF is called with the method

Network.
sclopf
(snapshots=None, branch_outages=None, solver_name='glpk', pyomo=True, skip_pre=False, extra_functionality=None, solver_options={}, keep_files=False, formulation='kirchhoff', ptdf_tolerance=0.0)¶ Computes SecurityConstrained Linear Optimal Power Flow (SCLOPF).
This ensures that no branch is overloaded even given the branch outages.
 Parameters
snapshots (list or index slice) – A list of snapshots to optimise, must be a subset of network.snapshots, defaults to network.snapshots
branch_outages (listlike) – A list of passive branches which are to be tested for outages. If None, it’s take as all network.passive_branches_i()
solver_name (string) – Must be a solver name that pyomo recognises and that is installed, e.g. “glpk”, “gurobi”
pyomo (bool, default True) – Whether to use pyomo for building and solving the model, setting this to False saves a lot of memory and time.
skip_pre (bool, default False) – Skip the preliminary steps of computing topology, calculating dependent values and finding bus controls.
extra_functionality (callable function) – This function must take two arguments extra_functionality(network,snapshots) and is called after the model building is complete, but before it is sent to the solver. It allows the user to add/change constraints and add/change the objective function.
solver_options (dictionary) – A dictionary with additional options that get passed to the solver. (e.g. {‘threads’:2} tells gurobi to use only 2 cpus)
keep_files (bool, default False) – Keep the files that pyomo constructs from OPF problem construction, e.g. .lp file  useful for debugging
formulation (string, default "kirchhoff") – Formulation of the linear power flow equations to use; must be one of [“angles”,”cycles”,”kirchoff”,”ptdf”]
ptdf_tolerance (float) –
 Returns
 Return type
Examples
>>> network.sclopf(network, branch_outages)
Note that
network.sclopf()
is implemented by adding a function to
network.lopf()
via the extra_functionality
keyword.
For each potential outage of a branch \(c\) add a set of constraints for all other branches \(b\) in the subnetwork that they do not become overloaded beyond their capacity \(F_b\):
This applies for all snapshots \(t\) considered in the optimisation.