DegreeTwoReduction

In this tutorial the DegreeTwoReduction network reduction algorithm is presented. This reduction eliminates buses with exactly two connections by combining the incident branches into a single equivalent branch while preserving the electrical characteristics of the 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 DegreeTwoReduction.

Understanding Degree-Two Buses

Degree-two buses are nodes in the network topology that have exactly two connections. These intermediate buses can be eliminated by replacing the two incident branches with a single equivalent branch, simplifying the network while maintaining its electrical behavior. The reduction is performed recursively, identifying and eliminating chains of degree-two nodes to maximize network simplification.

Basic Usage of DegreeTwoReduction

The DegreeTwoReduction 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> const PNM = PowerNetworkMatricesPowerNetworkMatrices
julia> const PSB = PowerSystemCaseBuilderPowerSystemCaseBuilder
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/9434fe2e9f66a9d6af8518bf3b21355800258751/PowerSystemsTestData-4.0.1/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/h2Bwp/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/h2Bwp/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/h2Bwp/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/h2Bwp/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/f1vEv/src/utils/IO/branchdata_checks.jl:228 ┌ 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/f1vEv/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/f1vEv/src/utils/IO/branchdata_checks.jl:228 ┌ 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/f1vEv/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/f1vEv/src/utils/IO/branchdata_checks.jl:228 ┌ 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/f1vEv/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/f1vEv/src/utils/IO/branchdata_checks.jl:208 [ Info: Serialized time series data to /home/runner/.julia/packages/PowerSystemCaseBuilder/QOo1f/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys14_time_series_storage.h5. [ Info: Serialized System to /home/runner/.julia/packages/PowerSystemCaseBuilder/QOo1f/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys14.json [ Info: Serialized System metadata to /home/runner/.julia/packages/PowerSystemCaseBuilder/QOo1f/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys14_metadata.json
julia> # Create Ybus with degree-two reduction ybus = Ybus(sys; network_reductions=[DegreeTwoReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{DegreeTwoReduction}

Accessing Reduction Information

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

julia> # Get the network reduction data
       reduction_data = get_network_reduction_data(ybus);ERROR: UndefVarError: `ybus` not defined in `Main`
Suggestion: add an appropriate import or assignment. This global was declared but not assigned.
julia> # View the series branch mapping # This shows how multiple branches were combined into composite branches get_series_branch_map(reduction_data)ERROR: UndefVarError: `get_series_branch_map` not defined in `Main` Suggestion: check for spelling errors or missing imports.
julia> # View the removed buses get_removed_buses(reduction_data)ERROR: UndefVarError: `get_removed_buses` not defined in `Main` Suggestion: check for spelling errors or missing imports.
julia> # View the removed arcs (branches that were combined) get_removed_arcs(reduction_data)ERROR: UndefVarError: `get_removed_arcs` not defined in `Main` Suggestion: check for spelling errors or missing imports.

Configuration Options

The DegreeTwoReduction provides several configuration options:

Protecting Specific Buses

You can protect certain buses from reduction even if they have degree two:

julia> # Create degree-two reduction that protects specific buses
       reduction = DegreeTwoReduction(irreducible_buses=[101, 205]);

Handling Reactive Power Injectors

By default, DegreeTwoReduction reduces buses with reactive power injections. You can change this behavior:

julia> # Create reduction that preserves buses with reactive power injections
       reduction = DegreeTwoReduction(reduce_reactive_power_injectors=false);
julia> # Apply to system ybus_preserve_reactive = Ybus(sys; network_reductions=[reduction]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{DegreeTwoReduction}

Combining with Other Network Matrices

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

julia> # Apply to PTDF matrix
       ptdf = PTDF(sys; network_reductions=[DegreeTwoReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{DegreeTwoReduction}
julia> # Apply to LODF matrix lodf = LODF(sys; network_reductions=[DegreeTwoReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{DegreeTwoReduction}
julia> # Apply to BA Matrix ba_matrix = BA_Matrix(sys; network_reductions=[DegreeTwoReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{DegreeTwoReduction}
julia> # Apply to ABA Matrix aba_matrix = ABA_Matrix(sys; network_reductions=[DegreeTwoReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{DegreeTwoReduction}

Benefits of Degree-Two Reduction

Using DegreeTwoReduction provides several advantages:

  1. Smaller Matrices: Eliminates intermediate buses from network matrices
  2. Faster Computations: Reduced matrix dimensions lead to faster operations
  3. Simplified Topology: Creates a more direct representation of the network
  4. Preserved Accuracy: Maintains exact electrical equivalence for the reduced network

Example: Comparing Matrix Sizes

julia> # Create Ybus without reduction
       ybus_full = Ybus(sys);[ Info: Finding subnetworks via iterative union find
julia> # Create Ybus with degree-two reduction ybus_reduced = Ybus(sys; network_reductions=[DegreeTwoReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{DegreeTwoReduction}
julia> # Compare sizes size(get_ybus_data(ybus_full))ERROR: UndefVarError: `get_ybus_data` not defined in `Main` Suggestion: check for spelling errors or missing imports.
julia> size(get_ybus_data(ybus_reduced))ERROR: UndefVarError: `get_ybus_data` not defined in `Main` Suggestion: check for spelling errors or missing imports.

Understanding Series Branch Chains

When degree-two buses are eliminated, the reduction algorithm identifies chains of series-connected branches. For example:

Bus A --- Branch 1 --- Bus B --- Branch 2 --- Bus C

If Bus B has degree two, it can be eliminated, and Branches 1 and 2 are combined into a single equivalent branch:

Bus A --- Equivalent Branch --- Bus C

The equivalent branch's electrical parameters (impedance, admittance) are calculated to preserve the overall electrical behavior.

Combining Multiple Reductions

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

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
julia> # Get combined reduction data multi_reduction_data = get_network_reduction_data(ybus_multi);

Order of Reductions

When combining multiple reductions, the order can affect the final result:

julia> # First apply radial, then degree-two
       reductions1 = [RadialReduction(), DegreeTwoReduction()];
julia> ybus1 = Ybus(sys; network_reductions=reductions1);[ Info: Finding subnetworks via iterative union find
julia> # First apply degree-two, then radial reductions2 = [DegreeTwoReduction(), RadialReduction()];
julia> ybus2 = Ybus(sys; network_reductions=reductions2);[ Info: Finding subnetworks via iterative union find ┌ Warning: When applying both RadialReduction and DegreeTwoReduction, it is likely beneficial to apply RadialReduction first. @ PowerNetworkMatrices ~/work/PowerNetworkMatrices.jl/PowerNetworkMatrices.jl/src/ReductionContainer.jl:32
julia> # Compare results size(get_ybus_data(ybus1))ERROR: UndefVarError: `get_ybus_data` not defined in `Main` Suggestion: check for spelling errors or missing imports.
julia> size(get_ybus_data(ybus2))ERROR: UndefVarError: `get_ybus_data` not defined in `Main` Suggestion: check for spelling errors or missing imports.

In general, applying RadialReduction first is recommended, as it can create new degree-two buses that can then be eliminated by DegreeTwoReduction.

Important Notes

  • Topology Preservation: The reduction maintains essential network connectivity
  • Reference Bus Protection: Reference (slack) buses are automatically protected from elimination
  • Parallel Paths: The algorithm handles parallel branches correctly
  • Three-Winding Transformers: Special handling for three-winding transformer connections
  • Reversibility: The reduction maintains detailed mapping information for result interpretation
  • Electrical Equivalence: Equivalent branches are computed to maintain exact electrical behavior