…

What am I looking at?

A replay of the component-ablation campaign behind the paper. Each run is one configuration of the solver on one test system; you can scrub through every topology it proposed on the way to its answer.

The problem — OTSD

Optimal Transmission Switching with De-energization. Choose a set of transmission lines to open so that the remaining network carries the least load at risk, while staying N−1 secure — no single further line outage may overload anything. Opening lines can strand part of the grid, and the load in a stranded pocket is what the objective counts.

Read the preprint on SSRN →

How it is solved

A master MILP proposes which branches to open; a subproblem checks N−1 security and, when it fails, returns cuts that forbid that proposal. Each exchange is one candidate. Around that sits a local search of k phases, each re-seeded from the last phase's answer with a wider switchable set.

Terms, as this app uses them

candidateOne Benders iteration: a set of open branches the master proposed. 88,149 of them in the corpus.
feasibleA candidate whose N−1 check found no violated contingency. Only these can move the incumbent. Green everywhere in this app.
incumbentThe best objective among feasible candidates so far.
phaseOne outer local-search iteration; k = 3 per run.
SBSSwitchable branch set — the branches the master is allowed to open in this phase. Everything else is held closed. It grows each phase, so membership is per phase, not permanent.
HHamming bound: how many branches a candidate may differ from the warm start. Larger H is a wider neighbourhood and a harder master.
d_violHow far the SBS reaches out from trouble: starting at each overloaded branch, follow the flow outward this many hops and add what you pass. SBS_SA_depth in the code.
d_solGraph hops around the current solution's open branches, also added to the SBS. warmstart_hop_sbs in the code, hop in run names. The campaign behind the paper's numbers ran d_sol = 0.
objectiveLoad at risk, per unit on a 100 MVA base — so 5.29 p.u. is 529 MW. Shown in MW with p.u. underneath.
violated contingencyA branch whose outage would overload something on top of this candidate's topology — what the Benders subproblem reports as v_ctg, drawn red and dashed. Point at one to see the branches it overloads and their loading. The logs record only which contingencies failed, so the overloads are precomputed with the same DC solve the campaign used.
bridge / pocketA live branch whose own outage would split the grid. The side that falls off is its pocket, and the load stranded there is what that bridge contributes to the objective. A bridge can sit inside another bridge's pocket; the objective charges that inner load to both, so the per-bridge figures sum to the objective while the distinct load at risk is smaller. Turn on the bridges layer to see them, and point at one to see its pocket.
TLFThermal limit factor scaling every line rating: 1.5 for ieee118, 1.0 for ieee57.

The configurations — what each one switches off

REFNothing disabled: the reference.
NO-SCREENSecurity screening.
NO-CF-POCKETClosed-form cuts, replaced by an LP with pocket π.
NO-CF-FREEClosed-form cuts, replaced by an LP with free π.
NO-EMBEDContingency embedding.
NO-INHERITCut inheritance between phases.
NO-LOCALSEARCHThe whole outer loop — no Hamming bound, no SBS.

The two x-axes

By default the objective plot and the gantt put one candidate per equal step, which is the right view for what the search tried. time axis rescales both to elapsed solve time within the phase, so a column's width is the time that candidate took. Candidates arrive very unevenly — the longest gap in a phase is typically 10× the median one, and a median 20 % of a phase's wall time sits inside a single gap — so the two views can look completely different. The scrubber underneath always steps candidate by candidate.

Comparing the shape of time within one phase is sound. Comparing total times between runs is not — see below.

Two things to read carefully

Wall time is confounded. Configurations ran in a fixed order within each block, so timing carries machine drift. LP-solve and Benders-iteration counts are the deterministic quantities — it is marked ⚠ wherever it appears.

The outer search is heuristic. Two configurations ending at different local optima is a finding, not a bug; that is what pinning a reference run is for.

Campaign

Run

network
candidates
objective of each candidate
speed