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_head_flow_curve or width_depth_curve to describe the head dependent flow. Additionally, flow_cost can be used to penalize overflow.

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_head.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()

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_head.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 head 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_head.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()

basic.py#

import pandas as pd

def build_model(shop):
    starttime=pd.Timestamp("2018-02-27 00:00:00")
    endtime=pd.Timestamp("2018-02-28 00:00:00")
    shop.set_time_resolution(starttime=starttime, endtime=endtime, timeunit="hour")

    rsv1=shop.model.reservoir.add_object("Reservoir1")
    rsv1.hrl.set(100)
    rsv1.lrl.set(90)
    rsv1.max_vol.set(12)
    rsv1.vol_head.set(pd.Series([90,100,101],index=[0,12,14]))
    # rsv1.flow_descr.set(pd.Series([0, 1000], index=[100, 101]))

    plant1=shop.model.plant.add_object("Plant1")
    plant1.main_loss.set([0.0002])
    plant1.penstock_loss.set([0.0001])
    plant1.outlet_line.set(40)

    p1g1=shop.model.generator.add_object("P1G1")
    p1g1.connect_to(plant1)
    p1g1.penstock.set(1)
    p1g1.p_min.set(25)
    p1g1.p_nom.set(100)
    p1g1.p_max.set(100)
    p1g1.startcost.set(500)
    p1g1.gen_eff_curve.set(pd.Series([95,98], index=[0,100]))
    p1g1.turb_eff_curves.set([pd.Series([80,95,90],index=[25,90,100],name=90),pd.Series([82,98,92],index=[25,90,100],name=100)])

    rsv2=shop.model.reservoir.add_object("Reservoir2")
    rsv2.hrl.set(50)
    rsv2.lrl.set(40)
    rsv2.max_vol.set(5)
    rsv2.vol_head.set(pd.Series([40,50,51],index=[0,5,6]))
    # rsv2.flow_descr.set(pd.Series([0, 1000], index=[50, 51]))

    rsv1.connect_to(plant1)
    plant1.connect_to(rsv2)
   
    # rsv1.start_head.set(92)
    rsv2.start_head.set(43)

    rsv1.inflow.set(10)
    rsv2.inflow.set(0)

    rsv1.energy_value_input.set(39.7)
    rsv2.energy_value_input.set(0)

    da=shop.model.market.add_object('Day_Ahead')
    da.sale_price.set(pd.Series([19.99,39.99],index=[starttime,starttime+pd.Timedelta(hours=6)]))
    da.buy_price.set(pd.Series([20.01,40.01],index=[starttime,starttime+pd.Timedelta(hours=6)]))
    da.max_sale.set(9999)
    da.max_buy.set(9999)