Note

You can download this example as a Jupyter notebook or start it in interactive mode.

# Two chained reservoirs#

Two disconnected electrical loads are fed from two reservoirs linked by a river; the first reservoir has inflow from rain onto a water basin.

Note that the two reservoirs are tightly coupled, meaning there is no time delay between the first one emptying and the second one filling, as there would be if there were a long stretch of river between the reservoirs. The reservoirs are essentially assumed to be close to each other. A time delay would require a “Link” element between different snapshots, which is not yet supported by PyPSA (but could be enabled by passing `network.optimize()`

an extra_functionality function).

```
[1]:
```

```
import pypsa
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
```

```
[2]:
```

```
network = pypsa.Network()
network.set_snapshots(pd.date_range("2016-01-01 00:00", "2016-01-01 03:00", freq="H"))
```

Add assets to the network.

```
[3]:
```

```
network.add("Carrier", "reservoir")
network.add("Carrier", "rain")
network.add("Bus", "0", carrier="AC")
network.add("Bus", "1", carrier="AC")
network.add("Bus", "0 reservoir", carrier="reservoir")
network.add("Bus", "1 reservoir", carrier="reservoir")
network.add(
"Generator",
"rain",
bus="0 reservoir",
carrier="rain",
p_nom=1000,
p_max_pu=[0.0, 0.2, 0.7, 0.4],
)
network.add("Load", "0 load", bus="0", p_set=20.0)
network.add("Load", "1 load", bus="1", p_set=30.0)
```

The efficiency of a river is the relation between the gravitational potential energy of 1 m^3 of water in reservoir 0 relative to its turbine versus the potential energy of 1 m^3 of water in reservoir 1 relative to its turbine

```
[4]:
```

```
network.add(
"Link",
"spillage",
bus0="0 reservoir",
bus1="1 reservoir",
efficiency=0.5,
p_nom_extendable=True,
)
# water from turbine also goes into next reservoir
network.add(
"Link",
"0 turbine",
bus0="0 reservoir",
bus1="0",
bus2="1 reservoir",
efficiency=0.9,
efficiency2=0.5,
capital_cost=1000,
p_nom_extendable=True,
)
network.add(
"Link",
"1 turbine",
bus0="1 reservoir",
bus1="1",
efficiency=0.9,
capital_cost=1000,
p_nom_extendable=True,
)
network.add(
"Store", "0 reservoir", bus="0 reservoir", e_cyclic=True, e_nom_extendable=True
)
network.add(
"Store", "1 reservoir", bus="1 reservoir", e_cyclic=True, e_nom_extendable=True
)
```

```
[5]:
```

```
network.optimize(network.snapshots)
print("Objective:", network.objective)
```

```
WARNING:pypsa.components:The following links have bus2 which are not defined:
Index(['spillage'], dtype='object', name='Link')
WARNING:pypsa.components:The following links have bus2 which are not defined:
Index(['spillage'], dtype='object', name='Link')
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.09s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 37 primals, 77 duals
Objective: 5.56e+04
Solver model: not available
Solver message: optimal
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper, Link-ext-p-lower, Link-ext-p-upper, Store-ext-e-lower, Store-ext-e-upper, Store-energy_balance were not assigned to the network.
```

```
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
--lp /tmp/linopy-problem-iz7w_5a1.lp --output /tmp/linopy-solve-qtmw_1_g.sol
Reading problem data from '/tmp/linopy-problem-iz7w_5a1.lp'...
77 rows, 37 columns, 137 non-zeros
410 lines were read
GLPK Simplex Optimizer 5.0
77 rows, 37 columns, 137 non-zeros
Preprocessing...
28 rows, 23 columns, 64 non-zeros
Scaling...
A: min|aij| = 5.000e-01 max|aij| = 1.000e+00 ratio = 2.000e+00
Problem data seem to be well scaled
Constructing initial basis...
Size of triangular part is 28
0: obj = 5.555555556e+04 inf = 2.222e+02 (5)
6: obj = 5.555555556e+04 inf = 0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Time used: 0.0 secs
Memory used: 0.1 Mb (80884 bytes)
Writing basic solution to '/tmp/linopy-solve-qtmw_1_g.sol'...
Objective: 55555.55556
```

```
[6]:
```

```
network.generators_t.p.plot.area(figsize=(9, 4))
plt.tight_layout()
```

Now, let’s have look at the different outputs of the links.

```
[7]:
```

```
network.links_t.p0.plot(figsize=(9, 4), lw=3)
plt.tight_layout()
```

```
[8]:
```

```
network.links_t.p1.plot(figsize=(9, 4), lw=3)
plt.tight_layout()
```

```
[9]:
```

```
network.links_t.p2.plot(figsize=(9, 4), lw=3)
plt.tight_layout()
```

What are the energy outputs and energy levels at the reservoirs?

```
[10]:
```

```
pd.DataFrame({attr: network.stores_t[attr]["0 reservoir"] for attr in ["p", "e"]})
```

```
[10]:
```

p | e | |
---|---|---|

snapshot | ||

2016-01-01 00:00:00 | 22.2222 | 0.0000 |

2016-01-01 01:00:00 | 0.0000 | 0.0000 |

2016-01-01 02:00:00 | 0.0000 | 0.0000 |

2016-01-01 03:00:00 | -22.2222 | 22.2222 |

```
[11]:
```

```
pd.DataFrame({attr: network.stores_t[attr]["1 reservoir"] for attr in ["p", "e"]})
```

```
[11]:
```

p | e | |
---|---|---|

snapshot | ||

2016-01-01 00:00:00 | 22.22220 | 0.00000 |

2016-01-01 01:00:00 | -7.40741 | 7.40741 |

2016-01-01 02:00:00 | -7.40741 | 14.81480 |

2016-01-01 03:00:00 | -7.40741 | 22.22220 |

```
[ ]:
```

```
```