Basic tunnel modelling#
This example is available in the following formats.
pyshop
YAML
ASCII
#Necessary imports used in all examples
import pandas as pd
from pyshop import ShopSession
pd.options.plotting.backend = "plotly"
#Functions used in this example for building a tunnel model, adding a gate to a tunnel and running the optimization
from tunnel_model import build_model, add_gate, run_model
We create a system with three reservoirs, three tunnels and one plant. In the first model, shop_default, there are no gates to optimize, and the flow simply follows the physical laws of the tunnel system. Both the start level and the inflow in Reservoir3, the closest reservoir to the plant, is higher than in the other reservoirs. This means, that some of this extra water in Reservoir3 will naturally flow into the other reservoirs.
#Create a standard ShopSession
shop_default=ShopSession()
#Build a simple tunnel model without tunnel gates by calling function "build_model" in tunnel_model.py
build_model(shop_default)
#Optimize model by calling "run_model" in tunnel_model.py
run_model(shop_default)
#Display topology to the screen
display(shop_default.model.build_connection_tree())
#Display results for reservoir levels
pd.concat([obj.head.get().rename(obj.get_name()) for obj in shop_default.model.reservoir], axis=1).plot(title="Reservoir level")
#Display results for tunnel flows
pd.concat([obj.flow.get().rename(obj.get_name()) for obj in shop_default.model.tunnel], axis=1).plot(title="Tunnel flow")
The second model is allowed to adjust the gate opening in the tunnel between Reservoir2 and Reservoir3. As we see in the results, SHOP is able to keep more water in Reservoir3, and thus get more energy from the plant, by closing this gate for most of the period. Only at the end of the period it is partially opened to prevent spillage from Reservoir3.
#Create a standard ShopSession
shop_optimized=ShopSession()
#Build a simple tunnel model without gates by calling function "build_model" in tunnel_model.py
build_model(shop_optimized)
#Add a gate between Reservoir2 and Reservoir3 by calling function "add_gate" in tunnel_model.py
add_gate(shop_optimized)
#Optimize model by calling "run_model" in tunnel_model.py
run_model(shop_optimized)
#Display results for reservoir levels
pd.concat([obj.head.get().rename(obj.get_name()) for obj in shop_optimized.model.reservoir], axis=1).plot(title="Reservoir level")
#Display results for tunnel flows
pd.concat([obj.flow.get().rename(obj.get_name()) for obj in shop_optimized.model.tunnel], axis=1).plot(title="Tunnel flow")
#Display results for tunnel opening
pd.concat([obj.gate_opening.get().rename(obj.get_name()) for obj in shop_optimized.model.tunnel], axis=1).plot(title="Gate opening")
#Compare objective functions to see improvement in result from optimizing the gate
default_objective=shop_default.model.objective["average_objective"].grand_total.get()
optimized_objective=shop_optimized.model.objective["average_objective"].grand_total.get()
print(f"Optimization of the gate in Tunnel2 improved the objective with {-(optimized_objective-default_objective):.2f}€")
Optimization of the gate in Tunnel2 improved the objective with 550.35€
File contents#
tunnel_model.py #
import pandas as pd
def build_model(shop):
starttime=pd.Timestamp("2018-02-27 00:00:00")
endtime=pd.Timestamp("2018-02-27 06: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(5)
rsv1.vol_head.set(pd.Series([90,100,101],index=[0,5,6]))
rsv1.flow_descr.set(pd.Series([0, 1000], index=[100, 101]))
rsv2=shop.model.reservoir.add_object("Reservoir2")
rsv2.hrl.set(100)
rsv2.lrl.set(90)
rsv2.max_vol.set(5)
rsv2.vol_head.set(pd.Series([90,100,101],index=[0,5,6]))
rsv2.flow_descr.set(pd.Series([0, 1000], index=[100, 101]))
rsv3=shop.model.reservoir.add_object("Reservoir3")
rsv3.hrl.set(100)
rsv3.lrl.set(90)
rsv3.max_vol.set(5)
rsv3.vol_head.set(pd.Series([90,100,101],index=[0,5,6]))
rsv3.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])
p1g1=shop.model.generator.add_object("P1G1")
p1g1.connect_to(plant1)
p1g1.penstock.set(1)
p1g1.p_min.set(0.1)
p1g1.p_nom.set(100)
p1g1.p_max.set(100)
p1g1.gen_eff_curve.set(pd.Series([95,98], index=[0,100]))
p1g1.turb_eff_curves.set([pd.Series([80,95,90],index=[1,90,100],name=90),pd.Series([82,98,92],index=[1,90,100],name=100)])
tunnel1=shop.model.tunnel.add_object("Tunnel1")
tunnel1.loss_factor.set(0.00016)
tunnel1.start_height.set(90)
tunnel1.end_height.set(90)
tunnel1.diameter.set(3)
tunnel1.length.set(2022)
tunnel2=shop.model.tunnel.add_object("Tunnel2")
tunnel2.loss_factor.set(0.00015)
tunnel2.start_height.set(90)
tunnel2.end_height.set(90)
tunnel2.diameter.set(3)
tunnel2.length.set(2022)
tunnel3=shop.model.tunnel.add_object("Tunnel3")
tunnel3.loss_factor.set(0.00030)
tunnel3.start_height.set(90)
tunnel3.end_height.set(90)
tunnel3.diameter.set(3)
tunnel3.length.set(2022)
rsv1.connect_to(tunnel1)
tunnel1.connect_to(rsv2)
rsv2.connect_to(tunnel2)
tunnel2.connect_to(rsv3)
rsv3.connect_to(tunnel3)
tunnel3.connect_to(plant1)
rsv1.start_head.set(93)
rsv2.start_head.set(93)
rsv3.start_head.set(97)
rsv3.inflow.set(200)
rsv1.energy_value_input.set(31.7)
rsv2.energy_value_input.set(31.7)
rsv3.energy_value_input.set(31.7)
da=shop.model.market.add_object('1')
da.sale_price.set(39.99)
da.buy_price.set(40.01)
da.max_sale.set(9999)
da.max_buy.set(9999)
def add_gate(shop):
tunnel2=shop.model.tunnel["Tunnel2"]
tunnel2.gate_opening_curve.set(pd.Series([0,1],index=[0,1]))
tunnel2.continuous_gate.set(1)
def run_model(shop):
shop.start_sim([],['3'])
shop.set_code(['inc'],[])
shop.start_sim([],['3'])
tunnel_gate.py#
import pandas as pd
def add_tunnel_gate(shop):
tunnel2=shop.model.tunnel["Tunnel2"]
tunnel2.gate_opening_curve.set(pd.Series([0,1],index=[0,1]))
tunnel2.continuous_gate.set(1)
tunnel_model.yaml #
time:
starttime: 2018-02-27 00:00:00
endtime: 2018-02-27 06:00:00
timeunit: hour
timeresolution:
2018-02-27 00:00:00: 1
model:
reservoir:
Reservoir1:
start_vol: 0
start_head: 93
max_vol: 5
lrl: 90
hrl: 100
vol_head:
ref: 0
x:
- 0
- 5
- 6
y:
- 90
- 100
- 101
flow_descr:
ref: 0
x:
- 100
- 101
y:
- 0
- 1000
endpoint_desc_nok_mwh:
ref: 0
x:
- 0
y:
- 31.7
Reservoir2:
start_vol: 0
start_head: 93
max_vol: 5
lrl: 90
hrl: 100
vol_head:
ref: 0
x:
- 0
- 5
- 6
y:
- 90
- 100
- 101
flow_descr:
ref: 0
x:
- 100
- 101
y:
- 0
- 1000
endpoint_desc_nok_mwh:
ref: 0
x:
- 0
y:
- 31.7
Reservoir3:
start_vol: 0
start_head: 97
max_vol: 5
lrl: 90
hrl: 100
vol_head:
ref: 0
x:
- 0
- 5
- 6
y:
- 90
- 100
- 101
flow_descr:
ref: 0
x:
- 100
- 101
y:
- 0
- 1000
endpoint_desc_nok_mwh:
ref: 0
x:
- 0
y:
- 31.7
inflow:
2018-02-27 00:00:00: 200
plant:
Plant1:
main_loss:
- 0.0002
penstock_loss:
- 0.0001
generator:
P1G1:
penstock: 1
p_min: 0.1
p_max: 100
p_nom: 100
gen_eff_curve:
ref: 0
x:
- 0
- 100
y:
- 95
- 98
turb_eff_curves:
- ref: 90
x:
- 1
- 90
- 100
y:
- 80
- 95
- 90
- ref: 100
x:
- 1
- 90
- 100
y:
- 82
- 98
- 92
startcost:
2018-02-27 00:00:00: 0
tunnel:
Tunnel1:
start_height: 90
end_height: 90
diameter: 3
length: 2022
loss_factor: 0.00016
Tunnel2:
start_height: 90
end_height: 90
diameter: 3
length: 2022
loss_factor: 0.00015
Tunnel3:
start_height: 90
end_height: 90
diameter: 3
length: 2022
loss_factor: 0.0003
market:
1:
market_type: ENERGY
max_buy:
2018-02-27 00:00:00: 9999
max_sale:
2018-02-27 00:00:00: 9999
buy_price:
2018-02-27 00:00:00: 40.01
sale_price:
2018-02-27 00:00:00: 39.99
connections:
- from: Tunnel1
to: Reservoir2
- from: Tunnel2
to: Reservoir3
- from: Tunnel3
to: Plant1
- from: Plant1
to: P1G1
- from: Reservoir1
to: Tunnel1
- from: Reservoir2
to: Tunnel2
- from: Reservoir3
to: Tunnel3
tunnel_gate.yaml #
model:
tunnel:
Tunnel2:
continuous_gate: 1
gate_opening_curve:
ref: 0
x:
- 0
- 1
y:
- 0
- 1
tunnel_model.ascii #
OPTIMIZATION time
#Start_time; End_time;
20180227000000 20180227060000
#;N_full_iterations;Accuracy;
OPTIMIZATION 1000 1.00
#Time resolution in the optimization;
#Id;Number;Start_Time;Time_unit;Period;Data_type;Y_unit;Pts;
0 0 20180227000000000 HOUR 0 -1 NO_UNIT 7
# Time; f(t);
20180227000000000 1.00000000000000000
RESERVOIR attributes Reservoir1
#ID;Water_course;Type;Maxvol;Lrl;Hrl;
0 0 0 5.000 90.000 100.000
RESERVOIR vol_head Reservoir1
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 3 MM3 METER
# x_value; y_value;
0.0000000000 90.0000000000
5.0000000000 100.0000000000
6.0000000000 101.0000000000
RESERVOIR flow_descr Reservoir1
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 2 METER M3/S
# x_value; y_value;
100.0000000000 0.0000000000
101.0000000000 1000.0000000000
RESERVOIR endpoint_desc Reservoir1
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 1 MM3 NOK/MWH
# x_value; y_value;
0.0000000000 31.7000000000
RESERVOIR attributes Reservoir2
#ID;Water_course;Type;Maxvol;Lrl;Hrl;
0 0 0 5.000 90.000 100.000
RESERVOIR vol_head Reservoir2
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 3 MM3 METER
# x_value; y_value;
0.0000000000 90.0000000000
5.0000000000 100.0000000000
6.0000000000 101.0000000000
RESERVOIR flow_descr Reservoir2
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 2 METER M3/S
# x_value; y_value;
100.0000000000 0.0000000000
101.0000000000 1000.0000000000
RESERVOIR endpoint_desc Reservoir2
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 1 MM3 NOK/MWH
# x_value; y_value;
0.0000000000 31.7000000000
RESERVOIR attributes Reservoir3
#ID;Water_course;Type;Maxvol;Lrl;Hrl;
0 0 0 5.000 90.000 100.000
RESERVOIR vol_head Reservoir3
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 3 MM3 METER
# x_value; y_value;
0.0000000000 90.0000000000
5.0000000000 100.0000000000
6.0000000000 101.0000000000
RESERVOIR flow_descr Reservoir3
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 2 METER M3/S
# x_value; y_value;
100.0000000000 0.0000000000
101.0000000000 1000.0000000000
RESERVOIR endpoint_desc Reservoir3
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 1 MM3 NOK/MWH
# x_value; y_value;
0.0000000000 31.7000000000
RESERVOIR inflow Reservoir3
#Id;Number;Start_Time;Time_unit;Period;Data_type;Y_unit;Pts;
0 0 20180227000000000 HOUR 0 -1 M3/S 7
# Time; f(t);
20180227000000000 200.00000000000000000
PLANT attributes Plant1
#Id;Water_course;Type;Future_use;Prod_area;Num_gen;Num_pump;
0 0 6 0 0 1 0
#Num_main_seg;Num_penstock;Time_delay;Read_prod_factor;Outlet_line;
1 1 0 0.000000 0.000000
0.000200
0.000100
GENERATOR attributes Plant1 1
#Id Type Penstock Nom_prod Min_prod Max_prod Start_cost
0 7 1 100.00 0.10 100.00 0.00
GENERATOR gen_eff_curve Plant1 1
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 0.00 2 MW %
# x_value; y_value;
0.0000000000 95.0000000000
100.0000000000 98.0000000000
GENERATOR turb_eff_curves Plant1 1
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 90.00 3 M3/S %
# x_value; y_value;
1.0000000000 80.0000000000
90.0000000000 95.0000000000
100.0000000000 90.0000000000
GENERATOR turb_eff_curves Plant1 1
#Id;Number;Reference;Pts;X_unit;Y_unit
0 0 100.00 3 M3/S %
# x_value; y_value;
1.0000000000 82.0000000000
90.0000000000 98.0000000000
100.0000000000 92.0000000000
#Initial reservoir volumes;
STARTRES 3 MM3
#Name; Volume (Mm3);
Reservoir1 1.5000
Reservoir2 1.5000
Reservoir3 3.5000
MULTI_MARKET price_buy 1 0
#Id;Number;Start_Time;Time_unit;Period;Data_type;Y_unit;Pts;
0 0 20180227000000000 HOUR 0 -1 NOK/MWH 7
# Time; f(t);
20180227000000000 40.01
MULTI_MARKET price_sale 1 0
#Id;Number;Start_Time;Time_unit;Period;Data_type;Y_unit;Pts;
0 0 20180227000000000 HOUR 0 -1 NOK/MWH 7
# Time; f(t);
20180227000000000 39.99
MULTI_MARKET max_buy 1 0
#Id;Number;Start_Time;Time_unit;Period;Data_type;Y_unit;Pts;
0 0 20180227000000000 HOUR 0 -1 MW 7
# Time; f(t);
20180227000000000 9999
MULTI_MARKET max_sale 1 0
#Id;Number;Start_Time;Time_unit;Period;Data_type;Y_unit;Pts;
0 0 20180227000000000 HOUR 0 -1 MW 7
# Time; f(t);
20180227000000000 9999
TUNNEL attributes Tunnel1
# loss_factor start_height end_height diameter length
0.00016 90 90 3 2022
TUNNEL attributes Tunnel2
# loss_factor start_height end_height diameter length
0.00015 90 90 3 2022
TUNNEL attributes Tunnel3
# loss_factor start_height end_height diameter length
0.00030 90 90 3 2022
#Write connection data for the hydro power system
#; From_type/To_type; From_name; To_name;
CONNECT RESERVOIR/TUNNEL Reservoir1 Tunnel1
CONNECT TUNNEL/RESERVOIR Tunnel1 Reservoir2
CONNECT RESERVOIR/TUNNEL Reservoir2 Tunnel2
CONNECT TUNNEL/RESERVOIR Tunnel2 Reservoir3
CONNECT RESERVOIR/TUNNEL Reservoir3 Tunnel3
CONNECT TUNNEL/PLANT Tunnel3 Plant1
tunnel_gate.ascii #
TUNNEL gate_positions Tunnel2
#Id;Number;Reference;Pts;X_unit;Y_unit
10600 0 0.000 4 NO_UNIT PERCENT
# x_value; y_value;
0 0.0
1 1.0
TUNNEL continuous_gate Tunnel2
1