add flexiramp

This commit is contained in:
oyurdakul
2022-02-03 09:45:06 +01:00
parent 5e2cdb9e0c
commit a3a71ff5a9
13 changed files with 338 additions and 15 deletions

View File

@@ -0,0 +1,152 @@
# UnitCommitmentFL.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.
function _add_flexiramp_vars!(model::JuMP.Model, g::Unit)::Nothing
upflexiramp = _init(model, :upflexiramp)
upflexiramp_shortfall = _init(model, :upflexiramp_shortfall)
mfg=_init(model,:mfg)
dwflexiramp = _init(model, :dwflexiramp)
dwflexiramp_shortfall = _init(model, :dwflexiramp_shortfall)
for t in 1:model[:instance].time
# maximum feasible generation, \bar{g_{its}} in Wang & Hobbs (2016)
mfg[g.name,t]=@variable(model, lower_bound = 0)
if g.provides_flexiramp_reserves[t]
upflexiramp[g.name, t] = @variable(model) # up-flexiramp, ur_{it} in Wang & Hobbs (2016)
dwflexiramp[g.name, t] = @variable(model) # down-flexiramp, dr_{it} in Wang & Hobbs (2016)
else
upflexiramp[g.name, t] = 0.0
dwflexiramp[g.name, t] = 0.0
end
upflexiramp_shortfall[t] =
(model[:instance].flexiramp_shortfall_penalty[t] >= 0) ?
@variable(model, lower_bound = 0) : 0.0
dwflexiramp_shortfall[t] =
(model[:instance].flexiramp_shortfall_penalty[t] >= 0) ?
@variable(model, lower_bound = 0) : 0.0
end
return
end
function _add_ramp_eqs!(
model::JuMP.Model,
g::Unit,
formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::WanHob2016.Ramping,
formulation_status_vars::Gar1962.StatusVars,
)::Nothing
is_initially_on = (g.initial_status > 0)
SU = g.startup_limit
SD = g.shutdown_limit
RU = g.ramp_up_limit
RD = g.ramp_down_limit
gn = g.name
minp=g.min_power
maxp=g.max_power
initial_power=g.initial_power
is_on = model[:is_on]
prod_above = model[:prod_above]
upflexiramp=model[:upflexiramp]
dwflexiramp=model[:dwflexiramp]
mfg=model[:mfg]
for t in 1:model[:instance].time
@constraint(model, prod_above[gn, t] + (is_on[gn,t]*minp[t])
<=mfg[gn,t]) # Eq. (19) in Wang & Hobbs (2016)
@constraint(model, mfg[gn,t]<= is_on[gn,t]* maxp[t]) # Eq. (22) in Wang & Hobbs (2016)
if t!=model[:instance].time
@constraint(model, minp[t] * (is_on[gn,t+1]+is_on[gn,t]-1) <=
prod_above[gn, t] - dwflexiramp[gn,t] +(is_on[gn,t]*minp[t])
) # first inequality of Eq. (20) in Wang & Hobbs (2016)
@constraint(model, prod_above[gn, t] - dwflexiramp[gn,t] + (is_on[gn,t]*minp[t]) <=
mfg[gn,t+1]
+ (maxp[t] * (1-is_on[gn,t+1]))
) # second inequality of Eq. (20) in Wang & Hobbs (2016)
@constraint(model, minp[t] * (is_on[gn,t+1]+is_on[gn,t]-1) <=
prod_above[gn, t] + upflexiramp[gn,t] + (is_on[gn,t]*minp[t])
) # first inequality of Eq. (21) in Wang & Hobbs (2016)
@constraint(model, prod_above[gn, t] + upflexiramp[gn,t] +(is_on[gn,t]*minp[t]) <=
mfg[gn,t+1] + (maxp[t] * (1-is_on[gn,t+1]))
) # second inequality of Eq. (21) in Wang & Hobbs (2016)
if t!=1
@constraint(model, mfg[gn,t]<=prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t])
+ (RU * is_on[gn,t-1])
+ (SU*(is_on[gn,t] - is_on[gn,t-1]))
+ maxp[t] * (1-is_on[gn,t])
) # Eq. (23) in Wang & Hobbs (2016)
@constraint(model, (prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t]))
- (prod_above[gn,t] + (is_on[gn,t]*minp[t]))
<= RD * is_on[gn,t]
+ SD * (is_on[gn,t-1] - is_on[gn,t])
+ maxp[t] * (1-is_on[gn,t-1])
) # Eq. (25) in Wang & Hobbs (2016)
else
@constraint(model, mfg[gn,t]<=initial_power
+ (RU * is_initially_on)
+ (SU*(is_on[gn,t] - is_initially_on))
+ maxp[t] * (1-is_on[gn,t])
) # Eq. (23) in Wang & Hobbs (2016) for the first time period
@constraint(model, initial_power
- (prod_above[gn,t] + (is_on[gn,t]*minp[t]))
<= RD * is_on[gn,t]
+ SD * (is_initially_on - is_on[gn,t])
+ maxp[t] * (1-is_initially_on)
) # Eq. (25) in Wang & Hobbs (2016) for the first time period
end
@constraint(model, mfg[gn,t]<=
(SD*(is_on[gn,t] - is_on[gn,t+1]))
+ (maxp[t] * is_on[gn,t+1])
) # Eq. (24) in Wang & Hobbs (2016)
@constraint(model, -RD * is_on[gn,t+1]
-SD * (is_on[gn,t]-is_on[gn,t+1])
-maxp[t] * (1-is_on[gn,t])
<= upflexiramp[gn,t]
) # first inequality of Eq. (26) in Wang & Hobbs (2016)
@constraint(model, upflexiramp[gn,t] <=
RU * is_on[gn,t]
+ SU * (is_on[gn,t+1]-is_on[gn,t])
+ maxp[t] * (1-is_on[gn,t+1])
) # second inequality of Eq. (26) in Wang & Hobbs (2016)
@constraint(model, -RU * is_on[gn,t]
-SU * (is_on[gn,t+1]-is_on[gn,t])
-maxp[t] * (1-is_on[gn,t+1])
<= dwflexiramp[gn,t]
) # first inequality of Eq. (27) in Wang & Hobbs (2016)
@constraint(model, dwflexiramp[gn,t] <=
RD * is_on[gn,t+1]
+ SD * (is_on[gn,t]-is_on[gn,t+1])
+ maxp[t] * (1-is_on[gn,t])
) # second inequality of Eq. (27) in Wang & Hobbs (2016)
@constraint(model, -maxp[t] * is_on[gn,t]
+minp[t] * is_on[gn,t+1]
<= upflexiramp[gn,t]
) # first inequality of Eq. (28) in Wang & Hobbs (2016)
@constraint(model, upflexiramp[gn,t] <=
maxp[t] * is_on[gn,t+1]
) # second inequality of Eq. (28) in Wang & Hobbs (2016)
@constraint(model, -maxp[t] * is_on[gn,t+1]
<= dwflexiramp[gn,t]
) # first inequality of Eq. (29) in Wang & Hobbs (2016)
@constraint(model, dwflexiramp[gn,t] <=
(maxp[t] * is_on[gn,t])
-(minp[t] * is_on[gn,t+1])
) # second inequality of Eq. (29) in Wang & Hobbs (2016)
else
@constraint(model, mfg[gn,t]<=prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t])
+ (RU * is_on[gn,t-1])
+ (SU*(is_on[gn,t] - is_on[gn,t-1]))
+ maxp[t] * (1-is_on[gn,t])
) # Eq. (23) in Wang & Hobbs (2016) for the last time period
@constraint(model, (prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t]))
- (prod_above[gn,t] + (is_on[gn,t]*minp[t]))
<= RD * is_on[gn,t]
+ SD * (is_on[gn,t-1] - is_on[gn,t])
+ maxp[t] * (1-is_on[gn,t-1])
) # Eq. (25) in Wang & Hobbs (2016) for the last time period
end
end
end

View File

@@ -0,0 +1,18 @@
# UnitCommitmentFL.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:
B. Wang and B. F. Hobbs, "Real-Time Markets for Flexiramp: A Stochastic
Unit Commitment-Based Analysis," in IEEE Transactions on Power Systems,
vol. 31, no. 2, pp. 846-860, March 2016, doi: 10.1109/TPWRS.2015.2411268.
"""
module WanHob2016
import ..RampingFormulation
struct Ramping <: RampingFormulation end
end

View File

@@ -5,6 +5,7 @@
function _add_system_wide_eqs!(model::JuMP.Model)::Nothing
_add_net_injection_eqs!(model)
_add_reserve_eqs!(model)
_add_flexiramp_eqs!(model) # Add system-wide flexiramp requirements
return
end
@@ -54,3 +55,41 @@ function _add_reserve_eqs!(model::JuMP.Model)::Nothing
end
return
end
function _add_flexiramp_eqs!(model::JuMP.Model)::Nothing
# Note: The flexpramp requirements in Wang & Hobbs (2016) are imposed as hard constraints
# through Eq. (17) and Eq. (18). The constraints eq_min_upflexiramp[t] and eq_min_dwflexiramp[t]
# provided below are modified versions of Eq. (17) and Eq. (18), respectively, in that
# they include slack variables for flexiramp shortfall, which are penalized in the
# objective function.
eq_min_upflexiramp = _init(model, :eq_min_upflexiramp)
eq_min_dwflexiramp = _init(model, :eq_min_dwflexiramp)
instance = model[:instance]
for t in 1:instance.time
flexiramp_shortfall_penalty = instance.flexiramp_shortfall_penalty[t]
# Eq. (17) in Wang & Hobbs (2016)
eq_min_upflexiramp[t] = @constraint(
model,
sum(model[:upflexiramp][g.name, t] for g in instance.units) +
(flexiramp_shortfall_penalty >= 0 ? model[:upflexiramp_shortfall][t] : 0.0) >=
instance.reserves.upflexiramp[t]
)
# Eq. (18) in Wang & Hobbs (2016)
eq_min_dwflexiramp[t] = @constraint(
model,
sum(model[:dwflexiramp][g.name, t] for g in instance.units) +
(flexiramp_shortfall_penalty >= 0 ? model[:dwflexiramp_shortfall][t] : 0.0) >=
instance.reserves.dwflexiramp[t]
)
# Account for flexiramp shortfall contribution to objective
if flexiramp_shortfall_penalty >= 0
add_to_expression!(
model[:obj],
flexiramp_shortfall_penalty,
(model[:upflexiramp_shortfall][t]+model[:dwflexiramp_shortfall][t]),
)
end
end
return
end

View File

@@ -13,6 +13,7 @@ function _add_unit!(model::JuMP.Model, g::Unit, formulation::Formulation)
# Variables
_add_production_vars!(model, g, formulation.prod_vars)
_add_reserve_vars!(model, g)
_add_flexiramp_vars!(model, g) # Add variables for flexiramp
_add_startup_shutdown_vars!(model, g)
_add_status_vars!(model, g, formulation.status_vars)