Skip to content

Commit 743abcb

Browse files
Documentation update
1 parent 39006c8 commit 743abcb

File tree

9 files changed

+421
-0
lines changed

9 files changed

+421
-0
lines changed

docs/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[deps]
2+
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"

docs/make.jl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Pkg
2+
Pkg.activate("..") # assumes docs/ is a subfolder of the main project
3+
4+
using Documenter, ExaModelsPower, DocumenterCitations, Literate
5+
6+
if !(@isdefined _PAGES)
7+
const _PAGES = [
8+
"Introduction" => "Introduction.md",
9+
"Tutorial" => [
10+
"opf_demo.md",
11+
"mpopf_demo.md"
12+
],
13+
"OPF Formulations" => "opfs_doc.md",
14+
"API Manual" => "core.md"
15+
]
16+
end
17+
18+
if !(@isdefined _JL_FILENAMES)
19+
const _JL_FILENAMES = [
20+
"opf_demo.jl",
21+
"mpopf_demo.jl"
22+
]
23+
end
24+
25+
for jl_filename in _JL_FILENAMES
26+
27+
Literate.markdown(
28+
joinpath(@__DIR__, "src", jl_filename),
29+
joinpath(@__DIR__, "src");
30+
documenter = true,
31+
execute = true,
32+
)
33+
34+
end
35+
36+
37+
makedocs(;
38+
sitename = "My Documentation",
39+
modules = [ExaModelsPower],
40+
remotes = nothing,
41+
pages = _PAGES
42+
)

docs/src/Introduction.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Introduction
2+
3+
Welcome to the documentation of [ExaModelsPower.jl](https://github.com/exanauts/ExaModelsPower.jl)
4+
!!! note
5+
ExaModelsPower runs on julia `VERSION ≥ v"1.9"`
6+
7+
!!! warning
8+
**Please help us improve ExaModelsPower and this documentation!** ExaModelsPower is in the early stage of development, and you may encounter unintended behaviors or missing documentations. If you find anything is not working as intended or documentation is missing, please [open issues](https://github.com/exanauts/ExaModelsPower.jl/issues) or [pull requests](https://github.com/exanauts/ExaModelsPower.jl/pulls) or start [discussions](https://github.com/exanauts/ExaModelsPower.jl/discussions).
9+
10+
## What is ExaModelsPower.jl?
11+
ExaModelsPower.jl is a Julia package for creating optimal power flow (OPF) models. Unlike other OPF modeling frameworks, ExaModelsPower.jl leverages the capabilities of [ExaModels.jl](https://exanauts.github.io/ExaModels.jl/stable/) in order to solve more complex, large-scale versions of the OPF. ExaModels.jl employs what we call [SIMD](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data) abstraction for [nonlinear programs](https://en.wikipedia.org/wiki/Nonlinear_programming) (NLPs), which allows for the preservation of the parallelizable structure within the model equations, facilitating efficient [automatic differentiation](https://en.wikipedia.org/wiki/Automatic_differentiation) either on the single-thread CPUs, multi-threaded CPUs, as well as [GPU accelerators](https://en.wikipedia.org/wiki/Graphics_processing_unit). More details about SIMD abstraction can be found [here](https://exanauts.github.io/ExaModels.jl/v0.8/simd/). ExaModels.jl compiles (via Julia's compiler) derivative evaluation codes tailored to each computation pattern. Through reverse-mode automatic differentiation using these tailored codes, ExaModels.jl achieves significantly faster derivative evaluation speeds, even when using CPU.
12+
13+
Recent benchmark results demonstrate that derivative evaluation using ExaModels.jl on GPU can be up to two orders of magnitude faster compared to JuMP or AMPL. This enables us to implement more complex versions of the OPF without needing any relaxations. Currently, ExaModelsPower.jl supports developing models for static OPF, multi-period OPF with or without storage, and security constrained OPF. ExaModelsPower.jl also supports a number of flexible options for the user to specify model coordinate system, setup of time-varying demand profiles, and handling of complementarity constraints for storage models.
14+
15+
## Supported Solvers
16+
ExaModelsPower can be used with any solver that can handle `NLPModel` data type, but several callbacks are not currently implemented, and cause some errors. Currently, it is tested with the following solvers:
17+
- [Ipopt](https://github.com/JuliaSmoothOptimizers/NLPModelsIpopt.jl) (via [NLPModelsIpopt.jl](https://github.com/JuliaSmoothOptimizers/NLPModelsIpopt.jl))
18+
- [MadNLP.jl](https://github.com/MadNLP/MadNLP.jl)
19+
20+
## Documentation Structure
21+
This documentation is structured in the following way.
22+
- This page provides some introductory information about ExaModelsPower.jl
23+
- The step-by-step tutorial of using ExaModelsPower.jl can be found in TK.
24+
- The API Manual provides information on functions provided within ExaModelsPower.jl, as well as information on the constraints and variables implemented in the static and multi-period OPFs
25+
26+
27+
## Supporting ExaModelsPower.jl
28+
- Please report issues and feature requests via the [GitHub issue tracker](https://github.com/exanauts/ExaModelsPower.jl/issues).
29+
- Questions are welcome at [GitHub discussion forum](https://github.com/exanauts/ExaModelsPower.jl/discussions).

docs/src/core.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```@autodocs
2+
Modules = [ExaModelsPower]
3+
```

docs/src/mpopf_demo.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
```@meta
2+
EditURL = "mpopf_demo.jl"
3+
```
4+
5+
# [Multi-period OPF](@id mpopf_demo)
6+
7+
The multi-period (MP) OPF can also be modeled in ExaModelsPower with a number of user-specified adjustments, including storage.
8+
9+
Some of the models in this portion of the tutorial involve using external files. While we provide the necessary code to access these additional files, you may view them __[here](https://github.com/mit-shin-group/multi-period-opf-data)__ as well.
10+
We will start with the simplest way to model the MPOPF, which also does not require the user to have any data already downloaded. Instead, the user specifies a demand curve for the system. The demand curve is a vector of ratios from 0 to 1 which indicate the scaling of demand compared to the demand indicated by the static OPF file. In this model of the MPOPF, every consuming bus has the same scaling in power demand for each point in time. A corrective action ratio, which limits the ramp rate of generators, can also be inputted. It is set to 0.1 as a default. The adjustable coordinate system and backend that were present for the static OPF are also available for all MPOPF models.
11+
12+
````julia
13+
using ExaModelsPower, CUDA, MadNLP, MadNLPGPU, ExaModels
14+
model, vars, cons = mpopf_model(
15+
"pglib_opf_case118_ieee.m", # static network data
16+
[.64, .60, .58, .56, .56, .58, .64, .76, .87, .95, .99, 1.0, .99, 1.0, 1.0,
17+
.97, .96, .96, .93, .92, .92, .93, .87, .72, .64], #Demand curve
18+
backend = CUDABackend(),
19+
corrective_action_ratio = 0.3
20+
)
21+
result = madnlp(model; tol=1e-6)
22+
````
23+
24+
````
25+
"Execution stats: Optimal Solution Found (tol = 1.0e-06)."
26+
````
27+
28+
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.
29+
First, download the example load profile datafiles.
30+
31+
````julia
32+
using Downloads
33+
34+
#Define URLs for Pd and Qd data files (raw or raw GitHub links)
35+
pd_url = "https://raw.githubusercontent.com/mit-shin-group/multi-period-opf-data/refs/heads/main/halfhour_30.Pd"
36+
qd_url = "https://raw.githubusercontent.com/mit-shin-group/multi-period-opf-data/refs/heads/main/halfhour_30.Qd"
37+
38+
#Define local paths to temporarily store the files
39+
pd_file = "halfhour_30.Pd"
40+
qd_file = "halfhour_30.Qd"
41+
42+
#Download the files if they don't already exist
43+
if !isfile(pd_file)
44+
Downloads.download(pd_url, pd_file)
45+
end
46+
47+
if !isfile(qd_file)
48+
Downloads.download(qd_url, qd_file);
49+
end
50+
````
51+
52+
Next, build the MPOPF model, providing the dynamic load data instead of a demand curve as input.
53+
54+
````julia
55+
#Run your model
56+
model, vars, cons = mpopf_model(
57+
"pglib_opf_case30_ieee.m", # static network data (assumed local or already handled)
58+
pd_file, # dynamic load data (Pd)
59+
qd_file; # dynamic load data (Qd)
60+
backend = CUDABackend()
61+
)
62+
63+
#Solve
64+
result = madnlp(model; tol=1e-6)
65+
66+
# MPOPF with storage
67+
````
68+
69+
````
70+
"Execution stats: Optimal Solution Found (tol = 1.0e-06)."
71+
````
72+
73+
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.
74+
75+
````julia
76+
#First, we download the modified datafile with storage parameters included.
77+
#Define URL for the main datafile
78+
stor_url = "https://raw.githubusercontent.com/mit-shin-group/multi-period-opf-data/refs/heads/main/pglib_opf_case30_ieee_mod.m"
79+
80+
#Define local path to temporarily store the file
81+
stor_file = "pglib_opf_case30_ieee_mod.m"
82+
83+
#Download the file if it doesn't already exist
84+
if !isfile(stor_file)
85+
Downloads.download(stor_url, stor_file);
86+
end
87+
````
88+
89+
Generate the model with your modified datafile. If the datafile contains storage parameters, ExaModelsPower will automatically recognize it and include the additional necessary constraints.
90+
91+
````julia
92+
model, vars, cons = mpopf_model(
93+
stor_file, # static network data with storage parameters
94+
pd_file, # dynamic load data (Pd)
95+
qd_file; # dynamic load data (Qd)
96+
backend = CUDABackend(),
97+
storage_complementarity_constraint = false
98+
)
99+
result = madnlp(model; tol=1e-6)
100+
result.objective
101+
````
102+
103+
````
104+
299068.0404892947
105+
````
106+
107+
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.
108+
109+
````julia
110+
function example_function(d, srating)
111+
return d + .2/srating*d^2
112+
end;
113+
````
114+
115+
ExaModelsPower will automatically adjust the necessary constraints if one of the inputs provided is a function.
116+
117+
````julia
118+
model, vars, cons = mpopf_model(
119+
stor_file, # static network data with storage parameters
120+
pd_file, # dynamic load data (Pd)
121+
qd_file, # dynamic load data (Qd)
122+
example_function; # discharge function
123+
backend = CUDABackend(),
124+
storage_complementarity_constraint = false
125+
)
126+
result = madnlp(model; tol=1e-6)
127+
result.objective
128+
````
129+
130+
````
131+
299044.324045392
132+
````
133+
134+
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.
135+
136+
---
137+
138+
*This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*
139+

docs/src/opf_demo.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
```@meta
2+
EditURL = "opf_demo.jl"
3+
```
4+
5+
# [Static OPF](@id opf_demo)
6+
7+
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.
8+
9+
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.
10+
11+
````julia
12+
using ExaModelsPower, CUDA
13+
````
14+
15+
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.
16+
17+
````julia
18+
using MadNLP, MadNLPGPU #, NLPModelsIpopt
19+
````
20+
21+
Finally, we install ExaModels to allow solved models to be unpacked.
22+
23+
````julia
24+
using ExaModels
25+
````
26+
27+
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](https://github.com/power-grid-lib/pglib-opf)__ 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.
28+
29+
````julia
30+
model, vars, cons = opf_model(
31+
"pglib_opf_case118_ieee.m";
32+
backend = CUDABackend(),
33+
form = :polar,
34+
T = Float64
35+
);
36+
model
37+
````
38+
39+
````
40+
An ExaModel{Float64, CUDA.CuArray{Float64, 1, CUDA.DeviceMemory}, ...}
41+
42+
Problem name: Generic
43+
All variables: ████████████████████ 1088 All constraints: ████████████████████ 1539
44+
free: ███⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 118 free: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
45+
lower: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 lower: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
46+
upper: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 upper: █████⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 372
47+
low/upp: ██████████████████⋅⋅ 935 low/upp: ███⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 186
48+
fixed: █⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 35 fixed: █████████████⋅⋅⋅⋅⋅⋅⋅ 981
49+
infeas: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0 infeas: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
50+
nnzh: ( 98.57% sparsity) 8474 linear: ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ 0
51+
nonlinear: ████████████████████ 1539
52+
nnzj: ( 99.65% sparsity) 5925
53+
54+
55+
````
56+
57+
Once the model is built, we can generate a solution using MadNLP.
58+
59+
````julia
60+
result = madnlp(model; tol=1e-6)
61+
````
62+
63+
````
64+
"Execution stats: Optimal Solution Found (tol = 1.0e-06)."
65+
````
66+
67+
Once a solution has been generated, the values of any of the variables in the model can be unpacked using the vars NamedTuple.
68+
69+
````julia
70+
solution(result, vars.vm)[1:10]
71+
````
72+
73+
````
74+
10-element CUDA.CuArray{Float64, 1, CUDA.DeviceMemory}:
75+
1.0580725147179784
76+
1.0115214146058313
77+
1.0371945440878167
78+
1.0127115639231665
79+
1.017052454591496
80+
1.054436931655935
81+
1.0575146839020813
82+
1.030351103447083
83+
1.0418501518762922
84+
1.0519359527783783
85+
````
86+
87+
Result also stores the objective value.
88+
89+
````julia
90+
result.objective
91+
````
92+
93+
````
94+
97210.50257420563
95+
````
96+
97+
ExaModelsPower supports solving the OPF in either polar or rectangular coordinates.
98+
99+
````julia
100+
model, vars, cons = opf_model(
101+
"pglib_opf_case118_ieee.m";
102+
form = :rect
103+
)
104+
result = madnlp(model; tol=1e-6)
105+
result.objective
106+
````
107+
108+
````
109+
97213.56501338647
110+
````
111+
112+
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.
113+
114+
---
115+
116+
*This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*
117+

docs/src/opfs_doc.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Optimal Power Flow Formulation
2+
3+
The AC optimal power flow (ACOPF) formulation is a problem characterizing the nonlinear optimization problem which independent service operators must solve to route power through transmission systems. The OPF has also been built upon, leading to even more complex models that account for other considerations such as multiperiodicity and reliability. This documentation provides a brief outline of the key features of each version of the OPF modeled in ExaModelsPower.jl.
4+
5+
## Static OPF
6+
The static OPF is the most basic version of the OPF, implemented over just a single time period. While some simplifications can be made to the model to make it easier to solve, the version implemented in ExaModelsPower.jl is the full, unrelaxed version. The focal constraint in the static OPF is the power balance - this constraint requires that the power generated at each bus is matched by the power consumed, shunt losses, and net power flow from the bus to others via transmission lines.
7+
8+
A central complexity of the ACOPF is calculating the power transfer along transmission lines, which requires the following nonlinear constraint in polar coordinates, where G and B are parameters of the line, n and m are bus indeces, and V and θ represent voltage and phase angle.
9+
10+
$$$
11+
P_n = \sum_{mk} V_n V_m \left( G_{nmk} \cos \theta_{nm} + B_{nmk} \sin \theta_{nm} \right)
12+
$$$
13+
14+
Due to the computational challenges introduced by these equations, ExaModelsPower.jl implements the OPF in both polar and rectangular coordinates to provide flexibility in the case that a certain algorithm may be more capable of performing computations for certain forms of nonlinear equations.
15+
16+
A more complete description of the static OPF can be found [here](https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=16f56c56e83bb2e2fa98a1400dcf9367f04783b6).
17+
18+
## Multi-period OPF
19+
The multi-period OPF (MPOPF) is a simple variant of the static OPF, but it can introduce powerful results. The MPOPF expands variables across time periods, requiring the same balance as in the static OPF to be balanced for each time period. This allows for the evaluation of real-world problems that involve fluctuating demand over time. The MPOPF also introduces an additional constraint to restrict how quickly generators can ramp up or down.
20+
$$$
21+
-\Delta P \leq P_{g,t} - P_{g,t-1} \leq \Delta P
22+
$$$
23+
24+
## MPOPF with storage
25+
The MPOPF also enables the introduction of storage devices to the model. We model storage devices as discussed in __[Geth, Coffrin, Fobes 2020](https://arxiv.org/pdf/2004.14768)__ [2]. Transfer of power to and from storage devices along with associated losses are now included in the overall power balance for each bus.
26+
27+
One challenge of implementing storage is the complementarity constraint that prevents storage devices from charging and discharging simultaneously. In order to not introduce integer variables, the constraint is implemented as so:
28+
$$$
29+
P_{d} \cdot P_{c} = 0
30+
$$$
31+
32+
This formulation can lead to errors arising from numerical imprecision. As a result, ExaModelsPower.jl provides several options to avoid the explicit implementation of this complementarity constraint.

0 commit comments

Comments
 (0)