You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
UnitCommitment.jl/src/solution/methods/XavQiuWanThi19/find.jl

178 lines
5.5 KiB

# UnitCommitment.jl: Optimization Package for Security-Constrained Unit Commitment
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
import Base.Threads: @threads
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]
length(instance.buses) > 1 || return []
violations = []
@info "Verifying transmission limits..."
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
]
violations = UnitCommitment._find_violations(
instance = instance,
net_injections = net_injection_values,
overflow = overflow_values,
isf = model[:isf],
lodf = model[:lodf],
max_per_line = max_per_line,
max_per_period = max_per_period,
)
end
@info @sprintf(
"Verified transmission limits in %.2f seconds",
time_screening
)
return violations
end
"""
function _find_violations(
instance::UnitCommitmentInstance,
net_injections::Array{Float64, 2};
isf::Array{Float64,2},
lodf::Array{Float64,2},
max_per_line::Int,
max_per_period::Int,
)::Array{_Violation, 1}
Find transmission constraint violations (both pre-contingency, as well as
post-contingency).
The argument `net_injection` should be a (B-1) x T matrix, where B is the
number of buses and T is the number of time periods. The arguments `isf` and
`lodf` can be computed using UnitCommitment.injection_shift_factors and
UnitCommitment.line_outage_factors. The argument `overflow` specifies how much
flow above the transmission limits (in MW) is allowed. It should be an L x T
matrix, where L is the number of transmission lines.
"""
function _find_violations(;
instance::UnitCommitmentInstance,
net_injections::Array{Float64,2},
overflow::Array{Float64,2},
isf::Array{Float64,2},
lodf::Array{Float64,2},
max_per_line::Int,
max_per_period::Int,
)::Array{_Violation,1}
B = length(instance.buses) - 1
L = length(instance.lines)
T = instance.time
K = nthreads()
size(net_injections) == (B, T) || error("net_injections has incorrect size")
size(isf) == (L, B) || error("isf has incorrect size")
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
)
pre_flow::Array{Float64} = zeros(L, K) # pre_flow[lm, thread]
post_flow::Array{Float64} = zeros(L, L, K) # post_flow[lm, lc, thread]
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
]
emergency_limits::Array{Float64,2} = [
l.emergency_flow_limit[t] + overflow[l.offset, t] for
l in instance.lines, t in 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
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]
end
# Pre-contingency violations
for lm in 1:L
pre_v[lm, k] = max(
0.0,
pre_flow[lm, k] - normal_limits[lm, t],
-pre_flow[lm, k] - normal_limits[lm, t],
)
end
# Post-contingency violations
for lc in 1:L, lm in 1:L
post_v[lm, lc, k] = max(
0.0,
post_flow[lm, lc, k] - emergency_limits[lm, t],
-post_flow[lm, lc, k] - emergency_limits[lm, t],
)
end
# Offer pre-contingency violations
for lm in 1:L
if pre_v[lm, k] > 1e-5
_offer(
filters[t],
_Violation(
time = t,
monitored_line = instance.lines[lm],
outage_line = nothing,
amount = pre_v[lm, k],
),
)
end
end
# Offer post-contingency violations
for lm in 1:L, lc in 1:L
if post_v[lm, lc, k] > 1e-5 && is_vulnerable[lc]
_offer(
filters[t],
_Violation(
time = t,
monitored_line = instance.lines[lm],
outage_line = instance.lines[lc],
amount = post_v[lm, lc, k],
),
)
end
end
end
violations = _Violation[]
for t in 1:instance.time
append!(violations, _query(filters[t]))
end
return violations
end