mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 08:18:51 -06:00
add in after_build and after_optimize
This commit is contained in:
@@ -7,22 +7,64 @@
|
|||||||
instance::UnitCommitmentInstance,
|
instance::UnitCommitmentInstance,
|
||||||
method::TimeDecomposition;
|
method::TimeDecomposition;
|
||||||
optimizer,
|
optimizer,
|
||||||
|
after_build = nothing,
|
||||||
|
after_optimize = nothing,
|
||||||
)::OrderedDict
|
)::OrderedDict
|
||||||
|
|
||||||
Solve the given unit commitment instance with time decomposition.
|
Solve the given unit commitment instance with time decomposition.
|
||||||
The model solves each sub-problem of a given time length specified by method.time_window,
|
The model solves each sub-problem of a given time length specified by method.time_window,
|
||||||
and proceeds to the next sub-problem by incrementing the time length of method.time_increment.
|
and proceeds to the next sub-problem by incrementing the time length of `method.time_increment`.
|
||||||
|
|
||||||
|
Arguments
|
||||||
|
---------
|
||||||
|
|
||||||
|
- `instance`:
|
||||||
|
the UnitCommitment instance.
|
||||||
|
|
||||||
|
- `method`:
|
||||||
|
the `TimeDecomposition` method.
|
||||||
|
|
||||||
|
- `optimizer`:
|
||||||
|
the optimizer for solving the problem.
|
||||||
|
|
||||||
|
- `after_build`:
|
||||||
|
a user-defined function that allows modifying the model after building,
|
||||||
|
must have 2 arguments `model` and `instance` in order.
|
||||||
|
|
||||||
|
- `after_optimize`:
|
||||||
|
a user-defined function that allows handling additional steps after optimizing,
|
||||||
|
must have 3 arguments `solution`, `model` and `instance` in order.
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
```julia
|
```julia
|
||||||
using UnitCommitment, Cbc
|
using UnitCommitment, JuMP, Cbc, HiGHS
|
||||||
|
|
||||||
import UnitCommitment:
|
import UnitCommitment:
|
||||||
TimeDecomposition,
|
TimeDecomposition,
|
||||||
Formulation,
|
ConventionalLMP,
|
||||||
XavQiuWanThi2019
|
XavQiuWanThi2019,
|
||||||
|
Formulation
|
||||||
|
|
||||||
|
# specifying the after_build and after_optimize functions
|
||||||
|
function after_build(model, instance)
|
||||||
|
@constraint(
|
||||||
|
model,
|
||||||
|
model[:is_on]["g3", 1] + model[:is_on]["g4", 1] <= 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
lmps = []
|
||||||
|
function after_optimize(solution, model, instance)
|
||||||
|
lmp = UnitCommitment.compute_lmp(
|
||||||
|
model,
|
||||||
|
ConventionalLMP(),
|
||||||
|
optimizer = HiGHS.Optimizer,
|
||||||
|
)
|
||||||
|
return push!(lmps, lmp)
|
||||||
|
end
|
||||||
|
|
||||||
# assume the instance is given as a 120h problem
|
# assume the instance is given as a 120h problem
|
||||||
instance = UnitCommitment.read("instance.json")
|
instance = UnitCommitment.read("instance.json")
|
||||||
@@ -35,7 +77,9 @@ solution = UnitCommitment.optimize!(
|
|||||||
inner_method = XavQiuWanThi2019.Method(),
|
inner_method = XavQiuWanThi2019.Method(),
|
||||||
formulation = Formulation(),
|
formulation = Formulation(),
|
||||||
),
|
),
|
||||||
optimizer=Cbc.Optimizer
|
optimizer = Cbc.Optimizer,
|
||||||
|
after_build = after_build,
|
||||||
|
after_optimize = after_optimize,
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -43,6 +87,8 @@ function optimize!(
|
|||||||
instance::UnitCommitmentInstance,
|
instance::UnitCommitmentInstance,
|
||||||
method::TimeDecomposition;
|
method::TimeDecomposition;
|
||||||
optimizer,
|
optimizer,
|
||||||
|
after_build = nothing,
|
||||||
|
after_optimize = nothing,
|
||||||
)::OrderedDict
|
)::OrderedDict
|
||||||
# get instance total length
|
# get instance total length
|
||||||
T = instance.time
|
T = instance.time
|
||||||
@@ -58,16 +104,26 @@ function optimize!(
|
|||||||
# if t_end exceed total T
|
# if t_end exceed total T
|
||||||
t_end = t_end > T ? T : t_end
|
t_end = t_end > T ? T : t_end
|
||||||
# slice the model
|
# slice the model
|
||||||
modified = UnitCommitment.slice(instance, t_start:t_end)
|
@info "Solving the sub-problem of time $t_start to $t_end..."
|
||||||
# solve the model
|
sub_instance = UnitCommitment.slice(instance, t_start:t_end)
|
||||||
model = UnitCommitment.build_model(
|
# build and optimize the model
|
||||||
instance = modified,
|
sub_model = UnitCommitment.build_model(
|
||||||
|
instance = sub_instance,
|
||||||
optimizer = optimizer,
|
optimizer = optimizer,
|
||||||
formulation = method.formulation,
|
formulation = method.formulation,
|
||||||
)
|
)
|
||||||
UnitCommitment.optimize!(model, method.inner_method)
|
if after_build !== nothing
|
||||||
|
@info "Calling after build..."
|
||||||
|
after_build(sub_model, sub_instance)
|
||||||
|
end
|
||||||
|
UnitCommitment.optimize!(sub_model, method.inner_method)
|
||||||
# get the result of each time period
|
# get the result of each time period
|
||||||
sub_solution = UnitCommitment.solution(model)
|
sub_solution = UnitCommitment.solution(sub_model)
|
||||||
|
if after_optimize !== nothing
|
||||||
|
@info "Calling after optimize..."
|
||||||
|
after_optimize(sub_solution, sub_model, sub_instance)
|
||||||
|
end
|
||||||
|
# merge solution
|
||||||
if length(instance.scenarios) == 1
|
if length(instance.scenarios) == 1
|
||||||
_update_solution!(solution, sub_solution, method.time_increment)
|
_update_solution!(solution, sub_solution, method.time_increment)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||||
# Released under the modified BSD license. See COPYING.md for more details.
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
using UnitCommitment, DataStructures, Cbc
|
using UnitCommitment, DataStructures, Cbc, HiGHS
|
||||||
import UnitCommitment: TimeDecomposition, XavQiuWanThi2019, Formulation
|
import UnitCommitment: TimeDecomposition, ConventionalLMP
|
||||||
|
|
||||||
function solution_methods_TimeDecomposition_optimize_test()
|
function solution_methods_TimeDecomposition_optimize_test()
|
||||||
@testset "optimize_time_decomposition" begin
|
@testset "optimize_time_decomposition" begin
|
||||||
@@ -11,12 +11,7 @@ function solution_methods_TimeDecomposition_optimize_test()
|
|||||||
instance = UnitCommitment.read(fixture("case14.json.gz"))
|
instance = UnitCommitment.read(fixture("case14.json.gz"))
|
||||||
solution = UnitCommitment.optimize!(
|
solution = UnitCommitment.optimize!(
|
||||||
instance,
|
instance,
|
||||||
TimeDecomposition(
|
TimeDecomposition(time_window = 3, time_increment = 2),
|
||||||
time_window = 3,
|
|
||||||
time_increment = 2,
|
|
||||||
inner_method = XavQiuWanThi2019.Method(),
|
|
||||||
formulation = Formulation(),
|
|
||||||
),
|
|
||||||
optimizer = optimizer_with_attributes(
|
optimizer = optimizer_with_attributes(
|
||||||
Cbc.Optimizer,
|
Cbc.Optimizer,
|
||||||
"logLevel" => 0,
|
"logLevel" => 0,
|
||||||
@@ -26,6 +21,41 @@ function solution_methods_TimeDecomposition_optimize_test()
|
|||||||
@test length(solution["Is on"]["g2"]) == 4
|
@test length(solution["Is on"]["g2"]) == 4
|
||||||
@test length(solution["Spinning reserve (MW)"]["r1"]["g2"]) == 4
|
@test length(solution["Spinning reserve (MW)"]["r1"]["g2"]) == 4
|
||||||
|
|
||||||
|
# read one scenario with after_build and after_optimize
|
||||||
|
function after_build(model, instance)
|
||||||
|
@constraint(
|
||||||
|
model,
|
||||||
|
model[:is_on]["g3", 1] + model[:is_on]["g4", 1] <= 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
lmps = []
|
||||||
|
function after_optimize(solution, model, instance)
|
||||||
|
lmp = UnitCommitment.compute_lmp(
|
||||||
|
model,
|
||||||
|
ConventionalLMP(),
|
||||||
|
optimizer = HiGHS.Optimizer,
|
||||||
|
)
|
||||||
|
return push!(lmps, lmp)
|
||||||
|
end
|
||||||
|
|
||||||
|
instance = UnitCommitment.read(fixture("case14-profiled.json.gz"))
|
||||||
|
solution = UnitCommitment.optimize!(
|
||||||
|
instance,
|
||||||
|
TimeDecomposition(time_window = 3, time_increment = 2),
|
||||||
|
optimizer = optimizer_with_attributes(
|
||||||
|
Cbc.Optimizer,
|
||||||
|
"logLevel" => 0,
|
||||||
|
),
|
||||||
|
after_build = after_build,
|
||||||
|
after_optimize = after_optimize,
|
||||||
|
)
|
||||||
|
@test length(lmps) == 2
|
||||||
|
@test lmps[1]["s1", "b1", 1] == 50.0
|
||||||
|
@test lmps[2]["s1", "b10", 2] ≈ 38.04 atol = 0.1
|
||||||
|
@test solution["Is on"]["g3"][1] == 1.0
|
||||||
|
@test solution["Is on"]["g4"][1] == 0.0
|
||||||
|
|
||||||
# read multiple scenarios
|
# read multiple scenarios
|
||||||
instance = UnitCommitment.read([
|
instance = UnitCommitment.read([
|
||||||
fixture("case14.json.gz"),
|
fixture("case14.json.gz"),
|
||||||
@@ -33,12 +63,7 @@ function solution_methods_TimeDecomposition_optimize_test()
|
|||||||
])
|
])
|
||||||
solution = UnitCommitment.optimize!(
|
solution = UnitCommitment.optimize!(
|
||||||
instance,
|
instance,
|
||||||
TimeDecomposition(
|
TimeDecomposition(time_window = 3, time_increment = 2),
|
||||||
time_window = 3,
|
|
||||||
time_increment = 2,
|
|
||||||
inner_method = XavQiuWanThi2019.Method(),
|
|
||||||
formulation = Formulation(),
|
|
||||||
),
|
|
||||||
optimizer = optimizer_with_attributes(
|
optimizer = optimizer_with_attributes(
|
||||||
Cbc.Optimizer,
|
Cbc.Optimizer,
|
||||||
"logLevel" => 0,
|
"logLevel" => 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user