mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 08:18:51 -06:00
Rename internal methods to _something; reformat code
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Sub-hourly unit commitment
|
- Sub-hourly unit commitment
|
||||||
- Added function `UnitCommitment.write(filename, solution)` to simplify saving the solution to a file
|
- Added function `UnitCommitment.write(filename, solution)`
|
||||||
- Added mathematical formulation to the documentation
|
- Added mathematical formulation to the documentation
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
@@ -18,7 +18,8 @@
|
|||||||
- `model.isf` becomes `model[:isf]`
|
- `model.isf` becomes `model[:isf]`
|
||||||
- `model.lodf` becomes `model[:lodf]`
|
- `model.lodf` becomes `model[:lodf]`
|
||||||
- The function `UnitCommitment.get_solution` has been renamed to `UnitCommitment.solution`
|
- The function `UnitCommitment.get_solution` has been renamed to `UnitCommitment.solution`
|
||||||
- The function `UnitCommitment.fix!(instance)`, which attempts to repair an invalid instance, has been renamed to `UnitCommitment.repair!(instance)`
|
- All function that do not appear in the documentation have been renamed to `_something`.
|
||||||
|
These functions are not part of the public API and may change without notice.
|
||||||
|
|
||||||
## [0.1.1] - 2020-11-16
|
## [0.1.1] - 2020-11-16
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ using Logging
|
|||||||
using Printf
|
using Printf
|
||||||
using LinearAlgebra
|
using LinearAlgebra
|
||||||
|
|
||||||
|
UnitCommitment._setup_logger()
|
||||||
|
|
||||||
function main()
|
function main()
|
||||||
basename, suffix = split(ARGS[1], ".")
|
basename, suffix = split(ARGS[1], ".")
|
||||||
solution_filename = "results/$basename.$suffix.sol.json"
|
solution_filename = "results/$basename.$suffix.sol.json"
|
||||||
@@ -18,7 +20,6 @@ function main()
|
|||||||
time_limit = 60 * 20
|
time_limit = 60 * 20
|
||||||
|
|
||||||
BLAS.set_num_threads(4)
|
BLAS.set_num_threads(4)
|
||||||
global_logger(TimeLogger(initial_time = time()))
|
|
||||||
|
|
||||||
total_time = @elapsed begin
|
total_time = @elapsed begin
|
||||||
@info "Reading: $basename"
|
@info "Reading: $basename"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
using DataStructures, JSON, GZip
|
using DataStructures, JSON, GZip
|
||||||
|
|
||||||
function read_json(path::String)::OrderedDict
|
function _read_json(path::String)::OrderedDict
|
||||||
if endswith(path, ".gz")
|
if endswith(path, ".gz")
|
||||||
file = GZip.gzopen(path)
|
file = GZip.gzopen(path)
|
||||||
else
|
else
|
||||||
@@ -13,8 +13,8 @@ function read_json(path::String)::OrderedDict
|
|||||||
return JSON.parse(file, dicttype=()->DefaultOrderedDict(nothing))
|
return JSON.parse(file, dicttype=()->DefaultOrderedDict(nothing))
|
||||||
end
|
end
|
||||||
|
|
||||||
function read_egret_solution(path::String)::OrderedDict
|
function _read_egret_solution(path::String)::OrderedDict
|
||||||
egret = read_json(path)
|
egret = _read_json(path)
|
||||||
T = length(egret["system"]["time_keys"])
|
T = length(egret["system"]["time_keys"])
|
||||||
|
|
||||||
solution = OrderedDict()
|
solution = OrderedDict()
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ Generates feasible initial conditions for the given instance, by constructing
|
|||||||
and solving a single-period mixed-integer optimization problem, using the given
|
and solving a single-period mixed-integer optimization problem, using the given
|
||||||
optimizer. The instance is modified in-place.
|
optimizer. The instance is modified in-place.
|
||||||
"""
|
"""
|
||||||
function generate_initial_conditions!(instance::UnitCommitmentInstance,
|
function generate_initial_conditions!(
|
||||||
optimizer)
|
instance::UnitCommitmentInstance,
|
||||||
|
optimizer,
|
||||||
|
)::Nothing
|
||||||
G = instance.units
|
G = instance.units
|
||||||
B = instance.buses
|
B = instance.buses
|
||||||
t = 1
|
t = 1
|
||||||
@@ -73,4 +75,5 @@ function generate_initial_conditions!(instance::UnitCommitmentInstance,
|
|||||||
g.initial_status = -24
|
g.initial_status = -24
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
using Printf
|
using Printf
|
||||||
using JSON
|
using JSON
|
||||||
using DataStructures
|
using DataStructures
|
||||||
|
using GZip
|
||||||
import Base: getindex, time
|
import Base: getindex, time
|
||||||
import GZip
|
|
||||||
|
|
||||||
|
|
||||||
mutable struct Bus
|
mutable struct Bus
|
||||||
@@ -116,18 +116,19 @@ end
|
|||||||
|
|
||||||
function read(path::AbstractString)::UnitCommitmentInstance
|
function read(path::AbstractString)::UnitCommitmentInstance
|
||||||
if endswith(path, ".gz")
|
if endswith(path, ".gz")
|
||||||
return read(GZip.gzopen(path))
|
return _read(gzopen(path))
|
||||||
else
|
else
|
||||||
return read(open(path))
|
return _read(open(path))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function read(file::IO)::UnitCommitmentInstance
|
function _read(file::IO)::UnitCommitmentInstance
|
||||||
return from_json(JSON.parse(file, dicttype=()->DefaultOrderedDict(nothing)))
|
return _from_json(JSON.parse(file, dicttype=()->DefaultOrderedDict(nothing)))
|
||||||
end
|
end
|
||||||
|
|
||||||
function from_json(json; repair=true)
|
|
||||||
|
function _from_json(json; repair=true)
|
||||||
units = Unit[]
|
units = Unit[]
|
||||||
buses = Bus[]
|
buses = Bus[]
|
||||||
contingencies = Contingency[]
|
contingencies = Contingency[]
|
||||||
@@ -160,16 +161,20 @@ function from_json(json; repair=true)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Read parameters
|
# Read parameters
|
||||||
power_balance_penalty = timeseries(json["Parameters"]["Power balance penalty (\$/MW)"],
|
power_balance_penalty = timeseries(
|
||||||
default=[1000.0 for t in 1:T])
|
json["Parameters"]["Power balance penalty (\$/MW)"],
|
||||||
|
default=[1000.0 for t in 1:T],
|
||||||
|
)
|
||||||
|
|
||||||
# Read buses
|
# Read buses
|
||||||
for (bus_name, dict) in json["Buses"]
|
for (bus_name, dict) in json["Buses"]
|
||||||
bus = Bus(bus_name,
|
bus = Bus(
|
||||||
|
bus_name,
|
||||||
length(buses),
|
length(buses),
|
||||||
timeseries(dict["Load (MW)"]),
|
timeseries(dict["Load (MW)"]),
|
||||||
Unit[],
|
Unit[],
|
||||||
PriceSensitiveLoad[])
|
PriceSensitiveLoad[],
|
||||||
|
)
|
||||||
name_to_bus[bus_name] = bus
|
name_to_bus[bus_name] = bus
|
||||||
push!(buses, bus)
|
push!(buses, bus)
|
||||||
end
|
end
|
||||||
@@ -251,25 +256,35 @@ function from_json(json; repair=true)
|
|||||||
# Read reserves
|
# Read reserves
|
||||||
reserves = Reserves(zeros(T))
|
reserves = Reserves(zeros(T))
|
||||||
if "Reserves" in keys(json)
|
if "Reserves" in keys(json)
|
||||||
reserves.spinning = timeseries(json["Reserves"]["Spinning (MW)"],
|
reserves.spinning = timeseries(
|
||||||
default=zeros(T))
|
json["Reserves"]["Spinning (MW)"],
|
||||||
|
default=zeros(T),
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Read transmission lines
|
# Read transmission lines
|
||||||
if "Transmission lines" in keys(json)
|
if "Transmission lines" in keys(json)
|
||||||
for (line_name, dict) in json["Transmission lines"]
|
for (line_name, dict) in json["Transmission lines"]
|
||||||
line = TransmissionLine(line_name,
|
line = TransmissionLine(
|
||||||
|
line_name,
|
||||||
length(lines) + 1,
|
length(lines) + 1,
|
||||||
name_to_bus[dict["Source bus"]],
|
name_to_bus[dict["Source bus"]],
|
||||||
name_to_bus[dict["Target bus"]],
|
name_to_bus[dict["Target bus"]],
|
||||||
scalar(dict["Reactance (ohms)"]),
|
scalar(dict["Reactance (ohms)"]),
|
||||||
scalar(dict["Susceptance (S)"]),
|
scalar(dict["Susceptance (S)"]),
|
||||||
timeseries(dict["Normal flow limit (MW)"],
|
timeseries(
|
||||||
default=[1e8 for t in 1:T]),
|
dict["Normal flow limit (MW)"],
|
||||||
timeseries(dict["Emergency flow limit (MW)"],
|
default=[1e8 for t in 1:T],
|
||||||
default=[1e8 for t in 1:T]),
|
),
|
||||||
timeseries(dict["Flow limit penalty (\$/MW)"],
|
timeseries(
|
||||||
default=[5000.0 for t in 1:T]))
|
dict["Emergency flow limit (MW)"],
|
||||||
|
default=[1e8 for t in 1:T],
|
||||||
|
),
|
||||||
|
timeseries(
|
||||||
|
dict["Flow limit penalty (\$/MW)"],
|
||||||
|
default=[5000.0 for t in 1:T],
|
||||||
|
),
|
||||||
|
)
|
||||||
name_to_line[line_name] = line
|
name_to_line[line_name] = line
|
||||||
push!(lines, line)
|
push!(lines, line)
|
||||||
end
|
end
|
||||||
@@ -295,7 +310,8 @@ function from_json(json; repair=true)
|
|||||||
if "Price-sensitive loads" in keys(json)
|
if "Price-sensitive loads" in keys(json)
|
||||||
for (load_name, dict) in json["Price-sensitive loads"]
|
for (load_name, dict) in json["Price-sensitive loads"]
|
||||||
bus = name_to_bus[dict["Bus"]]
|
bus = name_to_bus[dict["Bus"]]
|
||||||
load = PriceSensitiveLoad(load_name,
|
load = PriceSensitiveLoad(
|
||||||
|
load_name,
|
||||||
bus,
|
bus,
|
||||||
timeseries(dict["Demand (MW)"]),
|
timeseries(dict["Demand (MW)"]),
|
||||||
timeseries(dict["Revenue (\$/MW)"]),
|
timeseries(dict["Revenue (\$/MW)"]),
|
||||||
@@ -305,14 +321,16 @@ function from_json(json; repair=true)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
instance = UnitCommitmentInstance(T,
|
instance = UnitCommitmentInstance(
|
||||||
|
T,
|
||||||
power_balance_penalty,
|
power_balance_penalty,
|
||||||
units,
|
units,
|
||||||
buses,
|
buses,
|
||||||
lines,
|
lines,
|
||||||
reserves,
|
reserves,
|
||||||
contingencies,
|
contingencies,
|
||||||
loads)
|
loads,
|
||||||
|
)
|
||||||
if repair
|
if repair
|
||||||
UnitCommitment.repair!(instance)
|
UnitCommitment.repair!(instance)
|
||||||
end
|
end
|
||||||
@@ -335,7 +353,10 @@ Example
|
|||||||
modified = UnitCommitment.slice(instance, 1:2)
|
modified = UnitCommitment.slice(instance, 1:2)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
function slice(instance::UnitCommitmentInstance, range::UnitRange{Int})::UnitCommitmentInstance
|
function slice(
|
||||||
|
instance::UnitCommitmentInstance,
|
||||||
|
range::UnitRange{Int},
|
||||||
|
)::UnitCommitmentInstance
|
||||||
modified = deepcopy(instance)
|
modified = deepcopy(instance)
|
||||||
modified.time = length(range)
|
modified.time = length(range)
|
||||||
modified.power_balance_penalty = modified.power_balance_penalty[range]
|
modified.power_balance_penalty = modified.power_balance_penalty[range]
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ function handle_message(logger::TimeLogger,
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function setup_logger()
|
function _setup_logger()
|
||||||
initial_time = time()
|
initial_time = time()
|
||||||
global_logger(TimeLogger(initial_time=initial_time))
|
global_logger(TimeLogger(initial_time=initial_time))
|
||||||
end
|
end
|
||||||
|
|
||||||
export TimeLogger
|
|
||||||
18
src/model.jl
18
src/model.jl
@@ -50,7 +50,7 @@ function build_model(;
|
|||||||
if isf === nothing
|
if isf === nothing
|
||||||
@info "Computing injection shift factors..."
|
@info "Computing injection shift factors..."
|
||||||
time_isf = @elapsed begin
|
time_isf = @elapsed begin
|
||||||
isf = UnitCommitment.injection_shift_factors(
|
isf = UnitCommitment._injection_shift_factors(
|
||||||
lines=instance.lines,
|
lines=instance.lines,
|
||||||
buses=instance.buses,
|
buses=instance.buses,
|
||||||
)
|
)
|
||||||
@@ -59,7 +59,7 @@ function build_model(;
|
|||||||
|
|
||||||
@info "Computing line outage factors..."
|
@info "Computing line outage factors..."
|
||||||
time_lodf = @elapsed begin
|
time_lodf = @elapsed begin
|
||||||
lodf = UnitCommitment.line_outage_factors(
|
lodf = UnitCommitment._line_outage_factors(
|
||||||
lines=instance.lines,
|
lines=instance.lines,
|
||||||
buses=instance.buses,
|
buses=instance.buses,
|
||||||
isf=isf,
|
isf=isf,
|
||||||
@@ -439,7 +439,7 @@ function _build_reserve_eqs!(model::JuMP.Model)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function enforce_transmission(
|
function _enforce_transmission(
|
||||||
;
|
;
|
||||||
model::JuMP.Model,
|
model::JuMP.Model,
|
||||||
violation::Violation,
|
violation::Violation,
|
||||||
@@ -667,7 +667,7 @@ function optimize!(
|
|||||||
|
|
||||||
has_transmission || break
|
has_transmission || break
|
||||||
|
|
||||||
violations = find_violations(model)
|
violations = _find_violations(model)
|
||||||
if isempty(violations)
|
if isempty(violations)
|
||||||
@info "No violations found"
|
@info "No violations found"
|
||||||
if large_gap
|
if large_gap
|
||||||
@@ -677,7 +677,7 @@ function optimize!(
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
enforce_transmission(model, violations)
|
_enforce_transmission(model, violations)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -685,7 +685,7 @@ function optimize!(
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function find_violations(model::JuMP.Model)
|
function _find_violations(model::JuMP.Model)
|
||||||
instance = model[:instance]
|
instance = model[:instance]
|
||||||
net_injection = model[:net_injection]
|
net_injection = model[:net_injection]
|
||||||
overflow = model[:overflow]
|
overflow = model[:overflow]
|
||||||
@@ -702,7 +702,7 @@ function find_violations(model::JuMP.Model)
|
|||||||
value(overflow[lm.name, t])
|
value(overflow[lm.name, t])
|
||||||
for lm in instance.lines, t in 1:instance.time
|
for lm in instance.lines, t in 1:instance.time
|
||||||
]
|
]
|
||||||
violations = UnitCommitment.find_violations(
|
violations = UnitCommitment._find_violations(
|
||||||
instance=instance,
|
instance=instance,
|
||||||
net_injections=net_injection_values,
|
net_injections=net_injection_values,
|
||||||
overflow=overflow_values,
|
overflow=overflow_values,
|
||||||
@@ -715,12 +715,12 @@ function find_violations(model::JuMP.Model)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function enforce_transmission(
|
function _enforce_transmission(
|
||||||
model::JuMP.Model,
|
model::JuMP.Model,
|
||||||
violations::Vector{Violation},
|
violations::Vector{Violation},
|
||||||
)::Nothing
|
)::Nothing
|
||||||
for v in violations
|
for v in violations
|
||||||
enforce_transmission(
|
_enforce_transmission(
|
||||||
model=model,
|
model=model,
|
||||||
violation=v,
|
violation=v,
|
||||||
isf=model[:isf],
|
isf=model[:isf],
|
||||||
|
|||||||
@@ -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,23 +85,27 @@ end
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
function find_violations(instance::UnitCommitmentInstance,
|
function _find_violations(
|
||||||
|
instance::UnitCommitmentInstance,
|
||||||
net_injections::Array{Float64, 2};
|
net_injections::Array{Float64, 2};
|
||||||
isf::Array{Float64,2},
|
isf::Array{Float64,2},
|
||||||
lodf::Array{Float64,2},
|
lodf::Array{Float64,2},
|
||||||
max_per_line::Int = 1,
|
max_per_line::Int = 1,
|
||||||
max_per_period::Int = 5,
|
max_per_period::Int = 5,
|
||||||
) :: Array{Violation, 1}
|
)::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
|
||||||
|
post-contingency).
|
||||||
|
|
||||||
The argument `net_injection` should be a (B-1) x T matrix, where B is the number of buses
|
The argument `net_injection` should be a (B-1) x T matrix, where B is the
|
||||||
and T is the number of time periods. The arguments `isf` and `lodf` can be computed using
|
number of buses and T is the number of time periods. The arguments `isf` and
|
||||||
UnitCommitment.injection_shift_factors and UnitCommitment.line_outage_factors.
|
`lodf` can be computed using UnitCommitment.injection_shift_factors and
|
||||||
The argument `overflow` specifies how much flow above the transmission limits (in MW) is allowed.
|
UnitCommitment.line_outage_factors. The argument `overflow` specifies how much
|
||||||
It should be an L x T matrix, where L is the number of transmission lines.
|
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,
|
instance::UnitCommitmentInstance,
|
||||||
net_injections::Array{Float64, 2},
|
net_injections::Array{Float64, 2},
|
||||||
overflow::Array{Float64, 2},
|
overflow::Array{Float64, 2},
|
||||||
@@ -109,7 +113,7 @@ function find_violations(;
|
|||||||
lodf::Array{Float64,2},
|
lodf::Array{Float64,2},
|
||||||
max_per_line::Int = 1,
|
max_per_line::Int = 1,
|
||||||
max_per_period::Int = 5,
|
max_per_period::Int = 5,
|
||||||
)::Array{Violation, 1}
|
)::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(
|
||||||
|
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])
|
- 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(
|
||||||
|
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])
|
- 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(
|
||||||
|
filters[t],
|
||||||
|
Violation(
|
||||||
|
time=t,
|
||||||
monitored_line=instance.lines[lm],
|
monitored_line=instance.lines[lm],
|
||||||
outage_line=nothing,
|
outage_line=nothing,
|
||||||
amount=pre_v[lm, k]))
|
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(
|
||||||
|
filters[t],
|
||||||
|
Violation(
|
||||||
|
time=t,
|
||||||
monitored_line=instance.lines[lm],
|
monitored_line=instance.lines[lm],
|
||||||
outage_line=instance.lines[lc],
|
outage_line=instance.lines[lc],
|
||||||
amount=post_v[lm, lc, k]))
|
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
|
|
||||||
@@ -5,16 +5,17 @@
|
|||||||
using SparseArrays, Base.Threads, LinearAlgebra, JuMP
|
using SparseArrays, Base.Threads, LinearAlgebra, JuMP
|
||||||
|
|
||||||
"""
|
"""
|
||||||
injection_shift_factors(; buses, lines)
|
_injection_shift_factors(; buses, lines)
|
||||||
|
|
||||||
Returns a (B-1)xL matrix M, where B is the number of buses and L is the number of transmission
|
Returns a (B-1)xL matrix M, where B is the number of buses and L is the number
|
||||||
lines. For a given bus b and transmission line l, the entry M[l.offset, b.offset] indicates
|
of transmission lines. For a given bus b and transmission line l, the entry
|
||||||
the amount of power (in MW) that flows through transmission line l when 1 MW of power is
|
M[l.offset, b.offset] indicates the amount of power (in MW) that flows through
|
||||||
injected at the slack bus (the bus that has offset zero) and withdrawn from b.
|
transmission line l when 1 MW of power is injected at the slack bus (the bus
|
||||||
|
that has offset zero) and withdrawn from b.
|
||||||
"""
|
"""
|
||||||
function injection_shift_factors(; buses, lines)
|
function _injection_shift_factors(; buses::Array{Bus}, lines::Array{TransmissionLine})
|
||||||
susceptance = susceptance_matrix(lines)
|
susceptance = _susceptance_matrix(lines)
|
||||||
incidence = reduced_incidence_matrix(lines = lines, buses = buses)
|
incidence = _reduced_incidence_matrix(lines=lines, buses=buses)
|
||||||
laplacian = transpose(incidence) * susceptance * incidence
|
laplacian = transpose(incidence) * susceptance * incidence
|
||||||
isf = susceptance * incidence * inv(Array(laplacian))
|
isf = susceptance * incidence * inv(Array(laplacian))
|
||||||
return isf
|
return isf
|
||||||
@@ -22,14 +23,15 @@ end
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{TransmissionLine})
|
_reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{TransmissionLine})
|
||||||
|
|
||||||
Returns the incidence matrix for the network, with the column corresponding to the slack
|
Returns the incidence matrix for the network, with the column corresponding to
|
||||||
bus is removed. More precisely, returns a (B-1) x L matrix, where B is the number of buses
|
the slack bus is removed. More precisely, returns a (B-1) x L matrix, where B
|
||||||
and L is the number of lines. For each row, there is a 1 element and a -1 element, indicating
|
is the number of buses and L is the number of lines. For each row, there is a 1
|
||||||
the source and target buses, respectively, for that line.
|
element and a -1 element, indicating the source and target buses, respectively,
|
||||||
|
for that line.
|
||||||
"""
|
"""
|
||||||
function reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{TransmissionLine})
|
function _reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{TransmissionLine})
|
||||||
matrix = spzeros(Float64, length(lines), length(buses) - 1)
|
matrix = spzeros(Float64, length(lines), length(buses) - 1)
|
||||||
for line in lines
|
for line in lines
|
||||||
if line.source.offset > 0
|
if line.source.offset > 0
|
||||||
@@ -43,33 +45,37 @@ function reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{Transmission
|
|||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
susceptance_matrix(lines::Array{TransmissionLine})
|
_susceptance_matrix(lines::Array{TransmissionLine})
|
||||||
|
|
||||||
Returns a LxL diagonal matrix, where each diagonal entry is the susceptance of the
|
Returns a LxL diagonal matrix, where each diagonal entry is the susceptance of
|
||||||
corresponding transmission line.
|
the corresponding transmission line.
|
||||||
"""
|
"""
|
||||||
function susceptance_matrix(lines::Array{TransmissionLine})
|
function _susceptance_matrix(lines::Array{TransmissionLine})
|
||||||
return Diagonal([l.susceptance for l in lines])
|
return Diagonal([l.susceptance for l in lines])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
line_outage_factors(; buses, lines, isf)
|
_line_outage_factors(; buses, lines, isf)
|
||||||
|
|
||||||
Returns a LxL matrix containing the Line Outage Distribution Factors (LODFs) for the
|
Returns a LxL matrix containing the Line Outage Distribution Factors (LODFs)
|
||||||
given network. This matrix how does the pre-contingency flow change when each individual
|
for the given network. This matrix how does the pre-contingency flow change
|
||||||
transmission line is removed.
|
when each individual transmission line is removed.
|
||||||
"""
|
"""
|
||||||
function line_outage_factors(;
|
function _line_outage_factors(
|
||||||
|
;
|
||||||
buses::Array{Bus, 1},
|
buses::Array{Bus, 1},
|
||||||
lines::Array{TransmissionLine, 1},
|
lines::Array{TransmissionLine, 1},
|
||||||
isf::Array{Float64,2},
|
isf::Array{Float64,2},
|
||||||
) :: Array{Float64,2}
|
) :: Array{Float64,2}
|
||||||
|
|
||||||
n_lines, n_buses = size(isf)
|
n_lines, n_buses = size(isf)
|
||||||
incidence = Array(reduced_incidence_matrix(lines=lines,
|
incidence = Array(
|
||||||
buses=buses))
|
_reduced_incidence_matrix(
|
||||||
|
lines=lines,
|
||||||
|
buses=buses,
|
||||||
|
),
|
||||||
|
)
|
||||||
lodf::Array{Float64,2} = isf * transpose(incidence)
|
lodf::Array{Float64,2} = isf * transpose(incidence)
|
||||||
m, n = size(lodf)
|
m, n = size(lodf)
|
||||||
for i in 1:n
|
for i in 1:n
|
||||||
|
|||||||
@@ -10,14 +10,17 @@ using JuMP
|
|||||||
using MathOptInterface
|
using MathOptInterface
|
||||||
using SparseArrays
|
using SparseArrays
|
||||||
|
|
||||||
pkg = [:DataStructures,
|
pkg = [
|
||||||
|
:DataStructures,
|
||||||
:JSON,
|
:JSON,
|
||||||
:JuMP,
|
:JuMP,
|
||||||
:MathOptInterface,
|
:MathOptInterface,
|
||||||
:SparseArrays,
|
:SparseArrays,
|
||||||
]
|
]
|
||||||
|
|
||||||
@info "Building system image..."
|
@info "Building system image..."
|
||||||
create_sysimage(pkg,
|
create_sysimage(
|
||||||
|
pkg,
|
||||||
precompile_statements_file="build/precompile.jl",
|
precompile_statements_file="build/precompile.jl",
|
||||||
sysimage_path="build/sysimage.so")
|
sysimage_path="build/sysimage.so",
|
||||||
|
)
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ bin(x) = [xi > 0.5 for xi in x]
|
|||||||
"""
|
"""
|
||||||
repair!(instance)
|
repair!(instance)
|
||||||
|
|
||||||
Verifies that the given unit commitment instance is valid and automatically fixes
|
Verifies that the given unit commitment instance is valid and automatically
|
||||||
some validation errors if possible, issuing a warning for each error found.
|
fixes some validation errors if possible, issuing a warning for each error
|
||||||
If a validation error cannot be automatically fixed, issues an exception.
|
found. If a validation error cannot be automatically fixed, issues an
|
||||||
|
exception.
|
||||||
|
|
||||||
Returns the number of validation errors found.
|
Returns the number of validation errors found.
|
||||||
"""
|
"""
|
||||||
@@ -86,16 +87,17 @@ Verifies that the given solution is feasible for the problem. If feasible,
|
|||||||
silently returns true. In infeasible, returns false and prints the validation
|
silently returns true. In infeasible, returns false and prints the validation
|
||||||
errors to the screen.
|
errors to the screen.
|
||||||
|
|
||||||
This function is implemented independently from the optimization model in `model.jl`, and
|
This function is implemented independently from the optimization model in
|
||||||
therefore can be used to verify that the model is indeed producing valid solutions. It
|
`model.jl`, and therefore can be used to verify that the model is indeed
|
||||||
can also be used to verify the solutions produced by other optimization packages.
|
producing valid solutions. It can also be used to verify the solutions produced
|
||||||
|
by other optimization packages.
|
||||||
"""
|
"""
|
||||||
function validate(instance::UnitCommitmentInstance,
|
function validate(instance::UnitCommitmentInstance,
|
||||||
solution::Union{Dict,OrderedDict};
|
solution::Union{Dict,OrderedDict};
|
||||||
)::Bool
|
)::Bool
|
||||||
err_count = 0
|
err_count = 0
|
||||||
err_count += validate_units(instance, solution)
|
err_count += _validate_units(instance, solution)
|
||||||
err_count += validate_reserve_and_demand(instance, solution)
|
err_count += _validate_reserve_and_demand(instance, solution)
|
||||||
|
|
||||||
if err_count > 0
|
if err_count > 0
|
||||||
@error "Found $err_count validation errors"
|
@error "Found $err_count validation errors"
|
||||||
@@ -106,7 +108,7 @@ function validate(instance::UnitCommitmentInstance,
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function validate_units(instance, solution; tol=0.01)
|
function _validate_units(instance, solution; tol=0.01)
|
||||||
err_count = 0
|
err_count = 0
|
||||||
|
|
||||||
for unit in instance.units
|
for unit in instance.units
|
||||||
@@ -300,7 +302,7 @@ function validate_units(instance, solution; tol=0.01)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function validate_reserve_and_demand(instance, solution, tol=0.01)
|
function _validate_reserve_and_demand(instance, solution, tol=0.01)
|
||||||
err_count = 0
|
err_count = 0
|
||||||
for t in 1:instance.time
|
for t in 1:instance.time
|
||||||
load_curtail = 0
|
load_curtail = 0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using UnitCommitment
|
|||||||
|
|
||||||
@testset "convert" begin
|
@testset "convert" begin
|
||||||
@testset "EGRET solution" begin
|
@testset "EGRET solution" begin
|
||||||
solution = UnitCommitment.read_egret_solution("fixtures/egret_output.json.gz")
|
solution = UnitCommitment._read_egret_solution("fixtures/egret_output.json.gz")
|
||||||
for attr in ["Is on", "Production (MW)", "Production cost (\$)"]
|
for attr in ["Is on", "Production (MW)", "Production cost (\$)"]
|
||||||
@test attr in keys(solution)
|
@test attr in keys(solution)
|
||||||
@test "115_STEAM_1" in keys(solution[attr])
|
@test "115_STEAM_1" in keys(solution[attr])
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
using Test
|
using Test
|
||||||
using UnitCommitment
|
using UnitCommitment
|
||||||
|
|
||||||
UnitCommitment.setup_logger()
|
UnitCommitment._setup_logger()
|
||||||
|
|
||||||
@testset "UnitCommitment" begin
|
@testset "UnitCommitment" begin
|
||||||
include("instance_test.jl")
|
include("instance_test.jl")
|
||||||
|
|||||||
@@ -3,51 +3,83 @@
|
|||||||
# Released under the modified BSD license. See COPYING.md for more details.
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
using UnitCommitment, Test, LinearAlgebra
|
using UnitCommitment, Test, LinearAlgebra
|
||||||
|
import UnitCommitment: Violation, _offer, _query
|
||||||
|
|
||||||
@testset "Screening" begin
|
@testset "Screening" begin
|
||||||
@testset "Violation filter" begin
|
@testset "Violation filter" begin
|
||||||
instance = UnitCommitment.read_benchmark("test/case14")
|
instance = UnitCommitment.read_benchmark("test/case14")
|
||||||
filter = ViolationFilter(max_per_line=1, max_total=2)
|
filter = UnitCommitment.ViolationFilter(max_per_line=1, max_total=2)
|
||||||
|
|
||||||
offer(filter, Violation(time=1,
|
_offer(
|
||||||
|
filter,
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[1],
|
monitored_line=instance.lines[1],
|
||||||
outage_line=nothing,
|
outage_line=nothing,
|
||||||
amount=100.))
|
amount=100.,
|
||||||
|
),
|
||||||
offer(filter, Violation(time=1,
|
)
|
||||||
|
_offer(
|
||||||
|
filter,
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[1],
|
monitored_line=instance.lines[1],
|
||||||
outage_line=instance.lines[1],
|
outage_line=instance.lines[1],
|
||||||
amount=300.))
|
amount=300.,
|
||||||
|
),
|
||||||
offer(filter, Violation(time=1,
|
)
|
||||||
|
_offer(
|
||||||
|
filter,
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[1],
|
monitored_line=instance.lines[1],
|
||||||
outage_line=instance.lines[5],
|
outage_line=instance.lines[5],
|
||||||
amount=500.))
|
amount=500.,
|
||||||
|
),
|
||||||
offer(filter, Violation(time=1,
|
)
|
||||||
|
_offer(
|
||||||
|
filter,
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[1],
|
monitored_line=instance.lines[1],
|
||||||
outage_line=instance.lines[4],
|
outage_line=instance.lines[4],
|
||||||
amount=400.))
|
amount=400.,
|
||||||
|
),
|
||||||
offer(filter, Violation(time=1,
|
)
|
||||||
|
_offer(
|
||||||
|
filter,
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[2],
|
monitored_line=instance.lines[2],
|
||||||
outage_line=instance.lines[1],
|
outage_line=instance.lines[1],
|
||||||
amount=200.))
|
amount=200.,
|
||||||
|
),
|
||||||
offer(filter, Violation(time=1,
|
)
|
||||||
|
_offer(
|
||||||
|
filter,
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[2],
|
monitored_line=instance.lines[2],
|
||||||
outage_line=instance.lines[8],
|
outage_line=instance.lines[8],
|
||||||
amount=100.))
|
amount=100.,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
actual = query(filter)
|
actual = _query(filter)
|
||||||
expected = [Violation(time=1,
|
expected = [
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[2],
|
monitored_line=instance.lines[2],
|
||||||
outage_line=instance.lines[1],
|
outage_line=instance.lines[1],
|
||||||
amount=200.),
|
amount=200.,
|
||||||
Violation(time=1,
|
),
|
||||||
|
Violation(
|
||||||
|
time=1,
|
||||||
monitored_line=instance.lines[1],
|
monitored_line=instance.lines[1],
|
||||||
outage_line=instance.lines[5],
|
outage_line=instance.lines[5],
|
||||||
amount=500.)]
|
amount=500.,
|
||||||
|
),
|
||||||
|
]
|
||||||
@test actual == expected
|
@test actual == expected
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -57,19 +89,24 @@ using UnitCommitment, Test, LinearAlgebra
|
|||||||
line.normal_flow_limit[t] = 1.0
|
line.normal_flow_limit[t] = 1.0
|
||||||
line.emergency_flow_limit[t] = 1.0
|
line.emergency_flow_limit[t] = 1.0
|
||||||
end
|
end
|
||||||
isf = UnitCommitment.injection_shift_factors(lines=instance.lines,
|
isf = UnitCommitment._injection_shift_factors(
|
||||||
buses=instance.buses)
|
lines=instance.lines,
|
||||||
lodf = UnitCommitment.line_outage_factors(lines=instance.lines,
|
|
||||||
buses=instance.buses,
|
buses=instance.buses,
|
||||||
isf=isf)
|
)
|
||||||
|
lodf = UnitCommitment._line_outage_factors(
|
||||||
|
lines=instance.lines,
|
||||||
|
buses=instance.buses,
|
||||||
|
isf=isf,
|
||||||
|
)
|
||||||
inj = [1000.0 for b in 1:13, t in 1:instance.time]
|
inj = [1000.0 for b in 1:13, t in 1:instance.time]
|
||||||
overflow = [0.0 for l in instance.lines, t in 1:instance.time]
|
overflow = [0.0 for l in instance.lines, t in 1:instance.time]
|
||||||
violations = UnitCommitment.find_violations(instance=instance,
|
violations = UnitCommitment._find_violations(
|
||||||
|
instance=instance,
|
||||||
net_injections=inj,
|
net_injections=inj,
|
||||||
overflow=overflow,
|
overflow=overflow,
|
||||||
isf=isf,
|
isf=isf,
|
||||||
lodf=lodf)
|
lodf=lodf,
|
||||||
|
)
|
||||||
@test length(violations) == 20
|
@test length(violations) == 20
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -7,7 +7,7 @@ using UnitCommitment, Test, LinearAlgebra
|
|||||||
@testset "Sensitivity" begin
|
@testset "Sensitivity" begin
|
||||||
@testset "Susceptance matrix" begin
|
@testset "Susceptance matrix" begin
|
||||||
instance = UnitCommitment.read_benchmark("test/case14")
|
instance = UnitCommitment.read_benchmark("test/case14")
|
||||||
actual = UnitCommitment.susceptance_matrix(instance.lines)
|
actual = UnitCommitment._susceptance_matrix(instance.lines)
|
||||||
@test size(actual) == (20, 20)
|
@test size(actual) == (20, 20)
|
||||||
expected = Diagonal([29.5, 7.83, 8.82, 9.9, 10.04,
|
expected = Diagonal([29.5, 7.83, 8.82, 9.9, 10.04,
|
||||||
10.2, 41.45, 8.35, 3.14, 6.93,
|
10.2, 41.45, 8.35, 3.14, 6.93,
|
||||||
@@ -18,8 +18,10 @@ using UnitCommitment, Test, LinearAlgebra
|
|||||||
|
|
||||||
@testset "Reduced incidence matrix" begin
|
@testset "Reduced incidence matrix" begin
|
||||||
instance = UnitCommitment.read_benchmark("test/case14")
|
instance = UnitCommitment.read_benchmark("test/case14")
|
||||||
actual = UnitCommitment.reduced_incidence_matrix(lines=instance.lines,
|
actual = UnitCommitment._reduced_incidence_matrix(
|
||||||
buses=instance.buses)
|
lines=instance.lines,
|
||||||
|
buses=instance.buses,
|
||||||
|
)
|
||||||
@test size(actual) == (20, 13)
|
@test size(actual) == (20, 13)
|
||||||
@test actual[1, 1] == -1.0
|
@test actual[1, 1] == -1.0
|
||||||
@test actual[3, 1] == 1.0
|
@test actual[3, 1] == 1.0
|
||||||
@@ -63,8 +65,10 @@ using UnitCommitment, Test, LinearAlgebra
|
|||||||
|
|
||||||
@testset "Injection Shift Factors (ISF)" begin
|
@testset "Injection Shift Factors (ISF)" begin
|
||||||
instance = UnitCommitment.read_benchmark("test/case14")
|
instance = UnitCommitment.read_benchmark("test/case14")
|
||||||
actual = UnitCommitment.injection_shift_factors(lines=instance.lines,
|
actual = UnitCommitment._injection_shift_factors(
|
||||||
buses=instance.buses)
|
lines=instance.lines,
|
||||||
|
buses=instance.buses,
|
||||||
|
)
|
||||||
@test size(actual) == (20, 13)
|
@test size(actual) == (20, 13)
|
||||||
@test round.(actual, digits=2) == [
|
@test round.(actual, digits=2) == [
|
||||||
-0.84 -0.75 -0.67 -0.61 -0.63 -0.66 -0.66 -0.65 -0.65 -0.64 -0.63 -0.63 -0.64;
|
-0.84 -0.75 -0.67 -0.61 -0.63 -0.66 -0.66 -0.65 -0.65 -0.64 -0.63 -0.63 -0.64;
|
||||||
@@ -91,17 +95,23 @@ using UnitCommitment, Test, LinearAlgebra
|
|||||||
|
|
||||||
@testset "Line Outage Distribution Factors (LODF)" begin
|
@testset "Line Outage Distribution Factors (LODF)" begin
|
||||||
instance = UnitCommitment.read_benchmark("test/case14")
|
instance = UnitCommitment.read_benchmark("test/case14")
|
||||||
isf_before = UnitCommitment.injection_shift_factors(lines=instance.lines,
|
isf_before = UnitCommitment._injection_shift_factors(
|
||||||
buses=instance.buses)
|
lines=instance.lines,
|
||||||
lodf = UnitCommitment.line_outage_factors(lines=instance.lines,
|
|
||||||
buses=instance.buses,
|
buses=instance.buses,
|
||||||
isf=isf_before)
|
)
|
||||||
|
lodf = UnitCommitment._line_outage_factors(
|
||||||
|
lines=instance.lines,
|
||||||
|
buses=instance.buses,
|
||||||
|
isf=isf_before,
|
||||||
|
)
|
||||||
for contingency in instance.contingencies
|
for contingency in instance.contingencies
|
||||||
for lc in contingency.lines
|
for lc in contingency.lines
|
||||||
prev_susceptance = lc.susceptance
|
prev_susceptance = lc.susceptance
|
||||||
lc.susceptance = 0.0
|
lc.susceptance = 0.0
|
||||||
isf_after = UnitCommitment.injection_shift_factors(lines=instance.lines,
|
isf_after = UnitCommitment._injection_shift_factors(
|
||||||
buses=instance.buses)
|
lines=instance.lines,
|
||||||
|
buses=instance.buses,
|
||||||
|
)
|
||||||
lc.susceptance = prev_susceptance
|
lc.susceptance = prev_susceptance
|
||||||
for lm in instance.lines
|
for lm in instance.lines
|
||||||
expected = isf_after[lm.offset, :]
|
expected = isf_after[lm.offset, :]
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ parse_case14() = JSON.parse(GZip.gzopen("../instances/test/case14.json.gz"),
|
|||||||
json = parse_case14()
|
json = parse_case14()
|
||||||
json["Generators"]["g1"]["Production cost curve (MW)"] = [100, 150, 200]
|
json["Generators"]["g1"]["Production cost curve (MW)"] = [100, 150, 200]
|
||||||
json["Generators"]["g1"]["Production cost curve (\$)"] = [10, 25, 30]
|
json["Generators"]["g1"]["Production cost curve (\$)"] = [10, 25, 30]
|
||||||
instance = UnitCommitment.from_json(json, repair=false)
|
instance = UnitCommitment._from_json(json, repair=false)
|
||||||
@test UnitCommitment.repair!(instance) == 4
|
@test UnitCommitment.repair!(instance) == 4
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ parse_case14() = JSON.parse(GZip.gzopen("../instances/test/case14.json.gz"),
|
|||||||
json["Generators"]["g1"]["Production cost curve (MW)"] = [100, 150]
|
json["Generators"]["g1"]["Production cost curve (MW)"] = [100, 150]
|
||||||
json["Generators"]["g1"]["Production cost curve (\$)"] = [100, 150]
|
json["Generators"]["g1"]["Production cost curve (\$)"] = [100, 150]
|
||||||
json["Generators"]["g1"]["Startup limit (MW)"] = 80
|
json["Generators"]["g1"]["Startup limit (MW)"] = 80
|
||||||
instance = UnitCommitment.from_json(json, repair=false)
|
instance = UnitCommitment._from_json(json, repair=false)
|
||||||
@test UnitCommitment.repair!(instance) == 1
|
@test UnitCommitment.repair!(instance) == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ parse_case14() = JSON.parse(GZip.gzopen("../instances/test/case14.json.gz"),
|
|||||||
json = parse_case14()
|
json = parse_case14()
|
||||||
json["Generators"]["g1"]["Startup costs (\$)"] = [300, 200, 100]
|
json["Generators"]["g1"]["Startup costs (\$)"] = [300, 200, 100]
|
||||||
json["Generators"]["g1"]["Startup delays (h)"] = [8, 4, 2]
|
json["Generators"]["g1"]["Startup delays (h)"] = [8, 4, 2]
|
||||||
instance = UnitCommitment.from_json(json, repair=false)
|
instance = UnitCommitment._from_json(json, repair=false)
|
||||||
@test UnitCommitment.repair!(instance) == 4
|
@test UnitCommitment.repair!(instance) == 4
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user