From d459fcf5345b96cb9394c3f0232a956a53f1ae4c Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Fri, 28 Mar 2025 15:32:31 -0400 Subject: [PATCH 01/21] Added efficiency, test cases --- src/constraint.jl | 2 +- src/mpopf.jl | 39 ++++++++++++++-------- test/runtests.jl | 85 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 102 insertions(+), 24 deletions(-) diff --git a/src/constraint.jl b/src/constraint.jl index 2d81b68..4cae701 100644 --- a/src/constraint.jl +++ b/src/constraint.jl @@ -103,7 +103,7 @@ end #storage constraints -#Formulation from Geth, Carleton (2020) +#Formulation from Geth, Coffrin, Fobes (2020) function c_active_stor_power(s, pst, pstd, pstc, I2) return pst + pstd - pstc - s.Pexts - s.Zr*I2 end diff --git a/src/mpopf.jl b/src/mpopf.jl index bc60f4b..3b9962c 100644 --- a/src/mpopf.jl +++ b/src/mpopf.jl @@ -79,9 +79,6 @@ function build_base_polar_mpopf(core, data, N, Nbus) q = variable(core, size(data.arc, 1), N; lvar = repeat(-data.rate_a, 1, N), uvar = repeat(data.rate_a, 1, N)) #Storage specific variables - #charge or discharge from battery to grid - pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) - pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) #active/reactive power from bus into storage pst = variable(core, size(data.storage, 1), N) @@ -171,8 +168,6 @@ function build_base_polar_mpopf(core, data, N, Nbus) qg = qg, p = p, q = q, - pstc = pstc, - pstd = pstd, pst = pst, qst = qst, I2 = I2, @@ -197,9 +192,6 @@ function build_base_rect_mpopf(core, data, N, Nbus) q = variable(core, size(data.arc, 1), N; lvar = repeat(-data.rate_a, 1, N), uvar = repeat(data.rate_a, 1, N)) #Storage specific variables - #charge or discharge from battery to grid - pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) - pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) #active/reactive power from bus into storage pst = variable(core, size(data.storage, 1), N) @@ -282,8 +274,6 @@ function build_base_rect_mpopf(core, data, N, Nbus) qg = qg, p = p, q = q, - pstc = pstc, - pstd = pstd, pst = pst, qst = qst, I2 = I2, @@ -317,7 +307,7 @@ function build_polar_mpopf(data, Nbus, N; backend = nothing, T = Float64, storag vars, cons = build_base_polar_mpopf(core, data, N, Nbus) - va, vm, pg, qg, p, q, pstc, pstd, pst, qst, I2, qint, E = vars + va, vm, pg, qg, p, q, pst, qst, I2, qint, E = vars (c_ref_angle, c_to_active_power_flow, @@ -331,6 +321,10 @@ function build_polar_mpopf(data, Nbus, N; backend = nothing, T = Float64, storag c_to_thermal_limit, c_ramp_rate) = cons + #charge or discharge from battery to grid + pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) + #adding storage constraints c_active_storage_power = constraint(core, c_active_stor_power(s, pst[s.c, s.t], pstd[s.c, s.t], pstc[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) @@ -373,6 +367,7 @@ function build_polar_mpopf(data, Nbus, N; backend = nothing, T = Float64, storag c_discharge_thermal_limit = c_discharge_thermal_limit ) + vars = va, vm, pg, qg, p, q, pst, qst, I2, qint, E, pstd, pstc model = ExaModel(core; kwargs...) return model, vars, cons @@ -383,7 +378,7 @@ function build_rect_mpopf(data, Nbus, N; backend = nothing, T = Float64, storage vars, cons = build_base_rect_mpopf(core, data, N, Nbus) - vr, vim, pg, qg, p, q, pstc, pstd, pst, qst, I2, qint, E = vars + vr, vim, pg, qg, p, q, pst, qst, I2, qint, E = vars (c_ref_angle, c_to_active_power_flow, @@ -397,6 +392,10 @@ function build_rect_mpopf(data, Nbus, N; backend = nothing, T = Float64, storage c_to_thermal_limit, c_voltage_magnitude, c_ramp_rate) = cons + + #charge or discharge from battery to grid + pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) #adding storage constraints c_active_storage_power = constraint(core, c_active_stor_power(s, pst[s.c, s.t], pstd[s.c, s.t], pstc[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) @@ -439,6 +438,7 @@ function build_rect_mpopf(data, Nbus, N; backend = nothing, T = Float64, storage c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, c_discharge_thermal_limit = c_discharge_thermal_limit ) + vars = vr, vim, pg, qg, p, q, pst, qst, I2, qint, E, pstc, pstd model = ExaModel(core; kwargs...) return model, vars, cons @@ -450,7 +450,7 @@ function build_polar_mpopf(data, Nbus, N, discharge_func::Function; backend = no vars, cons = build_base_polar_mpopf(core, data, N, Nbus) - va, vm, pg, qg, p, q, pstc, pstd, pst, qst, I2, qint, E = vars + va, vm, pg, qg, p, q, pst, qst, I2, qint, E = vars (c_ref_angle, c_to_active_power_flow, @@ -464,6 +464,9 @@ function build_polar_mpopf(data, Nbus, N, discharge_func::Function; backend = no c_to_thermal_limit, c_ramp_rate) = cons + #discharge or charge from battery to grid (positive or negative) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) + c_active_storage_power = constraint(core, c_active_storage_power_smooth(s, pst[s.c, s.t], pstd[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) @@ -499,6 +502,8 @@ function build_polar_mpopf(data, Nbus, N, discharge_func::Function; backend = no c_discharge_thermal_limit = c_discharge_thermal_limit ) + vars = va, vm, pg, qg, p, q, pst, qst, I2, qint, E, pstd + model = ExaModel(core; kwargs...) return model, vars, cons end @@ -509,7 +514,7 @@ function build_rect_mpopf(data, Nbus, N, discharge_func::Function; backend = not vars, cons = build_base_rect_mpopf(core, data, N, Nbus) - vr, vim, pg, qg, p, q, pstc, pstd, pst, qst, I2, qint, E = vars + vr, vim, pg, qg, p, q, pst, qst, I2, qint, E = vars (c_ref_angle, c_to_active_power_flow, @@ -524,6 +529,10 @@ function build_rect_mpopf(data, Nbus, N, discharge_func::Function; backend = not c_voltage_magnitude, c_ramp_rate) = cons + + #discharge or charge from battery to grid (can be positive or negative) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) + c_active_storage_power = constraint(core, c_active_storage_power_smooth(s, pst[s.c, s.t], pstd[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) @@ -560,6 +569,8 @@ function build_rect_mpopf(data, Nbus, N, discharge_func::Function; backend = not c_discharge_thermal_limit = c_discharge_thermal_limit ) + vars = vr, vim, pg, qg, p, q, pst, qst, I2, qint, E, pstd + model = ExaModel(core; kwargs...) return model, vars, cons end diff --git a/test/runtests.jl b/test/runtests.jl index 11dd0b5..129a83c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA +using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt const CONFIGS = [ (Float32, nothing), @@ -18,15 +18,82 @@ if CUDA.has_cuda_gpu() ) end +numeric_tolerance(::Type{Float32}) = 1e-2 +numeric_tolerance(::Type{Float64}) = 1e-4 + + function runtests() - @testset "ExaModelsExamples test" begin - for name in ExaModelsPower.NAMES - for (T, backend) in CONFIGS - m = eval(name)(; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - - @testset "$name" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED + @testset "ExaModelsPower test" begin + + #Test static opf + #data_pm = PowerModels.parse_file("data/pglib_opf_case3_lmbd.m") + + data, dicts = ExaModelsPower.parse_ac_power_data("pglib_opf_case3_lmbd.m") + + for (T, backend) in CONFIGS + #Polar tests + m, v, c = eval(opf_model)("pglib_opf_case3_lmbd.m"; T=T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + va, vm, pg, qg, p, q = v + + nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) + result_pm = solve_opf("data/pglib_opf_case3_lmbd.m",ACPPowerModel, nlp_solver) + + @testset "$(T), $(backend), polar" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED + @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) + for key in keys(dicts.gen) + @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*100) + @test isapprox(Array(solution(result, qg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["qg"], atol = result.options.tol*100) + end + for key in keys(dicts.bus) + @test isapprox(Array(solution(result, va))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["va"], atol = result.options.tol*100) + @test isapprox(Array(solution(result, vm))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vm"], atol = result.options.tol*100) + end + + #Branches are encoded differently in solutions, so matches are hard coded + vars_dict = Dict("p" => p, "q" => q) + for st_var in ["p", "q"] + var = vars_dict[st_var] + @test isapprox(Array(solution(result, var))[1], result_pm["solution"]["branch"]["2"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[2], result_pm["solution"]["branch"]["3"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[3], result_pm["solution"]["branch"]["1"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[4], result_pm["solution"]["branch"]["2"][string(st_var, "t")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[5], result_pm["solution"]["branch"]["3"][string(st_var, "t")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[6], result_pm["solution"]["branch"]["1"][string(st_var, "t")], atol = result.options.tol*100) + end + end + + #Rectangular tests + m, v, c = eval(opf_model)("pglib_opf_case3_lmbd.m"; T=T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + vr, vim, pg, qg, p, q = v + + nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) + result_pm = solve_opf("data/pglib_opf_case3_lmbd.m", ACRPowerModel, nlp_solver) + + @testset "$(T), $(backend), rect" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED + @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) + for key in keys(dicts.gen) + @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*100) + @test isapprox(Array(solution(result, qg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["qg"], atol = result.options.tol*100) + end + for key in keys(dicts.bus) + @test isapprox(Array(solution(result, vr))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vr"], atol = result.options.tol*100) + @test isapprox(Array(solution(result, vim))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vi"], atol = result.options.tol*100) + end + + #Branches are encoded differently in solutions, so matches are hard coded + vars_dict = Dict("p" => p, "q" => q) + for st_var in ["p", "q"] + var = vars_dict[st_var] + @test isapprox(Array(solution(result, var))[1], result_pm["solution"]["branch"]["2"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[2], result_pm["solution"]["branch"]["3"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[3], result_pm["solution"]["branch"]["1"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[4], result_pm["solution"]["branch"]["2"][string(st_var, "t")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[5], result_pm["solution"]["branch"]["3"][string(st_var, "t")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[6], result_pm["solution"]["branch"]["1"][string(st_var, "t")], atol = result.options.tol*100) end end end From a158abd72a42e0106d62ceec26dde348bf5af289 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 1 Apr 2025 15:26:14 -0400 Subject: [PATCH 02/21] tests --- data/case3_5split.Pd | 3 + data/case3_5split.Qd | 3 + data/pglib_opf_case3_lmbd.m | 103 ++++++++ data/pglib_opf_case3_lmbd_mod.m | 111 ++++++++ src/mpopf.jl | 431 ++++++++++++++++---------------- test/runtests.jl | 196 +++++++++++++-- 6 files changed, 620 insertions(+), 227 deletions(-) create mode 100644 data/case3_5split.Pd create mode 100644 data/case3_5split.Qd create mode 100644 data/pglib_opf_case3_lmbd.m create mode 100644 data/pglib_opf_case3_lmbd_mod.m diff --git a/data/case3_5split.Pd b/data/case3_5split.Pd new file mode 100644 index 0000000..a539db8 --- /dev/null +++ b/data/case3_5split.Pd @@ -0,0 +1,3 @@ +110.00000000 109.700000000 109.200000000 110.30000000 109.90000000 +110.0000000 110.30892087 109.70779399 110.69866241 110.68356854 +95.0000000 94.40098664 94.90086201 95.39985206 94.79818270 diff --git a/data/case3_5split.Qd b/data/case3_5split.Qd new file mode 100644 index 0000000..3b226c8 --- /dev/null +++ b/data/case3_5split.Qd @@ -0,0 +1,3 @@ +40.00000000 40.700000000 39.200000000 39.30000000 39.90000000 +40.0000000 39.30892087 39.70779399 40.69866241 39.68356854 +50.0000000 50.40098664 50.90086201 49.39985206 49.79818270 diff --git a/data/pglib_opf_case3_lmbd.m b/data/pglib_opf_case3_lmbd.m new file mode 100644 index 0000000..b52e755 --- /dev/null +++ b/data/pglib_opf_case3_lmbd.m @@ -0,0 +1,103 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% %%%%% +%%%% IEEE PES Power Grid Library - Optimal Power Flow - v23.07 %%%%% +%%%% (https://github.com/power-grid-lib/pglib-opf) %%%%% +%%%% Benchmark Group - Typical Operations %%%%% +%%%% 23 - July - 2023 %%%%% +%%%% %%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The semidefinite relaxation of the OPF problem successfully solves +% this network with a value of 60 MVA for the line-flow limit on the line from +% bus 2 to bus 3. The semidefinite relaxation fails to give a physically +% meaningful solution to this network with a value of 50 MVA for the line-flow +% limit on this line. See the following publication for further details. +% +% Lesieutre, B.C. & Molzahn, D.K. & Borden, AR. & Demarco, C.L., +% "Examining the Limits of the Application of Semidefinite Programming to Power Flow Problems", +% 49th Annual Allerton Conference on Communication, Control, and Computing (Allerton), +% September, 2011, pp. 1492-1499 +% +% opt objective value: 5812.64 $/hr +% +% Bus Voltage Generation Load Lambda($/MVA-hr) +% # Mag(pu) Ang(deg) P (MW) Q (MVAr) P (MW) Q (MVAr) P Q +% ----- ------- -------- -------- -------- -------- -------- ------- ------- +% 1 1.100 0.000* 148.07 54.70 110.00 40.00 37.575 - +% 2 0.926 7.259 170.01 -8.79 110.00 40.00 30.101 - +% 3 0.900 -17.267 0.00 -4.84 95.00 50.00 45.537 - +% -------- -------- -------- -------- +% Total: 318.07 41.06 315.00 130.00 +% +% Copyright (c) 2011 by The Institute of Electrical and Electronics Engineers (IEEE) +% Licensed under the Creative Commons Attribution 4.0 +% International license, http://creativecommons.org/licenses/by/4.0/ +% +% Contact M.E. Brennan (me.brennan@ieee.org) for inquries on further reuse of +% this dataset. +% +function mpc = pglib_opf_case3_lmbd +mpc.version = '2'; +mpc.baseMVA = 100.0; + +%% bus data +% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin +mpc.bus = [ + 1 3 110.0 40.0 0.0 0.0 1 1.00000 0.00000 240.0 1 1.10000 0.90000; + 2 2 110.0 40.0 0.0 0.0 1 1.00000 0.00000 240.0 1 1.10000 0.90000; + 3 2 95.0 50.0 0.0 0.0 1 1.00000 0.00000 240.0 1 1.10000 0.90000; +]; + +%% generator data +% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin +mpc.gen = [ + 1 1000.0 0.0 1000.0 -1000.0 1.0 100.0 1 2000.0 0.0; + 2 1000.0 0.0 1000.0 -1000.0 1.0 100.0 1 2000.0 0.0; + 3 0.0 0.0 1000.0 -1000.0 1.0 100.0 1 0.0 0.0; +]; + +%% generator cost data +% 2 startup shutdown n c(n-1) ... c0 +mpc.gencost = [ + 2 0.0 0.0 3 0.110000 5.000000 0.000000; + 2 0.0 0.0 3 0.085000 1.200000 0.000000; + 2 0.0 0.0 3 0.000000 0.000000 0.000000; +]; + +%% branch data +% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax +mpc.branch = [ + 1 3 0.065 0.62 0.45 9000.0 9000.0 9000.0 0.0 0.0 1 -30.0 30.0; + 3 2 0.025 0.75 0.7 50.0 50.0 50.0 0.0 0.0 1 -30.0 30.0; + 1 2 0.042 0.9 0.3 9000.0 9000.0 9000.0 0.0 0.0 1 -30.0 30.0; +]; + +% INFO : === Translation Options === +% INFO : Phase Angle Bound: 30.0 (deg.) +% INFO : Setting Flat Start +% INFO : +% INFO : === Generator Bounds Update Notes === +% INFO : +% INFO : === Base KV Replacement Notes === +% INFO : +% INFO : === Transformer Setting Replacement Notes === +% INFO : +% INFO : === Line Capacity Monotonicity Notes === +% INFO : Updated Thermal Rating: on line 1-3 : Rate B, Rate C - 0.0, 0.0 -> 9000.0, 9000.0 +% INFO : Updated Thermal Rating: on line 3-2 : Rate B, Rate C - 0.0, 0.0 -> 50.0, 50.0 +% INFO : Updated Thermal Rating: on line 1-2 : Rate B, Rate C - 0.0, 0.0 -> 9000.0, 9000.0 +% INFO : +% INFO : === Voltage Setpoint Replacement Notes === +% INFO : Bus 1 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 2 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 3 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : +% INFO : === Generator Setpoint Replacement Notes === +% INFO : Gen at bus 1 : Pg=0.0, Qg=0.0 -> Pg=1000.0, Qg=0.0 +% INFO : Gen at bus 1 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 2 : Pg=0.0, Qg=0.0 -> Pg=1000.0, Qg=0.0 +% INFO : Gen at bus 2 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 3 : Pg=0.0, Qg=0.0 -> Pg=0.0, Qg=0.0 +% INFO : Gen at bus 3 : Vg=1.0 -> Vg=1.0 +% INFO : +% INFO : === Writing Matpower Case File Notes === diff --git a/data/pglib_opf_case3_lmbd_mod.m b/data/pglib_opf_case3_lmbd_mod.m new file mode 100644 index 0000000..163880b --- /dev/null +++ b/data/pglib_opf_case3_lmbd_mod.m @@ -0,0 +1,111 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% %%%%% +%%%% IEEE PES Power Grid Library - Optimal Power Flow - v23.07 %%%%% +%%%% (https://github.com/power-grid-lib/pglib-opf) %%%%% +%%%% Benchmark Group - Typical Operations %%%%% +%%%% 23 - July - 2023 %%%%% +%%%% %%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% The semidefinite relaxation of the OPF problem successfully solves +% this network with a value of 60 MVA for the line-flow limit on the line from +% bus 2 to bus 3. The semidefinite relaxation fails to give a physically +% meaningful solution to this network with a value of 50 MVA for the line-flow +% limit on this line. See the following publication for further details. +% +% Lesieutre, B.C. & Molzahn, D.K. & Borden, AR. & Demarco, C.L., +% "Examining the Limits of the Application of Semidefinite Programming to Power Flow Problems", +% 49th Annual Allerton Conference on Communication, Control, and Computing (Allerton), +% September, 2011, pp. 1492-1499 +% +% opt objective value: 5812.64 $/hr +% +% Bus Voltage Generation Load Lambda($/MVA-hr) +% # Mag(pu) Ang(deg) P (MW) Q (MVAr) P (MW) Q (MVAr) P Q +% ----- ------- -------- -------- -------- -------- -------- ------- ------- +% 1 1.100 0.000* 148.07 54.70 110.00 40.00 37.575 - +% 2 0.926 7.259 170.01 -8.79 110.00 40.00 30.101 - +% 3 0.900 -17.267 0.00 -4.84 95.00 50.00 45.537 - +% -------- -------- -------- -------- +% Total: 318.07 41.06 315.00 130.00 +% +% Copyright (c) 2011 by The Institute of Electrical and Electronics Engineers (IEEE) +% Licensed under the Creative Commons Attribution 4.0 +% International license, http://creativecommons.org/licenses/by/4.0/ +% +% Contact M.E. Brennan (me.brennan@ieee.org) for inquries on further reuse of +% this dataset. +% +% Modified to have additional storage capacity on bus 2 + +function mpc = pglib_opf_case3_lmbd +mpc.version = '2'; +mpc.baseMVA = 100.0; + +%% bus data +% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin +mpc.bus = [ + 1 3 110.0 40.0 0.0 0.0 1 1.00000 0.00000 240.0 1 1.10000 0.90000; + 2 2 110.0 40.0 0.0 0.0 1 1.00000 0.00000 240.0 1 1.10000 0.90000; + 3 2 95.0 50.0 0.0 0.0 1 1.00000 0.00000 240.0 1 1.10000 0.90000; +]; + +%% generator data +% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin +mpc.gen = [ + 1 1000.0 0.0 1000.0 -1000.0 1.0 100.0 1 2000.0 0.0; + 2 1000.0 0.0 1000.0 -1000.0 1.0 100.0 1 2000.0 0.0; + 3 0.0 0.0 1000.0 -1000.0 1.0 100.0 1 0.0 0.0; +]; + +%% generator cost data +% 2 startup shutdown n c(n-1) ... c0 +mpc.gencost = [ + 2 0.0 0.0 3 0.110000 5.000000 0.000000; + 2 0.0 0.0 3 0.085000 1.200000 0.000000; + 2 0.0 0.0 3 0.000000 0.000000 0.000000; +]; + +%% branch data +% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax +mpc.branch = [ + 1 3 0.065 0.62 0.45 9000.0 9000.0 9000.0 0.0 0.0 1 -30.0 30.0; + 3 2 0.025 0.75 0.7 50.0 50.0 50.0 0.0 0.0 1 -30.0 30.0; + 1 2 0.042 0.9 0.3 9000.0 9000.0 9000.0 0.0 0.0 1 -30.0 30.0; +]; + +%% storage data +% storage_bus ps qs energy energy_rating charge_rating discharge_rating charge_efficiency discharge_efficiency thermal_rating qmin qmax r x p_loss q_loss status +mpc.storage = [ + 2 0.0 0.0 1.00 200.0 100.0 72.0 0.90 0.85 1000.0 -1000.0 1000.0 0.1 0.01 0.0 0.0 1; +]; + +% INFO : === Translation Options === +% INFO : Phase Angle Bound: 30.0 (deg.) +% INFO : Setting Flat Start +% INFO : +% INFO : === Generator Bounds Update Notes === +% INFO : +% INFO : === Base KV Replacement Notes === +% INFO : +% INFO : === Transformer Setting Replacement Notes === +% INFO : +% INFO : === Line Capacity Monotonicity Notes === +% INFO : Updated Thermal Rating: on line 1-3 : Rate B, Rate C - 0.0, 0.0 -> 9000.0, 9000.0 +% INFO : Updated Thermal Rating: on line 3-2 : Rate B, Rate C - 0.0, 0.0 -> 50.0, 50.0 +% INFO : Updated Thermal Rating: on line 1-2 : Rate B, Rate C - 0.0, 0.0 -> 9000.0, 9000.0 +% INFO : +% INFO : === Voltage Setpoint Replacement Notes === +% INFO : Bus 1 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 2 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 3 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : +% INFO : === Generator Setpoint Replacement Notes === +% INFO : Gen at bus 1 : Pg=0.0, Qg=0.0 -> Pg=1000.0, Qg=0.0 +% INFO : Gen at bus 1 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 2 : Pg=0.0, Qg=0.0 -> Pg=1000.0, Qg=0.0 +% INFO : Gen at bus 2 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 3 : Pg=0.0, Qg=0.0 -> Pg=0.0, Qg=0.0 +% INFO : Gen at bus 3 : Vg=1.0 -> Vg=1.0 +% INFO : +% INFO : === Writing Matpower Case File Notes === diff --git a/src/mpopf.jl b/src/mpopf.jl index 3b9962c..c6960c3 100644 --- a/src/mpopf.jl +++ b/src/mpopf.jl @@ -300,74 +300,74 @@ function build_base_rect_mpopf(core, data, N, Nbus) end - - function build_polar_mpopf(data, Nbus, N; backend = nothing, T = Float64, storage_complementarity_constraint = false, kwargs...) core = ExaCore(T; backend = backend) vars, cons = build_base_polar_mpopf(core, data, N, Nbus) - va, vm, pg, qg, p, q, pst, qst, I2, qint, E = vars - - (c_ref_angle, - c_to_active_power_flow, - c_to_reactive_power_flow, - c_from_active_power_flow, - c_from_reactive_power_flow, - c_phase_angle_diff, - c_active_power_balance, - c_reactive_power_balance, - c_from_thermal_limit, - c_to_thermal_limit, - c_ramp_rate) = cons + if length(data.storarray) > 0 + va, vm, pg, qg, p, q, pst, qst, I2, qint, E = vars - #charge or discharge from battery to grid - pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) - pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) + (c_ref_angle, + c_to_active_power_flow, + c_to_reactive_power_flow, + c_from_active_power_flow, + c_from_reactive_power_flow, + c_phase_angle_diff, + c_active_power_balance, + c_reactive_power_balance, + c_from_thermal_limit, + c_to_thermal_limit, + c_ramp_rate) = cons - #adding storage constraints - c_active_storage_power = constraint(core, c_active_stor_power(s, pst[s.c, s.t], pstd[s.c, s.t], pstc[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + #charge or discharge from battery to grid + pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) - c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + #adding storage constraints + c_active_storage_power = constraint(core, c_active_stor_power(s, pst[s.c, s.t], pstd[s.c, s.t], pstc[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - c_ohms = constraint(core, c_ohms_polar(pst[s.c, s.t], qst[s.c, s.t], vm[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) + c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - c_storage_state = constraint(core, c_stor_state(s, E[s.c, s.t], E[s.c, s.t - 1], pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) + c_ohms = constraint(core, c_ohms_polar(pst[s.c, s.t], qst[s.c, s.t], vm[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) - c_storage_state_init = constraint(core, c_stor_state(s, E[s.c, s.t], s.Einit, pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 1]) + c_storage_state = constraint(core, c_stor_state(s, E[s.c, s.t], E[s.c, s.t - 1], pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) - c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) + c_storage_state_init = constraint(core, c_stor_state(s, E[s.c, s.t], s.Einit, pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 1]) - c_discharge_thermal_limit = constraint(core, c_discharge_lim(pstd[s.c, s.t], pstc[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) + c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) - #Complimentarity constraint - if storage_complementarity_constraint - c_complementarity = constraint(core, c_comp(pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray) - end - + c_discharge_thermal_limit = constraint(core, c_discharge_lim(pstd[s.c, s.t], pstc[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) - cons = ( - c_ref_angle = c_ref_angle, - c_to_active_power_flow = c_to_active_power_flow, - c_to_reactive_power_flow = c_to_reactive_power_flow, - c_from_active_power_flow = c_from_active_power_flow, - c_from_reactive_power_flow = c_from_reactive_power_flow, - c_phase_angle_diff = c_phase_angle_diff, - c_active_power_balance = c_active_power_balance, - c_reactive_power_balance = c_reactive_power_balance, - c_from_thermal_limit = c_from_thermal_limit, - c_to_thermal_limit = c_to_thermal_limit, - c_ramp_rate = c_ramp_rate, - c_active_storage_power = c_active_storage_power, - c_reactive_storage_power = c_reactive_storage_power, - c_ohms = c_ohms, - c_storage_state = c_storage_state, - c_storage_state_init = c_storage_state_init, - c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, - c_discharge_thermal_limit = c_discharge_thermal_limit - ) + #Complimentarity constraint + if storage_complementarity_constraint + c_complementarity = constraint(core, c_comp(pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray) + end + + + cons = ( + c_ref_angle = c_ref_angle, + c_to_active_power_flow = c_to_active_power_flow, + c_to_reactive_power_flow = c_to_reactive_power_flow, + c_from_active_power_flow = c_from_active_power_flow, + c_from_reactive_power_flow = c_from_reactive_power_flow, + c_phase_angle_diff = c_phase_angle_diff, + c_active_power_balance = c_active_power_balance, + c_reactive_power_balance = c_reactive_power_balance, + c_from_thermal_limit = c_from_thermal_limit, + c_to_thermal_limit = c_to_thermal_limit, + c_ramp_rate = c_ramp_rate, + c_active_storage_power = c_active_storage_power, + c_reactive_storage_power = c_reactive_storage_power, + c_ohms = c_ohms, + c_storage_state = c_storage_state, + c_storage_state_init = c_storage_state_init, + c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, + c_discharge_thermal_limit = c_discharge_thermal_limit + ) - vars = va, vm, pg, qg, p, q, pst, qst, I2, qint, E, pstd, pstc + vars = va, vm, pg, qg, p, q, pst, qst, I2, qint, E, pstd, pstc + end model = ExaModel(core; kwargs...) return model, vars, cons @@ -378,67 +378,69 @@ function build_rect_mpopf(data, Nbus, N; backend = nothing, T = Float64, storage vars, cons = build_base_rect_mpopf(core, data, N, Nbus) - vr, vim, pg, qg, p, q, pst, qst, I2, qint, E = vars - - (c_ref_angle, - c_to_active_power_flow, - c_to_reactive_power_flow, - c_from_active_power_flow, - c_from_reactive_power_flow, - c_phase_angle_diff, - c_active_power_balance, - c_reactive_power_balance, - c_from_thermal_limit, - c_to_thermal_limit, - c_voltage_magnitude, - c_ramp_rate) = cons - - #charge or discharge from battery to grid - pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) - pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) - - #adding storage constraints - c_active_storage_power = constraint(core, c_active_stor_power(s, pst[s.c, s.t], pstd[s.c, s.t], pstc[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + if length(data.storarray) > 0 + vr, vim, pg, qg, p, q, pst, qst, I2, qint, E = vars - c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + (c_ref_angle, + c_to_active_power_flow, + c_to_reactive_power_flow, + c_from_active_power_flow, + c_from_reactive_power_flow, + c_phase_angle_diff, + c_active_power_balance, + c_reactive_power_balance, + c_from_thermal_limit, + c_to_thermal_limit, + c_voltage_magnitude, + c_ramp_rate) = cons - c_ohms = constraint(core, c_ohms_rect(pst[s.c, s.t], qst[s.c, s.t], vr[s.bus, s.t], vim[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) + #charge or discharge from battery to grid + pstc = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pcmax, 1, N)) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) + + #adding storage constraints + c_active_storage_power = constraint(core, c_active_stor_power(s, pst[s.c, s.t], pstd[s.c, s.t], pstc[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - c_storage_state = constraint(core, c_stor_state(s, E[s.c, s.t], E[s.c, s.t - 1], pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) + c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - c_storage_state_init = constraint(core, c_stor_state(s, E[s.c, s.t], s.Einit, pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 1]) + c_ohms = constraint(core, c_ohms_rect(pst[s.c, s.t], qst[s.c, s.t], vr[s.bus, s.t], vim[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) - c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) + c_storage_state = constraint(core, c_stor_state(s, E[s.c, s.t], E[s.c, s.t - 1], pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) - c_discharge_thermal_limit = constraint(core, c_discharge_lim(pstd[s.c, s.t], pstc[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) + c_storage_state_init = constraint(core, c_stor_state(s, E[s.c, s.t], s.Einit, pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray[:, 1]) - #Complimentarity constraint - if storage_complementarity_constraint - c_complementarity = constraint(core, c_comp(pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray) - end + c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) - cons = ( - c_ref_angle = c_ref_angle, - c_to_active_power_flow = c_to_active_power_flow, - c_to_reactive_power_flow = c_to_reactive_power_flow, - c_from_active_power_flow = c_from_active_power_flow, - c_from_reactive_power_flow = c_from_reactive_power_flow, - c_phase_angle_diff = c_phase_angle_diff, - c_active_power_balance = c_active_power_balance, - c_reactive_power_balance = c_reactive_power_balance, - c_from_thermal_limit = c_from_thermal_limit, - c_to_thermal_limit = c_to_thermal_limit, - c_voltage_magnitude = c_voltage_magnitude, - c_ramp_rate = c_ramp_rate, - c_active_storage_power = c_active_storage_power, - c_reactive_storage_power = c_reactive_storage_power, - c_ohms = c_ohms, - c_storage_state = c_storage_state, - c_storage_state_init = c_storage_state_init, - c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, - c_discharge_thermal_limit = c_discharge_thermal_limit - ) - vars = vr, vim, pg, qg, p, q, pst, qst, I2, qint, E, pstc, pstd + c_discharge_thermal_limit = constraint(core, c_discharge_lim(pstd[s.c, s.t], pstc[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) + + #Complimentarity constraint + if storage_complementarity_constraint + c_complementarity = constraint(core, c_comp(pstc[s.c, s.t], pstd[s.c, s.t]) for s in data.storarray) + end + + cons = ( + c_ref_angle = c_ref_angle, + c_to_active_power_flow = c_to_active_power_flow, + c_to_reactive_power_flow = c_to_reactive_power_flow, + c_from_active_power_flow = c_from_active_power_flow, + c_from_reactive_power_flow = c_from_reactive_power_flow, + c_phase_angle_diff = c_phase_angle_diff, + c_active_power_balance = c_active_power_balance, + c_reactive_power_balance = c_reactive_power_balance, + c_from_thermal_limit = c_from_thermal_limit, + c_to_thermal_limit = c_to_thermal_limit, + c_voltage_magnitude = c_voltage_magnitude, + c_ramp_rate = c_ramp_rate, + c_active_storage_power = c_active_storage_power, + c_reactive_storage_power = c_reactive_storage_power, + c_ohms = c_ohms, + c_storage_state = c_storage_state, + c_storage_state_init = c_storage_state_init, + c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, + c_discharge_thermal_limit = c_discharge_thermal_limit + ) + vars = vr, vim, pg, qg, p, q, pst, qst, I2, qint, E, pstc, pstd + end model = ExaModel(core; kwargs...) return model, vars, cons @@ -450,59 +452,61 @@ function build_polar_mpopf(data, Nbus, N, discharge_func::Function; backend = no vars, cons = build_base_polar_mpopf(core, data, N, Nbus) - va, vm, pg, qg, p, q, pst, qst, I2, qint, E = vars - - (c_ref_angle, - c_to_active_power_flow, - c_to_reactive_power_flow, - c_from_active_power_flow, - c_from_reactive_power_flow, - c_phase_angle_diff, - c_active_power_balance, - c_reactive_power_balance, - c_from_thermal_limit, - c_to_thermal_limit, - c_ramp_rate) = cons - - #discharge or charge from battery to grid (positive or negative) - pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) - - c_active_storage_power = constraint(core, c_active_storage_power_smooth(s, pst[s.c, s.t], pstd[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - - c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - - c_ohms = constraint(core, c_ohms_polar(pst[s.c, s.t], qst[s.c, s.t], vm[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) - - c_storage_state = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], E[s.c, s.t - 1], discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) - - c_storage_state_init = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], s.Einit, discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 1]) - - c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) - - c_discharge_thermal_limit = constraint(core, c_discharge_limit_smooth(pstd[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) - - cons = ( - c_ref_angle = c_ref_angle, - c_to_active_power_flow = c_to_active_power_flow, - c_to_reactive_power_flow = c_to_reactive_power_flow, - c_from_active_power_flow = c_from_active_power_flow, - c_from_reactive_power_flow = c_from_reactive_power_flow, - c_phase_angle_diff = c_phase_angle_diff, - c_active_power_balance = c_active_power_balance, - c_reactive_power_balance = c_reactive_power_balance, - c_from_thermal_limit = c_from_thermal_limit, - c_to_thermal_limit = c_to_thermal_limit, - c_ramp_rate = c_ramp_rate, - c_active_storage_power = c_active_storage_power, - c_reactive_storage_power = c_reactive_storage_power, - c_ohms = c_ohms, - c_storage_state = c_storage_state, - c_storage_state_init = c_storage_state_init, - c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, - c_discharge_thermal_limit = c_discharge_thermal_limit - ) + if length(data.storarray) > 0 + va, vm, pg, qg, p, q, pst, qst, I2, qint, E = vars + + (c_ref_angle, + c_to_active_power_flow, + c_to_reactive_power_flow, + c_from_active_power_flow, + c_from_reactive_power_flow, + c_phase_angle_diff, + c_active_power_balance, + c_reactive_power_balance, + c_from_thermal_limit, + c_to_thermal_limit, + c_ramp_rate) = cons + + #discharge or charge from battery to grid (positive or negative) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) + + c_active_storage_power = constraint(core, c_active_storage_power_smooth(s, pst[s.c, s.t], pstd[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + + c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + + c_ohms = constraint(core, c_ohms_polar(pst[s.c, s.t], qst[s.c, s.t], vm[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) + + c_storage_state = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], E[s.c, s.t - 1], discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) + + c_storage_state_init = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], s.Einit, discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 1]) + + c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) + + c_discharge_thermal_limit = constraint(core, c_discharge_limit_smooth(pstd[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) + + cons = ( + c_ref_angle = c_ref_angle, + c_to_active_power_flow = c_to_active_power_flow, + c_to_reactive_power_flow = c_to_reactive_power_flow, + c_from_active_power_flow = c_from_active_power_flow, + c_from_reactive_power_flow = c_from_reactive_power_flow, + c_phase_angle_diff = c_phase_angle_diff, + c_active_power_balance = c_active_power_balance, + c_reactive_power_balance = c_reactive_power_balance, + c_from_thermal_limit = c_from_thermal_limit, + c_to_thermal_limit = c_to_thermal_limit, + c_ramp_rate = c_ramp_rate, + c_active_storage_power = c_active_storage_power, + c_reactive_storage_power = c_reactive_storage_power, + c_ohms = c_ohms, + c_storage_state = c_storage_state, + c_storage_state_init = c_storage_state_init, + c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, + c_discharge_thermal_limit = c_discharge_thermal_limit + ) - vars = va, vm, pg, qg, p, q, pst, qst, I2, qint, E, pstd + vars = va, vm, pg, qg, p, q, pst, qst, I2, qint, E, pstd + end model = ExaModel(core; kwargs...) return model, vars, cons @@ -511,65 +515,66 @@ end function build_rect_mpopf(data, Nbus, N, discharge_func::Function; backend = nothing, T = Float64, kwargs...) core = ExaCore(T; backend = backend) - vars, cons = build_base_rect_mpopf(core, data, N, Nbus) - vr, vim, pg, qg, p, q, pst, qst, I2, qint, E = vars - - (c_ref_angle, - c_to_active_power_flow, - c_to_reactive_power_flow, - c_from_active_power_flow, - c_from_reactive_power_flow, - c_phase_angle_diff, - c_active_power_balance, - c_reactive_power_balance, - c_from_thermal_limit, - c_to_thermal_limit, - c_voltage_magnitude, - c_ramp_rate) = cons - - - #discharge or charge from battery to grid (can be positive or negative) - pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) - - c_active_storage_power = constraint(core, c_active_storage_power_smooth(s, pst[s.c, s.t], pstd[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - - c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) - - c_ohms = constraint(core, c_ohms_rect(pst[s.c, s.t], qst[s.c, s.t], vr[s.bus, s.t], vim[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) - - c_storage_state = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], E[s.c, s.t - 1], discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) - - c_storage_state_init = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], s.Einit, discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 1]) - - c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) - - c_discharge_thermal_limit = constraint(core, c_discharge_limit_smooth(pstd[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) - - cons = ( - c_ref_angle = c_ref_angle, - c_to_active_power_flow = c_to_active_power_flow, - c_to_reactive_power_flow = c_to_reactive_power_flow, - c_from_active_power_flow = c_from_active_power_flow, - c_from_reactive_power_flow = c_from_reactive_power_flow, - c_phase_angle_diff = c_phase_angle_diff, - c_active_power_balance = c_active_power_balance, - c_reactive_power_balance = c_reactive_power_balance, - c_from_thermal_limit = c_from_thermal_limit, - c_to_thermal_limit = c_to_thermal_limit, - c_voltage_magnitude = c_voltage_magnitude, - c_ramp_rate = c_ramp_rate, - c_active_storage_power = c_active_storage_power, - c_reactive_storage_power = c_reactive_storage_power, - c_ohms = c_ohms, - c_storage_state = c_storage_state, - c_storage_state_init = c_storage_state_init, - c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, - c_discharge_thermal_limit = c_discharge_thermal_limit - ) + if length(data.storarray) > 0 + vr, vim, pg, qg, p, q, pst, qst, I2, qint, E = vars + + (c_ref_angle, + c_to_active_power_flow, + c_to_reactive_power_flow, + c_from_active_power_flow, + c_from_reactive_power_flow, + c_phase_angle_diff, + c_active_power_balance, + c_reactive_power_balance, + c_from_thermal_limit, + c_to_thermal_limit, + c_voltage_magnitude, + c_ramp_rate) = cons + + + #discharge or charge from battery to grid (can be positive or negative) + pstd = variable(core, size(data.storage, 1), N; lvar = zeros(size(data.storarray)), uvar = repeat(data.pdmax, 1, N)) + + c_active_storage_power = constraint(core, c_active_storage_power_smooth(s, pst[s.c, s.t], pstd[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + + c_reactive_storage_power = constraint(core, c_reactive_stor_power(s, qst[s.c, s.t], qint[s.c, s.t], I2[s.c, s.t]) for s in data.storarray) + + c_ohms = constraint(core, c_ohms_rect(pst[s.c, s.t], qst[s.c, s.t], vr[s.bus, s.t], vim[s.bus, s.t], I2[s.c, s.t]) for s in data.storarray) + + c_storage_state = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], E[s.c, s.t - 1], discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 2:N]) + + c_storage_state_init = constraint(core, c_storage_state_smooth(s, E[s.c, s.t], s.Einit, discharge_func, pstd[s.c, s.t]) for s in data.storarray[:, 1]) + + c_storage_transfer_thermal_limit = constraint(core, c_transfer_lim(s, pst[s.c, s.t], qst[s.c, s.t]) for s in data.storarray; lcon = lcon = fill(-Inf, size(data.storarray))) + + c_discharge_thermal_limit = constraint(core, c_discharge_limit_smooth(pstd[s.c, s.t]) for s in data.storarray; lcon = -repeat(data.srating, 1, N), ucon = repeat(data.srating, 1, N)) + + cons = ( + c_ref_angle = c_ref_angle, + c_to_active_power_flow = c_to_active_power_flow, + c_to_reactive_power_flow = c_to_reactive_power_flow, + c_from_active_power_flow = c_from_active_power_flow, + c_from_reactive_power_flow = c_from_reactive_power_flow, + c_phase_angle_diff = c_phase_angle_diff, + c_active_power_balance = c_active_power_balance, + c_reactive_power_balance = c_reactive_power_balance, + c_from_thermal_limit = c_from_thermal_limit, + c_to_thermal_limit = c_to_thermal_limit, + c_voltage_magnitude = c_voltage_magnitude, + c_ramp_rate = c_ramp_rate, + c_active_storage_power = c_active_storage_power, + c_reactive_storage_power = c_reactive_storage_power, + c_ohms = c_ohms, + c_storage_state = c_storage_state, + c_storage_state_init = c_storage_state_init, + c_storage_transfer_thermal_limit = c_storage_transfer_thermal_limit, + c_discharge_thermal_limit = c_discharge_thermal_limit + ) - vars = vr, vim, pg, qg, p, q, pst, qst, I2, qint, E, pstd + vars = vr, vim, pg, qg, p, q, pst, qst, I2, qint, E, pstd + end model = ExaModel(core; kwargs...) return model, vars, cons diff --git a/test/runtests.jl b/test/runtests.jl index 129a83c..baf3d94 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt +using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt, JuMP, ExaModels const CONFIGS = [ (Float32, nothing), @@ -18,19 +18,13 @@ if CUDA.has_cuda_gpu() ) end -numeric_tolerance(::Type{Float32}) = 1e-2 -numeric_tolerance(::Type{Float64}) = 1e-4 - - function runtests() @testset "ExaModelsPower test" begin - #Test static opf - #data_pm = PowerModels.parse_file("data/pglib_opf_case3_lmbd.m") - - data, dicts = ExaModelsPower.parse_ac_power_data("pglib_opf_case3_lmbd.m") - for (T, backend) in CONFIGS + #Test static opf + data, dicts = ExaModelsPower.parse_ac_power_data("pglib_opf_case3_lmbd.m") + #Polar tests m, v, c = eval(opf_model)("pglib_opf_case3_lmbd.m"; T=T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @@ -39,8 +33,8 @@ function runtests() nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) result_pm = solve_opf("data/pglib_opf_case3_lmbd.m",ACPPowerModel, nlp_solver) - @testset "$(T), $(backend), polar" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED + @testset "static, $(T), $(backend), polar" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) for key in keys(dicts.gen) @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*100) @@ -72,8 +66,8 @@ function runtests() nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) result_pm = solve_opf("data/pglib_opf_case3_lmbd.m", ACRPowerModel, nlp_solver) - @testset "$(T), $(backend), rect" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED + @testset "static, $(T), $(backend), rect" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) for key in keys(dicts.gen) @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*100) @@ -96,6 +90,180 @@ function runtests() @test isapprox(Array(solution(result, var))[6], result_pm["solution"]["branch"]["1"][string(st_var, "t")], atol = result.options.tol*100) end end + #Test MP + #Curve = [1, .9, .8, .95, 1] + true_sol = 25384.366465 + + function example_func(d, srating) + return d + .2/srating*d^2 + end + + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1]; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), curve, polar" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #w function + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), curve, polar, func" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), curve, rect" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #w function + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), curve, rect" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #Pregenerated Pd and Qd + true_sol = 29049.351564 + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), pregen, polar" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #w function + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), pregen, polar, func" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), pregen, rect" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #w function + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP, $(T), $(backend), pregen, rect, func" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #Test MP w storage + + #Curve = [1, .9, .8, .95, 1] + true_sol = 25358.827525 + + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), curve, polar" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), curve, rect" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #With complementarity constraint + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend, storage_complementarity_constraint = true) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), curve, polar, complementarity" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect, storage_complementarity_constraint = true) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), curve, rect, complementarity" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #With function + true_sol = 25354.331998 + + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), curve, polar, func" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), curve, rect, func" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #Pregenerated Pd and Qd + true_sol = 29023.69118 + + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), pregen, polar" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), pregen, rect" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #With complementarity + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, storage_complementarity_constraint = true) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), pregen, polar, complementarity" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, form = :rect, storage_complementarity_constraint = true) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), pregen, rect, complementarity" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + + #With function + true_sol = 29019.172473 + + #Polar + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), pregen, polar, func" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end + #Rect + m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(T), $(backend), pregen, rect, func" begin + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + end end end end From 1f3970a4f08f0b458c88f570b01e327c13d98660 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Thu, 3 Apr 2025 09:07:15 -0400 Subject: [PATCH 03/21] removed complementarity constraints from testing --- test/runtests.jl | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index baf3d94..14e85fa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -179,22 +179,6 @@ function runtests() @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) end - #With complementarity constraint - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend, storage_complementarity_constraint = true) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), curve, polar, complementarity" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect, storage_complementarity_constraint = true) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), curve, rect, complementarity" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #With function true_sol = 25354.331998 @@ -231,22 +215,6 @@ function runtests() @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) end - #With complementarity - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, storage_complementarity_constraint = true) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), pregen, polar, complementarity" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, form = :rect, storage_complementarity_constraint = true) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), pregen, rect, complementarity" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #With function true_sol = 29019.172473 From 719b4c5efb4f343b3940a7203c800f0e4e3c0734 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Sat, 12 Apr 2025 11:53:59 -0400 Subject: [PATCH 04/21] Added cases for tests --- test/opf_tests.jl | 51 ++++++++++ test/runtests.jl | 251 ++++++++++++++++++++-------------------------- 2 files changed, 160 insertions(+), 142 deletions(-) create mode 100644 test/opf_tests.jl diff --git a/test/opf_tests.jl b/test/opf_tests.jl new file mode 100644 index 0000000..58dacb8 --- /dev/null +++ b/test/opf_tests.jl @@ -0,0 +1,51 @@ +function test_case3(result, result_pm, dicts, pg, qg, p, q) + test_static_case(result, result_pm, dicts, pg, qg) + + #Branches are encoded differently in solutions, so matches are hard coded + vars_dict = Dict("p" => p, "q" => q) + for st_var in ["p", "q"] + var = vars_dict[st_var] + @test isapprox(Array(solution(result, var))[1], result_pm["solution"]["branch"]["2"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[2], result_pm["solution"]["branch"]["3"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[3], result_pm["solution"]["branch"]["1"][string(st_var, "f")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[4], result_pm["solution"]["branch"]["2"][string(st_var, "t")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[5], result_pm["solution"]["branch"]["3"][string(st_var, "t")], atol = result.options.tol*100) + @test isapprox(Array(solution(result, var))[6], result_pm["solution"]["branch"]["1"][string(st_var, "t")], atol = result.options.tol*100) + end +end + +function test_static_case(result, result_pm, dicts, pg, qg) + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) + for key in keys(dicts.gen) + @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*1000) + @test isapprox(Array(solution(result, qg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["qg"], atol = result.options.tol*1000) + end +end + +function test_polar_voltage(result, result_pm, dicts, va, vm) + for key in keys(dicts.bus) + @test isapprox(Array(solution(result, va))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["va"], atol = result.options.tol*100) + @test isapprox(Array(solution(result, vm))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vm"], rtol = result.options.tol*100) + end +end + +function test_rect_voltage(result, result_pm, dicts, vr, vim) + for key in keys(dicts.bus) + @test isapprox(Array(solution(result, vr))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vr"], rtol = result.options.tol*100) + @test isapprox(Array(solution(result, vim))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vi"], atol = result.options.tol*100) + end +end + +function test_case5(result, result_pm, dicts, pg, qg, p, q) + test_static_case(result, result_pm, dicts, pg, qg) +end + +function test_case14(result, result_pm, dicts, pg, qg, p, q) + test_static_case(result, result_pm, dicts, pg, qg) +end + +function test_mp_case(result, true_sol) + @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL + @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 14e85fa..e3fe9a3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,7 @@ using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt, JuMP, ExaModels +include("opf_tests.jl") + const CONFIGS = [ (Float32, nothing), (Float64, nothing), @@ -18,147 +20,120 @@ if CUDA.has_cuda_gpu() ) end +test_cases = [("data/pglib_opf_case3_lmbd.m", "case3", test_case3), + ("data/pglib_opf_case5_pjm.m", "case5", test_case5), + ("data/pglib_opf_case14_ieee.m", "case14", test_case14)] + + +#Curve = [1, .9, .8, .95, 1] +true_sol_case3_curve = 25384.366465 +true_sol_case3_pregen = 29049.351564 +true_sol_case5_curve = 78491.04247 +true_sol_case5_pregen = 87816.396884 + +mp_test_cases = [("data/pglib_opf_case3_lmbd.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), + ("data/pglib_opf_case5_pjm.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] + + +function example_func(d, srating) + return d + .2/srating*d^2 +end + function runtests() @testset "ExaModelsPower test" begin for (T, backend) in CONFIGS - #Test static opf - data, dicts = ExaModelsPower.parse_ac_power_data("pglib_opf_case3_lmbd.m") - #Polar tests - m, v, c = eval(opf_model)("pglib_opf_case3_lmbd.m"; T=T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - va, vm, pg, qg, p, q = v - - nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) - result_pm = solve_opf("data/pglib_opf_case3_lmbd.m",ACPPowerModel, nlp_solver) - - @testset "static, $(T), $(backend), polar" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) - for key in keys(dicts.gen) - @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*100) - @test isapprox(Array(solution(result, qg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["qg"], atol = result.options.tol*100) - end - for key in keys(dicts.bus) - @test isapprox(Array(solution(result, va))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["va"], atol = result.options.tol*100) - @test isapprox(Array(solution(result, vm))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vm"], atol = result.options.tol*100) + for (filename, case, test_function) in test_cases + #Test static opf + data, dicts = ExaModelsPower.parse_ac_power_data(filename) + + #Polar tests + m, v, c = opf_model(filename; T=T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + va, vm, pg, qg, p, q = v + + nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) + result_pm = solve_opf(filename,ACPPowerModel, nlp_solver) + + @testset "$(case), static, $(T), $(backend), polar" begin + eval(test_function)(result, result_pm, dicts, pg, qg, p, q) + test_polar_voltage(result, result_pm, dicts, va, vm) end - #Branches are encoded differently in solutions, so matches are hard coded - vars_dict = Dict("p" => p, "q" => q) - for st_var in ["p", "q"] - var = vars_dict[st_var] - @test isapprox(Array(solution(result, var))[1], result_pm["solution"]["branch"]["2"][string(st_var, "f")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[2], result_pm["solution"]["branch"]["3"][string(st_var, "f")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[3], result_pm["solution"]["branch"]["1"][string(st_var, "f")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[4], result_pm["solution"]["branch"]["2"][string(st_var, "t")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[5], result_pm["solution"]["branch"]["3"][string(st_var, "t")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[6], result_pm["solution"]["branch"]["1"][string(st_var, "t")], atol = result.options.tol*100) + #Rectangular tests + m, v, c = eval(opf_model)(filename; T=T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + vr, vim, pg, qg, p, q = v + + nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) + result_pm = solve_opf(filename, ACRPowerModel, nlp_solver) + + @testset "$(case), static, $(T), $(backend), rect" begin + eval(test_function)(result, result_pm, dicts, pg, qg, p, q) + test_rect_voltage(result, result_pm, dicts, vr, vim) end end + - #Rectangular tests - m, v, c = eval(opf_model)("pglib_opf_case3_lmbd.m"; T=T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - vr, vim, pg, qg, p, q = v - - nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) - result_pm = solve_opf("data/pglib_opf_case3_lmbd.m", ACRPowerModel, nlp_solver) - - @testset "static, $(T), $(backend), rect" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) - for key in keys(dicts.gen) - @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*100) - @test isapprox(Array(solution(result, qg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["qg"], atol = result.options.tol*100) + #Test MP + for (filename, case, Pd_pregen, Qd_pregen, true_sol_curve, true_sol_pregen) in mp_test_cases + #Curve = [1, .9, .8, .95, 1] + + #Polar + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), curve, polar" begin + test_mp_case(result, true_sol_curve) end - for key in keys(dicts.bus) - @test isapprox(Array(solution(result, vr))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vr"], atol = result.options.tol*100) - @test isapprox(Array(solution(result, vim))[dicts.bus[key]], result_pm["solution"]["bus"][string(key)]["vi"], atol = result.options.tol*100) + #w function + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), curve, polar, func" begin + test_mp_case(result, true_sol_curve) end - - #Branches are encoded differently in solutions, so matches are hard coded - vars_dict = Dict("p" => p, "q" => q) - for st_var in ["p", "q"] - var = vars_dict[st_var] - @test isapprox(Array(solution(result, var))[1], result_pm["solution"]["branch"]["2"][string(st_var, "f")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[2], result_pm["solution"]["branch"]["3"][string(st_var, "f")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[3], result_pm["solution"]["branch"]["1"][string(st_var, "f")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[4], result_pm["solution"]["branch"]["2"][string(st_var, "t")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[5], result_pm["solution"]["branch"]["3"][string(st_var, "t")], atol = result.options.tol*100) - @test isapprox(Array(solution(result, var))[6], result_pm["solution"]["branch"]["1"][string(st_var, "t")], atol = result.options.tol*100) + #Rect + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), curve, rect" begin + test_mp_case(result, true_sol_curve) + end + #w function + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), curve, rect" begin + test_mp_case(result, true_sol_curve) + end + + + #Pregenerated Pd and Qd + #Polar + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), pregen, polar" begin + test_mp_case(result, true_sol_pregen) + end + #w function + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), pregen, polar, func" begin + test_mp_case(result, true_sol_pregen) end - end - #Test MP - #Curve = [1, .9, .8, .95, 1] - true_sol = 25384.366465 - - function example_func(d, srating) - return d + .2/srating*d^2 - end - - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1]; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), curve, polar" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #w function - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), curve, polar, func" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), curve, rect" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #w function - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), curve, rect" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - - #Pregenerated Pd and Qd - true_sol = 29049.351564 - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), pregen, polar" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #w function - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), pregen, polar, func" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), pregen, rect" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) - end - #w function - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP, $(T), $(backend), pregen, rect, func" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + #Rect + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), pregen, rect" begin + test_mp_case(result, true_sol_pregen) + end + #w function + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), pregen, rect, func" begin + test_mp_case(result, true_sol_pregen) + end end - + #Test MP w storage #Curve = [1, .9, .8, .95, 1] @@ -168,15 +143,13 @@ function runtests() m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), curve, polar" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end #Rect m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), curve, rect" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end #With function @@ -186,15 +159,13 @@ function runtests() m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), curve, polar, func" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end #Rect m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), curve, rect, func" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end #Pregenerated Pd and Qd @@ -204,15 +175,13 @@ function runtests() m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), pregen, polar" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end #Rect m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), pregen, rect" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end #With function @@ -222,15 +191,13 @@ function runtests() m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), pregen, polar, func" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end #Rect m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(T), $(backend), pregen, rect, func" begin - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL - @test isapprox(result.objective, true_sol, rtol = result.options.tol*100) + test_mp_case(result, true_sol) end end end From 4870fb4d78f6fb9cd37b2810cbbe33795cd47611 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Sun, 13 Apr 2025 18:10:18 -0400 Subject: [PATCH 05/21] CI, updated test functions --- .github/workflows/ci.yml | 53 +++++++ data/case5_5split.Pd | 5 + data/case5_5split.Qd | 5 + data/pglib_opf_case5_pjm_mod.m | 125 +++++++++++++++ test/opf_tests.jl | 31 +++- test/runtests.jl | 278 ++++++++++++++++++++++++--------- 6 files changed, 413 insertions(+), 84 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 data/case5_5split.Pd create mode 100644 data/case5_5split.Qd create mode 100644 data/pglib_opf_case5_pjm_mod.m diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..96b81c2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + pull_request: + branches: + - main + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest, self-hosted] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Julia + uses: julia-actions/setup-julia@v2 + with: + version: '1.11' + + - name: Cache Julia artifacts + uses: actions/cache@v3 + with: + path: ~/.julia/artifacts + key: artifacts-${{ runner.os }}-${{ hashFiles('**/Project.toml') }}-${{ hashFiles('**/Manifest.toml') }} + restore-keys: artifacts-${{ runner.os }}- + + - name: Cache Julia packages + uses: actions/cache@v3 + with: + path: ~/.julia/compiled + key: compiled-${{ runner.os }}-${{ hashFiles('**/Project.toml') }}-${{ hashFiles('**/Manifest.toml') }} + restore-keys: compiled-${{ runner.os }}- + + - name: Install package dependencies + run: | + julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.precompile()' + + - name: Check for CUDA availability + id: check-cuda + shell: bash + run: | + if command -v nvidia-smi &> /dev/null; then + echo "cuda=true" >> $GITHUB_OUTPUT + else + echo "cuda=false" >> $GITHUB_OUTPUT + fi + + - name: Run tests + run: | + julia --project=. -e 'using Pkg; Pkg.test(; test_args=["cuda=${{ steps.check-cuda.outputs.cuda }}"])' \ No newline at end of file diff --git a/data/case5_5split.Pd b/data/case5_5split.Pd new file mode 100644 index 0000000..879775f --- /dev/null +++ b/data/case5_5split.Pd @@ -0,0 +1,5 @@ +0.00000000 0.00000000 0.00000000 0.0000000 0.00000000 +300.00000000 299.700000000 299.200000000 300.30000000 299.90000000 +300.00000000 299.100000000 299.400000000 299.90000000 301.10000000 +400.0000000 400.30892087 399.70779399 401.69866241 400.68356854 +0.00000000 0.00000000 0.00000000 0.0000000 0.00000000 diff --git a/data/case5_5split.Qd b/data/case5_5split.Qd new file mode 100644 index 0000000..5ddda17 --- /dev/null +++ b/data/case5_5split.Qd @@ -0,0 +1,5 @@ +0.00000000 0.00000000 0.00000000 0.0000000 0.00000000 +98.61000000 99.700000000 98.200000000 98.30000000 98.90000000 +98.61000000 99.100000000 99.400000000 99.90000000 99.10000000 +131.4700000 132.30892087 131.70779399 130.69866241 131.68356854 +0.00000000 0.00000000 0.00000000 0.0000000 0.00000000 diff --git a/data/pglib_opf_case5_pjm_mod.m b/data/pglib_opf_case5_pjm_mod.m new file mode 100644 index 0000000..c07ad5a --- /dev/null +++ b/data/pglib_opf_case5_pjm_mod.m @@ -0,0 +1,125 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% %%%%% +%%%% IEEE PES Power Grid Library - Optimal Power Flow - v23.07 %%%%% +%%%% (https://github.com/power-grid-lib/pglib-opf) %%%%% +%%%% Benchmark Group - Typical Operations %%%%% +%%%% 23 - July - 2023 %%%%% +%%%% %%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% CASE5 Power flow data for modified 5 bus, 5 gen case based on PJM 5-bus system +% Please see CASEFORMAT for details on the case file format. +% +% Based on data from ... +% F.Li and R.Bo, "Small Test Systems for Power System Economic Studies", +% Proceedings of the 2010 IEEE Power & Energy Society General Meeting +% +% Created by Rui Bo in 2006, modified in 2010, 2014. +% +% Copyright (c) 2010 by The Institute of Electrical and Electronics Engineers (IEEE) +% Licensed under the Creative Commons Attribution 4.0 +% International license, http://creativecommons.org/licenses/by/4.0/ +% +% Contact M.E. Brennan (me.brennan@ieee.org) for inquries on further reuse of +% this dataset. +% +% Modified to have 2 storage buses added +% +function mpc = pglib_opf_case5_pjm +mpc.version = '2'; +mpc.baseMVA = 100.0; + +%% area data +% area refbus +mpc.areas = [ + 1 4; +]; + +%% bus data +% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin +mpc.bus = [ + 1 2 0.0 0.0 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 2 1 300.0 98.61 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 3 2 300.0 98.61 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 4 3 400.0 131.47 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 5 2 0.0 0.0 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; +]; + +%% generator data +% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin +mpc.gen = [ + 1 20.0 0.0 30.0 -30.0 1.0 100.0 1 40.0 0.0; + 2 85.0 0.0 127.5 -127.5 1.0 100.0 1 170.0 0.0; + 3 260.0 0.0 390.0 -390.0 1.0 100.0 1 520.0 0.0; + 4 100.0 0.0 150.0 -150.0 1.0 100.0 1 200.0 0.0; + 5 300.0 0.0 450.0 -450.0 1.0 100.0 1 600.0 0.0; +]; + +%% generator cost data +% 2 startup shutdown n c(n-1) ... c0 +mpc.gencost = [ + 2 0.0 0.0 3 0.000000 14.000000 0.000000; + 2 0.0 0.0 3 0.000000 15.000000 0.000000; + 2 0.0 0.0 3 0.000000 30.000000 0.000000; + 2 0.0 0.0 3 0.000000 40.000000 0.000000; + 2 0.0 0.0 3 0.000000 10.000000 0.000000; +]; + +%% branch data +% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax +mpc.branch = [ + 1 2 0.00281 0.0281 0.00712 400.0 400.0 400.0 0.0 0.0 1 -30.0 30.0; + 1 4 0.00304 0.0304 0.00658 426 426 426 0.0 0.0 1 -30.0 30.0; + 1 5 0.00064 0.0064 0.03126 426 426 426 0.0 0.0 1 -30.0 30.0; + 2 3 0.00108 0.0108 0.01852 426 426 426 0.0 0.0 1 -30.0 30.0; + 3 4 0.00297 0.0297 0.00674 426 426 426 0.0 0.0 1 -30.0 30.0; + 4 5 0.00297 0.0297 0.00674 240.0 240.0 240.0 0.0 0.0 1 -30.0 30.0; +]; + +%% storage data +% storage_bus ps qs energy energy_rating charge_rating discharge_rating charge_efficiency discharge_efficiency thermal_rating qmin qmax r x p_loss q_loss status +mpc.storage = [ + 2 0.0 0.0 1.00 200.0 100.0 72.0 0.90 0.85 1000.0 -1000.0 1000.0 0.1 0.01 0.0 0.0 1; + 4 0.0 0.0 1.00 200.0 100.0 72.0 0.90 0.85 1000.0 -1000.0 1000.0 0.1 0.01 0.0 0.0 1; +]; + +% INFO : === Translation Options === +% INFO : Phase Angle Bound: 30.0 (deg.) +% INFO : Line Capacity Model: stat +% INFO : Setting Flat Start +% INFO : Line Capacity PAB: 15.0 (deg.) +% INFO : +% INFO : === Generator Bounds Update Notes === +% INFO : +% INFO : === Base KV Replacement Notes === +% INFO : +% INFO : === Transformer Setting Replacement Notes === +% INFO : +% INFO : === Line Capacity Stat Model Notes === +% INFO : Updated Thermal Rating: on line 1-4 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : Updated Thermal Rating: on line 1-5 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : Updated Thermal Rating: on line 2-3 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : Updated Thermal Rating: on line 3-4 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : +% INFO : === Line Capacity Monotonicity Notes === +% INFO : +% INFO : === Voltage Setpoint Replacement Notes === +% INFO : Bus 1 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 2 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 3 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 4 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 5 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : +% INFO : === Generator Setpoint Replacement Notes === +% INFO : Gen at bus 1 : Pg=40.0, Qg=0.0 -> Pg=20.0, Qg=0.0 +% INFO : Gen at bus 1 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 1 : Pg=170.0, Qg=0.0 -> Pg=85.0, Qg=0.0 +% INFO : Gen at bus 1 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 3 : Pg=323.49, Qg=0.0 -> Pg=260.0, Qg=0.0 +% INFO : Gen at bus 3 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 4 : Pg=0.0, Qg=0.0 -> Pg=100.0, Qg=0.0 +% INFO : Gen at bus 4 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 5 : Pg=466.51, Qg=0.0 -> Pg=300.0, Qg=0.0 +% INFO : Gen at bus 5 : Vg=1.0 -> Vg=1.0 +% INFO : +% INFO : === Writing Matpower Case File Notes === diff --git a/test/opf_tests.jl b/test/opf_tests.jl index 58dacb8..eced3fd 100644 --- a/test/opf_tests.jl +++ b/test/opf_tests.jl @@ -1,5 +1,5 @@ -function test_case3(result, result_pm, dicts, pg, qg, p, q) - test_static_case(result, result_pm, dicts, pg, qg) +function test_case3(result, result_pm, result_nlp_pm, dicts, pg, qg, p, q) + test_static_case(result, result_pm, result_nlp_pm, dicts, pg, qg) #Branches are encoded differently in solutions, so matches are hard coded vars_dict = Dict("p" => p, "q" => q) @@ -14,8 +14,8 @@ function test_case3(result, result_pm, dicts, pg, qg, p, q) end end -function test_static_case(result, result_pm, dicts, pg, qg) - @test result.status == MadNLP.SOLVE_SUCCEEDED || result.status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL +function test_static_case(result, result_pm, result_nlp_pm, dicts, pg, qg) + @test result.status == result_nlp_pm.status @test isapprox(result.objective, result_pm["objective"], rtol = result.options.tol*100) for key in keys(dicts.gen) @test isapprox(Array(solution(result, pg))[dicts.gen[key]], result_pm["solution"]["gen"][string(key)]["pg"], atol = result.options.tol*1000) @@ -37,12 +37,27 @@ function test_rect_voltage(result, result_pm, dicts, vr, vim) end end -function test_case5(result, result_pm, dicts, pg, qg, p, q) - test_static_case(result, result_pm, dicts, pg, qg) +function test_case5(result, result_pm, result_nlp_pm, dicts, pg, qg, p, q) + test_static_case(result, result_pm, result_nlp_pm, dicts, pg, qg) +end + +function test_case14(result, result_pm, result_nlp_pm, dicts, pg, qg, p, q) + test_static_case(result, result_pm, result_nlp_pm, dicts, pg, qg) end -function test_case14(result, result_pm, dicts, pg, qg, p, q) - test_static_case(result, result_pm, dicts, pg, qg) +function test_float32(m, m64, result, backend) + x1 = result.solution + tol = 2.71828^(log(result.options.tol)/2) + x2 = x1 .* (1 .+ 0.01 .* (2 .* rand(size(x1)) .- 1)) + x3 = x1 .* (1 .+ 0.01 .* (2 .* rand(size(x1)) .- 1)) + for x in [x1, x2, x3] + @test isapprox(obj(m, x), obj(m64, x), rtol = tol) + @test isapprox(cons(m, x), cons(m64, x), rtol = tol) + if backend != CUDABackend() + @test isapprox(grad(m, x), grad(m64, x), rtol = tol) + @test isapprox(jac(m, x), jac(m64, x), rtol = tol) + end + end end function test_mp_case(result, true_sol) diff --git a/test/runtests.jl b/test/runtests.jl index e3fe9a3..fb6b95d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt, JuMP, ExaModels +using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt, JuMP, ExaModels, NLPModelsJuMP include("opf_tests.jl") @@ -24,16 +24,28 @@ test_cases = [("data/pglib_opf_case3_lmbd.m", "case3", test_case3), ("data/pglib_opf_case5_pjm.m", "case5", test_case5), ("data/pglib_opf_case14_ieee.m", "case14", test_case14)] - +#MP #Curve = [1, .9, .8, .95, 1] true_sol_case3_curve = 25384.366465 true_sol_case3_pregen = 29049.351564 true_sol_case5_curve = 78491.04247 true_sol_case5_pregen = 87816.396884 - +#W storage +true_sol_case3_curve_stor = 25358.827525 +true_sol_case3_curve_stor_func = 25354.331998 +true_sol_case3_pregen_stor = 29023.69118 +true_sol_case3_pregen_stor_func = 29019.172473 +true_sol_case5_curve_stor = 68782.0125 +true_sol_case5_curve_stor_func = 70235.91846 +true_sol_case5_pregen_stor = 79640.08493 +true_sol_case5_pregen_stor_func = 79630.14036 mp_test_cases = [("data/pglib_opf_case3_lmbd.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), ("data/pglib_opf_case5_pjm.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] +mp_stor_test_cases = [("data/pglib_opf_case3_lmbd_mod.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", + true_sol_case3_curve_stor, true_sol_case3_curve_stor_func, true_sol_case3_pregen_stor, true_sol_case3_pregen_stor_func), + ("data/pglib_opf_case5_pjm_mod.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", + true_sol_case5_curve_stor, true_sol_case5_curve_stor_func, true_sol_case5_pregen_stor, true_sol_case5_pregen_stor_func)] function example_func(d, srating) return d + .2/srating*d^2 @@ -47,6 +59,7 @@ function runtests() for (filename, case, test_function) in test_cases #Test static opf data, dicts = ExaModelsPower.parse_ac_power_data(filename) + data_pm = PowerModels.parse_file(filename) #Polar tests m, v, c = opf_model(filename; T=T, backend = backend) @@ -55,10 +68,23 @@ function runtests() nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) result_pm = solve_opf(filename,ACPPowerModel, nlp_solver) + + + m_pm = JuMP.Model() + pm = instantiate_model(data_pm, ACPPowerModel, PowerModels.build_opf, jump_model = m_pm) + nlp_pm = MathOptNLPModel(m_pm) + result_nlp_pm = madnlp(nlp_pm; print_level = MadNLP.ERROR) + @testset "$(case), static, $(T), $(backend), polar" begin - eval(test_function)(result, result_pm, dicts, pg, qg, p, q) - test_polar_voltage(result, result_pm, dicts, va, vm) + if T == Float32 + m64, v64, c64 = opf_model(filename; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + eval(test_function)(result, result_pm, result_nlp_pm, dicts, pg, qg, p, q) + test_polar_voltage(result, result_pm, dicts, va, vm) + end end #Rectangular tests @@ -68,14 +94,24 @@ function runtests() nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>result.options.tol, "print_level"=>0) result_pm = solve_opf(filename, ACRPowerModel, nlp_solver) + + m_pm = JuMP.Model() + pm = instantiate_model(data_pm, ACRPowerModel, PowerModels.build_opf, jump_model = m_pm) + nlp_pm = MathOptNLPModel(m_pm) + result_nlp_pm = madnlp(nlp_pm; print_level = MadNLP.ERROR) @testset "$(case), static, $(T), $(backend), rect" begin - eval(test_function)(result, result_pm, dicts, pg, qg, p, q) - test_rect_voltage(result, result_pm, dicts, vr, vim) + if T == Float32 + m64, v64, c64 = opf_model(filename; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + eval(test_function)(result, result_pm, result_nlp_pm, dicts, pg, qg, p, q) + test_rect_voltage(result, result_pm, dicts, vr, vim) + end end end - #Test MP for (filename, case, Pd_pregen, Qd_pregen, true_sol_curve, true_sol_pregen) in mp_test_cases #Curve = [1, .9, .8, .95, 1] @@ -84,25 +120,49 @@ function runtests() m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), curve, polar" begin - test_mp_case(result, true_sol_curve) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve) + end end #w function m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), curve, polar, func" begin - test_mp_case(result, true_sol_curve) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve) + end end #Rect m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), curve, rect" begin - test_mp_case(result, true_sol_curve) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve) + end end #w function m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), curve, rect" begin - test_mp_case(result, true_sol_curve) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve) + end end @@ -111,93 +171,159 @@ function runtests() m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), pregen, polar" begin - test_mp_case(result, true_sol_pregen) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen) + end end #w function m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), pregen, polar, func" begin - test_mp_case(result, true_sol_pregen) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen) + end end #Rect m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), pregen, rect" begin - test_mp_case(result, true_sol_pregen) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen) + end end #w function m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend, form = :rect) result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), pregen, rect, func" begin - test_mp_case(result, true_sol_pregen) + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen) + end end end #Test MP w storage + for (filename, case, Pd_pregen, Qd_pregen, true_sol_curve_stor, + true_sol_curve_stor_func, true_sol_pregen_stor, true_sol_pregen_stor_func) in mp_stor_test_cases + + #Polar + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), curve, polar" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve_stor) + end + end + #Rect + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), curve, rect" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve_stor) + end + end - #Curve = [1, .9, .8, .95, 1] - true_sol = 25358.827525 - - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), curve, polar" begin - test_mp_case(result, true_sol) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), curve, rect" begin - test_mp_case(result, true_sol) - end - - #With function - true_sol = 25354.331998 - - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), curve, polar, func" begin - test_mp_case(result, true_sol) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), curve, rect, func" begin - test_mp_case(result, true_sol) - end - - #Pregenerated Pd and Qd - true_sol = 29023.69118 - - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), pregen, polar" begin - test_mp_case(result, true_sol) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd"; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), pregen, rect" begin - test_mp_case(result, true_sol) - end + #With function + #Polar + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), curve, polar, func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve_stor_func) + end + end + #Rect + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case) $(T), $(backend), curve, rect, func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve_stor_func) + end + end - #With function - true_sol = 29019.172473 + #Pregenerated Pd and Qd + #Polar + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), pregen, polar" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen_stor) + end + end + #Rect + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), pregen, rect" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen_stor) + end + end - #Polar - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), pregen, polar, func" begin - test_mp_case(result, true_sol) - end - #Rect - m, v, c = eval(mpopf_model)("pglib_opf_case3_lmbd_mod.m", "data/case3_5split.Pd", "data/case3_5split.Qd", example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(T), $(backend), pregen, rect, func" begin - test_mp_case(result, true_sol) + #With function + #Polar + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), pregen, polar, func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen_stor_func) + end + end + #Rect + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend, form = :rect) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), pregen, rect, func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend, form = :rect) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen_stor_func) + end + end end end end From bfafbde0e6f29ed837202db93ada69204dd88248 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Sun, 13 Apr 2025 18:13:41 -0400 Subject: [PATCH 06/21] Readme updated --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index df44762..3c8e694 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # ExaModelsPower.jl ExaModelsPower.jl is an optimal power flow models using ExaModels.jl +![CI](https://github.com/exanauts/ExaModelsPower/actions/workflows/ci.yml/badge.svg) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) + ## Usage ### Static optimal power flow ```julia From 0c195fedf43395ecc68fb5e47e84220f965c7c90 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Sun, 13 Apr 2025 18:15:09 -0400 Subject: [PATCH 07/21] . --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96b81c2..1d6e388 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - sanjayjo jobs: test: From 13e5346b53ddc5f794244e599638887dcc9ad993 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Sun, 13 Apr 2025 18:16:25 -0400 Subject: [PATCH 08/21] readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c8e694..3183e33 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ExaModelsPower.jl ExaModelsPower.jl is an optimal power flow models using ExaModels.jl -![CI](https://github.com/exanauts/ExaModelsPower/actions/workflows/ci.yml/badge.svg) +![CI](https://github.com/exanauts/ExaModelsPower.jl/actions/workflows/ci.yml/badge.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ## Usage From e50dae793d73516f05e6d8c6f03ff6dd0bab754b Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 08:34:07 -0400 Subject: [PATCH 09/21] CI update --- .github/workflows/ci.yml | 3 +++ README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d6e388..1bb3ee1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,9 @@ on: branches: - main - sanjayjo + push_request: + branches: + - sanjayjo jobs: test: diff --git a/README.md b/README.md index 3183e33..7e74818 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ExaModelsPower.jl ExaModelsPower.jl is an optimal power flow models using ExaModels.jl -![CI](https://github.com/exanauts/ExaModelsPower.jl/actions/workflows/ci.yml/badge.svg) +![CI](https://github.com/exanauts/ExaModelsPower.jl/tree/sanjayjo/actions/workflows/ci.yml/badge.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ## Usage From fc9e9589fea4a13177018f1e1a228ae271be07b4 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 08:38:25 -0400 Subject: [PATCH 10/21] CI update --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bb3ee1..f7dbd74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: - main - sanjayjo - push_request: + push: branches: - sanjayjo From e85c09d8efd8345aefcbc73005706259c496ef1b Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 08:44:15 -0400 Subject: [PATCH 11/21] CI update, took out macos --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7dbd74..505e85e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest, self-hosted] + os: [ubuntu-latest, windows-latest, self-hosted] steps: - name: Checkout repository uses: actions/checkout@v4 From 01a0c86f25e6811194a5bcaf57b6cfd4feff0df7 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 08:55:31 -0400 Subject: [PATCH 12/21] CI update, ensuring dependencies are added --- test/runtests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index fb6b95d..2e0a20f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,3 +1,5 @@ +using Pkg +Pkg.add(["Ipopt", "JuMP", "ExaModels", "NLPModelsJuMP"]) using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt, JuMP, ExaModels, NLPModelsJuMP include("opf_tests.jl") From 48c29adb23f8af46944c9380cc10253be6eba9eb Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 09:10:40 -0400 Subject: [PATCH 13/21] CI update, add dependencies --- Project.toml | 5 ++++- test/runtests.jl | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index bff7570..f037f9e 100644 --- a/Project.toml +++ b/Project.toml @@ -24,6 +24,9 @@ KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c" MadNLP = "2621e9c9-9eb4-46b1-8089-e8c72242dfb6" MadNLPGPU = "d72a61cc-809d-412f-99be-fd81f4b8a598" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" +JuMP = "4076af6c-e467-56ae-b986-b466b2749572" +NLPModelsJuMP = "792afdf1-32c1-5681-94e0-d7bf7a5df49e" [targets] -test = ["Test", "MadNLP", "MadNLPGPU", "KernelAbstractions", "CUDA"] +test = ["Test", "MadNLP", "MadNLPGPU", "KernelAbstractions", "CUDA", "Ipopt", "JuMP", "NLPModelsJuMP"] diff --git a/test/runtests.jl b/test/runtests.jl index 2e0a20f..fb6b95d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,3 @@ -using Pkg -Pkg.add(["Ipopt", "JuMP", "ExaModels", "NLPModelsJuMP"]) using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt, JuMP, ExaModels, NLPModelsJuMP include("opf_tests.jl") From 9a49cde6a138795ecb51476f04af09c34f1e4aec Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 09:17:14 -0400 Subject: [PATCH 14/21] CI update, changed test case paths --- test/runtests.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index fb6b95d..3eae478 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,9 +20,9 @@ if CUDA.has_cuda_gpu() ) end -test_cases = [("data/pglib_opf_case3_lmbd.m", "case3", test_case3), - ("data/pglib_opf_case5_pjm.m", "case5", test_case5), - ("data/pglib_opf_case14_ieee.m", "case14", test_case14)] +test_cases = [("pglib_opf_case3_lmbd.m", "case3", test_case3), + ("pglib_opf_case5_pjm.m", "case5", test_case5), + ("pglib_opf_case14_ieee.m", "case14", test_case14)] #MP #Curve = [1, .9, .8, .95, 1] @@ -39,12 +39,12 @@ true_sol_case5_curve_stor = 68782.0125 true_sol_case5_curve_stor_func = 70235.91846 true_sol_case5_pregen_stor = 79640.08493 true_sol_case5_pregen_stor_func = 79630.14036 -mp_test_cases = [("data/pglib_opf_case3_lmbd.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), - ("data/pglib_opf_case5_pjm.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] +mp_test_cases = [("pglib_opf_case3_lmbd.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), + ("pglib_opf_case5_pjm.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] -mp_stor_test_cases = [("data/pglib_opf_case3_lmbd_mod.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", +mp_stor_test_cases = [("../data/pglib_opf_case3_lmbd_mod.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve_stor, true_sol_case3_curve_stor_func, true_sol_case3_pregen_stor, true_sol_case3_pregen_stor_func), - ("data/pglib_opf_case5_pjm_mod.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", + ("../data/pglib_opf_case5_pjm_mod.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve_stor, true_sol_case5_curve_stor_func, true_sol_case5_pregen_stor, true_sol_case5_pregen_stor_func)] function example_func(d, srating) From 69e79618bf425f938f2504885d3b69364cfcdb1a Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 09:21:56 -0400 Subject: [PATCH 15/21] Updated data files --- data/pglib_opf_case14_ieee.m | 214 +++++++++++++++++++++++++++++++++++ data/pglib_opf_case5_pjm.m | 116 +++++++++++++++++++ test/runtests.jl | 10 +- 3 files changed, 335 insertions(+), 5 deletions(-) create mode 100644 data/pglib_opf_case14_ieee.m create mode 100644 data/pglib_opf_case5_pjm.m diff --git a/data/pglib_opf_case14_ieee.m b/data/pglib_opf_case14_ieee.m new file mode 100644 index 0000000..2c8260f --- /dev/null +++ b/data/pglib_opf_case14_ieee.m @@ -0,0 +1,214 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% %%%%% +%%%% IEEE PES Power Grid Library - Optimal Power Flow - v23.07 %%%%% +%%%% (https://github.com/power-grid-lib/pglib-opf) %%%%% +%%%% Benchmark Group - Typical Operations %%%%% +%%%% 23 - July - 2023 %%%%% +%%%% %%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Power flow data for IEEE 14 bus test case. +% This data was converted from IEEE Common Data Format +% (ieee14cdf.txt) on 20-Sep-2004 by cdf2matp, rev. 1.11 +% +% Converted from IEEE CDF file from: +% http://www.ee.washington.edu/research/pstca/ +% +% Copyright (c) 1999 by Richard D. Christie, University of Washington +% Electrical Engineering Licensed under the Creative Commons Attribution 4.0 +% International license, http://creativecommons.org/licenses/by/4.0/ +% +% CDF Header: +% 08/19/93 UW ARCHIVE 100.0 1962 W IEEE 14 Bus Test Case +% +function mpc = pglib_opf_case14_ieee +mpc.version = '2'; +mpc.baseMVA = 100.0; + +%% bus data +% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin +mpc.bus = [ + 1 3 0.0 0.0 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 2 2 21.7 12.7 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 3 2 94.2 19.0 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 4 1 47.8 -3.9 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 5 1 7.6 1.6 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 6 2 11.2 7.5 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 7 1 0.0 0.0 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 8 2 0.0 0.0 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 9 1 29.5 16.6 0.0 19.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 10 1 9.0 5.8 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 11 1 3.5 1.8 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 12 1 6.1 1.6 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 13 1 13.5 5.8 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; + 14 1 14.9 5.0 0.0 0.0 1 1.00000 0.00000 1.0 1 1.06000 0.94000; +]; + +%% generator data +% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin +mpc.gen = [ + 1 170.0 5.0 10.0 0.0 1.0 100.0 1 340 0.0; % NG + 2 29.5 0.0 30.0 -30.0 1.0 100.0 1 59 0.0; % NG + 3 0.0 20.0 40.0 0.0 1.0 100.0 1 0 0.0; % SYNC + 6 0.0 9.0 24.0 -6.0 1.0 100.0 1 0 0.0; % SYNC + 8 0.0 9.0 24.0 -6.0 1.0 100.0 1 0 0.0; % SYNC +]; + +%% generator cost data +% 2 startup shutdown n c(n-1) ... c0 +mpc.gencost = [ + 2 0.0 0.0 3 0.000000 7.920951 0.000000; % NG + 2 0.0 0.0 3 0.000000 23.269494 0.000000; % NG + 2 0.0 0.0 3 0.000000 0.000000 0.000000; % SYNC + 2 0.0 0.0 3 0.000000 0.000000 0.000000; % SYNC + 2 0.0 0.0 3 0.000000 0.000000 0.000000; % SYNC +]; + +%% branch data +% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax +mpc.branch = [ + 1 2 0.01938 0.05917 0.0528 472 472 472 0.0 0.0 1 -30.0 30.0; + 1 5 0.05403 0.22304 0.0492 128 128 128 0.0 0.0 1 -30.0 30.0; + 2 3 0.04699 0.19797 0.0438 145 145 145 0.0 0.0 1 -30.0 30.0; + 2 4 0.05811 0.17632 0.034 158 158 158 0.0 0.0 1 -30.0 30.0; + 2 5 0.05695 0.17388 0.0346 161 161 161 0.0 0.0 1 -30.0 30.0; + 3 4 0.06701 0.17103 0.0128 160 160 160 0.0 0.0 1 -30.0 30.0; + 4 5 0.01335 0.04211 0.0 664 664 664 0.0 0.0 1 -30.0 30.0; + 4 7 0.0 0.20912 0.0 141 141 141 0.978 0.0 1 -30.0 30.0; + 4 9 0.0 0.55618 0.0 53 53 53 0.969 0.0 1 -30.0 30.0; + 5 6 0.0 0.25202 0.0 117 117 117 0.932 0.0 1 -30.0 30.0; + 6 11 0.09498 0.1989 0.0 134 134 134 0.0 0.0 1 -30.0 30.0; + 6 12 0.12291 0.25581 0.0 104 104 104 0.0 0.0 1 -30.0 30.0; + 6 13 0.06615 0.13027 0.0 201 201 201 0.0 0.0 1 -30.0 30.0; + 7 8 0.0 0.17615 0.0 167 167 167 0.0 0.0 1 -30.0 30.0; + 7 9 0.0 0.11001 0.0 267 267 267 0.0 0.0 1 -30.0 30.0; + 9 10 0.03181 0.0845 0.0 325 325 325 0.0 0.0 1 -30.0 30.0; + 9 14 0.12711 0.27038 0.0 99 99 99 0.0 0.0 1 -30.0 30.0; + 10 11 0.08205 0.19207 0.0 141 141 141 0.0 0.0 1 -30.0 30.0; + 12 13 0.22092 0.19988 0.0 99 99 99 0.0 0.0 1 -30.0 30.0; + 13 14 0.17093 0.34802 0.0 76 76 76 0.0 0.0 1 -30.0 30.0; +]; + +% INFO : === Translation Options === +% INFO : Phase Angle Bound: 30.0 (deg.) +% INFO : Line Capacity Model: stat +% INFO : Gen Active Capacity Model: stat +% INFO : Gen Reactive Capacity Model: am50ag +% INFO : Gen Active Cost Model: stat +% INFO : Setting Flat Start +% INFO : Line Capacity PAB: 15.0 (deg.) +% INFO : +% INFO : === Generator Classification Notes === +% INFO : SYNC 3 - 0.00 +% INFO : NG 2 - 100.00 +% INFO : +% INFO : === Generator Active Capacity Stat Model Notes === +% INFO : Gen at bus 1 - NG : Pg=232.4, Pmax=332.4 -> Pmax=340 samples: 20 +% INFO : Gen at bus 2 - NG : Pg=40.0, Pmax=140.0 -> Pmax=59 samples: 6 +% INFO : Gen at bus 3 - SYNC : Pg=0.0, Pmax=100.0 -> Pmax=0 samples: 0 +% INFO : Gen at bus 6 - SYNC : Pg=0.0, Pmax=100.0 -> Pmax=0 samples: 0 +% INFO : Gen at bus 8 - SYNC : Pg=0.0, Pmax=100.0 -> Pmax=0 samples: 0 +% INFO : +% INFO : === Generator Reactive Capacity Atmost Max 50 Percent Active Model Notes === +% INFO : Gen at bus 2 - NG : Pmax 59.0, Qmin -40.0, Qmax 50.0 -> Qmin -30.0, Qmax 30.0 +% INFO : +% INFO : === Generator Active Cost Stat Model Notes === +% INFO : Updated Generator Cost: NG - 0.0 20.0 0.0430293 -> 0 7.92095063323 0 +% INFO : Updated Generator Cost: NG - 0.0 20.0 0.25 -> 0 23.2694943686 0 +% INFO : Updated Generator Cost: SYNC - 0.0 40.0 0.01 -> 0 0.0 0 +% INFO : Updated Generator Cost: SYNC - 0.0 40.0 0.01 -> 0 0.0 0 +% INFO : Updated Generator Cost: SYNC - 0.0 40.0 0.01 -> 0 0.0 0 +% INFO : +% INFO : === Generator Bounds Update Notes === +% INFO : +% INFO : === Base KV Replacement Notes === +% WARNING : Bus 1 : basekv changed 0.0 => 1.0 +% WARNING : Bus 2 : basekv changed 0.0 => 1.0 +% WARNING : Bus 3 : basekv changed 0.0 => 1.0 +% WARNING : Bus 4 : basekv changed 0.0 => 1.0 +% WARNING : Bus 5 : basekv changed 0.0 => 1.0 +% WARNING : Bus 6 : basekv changed 0.0 => 1.0 +% WARNING : Bus 7 : basekv changed 0.0 => 1.0 +% WARNING : Bus 8 : basekv changed 0.0 => 1.0 +% WARNING : Bus 9 : basekv changed 0.0 => 1.0 +% WARNING : Bus 10 : basekv changed 0.0 => 1.0 +% WARNING : Bus 11 : basekv changed 0.0 => 1.0 +% WARNING : Bus 12 : basekv changed 0.0 => 1.0 +% WARNING : Bus 13 : basekv changed 0.0 => 1.0 +% WARNING : Bus 14 : basekv changed 0.0 => 1.0 +% INFO : +% INFO : === Transformer Setting Replacement Notes === +% INFO : +% INFO : === Line Capacity Stat Model Notes === +% WARNING : Missing data for branch flow stat model on line 1-2 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.01938 x=0.05917 +% INFO : Updated Thermal Rating: on line 1-2 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 472 +% WARNING : Missing data for branch flow stat model on line 1-5 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.05403 x=0.22304 +% INFO : Updated Thermal Rating: on line 1-5 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 128 +% WARNING : Missing data for branch flow stat model on line 2-3 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.04699 x=0.19797 +% INFO : Updated Thermal Rating: on line 2-3 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 145 +% WARNING : Missing data for branch flow stat model on line 2-4 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.05811 x=0.17632 +% INFO : Updated Thermal Rating: on line 2-4 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 158 +% WARNING : Missing data for branch flow stat model on line 2-5 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.05695 x=0.17388 +% INFO : Updated Thermal Rating: on line 2-5 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 161 +% WARNING : Missing data for branch flow stat model on line 3-4 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.06701 x=0.17103 +% INFO : Updated Thermal Rating: on line 3-4 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 160 +% WARNING : Missing data for branch flow stat model on line 4-5 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.01335 x=0.04211 +% INFO : Updated Thermal Rating: on line 4-5 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 664 +% WARNING : Missing data for branch flow stat model on line 4-7 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.0 x=0.20912 +% INFO : Updated Thermal Rating: on transformer 4-7 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 141 +% WARNING : Missing data for branch flow stat model on line 4-9 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.0 x=0.55618 +% INFO : Updated Thermal Rating: on transformer 4-9 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 53 +% WARNING : Missing data for branch flow stat model on line 5-6 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.0 x=0.25202 +% INFO : Updated Thermal Rating: on transformer 5-6 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 117 +% WARNING : Missing data for branch flow stat model on line 6-11 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.09498 x=0.1989 +% INFO : Updated Thermal Rating: on line 6-11 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 134 +% WARNING : Missing data for branch flow stat model on line 6-12 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.12291 x=0.25581 +% INFO : Updated Thermal Rating: on line 6-12 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 104 +% WARNING : Missing data for branch flow stat model on line 6-13 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.06615 x=0.13027 +% INFO : Updated Thermal Rating: on line 6-13 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 201 +% WARNING : Missing data for branch flow stat model on line 7-8 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.0 x=0.17615 +% INFO : Updated Thermal Rating: on line 7-8 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 167 +% WARNING : Missing data for branch flow stat model on line 7-9 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.0 x=0.11001 +% INFO : Updated Thermal Rating: on line 7-9 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 267 +% WARNING : Missing data for branch flow stat model on line 9-10 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.03181 x=0.0845 +% INFO : Updated Thermal Rating: on line 9-10 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 325 +% WARNING : Missing data for branch flow stat model on line 9-14 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.12711 x=0.27038 +% INFO : Updated Thermal Rating: on line 9-14 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 99 +% WARNING : Missing data for branch flow stat model on line 10-11 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.08205 x=0.19207 +% INFO : Updated Thermal Rating: on line 10-11 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 141 +% WARNING : Missing data for branch flow stat model on line 12-13 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.22092 x=0.19988 +% INFO : Updated Thermal Rating: on line 12-13 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 99 +% WARNING : Missing data for branch flow stat model on line 13-14 using max current model : from_basekv=1.0 to_basekv=1.0 r=0.17093 x=0.34802 +% INFO : Updated Thermal Rating: on line 13-14 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 76 +% INFO : +% INFO : === Line Capacity Monotonicity Notes === +% INFO : +% INFO : === Voltage Setpoint Replacement Notes === +% INFO : Bus 1 : V=1.06, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 2 : V=1.045, theta=-4.98 -> V=1.0, theta=0.0 +% INFO : Bus 3 : V=1.01, theta=-12.72 -> V=1.0, theta=0.0 +% INFO : Bus 4 : V=1.019, theta=-10.33 -> V=1.0, theta=0.0 +% INFO : Bus 5 : V=1.02, theta=-8.78 -> V=1.0, theta=0.0 +% INFO : Bus 6 : V=1.07, theta=-14.22 -> V=1.0, theta=0.0 +% INFO : Bus 7 : V=1.062, theta=-13.37 -> V=1.0, theta=0.0 +% INFO : Bus 8 : V=1.09, theta=-13.36 -> V=1.0, theta=0.0 +% INFO : Bus 9 : V=1.056, theta=-14.94 -> V=1.0, theta=0.0 +% INFO : Bus 10 : V=1.051, theta=-15.1 -> V=1.0, theta=0.0 +% INFO : Bus 11 : V=1.057, theta=-14.79 -> V=1.0, theta=0.0 +% INFO : Bus 12 : V=1.055, theta=-15.07 -> V=1.0, theta=0.0 +% INFO : Bus 13 : V=1.05, theta=-15.16 -> V=1.0, theta=0.0 +% INFO : Bus 14 : V=1.036, theta=-16.04 -> V=1.0, theta=0.0 +% INFO : +% INFO : === Generator Setpoint Replacement Notes === +% INFO : Gen at bus 1 : Pg=232.4, Qg=-16.9 -> Pg=170.0, Qg=5.0 +% INFO : Gen at bus 1 : Vg=1.06 -> Vg=1.0 +% INFO : Gen at bus 2 : Pg=40.0, Qg=42.4 -> Pg=29.5, Qg=0.0 +% INFO : Gen at bus 2 : Vg=1.045 -> Vg=1.0 +% INFO : Gen at bus 3 : Pg=0.0, Qg=23.4 -> Pg=0.0, Qg=20.0 +% INFO : Gen at bus 3 : Vg=1.01 -> Vg=1.0 +% INFO : Gen at bus 6 : Pg=0.0, Qg=12.2 -> Pg=0.0, Qg=9.0 +% INFO : Gen at bus 6 : Vg=1.07 -> Vg=1.0 +% INFO : Gen at bus 8 : Pg=0.0, Qg=17.4 -> Pg=0.0, Qg=9.0 +% INFO : Gen at bus 8 : Vg=1.09 -> Vg=1.0 +% INFO : +% INFO : === Writing Matpower Case File Notes === diff --git a/data/pglib_opf_case5_pjm.m b/data/pglib_opf_case5_pjm.m new file mode 100644 index 0000000..6f84496 --- /dev/null +++ b/data/pglib_opf_case5_pjm.m @@ -0,0 +1,116 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% %%%%% +%%%% IEEE PES Power Grid Library - Optimal Power Flow - v23.07 %%%%% +%%%% (https://github.com/power-grid-lib/pglib-opf) %%%%% +%%%% Benchmark Group - Typical Operations %%%%% +%%%% 23 - July - 2023 %%%%% +%%%% %%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% CASE5 Power flow data for modified 5 bus, 5 gen case based on PJM 5-bus system +% Please see CASEFORMAT for details on the case file format. +% +% Based on data from ... +% F.Li and R.Bo, "Small Test Systems for Power System Economic Studies", +% Proceedings of the 2010 IEEE Power & Energy Society General Meeting +% +% Created by Rui Bo in 2006, modified in 2010, 2014. +% +% Copyright (c) 2010 by The Institute of Electrical and Electronics Engineers (IEEE) +% Licensed under the Creative Commons Attribution 4.0 +% International license, http://creativecommons.org/licenses/by/4.0/ +% +% Contact M.E. Brennan (me.brennan@ieee.org) for inquries on further reuse of +% this dataset. +% +function mpc = pglib_opf_case5_pjm +mpc.version = '2'; +mpc.baseMVA = 100.0; + +%% area data +% area refbus +mpc.areas = [ + 1 4; +]; + +%% bus data +% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin +mpc.bus = [ + 1 2 0.0 0.0 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 2 1 300.0 98.61 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 3 2 300.0 98.61 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 4 3 400.0 131.47 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; + 5 2 0.0 0.0 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000; +]; + +%% generator data +% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin +mpc.gen = [ + 1 20.0 0.0 30.0 -30.0 1.0 100.0 1 40.0 0.0; + 1 85.0 0.0 127.5 -127.5 1.0 100.0 1 170.0 0.0; + 3 260.0 0.0 390.0 -390.0 1.0 100.0 1 520.0 0.0; + 4 100.0 0.0 150.0 -150.0 1.0 100.0 1 200.0 0.0; + 5 300.0 0.0 450.0 -450.0 1.0 100.0 1 600.0 0.0; +]; + +%% generator cost data +% 2 startup shutdown n c(n-1) ... c0 +mpc.gencost = [ + 2 0.0 0.0 3 0.000000 14.000000 0.000000; + 2 0.0 0.0 3 0.000000 15.000000 0.000000; + 2 0.0 0.0 3 0.000000 30.000000 0.000000; + 2 0.0 0.0 3 0.000000 40.000000 0.000000; + 2 0.0 0.0 3 0.000000 10.000000 0.000000; +]; + +%% branch data +% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax +mpc.branch = [ + 1 2 0.00281 0.0281 0.00712 400.0 400.0 400.0 0.0 0.0 1 -30.0 30.0; + 1 4 0.00304 0.0304 0.00658 426 426 426 0.0 0.0 1 -30.0 30.0; + 1 5 0.00064 0.0064 0.03126 426 426 426 0.0 0.0 1 -30.0 30.0; + 2 3 0.00108 0.0108 0.01852 426 426 426 0.0 0.0 1 -30.0 30.0; + 3 4 0.00297 0.0297 0.00674 426 426 426 0.0 0.0 1 -30.0 30.0; + 4 5 0.00297 0.0297 0.00674 240.0 240.0 240.0 0.0 0.0 1 -30.0 30.0; +]; + +% INFO : === Translation Options === +% INFO : Phase Angle Bound: 30.0 (deg.) +% INFO : Line Capacity Model: stat +% INFO : Setting Flat Start +% INFO : Line Capacity PAB: 15.0 (deg.) +% INFO : +% INFO : === Generator Bounds Update Notes === +% INFO : +% INFO : === Base KV Replacement Notes === +% INFO : +% INFO : === Transformer Setting Replacement Notes === +% INFO : +% INFO : === Line Capacity Stat Model Notes === +% INFO : Updated Thermal Rating: on line 1-4 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : Updated Thermal Rating: on line 1-5 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : Updated Thermal Rating: on line 2-3 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : Updated Thermal Rating: on line 3-4 : Rate A, Rate B, Rate C , 9900.0, 0.0, 0.0 -> 426 +% INFO : +% INFO : === Line Capacity Monotonicity Notes === +% INFO : +% INFO : === Voltage Setpoint Replacement Notes === +% INFO : Bus 1 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 2 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 3 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 4 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : Bus 5 : V=1.0, theta=0.0 -> V=1.0, theta=0.0 +% INFO : +% INFO : === Generator Setpoint Replacement Notes === +% INFO : Gen at bus 1 : Pg=40.0, Qg=0.0 -> Pg=20.0, Qg=0.0 +% INFO : Gen at bus 1 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 1 : Pg=170.0, Qg=0.0 -> Pg=85.0, Qg=0.0 +% INFO : Gen at bus 1 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 3 : Pg=323.49, Qg=0.0 -> Pg=260.0, Qg=0.0 +% INFO : Gen at bus 3 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 4 : Pg=0.0, Qg=0.0 -> Pg=100.0, Qg=0.0 +% INFO : Gen at bus 4 : Vg=1.0 -> Vg=1.0 +% INFO : Gen at bus 5 : Pg=466.51, Qg=0.0 -> Pg=300.0, Qg=0.0 +% INFO : Gen at bus 5 : Vg=1.0 -> Vg=1.0 +% INFO : +% INFO : === Writing Matpower Case File Notes === diff --git a/test/runtests.jl b/test/runtests.jl index 3eae478..24f07d4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,9 +20,9 @@ if CUDA.has_cuda_gpu() ) end -test_cases = [("pglib_opf_case3_lmbd.m", "case3", test_case3), - ("pglib_opf_case5_pjm.m", "case5", test_case5), - ("pglib_opf_case14_ieee.m", "case14", test_case14)] +test_cases = [("../data/pglib_opf_case3_lmbd.m", "case3", test_case3), + ("../data/pglib_opf_case5_pjm.m", "case5", test_case5), + ("../data/pglib_opf_case14_ieee.m", "case14", test_case14)] #MP #Curve = [1, .9, .8, .95, 1] @@ -39,8 +39,8 @@ true_sol_case5_curve_stor = 68782.0125 true_sol_case5_curve_stor_func = 70235.91846 true_sol_case5_pregen_stor = 79640.08493 true_sol_case5_pregen_stor_func = 79630.14036 -mp_test_cases = [("pglib_opf_case3_lmbd.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), - ("pglib_opf_case5_pjm.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] +mp_test_cases = [("../data/pglib_opf_case3_lmbd.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), + ("../data/pglib_opf_case5_pjm.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] mp_stor_test_cases = [("../data/pglib_opf_case3_lmbd_mod.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve_stor, true_sol_case3_curve_stor_func, true_sol_case3_pregen_stor, true_sol_case3_pregen_stor_func), From 85b3dc52d7a9076ebb356d33f00c45591f307990 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 09:43:44 -0400 Subject: [PATCH 16/21] updated to call nlpmodel evals correctly --- test/opf_tests.jl | 8 ++++---- test/runtests.jl | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/opf_tests.jl b/test/opf_tests.jl index eced3fd..3036c4d 100644 --- a/test/opf_tests.jl +++ b/test/opf_tests.jl @@ -51,11 +51,11 @@ function test_float32(m, m64, result, backend) x2 = x1 .* (1 .+ 0.01 .* (2 .* rand(size(x1)) .- 1)) x3 = x1 .* (1 .+ 0.01 .* (2 .* rand(size(x1)) .- 1)) for x in [x1, x2, x3] - @test isapprox(obj(m, x), obj(m64, x), rtol = tol) - @test isapprox(cons(m, x), cons(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.obj(m, x), obj(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.cons(m, x), cons(m64, x), rtol = tol) if backend != CUDABackend() - @test isapprox(grad(m, x), grad(m64, x), rtol = tol) - @test isapprox(jac(m, x), jac(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.grad(m, x), grad(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.jac(m, x), jac(m64, x), rtol = tol) end end end diff --git a/test/runtests.jl b/test/runtests.jl index 24f07d4..feaf4e3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -39,12 +39,12 @@ true_sol_case5_curve_stor = 68782.0125 true_sol_case5_curve_stor_func = 70235.91846 true_sol_case5_pregen_stor = 79640.08493 true_sol_case5_pregen_stor_func = 79630.14036 -mp_test_cases = [("../data/pglib_opf_case3_lmbd.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), - ("../data/pglib_opf_case5_pjm.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] +mp_test_cases = [("../data/pglib_opf_case3_lmbd.m", "case3", "../data/case3_5split.Pd", "../data/case3_5split.Qd", true_sol_case3_curve, true_sol_case3_pregen), + ("../data/pglib_opf_case5_pjm.m", "case5", "../data/case5_5split.Pd", "../data/case5_5split.Qd", true_sol_case5_curve, true_sol_case5_pregen)] -mp_stor_test_cases = [("../data/pglib_opf_case3_lmbd_mod.m", "case3", "data/case3_5split.Pd", "data/case3_5split.Qd", +mp_stor_test_cases = [("../data/pglib_opf_case3_lmbd_mod.m", "case3", "../data/case3_5split.Pd", "../data/case3_5split.Qd", true_sol_case3_curve_stor, true_sol_case3_curve_stor_func, true_sol_case3_pregen_stor, true_sol_case3_pregen_stor_func), - ("../data/pglib_opf_case5_pjm_mod.m", "case5", "data/case5_5split.Pd", "data/case5_5split.Qd", + ("../data/pglib_opf_case5_pjm_mod.m", "case5", "../data/case5_5split.Pd", "../data/case5_5split.Qd", true_sol_case5_curve_stor, true_sol_case5_curve_stor_func, true_sol_case5_pregen_stor, true_sol_case5_pregen_stor_func)] function example_func(d, srating) From aa657815aaba15999bd1b4d16465b83a138a8dc9 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 10:21:50 -0400 Subject: [PATCH 17/21] corrected opf_tests eval --- test/opf_tests.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/opf_tests.jl b/test/opf_tests.jl index 3036c4d..a163055 100644 --- a/test/opf_tests.jl +++ b/test/opf_tests.jl @@ -51,11 +51,11 @@ function test_float32(m, m64, result, backend) x2 = x1 .* (1 .+ 0.01 .* (2 .* rand(size(x1)) .- 1)) x3 = x1 .* (1 .+ 0.01 .* (2 .* rand(size(x1)) .- 1)) for x in [x1, x2, x3] - @test isapprox(NLPModelsJuMP.obj(m, x), obj(m64, x), rtol = tol) - @test isapprox(NLPModelsJuMP.cons(m, x), cons(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.obj(m, x), NLPModelsJuMP.obj(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.cons(m, x), NLPModelsJuMP.cons(m64, x), rtol = tol) if backend != CUDABackend() - @test isapprox(NLPModelsJuMP.grad(m, x), grad(m64, x), rtol = tol) - @test isapprox(NLPModelsJuMP.jac(m, x), jac(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.grad(m, x), NLPModelsJuMP.grad(m64, x), rtol = tol) + @test isapprox(NLPModelsJuMP.jac(m, x), NLPModelsJuMP.jac(m64, x), rtol = tol) end end end From 00524552bb05d15874dafb93de712ba0e849e6b9 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 13:24:45 -0400 Subject: [PATCH 18/21] Removed CI for sanjayjo branch push --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 505e85e..987b69b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,10 +4,6 @@ on: pull_request: branches: - main - - sanjayjo - push: - branches: - - sanjayjo jobs: test: From 7776d4c7415b5fd5d6cded76b4e7a06155474464 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Tue, 15 Apr 2025 13:33:32 -0400 Subject: [PATCH 19/21] Readme badge update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e74818..3183e33 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ExaModelsPower.jl ExaModelsPower.jl is an optimal power flow models using ExaModels.jl -![CI](https://github.com/exanauts/ExaModelsPower.jl/tree/sanjayjo/actions/workflows/ci.yml/badge.svg) +![CI](https://github.com/exanauts/ExaModelsPower.jl/actions/workflows/ci.yml/badge.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ## Usage From f32feefe5aa0f1afacc64519737e040f9829a404 Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Thu, 17 Apr 2025 18:09:19 -0400 Subject: [PATCH 20/21] Added license and readme for test cases, added form loop --- data/LICENSE.txt | 31 +++++ data/README_data.md | 19 +++ test/runtests.jl | 308 +++++++++++++++----------------------------- 3 files changed, 154 insertions(+), 204 deletions(-) create mode 100644 data/LICENSE.txt create mode 100644 data/README_data.md diff --git a/data/LICENSE.txt b/data/LICENSE.txt new file mode 100644 index 0000000..dee2b03 --- /dev/null +++ b/data/LICENSE.txt @@ -0,0 +1,31 @@ +Data License: + +Creative Commons Attribution 4.0 International license +http://creativecommons.org/licenses/by/4.0/ + +See data files for specific copyright holders and attribution details. + + +Software License: + +MIT License +Copyright (c) 2017 A Library of IEEE PES Power Grid Benchmarks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/data/README_data.md b/data/README_data.md new file mode 100644 index 0000000..fdb7c3b --- /dev/null +++ b/data/README_data.md @@ -0,0 +1,19 @@ +# ExaModelsPower.jl Test Data +The test cases represented here are original or modified forms of test cases represented +in power-grid-lib + +The modified cases have had storage devices added to certain bus(es) in the original +pglib test case. No other modifications were made. The location of the storage +devices was chosen arbitrarily. + +The casex_5split.Pd and .Qd files contain temporally varying active and reactive +power curves, with the baseline set at the demands presented in the static cases, +and arbitrarily altered over 5 different time periods. These cases are meant only +as tests, and their curve profile does not intend to represent any specific +real-world scenario. + + + + + + diff --git a/test/runtests.jl b/test/runtests.jl index feaf4e3..bea5297 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -25,6 +25,7 @@ test_cases = [("../data/pglib_opf_case3_lmbd.m", "case3", test_case3), ("../data/pglib_opf_case14_ieee.m", "case14", test_case14)] #MP +#MP solutions hard coded based on solutions computer 4/10/2025 on CPU with 1e-8 tol #Curve = [1, .9, .8, .95, 1] true_sol_case3_curve = 25384.366465 true_sol_case3_pregen = 29049.351564 @@ -113,215 +114,114 @@ function runtests() end #Test MP - for (filename, case, Pd_pregen, Qd_pregen, true_sol_curve, true_sol_pregen) in mp_test_cases - #Curve = [1, .9, .8, .95, 1] - - #Polar - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), curve, polar" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve) - end - end - #w function - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), curve, polar, func" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve) - end - end - #Rect - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), curve, rect" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve) - end - end - #w function - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), curve, rect" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve) - end - end - - - #Pregenerated Pd and Qd - #Polar - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), pregen, polar" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen) - end - end - #w function - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), pregen, polar, func" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen) - end - end - - #Rect - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), pregen, rect" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen) - end - end - #w function - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "$(case), MP, $(T), $(backend), pregen, rect, func" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen) + for (form_str, symbol) in [("polar", :polar), ("rect", :rect)] + for (filename, case, Pd_pregen, Qd_pregen, true_sol_curve, true_sol_pregen) in mp_test_cases + #Curve = [1, .9, .8, .95, 1] + + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), curve, $(form_str)" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve) + end + end + #w function + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), curve, $(form_str), func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve) + end end - end - end - - #Test MP w storage - for (filename, case, Pd_pregen, Qd_pregen, true_sol_curve_stor, - true_sol_curve_stor_func, true_sol_pregen_stor, true_sol_pregen_stor_func) in mp_stor_test_cases - #Polar - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case), $(T), $(backend), curve, polar" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve_stor) - end - end - #Rect - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case), $(T), $(backend), curve, rect" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve_stor) - end - end - - #With function - #Polar - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case), $(T), $(backend), curve, polar, func" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve_stor_func) - end - end - #Rect - m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case) $(T), $(backend), curve, rect, func" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_curve_stor_func) - end - end - #Pregenerated Pd and Qd - #Polar - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case), $(T), $(backend), pregen, polar" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen_stor) - end - end - #Rect - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case), $(T), $(backend), pregen, rect" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen_stor) + #Pregenerated Pd and Qd + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), pregen, $(form_str)" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen) + end + end + #w function + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "$(case), MP, $(T), $(backend), pregen, $(form_str), func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen) + end end end - - #With function - #Polar - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case), $(T), $(backend), pregen, polar, func" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen_stor_func) - end - end - #Rect - m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend, form = :rect) - result = madnlp(m; print_level = MadNLP.ERROR) - @testset "MP w storage, $(case), $(T), $(backend), pregen, rect, func" begin - if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend, form = :rect) - result = madnlp(m64; print_level = MadNLP.ERROR) - test_float32(m, m64, result, backend) - else - test_mp_case(result, true_sol_pregen_stor_func) + + #Test MP w storage + for (filename, case, Pd_pregen, Qd_pregen, true_sol_curve_stor, + true_sol_curve_stor_func, true_sol_pregen_stor, true_sol_pregen_stor_func) in mp_stor_test_cases + + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), curve, $(form_str)" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve_stor) + end + end + + #With function + m, v, c = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), curve, $(form_str), func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_curve_stor_func) + end + end + + #Pregenerated Pd and Qd + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), pregen, $(form_str)" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen_stor) + end + end + + #With function + m, v, c = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = T, backend = backend, form = symbol) + result = madnlp(m; print_level = MadNLP.ERROR) + @testset "MP w storage, $(case), $(T), $(backend), pregen, $(form_str), func" begin + if T == Float32 + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) + result = madnlp(m64; print_level = MadNLP.ERROR) + test_float32(m, m64, result, backend) + else + test_mp_case(result, true_sol_pregen_stor_func) + end end end end From c502712fa060f43d1b652b7e2ef9229c7a2795ad Mon Sep 17 00:00:00 2001 From: SanjayJohnson2 Date: Thu, 17 Apr 2025 18:52:22 -0400 Subject: [PATCH 21/21] Corrected form of m64 to match m --- test/runtests.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index bea5297..6afc7a1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -122,7 +122,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), curve, $(form_str)" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else @@ -134,7 +134,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), curve, $(form_str), func" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else @@ -148,7 +148,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), pregen, $(form_str)" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else @@ -160,7 +160,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "$(case), MP, $(T), $(backend), pregen, $(form_str), func" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else @@ -177,7 +177,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(case), $(T), $(backend), curve, $(form_str)" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else @@ -190,7 +190,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(case), $(T), $(backend), curve, $(form_str), func" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else @@ -203,7 +203,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(case), $(T), $(backend), pregen, $(form_str)" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else @@ -216,7 +216,7 @@ function runtests() result = madnlp(m; print_level = MadNLP.ERROR) @testset "MP w storage, $(case), $(T), $(backend), pregen, $(form_str), func" begin if T == Float32 - m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend) + m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T=Float64, backend = backend, form = symbol) result = madnlp(m64; print_level = MadNLP.ERROR) test_float32(m, m64, result, backend) else