From 5ca566f14781dedefe6b609519e5a26985738b62 Mon Sep 17 00:00:00 2001 From: Alinson S Xavier Date: Thu, 20 Jan 2022 15:51:23 -0600 Subject: [PATCH] Remove old reserves --- instances/test/case14.json.gz | Bin 1842 -> 1838 bytes src/instance/read.jl | 26 +++++-------------- src/instance/structs.jl | 8 +----- src/model/formulations/base/system.jl | 36 +++++--------------------- src/model/formulations/base/unit.jl | 25 +++++------------- src/solution/solution.jl | 19 +++++--------- src/validation/validate.jl | 24 +++-------------- 7 files changed, 29 insertions(+), 109 deletions(-) diff --git a/instances/test/case14.json.gz b/instances/test/case14.json.gz index 682622f6c4d6585d5eff46687fdca625fd942c31..0b7b54d811b53bcfa45ab7e21ed30f78f461f11a 100644 GIT binary patch delta 69 zcmV-L0J{IO4z3OcABzYG1fa17^9D8VA*u*K=eMi0Lv*&viUN~=AJ>~@*%q78Fa_%D brmUK)B+sWO!*>{8e0uQ@`H~kXf-e973`QPs delta 73 zcmV-P0Ji_G4zdmgABzYGDTuKK^9DJux5Kpi%6x$6{C1Ugkj_?FQDFA(1ADV9+hQ{t frcj;TlvQ(; ps for ps in loads), price_sensitive_loads = loads, reserves = reserves, - reserves2 = reserves2, reserves_by_name = name_to_reserve, shortfall_penalty = shortfall_penalty, time = T, diff --git a/src/instance/structs.jl b/src/instance/structs.jl index 33827ba..91e87bb 100644 --- a/src/instance/structs.jl +++ b/src/instance/structs.jl @@ -44,7 +44,6 @@ mutable struct Unit shutdown_limit::Float64 initial_status::Union{Int,Nothing} initial_power::Union{Float64,Nothing} - provides_spinning_reserves::Vector{Bool} startup_categories::Vector{StartupCategory} reserves::Vector{Reserve} end @@ -61,10 +60,6 @@ mutable struct TransmissionLine flow_limit_penalty::Vector{Float64} end -mutable struct Reserves - spinning::Vector{Float64} -end - mutable struct Contingency name::String lines::Vector{TransmissionLine} @@ -88,8 +83,7 @@ Base.@kwdef mutable struct UnitCommitmentInstance power_balance_penalty::Vector{Float64} price_sensitive_loads_by_name::Dict{AbstractString,PriceSensitiveLoad} price_sensitive_loads::Vector{PriceSensitiveLoad} - reserves::Reserves - reserves2::Vector{Reserve} + reserves::Vector{Reserve} reserves_by_name::Dict{AbstractString,Reserve} shortfall_penalty::Vector{Float64} time::Int diff --git a/src/model/formulations/base/system.jl b/src/model/formulations/base/system.jl index 7fef70f..a265b2e 100644 --- a/src/model/formulations/base/system.jl +++ b/src/model/formulations/base/system.jl @@ -28,42 +28,18 @@ function _add_net_injection_eqs!(model::JuMP.Model)::Nothing end function _add_reserve_eqs!(model::JuMP.Model)::Nothing - eq_min_reserve = _init(model, :eq_min_reserve) instance = model[:instance] - for t in 1:instance.time - # Equation (68) in Kneuven et al. (2020) - # As in Morales-España et al. (2013a) - # Akin to the alternative formulation with max_power_avail - # from Carrión and Arroyo (2006) and Ostrowski et al. (2012) - shortfall_penalty = instance.shortfall_penalty[t] - eq_min_reserve[t] = @constraint( - model, - sum(model[:reserve][g.name, t] for g in instance.units) + - (shortfall_penalty >= 0 ? model[:reserve_shortfall][t] : 0.0) >= - instance.reserves.spinning[t] - ) - - # Account for shortfall contribution to objective - if shortfall_penalty >= 0 - add_to_expression!( - model[:obj], - shortfall_penalty, - model[:reserve_shortfall][t], - ) - end - end - - eq_min_reserve2 = _init(model, :eq_min_reserve2) - for r in instance.reserves2 + eq_min_reserve = _init(model, :eq_min_reserve) + for r in instance.reserves for t in 1:instance.time # Equation (68) in Kneuven et al. (2020) # As in Morales-España et al. (2013a) # Akin to the alternative formulation with max_power_avail # from Carrión and Arroyo (2006) and Ostrowski et al. (2012) - eq_min_reserve2[r.name, t] = @constraint( + eq_min_reserve[r.name, t] = @constraint( model, - sum(model[:reserve2][r.name, g.name, t] for g in r.units) + - model[:reserve_shortfall2][r.name, t] >= r.amount[t] + sum(model[:reserve][r.name, g.name, t] for g in r.units) + + model[:reserve_shortfall][r.name, t] >= r.amount[t] ) # Account for shortfall contribution to objective @@ -71,7 +47,7 @@ function _add_reserve_eqs!(model::JuMP.Model)::Nothing add_to_expression!( model[:obj], r.shortfall_penalty, - model[:reserve_shortfall2][r.name, t], + model[:reserve_shortfall][r.name, t], ) end end diff --git a/src/model/formulations/base/unit.jl b/src/model/formulations/base/unit.jl index 51de4f2..1e08a90 100644 --- a/src/model/formulations/base/unit.jl +++ b/src/model/formulations/base/unit.jl @@ -45,26 +45,13 @@ _is_initially_on(g::Unit)::Float64 = (g.initial_status > 0 ? 1.0 : 0.0) function _add_reserve_vars!(model::JuMP.Model, g::Unit)::Nothing reserve = _init(model, :reserve) reserve_shortfall = _init(model, :reserve_shortfall) - for t in 1:model[:instance].time - if g.provides_spinning_reserves[t] - reserve[g.name, t] = @variable(model, lower_bound = 0) - else - reserve[g.name, t] = 0.0 - end - reserve_shortfall[t] = - (model[:instance].shortfall_penalty[t] >= 0) ? - @variable(model, lower_bound = 0) : 0.0 - end - - reserve2 = _init(model, :reserve2) - reserve_shortfall2 = _init(model, :reserve_shortfall2) for r in g.reserves for t in 1:model[:instance].time - reserve2[r.name, g.name, t] = @variable(model, lower_bound = 0) - if (r.name, t) ∉ keys(reserve_shortfall2) - reserve_shortfall2[r.name, t] = @variable(model, lower_bound = 0) + reserve[r.name, g.name, t] = @variable(model, lower_bound = 0) + if (r.name, t) ∉ keys(reserve_shortfall) + reserve_shortfall[r.name, t] = @variable(model, lower_bound = 0) if r.shortfall_penalty < 0 - set_upper_bound(reserve_shortfall2[r.name, t], 0.0) + set_upper_bound(reserve_shortfall[r.name, t], 0.0) end end end @@ -225,10 +212,10 @@ end function _total_reserves(model, g)::Vector T = model[:instance].time - reserve = [model[:reserve][g.name, t] for t in 1:T] + reserve = 0.0 if !isempty(g.reserves) reserve += [ - sum(model[:reserve2][r.name, g.name, t] for r in g.reserves) for + sum(model[:reserve][r.name, g.name, t] for r in g.reserves) for t in 1:model[:instance].time ] end diff --git a/src/solution/solution.jl b/src/solution/solution.jl index 35de2b3..57d6ef7 100644 --- a/src/solution/solution.jl +++ b/src/solution/solution.jl @@ -50,13 +50,6 @@ function solution(model::JuMP.Model)::OrderedDict sol["Is on"] = timeseries(model[:is_on], instance.units) sol["Switch on"] = timeseries(model[:switch_on], instance.units) sol["Switch off"] = timeseries(model[:switch_off], instance.units) - sol["Reserve (MW)"] = timeseries(model[:reserve], instance.units) - sol["Reserve shortfall (MW)"] = OrderedDict( - t => - (instance.shortfall_penalty[t] >= 0) ? - round(value(model[:reserve_shortfall][t]), digits = 5) : 0.0 for - t in 1:instance.time - ) sol["Net injection (MW)"] = timeseries(model[:net_injection], instance.buses) sol["Load curtail (MW)"] = timeseries(model[:curtail], instance.buses) @@ -67,19 +60,19 @@ function solution(model::JuMP.Model)::OrderedDict sol["Price-sensitive loads (MW)"] = timeseries(model[:loads], instance.price_sensitive_loads) end - sol["Reserve 2 (MW)"] = OrderedDict( + sol["Reserve (MW)"] = OrderedDict( r.name => OrderedDict( g.name => [ - value(model[:reserve2][r.name, g.name, t]) for + value(model[:reserve][r.name, g.name, t]) for t in 1:instance.time ] for g in r.units - ) for r in instance.reserves2 + ) for r in instance.reserves ) - sol["Reserve shortfall 2 (MW)"] = OrderedDict( + sol["Reserve shortfall (MW)"] = OrderedDict( r.name => [ - value(model[:reserve_shortfall2][r.name, t]) for + value(model[:reserve_shortfall][r.name, t]) for t in 1:instance.time - ] for r in instance.reserves2 + ] for r in instance.reserves ) return sol end diff --git a/src/validation/validate.jl b/src/validation/validate.jl index 62def52..5d69bc7 100644 --- a/src/validation/validate.jl +++ b/src/validation/validate.jl @@ -329,30 +329,12 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01) err_count += 1 end - # Verify spinning reserves - reserve = - sum(solution["Reserve (MW)"][g.name][t] for g in instance.units) - reserve_shortfall = - (instance.shortfall_penalty[t] >= 0) ? - solution["Reserve shortfall (MW)"][t] : 0 - - if reserve + reserve_shortfall < instance.reserves.spinning[t] - tol - @error @sprintf( - "Insufficient spinning reserves at time %d (%.2f + %.2f should be %.2f)", - t, - reserve, - reserve_shortfall, - instance.reserves.spinning[t], - ) - err_count += 1 - end - # Verify reserves - for r in instance.reserves2 + for r in instance.reserves provided = sum( - solution["Reserve 2 (MW)"][r.name][g.name][t] for g in r.units + solution["Reserve (MW)"][r.name][g.name][t] for g in r.units ) - shortfall = solution["Reserve shortfall 2 (MW)"][r.name][t] + shortfall = solution["Reserve shortfall (MW)"][r.name][t] required = r.amount[t] if provided + shortfall < required - tol