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

ConcreteTypeSuperTypesCount
StringStringInt64
1ArcTopology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any20
2AreaAggregationTopology <: Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any1
3BusTopology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any14
4FixedAdmittanceElectricLoad <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any1
5LineACBranch <: Branch <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any17
6LoadZoneAggregationTopology <: Topology <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any1
7PowerLoadStaticLoad <: ElectricLoad <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any11
8TapTransformerACBranch <: Branch <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any3
9ThermalStandardThermalGen <: Generator <: StaticInjection <: Device <: Component <: InfrastructureSystemsComponent <: InfrastructureSystemsType <: Any5

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