Matrices

The calculations on this page take a BalancedNetwork or a PioModule{BalancedNetwork} and return SparseMatrixCSC or Vector{Float64} values with 1-based indices. The DC calculations come from the powerio library; the admittance matrices are assembled in Julia.

DC calculations

The powerio library computes the eight DC calculations, under the same names as the Rust, Python, and C APIs. With A the branch by bus incidence matrix (+1 at the from bus, -1 at the to bus of every in-service branch) and b the branch susceptances:

A  = calc_incidence_matrix(net)            # branches by buses
b  = calc_branch_susceptances(net)         # one per in-service branch
B  = calc_bus_susceptance_matrix(net)      # A' * Diagonal(b) * A
Bf = calc_branch_flow_matrix(net)          # Diagonal(b) * A
ps = calc_branch_phase_shift_injection(net)
pb = calc_bus_phase_shift_injection(net)

va = zeros(length(net.buses))              # bus voltage angles, radians
pf = calc_branch_flow_dc(net, va)          # -(Bf * va) + ps
p  = calc_bus_injection_dc(net, va)        # -(B * va) + pb

formula="series_susceptance" (the default) uses the imaginary part of the series admittance as the branch susceptance. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. The admittance matrices below and to_powerdata do not share the branch axis.

Admittance matrices

calc_admittance_matrix assembles the complex bus admittance matrix Y = G + jB in Julia from the element tables, following MATPOWER's makeYbus as the powerio matrix crate implements it. For each in-service branch from bus i to bus j with series impedance z = r + jx, terminal charging y_fr and y_to, and complex tap a = tap * exp(j * shift):

Y[i,i] += (1/z + y_fr) / |a|^2
Y[j,j] += 1/z + y_to
Y[i,j] += -(1/z) / conj(a)
Y[j,i] += -(1/z) / a

plus the in-service bus shunts Y[i,i] += (g_s + j b_s) / base_mva. The result is a BusMappedMatrix with idx_to_bus, bus_to_idx, and the sparse matrix.

Y = calc_admittance_matrix(net)
Y.matrix[Y.bus_to_idx[4], Y.bus_to_idx[5]]
calc_admittance_matrix(net; include_taps=false)
calc_admittance_matrix("case9.m")          # parse, then assemble

calc_bprime_matrix and calc_bdoubleprime_matrix are the fast decoupled B' and B'' matrices. They use the same kernel, with charging, taps, shifts, shunts, and series resistance switched on or off as MATPOWER's makeB does, and the result negated. scheme=:bx (the default) or :xb selects where the series resistance is dropped.

A branch whose impedance magnitude is below the divisibility threshold is an error unless you pass skip_zero_impedance=true, which drops it.

PowerIO.calc_dc_index_mapFunction
calc_dc_index_map(net; formula="series_susceptance", skip_zero_impedance=false)

The axes every DC calculation shares, as a named tuple:

  • idx_to_bus[k]: the source bus id of bus row or column k, every bus in table order;
  • bus_to_idx[id]: the row of bus id;
  • idx_to_branch[k]: the 1-based position in net.branches of branch row k (three winding transformer windings follow the branches), in-service non self loop branches only;
  • branch_ids[k]: the stable identity of branch row k, the branch uid when the source states one and "branches:<row>" otherwise (row zero based);
  • skipped_branch_rows: the 1-based positions of the zero impedance branches dropped under skip_zero_impedance=true, empty otherwise.

This axis is the DC calculations' own. Neither to_powerdata, whose branch rows follow net.branches in table order with one row per branch and its own status field, nor calc_branch_admittances, whose rows follow net.branches over the in-service branches, shares it. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_incidence_matrixFunction
calc_incidence_matrix(net; formula="series_susceptance", skip_zero_impedance=false) -> SparseMatrixCSC

Branch by bus incidence matrix: +1 at the from bus and -1 at the to bus of every branch on the branch axis. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_branch_susceptancesFunction
calc_branch_susceptances(net; formula="series_susceptance", skip_zero_impedance=false) -> Vector{Float64}

One susceptance per branch on the branch axis. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_bus_susceptance_matrixFunction
calc_bus_susceptance_matrix(net; formula="series_susceptance", skip_zero_impedance=false) -> SparseMatrixCSC

The DC bus susceptance matrix A' * Diagonal(b) * A, buses by buses. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_branch_flow_matrixFunction
calc_branch_flow_matrix(net; formula="series_susceptance", skip_zero_impedance=false) -> SparseMatrixCSC

The branch flow matrix Diagonal(b) * A, branches by buses, mapping bus angles to branch flows. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_branch_phase_shift_injectionFunction
calc_branch_phase_shift_injection(net; formula="series_susceptance", skip_zero_impedance=false) -> Vector{Float64}

The per branch injection caused by transformer phase shifts, over the branch axis. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_bus_phase_shift_injectionFunction
calc_bus_phase_shift_injection(net; formula="series_susceptance", skip_zero_impedance=false) -> Vector{Float64}

The per bus injection caused by transformer phase shifts, over the bus axis. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_branch_flow_dcFunction
calc_branch_flow_dc(net, voltage_angles; formula="series_susceptance", skip_zero_impedance=false) -> Vector{Float64}

DC branch flows in per unit over the branch axis for the given bus voltage angles in radians, one per bus on the bus axis. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_bus_injection_dcFunction
calc_bus_injection_dc(net, voltage_angles; formula="series_susceptance", skip_zero_impedance=false) -> Vector{Float64}

DC bus injections in per unit over the bus axis for the given bus voltage angles in radians. formula selects the branch susceptance: "series_susceptance" (the imaginary part of the series admittance, the default), "tap_adjusted_reactance", or "reactance_only". Rows and columns are 1-based. A bus axis covers every bus in table order; a branch axis covers the in-service, non self loop branches in table order, with three winding transformer windings after the branches. calc_dc_index_map names both axes. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE unless skip_zero_impedance=true drops it from the branch axis. The argument is a BalancedNetwork or a PioModule{BalancedNetwork}.

source
PowerIO.calc_admittance_matrixFunction
calc_admittance_matrix(net; include_taps=true, include_shifts=true, skip_zero_impedance=false)

The complex bus admittance matrix Y = G + jB in per unit on the system base, following MATPOWER's makeYbus: series admittances, terminal charging, transformer taps and phase shifts, and in-service bus shunts. A zero impedance branch is a PowerIOError with code BUILD.OPERATOR.ZERO_IMPEDANCE, the code the DC calculations report, unless skip_zero_impedance=true drops it. Returns a BusMappedMatrix. The argument is a BalancedNetwork, a PioModule{BalancedNetwork}, or a path to parse.

source
PowerIO.calc_bprime_matrixFunction
calc_bprime_matrix(net; scheme=:bx, skip_zero_impedance=false)

MATPOWER's fast decoupled B' matrix: the negated imaginary part of a bus admittance matrix built with unity taps, no line charging, no bus shunts, and phase shifts kept. scheme=:xb also drops series resistance. Returns a real BusMappedMatrix.

source
PowerIO.calc_bdoubleprime_matrixFunction
calc_bdoubleprime_matrix(net; scheme=:bx, skip_zero_impedance=false)

MATPOWER's fast decoupled B'' matrix: the negated imaginary part of a bus admittance matrix built with phase shifts cleared and taps, charging, and bus shunts kept. scheme=:bx (the default) also drops series resistance. Returns a real BusMappedMatrix.

source
PowerIO.calc_branch_admittancesFunction
calc_branch_admittances(net; include_taps=true, include_shifts=true, skip_zero_impedance=false)

The primitive admittance of every in-service branch as (y_ff, y_ft, y_tf, y_tt) in per unit on the system base, the four coefficients MATPOWER's makeYbus adds into Y[f,f], Y[f,t], Y[t,f], and Y[t,t]. Rows follow net.branches in table order over the in-service branches; a skipped zero impedance branch has no row. That is not the branch axis calc_dc_index_map reports, which omits self loop branches and appends three winding transformer windings after the branches. Bus shunts are not included. Returns a Vector{NTuple{4,ComplexF64}}. to_powerdata states the same values as c5 + im*c6 = y_ff, c3 + im*c4 = y_ft, c1 + im*c2 = y_tf, and c7 + im*c8 = y_tt.

source
PowerIO.BusMappedMatrixType
BusMappedMatrix{T}

A sparse matrix over the bus table with its index maps: idx_to_bus[k] is the bus id of row and column k, bus_to_idx[id] the row of bus id, and matrix the SparseMatrixCSC{T,Int}.

source