Static OPF
ExaModelsPower.jl can model large-scale optimal power flow (OPF) problems using the ExaModels package to generate models that can be solved using either CPU or GPU. This tutorial will demonstrate how ExaModelsPower.jl can be leveraged to solve different versions of the OPF, and how the user can customize the solving technique to better match their needs. Currently, all models generated by ExaModelsPower represent the full, AC version of the OPF formulation without any simplifications.
The latest version of ExaModelsPower can be installed in julia as so. Additionally, in order to develop models that can be solved on the GPU, CUDA is required.
using ExaModelsPower, CUDA
In order to solve the ExaModels developed by ExaModelsPower, an NLP solver is required. ExaModels is compatible with MadNLP and Ipopt, but this tutorial will focus on MadNLP to demonstrate GPU solving capabilities.
using MadNLP, MadNLPGPU #, NLPModelsIpopt
Finally, we install ExaModels to allow solved models to be unpacked.
using ExaModels
We will begin by constructing and solving a static OPF using the function opf_model. For the static OPF, the only input required is the filename for the OPF matpower file. The file does not need to be locally installed, and it will be automatically downloaded from power-grid-library if the file is not found in the user's data folder. If keywords are not specified, the numerical type will default to Float64, the backend will default to nothing (used on CPU) and the form will default to polar coordinates.
model, vars, cons = opf_model(
"pglib_opf_case118_ieee.m";
backend = CUDABackend(),
form = :polar,
T = Float64
);
model
An ExaModel{Float64, CUDA.CuArray{Float64, 1, CUDA.DeviceMemory}, ...}
Problem name: Generic
All variables: ████████████████████ 1088 All constraints: ████████████████████ 1539
free: ███⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 118 free: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
lower: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 lower: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
upper: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 upper: █████⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 372
low/upp: ██████████████████⋅⋅ 935 low/upp: ███⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 186
fixed: █⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 35 fixed: █████████████⋅⋅⋅⋅⋅⋅⋅ 981
infeas: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 infeas: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
nnzh: ( 98.57% sparsity) 8474 linear: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
nonlinear: ████████████████████ 1539
nnzj: ( 99.65% sparsity) 5925
Once the model is built, we can generate a solution using MadNLP.
result = madnlp(model; tol=1e-6)
"Execution stats: Optimal Solution Found (tol = 1.0e-06)."
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]
10-element CUDA.CuArray{Float64, 1, CUDA.DeviceMemory}:
1.05807251471806
1.0115214146065403
1.0371945440877253
1.0127115639238602
1.0170524545918345
1.054436931653613
1.0575146839021448
1.0303511034471644
1.041850151876131
1.0519359527782988
Result also stores the objective value.
result.objective
97210.50257419972
ExaModelsPower supports solving the OPF in either polar or rectangular coordinates.
model, vars, cons = opf_model(
"pglib_opf_case118_ieee.m";
form = :rect
)
result = madnlp(model; tol=1e-6)
result.objective
97213.60754650863
In this case, the objective value and performance speed is comparable. However, for some cases, MadNLP can only solve the problem on one of the two available coordinate systems.
This page was generated using Literate.jl.