Overflow modelling

Overflow modelling#

This example will demonstrate overflow modelling based on the basic example. The recommended method of modelling overflow is using the river object. The river upstream_elevation should be equal to the reservoir hrl. The river may also use a flow description, such as up_level_flow_curve or width_depth_curve to describe the level-dependent flow. Additionally, flow_cost can be used to penalize overflow.

The model setup is available in the following formats:

The example below illustrates overflow modelling in SHOP:

from pyshop import ShopSession
from basic import build_model
import pandas as pd
import plotly.graph_objs as go


shop = ShopSession()
build_model(shop)
starttime = shop.get_time_resolution()['starttime']

# Add spill river and set elevation to hrl
spill_river = shop.model.river.add_object('SpillRiver')
spill_river.upstream_elevation.set(100)
spill_river.downstream_elevation.set(90)
# Connect objects in watercourse
shop.model.reservoir.Reservoir1.connect_to(spill_river)
spill_river.connect_to(shop.model.reservoir.Reservoir2)

# Add river to describe flow out of reservoir below. (Crest at 43 meters.)
discharge_river = shop.model.river.add_object('DischargeRiver')
discharge_river.upstream_elevation.set(43)
discharge_river.downstream_elevation.set(0)
discharge_river.width_depth_curve.set(pd.Series(index=[10, 10], data=[0, 7]))
shop.model.reservoir.Reservoir2.connect_to(discharge_river)

# Set start level to almost full, high inflow and scheduled production to ensure overflow
shop.model.reservoir.Reservoir1.start_level.set(98)
shop.model.reservoir.Reservoir1.inflow.set(200)
shop.model.generator.P1G1.production_schedule.set(50)

shop.start_sim([], [3])
spill_flow = spill_river.flow.get()

fig = go.Figure()
fig.add_trace(go.Scatter(x=spill_flow.index, y=spill_flow.values, name="Spill gate flow"))
fig.update_layout(xaxis_title="Time", yaxis_title="Flow")

fig.show()
/opt/conda/lib/python3.13/site-packages/kaleido/_sync_server.py:11: UserWarning:



Warning: You have Plotly version 5.24.0, which is not compatible with this version of Kaleido (1.5.0).

This means that static image generation (e.g. `fig.write_image()`) will not work.

Please upgrade Plotly to version 6.1.1 or greater, or downgrade Kaleido to version 0.2.1.

You can however, use the Kaleido API directly which will work with your plotly version. `kaleido.write_fig(...)`, for example. Please see the kaleido documentation.

In the illustrated case, all water above the maximum volume is routed to the spill gate immediately. Alternatively, a flow function can be used as shown below where the overflow is given by a width_depth_curve:

shop = ShopSession()
build_model(shop)
starttime = shop.get_time_resolution()['starttime']

# Add spill river and set elevation to hrl
spill_river = shop.model.river.add_object('SpillRiver')
spill_river.upstream_elevation.set(100)
spill_river.downstream_elevation.set(90)
# Use widht depth curve for overflow description
spill_river.width_depth_curve.set(pd.Series(index=[30, 30], data=[0, 1]))
# Connect objects in watercourse
shop.model.reservoir.Reservoir1.connect_to(spill_river)
spill_river.connect_to(shop.model.reservoir.Reservoir2)

# Add river to describe flow out of reservoir below. (Crest at 43 meters.)
discharge_river = shop.model.river.add_object('DischargeRiver')
discharge_river.upstream_elevation.set(43)
discharge_river.downstream_elevation.set(0)
discharge_river.width_depth_curve.set(pd.Series(index=[10, 10], data=[0, 7]))
shop.model.reservoir.Reservoir2.connect_to(discharge_river)

# Set start level to almost full, high inflow and scheduled production to ensure overflow
shop.model.reservoir.Reservoir1.start_level.set(98)
shop.model.reservoir.Reservoir1.inflow.set(200)
shop.model.generator.P1G1.production_schedule.set(50)

shop.start_sim([], [3])
spill_flow = spill_river.flow.get()

fig = go.Figure()
fig.add_trace(go.Scatter(x=spill_flow.index, y=spill_flow.values, name="Spill gate flow"))
fig.update_layout(xaxis_title="Time", yaxis_title="Flow")

fig.show()

Overflow with gate#

Before river was introduced in SHOP, overflow was modelled using gate. This is still supported and requires that the relation between level and overflow is given by flow_descr. Moreover, the upstream reservoir and the spill gate must be connected using the spill connection type. The example below show how the overflow can be modelled using a spill gate.

shop = ShopSession()
build_model(shop)
starttime = shop.get_time_resolution()['starttime']

# Add spill gate and set flow_descr
spill_gate = shop.model.gate.add_object('SpillGate')
shop.model.reservoir.Reservoir1.flow_descr.set(pd.Series([0, 1000], index=[100, 101]))
# Connect objects in watercourse
shop.model.reservoir.Reservoir1.connect_to(spill_gate, 'spill')
spill_river.connect_to(shop.model.reservoir.Reservoir2)

# Add river to describe flow out of reservoir below. (Crest at 43 meters.)
discharge_river = shop.model.river.add_object('DischargeRiver')
discharge_river.upstream_elevation.set(43)
discharge_river.downstream_elevation.set(0)
discharge_river.width_depth_curve.set(pd.Series(index=[10, 10], data=[0, 7]))
shop.model.reservoir.Reservoir2.connect_to(discharge_river)

# Set start level to almost full, high inflow and scheduled production to ensure overflow
shop.model.reservoir.Reservoir1.start_level.set(98)
shop.model.reservoir.Reservoir1.inflow.set(200)
shop.model.generator.P1G1.production_schedule.set(50)

shop.start_sim([], [3])
spill_flow = spill_gate.discharge.get()

fig = go.Figure()
fig.add_trace(go.Scatter(x=spill_flow.index, y=spill_flow.values, name="Spill gate flow"))
fig.update_layout(xaxis_title="Time", yaxis_title="Flow")

fig.show()