diff --git a/CHANGELOG.md b/CHANGELOG.md index c44ae12..ebe1121 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ All notable changes to this project will be documented in this file. [semver]: https://semver.org/spec/v2.0.0.html [pkjjl]: https://pkgdocs.julialang.org/v1/compatibility/#compat-pre-1.0 +## [0.3.0] - [Unreleased] +### Added +- Add multiple ramping formulations (ArrCon00, MorLatRam13, DamKucRajAta16, PanGua16) + ## [0.2.0] - 2021-05-28 ### Added - Add sub-hourly unit commitment. diff --git a/benchmark/benchmark.jl b/benchmark/benchmark.jl index d492ab0..742f12f 100644 --- a/benchmark/benchmark.jl +++ b/benchmark/benchmark.jl @@ -67,6 +67,9 @@ function main() "MorLatRam13" => UnitCommitment.Formulation( ramping = UnitCommitment.MorLatRam13(), ), + "PanGua16" => UnitCommitment.Formulation( + ramping = UnitCommitment.PanGua16(), + ), ) trials = [i for i in 1:5] combinations = [ diff --git a/src/UnitCommitment.jl b/src/UnitCommitment.jl index 6370cc5..8d42c7a 100644 --- a/src/UnitCommitment.jl +++ b/src/UnitCommitment.jl @@ -5,11 +5,12 @@ module UnitCommitment include("instance/structs.jl") -include("solution/structs.jl") include("model/formulations/base/structs.jl") include("model/formulations/ArrCon00/structs.jl") include("model/formulations/DamKucRajAta16/structs.jl") include("model/formulations/MorLatRam13/structs.jl") +include("model/formulations/PanGua16/structs.jl") +include("solution/structs.jl") include("solution/methods/XavQiuWanThi19/structs.jl") include("import/egret.jl") @@ -24,6 +25,7 @@ include("model/formulations/base/system.jl") include("model/formulations/base/unit.jl") include("model/formulations/DamKucRajAta16/ramp.jl") include("model/formulations/MorLatRam13/ramp.jl") +include("model/formulations/PanGua16/ramp.jl") include("model/jumpext.jl") include("solution/fix.jl") include("solution/methods/XavQiuWanThi19/enforce.jl") diff --git a/src/model/formulations/PanGua16/ramp.jl b/src/model/formulations/PanGua16/ramp.jl new file mode 100644 index 0000000..24ba25a --- /dev/null +++ b/src/model/formulations/PanGua16/ramp.jl @@ -0,0 +1,97 @@ +function _add_ramp_eqs!( + model::JuMP.Model, + g::Unit, + formulation::PanGua16, +)::Nothing + # TODO: Move upper case constants to model[:instance] + RESERVES_WHEN_SHUT_DOWN = true + gn = g.name + is_on = model[:is_on] + prod_above = model[:prod_above] + reserve = model[:reserve] + switch_off = model[:switch_off] + switch_on = model[:switch_on] + eq_str_prod_limit = _init(model, :eq_str_prod_limit) + eq_prod_limit_ramp_up_extra_period = + _init(model, :eq_prod_limit_ramp_up_extra_period) + eq_prod_limit_shutdown_trajectory = + _init(model, :eq_prod_limit_shutdown_trajectory) + UT = g.min_uptime + SU = g.startup_limit # startup rate, i.e., max production right after startup + SD = g.shutdown_limit # shutdown rate, i.e., max production right before shutdown + RU = g.ramp_up_limit # ramp up rate + RD = g.ramp_down_limit # ramp down rate + T = model[:instance].time + + for t in 1:T + Pbar = g.max_power[t] + if Pbar < 1e-7 + # Skip this time period if max power = 0 + continue + end + + #TRD = floor((Pbar - SU) / RD) # ramp down time + # TODO check amk changed TRD wrt Kneuven et al. + TRD = ceil((Pbar - SD) / RD) # ramp down time + TRU = floor((Pbar - SU) / RU) # ramp up time, can be negative if Pbar < SU + + # TODO check initial time periods: what if generator has been running for x periods? + # But maybe ok as long as (35) and (36) are also used... + if UT > 1 + # Equation (38) in Kneuven et al. (2020) + # Generalization of (20) + # Necessary that if any of the switch_on = 1 in the sum, + # then switch_off[gn, t+1] = 0 + eq_str_prod_limit[gn, t] = @constraint( + model, + prod_above[gn, t] + + g.min_power[t] * is_on[gn, t] + + reserve[gn, t] <= + Pbar * is_on[gn, t] - + (t < T ? (Pbar - SD) * switch_off[gn, t+1] : 0.0) - sum( + (Pbar - (SU + i * RU)) * switch_on[gn, t-i] for + i in 0:min(UT - 2, TRU, t - 1) + ) + ) + + if UT - 2 < TRU + # Equation (40) in Kneuven et al. (2020) + # Covers an additional time period of the ramp-up trajectory, compared to (38) + eq_prod_limit_ramp_up_extra_period[gn, t] = @constraint( + model, + prod_above[gn, t] + + g.min_power[t] * is_on[gn, t] + + reserve[gn, t] <= + Pbar * is_on[gn, t] - sum( + (Pbar - (SU + i * RU)) * switch_on[gn, t-i] for + i in 0:min(UT - 1, TRU, t - 1) + ) + ) + end + + # Add in shutdown trajectory if KSD >= 0 (else this is dominated by (38)) + KSD = min(TRD, UT - 1, T - t - 1) + if KSD > 0 + KSU = min(TRU, UT - 2 - KSD, t - 1) + # Equation (41) in Kneuven et al. (2020) + eq_prod_limit_shutdown_trajectory[gn, t] = @constraint( + model, + prod_above[gn, t] + + g.min_power[t] * is_on[gn, t] + + (RESERVES_WHEN_SHUT_DOWN ? reserve[gn, t] : 0.0) <= + Pbar * is_on[gn, t] - sum( + (Pbar - (SD + i * RD)) * switch_off[gn, t+1+i] for + i in 0:KSD + ) - sum( + (Pbar - (SU + i * RU)) * switch_on[gn, t-i] for + i in 0:KSU + ) - ( + (KSU >= TRU || KSU > t - 2) ? 0.0 : + max(0, (SU + (KSU + 1) * RU) - (SD + TRD * RD)) * + switch_on[gn, t-(KSU+1)] + ) + ) + end + end + end +end diff --git a/src/model/formulations/PanGua16/structs.jl b/src/model/formulations/PanGua16/structs.jl new file mode 100644 index 0000000..49d1fab --- /dev/null +++ b/src/model/formulations/PanGua16/structs.jl @@ -0,0 +1,11 @@ +# 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. + +""" +Formulation described in: + + Pan, K., & Guan, Y. (2016). Strong formulations for multistage stochastic + self-scheduling unit commitment. Operations Research, 64(6), 1482-1498. +""" +struct PanGua16 <: RampingFormulation end diff --git a/test/model/formulations_test.jl b/test/model/formulations_test.jl index dc39b2b..52dc75c 100644 --- a/test/model/formulations_test.jl +++ b/test/model/formulations_test.jl @@ -14,4 +14,5 @@ end _test(UnitCommitment.Formulation(ramping = UnitCommitment.ArrCon00())) _test(UnitCommitment.Formulation(ramping = UnitCommitment.DamKucRajAta16())) _test(UnitCommitment.Formulation(ramping = UnitCommitment.MorLatRam13())) + _test(UnitCommitment.Formulation(ramping = UnitCommitment.PanGua16())) end