From adcaf6fc5584095d0de9552bc298a568a730c7ee Mon Sep 17 00:00:00 2001 From: Jun He Date: Fri, 19 May 2023 13:31:32 -0400 Subject: [PATCH] time decomposition tests --- test/runtests.jl | 7 + .../TimeDecomposition/initial_status_test.jl | 219 ++++++++++++++++++ .../TimeDecomposition/optimize_test.jl | 52 +++++ .../TimeDecomposition/update_solution_test.jl | 49 ++++ 4 files changed, 327 insertions(+) create mode 100644 test/solution/methods/TimeDecomposition/initial_status_test.jl create mode 100644 test/solution/methods/TimeDecomposition/optimize_test.jl create mode 100644 test/solution/methods/TimeDecomposition/update_solution_test.jl diff --git a/test/runtests.jl b/test/runtests.jl index 08ade97..a98fa79 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -28,6 +28,13 @@ FIXTURES = "$(@__DIR__)/fixtures" include("solution/methods/XavQiuWanThi19/find_test.jl") include("solution/methods/XavQiuWanThi19/sensitivity_test.jl") end + @testset "TimeDecomposition" begin + include("solution/methods/TimeDecomposition/initial_status_test.jl") + include( + "solution/methods/TimeDecomposition/update_solution_test.jl", + ) + include("solution/methods/TimeDecomposition/optimize_test.jl") + end end @testset "transform" begin include("transform/initcond_test.jl") diff --git a/test/solution/methods/TimeDecomposition/initial_status_test.jl b/test/solution/methods/TimeDecomposition/initial_status_test.jl new file mode 100644 index 0000000..cd253d8 --- /dev/null +++ b/test/solution/methods/TimeDecomposition/initial_status_test.jl @@ -0,0 +1,219 @@ +# UnitCommitment.jl: Optimization Package for Security-Constrained Unit Commitment +# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. +# Released under the modified BSD license. See COPYING.md for more details. + +using UnitCommitment, DataStructures + +@testset "determine_initial_status" begin + t_increment = 24 + t_model = 36 + hot_start = 100 + cold_start = -100 + + # all on throughout + stat_seq = ones(t_model) + # hot start + new_stat = UnitCommitment._determine_initial_status( + hot_start, + stat_seq, + t_increment, + ) + @test new_stat == 124 + # cold start + new_stat = UnitCommitment._determine_initial_status( + cold_start, + stat_seq, + t_increment, + ) + @test new_stat == 24 + + # off in the last 12 periods + stat_seq = ones(t_model) + stat_seq[25:end] .= 0 + # hot start + new_stat = UnitCommitment._determine_initial_status( + hot_start, + stat_seq, + t_increment, + ) + @test new_stat == 124 + # cold start + new_stat = UnitCommitment._determine_initial_status( + cold_start, + stat_seq, + t_increment, + ) + @test new_stat == 24 + + # off in one of the first 24 periods + stat_seq = ones(t_model) + stat_seq[10] = 0 + # hot start + new_stat = UnitCommitment._determine_initial_status( + hot_start, + stat_seq, + t_increment, + ) + @test new_stat == 14 + # cold start + new_stat = UnitCommitment._determine_initial_status( + cold_start, + stat_seq, + t_increment, + ) + @test new_stat == 14 + + # off in several of the first 24 periods + stat_seq = ones(t_model) + stat_seq[[10, 11, 20]] .= 0 + # hot start + new_stat = UnitCommitment._determine_initial_status( + hot_start, + stat_seq, + t_increment, + ) + @test new_stat == 4 + # cold start + new_stat = UnitCommitment._determine_initial_status( + cold_start, + 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 + stat_seq = zeros(t_model) + # hot start + new_stat = UnitCommitment._determine_initial_status( + hot_start, + stat_seq, + t_increment, + ) + @test new_stat == -24 + # cold start + new_stat = UnitCommitment._determine_initial_status( + cold_start, + stat_seq, + t_increment, + ) + @test new_stat == -124 + + # on in the last 12 periods + stat_seq = zeros(t_model) + stat_seq[25:end] .= 1 + # hot start + new_stat = UnitCommitment._determine_initial_status( + hot_start, + stat_seq, + t_increment, + ) + @test new_stat == -24 + # cold start + new_stat = UnitCommitment._determine_initial_status( + cold_start, + stat_seq, + t_increment, + ) + @test new_stat == -124 +end + +@testset "set_initial_status" begin + # read one scenario + instance = UnitCommitment.read("$FIXTURES/case14.json.gz") + psuedo_solution = OrderedDict( + "Thermal production (MW)" => OrderedDict( + "g1" => [110.0, 112.0, 114.0, 116.0], + "g2" => [100.0, 102.0, 0.0, 0.0], + "g3" => [0.0, 0.0, 0.0, 0.0], + "g4" => [33.0, 34.0, 66.0, 99.0], + "g5" => [33.0, 34.0, 66.0, 99.0], + "g6" => [100.0, 100.0, 100.0, 100.0], + ), + "Is on" => OrderedDict( + "g1" => [1.0, 1.0, 1.0, 1.0], + "g2" => [1.0, 1.0, 0.0, 0.0], + "g3" => [0.0, 0.0, 0.0, 0.0], + "g4" => [1.0, 1.0, 1.0, 1.0], + "g5" => [1.0, 1.0, 1.0, 1.0], + "g6" => [1.0, 1.0, 1.0, 1.0], + ), + ) + UnitCommitment._set_initial_status!(instance, psuedo_solution, 3) + thermal_units = instance.scenarios[1].thermal_units + @test thermal_units[1].initial_power == 114.0 + @test thermal_units[1].initial_status == 3.0 + @test thermal_units[2].initial_power == 0.0 + @test thermal_units[2].initial_status == -1.0 + @test thermal_units[3].initial_power == 0.0 + @test thermal_units[3].initial_status == -9.0 + + # read multiple scenarios + instance = UnitCommitment.read([ + "$FIXTURES/case14.json.gz", + "$FIXTURES/case14-profiled.json.gz", + ]) + psuedo_solution = OrderedDict( + "case14" => OrderedDict( + "Thermal production (MW)" => OrderedDict( + "g1" => [110.0, 112.0, 114.0, 116.0], + "g2" => [100.0, 102.0, 0.0, 0.0], + "g3" => [0.0, 0.0, 0.0, 0.0], + "g4" => [33.0, 34.0, 66.0, 99.0], + "g5" => [33.0, 34.0, 66.0, 99.0], + "g6" => [100.0, 100.0, 100.0, 100.0], + ), + "Is on" => OrderedDict( + "g1" => [1.0, 1.0, 1.0, 1.0], + "g2" => [1.0, 1.0, 0.0, 0.0], + "g3" => [0.0, 0.0, 0.0, 0.0], + "g4" => [1.0, 1.0, 1.0, 1.0], + "g5" => [1.0, 1.0, 1.0, 1.0], + "g6" => [1.0, 1.0, 1.0, 1.0], + ), + ), + "case14-profiled" => OrderedDict( + "Thermal production (MW)" => OrderedDict( + "g1" => [112.0, 113.0, 116.0, 115.0], + "g2" => [0.0, 0.0, 0.0, 0.0], + "g3" => [0.0, 0.0, 0.0, 20.0], + "g4" => [33.0, 34.0, 66.0, 99.0], + "g5" => [33.0, 34.0, 66.0, 99.0], + "g6" => [100.0, 100.0, 100.0, 100.0], + ), + "Is on" => OrderedDict( + "g1" => [1.0, 1.0, 1.0, 1.0], + "g2" => [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], + "g5" => [1.0, 1.0, 1.0, 1.0], + "g6" => [1.0, 1.0, 1.0, 1.0], + ), + ), + ) + UnitCommitment._set_initial_status!(instance, psuedo_solution, 3) + thermal_units_sc2 = instance.scenarios[2].thermal_units + @test thermal_units_sc2[1].initial_power == 116.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_status == -11.0 + @test thermal_units_sc2[3].initial_power == 0.0 + @test thermal_units_sc2[3].initial_status == -9.0 +end diff --git a/test/solution/methods/TimeDecomposition/optimize_test.jl b/test/solution/methods/TimeDecomposition/optimize_test.jl new file mode 100644 index 0000000..9987d1e --- /dev/null +++ b/test/solution/methods/TimeDecomposition/optimize_test.jl @@ -0,0 +1,52 @@ +# UnitCommitment.jl: Optimization Package for Security-Constrained Unit Commitment +# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. +# Released under the modified BSD license. See COPYING.md for more details. + +using UnitCommitment, DataStructures, Cbc +import UnitCommitment: TimeDecomposition, XavQiuWanThi2019, Formulation + +@testset "optimize_time_decomposition" begin + # read one scenario + instance = UnitCommitment.read("$FIXTURES/case14.json.gz") + solution = UnitCommitment.optimize!( + instance, + TimeDecomposition( + time_window = 3, + time_increment = 2, + inner_method = XavQiuWanThi2019.Method(), + formulation = Formulation(), + ), + optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0), + ) + @test length(solution["Thermal production (MW)"]["g1"]) == 4 + @test length(solution["Is on"]["g2"]) == 4 + @test length(solution["Spinning reserve (MW)"]["r1"]["g2"]) == 4 + + # read multiple scenarios + instance = UnitCommitment.read([ + "$FIXTURES/case14.json.gz", + "$FIXTURES/case14-profiled.json.gz", + ]) + solution = UnitCommitment.optimize!( + instance, + TimeDecomposition( + time_window = 3, + time_increment = 2, + inner_method = XavQiuWanThi2019.Method(), + formulation = Formulation(), + ), + optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0), + ) + @test length(solution["case14"]["Thermal production (MW)"]["g3"]) == 4 + @test length(solution["case14"]["Is on"]["g4"]) == 4 + @test length( + solution["case14-profiled"]["Thermal production (MW)"]["g5"], + ) == 4 + @test length(solution["case14-profiled"]["Is on"]["g6"]) == 4 + @test length( + solution["case14-profiled"]["Profiled production (MW)"]["g7"], + ) == 4 + @test length( + solution["case14-profiled"]["Spinning reserve (MW)"]["r1"]["g3"], + ) == 4 +end diff --git a/test/solution/methods/TimeDecomposition/update_solution_test.jl b/test/solution/methods/TimeDecomposition/update_solution_test.jl new file mode 100644 index 0000000..106002e --- /dev/null +++ b/test/solution/methods/TimeDecomposition/update_solution_test.jl @@ -0,0 +1,49 @@ +# UnitCommitment.jl: Optimization Package for Security-Constrained Unit Commitment +# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. +# Released under the modified BSD license. See COPYING.md for more details. + +using UnitCommitment, DataStructures + +@testset "update_solution" begin + psuedo_solution = OrderedDict() + time_increment = 4 + psuedo_sub_solution = OrderedDict( + "Thermal production (MW)" => + OrderedDict("g1" => [100.0, 200.0, 300.0, 400.0, 500.0, 600.0]), + "Is on" => OrderedDict("g1" => [1.0, 0.0, 1.0, 1.0, 0.0, 1.0]), + "Profiled production (MW)" => + OrderedDict("g1" => [199.0, 299.0, 399.0, 499.0, 599.0, 699.0]), + "Spinning reserve (MW)" => OrderedDict( + "r1" => OrderedDict("g1" => [31.0, 32.0, 33.0, 34.0, 35.0, 36.0]), + ), + ) + + # first update should directly copy the first 4 entries of sub solution + UnitCommitment._update_solution!( + psuedo_solution, + psuedo_sub_solution, + time_increment, + ) + @test psuedo_solution["Thermal production (MW)"]["g1"] == + [100.0, 200.0, 300.0, 400.0] + @test psuedo_solution["Is on"]["g1"] == [1.0, 0.0, 1.0, 1.0] + @test psuedo_solution["Profiled production (MW)"]["g1"] == + [199.0, 299.0, 399.0, 499.0] + @test psuedo_solution["Spinning reserve (MW)"]["r1"]["g1"] == + [31.0, 32.0, 33.0, 34.0] + + # second update should append the first 4 entries of sub solution + UnitCommitment._update_solution!( + psuedo_solution, + psuedo_sub_solution, + time_increment, + ) + @test psuedo_solution["Thermal production (MW)"]["g1"] == + [100.0, 200.0, 300.0, 400.0, 100.0, 200.0, 300.0, 400.0] + @test psuedo_solution["Is on"]["g1"] == + [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0] + @test psuedo_solution["Profiled production (MW)"]["g1"] == + [199.0, 299.0, 399.0, 499.0, 199.0, 299.0, 399.0, 499.0] + @test psuedo_solution["Spinning reserve (MW)"]["r1"]["g1"] == + [31.0, 32.0, 33.0, 34.0, 31.0, 32.0, 33.0, 34.0] +end