You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
3.9 KiB
103 lines
3.9 KiB
# 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.
|
|
|
|
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
|
|
|
|
function _add_net_injection_eqs!(model::JuMP.Model)::Nothing
|
|
T = model[:instance].time
|
|
net_injection = _init(model, :net_injection)
|
|
eq_net_injection = _init(model, :eq_net_injection)
|
|
eq_power_balance = _init(model, :eq_power_balance)
|
|
for t in 1:T, b in model[:instance].buses
|
|
n = net_injection[b.name, t] = @variable(model)
|
|
eq_net_injection[b.name, t] =
|
|
@constraint(model, -n + model[:expr_net_injection][b.name, t] == 0)
|
|
end
|
|
for t in 1:T
|
|
eq_power_balance[t] = @constraint(
|
|
model,
|
|
sum(net_injection[b.name, t] for b in model[:instance].buses) == 0
|
|
)
|
|
end
|
|
return
|
|
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
|
|
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
|