Hydro-thermal with inner approximation
This tutorial was generated using Literate.jl. Download the source as a .jl file. Download the source as a .ipynb file.
This is a simple version of the hydro-thermal scheduling problem. The goal is to operate one hydro-dam and two thermal plants over time in the face of inflow uncertainty.
The purpose of this tutorial is to provide a demonstration of the experimental SDDP.Inner submodule.
The SDDP.Inner code in this example is experimental and the API may change in any future release.
using SDDPusing Testimport HiGHSimport Randomfunction test_inner_hydro_1d() Random.seed!(2) stages = 4 Ω = max.(40 .+ 20.0 * randn(10), 0.0) risk_measure = SDDP.EAVaR(; lambda = 0.5, beta = 0.2) function build_subproblem(sp::Model, t::Int) @variable(sp, 0 <= x_vol <= 100, SDDP.State, initial_value = 83.222) @variable(sp, 0 <= u_gh <= 60) @variable(sp, 0 <= u_spill <= 200) @variable(sp, 0 <= u_gt[1:2] <= 15) @variable(sp, 0 <= u_def <= 75) @variable(sp, w_inflow == 0.0) @constraint(sp, sum(u_gt) + u_gh + u_def == 75) @constraint(sp, x_vol.in + w_inflow - u_gh - u_spill == x_vol.out) if t > 1 SDDP.parameterize(w -> fix(w_inflow, w), sp, Ω) end @stageobjective(sp, u_spill + 5 * u_gt[1] + 10 * u_gt[2] + 50 * u_def) end println("Building and solving primal outer model for lower bounds") model = SDDP.LinearPolicyGraph( build_subproblem; stages, sense = :Min, optimizer = HiGHS.Optimizer, lower_bound = 0.0, ) SDDP.train(model; iteration_limit = 10, risk_measure) lower_bound = SDDP.calculate_bound(model) simulations = SDDP.simulate(model, 500, [:x_vol, :u_gh, :u_spill, :u_gt, :u_def]) objs = [sum(data[:stage_objective] for data in sim) for sim in simulations] μ, ci = round.(SDDP.confidence_interval(objs); digits = 2) println("Building and solving inner model for upper bounds:") inner_model, upper_bound = SDDP.Inner.inner_dp( build_subproblem, model; stages, sense = :Min, optimizer = HiGHS.Optimizer, lower_bound = 0.0, risk_measure, bellman_function = SDDP.Inner.InnerBellmanFunction( t -> 50.0 * (stages - t); upper_bound = t -> 75.0 * 50.0 * (stages - t), vertex_type = SDDP.SINGLE_CUT, ), ) @test lower_bound <= upper_bound println() println("Bounds:") println(" Risk-neutral confidence interval: ", μ, " ± ", ci) println(" Risk-adjusted lower bound: ", round(lower_bound; digits = 2)) println(" Risk-adjusted upper bound: ", round(upper_bound; digits = 2)) returnendtest_inner_hydro_1d()Building and solving primal outer model for lower bounds
-------------------------------------------------------------------
SDDP.jl (c) Oscar Dowson and contributors, 2017-26
-------------------------------------------------------------------
problem
nodes : 4
state variables : 1
scenarios : 1.00000e+03
existing cuts : false
options
solver : serial mode
risk measure : A convex combination of 0.5 * SDDP.Expectation() + 0.5 * SDDP.AVaR(0.2)
sampling scheme : SDDP.InSampleMonteCarlo
subproblem structure
VariableRef : [9, 9]
AffExpr in MOI.EqualTo{Float64} : [2, 2]
VariableRef in MOI.EqualTo{Float64} : [1, 1]
VariableRef in MOI.GreaterThan{Float64} : [7, 7]
VariableRef in MOI.LessThan{Float64} : [6, 7]
numerical stability report
matrix range [1e+00, 1e+00]
objective range [1e+00, 5e+01]
bounds range [2e+01, 2e+02]
rhs range [8e+01, 8e+01]
-------------------------------------------------------------------
iteration simulation bound time (s) solves pid
-------------------------------------------------------------------
1 1.948878e+03 2.847167e+03 2.048397e-02 35 1
10 7.500000e+02 2.935390e+03 1.234879e-01 350 1
-------------------------------------------------------------------
status : iteration_limit
total time (s) : 1.234879e-01
total solves : 350
best bound : 2.935390e+03
numeric issues : 0
-------------------------------------------------------------------
Building and solving inner model for upper bounds:
Node: 3 - elapsed time: 0.05 plus 0.02 for vertex selection.
Node: 2 - elapsed time: 0.01 plus 0.0 for vertex selection.
Node: 1 - elapsed time: 0.0 plus 0.0 for vertex selection.
First-stage upper bound: 2969.680973503913
Total time for upper bound: 0.089246535
Bounds:
Risk-neutral confidence interval: 1411.99 ± 82.02
Risk-adjusted lower bound: 2935.39
Risk-adjusted upper bound: 2969.68