Simulating deviations from a production plan#
This documentation demonstrates how to use the SHOP simulator to simulate the validity of an optimized production plan and how changes to the production plan will affect the physical hydropower system. This could be useful when ensuring that a bid in an intra-day or real-time market is physically feasible without re-running the whole optimization.
The model setup for this example is available in the following format:
pyshop
System topology and initial simulation#
First, a simple SHOP model with two reservoirs and two plants are built. In addition, a reserve obligation for spinning FRR up and down reserves must be fulfilled by the generators in the system. See the reserve tutorial for more information about reserves and the reserve_group object.
#Necessary imports used in all examples
import pandas as pd
from pyshop import ShopSession
import plotly.graph_objects as go
pd.options.plotting.backend = "plotly"
from sim_two_rsv import build_model
#Create a standard ShopSession
shop=ShopSession()
#Build a simple model with two reservoirs, two plants, and 6 generators.
build_model(shop)
#Add a reserve_group object and 15 MW of FRR up and down requirements
frr = shop.model.reserve_group.add_object("frr_group")
frr.frr_up_obligation.set(15)
frr.frr_down_obligation.set(15)
#Connect all generators to the reserve group
for gen in shop.model.generator:
gen.connect_to(frr)
#Display topology to the screen
display(shop.model.build_connection_tree())
To get a baseline production plan for each generator, a basic optimization of the system is performed:
#Run an optimizatio
shop.start_sim([],5)
shop.set_code("incremental",[])
shop.start_sim([],5)
The optimized production plan for each generator has now been set by the optimization, and the start shopsim command can be used with the option “gen_mw_result”. This will perform a simulation of the system based on the initial reservoir state, reservoir inflow, and the generator production plans.
The output time resolution of the simulated timeseries attributes is set to 60 seconds with the optional value given to the shopsim command.
# Run a simulation based on the optimized production levels for each generator
shop.start_shopsim(["gen_mw_result"], 60)
After running the simulation, it is possible to retrieve various simulation result attributes on the regular SHOP objects. The simulated generator production values are stored as the attribute sim_production, which are identical to the optimized production plans since the “gen_mw_result” option was used. This is confirmed in the figure below, which shows the sum plant production in the simulator and optimization:
for plant in shop.model.plant:
fig = go.Figure()
name = plant.get_name()
sim_dis = plant.sim_production.get()
opt_dis = plant.production.get()
opt_dis[sim_dis.index[-1]] = opt_dis.values[-1]
opt_dis = opt_dis.resample("1min").ffill()
fig.add_trace(go.Scatter(x=opt_dis.index, y=opt_dis.values, name="optimized"))
fig.add_trace(go.Scatter(x=sim_dis.index, y=sim_dis.values, name="simulated", line=dict(dash='dash')))
fig.update_layout(xaxis_title="Time", yaxis_title="Power [MW]",title=f"Production: {name}")
fig.show()