Network Matrices
PowerSystems.jl
is able to build classic power systems modeling network matrices such as Ybus, PTDF and LODF
Check section Network Matrices for more details
Overview
Network matrices are implemented in PowerSystems.jl
as arrays that enable using Branch or Bus names as indexes to facilitate exploration and analysis. Ybus is stored as an SparseMatrix and the PTDF and LODF are stored as dense matrices. **Note*** Ybus is converted to a dense matrix for printing in the REPL, The network matrices code implements the Goderya algorithm to find islands.
using PowerSystems
const PSY = PowerSystems
system_data = System(joinpath(DATA_DIR, "matpower/case14.m"))
System
Base Power: 100.0
Components
Num components: 73
9 rows × 3 columns
ConcreteType | SuperTypes | Count | |
---|---|---|---|
String | String | Int64 | |
1 | Arc | Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 20 |
2 | Area | AggregationTopology <: Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 1 |
3 | Bus | Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 14 |
4 | FixedAdmittance | ElectricLoad <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 1 |
5 | Line | ACBranch <: Branch <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 17 |
6 | LoadZone | AggregationTopology <: Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 1 |
7 | PowerLoad | StaticLoad <: ElectricLoad <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 11 |
8 | TapTransformer | ACBranch <: Branch <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 3 |
9 | ThermalStandard | ThermalGen <: Generator <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any | 5 |
TimeSeriesContainer
Components with time series data: 0
Total StaticTimeSeries: 0
Total Forecasts: 0
Resolution: 0 seconds
Ybus
The ybus can be calculated as follows:
ybus = Ybus(system_data)
PowerNetworkMatrix : 6.02503-19.4471im -4.99913+15.2631im … ⋅ -4.99913+15.2631im 9.52132-30.2721im ⋅ ⋅ -1.13502+4.78186im ⋅ ⋅ -1.68603+5.11584im ⋅ -1.0259+4.23498im -1.70114+5.19393im ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ -1.42401+3.02905im ⋅ ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ -1.13699+2.31496im ⋅ ⋅ 2.561-5.34401im
The matrix can be indexed using directly the bus numbers. In this example buses are numbered 1-14. However, in large systems buses don't usually follow sequential numbering. You can access the entries of the Ybus with direct indexing or using the buses.
ybus_entry = ybus[3,3]
3.1209949022329564 - 9.82238012935164im
bus3 = get_component(Bus, system_data, "Bus 3 HV")
ybus_entry = ybus[bus3, bus3]
3.1209949022329564 - 9.82238012935164im
We recognize that many models require matrix operations. For those cases, you can access the sparse data as follows:
sparse_array = get_data(ybus)
14×14 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 54 stored entries: 6.02503-19.4471im -4.99913+15.2631im … ⋅ -4.99913+15.2631im 9.52132-30.2721im ⋅ ⋅ -1.13502+4.78186im ⋅ ⋅ -1.68603+5.11584im ⋅ -1.0259+4.23498im -1.70114+5.19393im ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ -1.42401+3.02905im ⋅ ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ -1.13699+2.31496im ⋅ ⋅ 2.561-5.34401im
PTDF
The PTDF matrix can be calculated as follows:
ptdf = PTDF(system_data)
PowerNetworkMatrix : 0.0 -0.838019 -0.746512 -0.667457 … -0.632327 -0.643266 0.0 -0.161981 -0.253488 -0.332543 -0.367673 -0.356734 0.0 0.0273499 -0.532008 -0.151329 -0.121535 -0.130812 0.0 0.0572376 -0.143381 -0.316698 -0.254346 -0.273762 0.0 0.0773939 -0.0711234 -0.19943 -0.256446 -0.238693 0.0 0.0273499 0.467992 -0.151329 … -0.121535 -0.130812 0.0 0.0799125 0.306671 0.502572 0.00606475 0.160669 0.0 0.0029521 0.0113289 0.0185658 -0.241187 -0.356933 0.0 0.00172287 0.00661167 0.0108352 -0.140759 -0.20831 0.0 -0.00467497 -0.0179406 -0.029401 -0.618054 -0.434757 0.0 -0.00281516 -0.0108034 -0.0177046 … 0.145234 -0.035575 0.0 -0.000413472 -0.00158673 -0.00260034 -0.169694 -0.0887458 0.0 -0.00144634 -0.00555046 -0.00909609 -0.593595 -0.310436 0.0 1.07132e-17 -1.34601e-17 4.84298e-17 4.25457e-18 0.0 0.0 0.0029521 0.0113289 0.0185658 -0.241187 -0.356933 0.0 0.00281516 0.0108034 0.0177046 … -0.145234 0.035575 0.0 0.00185981 0.00713719 0.0116964 -0.236711 -0.600818 0.0 0.00281516 0.0108034 0.0177046 -0.145234 0.035575 0.0 -0.000413472 -0.00158673 -0.00260034 -0.169694 -0.0887458 0.0 -0.00185981 -0.00713719 -0.0116964 0.236711 -0.399182
The entries of the matrix can also be indexed using the devices directly:
line = get_component(Line, system_data, "Bus 1 HV-Bus 2 HV-i_1")
bus = get_component(Bus, system_data, "Bus 3 HV")
ptdf_entry = ptdf[line, bus]
-0.7465116864925992
Alternatively, the branch name and bus number can be used. For instance, for the same PTDF entry we can do:
ptdf_entry = ptdf["Bus 1 HV-Bus 2 HV-i_1", 3]
-0.7465116864925992
PTDF also takes a vector of distributed slacks, for now this feature requires passing a vector of weights with the same number of elements are buses in the system. For more details check the API entry for PTDF
.
In the same fashion as in the case of the Ybus, we recognize many models use matrix operations when using the PTDF matrix. The raw data is available using get_data
and the lookup table between (names,numbers) and (i,j) matrix entries is available using get_lookup
branch_lookup, bus_lookup = get_lookup(ptdf);
Branch lookup:
branch_lookup
Dict{String, Int64} with 20 entries: "Bus 9 LV-Bus 14 LV-i_17" => 17 "Bus 6 LV-Bus 12 LV-i_12" => 12 "Bus 2 HV-Bus 4 HV-i_4" => 4 "Bus 7 ZV-Bus 9 LV-i_15" => 15 "Bus 7 ZV-Bus 8 TV-i_14" => 14 "Bus 1 HV-Bus 2 HV-i_1" => 1 "Bus 9 LV-Bus 10 LV-i_16" => 16 "Bus 4 HV-Bus 9 LV-i_9" => 9 "Bus 4 HV-Bus 7 ZV-i_8" => 8 "Bus 6 LV-Bus 13 LV-i_13" => 13 "Bus 6 LV-Bus 11 LV-i_11" => 11 "Bus 1 HV-Bus 5 HV-i_2" => 2 "Bus 10 LV-Bus 11 LV-i_18" => 18 "Bus 2 HV-Bus 5 HV-i_5" => 5 "Bus 5 HV-Bus 6 LV-i_10" => 10 "Bus 3 HV-Bus 4 HV-i_6" => 6 "Bus 2 HV-Bus 3 HV-i_3" => 3 "Bus 4 HV-Bus 5 HV-i_7" => 7 "Bus 12 LV-Bus 13 LV-i_19" => 19 "Bus 13 LV-Bus 14 LV-i_20" => 20
Bus Look up
bus_lookup
Dict{Int64, Int64} with 14 entries: 5 => 5 12 => 12 8 => 8 1 => 1 6 => 6 11 => 11 9 => 9 14 => 14 3 => 3 7 => 7 4 => 4 13 => 13 2 => 2 10 => 10
LODF
LODF and PTDF share the same characteristics in terms of indexing and calculation:
lodf = LODF(system_data)
PowerNetworkMatrix : -1.0 1.0 -0.207667 … 0.00397419 0.030043 1.0 -1.0 0.207667 -0.00397419 -0.030043 -0.168846 0.168846 -1.0 0.00337054 0.0254797 -0.353359 0.353359 0.455286 0.00705382 0.0533236 -0.477795 0.477795 0.337047 -0.00645017 -0.0487603 -0.168846 0.168846 -1.0 … 0.00337054 0.0254797 -0.493344 0.493344 -0.514609 -0.0561692 -0.424613 -0.0182249 0.0182249 -0.0190105 0.0420518 0.317892 -0.0106362 0.0106362 -0.0110947 0.0245418 0.185525 0.0288612 -0.0288612 0.0301052 -0.0665936 -0.503416 0.0173795 -0.0173795 0.0181287 … 0.0656897 0.496584 0.00255259 -0.00255259 0.00266262 -1.0 -0.222319 0.00892907 -0.00892907 0.00931395 0.867717 -0.777681 -6.61382e-17 9.64509e-18 5.48592e-17 1.28408e-16 1.1685e-17 -0.0182249 0.0182249 -0.0190105 0.0420518 0.317892 -0.0173795 0.0173795 -0.0181287 … -0.0656897 -0.496584 -0.0114817 0.0114817 -0.0119766 0.132283 1.0 -0.0173795 0.0173795 -0.0181287 -0.0656897 -0.496584 0.00255259 -0.00255259 0.00266262 -1.0 -0.222319 0.0114817 -0.0114817 0.0119766 -0.132283 -1.0