Rename internal methods to _something; reformat code

bugfix/formulations
Alinson S. Xavier 4 years ago
parent 11514b5de8
commit 7eb1019410

@ -4,7 +4,7 @@
### Added
- 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
### Changed
@ -18,7 +18,8 @@
- `model.isf` becomes `model[:isf]`
- `model.lodf` becomes `model[:lodf]`
- 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

@ -10,6 +10,8 @@ using Logging
using Printf
using LinearAlgebra
UnitCommitment._setup_logger()
function main()
basename, suffix = split(ARGS[1], ".")
solution_filename = "results/$basename.$suffix.sol.json"
@ -18,7 +20,6 @@ function main()
time_limit = 60 * 20
BLAS.set_num_threads(4)
global_logger(TimeLogger(initial_time = time()))
total_time = @elapsed begin
@info "Reading: $basename"

@ -4,7 +4,7 @@
using DataStructures, JSON, GZip
function read_json(path::String)::OrderedDict
function _read_json(path::String)::OrderedDict
if endswith(path, ".gz")
file = GZip.gzopen(path)
else
@ -13,8 +13,8 @@ function read_json(path::String)::OrderedDict
return JSON.parse(file, dicttype=()->DefaultOrderedDict(nothing))
end
function read_egret_solution(path::String)::OrderedDict
egret = read_json(path)
function _read_egret_solution(path::String)::OrderedDict
egret = _read_json(path)
T = length(egret["system"]["time_keys"])
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
optimizer. The instance is modified in-place.
"""
function generate_initial_conditions!(instance::UnitCommitmentInstance,
optimizer)
function generate_initial_conditions!(
instance::UnitCommitmentInstance,
optimizer,
)::Nothing
G = instance.units
B = instance.buses
t = 1
@ -73,4 +75,5 @@ function generate_initial_conditions!(instance::UnitCommitmentInstance,
g.initial_status = -24
end
end
return
end

@ -5,8 +5,8 @@
using Printf
using JSON
using DataStructures
using GZip
import Base: getindex, time
import GZip
mutable struct Bus
@ -116,18 +116,19 @@ end
function read(path::AbstractString)::UnitCommitmentInstance
if endswith(path, ".gz")
return read(GZip.gzopen(path))
return _read(gzopen(path))
else
return read(open(path))
return _read(open(path))
end
end
function read(file::IO)::UnitCommitmentInstance
return from_json(JSON.parse(file, dicttype=()->DefaultOrderedDict(nothing)))
function _read(file::IO)::UnitCommitmentInstance
return _from_json(JSON.parse(file, dicttype=()->DefaultOrderedDict(nothing)))
end
function from_json(json; repair=true)
function _from_json(json; repair=true)
units = Unit[]
buses = Bus[]
contingencies = Contingency[]
@ -160,16 +161,20 @@ function from_json(json; repair=true)
end
# Read parameters
power_balance_penalty = timeseries(json["Parameters"]["Power balance penalty (\$/MW)"],
default=[1000.0 for t in 1:T])
power_balance_penalty = timeseries(
json["Parameters"]["Power balance penalty (\$/MW)"],
default=[1000.0 for t in 1:T],
)
# Read buses
for (bus_name, dict) in json["Buses"]
bus = Bus(bus_name,
bus = Bus(
bus_name,
length(buses),
timeseries(dict["Load (MW)"]),
Unit[],
PriceSensitiveLoad[])
PriceSensitiveLoad[],
)
name_to_bus[bus_name] = bus
push!(buses, bus)
end
@ -251,25 +256,35 @@ function from_json(json; repair=true)
# Read reserves
reserves = Reserves(zeros(T))
if "Reserves" in keys(json)
reserves.spinning = timeseries(json["Reserves"]["Spinning (MW)"],
default=zeros(T))
reserves.spinning = timeseries(
json["Reserves"]["Spinning (MW)"],
default=zeros(T),
)
end
# Read transmission lines
if "Transmission lines" in keys(json)
for (line_name, dict) in json["Transmission lines"]
line = TransmissionLine(line_name,
line = TransmissionLine(
line_name,
length(lines) + 1,
name_to_bus[dict["Source bus"]],
name_to_bus[dict["Target bus"]],
scalar(dict["Reactance (ohms)"]),
scalar(dict["Susceptance (S)"]),
timeseries(dict["Normal flow limit (MW)"],
default=[1e8 for t in 1:T]),
timeseries(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]))
timeseries(
dict["Normal flow limit (MW)"],
default=[1e8 for t in 1:T],
),
timeseries(
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
push!(lines, line)
end
@ -295,7 +310,8 @@ function from_json(json; repair=true)
if "Price-sensitive loads" in keys(json)
for (load_name, dict) in json["Price-sensitive loads"]
bus = name_to_bus[dict["Bus"]]
load = PriceSensitiveLoad(load_name,
load = PriceSensitiveLoad(
load_name,
bus,
timeseries(dict["Demand (MW)"]),
timeseries(dict["Revenue (\$/MW)"]),
@ -305,14 +321,16 @@ function from_json(json; repair=true)
end
end
instance = UnitCommitmentInstance(T,
instance = UnitCommitmentInstance(
T,
power_balance_penalty,
units,
buses,
lines,
reserves,
contingencies,
loads)
loads,
)
if repair
UnitCommitment.repair!(instance)
end
@ -335,7 +353,10 @@ Example
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.time = length(range)
modified.power_balance_penalty = modified.power_balance_penalty[range]

@ -56,9 +56,7 @@ function handle_message(logger::TimeLogger,
end
end
function setup_logger()
function _setup_logger()
initial_time = time()
global_logger(TimeLogger(initial_time=initial_time))
end
export TimeLogger

@ -50,7 +50,7 @@ function build_model(;
if isf === nothing
@info "Computing injection shift factors..."
time_isf = @elapsed begin
isf = UnitCommitment.injection_shift_factors(
isf = UnitCommitment._injection_shift_factors(
lines=instance.lines,
buses=instance.buses,
)
@ -59,7 +59,7 @@ function build_model(;
@info "Computing line outage factors..."
time_lodf = @elapsed begin
lodf = UnitCommitment.line_outage_factors(
lodf = UnitCommitment._line_outage_factors(
lines=instance.lines,
buses=instance.buses,
isf=isf,
@ -439,7 +439,7 @@ function _build_reserve_eqs!(model::JuMP.Model)
end
function enforce_transmission(
function _enforce_transmission(
;
model::JuMP.Model,
violation::Violation,
@ -667,7 +667,7 @@ function optimize!(
has_transmission || break
violations = find_violations(model)
violations = _find_violations(model)
if isempty(violations)
@info "No violations found"
if large_gap
@ -677,7 +677,7 @@ function optimize!(
break
end
else
enforce_transmission(model, violations)
_enforce_transmission(model, violations)
end
end
@ -685,7 +685,7 @@ function optimize!(
end
function find_violations(model::JuMP.Model)
function _find_violations(model::JuMP.Model)
instance = model[:instance]
net_injection = model[:net_injection]
overflow = model[:overflow]
@ -702,7 +702,7 @@ function find_violations(model::JuMP.Model)
value(overflow[lm.name, t])
for lm in instance.lines, t in 1:instance.time
]
violations = UnitCommitment.find_violations(
violations = UnitCommitment._find_violations(
instance=instance,
net_injections=net_injection_values,
overflow=overflow_values,
@ -715,12 +715,12 @@ function find_violations(model::JuMP.Model)
end
function enforce_transmission(
function _enforce_transmission(
model::JuMP.Model,
violations::Vector{Violation},
)::Nothing
for v in violations
enforce_transmission(
_enforce_transmission(
model=model,
violation=v,
isf=model[:isf],

@ -42,7 +42,7 @@ function ViolationFilter(;
end
function offer(filter::ViolationFilter, v::Violation)::Nothing
function _offer(filter::ViolationFilter, v::Violation)::Nothing
if v.monitored_line.offset keys(filter.queues)
filter.queues[v.monitored_line.offset] = PriorityQueue{Violation, Float64}()
end
@ -59,7 +59,7 @@ function offer(filter::ViolationFilter, v::Violation)::Nothing
end
function query(filter::ViolationFilter)::Array{Violation, 1}
function _query(filter::ViolationFilter)::Array{Violation, 1}
violations = Array{Violation,1}()
time_queue = PriorityQueue{Violation, Float64}()
for l in keys(filter.queues)
@ -85,7 +85,8 @@ end
"""
function find_violations(instance::UnitCommitmentInstance,
function _find_violations(
instance::UnitCommitmentInstance,
net_injections::Array{Float64, 2};
isf::Array{Float64,2},
lodf::Array{Float64,2},
@ -93,15 +94,18 @@ end
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
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.
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(;
function _find_violations(
;
instance::UnitCommitmentInstance,
net_injections::Array{Float64, 2},
overflow::Array{Float64, 2},
@ -120,20 +124,28 @@ function find_violations(;
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)
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]
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]
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
@ -153,46 +165,57 @@ function find_violations(;
# Pre-contingency violations
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],
)
end
# Post-contingency violations
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],
)
end
# Offer pre-contingency violations
for lm in 1:L
if pre_v[lm, k] > 1e-5
offer(filters[t], Violation(time=t,
_offer(
filters[t],
Violation(
time=t,
monitored_line=instance.lines[lm],
outage_line=nothing,
amount=pre_v[lm, k]))
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,
_offer(
filters[t],
Violation(
time=t,
monitored_line=instance.lines[lm],
outage_line=instance.lines[lc],
amount=post_v[lm, lc, k]))
amount=post_v[lm, lc, k],
),
)
end
end
end
violations = Violation[]
for t in 1:instance.time
append!(violations, query(filters[t]))
append!(violations, _query(filters[t]))
end
return violations
end
export Violation, ViolationFilter, offer, query, find_violations

@ -5,16 +5,17 @@
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
lines. For a given bus b and transmission line l, the entry M[l.offset, b.offset] indicates
the amount of power (in MW) that flows through transmission line l when 1 MW of power is
injected at the slack bus (the bus that has offset zero) and withdrawn from b.
Returns a (B-1)xL matrix M, where B is the number of buses and L is the number
of transmission lines. For a given bus b and transmission line l, the entry
M[l.offset, b.offset] indicates the amount of power (in MW) that flows through
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)
susceptance = susceptance_matrix(lines)
incidence = reduced_incidence_matrix(lines = lines, buses = buses)
function _injection_shift_factors(; buses::Array{Bus}, lines::Array{TransmissionLine})
susceptance = _susceptance_matrix(lines)
incidence = _reduced_incidence_matrix(lines=lines, buses=buses)
laplacian = transpose(incidence) * susceptance * incidence
isf = susceptance * incidence * inv(Array(laplacian))
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
bus is removed. More precisely, returns a (B-1) x L matrix, where B is the number of buses
and L is the number of lines. For each row, there is a 1 element and a -1 element, indicating
the source and target buses, respectively, for that line.
Returns the incidence matrix for the network, with the column corresponding to
the slack bus is removed. More precisely, returns a (B-1) x L matrix, where B
is the number of buses and L is the number of lines. For each row, there is a 1
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)
for line in lines
if line.source.offset > 0
@ -43,33 +45,37 @@ function reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{Transmission
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
corresponding transmission line.
Returns a LxL diagonal matrix, where each diagonal entry is the susceptance of
the corresponding transmission line.
"""
function susceptance_matrix(lines::Array{TransmissionLine})
function _susceptance_matrix(lines::Array{TransmissionLine})
return Diagonal([l.susceptance for l in lines])
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
given network. This matrix how does the pre-contingency flow change when each individual
transmission line is removed.
Returns a LxL matrix containing the Line Outage Distribution Factors (LODFs)
for the given network. This matrix how does the pre-contingency flow change
when each individual transmission line is removed.
"""
function line_outage_factors(;
function _line_outage_factors(
;
buses::Array{Bus, 1},
lines::Array{TransmissionLine, 1},
isf::Array{Float64,2},
) :: Array{Float64,2}
n_lines, n_buses = size(isf)
incidence = Array(reduced_incidence_matrix(lines=lines,
buses=buses))
incidence = Array(
_reduced_incidence_matrix(
lines=lines,
buses=buses,
),
)
lodf::Array{Float64,2} = isf * transpose(incidence)
m, n = size(lodf)
for i in 1:n

@ -10,7 +10,8 @@ using JuMP
using MathOptInterface
using SparseArrays
pkg = [:DataStructures,
pkg = [
:DataStructures,
:JSON,
:JuMP,
:MathOptInterface,
@ -18,6 +19,8 @@ pkg = [:DataStructures,
]
@info "Building system image..."
create_sysimage(pkg,
create_sysimage(
pkg,
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)
Verifies that the given unit commitment instance is valid and automatically fixes
some validation errors if possible, issuing a warning for each error found.
If a validation error cannot be automatically fixed, issues an exception.
Verifies that the given unit commitment instance is valid and automatically
fixes some validation errors if possible, issuing a warning for each error
found. If a validation error cannot be automatically fixed, issues an
exception.
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
errors to the screen.
This function is implemented independently from the optimization model in `model.jl`, and
therefore can be used to verify that the model is indeed producing valid solutions. It
can also be used to verify the solutions produced by other optimization packages.
This function is implemented independently from the optimization model in
`model.jl`, and therefore can be used to verify that the model is indeed
producing valid solutions. It can also be used to verify the solutions produced
by other optimization packages.
"""
function validate(instance::UnitCommitmentInstance,
solution::Union{Dict,OrderedDict};
)::Bool
err_count = 0
err_count += validate_units(instance, solution)
err_count += validate_reserve_and_demand(instance, solution)
err_count += _validate_units(instance, solution)
err_count += _validate_reserve_and_demand(instance, solution)
if err_count > 0
@error "Found $err_count validation errors"
@ -106,7 +108,7 @@ function validate(instance::UnitCommitmentInstance,
end
function validate_units(instance, solution; tol=0.01)
function _validate_units(instance, solution; tol=0.01)
err_count = 0
for unit in instance.units
@ -300,7 +302,7 @@ function validate_units(instance, solution; tol=0.01)
end
function validate_reserve_and_demand(instance, solution, tol=0.01)
function _validate_reserve_and_demand(instance, solution, tol=0.01)
err_count = 0
for t in 1:instance.time
load_curtail = 0

@ -6,7 +6,7 @@ using UnitCommitment
@testset "convert" 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 (\$)"]
@test attr in keys(solution)
@test "115_STEAM_1" in keys(solution[attr])

@ -5,7 +5,7 @@
using Test
using UnitCommitment
UnitCommitment.setup_logger()
UnitCommitment._setup_logger()
@testset "UnitCommitment" begin
include("instance_test.jl")

@ -3,51 +3,83 @@
# Released under the modified BSD license. See COPYING.md for more details.
using UnitCommitment, Test, LinearAlgebra
import UnitCommitment: Violation, _offer, _query
@testset "Screening" begin
@testset "Violation filter" begin
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],
outage_line=nothing,
amount=100.))
offer(filter, Violation(time=1,
amount=100.,
),
)
_offer(
filter,
Violation(
time=1,
monitored_line=instance.lines[1],
outage_line=instance.lines[1],
amount=300.))
offer(filter, Violation(time=1,
amount=300.,
),
)
_offer(
filter,
Violation(
time=1,
monitored_line=instance.lines[1],
outage_line=instance.lines[5],
amount=500.))
offer(filter, Violation(time=1,
amount=500.,
),
)
_offer(
filter,
Violation(
time=1,
monitored_line=instance.lines[1],
outage_line=instance.lines[4],
amount=400.))
offer(filter, Violation(time=1,
amount=400.,
),
)
_offer(
filter,
Violation(
time=1,
monitored_line=instance.lines[2],
outage_line=instance.lines[1],
amount=200.))
offer(filter, Violation(time=1,
amount=200.,
),
)
_offer(
filter,
Violation(
time=1,
monitored_line=instance.lines[2],
outage_line=instance.lines[8],
amount=100.))
amount=100.,
)
)
actual = query(filter)
expected = [Violation(time=1,
actual = _query(filter)
expected = [
Violation(
time=1,
monitored_line=instance.lines[2],
outage_line=instance.lines[1],
amount=200.),
Violation(time=1,
amount=200.,
),
Violation(
time=1,
monitored_line=instance.lines[1],
outage_line=instance.lines[5],
amount=500.)]
amount=500.,
),
]
@test actual == expected
end
@ -57,19 +89,24 @@ using UnitCommitment, Test, LinearAlgebra
line.normal_flow_limit[t] = 1.0
line.emergency_flow_limit[t] = 1.0
end
isf = UnitCommitment.injection_shift_factors(lines=instance.lines,
buses=instance.buses)
lodf = UnitCommitment.line_outage_factors(lines=instance.lines,
isf = UnitCommitment._injection_shift_factors(
lines=instance.lines,
buses=instance.buses,
)
lodf = UnitCommitment._line_outage_factors(
lines=instance.lines,
buses=instance.buses,
isf=isf)
isf=isf,
)
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]
violations = UnitCommitment.find_violations(instance=instance,
violations = UnitCommitment._find_violations(
instance=instance,
net_injections=inj,
overflow=overflow,
isf=isf,
lodf=lodf)
lodf=lodf,
)
@test length(violations) == 20
end
end

@ -7,7 +7,7 @@ using UnitCommitment, Test, LinearAlgebra
@testset "Sensitivity" begin
@testset "Susceptance matrix" begin
instance = UnitCommitment.read_benchmark("test/case14")
actual = UnitCommitment.susceptance_matrix(instance.lines)
actual = UnitCommitment._susceptance_matrix(instance.lines)
@test size(actual) == (20, 20)
expected = Diagonal([29.5, 7.83, 8.82, 9.9, 10.04,
10.2, 41.45, 8.35, 3.14, 6.93,
@ -18,8 +18,10 @@ using UnitCommitment, Test, LinearAlgebra
@testset "Reduced incidence matrix" begin
instance = UnitCommitment.read_benchmark("test/case14")
actual = UnitCommitment.reduced_incidence_matrix(lines=instance.lines,
buses=instance.buses)
actual = UnitCommitment._reduced_incidence_matrix(
lines=instance.lines,
buses=instance.buses,
)
@test size(actual) == (20, 13)
@test actual[1, 1] == -1.0
@test actual[3, 1] == 1.0
@ -63,8 +65,10 @@ using UnitCommitment, Test, LinearAlgebra
@testset "Injection Shift Factors (ISF)" begin
instance = UnitCommitment.read_benchmark("test/case14")
actual = UnitCommitment.injection_shift_factors(lines=instance.lines,
buses=instance.buses)
actual = UnitCommitment._injection_shift_factors(
lines=instance.lines,
buses=instance.buses,
)
@test size(actual) == (20, 13)
@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;
@ -91,17 +95,23 @@ using UnitCommitment, Test, LinearAlgebra
@testset "Line Outage Distribution Factors (LODF)" begin
instance = UnitCommitment.read_benchmark("test/case14")
isf_before = UnitCommitment.injection_shift_factors(lines=instance.lines,
buses=instance.buses)
lodf = UnitCommitment.line_outage_factors(lines=instance.lines,
isf_before = UnitCommitment._injection_shift_factors(
lines=instance.lines,
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 lc in contingency.lines
prev_susceptance = lc.susceptance
lc.susceptance = 0.0
isf_after = UnitCommitment.injection_shift_factors(lines=instance.lines,
buses=instance.buses)
isf_after = UnitCommitment._injection_shift_factors(
lines=instance.lines,
buses=instance.buses,
)
lc.susceptance = prev_susceptance
for lm in instance.lines
expected = isf_after[lm.offset, :]

@ -14,7 +14,7 @@ parse_case14() = JSON.parse(GZip.gzopen("../instances/test/case14.json.gz"),
json = parse_case14()
json["Generators"]["g1"]["Production cost curve (MW)"] = [100, 150, 200]
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
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 (\$)"] = [100, 150]
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
end
@ -31,7 +31,7 @@ parse_case14() = JSON.parse(GZip.gzopen("../instances/test/case14.json.gz"),
json = parse_case14()
json["Generators"]["g1"]["Startup costs (\$)"] = [300, 200, 100]
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
end

Loading…
Cancel
Save