RadialReduction

In this tutorial the RadialReduction network reduction algorithm is presented. This reduction eliminates radial (dangling) buses and their associated branches from the power network while preserving the electrical behavior of the core network.

Before diving into this tutorial we encourage the user to load PowerNetworkMatrices, hit the ? key in the REPL terminal and look for the documentation of RadialReduction.

Understanding Radial Branches

Radial buses are leaf nodes in the network topology with only one connection. These buses do not affect the electrical behavior of the rest of the network and for certain applications can be safely eliminated to simplify network matrices and improve computational efficiency.

Basic Usage of RadialReduction

The RadialReduction can be applied when constructing various network matrices. The most common use case is with the Ybus matrix:

julia> using PowerNetworkMatrices
julia> using PowerSystemCaseBuilder
julia> import PowerNetworkMatrices as PNM
julia> import PowerSystemCaseBuilder as PSB
julia> # Load a test system sys = PSB.build_system(PSB.PSITestSystems, "c_sys14");┌ Info: Building new system c_sys14 from raw data sys_descriptor.raw_data = "/home/runner/.julia/artifacts/edcb5940e84a802a86ad4f2223214d33121ac044/PowerSystemsTestData-4.0.2/psy_data/data_14bus_pu.jl" ┌ Warning: Invalid range valid_info.struct_name = "ACBus" field_name = "magnitude" valid_range = "voltage_limits" valid_info.ist_struct = ACBus: Bus 6: number: 6 name: Bus 6 available: true bustype: PowerSystems.ACBusTypesModule.ACBusTypes.PV = 2 angle: -0.24818581963359368 magnitude: 1.07 voltage_limits: (min = 0.94, max = 1.06) base_voltage: 13.8 area: nothing load_zone: nothing ext: Dict{String, Any}() InfrastructureSystems.SystemUnitsSettings: base_value: 100.0 unit_system: InfrastructureSystems.UnitSystemModule.UnitSystem.SYSTEM_BASE = 0 has_supplemental_attributes: false has_time_series: false @ InfrastructureSystems ~/.julia/packages/InfrastructureSystems/0oq8N/src/validation.jl:219 ┌ Warning: Invalid range valid_info.struct_name = "ACBus" field_name = "magnitude" valid_range = "voltage_limits" valid_info.ist_struct = ACBus: Bus 7: number: 7 name: Bus 7 available: true bustype: PowerSystems.ACBusTypesModule.ACBusTypes.PQ = 1 angle: -0.23335052099164186 magnitude: 1.062 voltage_limits: (min = 0.94, max = 1.06) base_voltage: 13.8 area: nothing load_zone: nothing ext: Dict{String, Any}() InfrastructureSystems.SystemUnitsSettings: base_value: 100.0 unit_system: InfrastructureSystems.UnitSystemModule.UnitSystem.SYSTEM_BASE = 0 has_supplemental_attributes: false has_time_series: false @ InfrastructureSystems ~/.julia/packages/InfrastructureSystems/0oq8N/src/validation.jl:219 ┌ Warning: Invalid range valid_info.struct_name = "ACBus" field_name = "magnitude" valid_range = "voltage_limits" valid_info.ist_struct = ACBus: Bus 8: number: 8 name: Bus 8 available: true bustype: PowerSystems.ACBusTypesModule.ACBusTypes.PV = 2 angle: -0.2331759880664424 magnitude: 1.09 voltage_limits: (min = 0.94, max = 1.06) base_voltage: 18.0 area: nothing load_zone: nothing ext: Dict{String, Any}() InfrastructureSystems.SystemUnitsSettings: base_value: 100.0 unit_system: InfrastructureSystems.UnitSystemModule.UnitSystem.SYSTEM_BASE = 0 has_supplemental_attributes: false has_time_series: false @ InfrastructureSystems ~/.julia/packages/InfrastructureSystems/0oq8N/src/validation.jl:219 ┌ Warning: Invalid range valid_info.struct_name = "ThermalStandard" field_name = "reactive_power" valid_range = "reactive_power_limits" valid_info.ist_struct = ThermalStandard: Bus1: name: Bus1 available: true status: true bus: ACBus: Bus 1 active_power: 2.0 reactive_power: -0.169 rating: 2.324 active_power_limits: (min = 0.0, max = 3.332) reactive_power_limits: (min = 0.0, max = 0.1) ramp_limits: nothing operation_cost: PowerSystems.ThermalGenerationCost composed of variable: InfrastructureSystems.CostCurve{InfrastructureSystems.QuadraticCurve} base_power: 100.0 time_limits: nothing must_run: false prime_mover_type: PowerSystems.PrimeMoversModule.PrimeMovers.ST = 20 fuel: PowerSystems.ThermalFuelsModule.ThermalFuels.COAL = 1 services: 0-element Vector{PowerSystems.Service} time_at_status: 10000.0 dynamic_injector: nothing ext: Dict{String, Any}() InfrastructureSystems.SystemUnitsSettings: base_value: 100.0 unit_system: InfrastructureSystems.UnitSystemModule.UnitSystem.SYSTEM_BASE = 0 has_supplemental_attributes: false has_time_series: false @ InfrastructureSystems ~/.julia/packages/InfrastructureSystems/0oq8N/src/validation.jl:219 ┌ Warning: Transformer Trans3 per-unit reactance 0.20912 is higher than the typical range (min = 0.05, max = 0.2). Check if the reactance source data is correct. @ PowerSystems ~/.julia/packages/PowerSystems/d2x1q/src/utils/IO/branchdata_checks.jl:229 ┌ Warning: rating 2000.0 MW for Trans3 is 2x larger than the max expected rating 115.0 MW for Transformer at a 69.0 kV Voltage level. @ PowerSystems ~/.julia/packages/PowerSystems/d2x1q/src/utils/IO/branchdata_checks.jl:208 ┌ Warning: Transformer Trans1 per-unit reactance 0.55618 is higher than the typical range (min = 0.05, max = 0.2). Check if the reactance source data is correct. @ PowerSystems ~/.julia/packages/PowerSystems/d2x1q/src/utils/IO/branchdata_checks.jl:229 ┌ Warning: rating 2000.0 MW for Trans1 is 2x larger than the max expected rating 115.0 MW for Transformer at a 69.0 kV Voltage level. @ PowerSystems ~/.julia/packages/PowerSystems/d2x1q/src/utils/IO/branchdata_checks.jl:208 ┌ Warning: Transformer Trans2 per-unit reactance 0.25202 is higher than the typical range (min = 0.05, max = 0.2). Check if the reactance source data is correct. @ PowerSystems ~/.julia/packages/PowerSystems/d2x1q/src/utils/IO/branchdata_checks.jl:229 ┌ Warning: rating 2000.0 MW for Trans2 is 2x larger than the max expected rating 115.0 MW for Transformer at a 69.0 kV Voltage level. @ PowerSystems ~/.julia/packages/PowerSystems/d2x1q/src/utils/IO/branchdata_checks.jl:208 ┌ Warning: rating 2000.0 MW for Trans4 is 2x larger than the max expected rating 115.0 MW for Transformer at a 69.0 kV Voltage level. @ PowerSystems ~/.julia/packages/PowerSystems/d2x1q/src/utils/IO/branchdata_checks.jl:208 [ Info: Serialized time series data to /home/runner/.julia/packages/PowerSystemCaseBuilder/zW01F/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys14_time_series_storage.h5. [ Info: Serialized System to /home/runner/.julia/packages/PowerSystemCaseBuilder/zW01F/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys14.json [ Info: Serialized System metadata to /home/runner/.julia/packages/PowerSystemCaseBuilder/zW01F/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys14_metadata.json
julia> # Create Ybus with radial reduction ybus = Ybus(sys; network_reductions = NetworkReduction[RadialReduction()])[ Info: Finding subnetworks via iterative union find AC_Ybus_Matrix Dimension 1, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14] Dimension 2, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14] And data with size (13, 13): 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

Accessing Reduction Information

After applying the reduction, you can access information about which buses and branches were eliminated:

julia> # Get the network reduction data
       reduction_data = get_network_reduction_data(ybus);
julia> # View the bus reduction mapping # This shows which buses were reduced to which parent buses get_bus_reduction_map(reduction_data)Dict{Int64, Set{Int64}} with 13 entries: 5 => Set() 12 => Set() 1 => Set() 6 => Set() 11 => Set() 9 => Set() 14 => Set() 3 => Set() 7 => Set([8]) 4 => Set() 13 => Set() 2 => Set() 10 => Set()
julia> # View the reverse bus search mapping # This maps each reduced bus to its ultimate parent PNM.get_reverse_bus_search_map(reduction_data)Dict{Int64, Int64} with 1 entry: 8 => 7
julia> # View the removed arcs (branches) PNM.get_removed_arcs(reduction_data)Set{Tuple{Int64, Int64}} with 1 element: (7, 8)

Protecting Specific Buses from Reduction

In some cases, you may want to preserve certain buses even if they are radial. This can be done using the irreducible_buses parameter:

julia> # Create radial reduction that protects buses 8 and 14
       reduction = RadialReduction(; irreducible_buses = [8, 14]);
julia> # Apply to system (buses must exist in the system) ybus_protected = Ybus(sys; network_reductions = NetworkReduction[reduction]);[ Info: Finding subnetworks via iterative union find
julia> # Bus 8 was radial, but preserved from reduction reduction_data = get_network_reduction_data(ybus_protected);
julia> get_bus_reduction_map(reduction_data)Dict{Int64, Set{Int64}} with 14 entries: 5 => Set() 12 => Set() 8 => Set() 1 => Set() 6 => Set() 11 => Set() 9 => Set() 14 => Set() 3 => Set() 7 => Set() 4 => Set() 13 => Set() 2 => Set() 10 => Set()

Combining with Other Network Matrices

The RadialReduction can be applied to other network matrix types as well:

julia> # Apply to PTDF matrix
       ptdf = PTDF(sys; network_reductions = NetworkReduction[RadialReduction()]);[ Info: Finding subnetworks via iterative union find
julia> # Apply to LODF matrix lodf = LODF(sys; network_reductions = NetworkReduction[RadialReduction()]);[ Info: Finding subnetworks via iterative union find
julia> # Apply to Incidence Matrix incidence = IncidenceMatrix(sys; network_reductions = NetworkReduction[RadialReduction()]);[ Info: Finding subnetworks via iterative union find

Benefits of Radial Reduction

Using RadialReduction provides several advantages:

  1. Smaller Matrices: Eliminates unnecessary rows and columns from network matrices
  2. Faster Computations: Reduced matrix dimensions lead to faster linear algebra operations
  3. Better Conditioning: Removing radial elements can improve numerical properties
  4. Memory Efficiency: Reduces storage requirements for large network models

Example: Comparing Matrix Sizes

julia> # Create Ybus without reduction
       ybus_full = Ybus(sys);[ Info: Finding subnetworks via iterative union find
julia> # Create Ybus with radial reduction ybus_reduced = Ybus(sys; network_reductions = NetworkReduction[RadialReduction()]);[ Info: Finding subnetworks via iterative union find
julia> # Compare sizes size(ybus_full)(14, 14)
julia> size(ybus_reduced)(13, 13)

Combining Multiple Reductions

RadialReduction can be combined with other network reduction algorithms like DegreeTwoReduction:

julia> # Apply both radial and degree-two reductions
       reductions = [RadialReduction(), DegreeTwoReduction()];
julia> ybus_multi = Ybus(sys; network_reductions = reductions);[ Info: Finding subnetworks via iterative union find

Important Notes

  • Reference Bus Protection: Reference (slack) buses are automatically protected from elimination, regardless of their connectivity
  • Order Matters: When combining multiple reductions, they are applied in the order specified in the vector
  • Reversibility: The reduction maintains mapping information (bus_reduction_map and reverse_bus_search_map) that can be used for result interpretation
  • Electrical Equivalence: The reduced network maintains the same electrical behavior as the original network for all non-eliminated elements