mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 00:08:52 -06:00
more condition checking on AELMP
This commit is contained in:
@@ -189,7 +189,7 @@ This method has two configurable parameters: `allow_offline_participation` and `
|
|||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
|
|
||||||
This approximation method is still under active research, and has several limitations. The implementation provided in the package is based on MISO Phase I only. It only supports fast start resources. More specifically, the minimum up/down time of all generators must be 1. The method does not support time-varying start-up costs. AELMPs are only calculated for the first time period if offline participation is not allowed.
|
This approximation method is still under active research, and has several limitations. The implementation provided in the package is based on MISO Phase I only. It only supports fast start resources. More specifically, the minimum up/down time of all generators must be 1, the initial power of all generators must be 0, and the initial status of all generators must be negative. The method does not support time-varying start-up costs. If offline participation is not allowed, AELMPs treats an asset to be offline if it is never on throughout all time periods.
|
||||||
|
|
||||||
```julia
|
```julia
|
||||||
using UnitCommitment
|
using UnitCommitment
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ using JuMP
|
|||||||
function compute_lmp(
|
function compute_lmp(
|
||||||
model::JuMP.Model,
|
model::JuMP.Model,
|
||||||
method::AELMP;
|
method::AELMP;
|
||||||
optimizer = nothing,
|
optimizer,
|
||||||
)
|
)::OrderedDict{Tuple{String,Int},Float64}
|
||||||
|
|
||||||
Calculates the approximate extended locational marginal prices of the given unit commitment instance.
|
Calculates the approximate extended locational marginal prices of the given unit commitment instance.
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ WARNING: This approximation method is not fully developed. The implementation is
|
|||||||
|
|
||||||
1. It only supports Fast Start resources. More specifically, the minimum up/down time has to be zero.
|
1. It only supports Fast Start resources. More specifically, the minimum up/down time has to be zero.
|
||||||
2. The method does NOT support time-varying start-up costs.
|
2. The method does NOT support time-varying start-up costs.
|
||||||
3. AELMPs are only calculated for the first time period if offline participation is not allowed.
|
3. An asset is considered offline if it is never on throughout all time periods.
|
||||||
|
|
||||||
Arguments
|
Arguments
|
||||||
---------
|
---------
|
||||||
@@ -82,7 +82,7 @@ function compute_lmp(
|
|||||||
)::OrderedDict{Tuple{String,Int},Float64}
|
)::OrderedDict{Tuple{String,Int},Float64}
|
||||||
@info "Building the approximation model..."
|
@info "Building the approximation model..."
|
||||||
instance = deepcopy(model[:instance])
|
instance = deepcopy(model[:instance])
|
||||||
_aelmp_check_parameters(method, model)
|
_aelmp_check_parameters(instance, model, method)
|
||||||
_modify_instance!(instance, model, method)
|
_modify_instance!(instance, model, method)
|
||||||
|
|
||||||
# prepare the result dictionary and solve the model
|
# prepare the result dictionary and solve the model
|
||||||
@@ -111,7 +111,11 @@ function compute_lmp(
|
|||||||
return elmp
|
return elmp
|
||||||
end
|
end
|
||||||
|
|
||||||
function _aelmp_check_parameters(method::AELMP, model::JuMP.Model)
|
function _aelmp_check_parameters(
|
||||||
|
instance::UnitCommitmentInstance,
|
||||||
|
model::JuMP.Model,
|
||||||
|
method::AELMP,
|
||||||
|
)
|
||||||
# CHECK: model must be solved if allow_offline_participation=false
|
# CHECK: model must be solved if allow_offline_participation=false
|
||||||
if !method.allow_offline_participation
|
if !method.allow_offline_participation
|
||||||
if isnothing(model) || !has_values(model)
|
if isnothing(model) || !has_values(model)
|
||||||
@@ -120,6 +124,29 @@ function _aelmp_check_parameters(method::AELMP, model::JuMP.Model)
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
all_units = instance.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(
|
||||||
|
"The minimum up/down time of all generators must be 1. AELMP only supports fast-starts.",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if any(u -> u.initial_power > 0, all_units)
|
||||||
|
error(
|
||||||
|
"The initial power of all generators must be 0.",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if any(u -> u.initial_status >= 0, all_units)
|
||||||
|
error(
|
||||||
|
"The initial status of all generators must be negative.",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
# CHECK: model does not support startup costs (in time series)
|
||||||
|
if any(u -> length(u.startup_categories) > 1, all_units)
|
||||||
|
error(
|
||||||
|
"The method does NOT support time-varying start-up costs.",
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _modify_instance!(
|
function _modify_instance!(
|
||||||
@@ -128,22 +155,25 @@ function _modify_instance!(
|
|||||||
method::AELMP,
|
method::AELMP,
|
||||||
)
|
)
|
||||||
# this function modifies the instance units (generators)
|
# this function modifies the instance units (generators)
|
||||||
# 1. remove (if NOT allowing) the offline generators
|
|
||||||
if !method.allow_offline_participation
|
if !method.allow_offline_participation
|
||||||
|
# 1. remove (if NOT allowing) the offline generators
|
||||||
|
units_to_remove = []
|
||||||
for unit in instance.units
|
for unit in instance.units
|
||||||
# remove based on the solved UC model result
|
# remove based on the solved UC model result
|
||||||
# here, only look at the first time slot (TIME-SERIES-NOT-SUPPORTED)
|
# remove the unit if it is never on
|
||||||
if value(model[:is_on][unit.name, 1]) == 0
|
if all(t -> value(model[:is_on][unit.name, t]) == 0, instance.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.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.units)
|
||||||
end
|
end
|
||||||
|
# append the name to the remove list
|
||||||
|
push!(units_to_remove, unit.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# unregister the units
|
# unregister the units from the remove list
|
||||||
filter!(x -> value(model[:is_on][x.name, 1]) != 0, instance.units)
|
filter!(x -> !(x.name in units_to_remove), instance.units)
|
||||||
end
|
end
|
||||||
|
|
||||||
for unit in instance.units
|
for unit in instance.units
|
||||||
@@ -164,7 +194,6 @@ function _modify_instance!(
|
|||||||
end
|
end
|
||||||
|
|
||||||
# 3. average the start-up costs (if considering)
|
# 3. average the start-up costs (if considering)
|
||||||
# for now, consider first element only (TIME-SERIES-NOT-SUPPORTED)
|
|
||||||
# if consider_startup_costs = false, then use the current first_startup_cost
|
# if consider_startup_costs = false, then use the current first_startup_cost
|
||||||
first_startup_cost = unit.startup_categories[1].cost
|
first_startup_cost = unit.startup_categories[1].cost
|
||||||
if method.consider_startup_costs
|
if method.consider_startup_costs
|
||||||
@@ -174,17 +203,8 @@ function _modify_instance!(
|
|||||||
end
|
end
|
||||||
first_startup_cost = 0.0 # zero out the start up cost
|
first_startup_cost = 0.0 # zero out the start up cost
|
||||||
end
|
end
|
||||||
|
|
||||||
# 4. other adjustments...
|
|
||||||
### FIXME in the future
|
|
||||||
# MISO Phase I: can ONLY solve fast-starts, force all startup time to be 0
|
|
||||||
unit.startup_categories =
|
unit.startup_categories =
|
||||||
StartupCategory[StartupCategory(0, first_startup_cost)]
|
StartupCategory[StartupCategory(0, first_startup_cost)]
|
||||||
unit.initial_status = -100
|
|
||||||
unit.initial_power = 0
|
|
||||||
unit.min_uptime = 0
|
|
||||||
unit.min_downtime = 0
|
|
||||||
### END FIXME
|
|
||||||
end
|
end
|
||||||
return instance.units_by_name = Dict(g.name => g for g in instance.units)
|
return instance.units_by_name = Dict(g.name => g for g in instance.units)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user