time decomp bug fix

pull/31/head
Jun He 2 years ago
parent ec2d56602b
commit 7201acde78

@ -142,16 +142,28 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
return x return x
end end
time_horizon = json["Parameters"]["Time horizon (min)"]
if time_horizon === nothing
time_horizon = json["Parameters"]["Time (h)"] time_horizon = json["Parameters"]["Time (h)"]
if time_horizon === nothing if time_horizon === nothing
time_horizon = json["Parameters"]["Time horizon (h)"] time_horizon = json["Parameters"]["Time horizon (h)"]
end end
time_horizon !== nothing || error("Missing parameter: Time horizon (h)") if time_horizon !== nothing
time_horizon *= 60
end
end
time_horizon !== nothing || error("Missing parameter: Time horizon (min)")
isinteger(time_horizon) ||
error("Time horizon must be an integer in minutes")
time_horizon = Int(time_horizon)
time_step = scalar(json["Parameters"]["Time step (min)"], default = 60) time_step = scalar(json["Parameters"]["Time step (min)"], default = 60)
(60 % time_step == 0) || (60 % time_step == 0) ||
error("Time step $time_step is not a divisor of 60") error("Time step $time_step is not a divisor of 60")
(time_horizon % time_step == 0) || error(
"Time step $time_step is not a divisor of time horizon $time_horizon",
)
time_multiplier = 60 ÷ time_step time_multiplier = 60 ÷ time_step
T = time_horizon * time_multiplier T = time_horizon ÷ time_step
probability = json["Parameters"]["Scenario weight"] probability = json["Parameters"]["Scenario weight"]
probability !== nothing || (probability = 1) probability !== nothing || (probability = 1)
@ -408,6 +420,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
reserves = reserves, reserves = reserves,
reserves_by_name = name_to_reserve, reserves_by_name = name_to_reserve,
time = T, time = T,
time_step = time_step,
thermal_units_by_name = Dict(g.name => g for g in thermal_units), thermal_units_by_name = Dict(g.name => g for g in thermal_units),
thermal_units = thermal_units, thermal_units = thermal_units,
profiled_units_by_name = Dict(pu.name => pu for pu in profiled_units), profiled_units_by_name = Dict(pu.name => pu for pu in profiled_units),

@ -104,6 +104,7 @@ Base.@kwdef mutable struct UnitCommitmentScenario
thermal_units_by_name::Dict{AbstractString,ThermalUnit} thermal_units_by_name::Dict{AbstractString,ThermalUnit}
thermal_units::Vector{ThermalUnit} thermal_units::Vector{ThermalUnit}
time::Int time::Int
time_step::Int
end end
Base.@kwdef mutable struct UnitCommitmentInstance Base.@kwdef mutable struct UnitCommitmentInstance

@ -47,7 +47,6 @@ function optimize!(
# get instance total length # get instance total length
T = instance.time T = instance.time
solution = OrderedDict() solution = OrderedDict()
iter = 0
if length(instance.scenarios) > 1 if length(instance.scenarios) > 1
for sc in instance.scenarios for sc in instance.scenarios
solution[sc.name] = OrderedDict() solution[sc.name] = OrderedDict()
@ -55,10 +54,6 @@ function optimize!(
end end
# for each iteration, time increment by method.time_increment # for each iteration, time increment by method.time_increment
for t_start in 1:method.time_increment:T for t_start in 1:method.time_increment:T
# set the initial status
if iter > 0
_set_initial_status!(instance, solution, method.time_increment)
end
t_end = t_start + method.time_window - 1 t_end = t_start + method.time_window - 1
# 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
@ -84,7 +79,8 @@ function optimize!(
) )
end end
end end
iter += 1 # increment iteration counter # set the initial status for the next sub-problem
_set_initial_status!(instance, solution, method.time_increment)
end end
return solution return solution
end end
@ -96,7 +92,7 @@ end
time_increment::Int, time_increment::Int,
) )
Set the thermal units' initial power levels and statuses based on the first bunch of time slots Set the thermal units' initial power levels and statuses based on the last bunch of time slots
specified by time_increment in the solution dictionary. specified by time_increment in the solution dictionary.
""" """
function _set_initial_status!( function _set_initial_status!(
@ -114,11 +110,10 @@ function _set_initial_status!(
solution[sc.name]["Thermal production (MW)"][thermal_unit.name] solution[sc.name]["Thermal production (MW)"][thermal_unit.name]
is_on = solution[sc.name]["Is on"][thermal_unit.name] is_on = solution[sc.name]["Is on"][thermal_unit.name]
end end
thermal_unit.initial_power = prod[time_increment] thermal_unit.initial_power = prod[end]
thermal_unit.initial_status = _determine_initial_status( thermal_unit.initial_status = _determine_initial_status(
thermal_unit.initial_status, thermal_unit.initial_status,
is_on, is_on[end-time_increment+1:end],
time_increment,
) )
end end
end end
@ -128,16 +123,14 @@ end
_determine_initial_status( _determine_initial_status(
prev_initial_status::Union{Float64,Int}, prev_initial_status::Union{Float64,Int},
status_sequence::Vector{Float64}, status_sequence::Vector{Float64},
time_increment::Int,
)::Union{Float64,Int} )::Union{Float64,Int}
Determines a thermal unit's initial status based on its previous initial status, and Determines a thermal unit's initial status based on its previous initial status, and
the on/off statuses in first bunch of time slots. the on/off statuses in the last operation.
""" """
function _determine_initial_status( function _determine_initial_status(
prev_initial_status::Union{Float64,Int}, prev_initial_status::Union{Float64,Int},
status_sequence::Vector{Float64}, status_sequence::Vector{Float64},
time_increment::Int,
)::Union{Float64,Int} )::Union{Float64,Int}
# initialize the two flags # initialize the two flags
on_status = prev_initial_status on_status = prev_initial_status
@ -147,8 +140,8 @@ function _determine_initial_status(
# if the on_status < 0, set it to 1.0 # if the on_status < 0, set it to 1.0
# at each time if the unit is off, reset on_status, decrement off_status # at each time if the unit is off, reset on_status, decrement off_status
# if the off_status > 0, set it to -1.0 # if the off_status > 0, set it to -1.0
for t in 1:time_increment for status in status_sequence
if status_sequence[t] == 1.0 if status == 1.0
on_status = on_status < 0.0 ? 1.0 : on_status + 1.0 on_status = on_status < 0.0 ? 1.0 : on_status + 1.0
off_status = 0.0 off_status = 0.0
else else

@ -20,6 +20,7 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
@test length(sc.contingencies) == 19 @test length(sc.contingencies) == 19
@test length(sc.price_sensitive_loads) == 1 @test length(sc.price_sensitive_loads) == 1
@test instance.time == 4 @test instance.time == 4
@test sc.time_step == 60
@test sc.lines[5].name == "l5" @test sc.lines[5].name == "l5"
@test sc.lines[5].source.name == "b2" @test sc.lines[5].source.name == "b2"

@ -5,134 +5,66 @@
using UnitCommitment, DataStructures using UnitCommitment, DataStructures
@testset "determine_initial_status" begin @testset "determine_initial_status" begin
t_increment = 24
t_model = 36
hot_start = 100 hot_start = 100
cold_start = -100 cold_start = -100
# all on throughout # all on throughout
stat_seq = ones(t_model) stat_seq = ones(36)
# hot start # hot start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(hot_start, stat_seq)
hot_start, @test new_stat == 136
stat_seq,
t_increment,
)
@test new_stat == 124
# cold start # cold start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(cold_start, stat_seq)
cold_start, @test new_stat == 36
stat_seq,
t_increment,
)
@test new_stat == 24
# off in the last 12 periods # off in the last 12 periods
stat_seq = ones(t_model) stat_seq = ones(36)
stat_seq[25:end] .= 0 stat_seq[25:end] .= 0
# hot start # hot start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(hot_start, stat_seq)
hot_start, @test new_stat == -12
stat_seq,
t_increment,
)
@test new_stat == 124
# cold start # cold start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(cold_start, stat_seq)
cold_start, @test new_stat == -12
stat_seq,
t_increment,
)
@test new_stat == 24
# off in one of the first 24 periods # off in one period
stat_seq = ones(t_model) stat_seq = ones(36)
stat_seq[10] = 0 stat_seq[10] = 0
# hot start # hot start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(hot_start, stat_seq)
hot_start, @test new_stat == 26
stat_seq,
t_increment,
)
@test new_stat == 14
# cold start # cold start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(cold_start, stat_seq)
cold_start, @test new_stat == 26
stat_seq,
t_increment,
)
@test new_stat == 14
# off in several of the first 24 periods # off in several of the first 24 periods
stat_seq = ones(t_model) stat_seq = ones(36)
stat_seq[[10, 11, 20]] .= 0 stat_seq[[10, 11, 20]] .= 0
# hot start # hot start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(hot_start, stat_seq)
hot_start, @test new_stat == 16
stat_seq,
t_increment,
)
@test new_stat == 4
# cold start # cold start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(cold_start, stat_seq)
cold_start, @test new_stat == 16
stat_seq,
t_increment,
)
@test new_stat == 4
# off in several of the first 24 periods
stat_seq = ones(t_model)
stat_seq[20:24] .= 0
# hot start
new_stat = UnitCommitment._determine_initial_status(
hot_start,
stat_seq,
t_increment,
)
@test new_stat == -5
# cold start
new_stat = UnitCommitment._determine_initial_status(
cold_start,
stat_seq,
t_increment,
)
@test new_stat == -5
# all off throughout # all off throughout
stat_seq = zeros(t_model) stat_seq = zeros(36)
# hot start # hot start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(hot_start, stat_seq)
hot_start, @test new_stat == -36
stat_seq,
t_increment,
)
@test new_stat == -24
# cold start # cold start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(cold_start, stat_seq)
cold_start, @test new_stat == -136
stat_seq,
t_increment,
)
@test new_stat == -124
# on in the last 12 periods # on in the last 12 periods
stat_seq = zeros(t_model) stat_seq = zeros(36)
stat_seq[25:end] .= 1 stat_seq[25:end] .= 1
# hot start # hot start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(hot_start, stat_seq)
hot_start, @test new_stat == 12
stat_seq,
t_increment,
)
@test new_stat == -24
# cold start # cold start
new_stat = UnitCommitment._determine_initial_status( new_stat = UnitCommitment._determine_initial_status(cold_start, stat_seq)
cold_start, @test new_stat == 12
stat_seq,
t_increment,
)
@test new_stat == -124
end end
@testset "set_initial_status" begin @testset "set_initial_status" begin
@ -140,28 +72,28 @@ end
instance = UnitCommitment.read("$FIXTURES/case14.json.gz") instance = UnitCommitment.read("$FIXTURES/case14.json.gz")
psuedo_solution = OrderedDict( psuedo_solution = OrderedDict(
"Thermal production (MW)" => OrderedDict( "Thermal production (MW)" => OrderedDict(
"g1" => [110.0, 112.0, 114.0, 116.0], "g1" => [0.0, 112.0, 114.0, 116.0],
"g2" => [100.0, 102.0, 0.0, 0.0], "g2" => [0.0, 102.0, 0.0, 0.0],
"g3" => [0.0, 0.0, 0.0, 0.0], "g3" => [0.0, 0.0, 0.0, 0.0],
"g4" => [33.0, 34.0, 66.0, 99.0], "g4" => [0.0, 34.0, 66.0, 99.0],
"g5" => [33.0, 34.0, 66.0, 99.0], "g5" => [0.0, 34.0, 66.0, 99.0],
"g6" => [100.0, 100.0, 100.0, 100.0], "g6" => [0.0, 100.0, 100.0, 100.0],
), ),
"Is on" => OrderedDict( "Is on" => OrderedDict(
"g1" => [1.0, 1.0, 1.0, 1.0], "g1" => [0.0, 1.0, 1.0, 1.0],
"g2" => [1.0, 1.0, 0.0, 0.0], "g2" => [0.0, 1.0, 0.0, 0.0],
"g3" => [0.0, 0.0, 0.0, 0.0], "g3" => [0.0, 0.0, 0.0, 0.0],
"g4" => [1.0, 1.0, 1.0, 1.0], "g4" => [0.0, 1.0, 1.0, 1.0],
"g5" => [1.0, 1.0, 1.0, 1.0], "g5" => [0.0, 1.0, 1.0, 1.0],
"g6" => [1.0, 1.0, 1.0, 1.0], "g6" => [0.0, 1.0, 1.0, 1.0],
), ),
) )
UnitCommitment._set_initial_status!(instance, psuedo_solution, 3) UnitCommitment._set_initial_status!(instance, psuedo_solution, 3)
thermal_units = instance.scenarios[1].thermal_units thermal_units = instance.scenarios[1].thermal_units
@test thermal_units[1].initial_power == 114.0 @test thermal_units[1].initial_power == 116.0
@test thermal_units[1].initial_status == 3.0 @test thermal_units[1].initial_status == 3.0
@test thermal_units[2].initial_power == 0.0 @test thermal_units[2].initial_power == 0.0
@test thermal_units[2].initial_status == -1.0 @test thermal_units[2].initial_status == -2.0
@test thermal_units[3].initial_power == 0.0 @test thermal_units[3].initial_power == 0.0
@test thermal_units[3].initial_status == -9.0 @test thermal_units[3].initial_status == -9.0
@ -173,47 +105,47 @@ end
psuedo_solution = OrderedDict( psuedo_solution = OrderedDict(
"case14" => OrderedDict( "case14" => OrderedDict(
"Thermal production (MW)" => OrderedDict( "Thermal production (MW)" => OrderedDict(
"g1" => [110.0, 112.0, 114.0, 116.0], "g1" => [0.0, 112.0, 114.0, 116.0],
"g2" => [100.0, 102.0, 0.0, 0.0], "g2" => [0.0, 102.0, 0.0, 0.0],
"g3" => [0.0, 0.0, 0.0, 0.0], "g3" => [0.0, 0.0, 0.0, 0.0],
"g4" => [33.0, 34.0, 66.0, 99.0], "g4" => [0.0, 34.0, 66.0, 99.0],
"g5" => [33.0, 34.0, 66.0, 99.0], "g5" => [0.0, 34.0, 66.0, 99.0],
"g6" => [100.0, 100.0, 100.0, 100.0], "g6" => [0.0, 100.0, 100.0, 100.0],
), ),
"Is on" => OrderedDict( "Is on" => OrderedDict(
"g1" => [1.0, 1.0, 1.0, 1.0], "g1" => [0.0, 1.0, 1.0, 1.0],
"g2" => [1.0, 1.0, 0.0, 0.0], "g2" => [0.0, 1.0, 0.0, 0.0],
"g3" => [0.0, 0.0, 0.0, 0.0], "g3" => [0.0, 0.0, 0.0, 0.0],
"g4" => [1.0, 1.0, 1.0, 1.0], "g4" => [0.0, 1.0, 1.0, 1.0],
"g5" => [1.0, 1.0, 1.0, 1.0], "g5" => [0.0, 1.0, 1.0, 1.0],
"g6" => [1.0, 1.0, 1.0, 1.0], "g6" => [0.0, 1.0, 1.0, 1.0],
), ),
), ),
"case14-profiled" => OrderedDict( "case14-profiled" => OrderedDict(
"Thermal production (MW)" => OrderedDict( "Thermal production (MW)" => OrderedDict(
"g1" => [112.0, 113.0, 116.0, 115.0], "g1" => [0.0, 113.0, 116.0, 115.0],
"g2" => [0.0, 0.0, 0.0, 0.0], "g2" => [0.0, 0.0, 0.0, 0.0],
"g3" => [0.0, 0.0, 0.0, 20.0], "g3" => [0.0, 0.0, 0.0, 20.0],
"g4" => [33.0, 34.0, 66.0, 99.0], "g4" => [0.0, 34.0, 66.0, 98.0],
"g5" => [33.0, 34.0, 66.0, 99.0], "g5" => [0.0, 34.0, 66.0, 97.0],
"g6" => [100.0, 100.0, 100.0, 100.0], "g6" => [0.0, 100.0, 100.0, 100.0],
), ),
"Is on" => OrderedDict( "Is on" => OrderedDict(
"g1" => [1.0, 1.0, 1.0, 1.0], "g1" => [0.0, 1.0, 1.0, 1.0],
"g2" => [0.0, 0.0, 0.0, 0.0], "g2" => [0.0, 0.0, 0.0, 0.0],
"g3" => [0.0, 0.0, 0.0, 0.0], "g3" => [0.0, 0.0, 0.0, 1.0],
"g4" => [1.0, 1.0, 1.0, 1.0], "g4" => [0.0, 1.0, 1.0, 1.0],
"g5" => [1.0, 1.0, 1.0, 1.0], "g5" => [0.0, 1.0, 1.0, 1.0],
"g6" => [1.0, 1.0, 1.0, 1.0], "g6" => [0.0, 1.0, 1.0, 1.0],
), ),
), ),
) )
UnitCommitment._set_initial_status!(instance, psuedo_solution, 3) UnitCommitment._set_initial_status!(instance, psuedo_solution, 3)
thermal_units_sc2 = instance.scenarios[2].thermal_units thermal_units_sc2 = instance.scenarios[2].thermal_units
@test thermal_units_sc2[1].initial_power == 116.0 @test thermal_units_sc2[1].initial_power == 115.0
@test thermal_units_sc2[1].initial_status == 3.0 @test thermal_units_sc2[1].initial_status == 3.0
@test thermal_units_sc2[2].initial_power == 0.0 @test thermal_units_sc2[2].initial_power == 0.0
@test thermal_units_sc2[2].initial_status == -11.0 @test thermal_units_sc2[2].initial_status == -11.0
@test thermal_units_sc2[3].initial_power == 0.0 @test thermal_units_sc2[3].initial_power == 20.0
@test thermal_units_sc2[3].initial_status == -9.0 @test thermal_units_sc2[3].initial_status == 1.0
end end

Loading…
Cancel
Save