# Power System Contingency Analysis with Python PandaPower

This post will demonstrate how python’s pandapower package can be used to carry out a power system contingency analysis.

We will use the IEEE 14 bus test system included pandapower with panadapower, with some small modifications, for this demonstration.

## Load the Relevant Packages in Python

```    import pandas as pd
import pandapower as pp
import pandapower.networks as ppnets
import pandapower.plotting as plt
import matplotlib.pyplot as mplt
```

## Load the Test Network

```    net =  ppnets.case14()
```

The network summary is given by:

```net

This pandapower network includes the following parameter tables:
- bus (14 elements)
- load (11 elements)
- gen (4 elements)
- shunt (1 element)
- ext_grid (1 element)
- line (15 elements)
- trafo (5 elements)
- poly_cost (5 elements)
- bus_geodata (14 elements)
```

## Modify the Test Network

Disable the included external grid so that network is essentially stand-alone so that it can be stressed a bit more. More stress on the network means more lines become critical, which is good for contingency analysis demonstration purposes.

```net.ext_grid['in_service'] = False
```

Scale up the default load so as to further stress the network:

`net.load.scaling = 1.5`

Adjust the terminal voltages of the generators in the network so that bus voltages are within a more practical range, 0.95pu to 1.05pu.

`net.gen['vm_pu'] = 1.045`

Perform a simple generator dispatch by maxing out the first three generators and setting the fourth one as the slack.

```net.gen.loc[0,'p_mw'] = 120
net.gen.loc[1,'p_mw'] = 100
net.gen.loc[2,'p_mw'] = 100
net.gen.loc[3,'slack'] = True
```

## Run the Power Flow

Run the power flow by executing the pandapower ‘runnpp’ command:

`pp.runpp(net,numba=False)`

## Print the Total Generation and Load as a Quick Check

Let’s use the following commands to have a look at the initial load flow of the network to see that everything is as expected and we didn’t miss anything:

```gen_mw_total = net.res_gen['p_mw'].sum()
imports_mw_total = net.res_ext_grid['p_mw'].sum()

print('total gen MW:', gen_mw_total + imports_mw_total)
print('total imported gen MW:', imports_mw_total)
print('total local gen MW:', gen_mw_total)

total gen MW: 392.0112578522987
total imported gen MW: 0.0
total local gen MW: 392.0112578522987
total load MW: 388.50000000000006
```

## Display the Generation Parameters and Generator Dispatch to Check no Limits are Violated

Display the parameters of the generators with the following code:

`net.gen` `net.res_gen` ## Check the Bus Voltages Also

Display the bus voltages using the following code:

`net.res_bus` ## Perform the Contingency Analysis

The power system contingency analysis is performed by sequentially taking each line out of service, running the power flow, checking for network violations and returning the line to service before repeating.

The lines that result in a network voltage or loading limit violation are stored in ‘critical_lines’ along with an abbreviation of the violation caused.

```lines = net.line.index
critical_lines = []
critical_lines_indx = []

vmax = 1.05
vmin = 0.95

for l in lines:
net.line.loc[l, 'in_service'] = False
pp.runpp(net, numba=False)
if net.res_bus.vm_pu.max()>vmax:
critical_lines.append([l, 'hv'])
critical_lines_indx.append(l)
if net.res_bus.vm_pu.min() < vmin:
critical_lines.append([l, 'lv'])
critical_lines_indx.append(l)
critical_lines.append([l, 'ol'])
critical_lines_indx.append(l)
net.line.loc[l, 'in_service'] = True
```

## Print the Critical Lines

Print the critical lines and the effect that losing them will have on the network.

```print(crtical_lines)

[[9, 'lv'], [11, 'lv']]
```

Therefore lines 9 and 11 are critical lines and if either of them trips then it will result in low voltage in the network.

## Bonus – Plot the Network and Highlight the Critical Lines

For easy visualization, we can plot the network and highlight the critical lines in red as shown below.

```fig, ax = mplt.subplots()
fig.set_figheight(6)
fig.set_figwidth(8)

critical_lc = plt.create_line_collection(net, critical_lines_indx, color="r", zorder=2) #create lines

plt.draw_collections([critical_lc], ax=ax);
plt.simple_plot(net,  plot_loads=True, plot_gens=True,  ax=ax, show_plot=False);

mplt.show()
``` That’s it. Don’t forget to share this post with those you think will be interested in it.