← Explainer · Markdown · Source on GitHub
# GPU diffusion convergence: history and rationale **Status (2026-09-26):** the implemented contract — operator and effective right-hand side, method, exits, `DiffusionSolveSettings`, reporting convention, budget, kernel rules and tests — is the [Diffusion README](/src/PolyCfd.Gpu/Diffusion/README). This page keeps why the solve audits the stored field against an effective-RHS residual, why it has a bounded colored Gauss-Seidel fallback and one shared total budget, the enclosure evidence behind those decisions, and why SOL-02a replaced the weighted-Jacobi primary phase described below with Chebyshev semi-iteration (same operator, tolerance, budgets and fallback). ## Why an audited fallback and one shared budget The relative residual is normalized by the **effective** right-hand side, including prescribed normal values, tangential wall forcing and immersed terms; normalizing by the stored velocity alone rejected wall-driven starts from rest (see [physics](/docs/PHYSICS_GUIDE#diffusion-and-walls)). Weighted Jacobi (ω = 0.8) alone stalled above the unchanged `1e-6` target on the prescribed-flow enclosure at `nu*dt/h²=6.4`, and the former static 200 and moving 400 sweep budgets did not cover every valid scenario (below). The 2026-09-24 decision kept the first 400 sweeps on the existing weighted Jacobi path, continued unresolved solves with colored Gauss-Seidel on the same row evaluator and boundary rules, audited the **stored float32 velocity** against the original effective right-hand side, and capped both phases together at 800 iterations for static and moving steps. The fallback changes the iteration, not the backward-Euler operator or its tolerance, and adds no retained buffers. Effective scenario settings record the budget; a resumed campaign requires matching new evidence, not reuse of the old build's acceptance. Physical and performance references and all scientific limits remain unchanged. See the [work board](/docs/WORKBOARD) for current validation status and [performance validation](/docs/PERFORMANCE_VALIDATION). ## Chebyshev primary phase — 2026-09-26 (SOL-02a) Weighted Jacobi dominated the moving-fan step: on the 128³ fan a 2026-09-25 experiment measured 276 sweeps and 287 ms of a 345 ms step. Chebyshev semi-iteration on the same undamped Jacobi row, with the rigorous bound ρ = S/(1 + S), needed 56 sweeps (59 ms; step 124 ms), passed the quick regression checks and changed fields by 1–3e-6. The user approved it (2026-09-25) as the one primary method. SOL-02a kept the operator, tolerance, budgets, colored fallback and bytes, added deterministic double audits with one host read each and an exit for inputs already within the tolerance, and adopted the experiment's validated stall rule; bound-based exits are the proposed follow-up (SOL-05). On the SOL-02a build the short fan's median diffusion count is 56 (Jacobi 266), the enclosure step-3 solve that needed 468 iterations converges in 76, and circular Couette at d = 115 records the rule's early exit as a known limit ([Diffusion README](/src/PolyCfd.Gpu/Diffusion/README#limits), [complete validation](/docs/COMPLETE_VALIDATION#chebyshev-diffusion--2026-09-26)). ## Choice of fallback The initial residual-correction prototype solved the first enclosure step at `nu*dt/h²=6.4` in 560 sweeps, with independent residual `9.53e-7`. It still stagnated at step 3 near `1.09e-6`, including a 2,400-sweep diagnostic. Longer correction accumulation did not fix that plateau. The colored fallback is simpler and completed all four 20-step enclosure startups (centered n64 dt=1/64, centered n128 dt=1/256 and dt=1/128, offset n128 dt=1/128). At the formerly failing third centered n128 dt=1/128 step, 468 sweeps give an independent stored-U residual `9.8695035e-7`, matching the GPU report and production field exactly. The 92 CUDA diffusion tests pass, including independent wall solutions, odd periodic grids and honest nonconvergence reporting. Two complete before/after timing pairs pass all scientific checks. Their combined verification-call time changes by +3.55%; the first pair changes by +6.63% and fails its shear timing limit, while the reversed pair changes by +0.32% and passes. Isolated warmed diffusion shows no sustained penalty on the two tested fast-path grids. All attempts and the separate repeated short cases are retained in the [measurement report] (unavailable local reference: `../../openfoam/compare/ENCLOSURE_N128_DIAGNOSTICS.md`). That initial full CUDA run stopped at its historical timing gate after all 1,519 tests and nine scientific workloads passed. The ordinary-path cleanup removes runtime output checks/captured audit locals; 92 tests and all four startups pass again, and the cleaned solver passes a complete matched timing pair. Full validation completed in `output/validation/diffusion-full-verified-20260924`: all 1,525 selected tests, 25 native cases, channel refinement/replay and field regressions pass. Overall regression remains 30/31 because historical timing still fails after one fresh retry. The unchanged historical solver also fails its old gate under current conditions; monitoring caught intermittent Windows workers in both timing sequences. A quiet performance check is still needed. Startup success is not settled enclosure accuracy. See [the complete result](/docs/COMPLETE_VALIDATION#diffusion-fallback-validation--2026-09-24). Near-unit periodic stress fields still demonstrate the limits of float storage. An independent FFT solution has residual `7.21e-15`, but nearest float rounding raises it to `1.339e-6`. This is not a lower bound over all float fields. Those stress tests assert that convergence matches the actual stored-field residual; they do not require every finite-budget solve to converge. No above-target field is accepted. [Independent analysis] (unavailable local reference: `../../openfoam/enclosure/analyze_float_residual.py`) retains its input/operator and limitations. ## Observed enclosure startup limits — 2026-09-24 The former static 200-sweep budget does not cover every valid scenario. Exact-input CUDA probes on the prescribed-flow enclosure identify both iteration-budget and float-update limits. At `nu*dt/h² = 3.2`, n64 dt=1/64 and n128 dt=1/256 require 272 and 280 sweeps to reach the unchanged target; their independent returned-field residuals are 9.43e-7 and 8.84e-7. The n128 dt=1/128 case has coefficient 6.4: its independent residual stalls at 1.27329e-6 through 2,400 sweeps because the remaining corrections round away when added to the float32 velocities. Double row accumulation is already used; these data identify a limitation of the former update, not a proof that every float32 solution must miss the target. The failure predates the latest format pull. Earlier n64 dt=1/256 enclosure screening has coefficient 0.8 and converges in 76 sweeps. The full verify-all catalog excludes this separate enclosure campaign. Pressure multigrid does not address this diffusion limit. At diagnosis time no production tolerance/cap or protocol change had been made; the expensive reference campaign remains paused pending validated solver and campaign evidence. See the [independent evidence and reusable probe] (unavailable local reference: `../../openfoam/compare/ENCLOSURE_N128_DIAGNOSTICS.md`). These are first-step diagnostics, not completed physical comparisons.