mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 00:08:52 -06:00
Rename Unit to ThermalUnit
This commit is contained in:
@@ -129,7 +129,7 @@ end
|
||||
|
||||
function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
_migrate(json)
|
||||
units = Unit[]
|
||||
thermal_units = ThermalUnit[]
|
||||
buses = Bus[]
|
||||
contingencies = Contingency[]
|
||||
lines = TransmissionLine[]
|
||||
@@ -160,7 +160,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
|
||||
name_to_bus = Dict{String,Bus}()
|
||||
name_to_line = Dict{String,TransmissionLine}()
|
||||
name_to_unit = Dict{String,Unit}()
|
||||
name_to_unit = Dict{String,ThermalUnit}()
|
||||
name_to_reserve = Dict{String,Reserve}()
|
||||
|
||||
function timeseries(x; default = nothing)
|
||||
@@ -181,7 +181,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
bus_name,
|
||||
length(buses),
|
||||
timeseries(dict["Load (MW)"]),
|
||||
Unit[],
|
||||
ThermalUnit[],
|
||||
PriceSensitiveLoad[],
|
||||
ProfiledUnit[],
|
||||
)
|
||||
@@ -196,7 +196,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
name = reserve_name,
|
||||
type = lowercase(dict["Type"]),
|
||||
amount = timeseries(dict["Amount (MW)"]),
|
||||
units = [],
|
||||
thermal_units = [],
|
||||
shortfall_penalty = scalar(
|
||||
dict["Shortfall penalty (\$/MW)"],
|
||||
default = -1,
|
||||
@@ -282,7 +282,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
initial_status *= time_multiplier
|
||||
end
|
||||
|
||||
unit = Unit(
|
||||
unit = ThermalUnit(
|
||||
unit_name,
|
||||
bus,
|
||||
max_power,
|
||||
@@ -303,12 +303,12 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
startup_categories,
|
||||
unit_reserves,
|
||||
)
|
||||
push!(bus.units, unit)
|
||||
push!(bus.thermal_units, unit)
|
||||
for r in unit_reserves
|
||||
push!(r.units, unit)
|
||||
push!(r.thermal_units, unit)
|
||||
end
|
||||
name_to_unit[unit_name] = unit
|
||||
push!(units, unit)
|
||||
push!(thermal_units, unit)
|
||||
elseif lowercase(unit_type) === "profiled"
|
||||
bus = name_to_bus[dict["Bus"]]
|
||||
pu = ProfiledUnit(
|
||||
@@ -355,7 +355,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
# Read contingencies
|
||||
if "Contingencies" in keys(json)
|
||||
for (cont_name, dict) in json["Contingencies"]
|
||||
affected_units = Unit[]
|
||||
affected_units = ThermalUnit[]
|
||||
affected_lines = TransmissionLine[]
|
||||
if "Affected lines" in keys(dict)
|
||||
affected_lines =
|
||||
@@ -400,8 +400,8 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
||||
reserves = reserves,
|
||||
reserves_by_name = name_to_reserve,
|
||||
time = T,
|
||||
units_by_name = Dict(g.name => g for g in units),
|
||||
units = units,
|
||||
thermal_units_by_name = Dict(g.name => g for g in thermal_units),
|
||||
thermal_units = thermal_units,
|
||||
profiled_units_by_name = Dict(pu.name => pu for pu in profiled_units),
|
||||
profiled_units = profiled_units,
|
||||
isf = spzeros(Float64, length(lines), length(buses) - 1),
|
||||
|
||||
@@ -6,7 +6,7 @@ mutable struct Bus
|
||||
name::String
|
||||
offset::Int
|
||||
load::Vector{Float64}
|
||||
units::Vector
|
||||
thermal_units::Vector
|
||||
price_sensitive_loads::Vector
|
||||
profiled_units::Vector
|
||||
end
|
||||
@@ -25,11 +25,11 @@ Base.@kwdef mutable struct Reserve
|
||||
name::String
|
||||
type::String
|
||||
amount::Vector{Float64}
|
||||
units::Vector
|
||||
thermal_units::Vector
|
||||
shortfall_penalty::Float64
|
||||
end
|
||||
|
||||
mutable struct Unit
|
||||
mutable struct ThermalUnit
|
||||
name::String
|
||||
bus::Bus
|
||||
max_power::Vector{Float64}
|
||||
@@ -64,7 +64,7 @@ end
|
||||
mutable struct Contingency
|
||||
name::String
|
||||
lines::Vector{TransmissionLine}
|
||||
units::Vector{Unit}
|
||||
thermal_units::Vector{ThermalUnit}
|
||||
end
|
||||
|
||||
mutable struct PriceSensitiveLoad
|
||||
@@ -95,13 +95,13 @@ Base.@kwdef mutable struct UnitCommitmentScenario
|
||||
price_sensitive_loads_by_name::Dict{AbstractString,PriceSensitiveLoad}
|
||||
price_sensitive_loads::Vector{PriceSensitiveLoad}
|
||||
probability::Float64
|
||||
reserves_by_name::Dict{AbstractString,Reserve}
|
||||
reserves::Vector{Reserve}
|
||||
time::Int
|
||||
units_by_name::Dict{AbstractString,Unit}
|
||||
units::Vector{Unit}
|
||||
profiled_units_by_name::Dict{AbstractString,ProfiledUnit}
|
||||
profiled_units::Vector{ProfiledUnit}
|
||||
reserves_by_name::Dict{AbstractString,Reserve}
|
||||
reserves::Vector{Reserve}
|
||||
thermal_units_by_name::Dict{AbstractString,ThermalUnit}
|
||||
thermal_units::Vector{ThermalUnit}
|
||||
time::Int
|
||||
end
|
||||
|
||||
Base.@kwdef mutable struct UnitCommitmentInstance
|
||||
@@ -113,12 +113,12 @@ function Base.show(io::IO, instance::UnitCommitmentInstance)
|
||||
sc = instance.scenarios[1]
|
||||
print(io, "UnitCommitmentInstance(")
|
||||
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.lines)) lines, ")
|
||||
print(io, "$(length(sc.contingencies)) contingencies, ")
|
||||
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, ")")
|
||||
return
|
||||
|
||||
@@ -131,7 +131,7 @@ function _aelmp_check_parameters(
|
||||
)
|
||||
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)
|
||||
if any(u -> u.min_uptime > 1 || u.min_downtime > 1, all_units)
|
||||
error(
|
||||
@@ -159,25 +159,25 @@ function _modify_scenario!(
|
||||
if !method.allow_offline_participation
|
||||
# 1. remove (if NOT allowing) the offline generators
|
||||
units_to_remove = []
|
||||
for unit in sc.units
|
||||
for unit in sc.thermal_units
|
||||
# remove based on the solved UC model result
|
||||
# remove the unit if it is never on
|
||||
if all(t -> value(model[:is_on][unit.name, t]) == 0, sc.time)
|
||||
# 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
|
||||
for r in unit.reserves
|
||||
filter!(x -> x.name != unit.name, r.units)
|
||||
filter!(x -> x.name != unit.name, r.thermal_units)
|
||||
end
|
||||
# append the name to the remove list
|
||||
push!(units_to_remove, unit.name)
|
||||
end
|
||||
end
|
||||
# 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
|
||||
|
||||
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
|
||||
# min_power & min_costs are vectors with dimension T
|
||||
if unit.min_power[1] != 0
|
||||
@@ -207,5 +207,6 @@ function _modify_scenario!(
|
||||
unit.startup_categories =
|
||||
StartupCategory[StartupCategory(0, first_startup_cost)]
|
||||
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
|
||||
|
||||
@@ -77,7 +77,7 @@ function build_model(;
|
||||
end
|
||||
model[:obj] = AffExpr()
|
||||
model[:instance] = instance
|
||||
for g in instance.scenarios[1].units
|
||||
for g in instance.scenarios[1].thermal_units
|
||||
_add_unit_commitment!(model, g, formulation)
|
||||
end
|
||||
for sc in instance.scenarios
|
||||
@@ -93,7 +93,7 @@ function build_model(;
|
||||
for ps in sc.price_sensitive_loads
|
||||
_add_price_sensitive_load!(model, ps, sc)
|
||||
end
|
||||
for g in sc.units
|
||||
for g in sc.thermal_units
|
||||
_add_unit_dispatch!(model, g, formulation, sc)
|
||||
end
|
||||
for pu in sc.profiled_units
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_ramp_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
formulation_ramping::ArrCon2000.Ramping,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_production_piecewise_linear_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
formulation_pwl_costs::CarArr2006.PwlCosts,
|
||||
formulation_status_vars::StatusVarsFormulation,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_ramp_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
formulation_ramping::DamKucRajAta2016.Ramping,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_production_vars!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
sc::UnitCommitmentScenario,
|
||||
)::Nothing
|
||||
@@ -21,7 +21,7 @@ end
|
||||
|
||||
function _add_production_limit_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
sc::UnitCommitmentScenario,
|
||||
)::Nothing
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_production_piecewise_linear_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
formulation_pwl_costs::Gar1962.PwlCosts,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_status_vars!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
)::Nothing
|
||||
is_on = _init(model, :is_on)
|
||||
@@ -27,7 +27,7 @@ end
|
||||
|
||||
function _add_status_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
)::Nothing
|
||||
eq_binary_link = _init(model, :eq_binary_link)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_production_piecewise_linear_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
formulation_pwl_costs::KnuOstWat2018.PwlCosts,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_ramp_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
formulation_ramping::MorLatRam2013.Ramping,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_startup_cost_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation::MorLatRam2013.StartupCosts,
|
||||
)::Nothing
|
||||
eq_startup_choose = _init(model, :eq_startup_choose)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_ramp_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation_prod_vars::Gar1962.ProdVars,
|
||||
formulation_ramping::PanGua2016.Ramping,
|
||||
formulation_status_vars::Gar1962.StatusVars,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
function _add_ramp_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
::Gar1962.ProdVars,
|
||||
::WanHob2016.Ramping,
|
||||
::Gar1962.StatusVars,
|
||||
|
||||
@@ -53,7 +53,7 @@ function _add_spinning_reserve_eqs!(
|
||||
model,
|
||||
sum(
|
||||
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] >=
|
||||
r.amount[t]
|
||||
)
|
||||
@@ -91,7 +91,7 @@ function _add_flexiramp_reserve_eqs!(
|
||||
model,
|
||||
sum(
|
||||
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] >=
|
||||
r.amount[t]
|
||||
)
|
||||
@@ -100,7 +100,7 @@ function _add_flexiramp_reserve_eqs!(
|
||||
model,
|
||||
sum(
|
||||
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] >=
|
||||
r.amount[t]
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# related to the binary commitment, startup and shutdown decisions of units
|
||||
function _add_unit_commitment!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation::Formulation,
|
||||
)
|
||||
if !all(g.must_run) && any(g.must_run)
|
||||
@@ -31,7 +31,7 @@ end
|
||||
# related to the continuous dispatch decisions of units
|
||||
function _add_unit_dispatch!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation::Formulation,
|
||||
sc::UnitCommitmentScenario,
|
||||
)
|
||||
@@ -64,11 +64,11 @@ function _add_unit_dispatch!(
|
||||
return
|
||||
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!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
sc::UnitCommitmentScenario,
|
||||
)::Nothing
|
||||
reserve = _init(model, :reserve)
|
||||
@@ -92,7 +92,7 @@ end
|
||||
|
||||
function _add_flexiramp_reserve_vars!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
sc::UnitCommitmentScenario,
|
||||
)::Nothing
|
||||
upflexiramp = _init(model, :upflexiramp)
|
||||
@@ -128,7 +128,7 @@ function _add_flexiramp_reserve_vars!(
|
||||
return
|
||||
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)
|
||||
for t in 1:model[:instance].time
|
||||
for s in 1:length(g.startup_categories)
|
||||
@@ -140,7 +140,7 @@ end
|
||||
|
||||
function _add_startup_shutdown_limit_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
sc::UnitCommitmentScenario,
|
||||
)::Nothing
|
||||
eq_shutdown_limit = _init(model, :eq_shutdown_limit)
|
||||
@@ -179,7 +179,7 @@ end
|
||||
|
||||
function _add_ramp_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
formulation::RampingFormulation,
|
||||
sc::UnitCommitmentScenario,
|
||||
)::Nothing
|
||||
@@ -224,7 +224,10 @@ function _add_ramp_eqs!(
|
||||
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]
|
||||
switch_off = model[:switch_off]
|
||||
switch_on = model[:switch_on]
|
||||
@@ -269,7 +272,7 @@ end
|
||||
|
||||
function _add_net_injection_eqs!(
|
||||
model::JuMP.Model,
|
||||
g::Unit,
|
||||
g::ThermalUnit,
|
||||
sc::UnitCommitmentScenario,
|
||||
)::Nothing
|
||||
expr_net_injection = model[:expr_net_injection]
|
||||
|
||||
@@ -16,7 +16,7 @@ function fix!(model::JuMP.Model, solution::AbstractDict)::Nothing
|
||||
prod_above = model[:prod_above]
|
||||
reserve = model[:reserve]
|
||||
for sc in instance.scenarios
|
||||
for g in sc.units
|
||||
for g in sc.thermal_units
|
||||
for t in 1:T
|
||||
is_on_value = round(solution[sc.name]["Is on"][g.name][t])
|
||||
prod_value = round(
|
||||
@@ -33,7 +33,7 @@ function fix!(model::JuMP.Model, solution::AbstractDict)::Nothing
|
||||
end
|
||||
for r in sc.reserves
|
||||
r.type == "spinning" || continue
|
||||
for g in r.units
|
||||
for g in r.thermal_units
|
||||
for t in 1:T
|
||||
reserve_value = round(
|
||||
solution[sc.name]["Spinning reserve (MW)"][r.name][g.name][t],
|
||||
|
||||
@@ -65,17 +65,21 @@ function solution(model::JuMP.Model)::OrderedDict
|
||||
sol = OrderedDict()
|
||||
for sc in instance.scenarios
|
||||
sol[sc.name] = OrderedDict()
|
||||
if !isempty(sc.units)
|
||||
sol[sc.name]["Production (MW)"] =
|
||||
OrderedDict(g.name => production(g, sc) for g in sc.units)
|
||||
sol[sc.name]["Production cost (\$)"] =
|
||||
OrderedDict(g.name => production_cost(g, sc) for g in sc.units)
|
||||
sol[sc.name]["Startup cost (\$)"] =
|
||||
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]["Switch on"] = timeseries(model[:switch_on], sc.units)
|
||||
if !isempty(sc.thermal_units)
|
||||
sol[sc.name]["Production (MW)"] = OrderedDict(
|
||||
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.thermal_units
|
||||
)
|
||||
sol[sc.name]["Startup cost (\$)"] = OrderedDict(
|
||||
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"] =
|
||||
timeseries(model[:switch_off], sc.units)
|
||||
timeseries(model[:switch_off], sc.thermal_units)
|
||||
sol[sc.name]["Net injection (MW)"] =
|
||||
timeseries(model[:net_injection], sc.buses, sc = sc)
|
||||
sol[sc.name]["Load curtail (MW)"] =
|
||||
@@ -103,7 +107,7 @@ function solution(model::JuMP.Model)::OrderedDict
|
||||
r.name => OrderedDict(
|
||||
g.name => [
|
||||
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"
|
||||
)
|
||||
sol[sc.name]["Spinning reserve shortfall (MW)"] = OrderedDict(
|
||||
@@ -116,7 +120,7 @@ function solution(model::JuMP.Model)::OrderedDict
|
||||
r.name => OrderedDict(
|
||||
g.name => [
|
||||
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"
|
||||
)
|
||||
sol[sc.name]["Up-flexiramp shortfall (MW)"] = OrderedDict(
|
||||
@@ -128,7 +132,7 @@ function solution(model::JuMP.Model)::OrderedDict
|
||||
r.name => OrderedDict(
|
||||
g.name => [
|
||||
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"
|
||||
)
|
||||
sol[sc.name]["Down-flexiramp shortfall (MW)"] = OrderedDict(
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
function set_warm_start!(model::JuMP.Model, solution::AbstractDict)::Nothing
|
||||
instance, T = model[:instance], model[:instance].time
|
||||
is_on = model[:is_on]
|
||||
for g in instance.units
|
||||
for g in instance.thermal_units
|
||||
for t in 1:T
|
||||
JuMP.set_start_value(is_on[g.name, t], solution["Is on"][g.name][t])
|
||||
JuMP.set_start_value(
|
||||
|
||||
@@ -15,7 +15,7 @@ function generate_initial_conditions!(
|
||||
sc::UnitCommitmentScenario,
|
||||
optimizer,
|
||||
)::Nothing
|
||||
G = sc.units
|
||||
G = sc.thermal_units
|
||||
B = sc.buses
|
||||
t = 1
|
||||
mip = JuMP.Model(optimizer)
|
||||
|
||||
@@ -123,7 +123,7 @@ function _randomize_costs(
|
||||
sc::UnitCommitmentScenario,
|
||||
distribution,
|
||||
)::Nothing
|
||||
for unit in sc.units
|
||||
for unit in sc.thermal_units
|
||||
α = rand(rng, distribution)
|
||||
unit.min_power_cost *= α
|
||||
for k in unit.cost_segments
|
||||
@@ -168,7 +168,7 @@ function _randomize_load_profile(
|
||||
)
|
||||
push!(system_load, system_load[t-1] * gamma)
|
||||
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
|
||||
system_load = system_load ./ maximum(system_load) .* peak_load
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ function slice(
|
||||
for r in sc.reserves
|
||||
r.amount = r.amount[range]
|
||||
end
|
||||
for u in sc.units
|
||||
for u in sc.thermal_units
|
||||
u.max_power = u.max_power[range]
|
||||
u.min_power = u.min_power[range]
|
||||
u.must_run = u.must_run[range]
|
||||
|
||||
@@ -15,7 +15,7 @@ Returns the number of validation errors found.
|
||||
function repair!(sc::UnitCommitmentScenario)::Int
|
||||
n_errors = 0
|
||||
|
||||
for g in sc.units
|
||||
for g in sc.thermal_units
|
||||
|
||||
# Startup costs and delays must be increasing
|
||||
for s in 2:length(g.startup_categories)
|
||||
|
||||
@@ -45,7 +45,7 @@ end
|
||||
function _validate_units(instance::UnitCommitmentInstance, solution; tol = 0.01)
|
||||
err_count = 0
|
||||
for sc in instance.scenarios
|
||||
for unit in sc.units
|
||||
for unit in sc.thermal_units
|
||||
production = solution[sc.name]["Production (MW)"][unit.name]
|
||||
reserve = [0.0 for _ in 1:instance.time]
|
||||
spinning_reserves =
|
||||
@@ -114,7 +114,7 @@ function _validate_units(instance::UnitCommitmentInstance, solution; tol = 0.01)
|
||||
# Verify reserve eligibility
|
||||
for r in sc.reserves
|
||||
if r.type == "spinning"
|
||||
if unit ∉ r.units && (
|
||||
if unit ∉ r.thermal_units && (
|
||||
unit in keys(
|
||||
solution[sc.name]["Spinning reserve (MW)"][r.name],
|
||||
)
|
||||
@@ -324,7 +324,7 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
|
||||
end
|
||||
production = sum(
|
||||
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)
|
||||
load_curtail = sum(
|
||||
@@ -352,7 +352,7 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
|
||||
if r.type == "spinning"
|
||||
provided = sum(
|
||||
solution[sc.name]["Spinning reserve (MW)"][r.name][g.name][t]
|
||||
for g in r.units
|
||||
for g in r.thermal_units
|
||||
)
|
||||
shortfall =
|
||||
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"
|
||||
upflexiramp = sum(
|
||||
solution[sc.name]["Up-flexiramp (MW)"][r.name][g.name][t]
|
||||
for g in r.units
|
||||
for g in r.thermal_units
|
||||
)
|
||||
upflexiramp_shortfall =
|
||||
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(
|
||||
solution[sc.name]["Down-flexiramp (MW)"][r.name][g.name][t]
|
||||
for g in r.units
|
||||
for g in r.thermal_units
|
||||
)
|
||||
dwflexiramp_shortfall =
|
||||
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
|
||||
sc = instance.scenarios[1]
|
||||
@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
|
||||
|
||||
@testset "read v0.3" begin
|
||||
instance = UnitCommitment.read("$FIXTURES/ucjl-0.3.json.gz")
|
||||
@test length(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.lines) == 20
|
||||
end
|
||||
|
||||
@@ -8,15 +8,15 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
|
||||
instance = UnitCommitment.read("$FIXTURES/case14.json.gz")
|
||||
|
||||
@test repr(instance) == (
|
||||
"UnitCommitmentInstance(1 scenarios, 6 units, 14 buses, " *
|
||||
"20 lines, 19 contingencies, 1 price sensitive loads, 0 profiled units, 4 time steps)"
|
||||
"UnitCommitmentInstance(1 scenarios, 6 thermal units, 0 profiled units, 14 buses, " *
|
||||
"20 lines, 19 contingencies, 1 price sensitive loads, 4 time steps)"
|
||||
)
|
||||
|
||||
@test length(instance.scenarios) == 1
|
||||
sc = instance.scenarios[1]
|
||||
@test length(sc.lines) == 20
|
||||
@test length(sc.buses) == 14
|
||||
@test length(sc.units) == 6
|
||||
@test length(sc.thermal_units) == 6
|
||||
@test length(sc.contingencies) == 19
|
||||
@test length(sc.price_sensitive_loads) == 1
|
||||
@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_by_name["r1"].name == "r1"
|
||||
|
||||
unit = sc.units[1]
|
||||
unit = sc.thermal_units[1]
|
||||
@test unit.name == "g1"
|
||||
@test unit.bus.name == "b1"
|
||||
@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[3].cost == 2000.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.must_run == [false for t in 1:4]
|
||||
@test length(unit.reserves) == 1
|
||||
|
||||
unit = sc.units[3]
|
||||
unit = sc.thermal_units[3]
|
||||
@test unit.name == "g3"
|
||||
@test unit.bus.name == "b3"
|
||||
@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 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_by_name["c1"].name == "c1"
|
||||
|
||||
@@ -121,7 +121,7 @@ end
|
||||
@testset "read_benchmark sub-hourly" begin
|
||||
instance = UnitCommitment.read("$FIXTURES/case14-sub-hourly.json.gz")
|
||||
@test instance.time == 4
|
||||
unit = instance.scenarios[1].units[1]
|
||||
unit = instance.scenarios[1].thermal_units[1]
|
||||
@test unit.name == "g1"
|
||||
@test unit.min_uptime == 2
|
||||
@test unit.min_downtime == 2
|
||||
|
||||
@@ -10,7 +10,7 @@ using UnitCommitment, Cbc, JuMP
|
||||
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
|
||||
sc = instance.scenarios[1]
|
||||
# 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_status === nothing
|
||||
end
|
||||
@@ -19,7 +19,7 @@ using UnitCommitment, Cbc, JuMP
|
||||
UnitCommitment.generate_initial_conditions!(sc, optimizer)
|
||||
|
||||
# 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_status !== nothing
|
||||
end
|
||||
|
||||
@@ -21,7 +21,7 @@ test_approx(x, y) = @test isapprox(x, y, atol = 1e-3)
|
||||
@testset "cost and load share" begin
|
||||
sc = get_scenario()
|
||||
# Check original costs
|
||||
unit = sc.units[10]
|
||||
unit = sc.thermal_units[10]
|
||||
test_approx(unit.min_power_cost[1], 825.023)
|
||||
test_approx(unit.cost_segments[1].cost[1], 36.659)
|
||||
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 length(sc.power_balance_penalty) == 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.min_power) == 2
|
||||
@test length(u.must_run) == 2
|
||||
|
||||
Reference in New Issue
Block a user