Problem 5.1#
Integrated Energy Grids
Problem 5.1
Assume we have three buses (Denmark, Netherlands and Germany) with nominal voltage \(V_{nom}\)= 2000 V connected by three transmission lines. In the bus, Denmark there is a wind generator that is producing 100 MW. In the bus Germany, there is a load that is consuming 100 MW of active power and 100 MVAR of reactive power. The transmission lines DK-NL and NL-GE have a unitary resistance \(r\)=0.01 and reactance \(x\)=0.1. The transmission lines DK-GE has a unitary resistance \(r\)=0.02 and reactance \(x\)=0.1. Using Python for Power System Analysis (PyPSA):
a) Calculate the power flows along the transmission lines using AC power flow representation.
b) Calculate the power flows along the transmission lines using a linearized approximation (also known as DC optimal power flow) and discuss the results.
Hint: It is recommended to follow the PyPSA tutorial before trying this problem.
Note
If you have not yet set up Python on your computer, you can execute this tutorial in your browser via Google Colab. Click on the rocket in the top right corner and launch “Colab”. If that doesn’t work download the .ipynb
file and import it in Google Colab.
Then install the following packages by executing the following command in a Jupyter cell at the top of the notebook.
!pip install numpy pypsa
import numpy as np
import pypsa
We start by creating the network object and adding the three buses corresponding to Denmark, Netherlands and Germany. The added buses can be printed using network.buses
network = pypsa.Network()
network.add("Bus", "bus Denmark", v_nom=2000.0)
network.add("Bus", "bus Netherlands", v_nom=2000.0)
network.add("Bus", "bus Germany", v_nom=2000.0)
network.buses
v_nom | type | x | y | carrier | unit | location | v_mag_pu_set | v_mag_pu_min | v_mag_pu_max | control | generator | sub_network | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Bus | |||||||||||||
bus Denmark | 2000.0 | 0.0 | 0.0 | AC | 1.0 | 0.0 | inf | PQ | |||||
bus Netherlands | 2000.0 | 0.0 | 0.0 | AC | 1.0 | 0.0 | inf | PQ | |||||
bus Germany | 2000.0 | 0.0 | 0.0 | AC | 1.0 | 0.0 | inf | PQ |
We add the three lines connecting the buses
network.add("Line"," line DK-NL", bus0 = "bus Denmark", bus1= "bus Netherlands", x=0.1, r=0.01)
network.add("Line"," line DK-DE", bus0 = "bus Denmark", bus1= "bus Germany", x=0.1, r=0.02)
network.add("Line"," line NL-DE", bus0 = "bus Netherlands", bus1= "bus Germany", x=0.1, r=0.01)
network.lines
bus0 | bus1 | type | x | r | g | b | s_nom | s_nom_mod | s_nom_extendable | ... | v_ang_min | v_ang_max | sub_network | x_pu | r_pu | g_pu | b_pu | x_pu_eff | r_pu_eff | s_nom_opt | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Line | |||||||||||||||||||||
line DK-NL | bus Denmark | bus Netherlands | 0.1 | 0.01 | 0.0 | 0.0 | 0.0 | 0.0 | False | ... | -inf | inf | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ||
line DK-DE | bus Denmark | bus Germany | 0.1 | 0.02 | 0.0 | 0.0 | 0.0 | 0.0 | False | ... | -inf | inf | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ||
line NL-DE | bus Netherlands | bus Germany | 0.1 | 0.01 | 0.0 | 0.0 | 0.0 | 0.0 | False | ... | -inf | inf | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
3 rows × 31 columns
Add a generator at the Denmark bus.
network.add("Generator",
"generator Denmark",
bus="bus Denmark",
p_set=100)
network.generators
bus | control | type | p_nom | p_nom_mod | p_nom_extendable | p_nom_min | p_nom_max | p_min_pu | p_max_pu | ... | min_up_time | min_down_time | up_time_before | down_time_before | ramp_limit_up | ramp_limit_down | ramp_limit_start_up | ramp_limit_shut_down | weight | p_nom_opt | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Generator | |||||||||||||||||||||
generator Denmark | bus Denmark | PQ | 0.0 | 0.0 | False | 0.0 | inf | 0.0 | 1.0 | ... | 0 | 0 | 1 | 0 | NaN | NaN | 1.0 | 1.0 | 1.0 | 0.0 |
1 rows × 37 columns
network.generators.p_set
Generator
generator Denmark 100.0
Name: p_set, dtype: float64
Add a load at the Germany bus
network.add("Load",
"load Germany",
bus="bus Germany",
p_set=100,
q_set=100)
network.loads
bus | carrier | type | p_set | q_set | sign | active | |
---|---|---|---|---|---|---|---|
Load | |||||||
load Germany | bus Germany | 100.0 | 100.0 | -1.0 | True |
We can now solve the non-linear power flow using a Newton-Raphson method.
network.pf()
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x7f463396fb90> for snapshots Index(['now'], dtype='object', name='snapshot')
{'n_iter': SubNetwork 0
snapshot
now 2,
'error': SubNetwork 0
snapshot
now 8.204964e-09,
'converged': SubNetwork 0
snapshot
now True}
ok, the solution converge, we can check now the active power flow on the lines.
network.lines_t.p0
line DK-NL | line DK-DE | line NL-DE | |
---|---|---|---|
snapshot | |||
now | 31.441059 | 68.558996 | 31.441054 |
We can also check the voltage angles on the buses. We need to apply a conversion factor if we want to show them in degrees.
network.buses_t.v_ang * 180 / np.pi
Bus | bus Denmark | bus Netherlands | bus Germany |
---|---|---|---|
snapshot | |||
now | 0.0 | -0.00004 | -0.00008 |
and their per-unit magnitudes
network.buses_t.v_mag_pu
Bus | bus Denmark | bus Netherlands | bus Germany |
---|---|---|---|
snapshot | |||
now | 1.0 | 0.999999 | 0.999998 |
b) Calculate the power flows along the transmission lines using a linearized approximation (DC optimal power flow).
We can use linear power flows and get a similar solution
network.lpf()
INFO:pypsa.pf:Performing linear load-flow on AC sub-network <pypsa.networks.SubNetwork object at 0x7f463396fb90> for snapshot(s) Index(['now'], dtype='object', name='snapshot')
network.lines_t.p0
line DK-NL | line DK-DE | line NL-DE | |
---|---|---|---|
snapshot | |||
now | 33.333333 | 66.666667 | 33.333333 |
In this simple case, the solution that we obtain are very similar.