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 SDDP
using Test
import HiGHS
import Random
function 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::JuMP.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 -> JuMP.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))
return
end
test_inner_hydro_1d()
Building and solving primal outer model for lower bounds
-------------------------------------------------------------------
SDDP.jl (c) Oscar Dowson and contributors, 2017-25
-------------------------------------------------------------------
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 9.738922e-03 35 1
10 7.500000e+02 2.935390e+03 4.066491e-02 350 1
-------------------------------------------------------------------
status : iteration_limit
total time (s) : 4.066491e-02
total solves : 350
best bound : 2.935390e+03
simulation ci : 1.544902e+03 ± 5.533339e+02
numeric issues : 0
-------------------------------------------------------------------
Building and solving inner model for upper bounds:
Node: 3 - elapsed time: 0.01 plus 0.0 for vertex selection.
Node: 2 - elapsed time: 0.01 plus 0.0 for vertex selection.
Node: 1 - elapsed time: 0.01 plus 0.0 for vertex selection.
First-stage upper bound: 2969.680973503913
Total time for upper bound: 0.04153039
Bounds:
Risk-neutral confidence interval: 1411.99 ± 82.02
Risk-adjusted lower bound: 2935.39
Risk-adjusted upper bound: 2969.68