How to Diagnose a Disconnected Network
To follow along, you can download this tutorial as a Julia script (.jl) or Jupyter notebook (.ipynb).
A singular ABA matrix or a failed DC power flow is frequently just a disconnected network: an island with no reference bus leaves ABA singular. Checking connectivity first localizes the problem before you dig into the numerics. This guide walks through the check, then deliberately breaks a network so you can see exactly what a fragmented result looks like — and how to get back.
using PowerNetworkMatrices
import PowerSystems
import PowerSystemCaseBuilderLoad an example test system with PowerSystemCaseBuilder.build_system:
sys = PowerSystemCaseBuilder.build_system(
PowerSystemCaseBuilder.PSITestSystems,
"c_sys5",
);[ Info: Loaded time series from storage file existing=/home/runner/.julia/packages/PowerSystemCaseBuilder/zuCHR/data/serialized_system/8584b9e729c8aa68ee5405660c6258cde1f67ed3b68f114823707912e9a0d16c/c_sys5_time_series_storage.h5 new=/tmp/jl_jZWDZT compression=InfrastructureSystems.CompressionSettings(false, InfrastructureSystems.CompressionTypesModule.CompressionTypes.DEFLATE = 1, 3, true)Step 1 — Confirm a healthy network is connected
validate_connectivity returns true when the system forms a single connected component:
validate_connectivity(sys)truefind_subnetworks shows the decomposition behind that answer: a Dict mapping each island's reference bus to the set of bus numbers in it. A connected system yields a single entry:
find_subnetworks(sys)Dict{Int64, Set{Int64}} with 1 entry:
4 => Set([3, 2, 1, 4, 5])validate_connectivity and find_subnetworks also accept an already-built AdjacencyMatrix or Ybus, so a matrix you already have on hand is reused instead of rebuilt:
adj = AdjacencyMatrix(sys)
validate_connectivity(adj)trueStep 2 — Disconnect a bus and watch it split
To see a fragmented result on a real system, let's isolate one bus. A bus goes silent when every branch touching it is out of service, so we find bus 5's incident branches and mark them unavailable with PowerSystems.set_available! — Ybus (and therefore the connectivity check) only includes available branches:
isolated_bus = 5
incident = [
br for br in PowerSystems.get_components(PowerSystems.ACBranch, sys) if
PowerSystems.get_number(PowerSystems.get_from(PowerSystems.get_arc(br))) ==
isolated_bus ||
PowerSystems.get_number(PowerSystems.get_to(PowerSystems.get_arc(br))) == isolated_bus
]
for br in incident
PowerSystems.set_available!(br, false)
endThe network is now split. validate_connectivity reports it:
validate_connectivity(sys)false...and find_subnetworks returns two entries — the main island, and bus 5 stranded on its own:
find_subnetworks(sys)Dict{Int64, Set{Int64}} with 2 entries:
4 => Set([3, 2, 1, 4])
5 => Set([5])There is the diagnosis. That second island — the isolated {5} — has no reference bus of its own, which is exactly the block that would have made ABA singular. The bus set tells you precisely which buses to reconnect (or which island to study in isolation). Here it points straight back at the bus we broke.
Step 3 — Reconnect and recover
Restoring the branches we took out puts the network back together — bus 5 rejoins the main island and validate_connectivity is true again:
for br in incident
PowerSystems.set_available!(br, true)
end
validate_connectivity(sys)true...and find_subnetworks is back to a single island, identical to where we started:
find_subnetworks(sys)Dict{Int64, Set{Int64}} with 1 entry:
4 => Set([3, 2, 1, 4, 5])Choosing a traversal algorithm
The lower-level find_subnetworks(M, bus_numbers; subnetwork_algorithm) — which runs over a raw sparse connectivity matrix — lets you pick how the graph is walked:
iterative_union_find(the default) — an iterative union-find disjoint-set, safe on networks of any size.depth_first_search— a recursive traversal.
Both return the same island decomposition, so the choice is about performance, not correctness. Prefer the default union-find; it avoids the deep recursion that depth_first_search can hit on very large networks. The subnetwork_algorithm keyword also threads through the matrix constructors, so islands are detected the same way at build time as by an explicit find_subnetworks call — here an ABA_Matrix built with depth_first_search:
ABA_Matrix(sys; subnetwork_algorithm = depth_first_search);[ Info: Finding subnetworks via depth first searchSee also
- Matrix overview & indexing — the
AdjacencyMatrixandYbusgraphs these checks traverse, and per-island axes. - Network Reduction Theory — how the susceptance graph can fragment into more islands than the admittance graph, and why that matters for
ABA.