Binary pumps#

This example is available in the following formats:

pyshop code for adding pump is provided below, while the initial model is available in basic_pump.py.

Introduction#

This example imports a basic model and adds a simple binary pump. By varying the sale price in the market, we see that the watercourse pumps water to the upper reservoir when the price is lower than its water value.

Imports#

#Necessary imports used in all examples
import pandas as pd
import plotly.graph_objs as go
import plotly.express as px

from pyshop import ShopSession

#Functions used in this example for building a basic SHOP model and running it
from basic_pump import build_model, run_model

Create a SHOP session and import basic model from file function#

#Create a standard ShopSession
shop=ShopSession()
#Build a basic SHOP model
build_model(shop)
#Display topology to the screen
display(shop.model.build_connection_tree())
../../_images/a60546a335f8fae3def216233fad9115c27bd058eabdc5a5b9cddc50dd16053e.svg

Add pumping capabilities#

Pumps can be added as pump objects, and need to be connected to a plant. We then apply attributes to the pump object. A binary pump only has a single operating point, which is specified by only supplying a single point in the turbine efficiency curves. Note that the point may still change as a function of head. If the p_min and p_max attributes of the binary pump are set to be equal, the pump will always consume this amount of power. If the operation of the pump should only be constrained by the points defined in the turbine efficiency curves, p_min and p_max can be set to unconstraining values such as 0 and 10000, respectively. In the example below, consumption will also be bounded to be within 38 and 42 MW. Whereas you in the old ASCII format don’t need to specify a maximum and minimum production for a binary pump, you need to explicitly add those attributes in addition to the nominal production in pyshop.

p1p1=shop.model.pump.add_object("P1P1")
p1p1.connect_to(shop.model.plant.Plant1)
p1p1.penstock.set(1)
p1p1.p_nom.set(40)
p1p1.p_min.set(38)
p1p1.p_max.set(42)
p1p1.startcost.set(500)
p1p1.gen_eff_curve.set(pd.Series([100,100], index=[0,50]))
p1p1.turb_eff_curves.set([pd.Series([87],index=[80],name=40),pd.Series([86],index=[70],name=50),pd.Series([85],index=[60],name=60)])

Run SHOP#

run_model(shop)

Plots and results#

We observe that the pump is used in the first six hours of the period, where the market price is lower than the water value in the upper reservoir.

# Plot market price and water value of reservoirs
spot_price=shop.model.market.Day_Ahead.sale_price.get()

fig = go.Figure()
colorscale = px.colors.sequential.RdBu_r
color = 1
fig.add_trace(go.Scatter(x=spot_price.index, marker_color = colorscale[color], y=spot_price.values, name="Market price"))

for rsv in shop.model.reservoir:
    color+=1
    end_water_value=rsv.energy_value_input.get()
    water_value=pd.Series([end_water_value]*len(spot_price),index=spot_price.index)
    curve_name="Water value of "+rsv.get_name()
    fig.add_trace(go.Scatter(x=water_value.index, y=water_value.values, marker_color = colorscale[color], name=curve_name, line=dict(dash="dot")))
    
fig.update_layout(title="<b>Market price and water value of reservoirs</b>", xaxis_title="<b>Time</b> (Hour)", yaxis_title="<b>Price</b> (€/MWh)")

fig.show()
# Plotting pump consumption and generator production
p1p1_consumption=shop.model.pump.P1P1.consumption.get()
p1g1_production=shop.model.generator.P1G1.production.get()
fig = go.Figure()
colorscale = px.colors.sequential.Magenta
fig.add_trace(go.Bar(x=p1p1_consumption.index, y=p1p1_consumption.values, name="Pump consumption", marker_color=colorscale[1]))
fig.add_trace(go.Bar(x=p1g1_production.index, y=p1g1_production.values, name="Generator production", marker_color=colorscale[6]))
fig.update_layout(title="<b>Pump consumption and generator production</b>", xaxis_title="<b>Time</b> (Hour)", yaxis_title="<b>Production/Consumption</b> (MW)")
# Plotting reservoir trajectories
water_storage_rsv1=shop.model.reservoir.Reservoir1.storage.get()
water_storage_rsv2=shop.model.reservoir.Reservoir2.storage.get()
fig = go.Figure()
colorscale = px.colors.sequential.RdBu_r
fig.add_trace(go.Scatter(x=water_storage_rsv1.index, y=water_storage_rsv1.values, name="Reservoir1 storage", marker_color=colorscale[1],fill='tozeroy'))
fig.add_trace(go.Scatter(x=water_storage_rsv2.index, y=water_storage_rsv2.values, name="Reservoir2 storage", marker_color=colorscale[2],fill='tozeroy'))
fig.update_layout(title="<b>Reservoir trajectories </b>", xaxis_title="<b>Time</b> (Hour)", yaxis_title="<b>Volume</b> (Mm<sup>3</sup>)")
fig.show()

File contents#

basic_pump.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]))

    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]))

    river = shop.model.river.add_object("outlet")
    river.upstream_elevation.set(50)
    river.flow_cost.set(10)

    rsv1.connect_to(plant1)
    plant1.connect_to(rsv2)
    rsv2.connect_to(river)

    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)
    
    
def run_model(shop):
    shop.start_sim([],['3'])
    shop.set_code(['inc'],[])
    shop.start_sim([],['3'])

basic_pump.yaml #

time:
  starttime: 2018-02-27 00:00:00
  endtime: 2018-02-28 00:00:00
  timeunit: hour
  timeresolution:
    2018-02-27 00:00:00: 1
model:
  reservoir:
    Reservoir1:
      max_vol: 12
      lrl: 90
      hrl: 100
      vol_head:
        ref: 0
        x:
          - 0
          - 12
          - 14
        y:
          - 90
          - 100
          - 101
      start_head: 92
      inflow:
        2018-02-27 00:00:00: 10
      energy_value_input: 39.7
    Reservoir2:
      max_vol: 5
      lrl: 40
      hrl: 50
      vol_head:
        ref: 0
        x:
          - 0
          - 5
          - 6
        y:
          - 40
          - 50
          - 51
      start_head: 43
      inflow:
        2018-02-27 00:00:00: 0
  plant:
    Plant1:
      outlet_line: 40
      main_loss:
        - 0.0002
      penstock_loss:
        - 0.0001
  generator:
    P1G1:
      penstock: 1
      p_min: 25
      p_max: 100
      p_nom: 100
      gen_eff_curve:
        ref: 0
        x:
          - 0
          - 100
        y:
          - 95
          - 98
      turb_eff_curves:
        - ref: 90
          x:
            - 25
            - 90
            - 100
          y:
            - 80
            - 95
            - 90
        - ref: 100
          x:
            - 25
            - 90
            - 100
          y:
            - 82
            - 98
            - 92
      startcost:
        2018-02-27 00:00:00: 500
  river:
    outlet:
      upstream_elevation: 50
      flow_cost:
        2018-02-27 00:00:00: 10
  market:
    Day_Ahead:
      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: 20.01
        2018-02-27 06:00:00: 40.01
      sale_price:
        2018-02-27 00:00:00: 19.99
        2018-02-27 06:00:00: 39.99
  pump:
    P1P1:
      penstock: 1
      p_min: 38
      p_max: 42
      p_nom: 40
      gen_eff_curve:
        ref: 0
        x:
          - 0
          - 50
        y:
          - 100
          - 100
      turb_eff_curves:
        - ref: 40
          x:
            - 80
          y:
            - 87
        - ref: 50
          x:
            - 70
          y:
            - 86
        - ref: 60
          x:
            - 60
          y:
            - 85
      startcost:
        2018-02-27 00:00:00: 500
connections:
  - from: Reservoir1
    to: Plant1
  - from: P1G1
    to: Plant1
  - from: P1P1
    to: Plant1
  - from: Plant1
    to: Reservoir2
  - from: Reservoir2
    to: outlet
commands:
  - start sim 3
  - set code /inc
  - start sim 3

basic_pump.ascii #

OPTIMIZATION time
#Start_time End_time Time_unit
20180227000000 20180228000000 HOUR

OPTIMIZATION time_resolution
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000 HOUR 876000000 -1 HOUR 1
#time y_value
20180227000000000 1

RESERVOIR declaration Reservoir1

RESERVOIR max_vol Reservoir1
12

RESERVOIR lrl Reservoir1
90

RESERVOIR hrl Reservoir1
100

RESERVOIR vol_head Reservoir1
#Id Number Referance Pts X_unit Y_unit
0 0 0 3 MM3 METER
#x_values y_value
0  90
12 100
14 101

RESERVOIR start_head Reservoir1
92

RESERVOIR inflow Reservoir1
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 M3/S 1
#time y_value
20180227000000000 10

RESERVOIR energy_value_input Reservoir1
39.7

RESERVOIR declaration Reservoir2

RESERVOIR max_vol Reservoir2
5

RESERVOIR lrl Reservoir2
40

RESERVOIR hrl Reservoir2
50

RESERVOIR vol_head Reservoir2
#Id Number Referance Pts X_unit Y_unit
0 0 0 3 MM3 METER
#x_values y_value
0 40
5 50
6 51

RESERVOIR start_head Reservoir2
43

RESERVOIR inflow Reservoir2
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 M3/S 1
#time y_value
20180227000000000 0

PLANT declaration Plant1

PLANT prod_area Plant1
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 NO_UNIT 1
#time y_value
20180227000000000 1

PLANT outlet_line Plant1
40

PLANT main_loss Plant1
0.0002 

PLANT penstock_loss Plant1
0.0001 

GENERATOR declaration P1G1

GENERATOR penstock P1G1
1

GENERATOR p_min P1G1
25

GENERATOR p_max P1G1
100

GENERATOR p_nom P1G1
100

GENERATOR gen_eff_curve P1G1
#Id Number Referance Pts X_unit Y_unit
0 0 0 2 MW %
#x_values y_value
0   95
100 98

GENERATOR turb_eff_curves P1G1
#Id Number Referance Pts X_unit Y_unit
0 0 90 3 M3/S %
#x_values y_value
25  80
90  95
100 90

GENERATOR turb_eff_curves P1G1
#Id Number Referance Pts X_unit Y_unit
0 0 100 3 M3/S %
#x_values y_value
25  82
90  98
100 92

GENERATOR startcost P1G1
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 NOK 1
#time y_value
20180227000000000 500

PUMP declaration P1P1

PUMP penstock P1P1
1

PUMP p_min P1P1
38

PUMP p_max P1P1
42

PUMP p_nom P1P1
40

PUMP gen_eff_curve P1P1
#Id Number Referance Pts X_unit Y_unit
0 0 0 2 MW %
#x_values y_value
0  100
50 100

PUMP turb_eff_curves P1P1
#Id Number Referance Pts X_unit Y_unit
0 0 40 1 M3/S %
#x_values y_value
80 87

PUMP turb_eff_curves P1P1
#Id Number Referance Pts X_unit Y_unit
0 0 50 1 M3/S %
#x_values y_value
70 86

PUMP turb_eff_curves P1P1
#Id Number Referance Pts X_unit Y_unit
0 0 60 1 M3/S %
#x_values y_value
60 85

PUMP startcost P1P1
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 NOK 1
#time y_value
20180227000000000 500

MARKET declaration Day_Ahead

MARKET max_buy Day_Ahead
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 MW 1
#time y_value
20180227000000000 9999

MARKET max_sale Day_Ahead
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 MW 1
#time y_value
20180227000000000 9999

MARKET buy_price Day_Ahead
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 NOK/MWH 2
#time y_value
20180227000000000 20.01
20180227060000000 40.01

MARKET sale_price Day_Ahead
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 NOK/MWH 2
#time y_value
20180227000000000 19.99
20180227060000000 39.99

RIVER declaration outlet

RIVER upstream_elevation outlet
50

RIVER flow_cost outlet
#Id Number Start_Time Time_unit Period Data_type Y_unit Pts
0 0 20180227000000000 HOUR 876000000 -1 NOK/M3/S 1
#time y_value
20180227000000000 10

# From_type/To_type from_name To_name
CONNECT GENERATOR/PLANT P1G1 Plant1
CONNECT RESERVOIR/PLANT Reservoir1 Plant1
CONNECT PLANT/RESERVOIR Plant1 Reservoir2
CONNECT RESERVOIR/RIVER Reservoir2 outlet
CONNECT PUMP/PLANT P1P1 Plant1