Create file for status vars; add Gar1962.StatusVars

bugfix/formulations
Alinson S. Xavier 4 years ago
parent 2f90c48d60
commit 063b602d1a

@ -30,6 +30,7 @@ include("model/formulations/base/unit.jl")
include("model/formulations/CarArr2006/pwlcosts.jl") include("model/formulations/CarArr2006/pwlcosts.jl")
include("model/formulations/DamKucRajAta2016/ramp.jl") include("model/formulations/DamKucRajAta2016/ramp.jl")
include("model/formulations/Gar1962/pwlcosts.jl") include("model/formulations/Gar1962/pwlcosts.jl")
include("model/formulations/Gar1962/status.jl")
include("model/formulations/KnuOstWat2018/pwlcosts.jl") include("model/formulations/KnuOstWat2018/pwlcosts.jl")
include("model/formulations/MorLatRam2013/ramp.jl") include("model/formulations/MorLatRam2013/ramp.jl")
include("model/formulations/MorLatRam2013/scosts.jl") include("model/formulations/MorLatRam2013/scosts.jl")

@ -5,7 +5,8 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation::ArrCon2000.Ramping, formulation_status_vars::Gar1962.StatusVars,
formulation_ramping::ArrCon2000.Ramping,
)::Nothing )::Nothing
# TODO: Move upper case constants to model[:instance] # TODO: Move upper case constants to model[:instance]
RESERVES_WHEN_START_UP = true RESERVES_WHEN_START_UP = true
@ -17,15 +18,17 @@ function _add_ramp_eqs!(
RD = g.ramp_down_limit RD = g.ramp_down_limit
SU = g.startup_limit SU = g.startup_limit
SD = g.shutdown_limit SD = g.shutdown_limit
is_on = model[:is_on]
prod_above = model[:prod_above] prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
switch_off = model[:switch_off]
switch_on = model[:switch_on]
eq_ramp_down = _init(model, :eq_ramp_down) eq_ramp_down = _init(model, :eq_ramp_down)
eq_ramp_up = _init(model, :eq_ramp_up) eq_ramp_up = _init(model, :eq_ramp_up)
is_initially_on = (g.initial_status > 0) is_initially_on = (g.initial_status > 0)
# Gar1962.StatusVars
is_on = model[:is_on]
switch_off = model[:switch_off]
switch_on = model[:switch_on]
for t in 1:model[:instance].time for t in 1:model[:instance].time
# Ramp up limit # Ramp up limit
if t == 1 if t == 1

@ -5,6 +5,7 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_status_vars::StatusVarsFormulation,
formulation::CarArr2006.PwlCosts, formulation::CarArr2006.PwlCosts,
)::Nothing )::Nothing
eq_prod_above_def = _init(model, :eq_prod_above_def) eq_prod_above_def = _init(model, :eq_prod_above_def)

@ -5,7 +5,8 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation::DamKucRajAta2016.Ramping, formulation_status_vars::Gar1962.StatusVars,
formulation_ramping::DamKucRajAta2016.Ramping,
)::Nothing )::Nothing
# TODO: Move upper case constants to model[:instance] # TODO: Move upper case constants to model[:instance]
RESERVES_WHEN_START_UP = true RESERVES_WHEN_START_UP = true
@ -21,9 +22,11 @@ function _add_ramp_eqs!(
gn = g.name gn = g.name
eq_str_ramp_down = _init(model, :eq_str_ramp_down) eq_str_ramp_down = _init(model, :eq_str_ramp_down)
eq_str_ramp_up = _init(model, :eq_str_ramp_up) eq_str_ramp_up = _init(model, :eq_str_ramp_up)
is_on = model[:is_on]
prod_above = model[:prod_above] prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
# Gar1962.StatusVars
is_on = model[:is_on]
switch_off = model[:switch_off] switch_off = model[:switch_off]
switch_on = model[:switch_on] switch_on = model[:switch_on]

@ -5,14 +5,15 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation::Gar1962.PwlCosts, formulation_status_vars::Gar1962.StatusVars,
formulation_pwd::Gar1962.PwlCosts,
)::Nothing )::Nothing
eq_prod_above_def = _init(model, :eq_prod_above_def) eq_prod_above_def = _init(model, :eq_prod_above_def)
eq_segprod_limit = _init(model, :eq_segprod_limit) eq_segprod_limit = _init(model, :eq_segprod_limit)
is_on = model[:is_on]
prod_above = model[:prod_above] prod_above = model[:prod_above]
segprod = model[:segprod] segprod = model[:segprod]
gn = g.name gn = g.name
is_on = model[:is_on]
K = length(g.cost_segments) K = length(g.cost_segments)
for t in 1:model[:instance].time for t in 1:model[:instance].time
# Definition of production # Definition of production

@ -0,0 +1,61 @@
# 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_status_vars!(
model::JuMP.Model,
g::Unit,
formulation_status_vars::Gar1962.StatusVars,
)::Nothing
is_on = _init(model, :is_on)
switch_on = _init(model, :switch_on)
switch_off = _init(model, :switch_off)
for t in 1:model[:instance].time
if g.must_run[t]
is_on[g.name, t] = 1.0
switch_on[g.name, t] = (t == 1 ? 1.0 - _is_initially_on(g) : 0.0)
switch_off[g.name, t] = 0.0
else
is_on[g.name, t] = @variable(model, binary = true)
switch_on[g.name, t] = @variable(model, binary = true)
switch_off[g.name, t] = @variable(model, binary = true)
end
end
return
end
function _add_status_eqs!(
model::JuMP.Model,
g::Unit,
formulation_status_vars::Gar1962.StatusVars,
)::Nothing
eq_binary_link = _init(model, :eq_binary_link)
eq_switch_on_off = _init(model, :eq_switch_on_off)
is_on = model[:is_on]
switch_off = model[:switch_off]
switch_on = model[:switch_on]
for t in 1:model[:instance].time
if !g.must_run[t]
# Link binary variables
if t == 1
eq_binary_link[g.name, t] = @constraint(
model,
is_on[g.name, t] - _is_initially_on(g) ==
switch_on[g.name, t] - switch_off[g.name, t]
)
else
eq_binary_link[g.name, t] = @constraint(
model,
is_on[g.name, t] - is_on[g.name, t-1] ==
switch_on[g.name, t] - switch_off[g.name, t]
)
end
# Cannot switch on and off at the same time
eq_switch_on_off[g.name, t] = @constraint(
model,
switch_on[g.name, t] + switch_off[g.name, t] <= 1
)
end
end
return
end

@ -14,7 +14,9 @@ Formulation described in:
module Gar1962 module Gar1962
import ..PiecewiseLinearCostsFormulation import ..PiecewiseLinearCostsFormulation
import ..StatusVarsFormulation
struct PwlCosts <: PiecewiseLinearCostsFormulation end struct PwlCosts <: PiecewiseLinearCostsFormulation end
struct StatusVars <: StatusVarsFormulation end
end end

@ -5,7 +5,8 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation::KnuOstWat2018.PwlCosts, formulation_status_vars::Gar1962.StatusVars,
formulation_pwl::KnuOstWat2018.PwlCosts,
)::Nothing )::Nothing
eq_prod_above_def = _init(model, :eq_prod_above_def) eq_prod_above_def = _init(model, :eq_prod_above_def)
eq_segprod_limit_a = _init(model, :eq_segprod_limit_a) eq_segprod_limit_a = _init(model, :eq_segprod_limit_a)
@ -13,13 +14,15 @@ function _add_production_piecewise_linear_eqs!(
eq_segprod_limit_c = _init(model, :eq_segprod_limit_c) eq_segprod_limit_c = _init(model, :eq_segprod_limit_c)
prod_above = model[:prod_above] prod_above = model[:prod_above]
segprod = model[:segprod] segprod = model[:segprod]
is_on = model[:is_on]
switch_on = model[:switch_on]
switch_off = model[:switch_off]
gn = g.name gn = g.name
K = length(g.cost_segments) K = length(g.cost_segments)
T = model[:instance].time T = model[:instance].time
# Gar1962.StatusVars
is_on = model[:is_on]
switch_on = model[:switch_on]
switch_off = model[:switch_off]
for t in 1:T for t in 1:T
for k in 1:K for k in 1:K
# Pbar^{k-1) # Pbar^{k-1)

@ -5,7 +5,8 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation::MorLatRam2013.Ramping, formulation_status_vars::Gar1962.StatusVars,
formulation_ramping::MorLatRam2013.Ramping,
)::Nothing )::Nothing
# TODO: Move upper case constants to model[:instance] # TODO: Move upper case constants to model[:instance]
RESERVES_WHEN_START_UP = true RESERVES_WHEN_START_UP = true
@ -20,9 +21,11 @@ function _add_ramp_eqs!(
gn = g.name gn = g.name
eq_ramp_down = _init(model, :eq_ramp_down) eq_ramp_down = _init(model, :eq_ramp_down)
eq_ramp_up = _init(model, :eq_str_ramp_up) eq_ramp_up = _init(model, :eq_str_ramp_up)
is_on = model[:is_on]
prod_above = model[:prod_above] prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
# Gar1962.StatusVars
is_on = model[:is_on]
switch_off = model[:switch_off] switch_off = model[:switch_off]
switch_on = model[:switch_on] switch_on = model[:switch_on]

@ -1,16 +1,18 @@
# 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_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation::PanGua2016.Ramping, formulation_status_vars::Gar1962.StatusVars,
formulation_ramping::PanGua2016.Ramping,
)::Nothing )::Nothing
# TODO: Move upper case constants to model[:instance] # TODO: Move upper case constants to model[:instance]
RESERVES_WHEN_SHUT_DOWN = true RESERVES_WHEN_SHUT_DOWN = true
gn = g.name gn = g.name
is_on = model[:is_on]
prod_above = model[:prod_above] prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
switch_off = model[:switch_off]
switch_on = model[:switch_on]
eq_str_prod_limit = _init(model, :eq_str_prod_limit) eq_str_prod_limit = _init(model, :eq_str_prod_limit)
eq_prod_limit_ramp_up_extra_period = eq_prod_limit_ramp_up_extra_period =
_init(model, :eq_prod_limit_ramp_up_extra_period) _init(model, :eq_prod_limit_ramp_up_extra_period)
@ -23,6 +25,11 @@ function _add_ramp_eqs!(
RD = g.ramp_down_limit # ramp down rate RD = g.ramp_down_limit # ramp down rate
T = model[:instance].time T = model[:instance].time
# Gar1962.StatusVars
is_on = model[:is_on]
switch_off = model[:switch_off]
switch_on = model[:switch_on]
for t in 1:T for t in 1:T
Pbar = g.max_power[t] Pbar = g.max_power[t]
if Pbar < 1e-7 if Pbar < 1e-7

@ -6,20 +6,23 @@ abstract type TransmissionFormulation end
abstract type RampingFormulation end abstract type RampingFormulation end
abstract type PiecewiseLinearCostsFormulation end abstract type PiecewiseLinearCostsFormulation end
abstract type StartupCostsFormulation end abstract type StartupCostsFormulation end
abstract type StatusVarsFormulation end
struct Formulation struct Formulation
pwl_costs::PiecewiseLinearCostsFormulation pwl_costs::PiecewiseLinearCostsFormulation
ramping::RampingFormulation ramping::RampingFormulation
startup_costs::StartupCostsFormulation startup_costs::StartupCostsFormulation
status_vars::StatusVarsFormulation
transmission::TransmissionFormulation transmission::TransmissionFormulation
function Formulation(; function Formulation(;
pwl_costs::PiecewiseLinearCostsFormulation = KnuOstWat2018.PwlCosts(), pwl_costs::PiecewiseLinearCostsFormulation = KnuOstWat2018.PwlCosts(),
ramping::RampingFormulation = MorLatRam2013.Ramping(), ramping::RampingFormulation = MorLatRam2013.Ramping(),
startup_costs::StartupCostsFormulation = MorLatRam2013.StartupCosts(), startup_costs::StartupCostsFormulation = MorLatRam2013.StartupCosts(),
status_vars::StatusVarsFormulation = Gar1962.StatusVars(),
transmission::TransmissionFormulation = ShiftFactorsFormulation(), transmission::TransmissionFormulation = ShiftFactorsFormulation(),
) )
return new(pwl_costs, ramping, startup_costs, transmission) return new(pwl_costs, ramping, startup_costs, status_vars, transmission)
end end
end end

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details. # Released under the modified BSD license. See COPYING.md for more details.
function _add_unit!(model::JuMP.Model, g::Unit, f::Formulation) function _add_unit!(model::JuMP.Model, g::Unit, formulation::Formulation)
if !all(g.must_run) && any(g.must_run) if !all(g.must_run) && any(g.must_run)
error("Partially must-run units are not currently supported") error("Partially must-run units are not currently supported")
end end
@ -14,17 +14,22 @@ function _add_unit!(model::JuMP.Model, g::Unit, f::Formulation)
_add_production_vars!(model, g) _add_production_vars!(model, g)
_add_reserve_vars!(model, g) _add_reserve_vars!(model, g)
_add_startup_shutdown_vars!(model, g) _add_startup_shutdown_vars!(model, g)
_add_status_vars!(model, g) _add_status_vars!(model, g, formulation.status_vars)
# Constraints and objective function # Constraints and objective function
_add_min_uptime_downtime_eqs!(model, g) _add_min_uptime_downtime_eqs!(model, g)
_add_net_injection_eqs!(model, g) _add_net_injection_eqs!(model, g)
_add_production_limit_eqs!(model, g) _add_production_limit_eqs!(model, g)
_add_production_piecewise_linear_eqs!(model, g, f.pwl_costs) _add_production_piecewise_linear_eqs!(
_add_ramp_eqs!(model, g, f.ramping) model,
_add_startup_cost_eqs!(model, g, f.startup_costs) g,
formulation.status_vars,
formulation.pwl_costs,
)
_add_ramp_eqs!(model, g, formulation.status_vars, formulation.ramping)
_add_startup_cost_eqs!(model, g, formulation.startup_costs)
_add_startup_shutdown_limit_eqs!(model, g) _add_startup_shutdown_limit_eqs!(model, g)
_add_status_eqs!(model, g) _add_status_eqs!(model, g, formulation.status_vars)
return return
end end
@ -134,56 +139,6 @@ function _add_startup_shutdown_limit_eqs!(model::JuMP.Model, g::Unit)::Nothing
return return
end end
function _add_status_vars!(model::JuMP.Model, g::Unit)::Nothing
is_on = _init(model, :is_on)
switch_on = _init(model, :switch_on)
switch_off = _init(model, :switch_off)
for t in 1:model[:instance].time
if g.must_run[t]
is_on[g.name, t] = 1.0
switch_on[g.name, t] = (t == 1 ? 1.0 - _is_initially_on(g) : 0.0)
switch_off[g.name, t] = 0.0
else
is_on[g.name, t] = @variable(model, binary = true)
switch_on[g.name, t] = @variable(model, binary = true)
switch_off[g.name, t] = @variable(model, binary = true)
end
end
return
end
function _add_status_eqs!(model::JuMP.Model, g::Unit)::Nothing
eq_binary_link = _init(model, :eq_binary_link)
eq_switch_on_off = _init(model, :eq_switch_on_off)
is_on = model[:is_on]
switch_off = model[:switch_off]
switch_on = model[:switch_on]
for t in 1:model[:instance].time
if !g.must_run[t]
# Link binary variables
if t == 1
eq_binary_link[g.name, t] = @constraint(
model,
is_on[g.name, t] - _is_initially_on(g) ==
switch_on[g.name, t] - switch_off[g.name, t]
)
else
eq_binary_link[g.name, t] = @constraint(
model,
is_on[g.name, t] - is_on[g.name, t-1] ==
switch_on[g.name, t] - switch_off[g.name, t]
)
end
# Cannot switch on and off at the same time
eq_switch_on_off[g.name, t] = @constraint(
model,
switch_on[g.name, t] + switch_off[g.name, t] <= 1
)
end
end
return
end
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,

Loading…
Cancel
Save