Rename Unit to ThermalUnit

pull/26/head
Alinson S. Xavier 3 years ago
parent 51f6aa9a80
commit 19534a128f
Signed by: isoron
GPG Key ID: 0DA8E4B9E1109DCA

@ -129,7 +129,7 @@ end
function _from_json(json; repair = true)::UnitCommitmentScenario function _from_json(json; repair = true)::UnitCommitmentScenario
_migrate(json) _migrate(json)
units = Unit[] thermal_units = ThermalUnit[]
buses = Bus[] buses = Bus[]
contingencies = Contingency[] contingencies = Contingency[]
lines = TransmissionLine[] lines = TransmissionLine[]
@ -160,7 +160,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
name_to_bus = Dict{String,Bus}() name_to_bus = Dict{String,Bus}()
name_to_line = Dict{String,TransmissionLine}() name_to_line = Dict{String,TransmissionLine}()
name_to_unit = Dict{String,Unit}() name_to_unit = Dict{String,ThermalUnit}()
name_to_reserve = Dict{String,Reserve}() name_to_reserve = Dict{String,Reserve}()
function timeseries(x; default = nothing) function timeseries(x; default = nothing)
@ -181,7 +181,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
bus_name, bus_name,
length(buses), length(buses),
timeseries(dict["Load (MW)"]), timeseries(dict["Load (MW)"]),
Unit[], ThermalUnit[],
PriceSensitiveLoad[], PriceSensitiveLoad[],
ProfiledUnit[], ProfiledUnit[],
) )
@ -196,7 +196,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
name = reserve_name, name = reserve_name,
type = lowercase(dict["Type"]), type = lowercase(dict["Type"]),
amount = timeseries(dict["Amount (MW)"]), amount = timeseries(dict["Amount (MW)"]),
units = [], thermal_units = [],
shortfall_penalty = scalar( shortfall_penalty = scalar(
dict["Shortfall penalty (\$/MW)"], dict["Shortfall penalty (\$/MW)"],
default = -1, default = -1,
@ -282,7 +282,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
initial_status *= time_multiplier initial_status *= time_multiplier
end end
unit = Unit( unit = ThermalUnit(
unit_name, unit_name,
bus, bus,
max_power, max_power,
@ -303,12 +303,12 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
startup_categories, startup_categories,
unit_reserves, unit_reserves,
) )
push!(bus.units, unit) push!(bus.thermal_units, unit)
for r in unit_reserves for r in unit_reserves
push!(r.units, unit) push!(r.thermal_units, unit)
end end
name_to_unit[unit_name] = unit name_to_unit[unit_name] = unit
push!(units, unit) push!(thermal_units, unit)
elseif lowercase(unit_type) === "profiled" elseif lowercase(unit_type) === "profiled"
bus = name_to_bus[dict["Bus"]] bus = name_to_bus[dict["Bus"]]
pu = ProfiledUnit( pu = ProfiledUnit(
@ -355,7 +355,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
# Read contingencies # Read contingencies
if "Contingencies" in keys(json) if "Contingencies" in keys(json)
for (cont_name, dict) in json["Contingencies"] for (cont_name, dict) in json["Contingencies"]
affected_units = Unit[] affected_units = ThermalUnit[]
affected_lines = TransmissionLine[] affected_lines = TransmissionLine[]
if "Affected lines" in keys(dict) if "Affected lines" in keys(dict)
affected_lines = affected_lines =
@ -400,8 +400,8 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
reserves = reserves, reserves = reserves,
reserves_by_name = name_to_reserve, reserves_by_name = name_to_reserve,
time = T, time = T,
units_by_name = Dict(g.name => g for g in units), thermal_units_by_name = Dict(g.name => g for g in thermal_units),
units = units, thermal_units = thermal_units,
profiled_units_by_name = Dict(pu.name => pu for pu in profiled_units), profiled_units_by_name = Dict(pu.name => pu for pu in profiled_units),
profiled_units = profiled_units, profiled_units = profiled_units,
isf = spzeros(Float64, length(lines), length(buses) - 1), isf = spzeros(Float64, length(lines), length(buses) - 1),

@ -6,7 +6,7 @@ mutable struct Bus
name::String name::String
offset::Int offset::Int
load::Vector{Float64} load::Vector{Float64}
units::Vector thermal_units::Vector
price_sensitive_loads::Vector price_sensitive_loads::Vector
profiled_units::Vector profiled_units::Vector
end end
@ -25,11 +25,11 @@ Base.@kwdef mutable struct Reserve
name::String name::String
type::String type::String
amount::Vector{Float64} amount::Vector{Float64}
units::Vector thermal_units::Vector
shortfall_penalty::Float64 shortfall_penalty::Float64
end end
mutable struct Unit mutable struct ThermalUnit
name::String name::String
bus::Bus bus::Bus
max_power::Vector{Float64} max_power::Vector{Float64}
@ -64,7 +64,7 @@ end
mutable struct Contingency mutable struct Contingency
name::String name::String
lines::Vector{TransmissionLine} lines::Vector{TransmissionLine}
units::Vector{Unit} thermal_units::Vector{ThermalUnit}
end end
mutable struct PriceSensitiveLoad mutable struct PriceSensitiveLoad
@ -95,13 +95,13 @@ Base.@kwdef mutable struct UnitCommitmentScenario
price_sensitive_loads_by_name::Dict{AbstractString,PriceSensitiveLoad} price_sensitive_loads_by_name::Dict{AbstractString,PriceSensitiveLoad}
price_sensitive_loads::Vector{PriceSensitiveLoad} price_sensitive_loads::Vector{PriceSensitiveLoad}
probability::Float64 probability::Float64
profiled_units_by_name::Dict{AbstractString,ProfiledUnit}
profiled_units::Vector{ProfiledUnit}
reserves_by_name::Dict{AbstractString,Reserve} reserves_by_name::Dict{AbstractString,Reserve}
reserves::Vector{Reserve} reserves::Vector{Reserve}
thermal_units_by_name::Dict{AbstractString,ThermalUnit}
thermal_units::Vector{ThermalUnit}
time::Int time::Int
units_by_name::Dict{AbstractString,Unit}
units::Vector{Unit}
profiled_units_by_name::Dict{AbstractString,ProfiledUnit}
profiled_units::Vector{ProfiledUnit}
end end
Base.@kwdef mutable struct UnitCommitmentInstance Base.@kwdef mutable struct UnitCommitmentInstance
@ -113,12 +113,12 @@ function Base.show(io::IO, instance::UnitCommitmentInstance)
sc = instance.scenarios[1] sc = instance.scenarios[1]
print(io, "UnitCommitmentInstance(") print(io, "UnitCommitmentInstance(")
print(io, "$(length(instance.scenarios)) scenarios, ") print(io, "$(length(instance.scenarios)) scenarios, ")
print(io, "$(length(sc.units)) units, ") print(io, "$(length(sc.thermal_units)) thermal units, ")
print(io, "$(length(sc.profiled_units)) profiled units, ")
print(io, "$(length(sc.buses)) buses, ") print(io, "$(length(sc.buses)) buses, ")
print(io, "$(length(sc.lines)) lines, ") print(io, "$(length(sc.lines)) lines, ")
print(io, "$(length(sc.contingencies)) contingencies, ") print(io, "$(length(sc.contingencies)) contingencies, ")
print(io, "$(length(sc.price_sensitive_loads)) price sensitive loads, ") print(io, "$(length(sc.price_sensitive_loads)) price sensitive loads, ")
print(io, "$(length(sc.profiled_units)) profiled units, ")
print(io, "$(instance.time) time steps") print(io, "$(instance.time) time steps")
print(io, ")") print(io, ")")
return return

@ -131,7 +131,7 @@ function _aelmp_check_parameters(
) )
end end
end end
all_units = sc.units all_units = sc.thermal_units
# CHECK: model cannot handle non-fast-starts (MISO Phase I: can ONLY solve fast-starts) # CHECK: model cannot handle non-fast-starts (MISO Phase I: can ONLY solve fast-starts)
if any(u -> u.min_uptime > 1 || u.min_downtime > 1, all_units) if any(u -> u.min_uptime > 1 || u.min_downtime > 1, all_units)
error( error(
@ -159,25 +159,25 @@ function _modify_scenario!(
if !method.allow_offline_participation if !method.allow_offline_participation
# 1. remove (if NOT allowing) the offline generators # 1. remove (if NOT allowing) the offline generators
units_to_remove = [] units_to_remove = []
for unit in sc.units for unit in sc.thermal_units
# remove based on the solved UC model result # remove based on the solved UC model result
# remove the unit if it is never on # remove the unit if it is never on
if all(t -> value(model[:is_on][unit.name, t]) == 0, sc.time) if all(t -> value(model[:is_on][unit.name, t]) == 0, sc.time)
# unregister from the bus # unregister from the bus
filter!(x -> x.name != unit.name, unit.bus.units) filter!(x -> x.name != unit.name, unit.bus.thermal_units)
# unregister from the reserve # unregister from the reserve
for r in unit.reserves for r in unit.reserves
filter!(x -> x.name != unit.name, r.units) filter!(x -> x.name != unit.name, r.thermal_units)
end end
# append the name to the remove list # append the name to the remove list
push!(units_to_remove, unit.name) push!(units_to_remove, unit.name)
end end
end end
# unregister the units from the remove list # unregister the units from the remove list
filter!(x -> !(x.name in units_to_remove), sc.units) filter!(x -> !(x.name in units_to_remove), sc.thermal_units)
end end
for unit in sc.units for unit in sc.thermal_units
# 2. set min generation requirement to 0 by adding 0 to production curve and cost # 2. set min generation requirement to 0 by adding 0 to production curve and cost
# min_power & min_costs are vectors with dimension T # min_power & min_costs are vectors with dimension T
if unit.min_power[1] != 0 if unit.min_power[1] != 0
@ -207,5 +207,6 @@ function _modify_scenario!(
unit.startup_categories = unit.startup_categories =
StartupCategory[StartupCategory(0, first_startup_cost)] StartupCategory[StartupCategory(0, first_startup_cost)]
end end
return sc.units_by_name = Dict(g.name => g for g in sc.units) return sc.thermal_units_by_name =
Dict(g.name => g for g in sc.thermal_units)
end end

@ -77,7 +77,7 @@ function build_model(;
end end
model[:obj] = AffExpr() model[:obj] = AffExpr()
model[:instance] = instance model[:instance] = instance
for g in instance.scenarios[1].units for g in instance.scenarios[1].thermal_units
_add_unit_commitment!(model, g, formulation) _add_unit_commitment!(model, g, formulation)
end end
for sc in instance.scenarios for sc in instance.scenarios
@ -93,7 +93,7 @@ function build_model(;
for ps in sc.price_sensitive_loads for ps in sc.price_sensitive_loads
_add_price_sensitive_load!(model, ps, sc) _add_price_sensitive_load!(model, ps, sc)
end end
for g in sc.units for g in sc.thermal_units
_add_unit_dispatch!(model, g, formulation, sc) _add_unit_dispatch!(model, g, formulation, sc)
end end
for pu in sc.profiled_units for pu in sc.profiled_units

@ -4,7 +4,7 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::ArrCon2000.Ramping, formulation_ramping::ArrCon2000.Ramping,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,

@ -4,7 +4,7 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_pwl_costs::CarArr2006.PwlCosts, formulation_pwl_costs::CarArr2006.PwlCosts,
formulation_status_vars::StatusVarsFormulation, formulation_status_vars::StatusVarsFormulation,

@ -4,7 +4,7 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::DamKucRajAta2016.Ramping, formulation_ramping::DamKucRajAta2016.Ramping,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,

@ -4,7 +4,7 @@
function _add_production_vars!( function _add_production_vars!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
)::Nothing )::Nothing
@ -21,7 +21,7 @@ end
function _add_production_limit_eqs!( function _add_production_limit_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
)::Nothing )::Nothing

@ -4,7 +4,7 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_pwl_costs::Gar1962.PwlCosts, formulation_pwl_costs::Gar1962.PwlCosts,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,

@ -4,7 +4,7 @@
function _add_status_vars!( function _add_status_vars!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,
)::Nothing )::Nothing
is_on = _init(model, :is_on) is_on = _init(model, :is_on)
@ -27,7 +27,7 @@ end
function _add_status_eqs!( function _add_status_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,
)::Nothing )::Nothing
eq_binary_link = _init(model, :eq_binary_link) eq_binary_link = _init(model, :eq_binary_link)

@ -4,7 +4,7 @@
function _add_production_piecewise_linear_eqs!( function _add_production_piecewise_linear_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_pwl_costs::KnuOstWat2018.PwlCosts, formulation_pwl_costs::KnuOstWat2018.PwlCosts,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,

@ -4,7 +4,7 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::MorLatRam2013.Ramping, formulation_ramping::MorLatRam2013.Ramping,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,

@ -4,7 +4,7 @@
function _add_startup_cost_eqs!( function _add_startup_cost_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation::MorLatRam2013.StartupCosts, formulation::MorLatRam2013.StartupCosts,
)::Nothing )::Nothing
eq_startup_choose = _init(model, :eq_startup_choose) eq_startup_choose = _init(model, :eq_startup_choose)

@ -4,7 +4,7 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation_prod_vars::Gar1962.ProdVars, formulation_prod_vars::Gar1962.ProdVars,
formulation_ramping::PanGua2016.Ramping, formulation_ramping::PanGua2016.Ramping,
formulation_status_vars::Gar1962.StatusVars, formulation_status_vars::Gar1962.StatusVars,

@ -4,7 +4,7 @@
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
::Gar1962.ProdVars, ::Gar1962.ProdVars,
::WanHob2016.Ramping, ::WanHob2016.Ramping,
::Gar1962.StatusVars, ::Gar1962.StatusVars,

@ -53,7 +53,7 @@ function _add_spinning_reserve_eqs!(
model, model,
sum( sum(
model[:reserve][sc.name, r.name, g.name, t] for model[:reserve][sc.name, r.name, g.name, t] for
g in r.units g in r.thermal_units
) + model[:reserve_shortfall][sc.name, r.name, t] >= ) + model[:reserve_shortfall][sc.name, r.name, t] >=
r.amount[t] r.amount[t]
) )
@ -91,7 +91,7 @@ function _add_flexiramp_reserve_eqs!(
model, model,
sum( sum(
model[:upflexiramp][sc.name, r.name, g.name, t] for model[:upflexiramp][sc.name, r.name, g.name, t] for
g in r.units g in r.thermal_units
) + model[:upflexiramp_shortfall][sc.name, r.name, t] >= ) + model[:upflexiramp_shortfall][sc.name, r.name, t] >=
r.amount[t] r.amount[t]
) )
@ -100,7 +100,7 @@ function _add_flexiramp_reserve_eqs!(
model, model,
sum( sum(
model[:dwflexiramp][sc.name, r.name, g.name, t] for model[:dwflexiramp][sc.name, r.name, g.name, t] for
g in r.units g in r.thermal_units
) + model[:dwflexiramp_shortfall][sc.name, r.name, t] >= ) + model[:dwflexiramp_shortfall][sc.name, r.name, t] >=
r.amount[t] r.amount[t]
) )

@ -6,7 +6,7 @@
# related to the binary commitment, startup and shutdown decisions of units # related to the binary commitment, startup and shutdown decisions of units
function _add_unit_commitment!( function _add_unit_commitment!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation::Formulation, formulation::Formulation,
) )
if !all(g.must_run) && any(g.must_run) if !all(g.must_run) && any(g.must_run)
@ -31,7 +31,7 @@ end
# related to the continuous dispatch decisions of units # related to the continuous dispatch decisions of units
function _add_unit_dispatch!( function _add_unit_dispatch!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation::Formulation, formulation::Formulation,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
) )
@ -64,11 +64,11 @@ function _add_unit_dispatch!(
return return
end end
_is_initially_on(g::Unit)::Float64 = (g.initial_status > 0 ? 1.0 : 0.0) _is_initially_on(g::ThermalUnit)::Float64 = (g.initial_status > 0 ? 1.0 : 0.0)
function _add_spinning_reserve_vars!( function _add_spinning_reserve_vars!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
)::Nothing )::Nothing
reserve = _init(model, :reserve) reserve = _init(model, :reserve)
@ -92,7 +92,7 @@ end
function _add_flexiramp_reserve_vars!( function _add_flexiramp_reserve_vars!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
)::Nothing )::Nothing
upflexiramp = _init(model, :upflexiramp) upflexiramp = _init(model, :upflexiramp)
@ -128,7 +128,7 @@ function _add_flexiramp_reserve_vars!(
return return
end end
function _add_startup_shutdown_vars!(model::JuMP.Model, g::Unit)::Nothing function _add_startup_shutdown_vars!(model::JuMP.Model, g::ThermalUnit)::Nothing
startup = _init(model, :startup) startup = _init(model, :startup)
for t in 1:model[:instance].time for t in 1:model[:instance].time
for s in 1:length(g.startup_categories) for s in 1:length(g.startup_categories)
@ -140,7 +140,7 @@ end
function _add_startup_shutdown_limit_eqs!( function _add_startup_shutdown_limit_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
)::Nothing )::Nothing
eq_shutdown_limit = _init(model, :eq_shutdown_limit) eq_shutdown_limit = _init(model, :eq_shutdown_limit)
@ -179,7 +179,7 @@ end
function _add_ramp_eqs!( function _add_ramp_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
formulation::RampingFormulation, formulation::RampingFormulation,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
)::Nothing )::Nothing
@ -224,7 +224,10 @@ function _add_ramp_eqs!(
end end
end end
function _add_min_uptime_downtime_eqs!(model::JuMP.Model, g::Unit)::Nothing function _add_min_uptime_downtime_eqs!(
model::JuMP.Model,
g::ThermalUnit,
)::Nothing
is_on = model[:is_on] 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]
@ -269,7 +272,7 @@ end
function _add_net_injection_eqs!( function _add_net_injection_eqs!(
model::JuMP.Model, model::JuMP.Model,
g::Unit, g::ThermalUnit,
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
)::Nothing )::Nothing
expr_net_injection = model[:expr_net_injection] expr_net_injection = model[:expr_net_injection]

@ -16,7 +16,7 @@ function fix!(model::JuMP.Model, solution::AbstractDict)::Nothing
prod_above = model[:prod_above] prod_above = model[:prod_above]
reserve = model[:reserve] reserve = model[:reserve]
for sc in instance.scenarios for sc in instance.scenarios
for g in sc.units for g in sc.thermal_units
for t in 1:T for t in 1:T
is_on_value = round(solution[sc.name]["Is on"][g.name][t]) is_on_value = round(solution[sc.name]["Is on"][g.name][t])
prod_value = round( prod_value = round(
@ -33,7 +33,7 @@ function fix!(model::JuMP.Model, solution::AbstractDict)::Nothing
end end
for r in sc.reserves for r in sc.reserves
r.type == "spinning" || continue r.type == "spinning" || continue
for g in r.units for g in r.thermal_units
for t in 1:T for t in 1:T
reserve_value = round( reserve_value = round(
solution[sc.name]["Spinning reserve (MW)"][r.name][g.name][t], solution[sc.name]["Spinning reserve (MW)"][r.name][g.name][t],

@ -65,17 +65,21 @@ function solution(model::JuMP.Model)::OrderedDict
sol = OrderedDict() sol = OrderedDict()
for sc in instance.scenarios for sc in instance.scenarios
sol[sc.name] = OrderedDict() sol[sc.name] = OrderedDict()
if !isempty(sc.units) if !isempty(sc.thermal_units)
sol[sc.name]["Production (MW)"] = sol[sc.name]["Production (MW)"] = OrderedDict(
OrderedDict(g.name => production(g, sc) for g in sc.units) g.name => production(g, sc) for g in sc.thermal_units
sol[sc.name]["Production cost (\$)"] = )
OrderedDict(g.name => production_cost(g, sc) for g in sc.units) sol[sc.name]["Production cost (\$)"] = OrderedDict(
sol[sc.name]["Startup cost (\$)"] = g.name => production_cost(g, sc) for g in sc.thermal_units
OrderedDict(g.name => startup_cost(g, sc) for g in sc.units) )
sol[sc.name]["Is on"] = timeseries(model[:is_on], sc.units) sol[sc.name]["Startup cost (\$)"] = OrderedDict(
sol[sc.name]["Switch on"] = timeseries(model[:switch_on], sc.units) g.name => startup_cost(g, sc) for g in sc.thermal_units
)
sol[sc.name]["Is on"] = timeseries(model[:is_on], sc.thermal_units)
sol[sc.name]["Switch on"] =
timeseries(model[:switch_on], sc.thermal_units)
sol[sc.name]["Switch off"] = sol[sc.name]["Switch off"] =
timeseries(model[:switch_off], sc.units) timeseries(model[:switch_off], sc.thermal_units)
sol[sc.name]["Net injection (MW)"] = sol[sc.name]["Net injection (MW)"] =
timeseries(model[:net_injection], sc.buses, sc = sc) timeseries(model[:net_injection], sc.buses, sc = sc)
sol[sc.name]["Load curtail (MW)"] = sol[sc.name]["Load curtail (MW)"] =
@ -103,7 +107,7 @@ function solution(model::JuMP.Model)::OrderedDict
r.name => OrderedDict( r.name => OrderedDict(
g.name => [ g.name => [
value(model[:reserve][sc.name, r.name, g.name, t]) for t in 1:instance.time value(model[:reserve][sc.name, r.name, g.name, t]) for t in 1:instance.time
] for g in r.units ] for g in r.thermal_units
) for r in sc.reserves if r.type == "spinning" ) for r in sc.reserves if r.type == "spinning"
) )
sol[sc.name]["Spinning reserve shortfall (MW)"] = OrderedDict( sol[sc.name]["Spinning reserve shortfall (MW)"] = OrderedDict(
@ -116,7 +120,7 @@ function solution(model::JuMP.Model)::OrderedDict
r.name => OrderedDict( r.name => OrderedDict(
g.name => [ g.name => [
value(model[:upflexiramp][sc.name, r.name, g.name, t]) for t in 1:instance.time value(model[:upflexiramp][sc.name, r.name, g.name, t]) for t in 1:instance.time
] for g in r.units ] for g in r.thermal_units
) for r in sc.reserves if r.type == "flexiramp" ) for r in sc.reserves if r.type == "flexiramp"
) )
sol[sc.name]["Up-flexiramp shortfall (MW)"] = OrderedDict( sol[sc.name]["Up-flexiramp shortfall (MW)"] = OrderedDict(
@ -128,7 +132,7 @@ function solution(model::JuMP.Model)::OrderedDict
r.name => OrderedDict( r.name => OrderedDict(
g.name => [ g.name => [
value(model[:dwflexiramp][sc.name, r.name, g.name, t]) for t in 1:instance.time value(model[:dwflexiramp][sc.name, r.name, g.name, t]) for t in 1:instance.time
] for g in r.units ] for g in r.thermal_units
) for r in sc.reserves if r.type == "flexiramp" ) for r in sc.reserves if r.type == "flexiramp"
) )
sol[sc.name]["Down-flexiramp shortfall (MW)"] = OrderedDict( sol[sc.name]["Down-flexiramp shortfall (MW)"] = OrderedDict(

@ -5,7 +5,7 @@
function set_warm_start!(model::JuMP.Model, solution::AbstractDict)::Nothing function set_warm_start!(model::JuMP.Model, solution::AbstractDict)::Nothing
instance, T = model[:instance], model[:instance].time instance, T = model[:instance], model[:instance].time
is_on = model[:is_on] is_on = model[:is_on]
for g in instance.units for g in instance.thermal_units
for t in 1:T for t in 1:T
JuMP.set_start_value(is_on[g.name, t], solution["Is on"][g.name][t]) JuMP.set_start_value(is_on[g.name, t], solution["Is on"][g.name][t])
JuMP.set_start_value( JuMP.set_start_value(

@ -15,7 +15,7 @@ function generate_initial_conditions!(
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
optimizer, optimizer,
)::Nothing )::Nothing
G = sc.units G = sc.thermal_units
B = sc.buses B = sc.buses
t = 1 t = 1
mip = JuMP.Model(optimizer) mip = JuMP.Model(optimizer)

@ -123,7 +123,7 @@ function _randomize_costs(
sc::UnitCommitmentScenario, sc::UnitCommitmentScenario,
distribution, distribution,
)::Nothing )::Nothing
for unit in sc.units for unit in sc.thermal_units
α = rand(rng, distribution) α = rand(rng, distribution)
unit.min_power_cost *= α unit.min_power_cost *= α
for k in unit.cost_segments for k in unit.cost_segments
@ -168,7 +168,7 @@ function _randomize_load_profile(
) )
push!(system_load, system_load[t-1] * gamma) push!(system_load, system_load[t-1] * gamma)
end end
capacity = sum(maximum(u.max_power) for u in sc.units) capacity = sum(maximum(u.max_power) for u in sc.thermal_units)
peak_load = rand(rng, params.peak_load) * capacity peak_load = rand(rng, params.peak_load) * capacity
system_load = system_load ./ maximum(system_load) .* peak_load system_load = system_load ./ maximum(system_load) .* peak_load

@ -29,7 +29,7 @@ function slice(
for r in sc.reserves for r in sc.reserves
r.amount = r.amount[range] r.amount = r.amount[range]
end end
for u in sc.units for u in sc.thermal_units
u.max_power = u.max_power[range] u.max_power = u.max_power[range]
u.min_power = u.min_power[range] u.min_power = u.min_power[range]
u.must_run = u.must_run[range] u.must_run = u.must_run[range]

@ -15,7 +15,7 @@ Returns the number of validation errors found.
function repair!(sc::UnitCommitmentScenario)::Int function repair!(sc::UnitCommitmentScenario)::Int
n_errors = 0 n_errors = 0
for g in sc.units for g in sc.thermal_units
# Startup costs and delays must be increasing # Startup costs and delays must be increasing
for s in 2:length(g.startup_categories) for s in 2:length(g.startup_categories)

@ -45,7 +45,7 @@ end
function _validate_units(instance::UnitCommitmentInstance, solution; tol = 0.01) function _validate_units(instance::UnitCommitmentInstance, solution; tol = 0.01)
err_count = 0 err_count = 0
for sc in instance.scenarios for sc in instance.scenarios
for unit in sc.units for unit in sc.thermal_units
production = solution[sc.name]["Production (MW)"][unit.name] production = solution[sc.name]["Production (MW)"][unit.name]
reserve = [0.0 for _ in 1:instance.time] reserve = [0.0 for _ in 1:instance.time]
spinning_reserves = spinning_reserves =
@ -114,7 +114,7 @@ function _validate_units(instance::UnitCommitmentInstance, solution; tol = 0.01)
# Verify reserve eligibility # Verify reserve eligibility
for r in sc.reserves for r in sc.reserves
if r.type == "spinning" if r.type == "spinning"
if unit r.units && ( if unit r.thermal_units && (
unit in keys( unit in keys(
solution[sc.name]["Spinning reserve (MW)"][r.name], solution[sc.name]["Spinning reserve (MW)"][r.name],
) )
@ -324,7 +324,7 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
end end
production = sum( production = sum(
solution[sc.name]["Production (MW)"][g.name][t] for solution[sc.name]["Production (MW)"][g.name][t] for
g in sc.units g in sc.thermal_units
) )
if "Load curtail (MW)" in keys(solution) if "Load curtail (MW)" in keys(solution)
load_curtail = sum( load_curtail = sum(
@ -352,7 +352,7 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
if r.type == "spinning" if r.type == "spinning"
provided = sum( provided = sum(
solution[sc.name]["Spinning reserve (MW)"][r.name][g.name][t] solution[sc.name]["Spinning reserve (MW)"][r.name][g.name][t]
for g in r.units for g in r.thermal_units
) )
shortfall = shortfall =
solution[sc.name]["Spinning reserve shortfall (MW)"][r.name][t] solution[sc.name]["Spinning reserve shortfall (MW)"][r.name][t]
@ -371,7 +371,7 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
elseif r.type == "flexiramp" elseif r.type == "flexiramp"
upflexiramp = sum( upflexiramp = sum(
solution[sc.name]["Up-flexiramp (MW)"][r.name][g.name][t] solution[sc.name]["Up-flexiramp (MW)"][r.name][g.name][t]
for g in r.units for g in r.thermal_units
) )
upflexiramp_shortfall = upflexiramp_shortfall =
solution[sc.name]["Up-flexiramp shortfall (MW)"][r.name][t] solution[sc.name]["Up-flexiramp shortfall (MW)"][r.name][t]
@ -389,7 +389,7 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
dwflexiramp = sum( dwflexiramp = sum(
solution[sc.name]["Down-flexiramp (MW)"][r.name][g.name][t] solution[sc.name]["Down-flexiramp (MW)"][r.name][g.name][t]
for g in r.units for g in r.thermal_units
) )
dwflexiramp_shortfall = dwflexiramp_shortfall =
solution[sc.name]["Down-flexiramp shortfall (MW)"][r.name][t] solution[sc.name]["Down-flexiramp shortfall (MW)"][r.name][t]

@ -9,14 +9,14 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
@test length(instance.scenarios) == 1 @test length(instance.scenarios) == 1
sc = instance.scenarios[1] sc = instance.scenarios[1]
@test length(sc.reserves_by_name["r1"].amount) == 4 @test length(sc.reserves_by_name["r1"].amount) == 4
@test sc.units_by_name["g2"].reserves[1].name == "r1" @test sc.thermal_units_by_name["g2"].reserves[1].name == "r1"
end end
@testset "read v0.3" begin @testset "read v0.3" begin
instance = UnitCommitment.read("$FIXTURES/ucjl-0.3.json.gz") instance = UnitCommitment.read("$FIXTURES/ucjl-0.3.json.gz")
@test length(instance.scenarios) == 1 @test length(instance.scenarios) == 1
sc = instance.scenarios[1] sc = instance.scenarios[1]
@test length(sc.units) == 6 @test length(sc.thermal_units) == 6
@test length(sc.buses) == 14 @test length(sc.buses) == 14
@test length(sc.lines) == 20 @test length(sc.lines) == 20
end end

@ -8,15 +8,15 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
instance = UnitCommitment.read("$FIXTURES/case14.json.gz") instance = UnitCommitment.read("$FIXTURES/case14.json.gz")
@test repr(instance) == ( @test repr(instance) == (
"UnitCommitmentInstance(1 scenarios, 6 units, 14 buses, " * "UnitCommitmentInstance(1 scenarios, 6 thermal units, 0 profiled units, 14 buses, " *
"20 lines, 19 contingencies, 1 price sensitive loads, 0 profiled units, 4 time steps)" "20 lines, 19 contingencies, 1 price sensitive loads, 4 time steps)"
) )
@test length(instance.scenarios) == 1 @test length(instance.scenarios) == 1
sc = instance.scenarios[1] sc = instance.scenarios[1]
@test length(sc.lines) == 20 @test length(sc.lines) == 20
@test length(sc.buses) == 14 @test length(sc.buses) == 14
@test length(sc.units) == 6 @test length(sc.thermal_units) == 6
@test length(sc.contingencies) == 19 @test length(sc.contingencies) == 19
@test length(sc.price_sensitive_loads) == 1 @test length(sc.price_sensitive_loads) == 1
@test instance.time == 4 @test instance.time == 4
@ -49,7 +49,7 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
@test sc.reserves[1].amount == [100.0, 100.0, 100.0, 100.0] @test sc.reserves[1].amount == [100.0, 100.0, 100.0, 100.0]
@test sc.reserves_by_name["r1"].name == "r1" @test sc.reserves_by_name["r1"].name == "r1"
unit = sc.units[1] unit = sc.thermal_units[1]
@test unit.name == "g1" @test unit.name == "g1"
@test unit.bus.name == "b1" @test unit.bus.name == "b1"
@test unit.ramp_up_limit == 1e6 @test unit.ramp_up_limit == 1e6
@ -76,14 +76,14 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
@test unit.startup_categories[2].cost == 1500.0 @test unit.startup_categories[2].cost == 1500.0
@test unit.startup_categories[3].cost == 2000.0 @test unit.startup_categories[3].cost == 2000.0
@test length(unit.reserves) == 0 @test length(unit.reserves) == 0
@test sc.units_by_name["g1"].name == "g1" @test sc.thermal_units_by_name["g1"].name == "g1"
unit = sc.units[2] unit = sc.thermal_units[2]
@test unit.name == "g2" @test unit.name == "g2"
@test unit.must_run == [false for t in 1:4] @test unit.must_run == [false for t in 1:4]
@test length(unit.reserves) == 1 @test length(unit.reserves) == 1
unit = sc.units[3] unit = sc.thermal_units[3]
@test unit.name == "g3" @test unit.name == "g3"
@test unit.bus.name == "b3" @test unit.bus.name == "b3"
@test unit.ramp_up_limit == 70.0 @test unit.ramp_up_limit == 70.0
@ -106,7 +106,7 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
@test unit.reserves[1].name == "r1" @test unit.reserves[1].name == "r1"
@test sc.contingencies[1].lines == [sc.lines[1]] @test sc.contingencies[1].lines == [sc.lines[1]]
@test sc.contingencies[1].units == [] @test sc.contingencies[1].thermal_units == []
@test sc.contingencies[1].name == "c1" @test sc.contingencies[1].name == "c1"
@test sc.contingencies_by_name["c1"].name == "c1" @test sc.contingencies_by_name["c1"].name == "c1"
@ -121,7 +121,7 @@ end
@testset "read_benchmark sub-hourly" begin @testset "read_benchmark sub-hourly" begin
instance = UnitCommitment.read("$FIXTURES/case14-sub-hourly.json.gz") instance = UnitCommitment.read("$FIXTURES/case14-sub-hourly.json.gz")
@test instance.time == 4 @test instance.time == 4
unit = instance.scenarios[1].units[1] unit = instance.scenarios[1].thermal_units[1]
@test unit.name == "g1" @test unit.name == "g1"
@test unit.min_uptime == 2 @test unit.min_uptime == 2
@test unit.min_downtime == 2 @test unit.min_downtime == 2

@ -10,7 +10,7 @@ using UnitCommitment, Cbc, JuMP
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
sc = instance.scenarios[1] sc = instance.scenarios[1]
# All units should have unknown initial conditions # All units should have unknown initial conditions
for g in sc.units for g in sc.thermal_units
@test g.initial_power === nothing @test g.initial_power === nothing
@test g.initial_status === nothing @test g.initial_status === nothing
end end
@ -19,7 +19,7 @@ using UnitCommitment, Cbc, JuMP
UnitCommitment.generate_initial_conditions!(sc, optimizer) UnitCommitment.generate_initial_conditions!(sc, optimizer)
# All units should now have known initial conditions # All units should now have known initial conditions
for g in sc.units for g in sc.thermal_units
@test g.initial_power !== nothing @test g.initial_power !== nothing
@test g.initial_status !== nothing @test g.initial_status !== nothing
end end

@ -21,7 +21,7 @@ test_approx(x, y) = @test isapprox(x, y, atol = 1e-3)
@testset "cost and load share" begin @testset "cost and load share" begin
sc = get_scenario() sc = get_scenario()
# Check original costs # Check original costs
unit = sc.units[10] unit = sc.thermal_units[10]
test_approx(unit.min_power_cost[1], 825.023) test_approx(unit.min_power_cost[1], 825.023)
test_approx(unit.cost_segments[1].cost[1], 36.659) test_approx(unit.cost_segments[1].cost[1], 36.659)
test_approx(unit.startup_categories[1].cost[1], 7570.42) test_approx(unit.startup_categories[1].cost[1], 7570.42)

@ -13,7 +13,7 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
@test modified.time == 2 @test modified.time == 2
@test length(sc.power_balance_penalty) == 2 @test length(sc.power_balance_penalty) == 2
@test length(sc.reserves_by_name["r1"].amount) == 2 @test length(sc.reserves_by_name["r1"].amount) == 2
for u in sc.units for u in sc.thermal_units
@test length(u.max_power) == 2 @test length(u.max_power) == 2
@test length(u.min_power) == 2 @test length(u.min_power) == 2
@test length(u.must_run) == 2 @test length(u.must_run) == 2

Loading…
Cancel
Save