Skip to content

Commit 6e746f6

Browse files
documentation updates
1 parent 743abcb commit 6e746f6

File tree

12 files changed

+243
-26
lines changed

12 files changed

+243
-26
lines changed

.github/workflows/docs.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Documentation
2+
3+
on:
4+
push:
5+
branches:
6+
- main # update to match your development branch (master, main, dev, trunk, ...)
7+
- documentation
8+
tags: '*'
9+
pull_request:
10+
11+
jobs:
12+
build:
13+
runs-on: self-hosted
14+
steps:
15+
- uses: actions/checkout@v2
16+
- uses: julia-actions/setup-julia@latest
17+
with:
18+
version: '1.9'
19+
- name: Install dependencies
20+
run: julia --project=docs/ -e 'using Pkg; Pkg.Registry.update(); Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
21+
- name: Build and deploy
22+
env:
23+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # If authenticating with GitHub Actions token
24+
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # If authenticating with SSH deploy key
25+
run: julia --project=docs/ docs/make.jl

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ ExaModelsPower.jl is an optimal power flow models using ExaModels.jl
33

44
![CI](https://github.com/exanauts/ExaModelsPower.jl/actions/workflows/ci.yml/badge.svg)
55
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6+
[![doc](https://img.shields.io/badge/docs-stable-blue.svg)](https://exanauts.github.io/ExaModelsPower.jl/stable)
67

78
## Usage
89
### Static optimal power flow

docs/make.jl

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ if !(@isdefined _PAGES)
1111
"mpopf_demo.md"
1212
],
1313
"OPF Formulations" => "opfs_doc.md",
14-
"API Manual" => "core.md"
14+
"API Manual" => "core.md",
15+
"References" => "ref.md"
1516
]
1617
end
1718

@@ -33,10 +34,24 @@ for jl_filename in _JL_FILENAMES
3334

3435
end
3536

37+
bib = CitationBibliography(joinpath(@__DIR__, "src", "refs.bib"))
3638

3739
makedocs(;
38-
sitename = "My Documentation",
40+
plugins = [bib],
41+
sitename = "ExaModelsPower.jl",
3942
modules = [ExaModelsPower],
4043
remotes = nothing,
41-
pages = _PAGES
42-
)
44+
authors = "Sungho Shin, Sanjay Johnson",
45+
format = Documenter.HTML(
46+
assets = ["assets/citations.css"],
47+
prettyurls = true,
48+
sidebar_sitename = true,
49+
collapselevel = 1,
50+
),
51+
pages = _PAGES,
52+
clean = false
53+
)
54+
55+
deploydocs(repo = "github.com/exanauts/ExaModelsPower.jl.git"; push_preview = true)
56+
57+
#- The step-by-step tutorials of using ExaModelsPower.jl can be found in [OPF tutorial](@ref opf_demo) and [MPOPF tutorial](@ref mpopf_demo).

docs/src/Introduction.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Welcome to the documentation of [ExaModelsPower.jl](https://github.com/exanauts/
1010
## What is ExaModelsPower.jl?
1111
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.
1212

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.
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 [shin2024scalablemultiperiodacoptimal](@cite). 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.
1414

1515
## Supported Solvers
1616
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:
@@ -20,7 +20,7 @@ ExaModelsPower can be used with any solver that can handle `NLPModel` data type,
2020
## Documentation Structure
2121
This documentation is structured in the following way.
2222
- This page provides some introductory information about ExaModelsPower.jl
23-
- The step-by-step tutorial of using ExaModelsPower.jl can be found in TK.
23+
- The step-by-step tutorials of using ExaModelsPower.jl can be found in [OPF tutorial](@ref opf_demo) and [MPOPF tutorial](@ref mpopf_demo).
2424
- 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
2525

2626

docs/src/assets/extra.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
img[alt=benchmark] { width: 100vw; }
2+
3+
.citation dl {
4+
display: grid;
5+
grid-template-columns: max-content auto; }
6+
.citation dt {
7+
grid-column-start: 1; }
8+
.citation dd {
9+
grid-column-start: 2;
10+
margin-bottom: 0.75em; }
11+
.citation ul {
12+
padding: 0 0 2.25em 0;
13+
margin: 0;
14+
list-style: none;}
15+
.citation ul li {
16+
text-indent: -2.25em;
17+
margin: 0.33em 0.5em 0.5em 2.25em;}
18+
.citation ol li {
19+
padding-left:0.75em;}

docs/src/mpopf_demo.jl

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# # [Multi-period OPF](@id mpopf_demo)
2+
3+
# The multi-period (MP) OPF can also be modeled in ExaModelsPower with a number of user-specified adjustments, including storage.
4+
5+
# 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.
6+
# 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.
7+
using ExaModelsPower, CUDA, MadNLP, MadNLPGPU, ExaModels
8+
model, vars, cons = mpopf_model(
9+
"pglib_opf_case118_ieee.m", # static network data
10+
[.64, .60, .58, .56, .56, .58, .64, .76, .87, .95, .99, 1.0, .99, 1.0, 1.0,
11+
.97, .96, .96, .93, .92, .92, .93, .87, .72, .64], #Demand curve
12+
backend = CUDABackend(),
13+
corrective_action_ratio = 0.3
14+
)
15+
result = madnlp(model; tol=1e-6)
16+
17+
# 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.
18+
# First, download the example load profile datafiles.
19+
using Downloads
20+
21+
#Define URLs for Pd and Qd data files (raw or raw GitHub links)
22+
pd_url = "https://raw.githubusercontent.com/mit-shin-group/multi-period-opf-data/refs/heads/main/halfhour_30.Pd"
23+
qd_url = "https://raw.githubusercontent.com/mit-shin-group/multi-period-opf-data/refs/heads/main/halfhour_30.Qd"
24+
25+
#Define local paths to temporarily store the files
26+
pd_file = "halfhour_30.Pd"
27+
qd_file = "halfhour_30.Qd"
28+
29+
#Download the files if they don't already exist
30+
if !isfile(pd_file)
31+
Downloads.download(pd_url, pd_file)
32+
end
33+
34+
if !isfile(qd_file)
35+
Downloads.download(qd_url, qd_file);
36+
end
37+
38+
# Next, build the MPOPF model, providing the dynamic load data instead of a demand curve as input.
39+
#Run your model
40+
model, vars, cons = mpopf_model(
41+
"pglib_opf_case30_ieee.m", # static network data (assumed local or already handled)
42+
pd_file, # dynamic load data (Pd)
43+
qd_file; # dynamic load data (Qd)
44+
backend = CUDABackend()
45+
)
46+
47+
#Solve
48+
result = madnlp(model; tol=1e-6)
49+
50+
## MPOPF with storage
51+
# 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.
52+
53+
#First, we download the modified datafile with storage parameters included.
54+
#Define URL for the main datafile
55+
stor_url = "https://raw.githubusercontent.com/mit-shin-group/multi-period-opf-data/refs/heads/main/pglib_opf_case30_ieee_mod.m"
56+
57+
#Define local path to temporarily store the file
58+
stor_file = "pglib_opf_case30_ieee_mod.m"
59+
60+
#Download the file if it doesn't already exist
61+
if !isfile(stor_file)
62+
Downloads.download(stor_url, stor_file);
63+
end
64+
65+
# Generate the model with your modified datafile. If the datafile contains storage parameters, ExaModelsPower will automatically recognize it and include the additional necessary constraints.
66+
model, vars, cons = mpopf_model(
67+
stor_file, # static network data with storage parameters
68+
pd_file, # dynamic load data (Pd)
69+
qd_file; # dynamic load data (Qd)
70+
backend = CUDABackend(),
71+
storage_complementarity_constraint = false
72+
)
73+
result = madnlp(model; tol=1e-6)
74+
result.objective
75+
76+
# 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.
77+
78+
function example_function(d, srating)
79+
return d + .2/srating*d^2
80+
end;
81+
82+
# ExaModelsPower will automatically adjust the necessary constraints if one of the inputs provided is a function.
83+
model, vars, cons = mpopf_model(
84+
stor_file, # static network data with storage parameters
85+
pd_file, # dynamic load data (Pd)
86+
qd_file, # dynamic load data (Qd)
87+
example_function; # discharge function
88+
backend = CUDABackend(),
89+
storage_complementarity_constraint = false
90+
)
91+
result = madnlp(model; tol=1e-6)
92+
result.objective
93+
94+
# 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.
95+

docs/src/mpopf_demo.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ result.objective
101101
````
102102

103103
````
104-
299068.0404892947
104+
299068.0404892949
105105
````
106106

107107
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.
@@ -128,7 +128,7 @@ result.objective
128128
````
129129

130130
````
131-
299044.324045392
131+
299044.32404539204
132132
````
133133

134134
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.

docs/src/opf_demo.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# # [Static OPF](@id opf_demo)
2+
3+
# 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.
4+
5+
# 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.
6+
using ExaModelsPower, CUDA
7+
8+
# 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.
9+
using MadNLP, MadNLPGPU #, NLPModelsIpopt
10+
11+
# Finally, we install ExaModels to allow solved models to be unpacked.
12+
using ExaModels
13+
14+
# 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.
15+
model, vars, cons = opf_model(
16+
"pglib_opf_case118_ieee.m";
17+
backend = CUDABackend(),
18+
form = :polar,
19+
T = Float64
20+
);
21+
model
22+
23+
# Once the model is built, we can generate a solution using MadNLP.
24+
result = madnlp(model; tol=1e-6)
25+
26+
# Once a solution has been generated, the values of any of the variables in the model can be unpacked using the vars NamedTuple.
27+
solution(result, vars.vm)[1:10]
28+
29+
# Result also stores the objective value.
30+
result.objective
31+
32+
# ExaModelsPower supports solving the OPF in either polar or rectangular coordinates.
33+
model, vars, cons = opf_model(
34+
"pglib_opf_case118_ieee.m";
35+
form = :rect
36+
)
37+
result = madnlp(model; tol=1e-6)
38+
result.objective
39+
40+
# 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.

docs/src/opf_demo.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,16 @@ solution(result, vars.vm)[1:10]
7272

7373
````
7474
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
75+
1.0580725147180055
76+
1.0115214146056677
77+
1.0371945440876782
78+
1.012711563923005
79+
1.0170524545913904
80+
1.0544369316430553
81+
1.0575146839020113
82+
1.0303511034471369
83+
1.041850151876181
84+
1.0519359527784276
8585
````
8686

8787
Result also stores the objective value.
@@ -91,7 +91,7 @@ result.objective
9191
````
9292

9393
````
94-
97210.50257420563
94+
97210.50257420744
9595
````
9696

9797
ExaModelsPower supports solving the OPF in either polar or rectangular coordinates.

docs/src/opfs_doc.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,26 @@ The static OPF is the most basic version of the OPF, implemented over just a sin
77

88
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.
99

10-
$$$
10+
```math
1111
P_n = \sum_{mk} V_n V_m \left( G_{nmk} \cos \theta_{nm} + B_{nmk} \sin \theta_{nm} \right)
12-
$$$
12+
```
1313

1414
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.
1515

1616
A more complete description of the static OPF can be found [here](https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=16f56c56e83bb2e2fa98a1400dcf9367f04783b6).
1717

1818
## Multi-period OPF
1919
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-
$$$
20+
```math
2121
-\Delta P \leq P_{g,t} - P_{g,t-1} \leq \Delta P
22-
$$$
22+
```
2323

2424
## 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.
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)__ [geth2020flexiblestoragemodelpower](@cite). Transfer of power to and from storage devices along with associated losses are now included in the overall power balance for each bus.
2626

2727
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-
$$$
28+
```math
2929
P_{d} \cdot P_{c} = 0
30-
$$$
30+
```
3131

3232
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)