Skip to content

Commit

Permalink
Tutorials (#51)
Browse files Browse the repository at this point in the history
* first tutorial on Incidence, BA and ABA matrices

* Tutorial on PTDF matrix: part 1

* Update tutorial_PTDF_matrix.md

* first tutorial on Incidence, BA and ABA matrices

* Tutorial on PTDF matrix: part 1

* Update tutorial_PTDF_matrix.md

* udpated documentation , updated docstring for "drop_small_entries!"

* updated documentation, added image

* updated image, finished VirtualPTDF tutorial

* updated tutorials - lodf

* updated documentation for PTDF, A, BA, ABA. added LODF documentation.

* concluded tutorials, new images

* removing unnecessary deps

* update case builder

* update mac requirements

---------

Co-authored-by: Jose Daniel Lara <[email protected]>
  • Loading branch information
alefcastelli and jd-lara authored Aug 28, 2023
1 parent 966c1c3 commit ab01648
Show file tree
Hide file tree
Showing 14 changed files with 622 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

## Version Advisory

- PowerNetworkMatrices.jl will work with Julia v1.6+.
- PowerNetworkMatrices.jl will work with Julia v1.6+. In Mac the requirement is to have Julia 1.9.2+ due to issues with MKL and dynamic library loading.
- PowerNetworkMatrices.jl exports Matrix methods that were available in PowerSystems.jl version 1.0 and have been implemented as a separate package.

## License
Expand Down
10 changes: 8 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import DataStructures: OrderedDict
pages = OrderedDict(
"Welcome Page" => "index.md",
"Quick Start Guide" => "quick_start_guide.md",
"Tutorials" => "tutorials/intro_page.md",
"Tutorials" => Any[
"Incidence, BA and ABA matrices" => "tutorials/tutorial_Incidence_BA_ABA_matrices.md",
"PTDF matrix" => "tutorials/tutorial_PTDF_matrix.md",
"VirtualPTDF matrix" => "tutorials/tutorial_VirtualPTDF_matrix.md",
"LODF matrix" => "tutorials/tutorial_LODF_matrix.md",
"VirtualLODF matrix" => "tutorials/tutorial_VirtualLODF_matrix.md",
],
"Public API Reference" => "api/public.md",
"Internal API Reference" => "api/internal.md",
)
Expand All @@ -15,7 +21,7 @@ makedocs(;
mathengine = Documenter.MathJax(),
prettyurls = haskey(ENV, "GITHUB_ACTIONS")),
sitename = "PowerNetworkMatrices.jl",
authors = "Jose Daniel Lara, Alessandro Castelli, Sourabh Dalvi",
authors = "Jose Daniel Lara, Alessandro Francesco Castelli, Sourabh Dalvi",
pages = Any[p for p in pages],
clean = true,
)
Expand Down
Binary file added docs/src/assets/VirtualLODF_scheme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/src/assets/VirtualPTDF_scheme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ CurrentModule = PowerNetworkMatrices

## Overview

`PowerNetworkMatrices.jl` documentation and code are organized according to the needs of different
`PowerNetworkMatrices.jl` is a [`Julia`](http://www.julialang.org) package for
the evaluation of network matrices given the system's data. The package allows to compute
the matrices according to different methods, providing a flexibe and powerful tool.

The documentation and code are organized according to the needs of different
users depending on their skillset and requirements. In broad terms there are three categories:

- **Modeler**: Users that want to run a particular analysis or experiment and use `PowerNetworkMatrices.jl` to develop data sets.
Expand Down
41 changes: 41 additions & 0 deletions docs/src/quick_start_guide.md
Original file line number Diff line number Diff line change
@@ -1 +1,42 @@
# Quick Start Guide

!!! note
`PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce examples in the documentation and tutorials. Normally you would pass your local files to create the system data instead of calling the function `build_system`.
For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/)

For more details about loading data and adding more dynamic components check the
[Creating a System with Dynamic devices](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/system_dynamic_data/)
section of the documentation in `PowerSystems.jl`.

## Loading data

Data can be loaded from a pss/e raw file and a pss/e dyr file.

``` @repl quick_start_guide
using PowerNetworkMatrices
using PowerSystemCaseBuilder
const PNM = PowerNetworkMatrices
const PSB = PowerSystemCaseBuilder
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5")
```

## Computation of the PTDF matrix

Once system data is loaded, netwrok matrices can be evaluated. The following
example shows how the PTDF matrix is computed.

The function `PTDF` is called for the evaluation of the matrix and other data. These
are stored in a structure of type `PTDF`.

``` @repl quick_start_guide
# evaluate the PTDF structure containing the matrix and other data.
ptdf_matrix = PNM.PTDF(sys);
# show the PTDF matrix.
PNM.get_data(ptdf_matrix)
```

As it can be seen, PTDF matrix is stored such that the number of rows is equal
to the number of buses, number of columns equal to the number of branches.
145 changes: 145 additions & 0 deletions docs/src/tutorials/tutorial_Incidence_BA_ABA_matrices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Incidence, BA and ABA matrices

In this tutorial the `IncidenceMatrix`, `BA_matrix` and `ABA_matrix` are presented.
The methods used for their evaluation, as well as how data is stored is shown in
the following subsections.

The matrices here presented are the building blocks for the compuation of the PTDF and LODF matrices.

## IncidenceMatrix

The `PowerNetworkMatrices` package defines the structure `IncidenceMatrix`, which
store the Incidence Matrix of the considered system as well as the most relevant network data.

At first, the `System` data is loaded.

``` @repl tutorial_Incidence_BA_ABA_matrices
using PowerNetworkMatrices
using PowerSystemCaseBuilder
const PNM = PowerNetworkMatrices
const PSB = PowerSystemCaseBuilder
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5");
```

Then the Incidence Matrix is computed as follows:

``` @repl tutorial_Incidence_BA_ABA_matrices
incidence_matrix = PNM.IncidenceMatrix(sys);
```

The `incidence_matrix` variable is a structure of type `IncidenceMatrix`
featuring the following fields:

``` @repl tutorial_Incidence_BA_ABA_matrices
# axis names: row and column names.
# row names: names of the branches
# column names: names of the buses
incidence_matrix.axes
# data: Incidence Matrix
incidence_matrix.data
# lookup: dictionary linking the branche names and bus numbers with the row
# and column numbers, respectively.
incidence_matrix.axes
# ref_bus_positions: set containing the positions of the reference buses.
# this represents the positions where to add the column of zeros. Please refer to the
# exaple in the BA matrix for more details.
incidence_matrix.ref_bus_positions
```

Please note that the matrix data can be easily access by using the following function:

``` @repl tutorial_Incidence_BA_ABA_matrices
PNM.get_data(incidence_matrix)
```

Note that the number of columns is lower than the actual number of system buses since
the column related to the reference bus is discarded.

## BA_Matrix

The `BA_Matrix` is a structure containing the matrix coming from the product of the
`IncidenceMatrix` and the diagonal matrix contianing the impedence of the system's branches ("B" matrix).

The `BA_Matrix` is computed as follows:

``` @repl tutorial_Incidence_BA_ABA_matrices
ba_matrix = PNM.BA_Matrix(sys);
```

As for the `IncidenceMatrix`, here too the `BA_Matrix` structure feature the same fields.

An example related to accessing the matrix data is now provided:
``` @repl tutorial_Incidence_BA_ABA_matrices
# access data by explicitly calling the field "data"
ba_matrix.data
# or by using the "get_data" function
PNM.get_data(ba_matrix)
```
Note that the number of columns is lower than the actual number of system buses since
the column related to the reference bus is discarded.

To add the column of zeros related to the reference bus, it is necessary to use the
information contained in the `ref_bus_positions` field.

``` @repl tutorial_Incidence_BA_ABA_matrices
new_ba_matrix = hcat(
ba_matrix.data[:,1:collect(ba_matrix.ref_bus_positions)[1]-1],
zeros(size(ba_matrix, 1), 1),
ba_matrix.data[:, collect(ba_matrix.ref_bus_positions)[1]:end]
)
```

However, trying to change the data field with a matrix of different dimension
will result in an error.

``` @repl tutorial_Incidence_BA_ABA_matrices
ba_matrix.data = hcat(
ba_matrix.data[:,1:collect(ba_matrix.ref_bus_positions)[1]-1],
zeros(size(ba_matrix, 1), 1),
ba_matrix.data[:, collect(ba_matrix.ref_bus_positions)[1]:end]
)
```


## ABA_Matrix

The `ABA_Matrix` is a structure containing the matrix coming from the product of the
`IncidenceMatrix` and the `BA_Matrix`.
It features the same fields as the `IncidenceMatrix` and the `BA_Matrix`, plus the `K` one.
The field `ABA_Matrix.K` stores the LU factorization matrices (using the
methods contained in the package `KLU`).

To evaluate the `ABA_Matrix`, the following command is sufficient:

``` @repl tutorial_Incidence_BA_ABA_matrices
aba_matrix = ABA_Matrix(sys);
```

By default the LU factorization matrices are not computed, leaving the `K` field empty.
In case these are wanted, the keyword `factorize` must be true.

``` @repl tutorial_Incidence_BA_ABA_matrices
aba_matrix_with_LU = ABA_Matrix(sys; factorize=true);
aba_matrix_with_LU.K
```

If the `ABA_Matrix` is already computed but the LU factorization was not performed, this can be done by considering the following command:

``` @repl tutorial_Incidence_BA_ABA_matrices
aba_matrix.K
aba_matrix = factorize(aba_matrix);
aba_matrix.K
```

The following command can then be used to check if the `ABA_Matrix` contains the LU factorization matrices:

``` @repl tutorial_Incidence_BA_ABA_matrices
is_factorized(aba_matrix_new)
```
100 changes: 100 additions & 0 deletions docs/src/tutorials/tutorial_LODF_matrix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# LODF matrix

In this tutorial the methods for computing the Line Outage Distribution Factor (`LODF`) are presented.
Before diving into this tutorial we encourage the user to load `PowerNetworkMatrices`, hit the `?` key in the REPL terminal and look for the documentiont of the different `LODF` methods avialable.

## Evaluation of the `LODF` matrix

As for the `PTDF` matrix, the `LODF` one can be evaluated according to two different approaches:
- `Dense`: considers functions for dense matrix multiplication and inversion
- `KLU`: considers functions for sparse matrix multiplication and inversion(**default**)

The evaluation of the `LODF` matrix can be easily performed starting from importing the system's data and then by simply calling the `LODF` method.

``` @repl tutorial_PTDF_matrix
using PowerNetworkMatrices
using PowerSystemCaseBuilder
const PNM = PowerNetworkMatrices
const PSB = PowerSystemCaseBuilder
# get the System data
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5");
# compute the LODF matrix
lodf_1 = LODF(sys);
lodf_2 = LODF(sys, linear_solver="Dense");
# show matrix
get_lodf_data(lodf_1)
```

Advanced users might be interested in computing the `LODF` matrix starting from either the `branches` and `buses` data (`CASE 1`), the `IncidenceMatrix` and `PTDF` structures (`CASE 2`), or by the information related to `IncidenceMatrix`, `BA_Matrix` and `ABA_Matrix` (`CASE 3`).

``` @repl tutorial_PTDF_matrix
# CASE 1
# get the branches and buses data
branches = PNM.get_ac_branches(sys);
buses = PNM.get_buses(sys);
# compute the LODF matrix from branches and buses data
lodf_3 = LODF(branches, buses);
# CASE 2
# get the Incidence and PTDF matrix
a = IncidenceMatrix(sys);
ptdf = PTDF(sys);
# compute LODF matrix with the two netwrok matrices
lodf_4 = LODF(a, ptdf);
# CASE 3
# get the BA and ABA matrices (ABA matrix must include LU factorization
# matrices)
ba = BA_Matrix(sys);
aba = ABA_Matrix(sys, factorize = true);
# compute LODF matrix with the three netwrok matrices
lodf_5 = LODF(a, aba, ba);
```

**NOTE:** whenever the method `LODF(sys::System)` is used, the methods previously defined for `CASE 1` and `CASE 2` are executed in sequence. Therefore the method `LODF(a::IncidenceMatrix, ptdf::PTDF)` is the default one when evaluating the `LODF` matrix from the `System` data directly.


## Available methods for the computation of the `LODF` matrix

For those methods that either require the evaluation of the `PTDF` matrix, or that execute this evaluation internally, two different approaches casen be used.

As for the `PTDF` matrix, here too the optional argument `linear_solver` can be specified with either `KLU` (for spars matrix calculation) or `Dense` (for sparse matrix calculation).

``` @repl tutorial_PTDF_matrix
lodf_dense = LODF(sys, linear_solver="Dense");
```

**NOTE (1):** by default the "KLU" method is selected, which appeared to require significant less time and memory with respect to "Dense".
Please note that wether the `KLU` or `Dense` method is used, the resultig `LODF` matrix is stored as a dense one.

**NOTE (2):** for the moment, the method `LODF(a::IncidenceMatrix, aba::ABA_Matrix, ba::BA_Matrix)` will take `KLU` as `linear_solver` option.

## "Sparse" `LODF` matrix

The `LODF` matrix can be computed in a "sparse" fashion by defining the input argument `tol`. If this argument is defined, then elements of the `LODF` matrix whose absolute values are below the set threshold are dropped. In addition, the matrix will be stored as a sparse one of type `SparseArrays.SparseMatrixCSC{Float64, Int64}` type instead of `Matrix{Float64}` one.

By considering an "extreme" value of 0.4 as `tol`, the `LODF` matrix can be computed as follows:

``` @repl tutorial_PTDF_matrix
lodf_sparse = LODF(sys, tol=0.4);
get_lodf_data(lodf_sparse)
```

Please consider that 0.4 was used for the purpose of this tutorial. In practice much smaller values are used (e.g., 1e-5).

**NOTE (1):** elements whose absolute values exceed the `tol` argument are removed from the `LODF` matrix *after* this has been computed.

**NOTE (2):** the `tol` argument does not refer to the "sparsification" tolerance of the `PTDF` matrix that is computed in the `LODF` method.

**NOTE (3):** in case the method `LODF(a::IncidenceMatrix, ptdf::PTDF)` is considerd, an error will be thrown whenever the `tol` argument in the `PTDF` structure used as input is different then 1e-15.
Loading

0 comments on commit ab01648

Please sign in to comment.