From 9cebd3d82c166d49c7f37977de466a31b8f9c73f Mon Sep 17 00:00:00 2001 From: Jun He Date: Fri, 28 Jul 2023 15:42:11 -0400 Subject: [PATCH 1/7] storage benchmark testcase --- test/fixtures/case24-iberian-storage.json.gz | Bin 0 -> 6293 bytes test/src/UnitCommitmentT.jl | 2 ++ test/src/model/storage_optimization_test.jl | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 test/fixtures/case24-iberian-storage.json.gz create mode 100644 test/src/model/storage_optimization_test.jl diff --git a/test/fixtures/case24-iberian-storage.json.gz b/test/fixtures/case24-iberian-storage.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..65a5528e1d1bf821297478147cf8c6ef2a7bca32 GIT binary patch literal 6293 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 0 + @test sum(charging_rates["su2"]) > 0 + @test sum(discharging_rates["su1"]) > 0 + @test sum(discharging_rates["su2"]) > 0 + end +end From a51dafd422ced75b1ea2478b14677efee98328f1 Mon Sep 17 00:00:00 2001 From: Jun He Date: Thu, 10 Aug 2023 16:44:07 -0400 Subject: [PATCH 2/7] interface --- src/UnitCommitment.jl | 1 + src/instance/read.jl | 43 ++++++++++++++++ src/instance/structs.jl | 13 +++++ src/model/build.jl | 3 ++ src/model/formulations/base/interface.jl | 46 ++++++++++++++++++ src/model/formulations/base/line.jl | 11 +++++ src/model/formulations/base/sensitivity.jl | 23 +++++++++ src/transform/slice.jl | 5 ++ test/fixtures/case14-interface.json.gz | Bin 0 -> 1956 bytes test/fixtures/case3-interface-2.json.gz | Bin 0 -> 705 bytes test/fixtures/case3-interface.json.gz | Bin 0 -> 700 bytes test/src/UnitCommitmentT.jl | 2 + test/src/instance/read_test.jl | 16 ++++++ test/src/model/interface_optimization_test.jl | 40 +++++++++++++++ .../XavQiuWanThi19/sensitivity_test.jl | 15 ++++++ test/src/transform/slice_test.jl | 41 ++++++++++++++-- 16 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 src/model/formulations/base/interface.jl create mode 100644 test/fixtures/case14-interface.json.gz create mode 100644 test/fixtures/case3-interface-2.json.gz create mode 100644 test/fixtures/case3-interface.json.gz create mode 100644 test/src/model/interface_optimization_test.jl diff --git a/src/UnitCommitment.jl b/src/UnitCommitment.jl index d46d71e..2a85320 100644 --- a/src/UnitCommitment.jl +++ b/src/UnitCommitment.jl @@ -37,6 +37,7 @@ include("model/formulations/base/system.jl") include("model/formulations/base/unit.jl") include("model/formulations/base/punit.jl") include("model/formulations/base/storage.jl") +include("model/formulations/base/interface.jl") include("model/formulations/CarArr2006/pwlcosts.jl") include("model/formulations/DamKucRajAta2016/ramp.jl") include("model/formulations/Gar1962/pwlcosts.jl") diff --git a/src/instance/read.jl b/src/instance/read.jl index 62b0230..12c9733 100644 --- a/src/instance/read.jl +++ b/src/instance/read.jl @@ -137,6 +137,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario reserves = Reserve[] profiled_units = ProfiledUnit[] storage_units = StorageUnit[] + interfaces = Interface[] function scalar(x; default = nothing) x !== nothing || return default @@ -452,6 +453,45 @@ function _from_json(json; repair = true)::UnitCommitmentScenario 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( name = scenario_name, probability = probability, @@ -474,8 +514,11 @@ function _from_json(json; repair = true)::UnitCommitmentScenario profiled_units = profiled_units, storage_units_by_name = Dict(su.name => su for su in 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), lodf = spzeros(Float64, length(lines), length(lines)), + interface_isf = spzeros(Float64, length(interfaces), length(buses) - 1), ) if repair UnitCommitment.repair!(scenario) diff --git a/src/instance/structs.jl b/src/instance/structs.jl index 4082fb0..bbb0bcd 100644 --- a/src/instance/structs.jl +++ b/src/instance/structs.jl @@ -103,6 +103,16 @@ mutable struct StorageUnit max_ending_level::Float64 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 buses_by_name::Dict{AbstractString,Bus} buses::Vector{Bus} @@ -125,6 +135,9 @@ Base.@kwdef mutable struct UnitCommitmentScenario thermal_units::Vector{ThermalUnit} storage_units_by_name::Dict{AbstractString,StorageUnit} storage_units::Vector{StorageUnit} + interfaces_by_name::Dict{AbstractString,Interface} + interfaces::Vector{Interface} + interface_isf::Array{Float64,2} time::Int time_step::Int end diff --git a/src/model/build.jl b/src/model/build.jl index 0e27d42..089db92 100644 --- a/src/model/build.jl +++ b/src/model/build.jl @@ -103,6 +103,9 @@ function build_model(; _add_storage_unit!(model, su, sc) end _add_system_wide_eqs!(model, sc) + for ifc in sc.interfaces + _add_interface!(model, ifc, formulation.transmission, sc) + end end @objective(model, Min, model[:obj]) end diff --git a/src/model/formulations/base/interface.jl b/src/model/formulations/base/interface.jl new file mode 100644 index 0000000..00c2b8e --- /dev/null +++ b/src/model/formulations/base/interface.jl @@ -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 diff --git a/src/model/formulations/base/line.jl b/src/model/formulations/base/line.jl index 98d5f2c..52eb199 100644 --- a/src/model/formulations/base/line.jl +++ b/src/model/formulations/base/line.jl @@ -26,9 +26,11 @@ function _setup_transmission( )::Nothing isf = formulation.precomputed_isf lodf = formulation.precomputed_lodf + interface_isf = nothing if length(sc.buses) == 1 isf = zeros(0, 0) lodf = zeros(0, 0) + interface_isf = zeros(0, 0) elseif isf === nothing @info "Computing injection shift factors..." time_isf = @elapsed begin @@ -36,6 +38,11 @@ function _setup_transmission( buses = sc.buses, lines = sc.lines, ) + interface_isf = + UnitCommitment._interface_injection_shift_factors( + interfaces = sc.interfaces, + isf = isf, + ) end @info @sprintf("Computed ISF in %.2f seconds", time_isf) @info "Computing line outage factors..." @@ -53,9 +60,13 @@ function _setup_transmission( formulation.lodf_cutoff ) isf[abs.(isf).N37a%N#;WiD!SZ*BnXT1{`;Mi4zWzd{gl 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 literal 0 HcmV?d00001 diff --git a/test/src/UnitCommitmentT.jl b/test/src/UnitCommitmentT.jl index 77ee669..5d92195 100644 --- a/test/src/UnitCommitmentT.jl +++ b/test/src/UnitCommitmentT.jl @@ -10,6 +10,7 @@ include("instance/read_test.jl") include("instance/migrate_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/find_test.jl") include("solution/methods/XavQiuWanThi19/sensitivity_test.jl") @@ -41,6 +42,7 @@ function runtests() instance_migrate_test() model_formulations_test() storage_optimization_test() + interface_optimization_test() solution_methods_XavQiuWanThi19_filter_test() solution_methods_XavQiuWanThi19_find_test() solution_methods_XavQiuWanThi19_sensitivity_test() diff --git a/test/src/instance/read_test.jl b/test/src/instance/read_test.jl index bcb3eb4..cc377d9 100644 --- a/test/src/instance/read_test.jl +++ b/test/src/instance/read_test.jl @@ -224,4 +224,20 @@ function instance_read_test() @test su4.simultaneous_charge_and_discharge == [false, false, true, true] 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 diff --git a/test/src/model/interface_optimization_test.jl b/test/src/model/interface_optimization_test.jl new file mode 100644 index 0000000..80ad5c8 --- /dev/null +++ b/test/src/model/interface_optimization_test.jl @@ -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 diff --git a/test/src/solution/methods/XavQiuWanThi19/sensitivity_test.jl b/test/src/solution/methods/XavQiuWanThi19/sensitivity_test.jl index 0eef038..318b69d 100644 --- a/test/src/solution/methods/XavQiuWanThi19/sensitivity_test.jl +++ b/test/src/solution/methods/XavQiuWanThi19/sensitivity_test.jl @@ -146,4 +146,19 @@ function solution_methods_XavQiuWanThi19_sensitivity_test() 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 diff --git a/test/src/transform/slice_test.jl b/test/src/transform/slice_test.jl index fdd86b4..f0e6a6e 100644 --- a/test/src/transform/slice_test.jl +++ b/test/src/transform/slice_test.jl @@ -2,7 +2,7 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # 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() @testset "slice" begin @@ -38,7 +38,10 @@ function transform_slice_test() end # 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, @@ -58,7 +61,10 @@ function transform_slice_test() end # 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, @@ -88,7 +94,34 @@ function transform_slice_test() end # 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( instance = modified, optimizer = optimizer, From dab24abb6c6680ba6dc9b4a266d1f704cc09b917 Mon Sep 17 00:00:00 2001 From: Jun He Date: Thu, 10 Aug 2023 17:01:19 -0400 Subject: [PATCH 3/7] updated doc for interface --- docs/src/format.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/src/format.md b/docs/src/format.md index 6714862..354ff5d 100644 --- a/docs/src/format.md +++ b/docs/src/format.md @@ -12,6 +12,7 @@ An instance of the stochastic security-constrained unit commitment (SCUC) proble * [Storage units](#Storage-units) * [Price-sensitive loads](#Price-sensitive-loads) * [Transmission lines](#Transmission-lines) +* [Interfaces](#Interfaces) * [Reserves](#Reserves) * [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 | `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 -| `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 #### 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 From 7412b5f7e57919ad9bd17050e5ab97b4cb793561 Mon Sep 17 00:00:00 2001 From: Jun He Date: Thu, 10 Aug 2023 17:22:43 -0400 Subject: [PATCH 4/7] report line and interface flows --- src/solution/solution.jl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/solution/solution.jl b/src/solution/solution.jl index c3a9cdf..c21a1b7 100644 --- a/src/solution/solution.jl +++ b/src/solution/solution.jl @@ -88,6 +88,26 @@ function solution(model::JuMP.Model)::OrderedDict if !isempty(sc.lines) sol[sc.name]["Line overflow (MW)"] = timeseries(model[:overflow], sc.lines, sc = sc) + sol[sc.name]["Transmission line flow (MW)"] = OrderedDict( + l.name => [ + ( + sc.isf[l.offset, :]' * [ + value(model[:net_injection][sc.name, bus.name, t]) for bus in sc.buses + ][2:end] + ) for t in 1:T + ] for l in sc.lines + ) + end + if !isempty(sc.interfaces) + sol[sc.name]["Interface flow (MW)"] = OrderedDict( + ifc.name => [ + ( + sc.interface_isf[ifc.offset, :]' * [ + value(model[:net_injection][sc.name, bus.name, t]) for bus in sc.buses + ][2:end] + ) for t in 1:T + ] for ifc in sc.interfaces + ) end if !isempty(sc.price_sensitive_loads) sol[sc.name]["Price-sensitive loads (MW)"] = From 547aba3b9b5888c9d034e2bb0f46c3f7a8552b9a Mon Sep 17 00:00:00 2001 From: Jun He Date: Thu, 10 Aug 2023 17:30:09 -0400 Subject: [PATCH 5/7] replaced Cbc with HiGHS --- test/src/instance/migrate_test.jl | 2 +- test/src/instance/read_test.jl | 2 +- test/src/lmp/aelmp_test.jl | 6 +++--- test/src/lmp/conventional_test.jl | 7 +++++-- test/src/market/market_test.jl | 14 +++++++------- test/src/model/formulations_test.jl | 4 ++-- .../methods/TimeDecomposition/optimize_test.jl | 14 +++++++------- test/src/transform/randomize/XavQiuAhm2021_test.jl | 2 +- test/src/usage.jl | 14 +++++++++----- 9 files changed, 36 insertions(+), 29 deletions(-) diff --git a/test/src/instance/migrate_test.jl b/test/src/instance/migrate_test.jl index 8328e53..08b12e2 100644 --- a/test/src/instance/migrate_test.jl +++ b/test/src/instance/migrate_test.jl @@ -2,7 +2,7 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # 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() @testset "read v0.2" begin diff --git a/test/src/instance/read_test.jl b/test/src/instance/read_test.jl index cc377d9..9ccbdc1 100644 --- a/test/src/instance/read_test.jl +++ b/test/src/instance/read_test.jl @@ -2,7 +2,7 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # 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() @testset "read_benchmark" begin diff --git a/test/src/lmp/aelmp_test.jl b/test/src/lmp/aelmp_test.jl index d619207..31904bb 100644 --- a/test/src/lmp/aelmp_test.jl +++ b/test/src/lmp/aelmp_test.jl @@ -2,7 +2,7 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Released under the modified BSD license. See COPYING.md for more details. -using UnitCommitment, Cbc, HiGHS, JuMP +using UnitCommitment, HiGHS, JuMP import UnitCommitment: AELMP function lmp_aelmp_test() @@ -13,8 +13,8 @@ function lmp_aelmp_test() model = UnitCommitment.build_model( instance = instance, optimizer = optimizer_with_attributes( - Cbc.Optimizer, - "logLevel" => 0, + HiGHS.Optimizer, + "log_to_console" => false, ), variable_names = true, ) diff --git a/test/src/lmp/conventional_test.jl b/test/src/lmp/conventional_test.jl index bd2529e..ce893de 100644 --- a/test/src/lmp/conventional_test.jl +++ b/test/src/lmp/conventional_test.jl @@ -2,13 +2,16 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # 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) instance = UnitCommitment.read(path) model = UnitCommitment.build_model( instance = instance, - optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0), + optimizer = optimizer_with_attributes( + HiGHS.Optimizer, + "log_to_console" => false, + ), variable_names = true, ) JuMP.set_silent(model) diff --git a/test/src/market/market_test.jl b/test/src/market/market_test.jl index 40a8d56..384ade6 100644 --- a/test/src/market/market_test.jl +++ b/test/src/market/market_test.jl @@ -2,7 +2,7 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Released under the modified BSD license. See COPYING.md for more details. -using UnitCommitment, Cbc, HiGHS, JuMP +using UnitCommitment, HiGHS, JuMP import UnitCommitment: MarketSettings function simple_market_test() @@ -20,8 +20,8 @@ function simple_market_test() rt_paths, MarketSettings(), # keep everything default optimizer = optimizer_with_attributes( - Cbc.Optimizer, - "logLevel" => 0, + HiGHS.Optimizer, + "log_to_console" => false, ), lp_optimizer = optimizer_with_attributes( HiGHS.Optimizer, @@ -52,8 +52,8 @@ function simple_market_test() rt_paths, MarketSettings(lmp_method = nothing), # no lmp optimizer = optimizer_with_attributes( - Cbc.Optimizer, - "logLevel" => 0, + HiGHS.Optimizer, + "log_to_console" => false, ), ) @@ -115,8 +115,8 @@ function stochastic_market_test() rt_paths, MarketSettings(), # keep everything default optimizer = optimizer_with_attributes( - Cbc.Optimizer, - "logLevel" => 0, + HiGHS.Optimizer, + "log_to_console" => false, ), lp_optimizer = optimizer_with_attributes( HiGHS.Optimizer, diff --git a/test/src/model/formulations_test.jl b/test/src/model/formulations_test.jl index 2b9307d..3f7e35c 100644 --- a/test/src/model/formulations_test.jl +++ b/test/src/model/formulations_test.jl @@ -4,7 +4,7 @@ using UnitCommitment using JuMP -using Cbc +using HiGHS using JSON import UnitCommitment: ArrCon2000, @@ -28,7 +28,7 @@ function _test( model = UnitCommitment.build_model( instance = instance, formulation = formulation, - optimizer = Cbc.Optimizer, + optimizer = HiGHS.Optimizer, variable_names = true, ) set_silent(model) diff --git a/test/src/solution/methods/TimeDecomposition/optimize_test.jl b/test/src/solution/methods/TimeDecomposition/optimize_test.jl index b9076fd..3969ff9 100644 --- a/test/src/solution/methods/TimeDecomposition/optimize_test.jl +++ b/test/src/solution/methods/TimeDecomposition/optimize_test.jl @@ -2,7 +2,7 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # 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 function solution_methods_TimeDecomposition_optimize_test() @@ -13,8 +13,8 @@ function solution_methods_TimeDecomposition_optimize_test() instance, TimeDecomposition(time_window = 3, time_increment = 2), optimizer = optimizer_with_attributes( - Cbc.Optimizer, - "logLevel" => 0, + HiGHS.Optimizer, + "log_to_console" => false, ), ) @test length(solution["Thermal production (MW)"]["g1"]) == 4 @@ -47,8 +47,8 @@ function solution_methods_TimeDecomposition_optimize_test() instance, TimeDecomposition(time_window = 3, time_increment = 2), optimizer = optimizer_with_attributes( - Cbc.Optimizer, - "logLevel" => 0, + HiGHS.Optimizer, + "log_to_console" => false, ), after_build = after_build, after_optimize = after_optimize, @@ -68,8 +68,8 @@ function solution_methods_TimeDecomposition_optimize_test() instance, TimeDecomposition(time_window = 3, time_increment = 2), optimizer = optimizer_with_attributes( - Cbc.Optimizer, - "logLevel" => 0, + HiGHS.Optimizer, + "log_to_console" => false, ), ) @test length(solution["case14"]["Thermal production (MW)"]["g3"]) == 4 diff --git a/test/src/transform/randomize/XavQiuAhm2021_test.jl b/test/src/transform/randomize/XavQiuAhm2021_test.jl index dfe397f..19796dd 100644 --- a/test/src/transform/randomize/XavQiuAhm2021_test.jl +++ b/test/src/transform/randomize/XavQiuAhm2021_test.jl @@ -7,7 +7,7 @@ import UnitCommitment: XavQiuAhm2021 using Distributions using Random -using UnitCommitment, Cbc, JuMP +using UnitCommitment, JuMP function get_scenario() return UnitCommitment.read_benchmark( diff --git a/test/src/usage.jl b/test/src/usage.jl index ea4eb20..3e5cf5f 100644 --- a/test/src/usage.jl +++ b/test/src/usage.jl @@ -2,7 +2,7 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # 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) for sc in instance.scenarios @@ -18,8 +18,10 @@ function usage_test() @testset "deterministic" begin instance = UnitCommitment.read(fixture("case14.json.gz")) _set_flow_limits!(instance) - optimizer = - optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) + optimizer = optimizer_with_attributes( + HiGHS.Optimizer, + "log_to_console" => false, + ) model = UnitCommitment.build_model( instance = instance, optimizer = optimizer, @@ -53,8 +55,10 @@ function usage_test() ]) _set_flow_limits!(instance) @test length(instance.scenarios) == 2 - optimizer = - optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) + optimizer = optimizer_with_attributes( + HiGHS.Optimizer, + "log_to_console" => false, + ) model = UnitCommitment.build_model( instance = instance, optimizer = optimizer, From b609abe4bb4d83122bc97b1aa70bb859310ed3b7 Mon Sep 17 00:00:00 2001 From: Jun He Date: Fri, 11 Aug 2023 09:53:02 -0400 Subject: [PATCH 6/7] fixed 0 step range in sparse matrix --- src/model/formulations/base/sensitivity.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/formulations/base/sensitivity.jl b/src/model/formulations/base/sensitivity.jl index fed4a1a..c680751 100644 --- a/src/model/formulations/base/sensitivity.jl +++ b/src/model/formulations/base/sensitivity.jl @@ -37,7 +37,7 @@ function _interface_injection_shift_factors(; interfaces::Array{Interface}, isf::Array{Float64,2}, ) - interface_isf = spzeros(Float64, length(interfaces), size(isf, 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] From e6b4f6add3a5c8b3edb7eab1eae9c2be844cbeef Mon Sep 17 00:00:00 2001 From: Jun He Date: Thu, 17 Aug 2023 18:29:25 -0400 Subject: [PATCH 7/7] replace for loops with matrices --- src/solution/solution.jl | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/solution/solution.jl b/src/solution/solution.jl index c21a1b7..a400e4a 100644 --- a/src/solution/solution.jl +++ b/src/solution/solution.jl @@ -85,28 +85,25 @@ function solution(model::JuMP.Model)::OrderedDict sol[sc.name]["Load curtail (MW)"] = timeseries(model[:curtail], sc.buses, sc = sc) 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) sol[sc.name]["Line overflow (MW)"] = timeseries(model[:overflow], sc.lines, sc = sc) - sol[sc.name]["Transmission line flow (MW)"] = OrderedDict( - l.name => [ - ( - sc.isf[l.offset, :]' * [ - value(model[:net_injection][sc.name, bus.name, t]) for bus in sc.buses - ][2:end] - ) for t in 1:T - ] for l in sc.lines - ) + # 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 => [ - ( - sc.interface_isf[ifc.offset, :]' * [ - value(model[:net_injection][sc.name, bus.name, t]) for bus in sc.buses - ][2:end] - ) for t in 1:T - ] for ifc in sc.interfaces + ifc.name => interface_flows[ifc.offset, :] for + ifc in sc.interfaces ) end if !isempty(sc.price_sensitive_loads)