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.

julia> using PowerNetworkMatrices
julia> using PowerSystemCaseBuilder
julia> const PNM = PowerNetworkMatricesPowerNetworkMatrices
julia> const PSB = PowerSystemCaseBuilderPowerSystemCaseBuilder
julia> sys = PSB.build_system(PSB.PSITestSystems, "c_sys5");[ Info: Loaded time series from storage file existing=/home/runner/.julia/packages/PowerSystemCaseBuilder/uZO8H/data/serialized_system/614e094ea985a55912fc1321256a49b755f9fc451c0f264f24d6d04af20e84d7/c_sys5_time_series_storage.h5 new=/tmp/jl_G3GjFG compression=InfrastructureSystems.CompressionSettings(false, InfrastructureSystems.CompressionTypesModule.CompressionTypes.DEFLATE = 1, 3, true)

Then the Incidence Matrix is computed as follows:

julia> incidence_matrix = PNM.IncidenceMatrix(sys);

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

julia> # axis names: row and column names.
       # row names: names of the branches
       # column names: names of the buses
       incidence_matrix.axes
       
       # data: Incidence Matrix(["1", "2", "3", "4", "5", "6"], [1, 2, 3, 4, 5])
julia> incidence_matrix.data # lookup: dictionary linking the branches names and bus numbers with the row # and column numbers, respectively.6×5 SparseArrays.SparseMatrixCSC{Int8, Int64} with 12 stored entries: 1 -1 ⋅ ⋅ ⋅ 1 ⋅ ⋅ -1 ⋅ 1 ⋅ ⋅ ⋅ -1 ⋅ 1 -1 ⋅ ⋅ ⋅ ⋅ 1 -1 ⋅ ⋅ ⋅ ⋅ 1 -1
julia> 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 # example in the BA matrix for more details.(["1", "2", "3", "4", "5", "6"], [1, 2, 3, 4, 5])
julia> incidence_matrix.ref_bus_positionsSet{Int64} with 1 element: 4

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

julia> PNM.get_data(incidence_matrix)6×5 SparseArrays.SparseMatrixCSC{Int8, Int64} with 12 stored entries:
 1  -1   ⋅   ⋅   ⋅
 1   ⋅   ⋅  -1   ⋅
 1   ⋅   ⋅   ⋅  -1
 ⋅   1  -1   ⋅   ⋅
 ⋅   ⋅   1  -1   ⋅
 ⋅   ⋅   ⋅   1  -1

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 containing the impedence of the system's branches ("B" matrix).

The BA_Matrix is computed as follows:

julia> 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:

julia> # access data by explicitly calling the field "data"
       ba_matrix.data
       
       # or by using the "get_data" function5×6 SparseArrays.SparseMatrixCSC{Float64, Int64} with 12 stored entries:
  35.5872   32.8947   156.25     ⋅         ⋅       ⋅
 -35.5872     ⋅          ⋅     92.5926     ⋅       ⋅
    ⋅         ⋅          ⋅    -92.5926   33.67     ⋅
    ⋅      -32.8947      ⋅       ⋅      -33.67   33.67
    ⋅         ⋅      -156.25     ⋅         ⋅    -33.67
julia> PNM.get_data(ba_matrix)5×6 SparseArrays.SparseMatrixCSC{Float64, Int64} with 12 stored entries: 35.5872 32.8947 156.25 ⋅ ⋅ ⋅ -35.5872 ⋅ ⋅ 92.5926 ⋅ ⋅ ⋅ ⋅ ⋅ -92.5926 33.67 ⋅ ⋅ -32.8947 ⋅ ⋅ -33.67 33.67 ⋅ ⋅ -156.25 ⋅ ⋅ -33.67

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.

julia> 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]
           )5×7 SparseArrays.SparseMatrixCSC{Float64, Int64} with 12 stored entries:
  35.5872   32.8947   156.25   ⋅      ⋅         ⋅       ⋅
 -35.5872     ⋅          ⋅     ⋅    92.5926     ⋅       ⋅
    ⋅         ⋅          ⋅     ⋅   -92.5926   33.67     ⋅
    ⋅      -32.8947      ⋅     ⋅      ⋅      -33.67   33.67
    ⋅         ⋅      -156.25   ⋅      ⋅         ⋅    -33.67

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

julia> 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]
           )ERROR: setfield!: immutable struct of type BA_Matrix cannot be changed

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:

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

julia> aba_matrix_with_LU = ABA_Matrix(sys; factorize=true);
julia> aba_matrix_with_LU.KKLU.KLUFactorization{Float64, Int64} L factor: 4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 7 stored entries: 1.0 ⋅ ⋅ ⋅ -0.695273 1.0 ⋅ ⋅ ⋅ ⋅ 1.0 ⋅ ⋅ -0.648697 -0.722365 1.0 U factor: 4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 7 stored entries: 1.0 -0.822715 ⋅ ⋅ ⋅ 0.427989 ⋅ -0.158354 ⋅ ⋅ 1.0 -0.733333 ⋅ ⋅ ⋅ 0.367542 F factor: 4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 0 stored entries: ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅

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

julia> aba_matrix.K
julia> aba_matrix = factorize(aba_matrix);
julia> aba_matrix.KKLU.KLUFactorization{Float64, Int64} L factor: 4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 7 stored entries: 1.0 ⋅ ⋅ ⋅ -0.695273 1.0 ⋅ ⋅ ⋅ ⋅ 1.0 ⋅ ⋅ -0.648697 -0.722365 1.0 U factor: 4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 7 stored entries: 1.0 -0.822715 ⋅ ⋅ ⋅ 0.427989 ⋅ -0.158354 ⋅ ⋅ 1.0 -0.733333 ⋅ ⋅ ⋅ 0.367542 F factor: 4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 0 stored entries: ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅

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

julia> is_factorized(aba_matrix)true