diff --git a/docs/src/assets/VirtualLODF_scheme.png b/docs/src/assets/VirtualLODF_scheme.png new file mode 100644 index 00000000..7c15d66a Binary files /dev/null and b/docs/src/assets/VirtualLODF_scheme.png differ diff --git a/docs/src/assets/VirtualPTDF_scheme.png b/docs/src/assets/VirtualPTDF_scheme.png index 94045c16..41ac7640 100644 Binary files a/docs/src/assets/VirtualPTDF_scheme.png and b/docs/src/assets/VirtualPTDF_scheme.png differ diff --git a/docs/src/tutorials/tutorial_VirtualLODF_matrix.md b/docs/src/tutorials/tutorial_VirtualLODF_matrix.md new file mode 100644 index 00000000..803feddc --- /dev/null +++ b/docs/src/tutorials/tutorial_VirtualLODF_matrix.md @@ -0,0 +1,98 @@ +# VirtualLODF + +The `VirtualLODF` structure follows the same philosofy as the `VirtualPTDF`: it contains rows of the original `LODF` matrix, evaluated and cached on demand. + +Refer to the different arguments of the `VirtualLODF` methods by looking at the "Public API Reference" page. + +## How the `VirtualLODF` works + +The `VirtualLODF` structure retains many of the similarities of the `VirtualPTDF`. However, its computation is more complex and requires some additional data. + +Starting from the system data, the `IncidenceMatrix`, `BA_Matrix` and `ABA_Matrix` (with relative LU factorization matrices) are evaluated. The `ABA_Matrix` and `BA_Matrix` are used for the computation of the diagonal elements of the `PTDF` matrix, and this vector is stored in the `VirtualLODF` structure together with the other structures abovementioned. + +Once the `VirtualLODF` is initialized, each row of the matrix can be evaluated separately and on user request. The algorithmic procedure is the following: +1. Define the `VirtualPTDF` structure +2. Call any element of the matrix to define and store the relative row as well as showing the selected element + +Regarding point 2, if the row has been stored previosly then the desired element is just loaded from the cache and shown. + +The flowchart below shows how the `VirtualLODF` is structured and how it works. Examples will be presented in the following sections. + +```@raw html + +``` + +## Initialize `VirtualLODF` and compute/access row/element + +As for the `LODF` matrix, at first the `System` data must be loaded. The "RTS GMLC" systems is considered as example: + +``` @repl tutorial_VirtualPTDF_matrix +using PowerNetworkMatrices +using PowerSystemCaseBuilder + +const PNM = PowerNetworkMatrices; +const PSB = PowerSystemCaseBuilder; + +sys = PSB.build_system(PSB.PSISystems, "RTS_GMLC_DA_sys"); +``` + +At this point the `VirtualLODF` is initialized with the following simple command: + +``` @repl tutorial_VirtualPTDF_matrix +v_lodf = VirtualLODF(sys); +``` + +Now, an element of the matrix can be computed by calling the branch name and bus number: + +``` @repl tutorial_VirtualPTDF_matrix +el_C31_2_105 = v_lodf["C31-2", "A3"] +``` + +This element represent the portion flowing on line "A3" now diverted on line "C31-2" as a consequence of its outage. + +Alternatively, the number of the branch and bus (corresponding to the number of the PTDF row and column) can be used. In this case the row and column numbers are mapped by the dictonaries contained in the `lookup` field. + +``` @repl tutorial_VirtualPTDF_matrix +row_number = v_lodf.lookup[1]["C31-2"] +col_number = v_lodf.lookup[2]["A3"] +el_C31_2_105_bis = v_lodf[row_number, col_number] +``` + +**NOTE**: this example was made for the sake of completeness and considering the actual branch names is reccomended. + +As previosly mentioned, in order to evalute a single element of the `VirtualLODF`, the entire row related to the selected branch must be considered. For this reason it is cached for later calls. +This is evident by looking at the following example: + +``` @repl tutorial_VirtualPTDF_matrix +sys_2k = PSB.build_system(PSB.PSYTestSystems, "tamu_ACTIVSg2000_sys"); + +v_lodf_2k = VirtualLODF(sys_2k); + +# evaluate PTDF row related to branch "ODESSA 2 0 -1001-ODESSA 3 0 -1064-i_1" +@time v_lodf_2k["ODESSA 2 0 -1001-ODESSA 3 0 -1064-i_1", + "BRYAN 1 1 -8159-BRYAN 1 0 -8158-i_1"] + +# call same element after the row has been stored +@time v_lodf_2k["ODESSA 2 0 -1001-ODESSA 3 0 -1064-i_1", + "BRYAN 1 1 -8159-BRYAN 1 0 -8158-i_1"] +``` + +## "Sparse" `VirtualPTDF` + +Sparsification of each row can be achieved in the same fashion as for the `LODF` matrix, by removing those elements whose absolute values is below a certain threshold. + +As for the example show for the `LODF` matrix, here to a very high values of 0.4 is considered for the `tol` field. Again, this value is considered just for the sake of this example. + +``` @repl tutorial_VirtualPTDF_matrix +# smaller system for the next examples +sys_2 = PSB.build_system(PSB.PSITestSystems, "c_sys5"); + +v_lodf_dense = VirtualLODF(sys_2); +v_lodf_sparse = VirtualLODF(sys_2, tol=0.4); +``` + +Let's now evaluate the same row as before and compare the results: +``` @repl tutorial_VirtualPTDF_matrix +original_row = [v_lodf_dense["1", j] for j in v_lodf_dense.axes[2]] +sparse_row = [v_lodf_sparse["1", j] for j in v_lodf_sparse.axes[2]] +``` \ No newline at end of file diff --git a/docs/src/tutorials/tutorial_VirtualPTDF_matrix.md b/docs/src/tutorials/tutorial_VirtualPTDF_matrix.md index ffc68676..7afcb5d6 100644 --- a/docs/src/tutorials/tutorial_VirtualPTDF_matrix.md +++ b/docs/src/tutorials/tutorial_VirtualPTDF_matrix.md @@ -23,7 +23,7 @@ The flowchart below shows how the `VirtualPTDF` is structured and how it works. ## Initialize `VirtualPTDF` and compute/access row/element -As for the `PTDF` matrix, at first the `System` data must be loaded. The same 5-bus systems is considered as example: +As for the `PTDF` matrix, at first the `System` data must be loaded. The "RTS GMLC" systems is considered as example: ``` @repl tutorial_VirtualPTDF_matrix using PowerNetworkMatrices @@ -55,15 +55,21 @@ col_number = v_ptdf.lookup[2][105] el_C31_2_105_bis = v_ptdf[row_number, col_number] ``` -**NOTE**: this example was made for the sake of completeness and considering the actual branche name and bus number is reccomended. +**NOTE**: this example was made for the sake of completeness and considering the actual branch name and bus number is reccomended. As previosly mentioned, in order to evalute a single element of the `VirtualPTDF`, the entire row related to the selected branch must be considered. For this reason it is cached in the `VirtualPTDF` structure for later calls. This is evident by looking at the following example: ``` @repl tutorial_VirtualPTDF_matrix -@time v_ptdf["A32-2", 215] # evaluate PTDF row related to branche "A32-2" +sys_2k = PSB.build_system(PSB.PSYTestSystems, "tamu_ACTIVSg2000_sys"); -@time v_ptdf["A32-2", 215] # call same element after the row has been stored +v_ptdf_2k = VirtualPTDF(sys_2k); + +# evaluate PTDF row related to branch "ODESSA 2 0 -1001-ODESSA 3 0 -1064-i_1" +@time v_ptdf_2k["ODESSA 2 0 -1001-ODESSA 3 0 -1064-i_1", 8155] + +# call same element after the row has been stored +@time v_ptdf_2k["ODESSA 2 0 -1001-ODESSA 3 0 -1064-i_1", 8155] ``` ## `VirtualPTDF` with distributed slack bus @@ -108,6 +114,6 @@ v_ptdf_sparse = VirtualPTDF(sys_2, tol=0.2); Let's now evaluate the same row as before and compare the results: ``` @repl tutorial_VirtualPTDF_matrix -sparse_row = [v_ptdf_sparse["1", j] for j in v_ptdf_sparse.axes[2]] original_row = [v_ptdf_dense["1", j] for j in v_ptdf_dense.axes[2]] +sparse_row = [v_ptdf_sparse["1", j] for j in v_ptdf_sparse.axes[2]] ``` \ No newline at end of file diff --git a/src/virtual_lodf_calculations.jl b/src/virtual_lodf_calculations.jl index 2e29a67c..decf67d6 100644 --- a/src/virtual_lodf_calculations.jl +++ b/src/virtual_lodf_calculations.jl @@ -195,7 +195,7 @@ function _getindex( ) # check if value is in the cache if haskey(vlodf.cache, row) - return vlodf.cache[row][column] + return vlodf.cache.temp_cache[row][column] else # evaluate the value for the LODF column diff --git a/src/virtual_ptdf_calculations.jl b/src/virtual_ptdf_calculations.jl index 2ac60559..b61fa63b 100644 --- a/src/virtual_ptdf_calculations.jl +++ b/src/virtual_ptdf_calculations.jl @@ -183,7 +183,7 @@ function _getindex( ) # check if value is in the cache if haskey(vptdf.cache, row) - return vptdf.cache[row][column] + return vptdf.cache.temp_cache[row][column] else # evaluate the value for the PTDF column # Needs improvement