SWMM5+ Technical Advisory Committee · CIMM.org

Anderson Acceleration for SWMM6

An interactive companion to Caleb Buahin's LinkedIn article on speeding up the dynamic wave solver with depth-2 mixing.

SWMM's dynamic wave solver finds node depths by Picard iteration — repeatedly applying a depth-update function G until depths stop changing. It converges, but slowly, and every routing timestep pays the iteration tax. On networks with many tightly coupled nodes the solver frequently hits MAX_TRIALS on nearly every timestep, even in mild conditions.

Caleb Buahin's proposal wraps that iteration with depth-2 Anderson mixing: at each step, take the last two G outputs and blend them with a coefficient α chosen to minimize the residual. The engine already has the state; the extra cost is bookkeeping. Reported savings: 25–50% fewer iterations per timestep. Enable it with one line:

[OPTIONS]
ANDERSON_ACCEL   YES
NODE_CONTINUITY  SEMI_IMPLICIT   ;; recommended pairing

This page walks both layers of the design. The mixing math first, then the per-node skip list that makes it safe for real networks.

Layer 1 · the mixing math

One AA step: blending two Picard outputs

Given G(yk-1) and G(yk), AA picks α to minimize the blended residual. Drag the slider, or snap to the optimum.

y* = 2.00 ft · ω = 0.5 · tol = 0.005
0.00 1.00 0.533
yk+1  =  (1 − α) · G(yk-1)  +  α · G(yk)
     =  0.467 · 2.400  +  0.533 · 1.650
     =  2.000 ft
|blend residual| = 0.000  ·  |rk| without blending = 1.050

The mixing is elegant — for a well-behaved linear operator, α lands exactly on the blend that zeros the residual, and depth-2 AA reaches the fixed point in a single step. But real SWMM doesn't give you that courtesy. Weirs snap between free-flow and submerged when HGL crosses the crown. EXTRAN's depth-update formula switches at surcharge onset. The Preissmann slot introduces a kink in flow area near 0.985·yfull. Pump state is on or off.

Each is a point where G is no longer smooth, and Anderson's linear-regime assumption breaks. Caleb's implementation handles this with a per-node skip list: every iteration, every node runs a sequence of checks. Any rule that fires forces plain Picard on that node for this step, while the rest of the network keeps the acceleration.

Layer 2 · the safety guards

Per-node AA eligibility check

Toggle conditions and watch the engine's decision. The first rule that fires wins.

Node classification
Iteration state
Static-slot conduit ratio y/yfull 0.985
0.850.98 — 1.02 skip band1.15
Current |rk| 0.024 ft
00.100 = 20·tol gate0.200
skip-list evaluation (engine order)
engine step for this node

What to watch in the benchmark corpus

The residual gate + surcharge interaction bites hardest. In a big surcharge event, most of the interesting nodes are simultaneously EXTRAN-flagged and above the 20·tol gate for several early iterations — AA contributes nothing there. All the speedup has to come from the paired NODE_CONTINUITY SEMI_IMPLICIT option, which smooths the crown-switch discontinuity. Worth quantifying on real pathological networks before claiming the 25–50% number universally.

The static-slot 0.98–1.02 window is the design choice that most deserves a second pair of eyes. Too narrow and AA applies across the area kink; too wide and you're leaving acceleration on the table exactly in the transition regime where convergence is already slowest. A benchmark corpus would pin down the right number.

The pump-always-skip rule is conservative and probably correct, but it means pump-heavy networks get less benefit than the headline suggests. Specific-system speedups are the interesting number, not the average.