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 PowerSystemCaseBuilder

Load 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)
true

find_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)
true

Step 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)
end

The 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:

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 search

See also