pull/44/merge
Jun He 2 years ago committed by GitHub
commit 918caa47db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,6 +12,7 @@ An instance of the stochastic security-constrained unit commitment (SCUC) proble
* [Storage units](#Storage-units) * [Storage units](#Storage-units)
* [Price-sensitive loads](#Price-sensitive-loads) * [Price-sensitive loads](#Price-sensitive-loads)
* [Transmission lines](#Transmission-lines) * [Transmission lines](#Transmission-lines)
* [Interfaces](#Interfaces)
* [Reserves](#Reserves) * [Reserves](#Reserves)
* [Contingencies](#Contingencies) * [Contingencies](#Contingencies)
@ -283,7 +284,7 @@ This section describes the characteristics of transmission system, such as its t
| `Target bus` | Identifier of the bus where the transmission line reaches. | Required | No | Yes | `Target bus` | Identifier of the bus where the transmission line reaches. | Required | No | Yes
| `Susceptance (S)` | Susceptance of the transmission line (in siemens). | Required | No | Yes | `Susceptance (S)` | Susceptance of the transmission line (in siemens). | Required | No | Yes
| `Normal flow limit (MW)` | Maximum amount of power (in MW) allowed to flow through the line when the system is in its regular, fully-operational state. | `+inf` | Yes | Yes | `Normal flow limit (MW)` | Maximum amount of power (in MW) allowed to flow through the line when the system is in its regular, fully-operational state. | `+inf` | Yes | Yes
| `Emergency flow limit (MW)` | Maximum amount of power (in MW) allowed to flow through the line when the system is in degraded state (for example, after the failure of another transmission line). | `+inf` | Y | Yes | `Emergency flow limit (MW)` | Maximum amount of power (in MW) allowed to flow through the line when the system is in degraded state (for example, after the failure of another transmission line). | `+inf` | Yes | Yes
| `Flow limit penalty ($/MW)` | Penalty for violating the flow limits of the transmission line (in $/MW). This is charged per time step. For example, if there is a thermal violation of 1 MW for three time steps, then three times this amount will be charged. | `5000.0` | Yes | Yes | `Flow limit penalty ($/MW)` | Penalty for violating the flow limits of the transmission line (in $/MW). This is charged per time step. For example, if there is a thermal violation of 1 MW for three time steps, then three times this amount will be charged. | `5000.0` | Yes | Yes
#### Example #### Example
@ -303,6 +304,33 @@ This section describes the characteristics of transmission system, such as its t
} }
``` ```
### Interfaces
This section describes the characteristics of interfaces, such as its topology and the flow limits of each interface. An interface is a set of transmission lines that, when opened, split the network into different islands. A postive direction is pre-defined by the user between every 2 interfaces. The net flow through an interface is the sum of the flows through the positive lines minus the sum of the flows through the negative lines.
| Key | Description | Default | Time series? | Uncertain?
| :--------------------- | :----------------------------------------------- | ------- | :------------: | :---:
| `Outbound lines` | List of transmission lines flow out from a region, which is defined as the positve direction. May be omitted if no outbound lines available. | `[]` | No | Yes
| `Inbound lines` | List of transmission lines flow into a region, which is defined as the negative direction. May be omitted if no inbound lines available. | `[]` | No | Yes
| `Net flow upper limit (MW)` | Maximum net amount of power (in MW) allowed to flow through the interface. | `+inf` | Yes | Yes
| `Net flow lower limit (MW)` | Minimum net amount of power (in MW) allowed to flow through the interface. | `-inf` | Yes | Yes
| `Flow limit penalty ($/MW)` | Penalty for violating the flow limits of the interface (in $/MW). This is charged per time step. For example, if there is a thermal violation of 1 MW for three time steps, then three times this amount will be charged. | `5000.0` | Yes | Yes
#### Example
```json
{
"Interfaces": {
"ifc1": {
"Outbound lines": ["l2", "l3", "l5", "l7", "l8", "l9"],
"Inbound lines": ["l6"],
"Net flow upper limit (MW)": 2000,
"Net flow lower limit (MW)": -1500,
"Flow limit penalty ($/MW)": 9999.0
}
}
}
```
### Reserves ### Reserves

@ -37,6 +37,7 @@ include("model/formulations/base/system.jl")
include("model/formulations/base/unit.jl") include("model/formulations/base/unit.jl")
include("model/formulations/base/punit.jl") include("model/formulations/base/punit.jl")
include("model/formulations/base/storage.jl") include("model/formulations/base/storage.jl")
include("model/formulations/base/interface.jl")
include("model/formulations/CarArr2006/pwlcosts.jl") include("model/formulations/CarArr2006/pwlcosts.jl")
include("model/formulations/DamKucRajAta2016/ramp.jl") include("model/formulations/DamKucRajAta2016/ramp.jl")
include("model/formulations/Gar1962/pwlcosts.jl") include("model/formulations/Gar1962/pwlcosts.jl")

@ -137,6 +137,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
reserves = Reserve[] reserves = Reserve[]
profiled_units = ProfiledUnit[] profiled_units = ProfiledUnit[]
storage_units = StorageUnit[] storage_units = StorageUnit[]
interfaces = Interface[]
function scalar(x; default = nothing) function scalar(x; default = nothing)
x !== nothing || return default x !== nothing || return default
@ -452,6 +453,45 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
end end
end end
# Read interfaces
if "Interfaces" in keys(json)
for (int_name, dict) in json["Interfaces"]
outbound_lines = TransmissionLine[]
inbound_lines = TransmissionLine[]
if "Outbound lines" in keys(dict)
outbound_lines = [
name_to_line[l] for
l in scalar(dict["Outbound lines"], default = [])
]
end
if "Inbound lines" in keys(dict)
inbound_lines = [
name_to_line[l] for
l in scalar(dict["Inbound lines"], default = [])
]
end
interface = Interface(
int_name,
length(interfaces) + 1,
outbound_lines,
inbound_lines,
timeseries(
dict["Net flow upper limit (MW)"],
default = [1e8 for t in 1:T],
),
timeseries(
dict["Net flow lower limit (MW)"],
default = [-1e8 for t in 1:T],
),
timeseries(
dict["Flow limit penalty (\$/MW)"],
default = [5000.0 for t in 1:T],
),
)
push!(interfaces, interface)
end
end
scenario = UnitCommitmentScenario( scenario = UnitCommitmentScenario(
name = scenario_name, name = scenario_name,
probability = probability, probability = probability,
@ -474,8 +514,11 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
profiled_units = profiled_units, profiled_units = profiled_units,
storage_units_by_name = Dict(su.name => su for su in storage_units), storage_units_by_name = Dict(su.name => su for su in storage_units),
storage_units = storage_units, storage_units = storage_units,
interfaces_by_name = Dict(i.name => i for i in interfaces),
interfaces = interfaces,
isf = spzeros(Float64, length(lines), length(buses) - 1), isf = spzeros(Float64, length(lines), length(buses) - 1),
lodf = spzeros(Float64, length(lines), length(lines)), lodf = spzeros(Float64, length(lines), length(lines)),
interface_isf = spzeros(Float64, length(interfaces), length(buses) - 1),
) )
if repair if repair
UnitCommitment.repair!(scenario) UnitCommitment.repair!(scenario)

@ -103,6 +103,16 @@ mutable struct StorageUnit
max_ending_level::Float64 max_ending_level::Float64
end end
mutable struct Interface
name::String
offset::Int
outbound_lines::Vector{TransmissionLine}
inbound_lines::Vector{TransmissionLine}
net_flow_upper_limit::Vector{Float64}
net_flow_lower_limit::Vector{Float64}
flow_limit_penalty::Vector{Float64}
end
Base.@kwdef mutable struct UnitCommitmentScenario Base.@kwdef mutable struct UnitCommitmentScenario
buses_by_name::Dict{AbstractString,Bus} buses_by_name::Dict{AbstractString,Bus}
buses::Vector{Bus} buses::Vector{Bus}
@ -125,6 +135,9 @@ Base.@kwdef mutable struct UnitCommitmentScenario
thermal_units::Vector{ThermalUnit} thermal_units::Vector{ThermalUnit}
storage_units_by_name::Dict{AbstractString,StorageUnit} storage_units_by_name::Dict{AbstractString,StorageUnit}
storage_units::Vector{StorageUnit} storage_units::Vector{StorageUnit}
interfaces_by_name::Dict{AbstractString,Interface}
interfaces::Vector{Interface}
interface_isf::Array{Float64,2}
time::Int time::Int
time_step::Int time_step::Int
end end

@ -103,6 +103,9 @@ function build_model(;
_add_storage_unit!(model, su, sc) _add_storage_unit!(model, su, sc)
end end
_add_system_wide_eqs!(model, sc) _add_system_wide_eqs!(model, sc)
for ifc in sc.interfaces
_add_interface!(model, ifc, formulation.transmission, sc)
end
end end
@objective(model, Min, model[:obj]) @objective(model, Min, model[:obj])
end end

@ -0,0 +1,46 @@
# 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.
function _add_interface!(
model::JuMP.Model,
ifc::Interface,
f::ShiftFactorsFormulation,
sc::UnitCommitmentScenario,
)::Nothing
overflow = _init(model, :interface_overflow)
net_injection = _init(model, :net_injection)
for t in 1:model[:instance].time
# define the net flow variable
flow = @variable(model, base_name = "interface_flow[$(ifc.name),$t]")
# define the overflow variable
overflow[sc.name, ifc.name, t] = @variable(model, lower_bound = 0)
# constraints: lb - v <= flow <= ub + v
@constraint(
model,
flow <=
ifc.net_flow_upper_limit[t] + overflow[sc.name, ifc.name, t]
)
@constraint(
model,
-flow <=
-ifc.net_flow_lower_limit[t] + overflow[sc.name, ifc.name, t]
)
# constraint: flow value is calculated from the interface ISF matrix
@constraint(
model,
flow == sum(
net_injection[sc.name, b.name, t] *
sc.interface_isf[ifc.offset, b.offset] for
b in sc.buses if b.offset > 0
)
)
# make overflow part of the objective as a punishment term
add_to_expression!(
model[:obj],
overflow[sc.name, ifc.name, t],
ifc.flow_limit_penalty[t] * sc.probability,
)
end
return
end

@ -26,9 +26,11 @@ function _setup_transmission(
)::Nothing )::Nothing
isf = formulation.precomputed_isf isf = formulation.precomputed_isf
lodf = formulation.precomputed_lodf lodf = formulation.precomputed_lodf
interface_isf = nothing
if length(sc.buses) == 1 if length(sc.buses) == 1
isf = zeros(0, 0) isf = zeros(0, 0)
lodf = zeros(0, 0) lodf = zeros(0, 0)
interface_isf = zeros(0, 0)
elseif isf === nothing elseif isf === nothing
@info "Computing injection shift factors..." @info "Computing injection shift factors..."
time_isf = @elapsed begin time_isf = @elapsed begin
@ -36,6 +38,11 @@ function _setup_transmission(
buses = sc.buses, buses = sc.buses,
lines = sc.lines, lines = sc.lines,
) )
interface_isf =
UnitCommitment._interface_injection_shift_factors(
interfaces = sc.interfaces,
isf = isf,
)
end end
@info @sprintf("Computed ISF in %.2f seconds", time_isf) @info @sprintf("Computed ISF in %.2f seconds", time_isf)
@info "Computing line outage factors..." @info "Computing line outage factors..."
@ -53,9 +60,13 @@ function _setup_transmission(
formulation.lodf_cutoff formulation.lodf_cutoff
) )
isf[abs.(isf).<formulation.isf_cutoff] .= 0 isf[abs.(isf).<formulation.isf_cutoff] .= 0
interface_isf[abs.(interface_isf).<formulation.isf_cutoff] .= 0
lodf[abs.(lodf).<formulation.lodf_cutoff] .= 0 lodf[abs.(lodf).<formulation.lodf_cutoff] .= 0
end end
sc.isf = isf sc.isf = isf
sc.lodf = lodf sc.lodf = lodf
if interface_isf !== nothing
sc.interface_isf = round.(interface_isf, digits = 5)
end
return return
end end

@ -24,6 +24,29 @@ function _injection_shift_factors(;
return isf return isf
end end
"""
_interface_injection_shift_factors(; interfaces, isf)
Returns a Ix(B-1) matrix M, where B is the number of buses and I is the number
of interfaces. For a given bus b and interface ifc, the entry M[ifc.offset, b.offset]
indicates the amount of power (in MW) that net flows through transmission lines of
the interface ifc when 1 MW of power is injected at b and withdrawn from the
slack bus (the bus that has offset zero).
"""
function _interface_injection_shift_factors(;
interfaces::Array{Interface},
isf::Array{Float64,2},
)
interface_isf = zeros(Float64, length(interfaces), size(isf, 2))
for ifc in interfaces
outbound_lines = [l.offset for l in ifc.outbound_lines]
inbound_lines = [l.offset for l in ifc.inbound_lines]
interface_isf[ifc.offset, :] += sum(isf[outbound_lines, :], dims = 1)'
interface_isf[ifc.offset, :] -= sum(isf[inbound_lines, :], dims = 1)'
end
return interface_isf
end
""" """
_reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{TransmissionLine}) _reduced_incidence_matrix(; buses::Array{Bus}, lines::Array{TransmissionLine})

@ -85,9 +85,26 @@ function solution(model::JuMP.Model)::OrderedDict
sol[sc.name]["Load curtail (MW)"] = sol[sc.name]["Load curtail (MW)"] =
timeseries(model[:curtail], sc.buses, sc = sc) timeseries(model[:curtail], sc.buses, sc = sc)
end end
# get matrix of bus net injection (BxT)
bus_net_injection = [
value(model[:net_injection][sc.name, bus.name, t]) for
bus in sc.buses, t in 1:T
]
if !isempty(sc.lines) if !isempty(sc.lines)
sol[sc.name]["Line overflow (MW)"] = sol[sc.name]["Line overflow (MW)"] =
timeseries(model[:overflow], sc.lines, sc = sc) timeseries(model[:overflow], sc.lines, sc = sc)
# get the matrix of line flows (Lx(B-1))x((B-1)xT)=(LxT)
line_flows = sc.isf * bus_net_injection[2:end, :]
sol[sc.name]["Transmission line flow (MW)"] =
OrderedDict(l.name => line_flows[l.offset, :] for l in sc.lines)
end
if !isempty(sc.interfaces)
# get the matrix of interface flows (Ix(B-1))x((B-1)xT)=(IxT)
interface_flows = sc.interface_isf * bus_net_injection[2:end, :]
sol[sc.name]["Interface flow (MW)"] = OrderedDict(
ifc.name => interface_flows[ifc.offset, :] for
ifc in sc.interfaces
)
end end
if !isempty(sc.price_sensitive_loads) if !isempty(sc.price_sensitive_loads)
sol[sc.name]["Price-sensitive loads (MW)"] = sol[sc.name]["Price-sensitive loads (MW)"] =

@ -71,6 +71,11 @@ function slice(
su.min_discharge_rate = su.min_discharge_rate[range] su.min_discharge_rate = su.min_discharge_rate[range]
su.max_discharge_rate = su.max_discharge_rate[range] su.max_discharge_rate = su.max_discharge_rate[range]
end end
for ifc in sc.interfaces
ifc.net_flow_upper_limit = ifc.net_flow_upper_limit[range]
ifc.net_flow_lower_limit = ifc.net_flow_lower_limit[range]
ifc.flow_limit_penalty = ifc.flow_limit_penalty[range]
end
end end
return modified return modified
end end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -9,6 +9,8 @@ include("import/egret_test.jl")
include("instance/read_test.jl") include("instance/read_test.jl")
include("instance/migrate_test.jl") include("instance/migrate_test.jl")
include("model/formulations_test.jl") include("model/formulations_test.jl")
include("model/storage_optimization_test.jl")
include("model/interface_optimization_test.jl")
include("solution/methods/XavQiuWanThi19/filter_test.jl") include("solution/methods/XavQiuWanThi19/filter_test.jl")
include("solution/methods/XavQiuWanThi19/find_test.jl") include("solution/methods/XavQiuWanThi19/find_test.jl")
include("solution/methods/XavQiuWanThi19/sensitivity_test.jl") include("solution/methods/XavQiuWanThi19/sensitivity_test.jl")
@ -39,6 +41,8 @@ function runtests()
instance_read_test() instance_read_test()
instance_migrate_test() instance_migrate_test()
model_formulations_test() model_formulations_test()
storage_optimization_test()
interface_optimization_test()
solution_methods_XavQiuWanThi19_filter_test() solution_methods_XavQiuWanThi19_filter_test()
solution_methods_XavQiuWanThi19_find_test() solution_methods_XavQiuWanThi19_find_test()
solution_methods_XavQiuWanThi19_sensitivity_test() solution_methods_XavQiuWanThi19_sensitivity_test()

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, LinearAlgebra, Cbc, JuMP, JSON, GZip using UnitCommitment, LinearAlgebra, JuMP, JSON, GZip
function instance_migrate_test() function instance_migrate_test()
@testset "read v0.2" begin @testset "read v0.2" begin

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, LinearAlgebra, Cbc, JuMP, JSON, GZip using UnitCommitment, LinearAlgebra, JuMP, JSON, GZip
function instance_read_test() function instance_read_test()
@testset "read_benchmark" begin @testset "read_benchmark" begin
@ -224,4 +224,20 @@ function instance_read_test()
@test su4.simultaneous_charge_and_discharge == @test su4.simultaneous_charge_and_discharge ==
[false, false, true, true] [false, false, true, true]
end end
@testset "read_benchmark interface" begin
instance = UnitCommitment.read(fixture("case14-interface.json.gz"))
sc = instance.scenarios[1]
@test length(sc.interfaces) == 1
@test sc.interfaces_by_name["ifc1"].name == "ifc1"
ifc = sc.interfaces[1]
@test ifc.name == "ifc1"
@test ifc.offset == 1
@test length(ifc.outbound_lines) == 6
@test length(ifc.inbound_lines) == 1
@test ifc.net_flow_upper_limit == [2000 for t in 1:4]
@test ifc.net_flow_lower_limit == [-1500 for t in 1:4]
@test ifc.flow_limit_penalty == [9999.0 for t in 1:4]
end
end end

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, Cbc, HiGHS, JuMP using UnitCommitment, HiGHS, JuMP
import UnitCommitment: AELMP import UnitCommitment: AELMP
function lmp_aelmp_test() function lmp_aelmp_test()
@ -13,8 +13,8 @@ function lmp_aelmp_test()
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = instance, instance = instance,
optimizer = optimizer_with_attributes( optimizer = optimizer_with_attributes(
Cbc.Optimizer, HiGHS.Optimizer,
"logLevel" => 0, "log_to_console" => false,
), ),
variable_names = true, variable_names = true,
) )

@ -2,13 +2,16 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, Cbc, HiGHS, JuMP using UnitCommitment, HiGHS, JuMP
function solve_conventional_testcase(path::String) function solve_conventional_testcase(path::String)
instance = UnitCommitment.read(path) instance = UnitCommitment.read(path)
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = instance, instance = instance,
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0), optimizer = optimizer_with_attributes(
HiGHS.Optimizer,
"log_to_console" => false,
),
variable_names = true, variable_names = true,
) )
JuMP.set_silent(model) JuMP.set_silent(model)

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, Cbc, HiGHS, JuMP using UnitCommitment, HiGHS, JuMP
import UnitCommitment: MarketSettings import UnitCommitment: MarketSettings
function simple_market_test() function simple_market_test()
@ -20,8 +20,8 @@ function simple_market_test()
rt_paths, rt_paths,
MarketSettings(), # keep everything default MarketSettings(), # keep everything default
optimizer = optimizer_with_attributes( optimizer = optimizer_with_attributes(
Cbc.Optimizer, HiGHS.Optimizer,
"logLevel" => 0, "log_to_console" => false,
), ),
lp_optimizer = optimizer_with_attributes( lp_optimizer = optimizer_with_attributes(
HiGHS.Optimizer, HiGHS.Optimizer,
@ -52,8 +52,8 @@ function simple_market_test()
rt_paths, rt_paths,
MarketSettings(lmp_method = nothing), # no lmp MarketSettings(lmp_method = nothing), # no lmp
optimizer = optimizer_with_attributes( optimizer = optimizer_with_attributes(
Cbc.Optimizer, HiGHS.Optimizer,
"logLevel" => 0, "log_to_console" => false,
), ),
) )
@ -115,8 +115,8 @@ function stochastic_market_test()
rt_paths, rt_paths,
MarketSettings(), # keep everything default MarketSettings(), # keep everything default
optimizer = optimizer_with_attributes( optimizer = optimizer_with_attributes(
Cbc.Optimizer, HiGHS.Optimizer,
"logLevel" => 0, "log_to_console" => false,
), ),
lp_optimizer = optimizer_with_attributes( lp_optimizer = optimizer_with_attributes(
HiGHS.Optimizer, HiGHS.Optimizer,

@ -4,7 +4,7 @@
using UnitCommitment using UnitCommitment
using JuMP using JuMP
using Cbc using HiGHS
using JSON using JSON
import UnitCommitment: import UnitCommitment:
ArrCon2000, ArrCon2000,
@ -28,7 +28,7 @@ function _test(
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = instance, instance = instance,
formulation = formulation, formulation = formulation,
optimizer = Cbc.Optimizer, optimizer = HiGHS.Optimizer,
variable_names = true, variable_names = true,
) )
set_silent(model) set_silent(model)

@ -0,0 +1,40 @@
# 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.
using UnitCommitment
using JuMP
using HiGHS
using JSON
function interface_optimization_test()
@testset "interface_optimization" begin
# case3-interface: only outbounds
instance = UnitCommitment.read(fixture("case3-interface.json.gz"))
model = UnitCommitment.build_model(
instance = instance,
optimizer = HiGHS.Optimizer,
variable_names = true,
)
set_silent(model)
UnitCommitment.optimize!(model)
@test value(variable_by_name(model, "interface_flow[ifc1,3]")) 20.0 atol =
0.1
@test value(variable_by_name(model, "interface_flow[ifc1,4]")) 20.0 atol =
0.1
# case3-interface-2: one outbound, one inbound
instance = UnitCommitment.read(fixture("case3-interface-2.json.gz"))
model = UnitCommitment.build_model(
instance = instance,
optimizer = HiGHS.Optimizer,
variable_names = true,
)
set_silent(model)
UnitCommitment.optimize!(model)
@test value(variable_by_name(model, "interface_flow[ifc1,1]")) 95.0 atol =
0.1
@test value(variable_by_name(model, "interface_flow[ifc1,2]")) 95.0 atol =
0.1
end
end

@ -0,0 +1,32 @@
# 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.
using UnitCommitment
using JuMP
using HiGHS
using JSON
function storage_optimization_test()
@testset "storage_optimization" begin
instance =
UnitCommitment.read(fixture("case24-iberian-storage.json.gz"))
model = UnitCommitment.build_model(
instance = instance,
optimizer = HiGHS.Optimizer,
variable_names = true,
)
set_silent(model)
UnitCommitment.optimize!(model)
solution = UnitCommitment.solution(model)
# results must be valid
@test UnitCommitment.validate(instance, solution)
# storages are being used
charging_rates = solution["Storage charging rates (MW)"]
discharging_rates = solution["Storage discharging rates (MW)"]
@test sum(charging_rates["su1"]) > 0
@test sum(charging_rates["su2"]) > 0
@test sum(discharging_rates["su1"]) > 0
@test sum(discharging_rates["su2"]) > 0
end
end

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, DataStructures, Cbc, HiGHS using UnitCommitment, DataStructures, HiGHS
import UnitCommitment: TimeDecomposition, ConventionalLMP import UnitCommitment: TimeDecomposition, ConventionalLMP
function solution_methods_TimeDecomposition_optimize_test() function solution_methods_TimeDecomposition_optimize_test()
@ -13,8 +13,8 @@ function solution_methods_TimeDecomposition_optimize_test()
instance, instance,
TimeDecomposition(time_window = 3, time_increment = 2), TimeDecomposition(time_window = 3, time_increment = 2),
optimizer = optimizer_with_attributes( optimizer = optimizer_with_attributes(
Cbc.Optimizer, HiGHS.Optimizer,
"logLevel" => 0, "log_to_console" => false,
), ),
) )
@test length(solution["Thermal production (MW)"]["g1"]) == 4 @test length(solution["Thermal production (MW)"]["g1"]) == 4
@ -47,8 +47,8 @@ function solution_methods_TimeDecomposition_optimize_test()
instance, instance,
TimeDecomposition(time_window = 3, time_increment = 2), TimeDecomposition(time_window = 3, time_increment = 2),
optimizer = optimizer_with_attributes( optimizer = optimizer_with_attributes(
Cbc.Optimizer, HiGHS.Optimizer,
"logLevel" => 0, "log_to_console" => false,
), ),
after_build = after_build, after_build = after_build,
after_optimize = after_optimize, after_optimize = after_optimize,
@ -68,8 +68,8 @@ function solution_methods_TimeDecomposition_optimize_test()
instance, instance,
TimeDecomposition(time_window = 3, time_increment = 2), TimeDecomposition(time_window = 3, time_increment = 2),
optimizer = optimizer_with_attributes( optimizer = optimizer_with_attributes(
Cbc.Optimizer, HiGHS.Optimizer,
"logLevel" => 0, "log_to_console" => false,
), ),
) )
@test length(solution["case14"]["Thermal production (MW)"]["g3"]) == 4 @test length(solution["case14"]["Thermal production (MW)"]["g3"]) == 4

@ -146,4 +146,19 @@ function solution_methods_XavQiuWanThi19_sensitivity_test()
end end
end end
end end
@testset "_interface_injection_shift_factors" begin
instance = UnitCommitment.read(fixture("/case14-interface.json.gz"))
sc = instance.scenarios[1]
actual = UnitCommitment._interface_injection_shift_factors(
interfaces = sc.interfaces,
isf = UnitCommitment._injection_shift_factors(
lines = sc.lines,
buses = sc.buses,
),
)
@test size(actual) == (1, 13)
@test round.(collect(actual), digits = 2) ==
[0.0 -1.0 0.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0]
end
end end

@ -7,7 +7,7 @@ import UnitCommitment: XavQiuAhm2021
using Distributions using Distributions
using Random using Random
using UnitCommitment, Cbc, JuMP using UnitCommitment, JuMP
function get_scenario() function get_scenario()
return UnitCommitment.read_benchmark( return UnitCommitment.read_benchmark(

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, LinearAlgebra, Cbc, JuMP, JSON, GZip using UnitCommitment, LinearAlgebra, HiGHS, JuMP, JSON, GZip
function transform_slice_test() function transform_slice_test()
@testset "slice" begin @testset "slice" begin
@ -38,7 +38,10 @@ function transform_slice_test()
end end
# Should be able to build model without errors # Should be able to build model without errors
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) optimizer = optimizer_with_attributes(
HiGHS.Optimizer,
"log_to_console" => false,
)
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = modified, instance = modified,
optimizer = optimizer, optimizer = optimizer,
@ -58,7 +61,10 @@ function transform_slice_test()
end end
# Should be able to build model without errors # Should be able to build model without errors
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) optimizer = optimizer_with_attributes(
HiGHS.Optimizer,
"log_to_console" => false,
)
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = modified, instance = modified,
optimizer = optimizer, optimizer = optimizer,
@ -88,7 +94,34 @@ function transform_slice_test()
end end
# Should be able to build model without errors # Should be able to build model without errors
optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) optimizer = optimizer_with_attributes(
HiGHS.Optimizer,
"log_to_console" => false,
)
model = UnitCommitment.build_model(
instance = modified,
optimizer = optimizer,
variable_names = true,
)
end
@testset "slice interfaces" begin
instance = UnitCommitment.read(fixture("case14-interface.json.gz"))
modified = UnitCommitment.slice(instance, 1:3)
sc = modified.scenarios[1]
# Should update all time-dependent fields
for ifc in sc.interfaces
@test length(ifc.net_flow_upper_limit) == 3
@test length(ifc.net_flow_lower_limit) == 3
@test length(ifc.flow_limit_penalty) == 3
end
# Should be able to build model without errors
optimizer = optimizer_with_attributes(
HiGHS.Optimizer,
"log_to_console" => false,
)
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = modified, instance = modified,
optimizer = optimizer, optimizer = optimizer,

@ -2,7 +2,7 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# 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, LinearAlgebra, Cbc, JuMP, JSON using UnitCommitment, LinearAlgebra, HiGHS, JuMP, JSON
function _set_flow_limits!(instance) function _set_flow_limits!(instance)
for sc in instance.scenarios for sc in instance.scenarios
@ -18,8 +18,10 @@ function usage_test()
@testset "deterministic" begin @testset "deterministic" begin
instance = UnitCommitment.read(fixture("case14.json.gz")) instance = UnitCommitment.read(fixture("case14.json.gz"))
_set_flow_limits!(instance) _set_flow_limits!(instance)
optimizer = optimizer = optimizer_with_attributes(
optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) HiGHS.Optimizer,
"log_to_console" => false,
)
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = instance, instance = instance,
optimizer = optimizer, optimizer = optimizer,
@ -53,8 +55,10 @@ function usage_test()
]) ])
_set_flow_limits!(instance) _set_flow_limits!(instance)
@test length(instance.scenarios) == 2 @test length(instance.scenarios) == 2
optimizer = optimizer = optimizer_with_attributes(
optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) HiGHS.Optimizer,
"log_to_console" => false,
)
model = UnitCommitment.build_model( model = UnitCommitment.build_model(
instance = instance, instance = instance,
optimizer = optimizer, optimizer = optimizer,

Loading…
Cancel
Save