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 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 PowerNetworkMatricesjulia> using PowerSystemCaseBuilderjulia> const PNM = PowerNetworkMatricesPowerNetworkMatricesjulia> const PSB = PowerSystemCaseBuilderPowerSystemCaseBuilderjulia> # Load a test system sys = PSB.build_system(PSB.PSITestSystems, "c_sys14");[ Info: Deserializing with InMemoryTimeSeriesStorage is currently not supported. Using HDF [ Info: Loaded time series from storage file existing=/home/runner/.julia/packages/PowerSystemCaseBuilder/QOo1f/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys14_time_series_storage.h5 new=/tmp/jl_XBrCVf compression=InfrastructureSystems.CompressionSettings(false, InfrastructureSystems.CompressionTypesModule.CompressionTypes.DEFLATE = 1, 3, true) ┌ 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: 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 ┌ 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: 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: 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:219julia> # Create Ybus with radial reduction ybus = Ybus(sys; network_reductions=[RadialReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{RadialReduction}
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);ERROR: UndefVarError: `ybus` not defined in `Main` Suggestion: add an appropriate import or assignment. This global was declared but not assigned.julia> # View the bus reduction mapping # This shows which buses were reduced to which parent buses get_bus_reduction_map(reduction_data)ERROR: UndefVarError: `reduction_data` not defined in `Main` Suggestion: add an appropriate import or assignment. This global was declared but not assigned.julia> # View the reverse bus search mapping # This maps each reduced bus to its ultimate parent get_reverse_bus_search_map(reduction_data)ERROR: UndefVarError: `get_reverse_bus_search_map` not defined in `Main` Suggestion: check for spelling errors or missing imports.julia> # View the removed arcs (branches) get_removed_arcs(reduction_data)ERROR: UndefVarError: `get_removed_arcs` not defined in `Main` Suggestion: check for spelling errors or missing imports.
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 101 and 205
reduction = RadialReduction(irreducible_buses=[101, 205]);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=[RadialReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{RadialReduction}julia> # Apply to LODF matrix lodf = LODF(sys; network_reductions=[RadialReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{RadialReduction}julia> # Apply to Incidence Matrix incidence = IncidenceMatrix(sys; network_reductions=[RadialReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{RadialReduction}
Benefits of Radial Reduction
Using RadialReduction provides several advantages:
- Smaller Matrices: Eliminates unnecessary rows and columns from network matrices
- Faster Computations: Reduced matrix dimensions lead to faster linear algebra operations
- Better Conditioning: Removing radial elements can improve numerical properties
- 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 findjulia> # Create Ybus with radial reduction ybus_reduced = Ybus(sys; network_reductions=[RadialReduction()]);ERROR: TypeError: in keyword argument network_reductions, expected Vector{NetworkReduction}, got a value of type Vector{RadialReduction}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.
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_mapandreverse_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