mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 00:08:52 -06:00
Reformat source code
This commit is contained in:
@@ -23,7 +23,10 @@ Example
|
|||||||
import UnitCommitment
|
import UnitCommitment
|
||||||
instance = UnitCommitment.read_benchmark("matpower/case3375wp/2017-02-01")
|
instance = UnitCommitment.read_benchmark("matpower/case3375wp/2017-02-01")
|
||||||
"""
|
"""
|
||||||
function read_benchmark(name::AbstractString; quiet::Bool=false)::UnitCommitmentInstance
|
function read_benchmark(
|
||||||
|
name::AbstractString;
|
||||||
|
quiet::Bool = false,
|
||||||
|
)::UnitCommitmentInstance
|
||||||
basedir = dirname(@__FILE__)
|
basedir = dirname(@__FILE__)
|
||||||
filename = "$basedir/../../instances/$name.json.gz"
|
filename = "$basedir/../../instances/$name.json.gz"
|
||||||
url = "$INSTANCES_URL/$name.json.gz"
|
url = "$INSTANCES_URL/$name.json.gz"
|
||||||
@@ -225,13 +228,17 @@ function _from_json(json; repair = true)
|
|||||||
# Read spinning, up-flexiramp, and down-flexiramp reserve requirements
|
# Read spinning, up-flexiramp, and down-flexiramp reserve requirements
|
||||||
reserves = Reserves(zeros(T), zeros(T), zeros(T))
|
reserves = Reserves(zeros(T), zeros(T), zeros(T))
|
||||||
if "Reserves" in keys(json)
|
if "Reserves" in keys(json)
|
||||||
reserves.spinning =
|
reserves.spinning =
|
||||||
timeseries(json["Reserves"]["Spinning (MW)"], default = zeros(T))
|
timeseries(json["Reserves"]["Spinning (MW)"], default = zeros(T))
|
||||||
reserves.upflexiramp =
|
reserves.upflexiramp = timeseries(
|
||||||
timeseries(json["Reserves"]["Up-flexiramp (MW)"], default = zeros(T))
|
json["Reserves"]["Up-flexiramp (MW)"],
|
||||||
reserves.dwflexiramp =
|
default = zeros(T),
|
||||||
timeseries(json["Reserves"]["Down-flexiramp (MW)"], default = zeros(T))
|
)
|
||||||
end
|
reserves.dwflexiramp = timeseries(
|
||||||
|
json["Reserves"]["Down-flexiramp (MW)"],
|
||||||
|
default = zeros(T),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# Read transmission lines
|
# Read transmission lines
|
||||||
if "Transmission lines" in keys(json)
|
if "Transmission lines" in keys(json)
|
||||||
|
|||||||
@@ -32,12 +32,20 @@ function build_model(;
|
|||||||
formulation = Formulation(),
|
formulation = Formulation(),
|
||||||
variable_names::Bool = false,
|
variable_names::Bool = false,
|
||||||
)::JuMP.Model
|
)::JuMP.Model
|
||||||
if formulation.ramping ==WanHob2016.Ramping() && instance.reserves.spinning!=zeros(instance.time)
|
if formulation.ramping == WanHob2016.Ramping() &&
|
||||||
error("Spinning reserves are not supported by the WanHob2016 ramping formulation")
|
instance.reserves.spinning != zeros(instance.time)
|
||||||
|
error(
|
||||||
|
"Spinning reserves are not supported by the WanHob2016 ramping formulation",
|
||||||
|
)
|
||||||
end
|
end
|
||||||
@show formulation.ramping
|
@show formulation.ramping
|
||||||
if formulation.ramping !== WanHob2016.Ramping() && (instance.reserves.upflexiramp!=zeros(instance.time) || instance.reserves.dwflexiramp!=zeros(instance.time))
|
if formulation.ramping !== WanHob2016.Ramping() && (
|
||||||
error("Flexiramp is supported only by the WanHob2016 ramping formulation")
|
instance.reserves.upflexiramp != zeros(instance.time) ||
|
||||||
|
instance.reserves.dwflexiramp != zeros(instance.time)
|
||||||
|
)
|
||||||
|
error(
|
||||||
|
"Flexiramp is supported only by the WanHob2016 ramping formulation",
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@info "Building model..."
|
@info "Building model..."
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
function _add_flexiramp_vars!(model::JuMP.Model, g::Unit)::Nothing
|
function _add_flexiramp_vars!(model::JuMP.Model, g::Unit)::Nothing
|
||||||
upflexiramp = _init(model, :upflexiramp)
|
upflexiramp = _init(model, :upflexiramp)
|
||||||
upflexiramp_shortfall = _init(model, :upflexiramp_shortfall)
|
upflexiramp_shortfall = _init(model, :upflexiramp_shortfall)
|
||||||
mfg=_init(model,:mfg)
|
mfg = _init(model, :mfg)
|
||||||
dwflexiramp = _init(model, :dwflexiramp)
|
dwflexiramp = _init(model, :dwflexiramp)
|
||||||
dwflexiramp_shortfall = _init(model, :dwflexiramp_shortfall)
|
dwflexiramp_shortfall = _init(model, :dwflexiramp_shortfall)
|
||||||
for t in 1:model[:instance].time
|
for t in 1:model[:instance].time
|
||||||
# maximum feasible generation, \bar{g_{its}} in Wang & Hobbs (2016)
|
# maximum feasible generation, \bar{g_{its}} in Wang & Hobbs (2016)
|
||||||
mfg[g.name,t]=@variable(model, lower_bound = 0)
|
mfg[g.name, t] = @variable(model, lower_bound = 0)
|
||||||
if g.provides_flexiramp_reserves[t]
|
if g.provides_flexiramp_reserves[t]
|
||||||
upflexiramp[g.name, t] = @variable(model) # up-flexiramp, ur_{it} in Wang & Hobbs (2016)
|
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)
|
dwflexiramp[g.name, t] = @variable(model) # down-flexiramp, dr_{it} in Wang & Hobbs (2016)
|
||||||
@@ -28,8 +28,6 @@ function _add_flexiramp_vars!(model::JuMP.Model, g::Unit)::Nothing
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function _add_ramp_eqs!(
|
function _add_ramp_eqs!(
|
||||||
model::JuMP.Model,
|
model::JuMP.Model,
|
||||||
g::Unit,
|
g::Unit,
|
||||||
@@ -43,110 +41,145 @@ function _add_ramp_eqs!(
|
|||||||
RU = g.ramp_up_limit
|
RU = g.ramp_up_limit
|
||||||
RD = g.ramp_down_limit
|
RD = g.ramp_down_limit
|
||||||
gn = g.name
|
gn = g.name
|
||||||
minp=g.min_power
|
minp = g.min_power
|
||||||
maxp=g.max_power
|
maxp = g.max_power
|
||||||
initial_power=g.initial_power
|
initial_power = g.initial_power
|
||||||
|
|
||||||
is_on = model[:is_on]
|
is_on = model[:is_on]
|
||||||
prod_above = model[:prod_above]
|
prod_above = model[:prod_above]
|
||||||
upflexiramp=model[:upflexiramp]
|
upflexiramp = model[:upflexiramp]
|
||||||
dwflexiramp=model[:dwflexiramp]
|
dwflexiramp = model[:dwflexiramp]
|
||||||
mfg=model[:mfg]
|
mfg = model[:mfg]
|
||||||
|
|
||||||
for t in 1:model[:instance].time
|
for t in 1:model[:instance].time
|
||||||
|
@constraint(
|
||||||
@constraint(model, prod_above[gn, t] + (is_on[gn,t]*minp[t])
|
model,
|
||||||
<=mfg[gn,t]) # Eq. (19) in Wang & Hobbs (2016)
|
prod_above[gn, t] + (is_on[gn, t] * minp[t]) <= mfg[gn, t]
|
||||||
@constraint(model, mfg[gn,t]<= is_on[gn,t]* maxp[t]) # Eq. (22) in Wang & Hobbs (2016)
|
) # Eq. (19) in Wang & Hobbs (2016)
|
||||||
if t!=model[:instance].time
|
@constraint(model, mfg[gn, t] <= is_on[gn, t] * maxp[t]) # Eq. (22) in Wang & Hobbs (2016)
|
||||||
@constraint(model, minp[t] * (is_on[gn,t+1]+is_on[gn,t]-1) <=
|
if t != model[:instance].time
|
||||||
prod_above[gn, t] - dwflexiramp[gn,t] +(is_on[gn,t]*minp[t])
|
@constraint(
|
||||||
) # first inequality of Eq. (20) in Wang & Hobbs (2016)
|
model,
|
||||||
@constraint(model, prod_above[gn, t] - dwflexiramp[gn,t] + (is_on[gn,t]*minp[t]) <=
|
minp[t] * (is_on[gn, t+1] + is_on[gn, t] - 1) <=
|
||||||
mfg[gn,t+1]
|
prod_above[gn, t] - dwflexiramp[gn, t] +
|
||||||
+ (maxp[t] * (1-is_on[gn,t+1]))
|
(is_on[gn, t] * minp[t])
|
||||||
) # second inequality of Eq. (20) in Wang & Hobbs (2016)
|
) # first inequality of Eq. (20) in Wang & Hobbs (2016)
|
||||||
@constraint(model, minp[t] * (is_on[gn,t+1]+is_on[gn,t]-1) <=
|
@constraint(
|
||||||
prod_above[gn, t] + upflexiramp[gn,t] + (is_on[gn,t]*minp[t])
|
model,
|
||||||
) # first inequality of Eq. (21) in Wang & Hobbs (2016)
|
prod_above[gn, t] - dwflexiramp[gn, t] +
|
||||||
@constraint(model, prod_above[gn, t] + upflexiramp[gn,t] +(is_on[gn,t]*minp[t]) <=
|
(is_on[gn, t] * minp[t]) <=
|
||||||
mfg[gn,t+1] + (maxp[t] * (1-is_on[gn,t+1]))
|
mfg[gn, t+1] + (maxp[t] * (1 - is_on[gn, t+1]))
|
||||||
) # second inequality of Eq. (21) in Wang & Hobbs (2016)
|
) # second inequality of Eq. (20) in Wang & Hobbs (2016)
|
||||||
if t!=1
|
@constraint(
|
||||||
@constraint(model, mfg[gn,t]<=prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t])
|
model,
|
||||||
+ (RU * is_on[gn,t-1])
|
minp[t] * (is_on[gn, t+1] + is_on[gn, t] - 1) <=
|
||||||
+ (SU*(is_on[gn,t] - is_on[gn,t-1]))
|
prod_above[gn, t] +
|
||||||
+ maxp[t] * (1-is_on[gn,t])
|
upflexiramp[gn, t] +
|
||||||
) # Eq. (23) in Wang & Hobbs (2016)
|
(is_on[gn, t] * minp[t])
|
||||||
@constraint(model, (prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t]))
|
) # first inequality of Eq. (21) in Wang & Hobbs (2016)
|
||||||
- (prod_above[gn,t] + (is_on[gn,t]*minp[t]))
|
@constraint(
|
||||||
<= RD * is_on[gn,t]
|
model,
|
||||||
+ SD * (is_on[gn,t-1] - is_on[gn,t])
|
prod_above[gn, t] +
|
||||||
+ maxp[t] * (1-is_on[gn,t-1])
|
upflexiramp[gn, t] +
|
||||||
) # Eq. (25) in Wang & Hobbs (2016)
|
(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
|
else
|
||||||
@constraint(model, mfg[gn,t]<=initial_power
|
@constraint(
|
||||||
+ (RU * is_initially_on)
|
model,
|
||||||
+ (SU*(is_on[gn,t] - is_initially_on))
|
mfg[gn, t] <=
|
||||||
+ maxp[t] * (1-is_on[gn,t])
|
initial_power +
|
||||||
) # Eq. (23) in Wang & Hobbs (2016) for the first time period
|
(RU * is_initially_on) +
|
||||||
@constraint(model, initial_power
|
(SU * (is_on[gn, t] - is_initially_on)) +
|
||||||
- (prod_above[gn,t] + (is_on[gn,t]*minp[t]))
|
maxp[t] * (1 - is_on[gn, t])
|
||||||
<= RD * is_on[gn,t]
|
) # Eq. (23) in Wang & Hobbs (2016) for the first time period
|
||||||
+ SD * (is_initially_on - is_on[gn,t])
|
@constraint(
|
||||||
+ maxp[t] * (1-is_initially_on)
|
model,
|
||||||
) # Eq. (25) in Wang & Hobbs (2016) for the first time period
|
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
|
end
|
||||||
@constraint(model, mfg[gn,t]<=
|
@constraint(
|
||||||
(SD*(is_on[gn,t] - is_on[gn,t+1]))
|
model,
|
||||||
+ (maxp[t] * is_on[gn,t+1])
|
mfg[gn, t] <=
|
||||||
) # Eq. (24) in Wang & Hobbs (2016)
|
(SD * (is_on[gn, t] - is_on[gn, t+1])) +
|
||||||
@constraint(model, -RD * is_on[gn,t+1]
|
(maxp[t] * is_on[gn, t+1])
|
||||||
-SD * (is_on[gn,t]-is_on[gn,t+1])
|
) # Eq. (24) in Wang & Hobbs (2016)
|
||||||
-maxp[t] * (1-is_on[gn,t])
|
@constraint(
|
||||||
<= upflexiramp[gn,t]
|
model,
|
||||||
) # first inequality of Eq. (26) in Wang & Hobbs (2016)
|
-RD * is_on[gn, t+1] - SD * (is_on[gn, t] - is_on[gn, t+1]) -
|
||||||
@constraint(model, upflexiramp[gn,t] <=
|
maxp[t] * (1 - is_on[gn, t]) <= upflexiramp[gn, t]
|
||||||
RU * is_on[gn,t]
|
) # first inequality of Eq. (26) in Wang & Hobbs (2016)
|
||||||
+ SU * (is_on[gn,t+1]-is_on[gn,t])
|
@constraint(
|
||||||
+ maxp[t] * (1-is_on[gn,t+1])
|
model,
|
||||||
) # second inequality of Eq. (26) in Wang & Hobbs (2016)
|
upflexiramp[gn, t] <=
|
||||||
@constraint(model, -RU * is_on[gn,t]
|
RU * is_on[gn, t] +
|
||||||
-SU * (is_on[gn,t+1]-is_on[gn,t])
|
SU * (is_on[gn, t+1] - is_on[gn, t]) +
|
||||||
-maxp[t] * (1-is_on[gn,t+1])
|
maxp[t] * (1 - is_on[gn, t+1])
|
||||||
<= dwflexiramp[gn,t]
|
) # second inequality of Eq. (26) in Wang & Hobbs (2016)
|
||||||
) # first inequality of Eq. (27) in Wang & Hobbs (2016)
|
@constraint(
|
||||||
@constraint(model, dwflexiramp[gn,t] <=
|
model,
|
||||||
RD * is_on[gn,t+1]
|
-RU * is_on[gn, t] - SU * (is_on[gn, t+1] - is_on[gn, t]) -
|
||||||
+ SD * (is_on[gn,t]-is_on[gn,t+1])
|
maxp[t] * (1 - is_on[gn, t+1]) <= dwflexiramp[gn, t]
|
||||||
+ maxp[t] * (1-is_on[gn,t])
|
) # first inequality of Eq. (27) in Wang & Hobbs (2016)
|
||||||
) # second inequality of Eq. (27) in Wang & Hobbs (2016)
|
@constraint(
|
||||||
@constraint(model, -maxp[t] * is_on[gn,t]
|
model,
|
||||||
+minp[t] * is_on[gn,t+1]
|
dwflexiramp[gn, t] <=
|
||||||
<= upflexiramp[gn,t]
|
RD * is_on[gn, t+1] +
|
||||||
) # first inequality of Eq. (28) in Wang & Hobbs (2016)
|
SD * (is_on[gn, t] - is_on[gn, t+1]) +
|
||||||
@constraint(model, upflexiramp[gn,t] <=
|
maxp[t] * (1 - is_on[gn, t])
|
||||||
maxp[t] * is_on[gn,t+1]
|
) # second inequality of Eq. (27) in Wang & Hobbs (2016)
|
||||||
) # second inequality of Eq. (28) in Wang & Hobbs (2016)
|
@constraint(
|
||||||
@constraint(model, -maxp[t] * is_on[gn,t+1]
|
model,
|
||||||
<= dwflexiramp[gn,t]
|
-maxp[t] * is_on[gn, t] + minp[t] * is_on[gn, t+1] <=
|
||||||
) # first inequality of Eq. (29) in Wang & Hobbs (2016)
|
upflexiramp[gn, t]
|
||||||
@constraint(model, dwflexiramp[gn,t] <=
|
) # first inequality of Eq. (28) in Wang & Hobbs (2016)
|
||||||
(maxp[t] * is_on[gn,t])
|
@constraint(model, upflexiramp[gn, t] <= maxp[t] * is_on[gn, t+1]) # second inequality of Eq. (28) in Wang & Hobbs (2016)
|
||||||
-(minp[t] * is_on[gn,t+1])
|
@constraint(model, -maxp[t] * is_on[gn, t+1] <= dwflexiramp[gn, t]) # first inequality of Eq. (29) in Wang & Hobbs (2016)
|
||||||
) # second 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
|
else
|
||||||
@constraint(model, mfg[gn,t]<=prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t])
|
@constraint(
|
||||||
+ (RU * is_on[gn,t-1])
|
model,
|
||||||
+ (SU*(is_on[gn,t] - is_on[gn,t-1]))
|
mfg[gn, t] <=
|
||||||
+ maxp[t] * (1-is_on[gn,t])
|
prod_above[gn, t-1] +
|
||||||
) # Eq. (23) in Wang & Hobbs (2016) for the last time period
|
(is_on[gn, t-1] * minp[t]) +
|
||||||
@constraint(model, (prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t]))
|
(RU * is_on[gn, t-1]) +
|
||||||
- (prod_above[gn,t] + (is_on[gn,t]*minp[t]))
|
(SU * (is_on[gn, t] - is_on[gn, t-1])) +
|
||||||
<= RD * is_on[gn,t]
|
maxp[t] * (1 - is_on[gn, t])
|
||||||
+ SD * (is_on[gn,t-1] - is_on[gn,t])
|
) # Eq. (23) in Wang & Hobbs (2016) for the last time period
|
||||||
+ maxp[t] * (1-is_on[gn,t-1])
|
@constraint(
|
||||||
) # Eq. (25) in Wang & Hobbs (2016) for the last time period
|
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
|
end
|
||||||
end
|
end
|
||||||
@@ -12,7 +12,6 @@ module WanHob2016
|
|||||||
|
|
||||||
import ..RampingFormulation
|
import ..RampingFormulation
|
||||||
|
|
||||||
|
|
||||||
struct Ramping <: RampingFormulation end
|
struct Ramping <: RampingFormulation end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ function _add_reserve_eqs!(model::JuMP.Model)::Nothing
|
|||||||
end
|
end
|
||||||
|
|
||||||
function _add_flexiramp_eqs!(model::JuMP.Model)::Nothing
|
function _add_flexiramp_eqs!(model::JuMP.Model)::Nothing
|
||||||
# Note: The flexpramp requirements in Wang & Hobbs (2016) are imposed as hard constraints
|
# 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]
|
# 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
|
# 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
|
# they include slack variables for flexiramp shortfall, which are penalized in the
|
||||||
@@ -71,15 +71,19 @@ function _add_flexiramp_eqs!(model::JuMP.Model)::Nothing
|
|||||||
eq_min_upflexiramp[t] = @constraint(
|
eq_min_upflexiramp[t] = @constraint(
|
||||||
model,
|
model,
|
||||||
sum(model[:upflexiramp][g.name, t] for g in instance.units) +
|
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]
|
flexiramp_shortfall_penalty >= 0 ?
|
||||||
|
model[:upflexiramp_shortfall][t] : 0.0
|
||||||
|
) >= instance.reserves.upflexiramp[t]
|
||||||
)
|
)
|
||||||
# Eq. (18) in Wang & Hobbs (2016)
|
# Eq. (18) in Wang & Hobbs (2016)
|
||||||
eq_min_dwflexiramp[t] = @constraint(
|
eq_min_dwflexiramp[t] = @constraint(
|
||||||
model,
|
model,
|
||||||
sum(model[:dwflexiramp][g.name, t] for g in instance.units) +
|
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]
|
flexiramp_shortfall_penalty >= 0 ?
|
||||||
|
model[:dwflexiramp_shortfall][t] : 0.0
|
||||||
|
) >= instance.reserves.dwflexiramp[t]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Account for flexiramp shortfall contribution to objective
|
# Account for flexiramp shortfall contribution to objective
|
||||||
@@ -87,7 +91,10 @@ function _add_flexiramp_eqs!(model::JuMP.Model)::Nothing
|
|||||||
add_to_expression!(
|
add_to_expression!(
|
||||||
model[:obj],
|
model[:obj],
|
||||||
flexiramp_shortfall_penalty,
|
flexiramp_shortfall_penalty,
|
||||||
(model[:upflexiramp_shortfall][t]+model[:dwflexiramp_shortfall][t]),
|
(
|
||||||
|
model[:upflexiramp_shortfall][t] +
|
||||||
|
model[:dwflexiramp_shortfall][t]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -50,22 +50,25 @@ function solution(model::JuMP.Model)::OrderedDict
|
|||||||
sol["Is on"] = timeseries(model[:is_on], instance.units)
|
sol["Is on"] = timeseries(model[:is_on], instance.units)
|
||||||
sol["Switch on"] = timeseries(model[:switch_on], instance.units)
|
sol["Switch on"] = timeseries(model[:switch_on], instance.units)
|
||||||
sol["Switch off"] = timeseries(model[:switch_off], instance.units)
|
sol["Switch off"] = timeseries(model[:switch_off], instance.units)
|
||||||
if instance.reserves.upflexiramp != zeros(T) || instance.reserves.dwflexiramp != zeros(T)
|
if instance.reserves.upflexiramp != zeros(T) ||
|
||||||
|
instance.reserves.dwflexiramp != zeros(T)
|
||||||
# Report flexiramp solutions only if either of the up-flexiramp and
|
# Report flexiramp solutions only if either of the up-flexiramp and
|
||||||
# down-flexiramp requirements is not a default array of zeros
|
# down-flexiramp requirements is not a default array of zeros
|
||||||
sol["Up-flexiramp (MW)"] = timeseries(model[:upflexiramp], instance.units)
|
sol["Up-flexiramp (MW)"] =
|
||||||
|
timeseries(model[:upflexiramp], instance.units)
|
||||||
sol["Up-flexiramp shortfall (MW)"] = OrderedDict(
|
sol["Up-flexiramp shortfall (MW)"] = OrderedDict(
|
||||||
t =>
|
t =>
|
||||||
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
||||||
round(value(model[:upflexiramp_shortfall][t]), digits = 5) : 0.0 for
|
round(value(model[:upflexiramp_shortfall][t]), digits = 5) :
|
||||||
t in 1:instance.time
|
0.0 for t in 1:instance.time
|
||||||
)
|
)
|
||||||
sol["Down-flexiramp (MW)"] = timeseries(model[:dwflexiramp], instance.units)
|
sol["Down-flexiramp (MW)"] =
|
||||||
|
timeseries(model[:dwflexiramp], instance.units)
|
||||||
sol["Down-flexiramp shortfall (MW)"] = OrderedDict(
|
sol["Down-flexiramp shortfall (MW)"] = OrderedDict(
|
||||||
t =>
|
t =>
|
||||||
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
||||||
round(value(model[:dwflexiramp_shortfall][t]), digits = 5) : 0.0 for
|
round(value(model[:dwflexiramp_shortfall][t]), digits = 5) :
|
||||||
t in 1:instance.time
|
0.0 for t in 1:instance.time
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
# Report spinning reserve solutions only if both up-flexiramp and
|
# Report spinning reserve solutions only if both up-flexiramp and
|
||||||
@@ -74,10 +77,9 @@ function solution(model::JuMP.Model)::OrderedDict
|
|||||||
sol["Reserve shortfall (MW)"] = OrderedDict(
|
sol["Reserve shortfall (MW)"] = OrderedDict(
|
||||||
t =>
|
t =>
|
||||||
(instance.shortfall_penalty[t] >= 0) ?
|
(instance.shortfall_penalty[t] >= 0) ?
|
||||||
round(value(model[:reserve_shortfall][t]), digits = 5) : 0.0 for
|
round(value(model[:reserve_shortfall][t]), digits = 5) :
|
||||||
t in 1:instance.time
|
0.0 for t in 1:instance.time
|
||||||
)
|
)
|
||||||
|
|
||||||
end
|
end
|
||||||
sol["Net injection (MW)"] =
|
sol["Net injection (MW)"] =
|
||||||
timeseries(model[:net_injection], instance.buses)
|
timeseries(model[:net_injection], instance.buses)
|
||||||
|
|||||||
@@ -339,13 +339,15 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
|
|||||||
err_count += 1
|
err_count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
upflexiramp =
|
upflexiramp = sum(
|
||||||
sum(solution["Up-flexiramp (MW)"][g.name][t] for g in instance.units)
|
solution["Up-flexiramp (MW)"][g.name][t] for g in instance.units
|
||||||
|
)
|
||||||
upflexiramp_shortfall =
|
upflexiramp_shortfall =
|
||||||
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
||||||
solution["Up-flexiramp shortfall (MW)"][t] : 0
|
solution["Up-flexiramp shortfall (MW)"][t] : 0
|
||||||
|
|
||||||
if upflexiramp + upflexiramp_shortfall < instance.reserves.upflexiramp[t] - tol
|
if upflexiramp + upflexiramp_shortfall <
|
||||||
|
instance.reserves.upflexiramp[t] - tol
|
||||||
@error @sprintf(
|
@error @sprintf(
|
||||||
"Insufficient up-flexiramp at time %d (%.2f + %.2f should be %.2f)",
|
"Insufficient up-flexiramp at time %d (%.2f + %.2f should be %.2f)",
|
||||||
t,
|
t,
|
||||||
@@ -356,13 +358,15 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
|
|||||||
err_count += 1
|
err_count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
dwflexiramp =
|
dwflexiramp = sum(
|
||||||
sum(solution["Down-flexiramp (MW)"][g.name][t] for g in instance.units)
|
solution["Down-flexiramp (MW)"][g.name][t] for g in instance.units
|
||||||
|
)
|
||||||
dwflexiramp_shortfall =
|
dwflexiramp_shortfall =
|
||||||
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
||||||
solution["Down-flexiramp shortfall (MW)"][t] : 0
|
solution["Down-flexiramp shortfall (MW)"][t] : 0
|
||||||
|
|
||||||
if dwflexiramp + dwflexiramp_shortfall < instance.reserves.dwflexiramp[t] - tol
|
if dwflexiramp + dwflexiramp_shortfall <
|
||||||
|
instance.reserves.dwflexiramp[t] - tol
|
||||||
@error @sprintf(
|
@error @sprintf(
|
||||||
"Insufficient down-flexiramp at time %d (%.2f + %.2f should be %.2f)",
|
"Insufficient down-flexiramp at time %d (%.2f + %.2f should be %.2f)",
|
||||||
t,
|
t,
|
||||||
|
|||||||
Reference in New Issue
Block a user