Reformat source code

pull/21/head
Alinson S. Xavier 4 years ago
parent 03268dd3df
commit 360308ef4a

@ -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"
@ -227,10 +230,14 @@ function _from_json(json; repair = true)
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)) )
reserves.dwflexiramp = timeseries(
json["Reserves"]["Down-flexiramp (MW)"],
default = zeros(T),
)
end end
# Read transmission lines # Read transmission lines

@ -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..."

@ -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,
@ -54,98 +52,133 @@ function _add_ramp_eqs!(
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]
) # Eq. (19) in Wang & Hobbs (2016)
@constraint(model, mfg[gn, t] <= is_on[gn, t] * maxp[t]) # Eq. (22) 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 if t != model[:instance].time
@constraint(model, minp[t] * (is_on[gn,t+1]+is_on[gn,t]-1) <= @constraint(
prod_above[gn, t] - dwflexiramp[gn,t] +(is_on[gn,t]*minp[t]) 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) ) # first inequality of Eq. (20) in Wang & Hobbs (2016)
@constraint(model, prod_above[gn, t] - dwflexiramp[gn,t] + (is_on[gn,t]*minp[t]) <= @constraint(
mfg[gn,t+1] model,
+ (maxp[t] * (1-is_on[gn,t+1])) 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) ) # second 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,
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) ) # first inequality of Eq. (21) in Wang & Hobbs (2016)
@constraint(model, prod_above[gn, t] + upflexiramp[gn,t] +(is_on[gn,t]*minp[t]) <= @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])) 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. (21) in Wang & Hobbs (2016)
if t != 1 if t != 1
@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] +
(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) ) # Eq. (23) in Wang & Hobbs (2016)
@constraint(model, (prod_above[gn,t-1] + (is_on[gn,t-1]*minp[t])) @constraint(
- (prod_above[gn,t] + (is_on[gn,t]*minp[t])) model,
<= RD * is_on[gn,t] (prod_above[gn, t-1] + (is_on[gn, t-1] * minp[t])) -
+ SD * (is_on[gn,t-1] - is_on[gn,t]) (prod_above[gn, t] + (is_on[gn, t] * minp[t])) <=
+ maxp[t] * (1-is_on[gn,t-1]) 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) ) # 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 +
(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 ) # Eq. (23) in Wang & Hobbs (2016) for the first time period
@constraint(model, initial_power @constraint(
- (prod_above[gn,t] + (is_on[gn,t]*minp[t])) model,
<= RD * is_on[gn,t] initial_power -
+ SD * (is_initially_on - is_on[gn,t]) (prod_above[gn, t] + (is_on[gn, t] * minp[t])) <=
+ maxp[t] * (1-is_initially_on) 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 ) # 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] <=
(SD * (is_on[gn, t] - is_on[gn, t+1])) +
(maxp[t] * is_on[gn, t+1])
) # Eq. (24) in Wang & Hobbs (2016) ) # Eq. (24) in Wang & Hobbs (2016)
@constraint(model, -RD * is_on[gn,t+1] @constraint(
-SD * (is_on[gn,t]-is_on[gn,t+1]) model,
-maxp[t] * (1-is_on[gn,t]) -RD * is_on[gn, t+1] - SD * (is_on[gn, t] - is_on[gn, t+1]) -
<= upflexiramp[gn,t] maxp[t] * (1 - is_on[gn, t]) <= upflexiramp[gn, t]
) # first inequality of Eq. (26) in Wang & Hobbs (2016) ) # first inequality of Eq. (26) in Wang & Hobbs (2016)
@constraint(model, upflexiramp[gn,t] <= @constraint(
RU * is_on[gn,t] model,
+ SU * (is_on[gn,t+1]-is_on[gn,t]) upflexiramp[gn, t] <=
+ maxp[t] * (1-is_on[gn,t+1]) 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) ) # second inequality of Eq. (26) in Wang & Hobbs (2016)
@constraint(model, -RU * is_on[gn,t] @constraint(
-SU * (is_on[gn,t+1]-is_on[gn,t]) model,
-maxp[t] * (1-is_on[gn,t+1]) -RU * is_on[gn, t] - SU * (is_on[gn, t+1] - is_on[gn, t]) -
<= dwflexiramp[gn,t] maxp[t] * (1 - is_on[gn, t+1]) <= dwflexiramp[gn, t]
) # first inequality of Eq. (27) in Wang & Hobbs (2016) ) # first inequality of Eq. (27) in Wang & Hobbs (2016)
@constraint(model, dwflexiramp[gn,t] <= @constraint(
RD * is_on[gn,t+1] model,
+ SD * (is_on[gn,t]-is_on[gn,t+1]) dwflexiramp[gn, t] <=
+ maxp[t] * (1-is_on[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) ) # second inequality of Eq. (27) in Wang & Hobbs (2016)
@constraint(model, -maxp[t] * is_on[gn,t] @constraint(
+minp[t] * is_on[gn,t+1] model,
<= upflexiramp[gn,t] -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) ) # first inequality of Eq. (28) in Wang & Hobbs (2016)
@constraint(model, upflexiramp[gn,t] <= @constraint(model, upflexiramp[gn, t] <= maxp[t] * is_on[gn, t+1]) # second inequality of Eq. (28) in Wang & Hobbs (2016)
maxp[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. (28) in Wang & Hobbs (2016) @constraint(
@constraint(model, -maxp[t] * is_on[gn,t+1] model,
<= dwflexiramp[gn,t] dwflexiramp[gn, t] <=
) # first inequality of Eq. (29) in Wang & Hobbs (2016) (maxp[t] * is_on[gn, t]) - (minp[t] * is_on[gn, t+1])
@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) ) # 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] +
(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 ) # 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])) @constraint(
- (prod_above[gn,t] + (is_on[gn,t]*minp[t])) model,
<= RD * is_on[gn,t] (prod_above[gn, t-1] + (is_on[gn, t-1] * minp[t])) -
+ SD * (is_on[gn,t-1] - is_on[gn,t]) (prod_above[gn, t] + (is_on[gn, t] * minp[t])) <=
+ maxp[t] * (1-is_on[gn,t-1]) 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 ) # Eq. (25) in Wang & Hobbs (2016) for the last time period
end end
end end

@ -12,7 +12,6 @@ module WanHob2016
import ..RampingFormulation import ..RampingFormulation
struct Ramping <: RampingFormulation end struct Ramping <: RampingFormulation end
end end

@ -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,

Loading…
Cancel
Save