Reservoirs store water between timesteps. They are nodes in the water network, and receive upstream flows and precipitation, and provide withdrawals to canals. However, their outflows are determined by an optimization.
In [2]:
include("../src/lib/readconfig.jl")
include("../src/lib/reservoirs.jl")
config = readconfig("../configs/standard.yml")
Out[2]:
In [4]:
@doc getreservoirs
Out[4]:
In [3]:
getreservoirs(config)
Out[3]:
To understand the functioning of reservoirs, consider how they work in a very simple three gauge example. The three guages example has three counties, with a river running through them. The middle county has a reservoir. Water is supplied only upstream (in counties 1 and 2) and consumed only downstream (in counties 2 and 3).
Note that the reservoir appears to be outside of the river system. While it is spatially synonymous with the middle gauge, reservoirs get all of their inflows from "captured" water. Any water that is not captured is allowed to run through the reservoir just like a stream. Reservoir captures can also be negative, providing releases.
The optimize-surface.jl
script models the constraints to satisfy surface water demands, using reservoirs to store water between periods.
In the three counties example, the first period has more rainfall than the second period, so that storage is optimal.
In [1]:
include("../src/optimize-surface.jl")
Out[1]:
First, look at the runoff values, with rows for the three gauges and columns for the two time periods.
In [2]:
runoff
Out[2]:
The requirements are for one unit of water each period for each of the lower two gauges.
In [5]:
reshape(constraintoffset_allocation_recordedbalance(m).f, 3, 2)
Out[5]:
The order of the parameters in the LP problem is:
In [6]:
parameters
Out[6]:
And the order of the constraint variables is:
In [8]:
constraints
Out[8]:
Consider the constraint matrix one parameter at a time. The first parameter is the water drawn from the supersource, which only affects the second constraint, :balance
, the difference between water demand and water supply. The objective function is such that supersource withdrawals are avoided.
In [3]:
full(house.A)[:, 1:6]
Out[3]:
Normal withdrawals affect :balance
as well, but they also affect the level of streamflow, which is constrained to be above 0. See the top six rows in two blocks, in the upper left and lower right, corresponding to the two periods. The gauges are ordered, by chance, such that the most upstream gauge is second, so a withdrawal from that gauge causes all three gauges to inch closer to empty.
In [4]:
full(house.A)[:, 7:12]
Out[4]:
We'll ignore the :returns
constraint. The last is the reservoir in the two periods. Reservoir captures have the same affect on streamflows, at least downstream. They have no direct effect on :balance
. Finally, they affect the last two constraints on the upper and lower bounds of the reservoir, where capture (or release) in period 1 affects both periods, while capture (or release) in period 2 only affects one.
In [6]:
full(house.A)[:, end-1:end]
Out[6]:
The result is that it is optimal to store one unit of water and release it in the second period.
In [7]:
constraining(house, sol.sol)
Out[7]:
Future work: