|
|
@ -22,7 +22,7 @@ function Violation(;
|
|
|
|
monitored_line::TransmissionLine,
|
|
|
|
monitored_line::TransmissionLine,
|
|
|
|
outage_line::Union{TransmissionLine, Nothing},
|
|
|
|
outage_line::Union{TransmissionLine, Nothing},
|
|
|
|
amount::Float64,
|
|
|
|
amount::Float64,
|
|
|
|
) :: Violation
|
|
|
|
)::Violation
|
|
|
|
return Violation(time, monitored_line, outage_line, amount)
|
|
|
|
return Violation(time, monitored_line, outage_line, amount)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
@ -42,7 +42,7 @@ function ViolationFilter(;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function offer(filter::ViolationFilter, v::Violation)::Nothing
|
|
|
|
function _offer(filter::ViolationFilter, v::Violation)::Nothing
|
|
|
|
if v.monitored_line.offset ∉ keys(filter.queues)
|
|
|
|
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
|
|
|
|
end
|
|
|
@ -59,7 +59,7 @@ function offer(filter::ViolationFilter, v::Violation)::Nothing
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function query(filter::ViolationFilter)::Array{Violation, 1}
|
|
|
|
function _query(filter::ViolationFilter)::Array{Violation, 1}
|
|
|
|
violations = Array{Violation,1}()
|
|
|
|
violations = Array{Violation,1}()
|
|
|
|
time_queue = PriorityQueue{Violation, Float64}()
|
|
|
|
time_queue = PriorityQueue{Violation, Float64}()
|
|
|
|
for l in keys(filter.queues)
|
|
|
|
for l in keys(filter.queues)
|
|
|
@ -85,31 +85,35 @@ end
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
function find_violations(instance::UnitCommitmentInstance,
|
|
|
|
function _find_violations(
|
|
|
|
net_injections::Array{Float64, 2};
|
|
|
|
instance::UnitCommitmentInstance,
|
|
|
|
isf::Array{Float64,2},
|
|
|
|
net_injections::Array{Float64, 2};
|
|
|
|
lodf::Array{Float64,2},
|
|
|
|
isf::Array{Float64,2},
|
|
|
|
max_per_line::Int = 1,
|
|
|
|
lodf::Array{Float64,2},
|
|
|
|
max_per_period::Int = 5,
|
|
|
|
max_per_line::Int = 1,
|
|
|
|
) :: Array{Violation, 1}
|
|
|
|
max_per_period::Int = 5,
|
|
|
|
|
|
|
|
)::Array{Violation, 1}
|
|
|
|
Find transmission constraint violations (both pre-contingency, as well as post-contingency).
|
|
|
|
|
|
|
|
|
|
|
|
Find transmission constraint violations (both pre-contingency, as well as
|
|
|
|
The argument `net_injection` should be a (B-1) x T matrix, where B is the number of buses
|
|
|
|
post-contingency).
|
|
|
|
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 `net_injection` should be a (B-1) x T matrix, where B is the
|
|
|
|
The argument `overflow` specifies how much flow above the transmission limits (in MW) is allowed.
|
|
|
|
number of buses and T is the number of time periods. The arguments `isf` and
|
|
|
|
It should be an L x T matrix, where L is the number of transmission lines.
|
|
|
|
`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(;
|
|
|
|
function _find_violations(
|
|
|
|
instance::UnitCommitmentInstance,
|
|
|
|
;
|
|
|
|
net_injections::Array{Float64, 2},
|
|
|
|
instance::UnitCommitmentInstance,
|
|
|
|
overflow::Array{Float64, 2},
|
|
|
|
net_injections::Array{Float64, 2},
|
|
|
|
isf::Array{Float64,2},
|
|
|
|
overflow::Array{Float64, 2},
|
|
|
|
lodf::Array{Float64,2},
|
|
|
|
isf::Array{Float64,2},
|
|
|
|
max_per_line::Int = 1,
|
|
|
|
lodf::Array{Float64,2},
|
|
|
|
max_per_period::Int = 5,
|
|
|
|
max_per_line::Int = 1,
|
|
|
|
)::Array{Violation, 1}
|
|
|
|
max_per_period::Int = 5,
|
|
|
|
|
|
|
|
)::Array{Violation, 1}
|
|
|
|
|
|
|
|
|
|
|
|
B = length(instance.buses) - 1
|
|
|
|
B = length(instance.buses) - 1
|
|
|
|
L = length(instance.lines)
|
|
|
|
L = length(instance.lines)
|
|
|
@ -120,20 +124,28 @@ function find_violations(;
|
|
|
|
size(isf) == (L, B) || error("isf has incorrect size")
|
|
|
|
size(isf) == (L, B) || error("isf has incorrect size")
|
|
|
|
size(lodf) == (L, L) || error("lodf has incorrect size")
|
|
|
|
size(lodf) == (L, L) || error("lodf has incorrect size")
|
|
|
|
|
|
|
|
|
|
|
|
filters = Dict(t => ViolationFilter(max_total=max_per_period,
|
|
|
|
filters = Dict(
|
|
|
|
max_per_line=max_per_line)
|
|
|
|
t => ViolationFilter(
|
|
|
|
for t in 1:T)
|
|
|
|
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]
|
|
|
|
pre_flow::Array{Float64} = zeros(L, K) # pre_flow[lm, thread]
|
|
|
|
post_flow::Array{Float64} = zeros(L, L, K) # post_flow[lm, lc, 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]
|
|
|
|
pre_v::Array{Float64} = zeros(L, K) # pre_v[lm, thread]
|
|
|
|
post_v::Array{Float64} = zeros(L, L, K) # post_v[lm, lc, 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]
|
|
|
|
normal_limits::Array{Float64,2} = [
|
|
|
|
for l in instance.lines, t in 1:T]
|
|
|
|
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]
|
|
|
|
emergency_limits::Array{Float64,2} = [
|
|
|
|
for l in instance.lines, t in 1:T]
|
|
|
|
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)
|
|
|
|
is_vulnerable::Array{Bool} = zeros(Bool, L)
|
|
|
|
for c in instance.contingencies
|
|
|
|
for c in instance.contingencies
|
|
|
@ -153,46 +165,57 @@ function find_violations(;
|
|
|
|
|
|
|
|
|
|
|
|
# Pre-contingency violations
|
|
|
|
# Pre-contingency violations
|
|
|
|
for lm in 1:L
|
|
|
|
for lm in 1:L
|
|
|
|
pre_v[lm, k] = max(0.0,
|
|
|
|
pre_v[lm, k] = max(
|
|
|
|
pre_flow[lm, k] - normal_limits[lm, t],
|
|
|
|
0.0,
|
|
|
|
- pre_flow[lm, k] - normal_limits[lm, t])
|
|
|
|
pre_flow[lm, k] - normal_limits[lm, t],
|
|
|
|
|
|
|
|
- pre_flow[lm, k] - normal_limits[lm, t],
|
|
|
|
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Post-contingency violations
|
|
|
|
# Post-contingency violations
|
|
|
|
for lc in 1:L, lm in 1:L
|
|
|
|
for lc in 1:L, lm in 1:L
|
|
|
|
post_v[lm, lc, k] = max(0.0,
|
|
|
|
post_v[lm, lc, k] = max(
|
|
|
|
post_flow[lm, lc, k] - emergency_limits[lm, t],
|
|
|
|
0.0,
|
|
|
|
- post_flow[lm, lc, k] - emergency_limits[lm, t])
|
|
|
|
post_flow[lm, lc, k] - emergency_limits[lm, t],
|
|
|
|
|
|
|
|
- post_flow[lm, lc, k] - emergency_limits[lm, t],
|
|
|
|
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Offer pre-contingency violations
|
|
|
|
# Offer pre-contingency violations
|
|
|
|
for lm in 1:L
|
|
|
|
for lm in 1:L
|
|
|
|
if pre_v[lm, k] > 1e-5
|
|
|
|
if pre_v[lm, k] > 1e-5
|
|
|
|
offer(filters[t], Violation(time=t,
|
|
|
|
_offer(
|
|
|
|
monitored_line=instance.lines[lm],
|
|
|
|
filters[t],
|
|
|
|
outage_line=nothing,
|
|
|
|
Violation(
|
|
|
|
amount=pre_v[lm, k]))
|
|
|
|
time=t,
|
|
|
|
|
|
|
|
monitored_line=instance.lines[lm],
|
|
|
|
|
|
|
|
outage_line=nothing,
|
|
|
|
|
|
|
|
amount=pre_v[lm, k],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Offer post-contingency violations
|
|
|
|
# Offer post-contingency violations
|
|
|
|
for lm in 1:L, lc in 1:L
|
|
|
|
for lm in 1:L, lc in 1:L
|
|
|
|
if post_v[lm, lc, k] > 1e-5 && is_vulnerable[lc]
|
|
|
|
if post_v[lm, lc, k] > 1e-5 && is_vulnerable[lc]
|
|
|
|
offer(filters[t], Violation(time=t,
|
|
|
|
_offer(
|
|
|
|
monitored_line=instance.lines[lm],
|
|
|
|
filters[t],
|
|
|
|
outage_line=instance.lines[lc],
|
|
|
|
Violation(
|
|
|
|
amount=post_v[lm, lc, k]))
|
|
|
|
time=t,
|
|
|
|
|
|
|
|
monitored_line=instance.lines[lm],
|
|
|
|
|
|
|
|
outage_line=instance.lines[lc],
|
|
|
|
|
|
|
|
amount=post_v[lm, lc, k],
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
violations = Violation[]
|
|
|
|
violations = Violation[]
|
|
|
|
for t in 1:instance.time
|
|
|
|
for t in 1:instance.time
|
|
|
|
append!(violations, query(filters[t]))
|
|
|
|
append!(violations, _query(filters[t]))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
return violations
|
|
|
|
return violations
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export Violation, ViolationFilter, offer, query, find_violations
|
|
|
|
|