Added comments on formulations, added start/stop constraints into MorLatRam and GenMorRam, added ability to add shortfall penalty.

add_formulations
Aleksandr Kazachkov 4 years ago
parent c7602d1fb4
commit 9ca3ae1e45

@ -45,7 +45,7 @@ function _add_ramp_eqs!(
for t in 1:model[:instance].time
# Ramp up limit
if t == 1
if is_initially_on
if _is_initially_on(g)
# min power is _not_ multiplied by is_on because if !is_on, then ramp up is irrelevant
eq_ramp_up[gn, t] = @constraint(
model,
@ -76,7 +76,7 @@ function _add_ramp_eqs!(
# Ramp down limit
if t == 1
if is_initially_on
if _is_initially_on(g)
# TODO If RD < SD, or more specifically if
# min_power + RD < initial_power < SD
# then the generator should be able to shut down at time t = 1,

@ -35,7 +35,7 @@ function _add_ramp_eqs!(
RESERVES_WHEN_RAMP_DOWN = true
RESERVES_WHEN_SHUT_DOWN = true
is_initially_on = _is_initially_on(g)
# The following are the same for generator g across all time periods
SU = g.startup_limit # startup rate
SD = g.shutdown_limit # shutdown rate

@ -12,6 +12,7 @@ function _add_status_vars!(
model::JuMP.Model,
g::Unit,
formulation_status_vars::Gar1962.StatusVars,
ALWAYS_CREATE_VARS = false
)::Nothing
is_on = _init(model, :is_on)
switch_on = _init(model, :switch_on)
@ -63,6 +64,44 @@ function _add_status_vars!(
end
end
end
if ALWAYS_CREATE_VARS
# If variables are created, use initial conditions to fix some values
if t == 1
if _is_initially_on(g)
# Generator was on (for g.initial_status time periods),
# so cannot be more switched on until the period after the first time it can be turned off
fix(switch_on[g.name, 1], 0.0; force = true)
else
# Generator is initially off (for -g.initial_status time periods)
# Cannot be switched off more
fix(switch_off[g.name, 1], 0.0; force = true)
end
end
if g.must_run[t]
# If the generator _must_ run, then it is obviously on and cannot be switched off
# In the first time period, force unit to switch on if was off before
# Otherwise, unit is on, and will never turn off, so will never need to turn on
fix(is_on[g.name, t], 1.0; force = true)
fix(switch_on[g.name, t], (t == 1 ? 1.0 - _is_initially_on(g) : 0.0); force = true)
fix(switch_off[g.name, t], 0.0; force = true)
end
else
# If vars are not created, then replace them by a constant
if t == 1
if _is_initially_on(g)
switch_on[g.name, t] = 0.0
else
switch_off[g.name, t] = 0.0
end
end
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
end
end # check if ALWAYS_CREATE_VARS
end
return
end

@ -2,10 +2,10 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
abstract type TransmissionFormulation end
abstract type RampingFormulation end
abstract type AbstractTransmissionFormulation end
abstract type AbstractRampingFormulation end
abstract type PiecewiseLinearCostsFormulation end
abstract type StartupCostsFormulation end
abstract type AbstractStartupCostsFormulation end
abstract type StatusVarsFormulation end
abstract type ProductionVarsFormulation end
@ -21,18 +21,18 @@ Some of these components are allowed to be empty, as long as overall validity of
struct Formulation
prod_vars::ProductionVarsFormulation
pwl_costs::PiecewiseLinearCostsFormulation
ramping::RampingFormulation
startup_costs::StartupCostsFormulation
ramping::AbstractRampingFormulation
startup_costs::AbstractStartupCostsFormulation
status_vars::StatusVarsFormulation
transmission::TransmissionFormulation
transmission::AbstractTransmissionFormulation
function Formulation(;
prod_vars::ProductionVarsFormulation = Gar1962.ProdVars(),
pwl_costs::PiecewiseLinearCostsFormulation = KnuOstWat2018.PwlCosts(),
ramping::RampingFormulation = MorLatRam2013.Ramping(),
startup_costs::StartupCostsFormulation = MorLatRam2013.StartupCosts(),
ramping::AbstractRampingFormulation = MorLatRam2013.Ramping(),
startup_costs::AbstractStartupCostsFormulation = MorLatRam2013.StartupCosts(),
status_vars::StatusVarsFormulation = Gar1962.StatusVars(),
transmission::TransmissionFormulation = ShiftFactorsFormulation(),
transmission::AbstractTransmissionFormulation = ShiftFactorsFormulation(),
)
return new(
prod_vars,
@ -70,7 +70,7 @@ Arguments
the cutoff that should be applied to the LODF matrix. Entries with magnitude
smaller than this value will be set to zero.
"""
struct ShiftFactorsFormulation <: TransmissionFormulation
struct ShiftFactorsFormulation <: AbstractTransmissionFormulation
isf_cutoff::Float64
lodf_cutoff::Float64
precomputed_isf::Union{Nothing,Matrix{Float64}}

@ -192,7 +192,7 @@ end
function _add_ramp_eqs!(
model::JuMP.Model,
g::Unit,
formulation::RampingFormulation,
formulation::AbstractRampingFormulation,
)::Nothing
prod_above = model[:prod_above]
reserve = model[:reserve]
@ -265,16 +265,16 @@ function _add_min_uptime_downtime_eqs!(model::JuMP.Model, g::Unit)::Nothing
# Equation (4) in Knueven et al. (2020)
eq_min_uptime[g.name, t] = @constraint(
model,
sum(switch_on[g.name, i] for i in (t-g.min_uptime+1):t if i >= 1) <= is_on[g.name, t]
sum(switch_on[g.name, i] for i in (t-g.min_uptime+1):t if i >= 1)
<= is_on[g.name, t]
)
# Minimum down-time
# Equation (5) in Knueven et al. (2020)
eq_min_downtime[g.name, t] = @constraint(
model,
sum(
switch_off[g.name, i] for i in (t-g.min_downtime+1):t if i >= 1
) <= 1 - is_on[g.name, t]
sum(switch_off[g.name, i] for i in (t-g.min_downtime+1):t if i >= 1)
<= 1 - is_on[g.name, t]
)
# Minimum up/down-time for initial periods

Loading…
Cancel
Save