mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-07 08:48:51 -06:00
new formatting
This commit is contained in:
@@ -14,12 +14,10 @@ function fix!(model::JuMP.Model, solution::AbstractDict)::Nothing
|
||||
prod_above = model[:prod_above]
|
||||
reserve = model[:reserve]
|
||||
for g in instance.units
|
||||
for t in 1:T
|
||||
for t = 1:T
|
||||
is_on_value = round(solution["Is on"][g.name][t])
|
||||
prod_value =
|
||||
round(solution["Production (MW)"][g.name][t], digits = 5)
|
||||
reserve_value =
|
||||
round(solution["Reserve (MW)"][g.name][t], digits = 5)
|
||||
prod_value = round(solution["Production (MW)"][g.name][t], digits = 5)
|
||||
reserve_value = round(solution["Reserve (MW)"][g.name][t], digits = 5)
|
||||
JuMP.fix(is_on[g.name, t], is_on_value, force = true)
|
||||
JuMP.fix(
|
||||
prod_above[g.name, t],
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
function _enforce_transmission(
|
||||
model::JuMP.Model,
|
||||
violations::Vector{_Violation},
|
||||
)::Nothing
|
||||
function _enforce_transmission(model::JuMP.Model, violations::Vector{_Violation})::Nothing
|
||||
for v in violations
|
||||
_enforce_transmission(
|
||||
model = model,
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
|
||||
function _offer(filter::_ViolationFilter, v::_Violation)::Nothing
|
||||
if v.monitored_line.offset ∉ keys(filter.queues)
|
||||
filter.queues[v.monitored_line.offset] =
|
||||
PriorityQueue{_Violation,Float64}()
|
||||
filter.queues[v.monitored_line.offset] = PriorityQueue{_Violation,Float64}()
|
||||
end
|
||||
q::PriorityQueue{_Violation,Float64} =
|
||||
filter.queues[v.monitored_line.offset]
|
||||
q::PriorityQueue{_Violation,Float64} = filter.queues[v.monitored_line.offset]
|
||||
if length(q) < filter.max_per_line
|
||||
enqueue!(q, v => v.amount)
|
||||
else
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
|
||||
import Base.Threads: @threads
|
||||
|
||||
function _find_violations(
|
||||
model::JuMP.Model;
|
||||
max_per_line::Int,
|
||||
max_per_period::Int,
|
||||
)
|
||||
function _find_violations(model::JuMP.Model; max_per_line::Int, max_per_period::Int)
|
||||
instance = model[:instance]
|
||||
net_injection = model[:net_injection]
|
||||
overflow = model[:overflow]
|
||||
@@ -18,13 +14,10 @@ function _find_violations(
|
||||
time_screening = @elapsed begin
|
||||
non_slack_buses = [b for b in instance.buses if b.offset > 0]
|
||||
net_injection_values = [
|
||||
value(net_injection[b.name, t]) for b in non_slack_buses,
|
||||
t in 1:instance.time
|
||||
]
|
||||
overflow_values = [
|
||||
value(overflow[lm.name, t]) for lm in instance.lines,
|
||||
t in 1:instance.time
|
||||
value(net_injection[b.name, t]) for b in non_slack_buses, t = 1:instance.time
|
||||
]
|
||||
overflow_values =
|
||||
[value(overflow[lm.name, t]) for lm in instance.lines, t = 1:instance.time]
|
||||
violations = UnitCommitment._find_violations(
|
||||
instance = instance,
|
||||
net_injections = net_injection_values,
|
||||
@@ -35,10 +28,7 @@ function _find_violations(
|
||||
max_per_period = max_per_period,
|
||||
)
|
||||
end
|
||||
@info @sprintf(
|
||||
"Verified transmission limits in %.2f seconds",
|
||||
time_screening
|
||||
)
|
||||
@info @sprintf("Verified transmission limits in %.2f seconds", time_screening)
|
||||
return violations
|
||||
end
|
||||
|
||||
@@ -81,10 +71,8 @@ function _find_violations(;
|
||||
size(lodf) == (L, L) || error("lodf has incorrect size")
|
||||
|
||||
filters = Dict(
|
||||
t => _ViolationFilter(
|
||||
max_total = max_per_period,
|
||||
max_per_line = max_per_line,
|
||||
) for t in 1:T
|
||||
t => _ViolationFilter(max_total = max_per_period, max_per_line = max_per_line)
|
||||
for t = 1:T
|
||||
)
|
||||
|
||||
pre_flow::Array{Float64} = zeros(L, K) # pre_flow[lm, thread]
|
||||
@@ -92,35 +80,30 @@ function _find_violations(;
|
||||
pre_v::Array{Float64} = zeros(L, K) # pre_v[lm, thread]
|
||||
post_v::Array{Float64} = zeros(L, L, K) # post_v[lm, lc, thread]
|
||||
|
||||
normal_limits::Array{Float64,2} = [
|
||||
l.normal_flow_limit[t] + overflow[l.offset, t] for
|
||||
l in instance.lines, t in 1:T
|
||||
]
|
||||
normal_limits::Array{Float64,2} =
|
||||
[l.normal_flow_limit[t] + overflow[l.offset, t] for l in instance.lines, t = 1:T]
|
||||
|
||||
emergency_limits::Array{Float64,2} = [
|
||||
l.emergency_flow_limit[t] + overflow[l.offset, t] for
|
||||
l in instance.lines, t in 1:T
|
||||
]
|
||||
emergency_limits::Array{Float64,2} =
|
||||
[l.emergency_flow_limit[t] + overflow[l.offset, t] for l in instance.lines, t = 1:T]
|
||||
|
||||
is_vulnerable::Array{Bool} = zeros(Bool, L)
|
||||
for c in instance.contingencies
|
||||
is_vulnerable[c.lines[1].offset] = true
|
||||
end
|
||||
|
||||
@threads for t in 1:T
|
||||
@threads for t = 1:T
|
||||
k = threadid()
|
||||
|
||||
# Pre-contingency flows
|
||||
pre_flow[:, k] = isf * net_injections[:, t]
|
||||
|
||||
# Post-contingency flows
|
||||
for lc in 1:L, lm in 1:L
|
||||
post_flow[lm, lc, k] =
|
||||
pre_flow[lm, k] + pre_flow[lc, k] * lodf[lm, lc]
|
||||
for lc = 1:L, lm = 1:L
|
||||
post_flow[lm, lc, k] = pre_flow[lm, k] + pre_flow[lc, k] * lodf[lm, lc]
|
||||
end
|
||||
|
||||
# Pre-contingency violations
|
||||
for lm in 1:L
|
||||
for lm = 1:L
|
||||
pre_v[lm, k] = max(
|
||||
0.0,
|
||||
pre_flow[lm, k] - normal_limits[lm, t],
|
||||
@@ -129,7 +112,7 @@ function _find_violations(;
|
||||
end
|
||||
|
||||
# Post-contingency violations
|
||||
for lc in 1:L, lm in 1:L
|
||||
for lc = 1:L, lm = 1:L
|
||||
post_v[lm, lc, k] = max(
|
||||
0.0,
|
||||
post_flow[lm, lc, k] - emergency_limits[lm, t],
|
||||
@@ -138,7 +121,7 @@ function _find_violations(;
|
||||
end
|
||||
|
||||
# Offer pre-contingency violations
|
||||
for lm in 1:L
|
||||
for lm = 1:L
|
||||
if pre_v[lm, k] > 1e-5
|
||||
_offer(
|
||||
filters[t],
|
||||
@@ -153,7 +136,7 @@ function _find_violations(;
|
||||
end
|
||||
|
||||
# Offer post-contingency violations
|
||||
for lm in 1:L, lc in 1:L
|
||||
for lm = 1:L, lc = 1:L
|
||||
if post_v[lm, lc, k] > 1e-5 && is_vulnerable[lc]
|
||||
_offer(
|
||||
filters[t],
|
||||
@@ -169,7 +152,7 @@ function _find_violations(;
|
||||
end
|
||||
|
||||
violations = _Violation[]
|
||||
for t in 1:instance.time
|
||||
for t = 1:instance.time
|
||||
append!(violations, _query(filters[t]))
|
||||
end
|
||||
|
||||
|
||||
@@ -27,10 +27,7 @@ function optimize!(model::JuMP.Model, method::XavQiuWanThi2019.Method)::Nothing
|
||||
@info "Time limit exceeded"
|
||||
break
|
||||
end
|
||||
@info @sprintf(
|
||||
"Setting MILP time limit to %.2f seconds",
|
||||
time_remaining
|
||||
)
|
||||
@info @sprintf("Setting MILP time limit to %.2f seconds", time_remaining)
|
||||
JuMP.set_time_limit_sec(model, time_remaining)
|
||||
@info "Solving MILP..."
|
||||
JuMP.optimize!(model)
|
||||
|
||||
@@ -6,43 +6,40 @@ function solution(model::JuMP.Model)::OrderedDict
|
||||
instance, T = model[:instance], model[:instance].time
|
||||
function timeseries(vars, collection)
|
||||
return OrderedDict(
|
||||
b.name => [round(value(vars[b.name, t]), digits = 5) for t in 1:T]
|
||||
for b in collection
|
||||
b.name => [round(value(vars[b.name, t]), digits = 5) for t = 1:T] for
|
||||
b in collection
|
||||
)
|
||||
end
|
||||
function production_cost(g)
|
||||
return [
|
||||
value(model[:is_on][g.name, t]) * g.min_power_cost[t] + sum(
|
||||
Float64[
|
||||
value(model[:segprod][g.name, t, k]) *
|
||||
g.cost_segments[k].cost[t] for
|
||||
k in 1:length(g.cost_segments)
|
||||
value(model[:segprod][g.name, t, k]) * g.cost_segments[k].cost[t] for
|
||||
k = 1:length(g.cost_segments)
|
||||
],
|
||||
) for t in 1:T
|
||||
) for t = 1:T
|
||||
]
|
||||
end
|
||||
function production(g)
|
||||
return [
|
||||
value(model[:is_on][g.name, t]) * g.min_power[t] + sum(
|
||||
Float64[
|
||||
value(model[:segprod][g.name, t, k]) for
|
||||
k in 1:length(g.cost_segments)
|
||||
value(model[:segprod][g.name, t, k]) for k = 1:length(g.cost_segments)
|
||||
],
|
||||
) for t in 1:T
|
||||
) for t = 1:T
|
||||
]
|
||||
end
|
||||
function startup_cost(g)
|
||||
S = length(g.startup_categories)
|
||||
return [
|
||||
sum(
|
||||
g.startup_categories[s].cost *
|
||||
value(model[:startup][g.name, t, s]) for s in 1:S
|
||||
) for t in 1:T
|
||||
g.startup_categories[s].cost * value(model[:startup][g.name, t, s]) for
|
||||
s = 1:S
|
||||
) for t = 1:T
|
||||
]
|
||||
end
|
||||
sol = OrderedDict()
|
||||
sol["Production (MW)"] =
|
||||
OrderedDict(g.name => production(g) for g in instance.units)
|
||||
sol["Production (MW)"] = OrderedDict(g.name => production(g) for g in instance.units)
|
||||
sol["Production cost (\$)"] =
|
||||
OrderedDict(g.name => production_cost(g) for g in instance.units)
|
||||
sol["Startup cost (\$)"] =
|
||||
@@ -54,21 +51,19 @@ function solution(model::JuMP.Model)::OrderedDict
|
||||
instance.reserves.dwflexiramp != zeros(T)
|
||||
# Report flexiramp solutions only if either of the up-flexiramp and
|
||||
# down-flexiramp requirements is not a default array of zeros
|
||||
sol["Up-flexiramp (MW)"] =
|
||||
timeseries(model[:upflexiramp], instance.units)
|
||||
sol["Up-flexiramp (MW)"] = timeseries(model[:upflexiramp], instance.units)
|
||||
sol["Up-flexiramp shortfall (MW)"] = OrderedDict(
|
||||
t =>
|
||||
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
||||
round(value(model[:upflexiramp_shortfall][t]), digits = 5) :
|
||||
0.0 for t in 1:instance.time
|
||||
round(value(model[:upflexiramp_shortfall][t]), digits = 5) : 0.0 for
|
||||
t = 1:instance.time
|
||||
)
|
||||
sol["Down-flexiramp (MW)"] =
|
||||
timeseries(model[:dwflexiramp], instance.units)
|
||||
sol["Down-flexiramp (MW)"] = timeseries(model[:dwflexiramp], instance.units)
|
||||
sol["Down-flexiramp shortfall (MW)"] = OrderedDict(
|
||||
t =>
|
||||
(instance.flexiramp_shortfall_penalty[t] >= 0) ?
|
||||
round(value(model[:dwflexiramp_shortfall][t]), digits = 5) :
|
||||
0.0 for t in 1:instance.time
|
||||
round(value(model[:dwflexiramp_shortfall][t]), digits = 5) : 0.0 for
|
||||
t = 1:instance.time
|
||||
)
|
||||
else
|
||||
# Report spinning reserve solutions only if both up-flexiramp and
|
||||
@@ -77,12 +72,11 @@ function solution(model::JuMP.Model)::OrderedDict
|
||||
sol["Reserve shortfall (MW)"] = OrderedDict(
|
||||
t =>
|
||||
(instance.shortfall_penalty[t] >= 0) ?
|
||||
round(value(model[:reserve_shortfall][t]), digits = 5) :
|
||||
0.0 for t in 1:instance.time
|
||||
round(value(model[:reserve_shortfall][t]), digits = 5) : 0.0 for
|
||||
t = 1:instance.time
|
||||
)
|
||||
end
|
||||
sol["Net injection (MW)"] =
|
||||
timeseries(model[:net_injection], instance.buses)
|
||||
sol["Net injection (MW)"] = timeseries(model[:net_injection], instance.buses)
|
||||
sol["Load curtail (MW)"] = timeseries(model[:curtail], instance.buses)
|
||||
if !isempty(instance.lines)
|
||||
sol["Line overflow (MW)"] = timeseries(model[:overflow], instance.lines)
|
||||
|
||||
@@ -6,16 +6,10 @@ 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 t in 1:T
|
||||
for t = 1:T
|
||||
JuMP.set_start_value(is_on[g.name, t], solution["Is on"][g.name][t])
|
||||
JuMP.set_start_value(
|
||||
switch_on[g.name, t],
|
||||
solution["Switch on"][g.name][t],
|
||||
)
|
||||
JuMP.set_start_value(
|
||||
switch_off[g.name, t],
|
||||
solution["Switch off"][g.name][t],
|
||||
)
|
||||
JuMP.set_start_value(switch_on[g.name, t], solution["Switch on"][g.name][t])
|
||||
JuMP.set_start_value(switch_off[g.name, t], solution["Switch off"][g.name][t])
|
||||
end
|
||||
end
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user