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 PowerNetworkMatricesjulia> using PowerSystemCaseBuilderjulia> const PNM = PowerNetworkMatricesPowerNetworkMatricesjulia> const PSB = PowerSystemCaseBuilderPowerSystemCaseBuilderjulia> # 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.jsonjulia> # 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:
- Smaller Matrices: Eliminates intermediate buses from network matrices
- Faster Computations: Reduced matrix dimensions lead to faster operations
- Simplified Topology: Creates a more direct representation of the network
- 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 findjulia> # 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 CIf 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 CThe 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 findjulia> # 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 findjulia> # 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:32julia> # 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