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.
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.
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.