Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ version = "0.3.1"

[deps]
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
ExaModels = "1037b233-b668-4ce9-9b63-f9f681f55dd2"
ExaPowerIO = "14903efe-9500-4d7f-a589-7ab7e15da6de"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"

[compat]
JSON = "0.21"
ExaModels = "0.9"
CUDA = "6"
ExaModels = "0.11"
ExaPowerIO = "0.3"
MadNLP = "0.8"
MadNLPGPU = "0.7"
CUDA = "5"
JSON = "0.21"
MadNLP = "0.10"
MadNLPGPU = "0.10"
julia = "1.11"

[extras]
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e"
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
Expand All @@ -29,4 +30,4 @@ PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "MadNLP", "MadNLPGPU", "KernelAbstractions", "CUDA", "Ipopt", "JuMP", "NLPModelsJuMP", "PowerModels"]
test = ["Test", "MadNLP", "MadNLPGPU", "KernelAbstractions", "CUDA", "CUDSS", "Ipopt", "JuMP", "NLPModelsJuMP", "PowerModels"]
6 changes: 3 additions & 3 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ MadNLPGPU = "d72a61cc-809d-412f-99be-fd81f4b8a598"
ExaModelsPower = "2fff4b78-0b6c-428d-bac8-85ccea8c4bdf"

[compat]
CUDA = "5"
ExaModels = "0.9"
CUDA = "6"
ExaModels = "0.11"

[sources]
ExaModelsPower = {path = ".."}
ExaModelsPower = {path = ".."}
8 changes: 4 additions & 4 deletions docs/src/mpopf_demo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ model, vars, cons = mpopf_model(
backend = CUDABackend(),
corrective_action_ratio = 0.3
)
result = madnlp(model; tol=1e-6)
result = madnlp(model; tol=1e-6, kkt_system = MadNLP.SparseCondensedKKTSystem, linear_solver = MadNLPGPU.CUDSSSolver)

# If the user would like to provide more complex demand profiles, they can provide their own input files. The number of rows in each input file should match the number of buses in the static OPF datafile, and the number of columns will dictate the number of time periods in the MP model.
# First, download the example load profile datafiles.
Expand Down Expand Up @@ -45,7 +45,7 @@ model, vars, cons = mpopf_model(
)

#Solve
result = madnlp(model; tol=1e-6)
result = madnlp(model; tol=1e-6, kkt_system = MadNLP.SparseCondensedKKTSystem, linear_solver = MadNLPGPU.CUDSSSolver)

## MPOPF with storage
# The MPOPF model can also be constructed with storage considerations. We model storage using the model proposed in __[Geth, Coffrin, Fobes 2020](https://arxiv.org/pdf/2004.14768)__. This requires inputting a modified datafile containing storage parameters. When modeling MPOPF with storage, all of the aforementioned tuneable parameters are still available. We also allow the user to specify whether or not to model the charging/discharging complementarity constraint. This is set to false by default to avoid potential numerical error.
Expand All @@ -70,7 +70,7 @@ model, vars, cons = mpopf_model(
backend = CUDABackend(),
storage_complementarity_constraint = false
)
result = madnlp(model; tol=1e-6)
result = madnlp(model; tol=1e-6, kkt_system = MadNLP.SparseCondensedKKTSystem, linear_solver = MadNLPGPU.CUDSSSolver)
result.objective

# ExaModelsPower also provides a secondary option to avoid dealing with complementarity constraints. The user can specify a function that computesloss in battery level as a smooth function of discharge rate and the storage devices thermal rating parameter. We provide an arbitrary example function to demonstrate the modeling capability.
Expand All @@ -88,7 +88,7 @@ model, vars, cons = mpopf_model(
backend = CUDABackend(),
storage_complementarity_constraint = false
)
result = madnlp(model; tol=1e-6)
result = madnlp(model; tol=1e-6, kkt_system = MadNLP.SparseCondensedKKTSystem, linear_solver = MadNLPGPU.CUDSSSolver)
result.objective

# Despite the example discharge function being generated somewhat arbitrarily, the resultant objective values remain quite close for both the smooth and piecewise charge/discharge functions.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/opf_demo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ model, vars, cons = ac_opf_model(
model

# Once the model is built, we can generate a solution using MadNLP.
result = madnlp(model; tol=1e-6)
result = madnlp(model; tol=1e-6, kkt_system = MadNLP.SparseCondensedKKTSystem, linear_solver = MadNLPGPU.CUDSSSolver)

# Once a solution has been generated, the values of any of the variables in the model can be unpacked using the vars NamedTuple.
solution(result, vars.vm)[1:10]
Expand Down
4 changes: 2 additions & 2 deletions src/dcopf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function build_dcopf(data, user_callback; backend = nothing, T = Float64, core =


vars2, cons2 = user_callback(core, vars, cons)
model =ExaModel(core; kwargs...)
model = ExaModel(core; prod = true, kwargs...)

vars = (;vars..., vars2...)
cons = (;cons..., cons2...)
Expand Down Expand Up @@ -90,7 +90,7 @@ function dcopf_model(
user_callback = dummy_extension,
kwargs...,
)
data = parse_ac_power_data(filename)
data = parse_ac_power_data(filename, T)
data = convert_data(data, backend)

return build_dcopf(data, user_callback; backend = backend, T = T, kwargs...)
Expand Down
20 changes: 10 additions & 10 deletions src/mpopf.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
function parse_mp_power_data(filename, N, corrective_action_ratio)
function parse_mp_power_data(filename, N, corrective_action_ratio, T = Float64)

data = parse_ac_power_data(filename)
data = parse_ac_power_data(filename, T)

nbus = length(data.bus)

Expand All @@ -27,7 +27,7 @@ function update_load_data(busarray, curve)
for x in 1:size(busarray, 1)
b = busarray[x, t]
busarray[x, t] = (
b=ExaPowerIO.BusData(
b=ExaPowerIO.BusData{typeof(b.b.pd)}(
b.b.i,
b.b.bus_i,
b.b.type,
Expand All @@ -53,7 +53,7 @@ function update_load_data(busarray, pd, qd, baseMVA)
for (idx ,pd_t) in pairs(pd)
b = busarray[idx[1], idx[2]]
busarray[idx[1], idx[2]] = (
b=ExaPowerIO.BusData(
b=ExaPowerIO.BusData{typeof(b.b.pd)}(
b.b.i,
b.b.bus_i,
b.b.type,
Expand Down Expand Up @@ -235,7 +235,7 @@ function build_mpopf(data, Nbus, N, form, user_callback; backend = nothing, T =
end

vars2, cons2 = user_callback(core, vars, cons)
model =ExaModel(core; kwargs...)
model = ExaModel(core; prod = true, kwargs...)

vars = (;vars..., vars2...)
cons = (;cons..., cons2...)
Expand All @@ -255,7 +255,7 @@ function build_mpopf(data, Nbus, N, discharge_func::Function, form, user_callbac
end

vars2, cons2 = user_callback(core, vars, cons)
model =ExaModel(core; kwargs...)
model = ExaModel(core; prod = true, kwargs...)

vars = (;vars..., vars2...)
cons = (;cons..., cons2...)
Expand Down Expand Up @@ -421,7 +421,7 @@ function mpopf_model(
)

@assert length(curve) > 0
data = parse_mp_power_data(filename, N, corrective_action_ratio)
data = parse_mp_power_data(filename, N, corrective_action_ratio, T)
update_load_data(data.busarray, curve)
data = convert_data(data,backend)
Nbus = size(data.bus, 1)
Expand All @@ -447,7 +447,7 @@ function mpopf_model(
kwargs...,
)

data = parse_mp_power_data(filename, N, corrective_action_ratio)
data = parse_mp_power_data(filename, N, corrective_action_ratio, T)
update_load_data(data.busarray, pd, qd, data.baseMVA[])
data = convert_data(data,backend)
Nbus = size(data.bus, 1)
Expand All @@ -473,7 +473,7 @@ function mpopf_model(
)

@assert length(curve) > 0
data = parse_mp_power_data(filename, N, corrective_action_ratio)
data = parse_mp_power_data(filename, N, corrective_action_ratio, T)
update_load_data(data.busarray, curve)
data = convert_data(data,backend)
Nbus = size(data.bus, 1)
Expand All @@ -500,7 +500,7 @@ function mpopf_model(
)


data = parse_mp_power_data(filename, N, corrective_action_ratio)
data = parse_mp_power_data(filename, N, corrective_action_ratio, T)
update_load_data(data.busarray, pd, qd, data.baseMVA[])
data = convert_data(data,backend)
Nbus = size(data.bus, 1)
Expand Down
6 changes: 3 additions & 3 deletions src/opf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function build_polar_opf(data, user_callback; backend = nothing, T=Float64, kwar
)

vars2, cons2 = user_callback(core, vars, cons)
model =ExaModel(core; kwargs...)
model = ExaModel(core; prod = true, kwargs...)

vars = (;vars..., vars2...)
cons = (;cons..., cons2...)
Expand Down Expand Up @@ -186,7 +186,7 @@ function build_rect_opf(data, user_callback; backend = nothing, T=Float64, kwarg
)

vars2, cons2 = user_callback(core, vars, cons)
model =ExaModel(core; kwargs...)
model = ExaModel(core; prod = true, kwargs...)

vars = (;vars..., vars2...)
cons = (;cons..., cons2...)
Expand Down Expand Up @@ -222,7 +222,7 @@ function ac_opf_model(
kwargs...,
)

data = parse_ac_power_data(filename)
data = parse_ac_power_data(filename, T)
data = convert_data(data, backend)

if form == :polar
Expand Down
4 changes: 2 additions & 2 deletions src/parser.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
convert_data(data::N, backend) where {names,N<:NamedTuple{names}} =
NamedTuple{names}(convert_array(d, backend) for d in data)

function parse_ac_power_data(filename)
function parse_ac_power_data(filename, T = Float64)
_, f = splitdir(filename)
name, _ = splitext(f)

@info "Loading matpower file"

library = isfile(filename) ? nothing : :pglib
data = ExaPowerIO.parse_matpower(filename; library)
data = ExaPowerIO.parse_matpower(T, filename; library)

data = (
baseMVA = [data.baseMVA],
Expand Down
2 changes: 1 addition & 1 deletion src/scopf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ function goc3_model(
end

vars2, cons2 = user_callback(core, vars, cons)
model =ExaModel(core; kwargs...)
model = ExaModel(core; prod = true, kwargs...)

vars = (;vars..., vars2...)
cons = (;cons..., cons2...)
Expand Down
14 changes: 13 additions & 1 deletion test/opf_tests.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# On a CUDA backend, MadNLP's defaults (SparseKKTSystem + MUMPS) are CPU-only and cannot
# assemble the KKT matrix from device arrays, so solve the condensed system with cuDSS on
# the GPU. On the CPU, pin the linear solver to Umfpack: MadNLP 0.10 changed the sparse
# default to MUMPS, which drives these OPFs into restoration, whereas Umfpack (the default
# through MadNLP 0.8, and what main uses) converges cleanly.
function exasolve(model, backend; kwargs...)
opts = backend isa CUDABackend ?
(; kkt_system = MadNLP.SparseCondensedKKTSystem, linear_solver = MadNLPGPU.CUDSSSolver) :
(; linear_solver = MadNLP.UmfpackSolver)
return madnlp(model; opts..., kwargs...)
end

function test_case3(result, result_pm, result_nlp_pm, pg, qg, p, q)
test_static_case(result, result_pm, result_nlp_pm, pg, qg)

Expand Down Expand Up @@ -70,7 +82,7 @@ function sc_tests(filename, backend, T)
uc_filename = filename*"_solution.json"
filename = filename*".json"
model, cons, vars, lengths, sc_data_array = ExaModelsPower.goc3_model(filename, uc_filename; backend=backend, T=T)
result = madnlp(model; max_iter=5, tol=1e-2)
result = exasolve(model, backend; max_iter=5, tol=1e-2)
end

function test_dcopf_case(result, result_pm, pg, pf)
Expand Down
42 changes: 21 additions & 21 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, PowerModels, Ipopt, JuMP, ExaModels, NLPModelsJuMP
using Test, ExaModelsPower, MadNLP, MadNLPGPU, KernelAbstractions, CUDA, CUDSS, PowerModels, Ipopt, JuMP, ExaModels, NLPModelsJuMP

include("opf_tests.jl")

Expand Down Expand Up @@ -106,11 +106,11 @@ function runtests()
data_pm = parse_pm(filename)
for (form_str, form, power_model, test_voltage) in static_forms
m32, v32, c32 = ac_opf_model(filename; T=Float32, backend = backend, form=form)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
va32, vm32, pg32, qg32, p32, q32 = v32

m64, v64, c64 = ac_opf_model(filename; T=Float64, backend = backend, form=form)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
va64, vm64, pg64, qg64, p64, q64 = v64

nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>Float64(result64.options.tol), "print_level"=>0)
Expand All @@ -136,18 +136,18 @@ function runtests()
#Curve = [1, .9, .8, .95, 1]

m32, v32, c32 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "$(case), MP, $(T), $(backend), curve, $(form_str)" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_curve)
end
#w function
m32, v32, c32 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "$(case), MP, $(T), $(backend), curve, $(form_str), func" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_curve)
Expand All @@ -156,18 +156,18 @@ function runtests()

#Pregenerated Pd and Qd
m32, v32, c32 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "$(case), MP, $(T), $(backend), pregen, $(form_str)" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_pregen)
end
#w function
m32, v32, c32 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "$(case), MP, $(T), $(backend), pregen, $(form_str), func" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_pregen)
Expand All @@ -179,39 +179,39 @@ function runtests()
true_sol_curve_stor_func, true_sol_pregen_stor, true_sol_pregen_stor_func) in mp_stor_test_cases

m32, v32, c32 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1]; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "MP w storage, $(case), $(T), $(backend), curve, $(form_str)" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_curve_stor)
end

#With function
m32, v32, c32 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, [1, .9, .8, .95, 1], example_func; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "MP w storage, $(case), $(T), $(backend), curve, $(form_str), func" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_curve_stor_func)
end

#Pregenerated Pd and Qd
m32, v32, c32 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "MP w storage, $(case), $(T), $(backend), pregen, $(form_str)" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_pregen_stor)
end

#With function
m32, v32, c32 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = Float32, backend = backend, form = symbol)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)
m64, v64, c64 = eval(mpopf_model)(filename, Pd_pregen, Qd_pregen, example_func; T = Float64, backend = backend, form = symbol)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
@testset "MP w storage, $(case), $(T), $(backend), pregen, $(form_str), func" begin
test_float32(m32, m64, result64, backend)
test_mp_case(result64, true_sol_pregen_stor_func)
Expand All @@ -222,10 +222,10 @@ function runtests()
for (filename, case, _) in test_cases
@testset "$case, DCOPF, $backend" begin
m32, v32, c32 = dcopf_model(filename; T=Float32, backend = backend)
result32 = madnlp(m32; print_level = MadNLP.ERROR)
result32 = exasolve(m32, backend; print_level = MadNLP.ERROR)

m64, v64, c64 = dcopf_model(filename; T=Float64, backend = backend)
result64 = madnlp(m64; print_level = MadNLP.ERROR)
result64 = exasolve(m64, backend; print_level = MadNLP.ERROR)
va64, pg64, pf64 = v64

nlp_solver = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "tol"=>Float64(result64.options.tol), "print_level"=>0)
Expand Down
Loading