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)