PTDF matrix
In this tutorial the methods for computing the Power Transfer Distribution Factors (PTDF) 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 documention of the different PTDF methods available.
Evaluation of the PTDF matrix
The PTDF matrix can be evaluated according to two different approaches:
Dense: considers functions for dense matrix multiplication and inversionKLU: considers functions for sparse matrix multiplication and inversion (default)
The evaluation of the PTDF matrix can be easily performed starting from importing the system's data and then by simply calling the PTDF method.
julia> using PowerNetworkMatricesjulia> using PowerSystemCaseBuilderjulia> const PNM = PowerNetworkMatricesPowerNetworkMatricesjulia> const PSB = PowerSystemCaseBuilderPowerSystemCaseBuilderjulia> sys = PSB.build_system(PSB.PSITestSystems, "c_sys5");[ Info: Loaded time series from storage file existing=/home/runner/.julia/packages/PowerSystemCaseBuilder/dJGb8/data/serialized_system/614e094ea985a55912fc1321256a49b755f9fc451c0f264f24d6d04af20e84d7/c_sys5_time_series_storage.h5 new=/tmp/jl_Q0GZlT compression=InfrastructureSystems.CompressionSettings(false, InfrastructureSystems.CompressionTypesModule.CompressionTypes.DEFLATE = 1, 3, true)julia> ptdf_1 = PTDF(sys);julia> get_ptdf_data(ptdf_1)6×5 transpose(::Matrix{Float64}) with eltype Float64: 0.193917 -0.475895 -0.348989 0.0 0.159538 0.437588 0.258343 0.189451 0.0 0.36001 0.368495 0.217552 0.159538 0.0 -0.519548 0.193917 0.524105 -0.348989 0.0 0.159538 0.193917 0.524105 0.651011 0.0 0.159538 -0.368495 -0.217552 -0.159538 0.0 -0.480452
Advanced users might be interested in computing the PTDF matrix starting from either the data contained in the IncidenceMatrix and BA_matrix structures, or by the information related to the branches and buses of the system.
julia> # evaluate the BA_matrix and Incidence_Matrix ba_matrix = BA_Matrix(sys);julia> a_matrix = IncidenceMatrix(sys); # get the PTDF matrix starting from the values of the # previosly cumputed matricesjulia> ptdf_2 = PTDF(a_matrix, ba_matrix);┌ Warning: PTDF creates via other matrices doesn't compute the subnetworks └ @ PowerNetworkMatrices ~/work/PowerNetworkMatrices.jl/PowerNetworkMatrices.jl/src/ptdf_calculations.jl:509julia> get_ptdf_data(ptdf_2) # get the buses and branches of the system6×5 transpose(::Matrix{Float64}) with eltype Float64: 0.193917 -0.475895 -0.348989 0.0 0.159538 0.437588 0.258343 0.189451 0.0 0.36001 0.368495 0.217552 0.159538 0.0 -0.519548 0.193917 0.524105 -0.348989 0.0 0.159538 0.193917 0.524105 0.651011 0.0 0.159538 -0.368495 -0.217552 -0.159538 0.0 -0.480452julia> branches = PNM.get_ac_branches(sys);julia> buses = PNM.get_buses(sys);julia> ptdf_3 = PTDF(branches, buses);julia> get_ptdf_data(ptdf_3)6×5 transpose(::Matrix{Float64}) with eltype Float64: 0.193917 -0.475895 -0.348989 0.0 0.159538 0.437588 0.258343 0.189451 0.0 0.36001 0.368495 0.217552 0.159538 0.0 -0.519548 0.193917 0.524105 -0.348989 0.0 0.159538 0.193917 0.524105 0.651011 0.0 0.159538 -0.368495 -0.217552 -0.159538 0.0 -0.480452
NOTE: both the get_ac_branches and get_ac_branches functions are not exported by the PowerNetworkMatrices package, and therefore require the package name to be called as a prefix. However, they are shown here just for the sake of making an example.
Available methods for the computation of the PTDF matrix
As previously mentioned, the PTDF matrix can be evaluated considering different approaches. The method can be selected by specifying the field linear_solver in the PTDF function.
julia> ptdf_dense = PTDF(sys, linear_solver="Dense");julia> get_ptdf_data(ptdf_dense)6×5 transpose(::Matrix{Float64}) with eltype Float64: 0.193917 -0.475895 -0.348989 0.0 0.159538 0.437588 0.258343 0.189451 0.0 0.36001 0.368495 0.217552 0.159538 0.0 -0.519548 0.193917 0.524105 -0.348989 0.0 0.159538 0.193917 0.524105 0.651011 0.0 0.159538 -0.368495 -0.217552 -0.159538 0.0 -0.480452julia> ptdf_klu = PTDF(sys, linear_solver="KLU");julia> get_ptdf_data(ptdf_klu)6×5 transpose(::Matrix{Float64}) with eltype Float64: 0.193917 -0.475895 -0.348989 0.0 0.159538 0.437588 0.258343 0.189451 0.0 0.36001 0.368495 0.217552 0.159538 0.0 -0.519548 0.193917 0.524105 -0.348989 0.0 0.159538 0.193917 0.524105 0.651011 0.0 0.159538 -0.368495 -0.217552 -0.159538 0.0 -0.480452
By default the "KLU" method is selected, which appeared to require significant less time and memory with respect to "Dense". Please note that either the KLU or Dense method is used, the resulting PTDF matrix is stored as a dense one.
Evaluating the PTDF matrix considering distributed slack bus
Whenever needed, the PTDF matrix can be computed with a distributed slack bus. To do so, a vector of type Vector{Float64} needs to be defined, specifying the weights for each bus of the system. These weights identify how the load on the slakc bus is redistributed accross the system.
julia> # consider equal distribution accross each bus for this example buscount = length(PNM.get_buses(sys));julia> dist_slack = 1 / buscount * ones(buscount);julia> dist_slack_array = dist_slack / sum(dist_slack);
Once the vector of the weights is defined, the PTDF matrix can be computed by defining the input argument dist_slack (empty array Float64[] by default):
julia> ptdf_distr = PTDF(sys, dist_slack=dist_slack_array);[ Info: Distributed bus
The difference between a the matrix computed with and without the dist_slack field defined can be seen as follows:
julia> # with no distributed slack bus get_ptdf_data(ptdf_klu) # with distributed slack bus6×5 transpose(::Matrix{Float64}) with eltype Float64: 0.193917 -0.475895 -0.348989 0.0 0.159538 0.437588 0.258343 0.189451 0.0 0.36001 0.368495 0.217552 0.159538 0.0 -0.519548 0.193917 0.524105 -0.348989 0.0 0.159538 0.193917 0.524105 0.651011 0.0 0.159538 -0.368495 -0.217552 -0.159538 0.0 -0.480452julia> get_ptdf_data(ptdf_distr)6×5 transpose(::Matrix{Float64}) with eltype Float64: 0.288203 -0.381609 -0.254704 0.0942859 0.253824 0.18851 0.00926433 -0.0596271 -0.249079 0.110932 0.323288 0.172344 0.114331 -0.0452074 -0.564756 0.0882025 0.418391 -0.454704 -0.105714 0.0538239 -0.111797 0.218391 0.345296 -0.305714 -0.146176 -0.123288 0.0276555 0.0856694 0.245207 -0.235244
"Sparse" PTDF matrix
The PTFD matrix can be computed in a "sparse" fashion by defining the input argument tol. If this argument is defined, then elements of the PTDF 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} instead of Matrix{Float64}.
By considering an "extreme" value of 0.2 as tol, the PTDF matrix can be computed as follows:
julia> ptdf_sparse = PTDF(sys, tol=0.2);julia> get_ptdf_data(ptdf_sparse)6×5 LinearAlgebra.Transpose{Float64, SparseArrays.SparseMatrixCSC{Float64, Int64}} with 15 stored entries: ⋅ -0.475895 -0.348989 ⋅ ⋅ 0.437588 0.258343 ⋅ ⋅ 0.36001 0.368495 0.217552 ⋅ ⋅ -0.519548 ⋅ 0.524105 -0.348989 ⋅ ⋅ ⋅ 0.524105 0.651011 ⋅ ⋅ -0.368495 -0.217552 ⋅ ⋅ -0.480452
NOTE: 0.2 was used for the purpose of this tutorial. In practice much smaller values are used (e.g., 1e-5).