---
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.14.6
kernelspec:
display_name: Python 3 (ipykernel)
language: python
name: python3
---
(binary-pump-example)=
# Binary pumps
This example is available in the following formats:
- YAML
- [basic_pump.yaml](basic-pump-yaml)
- ASCII
- [basic_pump.ascii](basic-pump-ascii)
pyshop code for adding pump is provided below, while the initial model is available in [basic_pump.py](basic-pump-py).
## Introduction
This example imports a basic model and adds a simple binary [pump](pump). By varying the sale price in the [market](market), we see that the watercourse pumps water to the upper [reservoir](reservoir) when the price is lower than its water value.
## Imports
```{code-cell} ipython3
:Collapsed: 'false'
#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
```{code-cell} ipython3
:Collapsed: 'false'
#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())
```
## Add pumping capabilities
Pumps can be added as pump objects, and need to be connected to a [plant](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](pump:turb_eff_curves). Note that the point may still change as a function of head. If the [p_min](pump:p_min) and [p_max](pump: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.
```{code-cell} ipython3
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
```{code-cell} ipython3
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.
```{code-cell} ipython3
# 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="Market price and water value of reservoirs", xaxis_title="Time (Hour)", yaxis_title="Price (€/MWh)")
fig.show()
```
```{code-cell} ipython3
# 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="Pump consumption and generator production", xaxis_title="Time (Hour)", yaxis_title="Production/Consumption (MW)")
```
```{code-cell} ipython3
# 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="Reservoir trajectories ", xaxis_title="Time (Hour)", yaxis_title="Volume (Mm3)")
fig.show()
```
# File contents
(basic-pump-py)=
## basic_pump.py
```{code-cell} ipython3
:Collapsed: 'false'
:tags: [remove-input]
with open('basic_pump.py', 'r') as f:
print(f.read())
```
(basic-pump-yaml)=
## basic_pump.yaml
```{code-cell} ipython3
:Collapsed: 'false'
:tags: [remove-input]
shop.dump_yaml(file_path='basic_pump.yaml',input_only=True)
with open('basic_pump.yaml', 'r') as f:
print(f.read())
```
(basic-pump-ascii)=
## basic_pump.ascii
```{code-cell} ipython3
:Collapsed: 'false'
:tags: [remove-input]
with open('basic_pump.ascii', 'r') as f:
print(f.read())
```