Add Gar1962.ProdVars

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

@ -31,6 +31,7 @@ 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/Gar1962/status.jl")
include("model/formulations/Gar1962/prod.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,8 +5,9 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_status_vars::Gar1962.StatusVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::ArrCon2000.Ramping, formulation_ramping::ArrCon2000.Ramping,
formulation_status_vars::Gar1962.StatusVars,
)::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
@ -18,12 +19,14 @@ 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
prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
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.ProdVars
prod_above = model[:prod_above]
# Gar1962.StatusVars # Gar1962.StatusVars
is_on = model[:is_on] is_on = model[:is_on]
switch_off = model[:switch_off] switch_off = model[:switch_off]

@ -5,14 +5,18 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_prod_vars::Gar1962.ProdVars,
formulation_pwl_costs::CarArr2006.PwlCosts,
formulation_status_vars::StatusVarsFormulation, formulation_status_vars::StatusVarsFormulation,
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)
eq_segprod_limit = _init(model, :eq_segprod_limit) eq_segprod_limit = _init(model, :eq_segprod_limit)
prod_above = model[:prod_above]
segprod = model[:segprod] segprod = model[:segprod]
gn = g.name gn = g.name
# Gar1962.ProdVars
prod_above = model[:prod_above]
K = length(g.cost_segments) K = length(g.cost_segments)
for t in 1:model[:instance].time for t in 1:model[:instance].time
gn = g.name gn = g.name

@ -5,8 +5,9 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_status_vars::Gar1962.StatusVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::DamKucRajAta2016.Ramping, formulation_ramping::DamKucRajAta2016.Ramping,
formulation_status_vars::Gar1962.StatusVars,
)::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
@ -22,9 +23,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)
prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
# Gar1962.ProdVars
prod_above = model[:prod_above]
# Gar1962.StatusVars # Gar1962.StatusVars
is_on = model[:is_on] is_on = model[:is_on]
switch_off = model[:switch_off] switch_off = model[:switch_off]

@ -0,0 +1,50 @@
# 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_production_vars!(
model::JuMP.Model,
g::Unit,
formulation_prod_vars::Gar1962.ProdVars,
)::Nothing
prod_above = _init(model, :prod_above)
segprod = _init(model, :segprod)
for t in 1:model[:instance].time
for k in 1:length(g.cost_segments)
segprod[g.name, t, k] = @variable(model, lower_bound = 0)
end
prod_above[g.name, t] = @variable(model, lower_bound = 0)
end
return
end
function _add_production_limit_eqs!(
model::JuMP.Model,
g::Unit,
formulation_prod_vars::Gar1962.ProdVars,
)::Nothing
eq_prod_limit = _init(model, :eq_prod_limit)
is_on = model[:is_on]
prod_above = model[:prod_above]
reserve = model[:reserve]
gn = g.name
for t in 1:model[:instance].time
# Objective function terms for production costs
# Part of (69) of Kneuven et al. (2020) as C^R_g * u_g(t) term
add_to_expression!(model[:obj], is_on[gn, t], g.min_power_cost[t])
# Production limit
# Equation (18) in Kneuven et al. (2020)
# as \bar{p}_g(t) \le \bar{P}_g u_g(t)
# amk: this is a weaker version of (20) and (21) in Kneuven et al. (2020)
# but keeping it here in case those are not present
power_diff = max(g.max_power[t], 0.0) - max(g.min_power[t], 0.0)
if power_diff < 1e-7
power_diff = 0.0
end
eq_prod_limit[gn, t] = @constraint(
model,
prod_above[gn, t] + reserve[gn, t] <= power_diff * is_on[gn, t]
)
end
end

@ -5,15 +5,21 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_prod_vars::Gar1962.ProdVars,
formulation_pwl_costs::Gar1962.PwlCosts,
formulation_status_vars::Gar1962.StatusVars, 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)
prod_above = model[:prod_above]
segprod = model[:segprod] segprod = model[:segprod]
gn = g.name gn = g.name
# Gar1962.ProdVars
prod_above = model[:prod_above]
# Gar1962.StatusVars
is_on = model[:is_on] 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

@ -14,8 +14,10 @@ Formulation described in:
module Gar1962 module Gar1962
import ..PiecewiseLinearCostsFormulation import ..PiecewiseLinearCostsFormulation
import ..ProductionVarsFormulation
import ..StatusVarsFormulation import ..StatusVarsFormulation
struct ProdVars <: ProductionVarsFormulation end
struct PwlCosts <: PiecewiseLinearCostsFormulation end struct PwlCosts <: PiecewiseLinearCostsFormulation end
struct StatusVars <: StatusVarsFormulation end struct StatusVars <: StatusVarsFormulation end

@ -5,19 +5,22 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_prod_vars::Gar1962.ProdVars,
formulation_pwl_costs::KnuOstWat2018.PwlCosts,
formulation_status_vars::Gar1962.StatusVars, 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)
eq_segprod_limit_b = _init(model, :eq_segprod_limit_b) eq_segprod_limit_b = _init(model, :eq_segprod_limit_b)
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]
segprod = model[:segprod] segprod = model[:segprod]
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.ProdVars
prod_above = model[:prod_above]
# Gar1962.StatusVars # Gar1962.StatusVars
is_on = model[:is_on] is_on = model[:is_on]
switch_on = model[:switch_on] switch_on = model[:switch_on]

@ -5,8 +5,9 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_status_vars::Gar1962.StatusVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::MorLatRam2013.Ramping, formulation_ramping::MorLatRam2013.Ramping,
formulation_status_vars::Gar1962.StatusVars,
)::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_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)
prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
# Gar1962.ProdVars
prod_above = model[:prod_above]
# Gar1962.StatusVars # Gar1962.StatusVars
is_on = model[:is_on] is_on = model[:is_on]
switch_off = model[:switch_off] switch_off = model[:switch_off]

@ -5,13 +5,13 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::Unit,
formulation_status_vars::Gar1962.StatusVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::PanGua2016.Ramping, formulation_ramping::PanGua2016.Ramping,
formulation_status_vars::Gar1962.StatusVars,
)::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
prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
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 =
@ -25,6 +25,9 @@ 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.ProdVars
prod_above = model[:prod_above]
# Gar1962.StatusVars # Gar1962.StatusVars
is_on = model[:is_on] is_on = model[:is_on]
switch_off = model[:switch_off] switch_off = model[:switch_off]

@ -7,8 +7,10 @@ abstract type RampingFormulation end
abstract type PiecewiseLinearCostsFormulation end abstract type PiecewiseLinearCostsFormulation end
abstract type StartupCostsFormulation end abstract type StartupCostsFormulation end
abstract type StatusVarsFormulation end abstract type StatusVarsFormulation end
abstract type ProductionVarsFormulation end
struct Formulation struct Formulation
prod_vars::ProductionVarsFormulation
pwl_costs::PiecewiseLinearCostsFormulation pwl_costs::PiecewiseLinearCostsFormulation
ramping::RampingFormulation ramping::RampingFormulation
startup_costs::StartupCostsFormulation startup_costs::StartupCostsFormulation
@ -16,13 +18,21 @@ struct Formulation
transmission::TransmissionFormulation transmission::TransmissionFormulation
function Formulation(; function Formulation(;
prod_vars::ProductionVarsFormulation = Gar1962.ProdVars(),
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(), status_vars::StatusVarsFormulation = Gar1962.StatusVars(),
transmission::TransmissionFormulation = ShiftFactorsFormulation(), transmission::TransmissionFormulation = ShiftFactorsFormulation(),
) )
return new(pwl_costs, ramping, startup_costs, status_vars, transmission) return new(
prod_vars,
pwl_costs,
ramping,
startup_costs,
status_vars,
transmission,
)
end end
end end

@ -11,7 +11,7 @@ function _add_unit!(model::JuMP.Model, g::Unit, formulation::Formulation)
end end
# Variables # Variables
_add_production_vars!(model, g) _add_production_vars!(model, g, formulation.prod_vars)
_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, formulation.status_vars) _add_status_vars!(model, g, formulation.status_vars)
@ -19,14 +19,21 @@ function _add_unit!(model::JuMP.Model, g::Unit, formulation::Formulation)
# 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, formulation.prod_vars)
_add_production_piecewise_linear_eqs!( _add_production_piecewise_linear_eqs!(
model, model,
g, g,
formulation.status_vars, formulation.prod_vars,
formulation.pwl_costs, formulation.pwl_costs,
formulation.status_vars,
)
_add_ramp_eqs!(
model,
g,
formulation.prod_vars,
formulation.ramping,
formulation.status_vars,
) )
_add_ramp_eqs!(model, g, formulation.status_vars, formulation.ramping)
_add_startup_cost_eqs!(model, g, formulation.startup_costs) _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, formulation.status_vars) _add_status_eqs!(model, g, formulation.status_vars)
@ -35,45 +42,6 @@ end
_is_initially_on(g::Unit)::Float64 = (g.initial_status > 0 ? 1.0 : 0.0) _is_initially_on(g::Unit)::Float64 = (g.initial_status > 0 ? 1.0 : 0.0)
function _add_production_vars!(model::JuMP.Model, g::Unit)::Nothing
prod_above = _init(model, :prod_above)
segprod = _init(model, :segprod)
for t in 1:model[:instance].time
for k in 1:length(g.cost_segments)
segprod[g.name, t, k] = @variable(model, lower_bound = 0)
end
prod_above[g.name, t] = @variable(model, lower_bound = 0)
end
return
end
function _add_production_limit_eqs!(model::JuMP.Model, g::Unit)::Nothing
eq_prod_limit = _init(model, :eq_prod_limit)
is_on = model[:is_on]
prod_above = model[:prod_above]
reserve = model[:reserve]
gn = g.name
for t in 1:model[:instance].time
# Objective function terms for production costs
# Part of (69) of Kneuven et al. (2020) as C^R_g * u_g(t) term
add_to_expression!(model[:obj], is_on[gn, t], g.min_power_cost[t])
# Production limit
# Equation (18) in Kneuven et al. (2020)
# as \bar{p}_g(t) \le \bar{P}_g u_g(t)
# amk: this is a weaker version of (20) and (21) in Kneuven et al. (2020)
# but keeping it here in case those are not present
power_diff = max(g.max_power[t], 0.0) - max(g.min_power[t], 0.0)
if power_diff < 1e-7
power_diff = 0.0
end
eq_prod_limit[gn, t] = @constraint(
model,
prod_above[gn, t] + reserve[gn, t] <= power_diff * is_on[gn, t]
)
end
end
function _add_reserve_vars!(model::JuMP.Model, g::Unit)::Nothing function _add_reserve_vars!(model::JuMP.Model, g::Unit)::Nothing
reserve = _init(model, :reserve) reserve = _init(model, :reserve)
for t in 1:model[:instance].time for t in 1:model[:instance].time
@ -149,7 +117,7 @@ function _add_ramp_eqs!(
eq_ramp_up = _init(model, :eq_ramp_up) eq_ramp_up = _init(model, :eq_ramp_up)
eq_ramp_down = _init(model, :eq_ramp_down) eq_ramp_down = _init(model, :eq_ramp_down)
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
if _is_initially_on(g) == 1 if _is_initially_on(g) == 1
eq_ramp_up[g.name, t] = @constraint( eq_ramp_up[g.name, t] = @constraint(

Loading…
Cancel
Save