← Explainer · Markdown · Source on GitHub
# Laminar backward-facing step The `backward-step` case compares separated laminar flow against a matching OpenFOAM Foundation 14 calculation. It is a numerical cross-code validation; it does not reproduce the Armaly experiment or the turbulent pitzDaily tutorial. ## Matched physical problem - Step height `h=1`; uniform inlet velocity `Uin=1`; kinematic viscosity `nu=0.01`. - Reynolds number is **`Re_h = Uin h / nu = 100`**. Inlet height is `h` and downstream height is `2h`. - Domain is `0 <= x <= 24`, `0 <= y <= 2`. Solid occupies `x < 4, y < 1`. - Inlet: `(u,v,w)=(1,0,0)` on the open upper half, zero pressure gradient. - Outlet: zero velocity gradient, fixed kinematic pressure zero. - Horizontal walls and step: stationary no-slip. No body force or turbulence model. - Start from rest and advance until the diagnostics have settled. - OpenFOAM uses a conformal Cartesian mesh and 2D `empty` spanwise boundaries. PolyCFD uses spanwise periodic copies of the same planar problem. Extra spanwise cells allow the existing three-dimensional multigrid hierarchy to coarsen. The step walls lie on grid planes, with equal spacing in all three directions. Geometry tests verify the exact fluid area at 8, 16 and 32 cells per step height. This case exercises static immersed walls, inflow, outflow, separation and pressure recovery. It does **not** establish accuracy for partially filled cells at an offset step, moving walls, or turbulent separation. The PolyCFD case uses `BlockedOnly`, static immersed-wall shear, and geometry-aware advection. The pressure solve must converge at every step (`RelTolerance=1e-7`). The pressure magnitude scan preserves isolated NaN/Infinity values so finite-field checks cannot silently overlook a bad cell. ## Run and export From the PolyCFD repository: ```bash dotnet run -c Release --project src/PolyCfd.Cli -- baseline record backward-step \ --scenario examples/scenarios/backward-step-refined/scenario.json --output-interval 200 \ --baseline output/validation/backward-step/baselines \ --sample-output output/validation/backward-step/n32-mc.json ``` Set `numerics.advection` to `semiLagrangian` for that comparison. `--viewer-ui` and VTU/HDF5 host options attach through the shared execution observers. Viscosity, inlet and step shape are fixed by the reference regime. Set `time.stepSeconds` explicitly and omit `time.adaptive`; adaptive steps are rejected for this reference protocol. Use `nx=12*ny` with even `ny` to preserve equal spacing and keep `x=4` and `y=1` on grid planes. Short runs can be useful diagnostics but fail the settled-flow requirement. ## Quantities and acceptance Final JSON samples contain spanwise-averaged cell-centred velocities interpolated at 40 common heights, `y=0.025, 0.075, ..., 1.975`, at `x-4=1,3,6,10`. Both codes use the first fluid row to estimate lower-wall kinematic shear `tau/rho = nu*u(y=dy/2)/(dy/2)`. Reattachment is the first negative-to-positive shear crossing after `x-4=0.25`, interpolated along the wall. Missing backflow or reattachment fails the comparison. This wall-shear estimate has finite-grid error; its refinement is checked with the reference. Pressure is sampled at `y=1.5`, `x=5..14`. Only differences from `p(x=5)` enter the accuracy check, so changing the pressure gauge cannot affect a result. `Cp` is kinematic pressure divided by `0.5*Uin^2`. Limits were fixed before evaluating PolyCFD: | Metric | Limit | |---|---:| | Reattachment relative error | 5% | | Combined U/V profile relative L2 error | 5% | | Wall-shear relative L2 error | 10% | | Pressure-difference Cp RMS error | 0.02 | | Relative cut-cell divergence, `max|div| min(dx,dy)/Uin` | `< 1e-4` | | Inlet/outlet flux mismatch divided by `Uin*h` | `< 1e-4` | | Maximum blocked-face velocity | `< 1e-6` | | Reattachment, pressure recovery and profile-norm range in final 20 time units | `< 0.2%` | The settled-flow check requires at least three samples spanning at least ten time units in that final window. Finite fields and conservation alone are insufficient for physical accuracy. The comparison script in the OpenFOAM repository is `compare/compare_backward_step.py`; `--check-reference` in PolyCFD applies the same limits to the embedded independently calculated reference. ## Accepted configuration and reference The OpenFOAM reference uses 64 cells per step height and has reattachment `x_r/h=4.858952`. The 32-to-64 refinement changes reattachment by 0.987%, velocity profiles by 0.372%, wall shear by 2.479%, and pressure-difference Cp RMS by 0.001676. All pass the reference limits (1%, 1%, 3%, 0.005 respectively). A restart of the settled fine solution from t=160 to t=200 with dt reduced from 0.1 to 0.05 changes the relative metrics by less than 0.001%. The final 20-unit settling check also passes. The embedded `ReferenceData/backward-step-openfoam.json` contains the samples, reference checks, and physical provenance. The accepted PolyCFD configuration is **384x32x32, MacCormack, multigrid, dt=0.05, t=120** (16 cells per step height). Measured errors against that reference: | Metric | PolyCFD result | Error | Limit | |---|---:|---:|---:| | Reattachment x_r/h | 4.929885 | 1.46% | 5% | | Combined velocity profiles | — | 0.575% | 5% | | Lower-wall shear | — | 4.00% | 10% | | Pressure-difference Cp RMS | — | 0.00666 | 0.02 | Flux mismatch is `1.2e-9` of inlet flow, relative cut-cell divergence is `3.2e-7`, and blocked-face velocity is zero. The settling check passes. `verify-all` always runs this accepted MacCormack configuration, even when no local backward-step CSV exists. It requires pressure convergence, finite fields, conservation, settling, and every OpenFOAM accuracy limit. Its elapsed time and step timings join the same configurable performance gate as the other cases. The embedded reference makes this check self-contained; OpenFOAM is only needed to regenerate the independent reference. ```bash # Run the accepted check directly and optionally view it. dotnet run -c Release --project src/PolyCfd.Cli -- baseline record backward-step \ --scenario examples/scenarios/backward-step-reference/scenario.json --check-reference --sample-output output/backward-step.json # Run the full correctness suite and explicitly accept its new case coverage/timings. dotnet run -c Release --project src/PolyCfd.Cli -- verify-all --suite quick --backend cuda --output output/validation/checks --record-performance --performance-baseline output/references/performance-raw.json ``` The same coarse grid with SemiLagrangian settles and conserves flow but **fails** the independent physical accuracy checks. It is not the mandatory regression configuration. Passing this benchmark supports laminar, stationary, grid-aligned step flow at the specified conditions; it is not a blanket validation of other advection/grid choices, turbulence, or moving geometry. ## Additional grid/advection comparison The independent OpenFOAM runs used 16, 32, and 64 cells per step height. The PolyCFD runs below all started from rest and passed the settling/conservation checks; only the MacCormack configurations passed all independent accuracy limits. | PolyCFD grid / scheme / dt | Reattachment error | Velocity L2 | Wall-shear L2 | Pressure Cp RMS | Accuracy | |---|---:|---:|---:|---:|---| | 384x32x32 / SemiLagrangian / 0.05 | 9.94% | 5.38% | 15.50% | 0.05076 | FAIL | | 384x32x32 / MacCormack / 0.05 | 1.46% | 0.575% | 4.00% | 0.00666 | PASS | | 768x64x32 / MacCormack / 0.025 | 1.70% | 0.151% | 5.47% | 0.00117 | PASS | The refined MacCormack run reaches x_r/h=4.941533. Profile and pressure errors improve, while reattachment and wall-shear errors do not improve monotonically. These measurements establish agreement within the stated tolerances; they do not establish an asymptotic grid-convergence rate for PolyCFD. Both grid spacing and time step change between the two MacCormack runs. The expanded full suite passed 12/12 and recorded its performance reference. The step contributed 202.61 s elapsed and 82.76 ms median solver-step time on the RTX 3080; [performance validation](/docs/PERFORMANCE_VALIDATION) records the audit against the previous reference. A separate [OpenFOAM/PolyCFD performance comparison](https://github.com/hankbeasley/polycfd/blob/18102808d7066ed97d8908d66755a68df8d0516e/docs/BACKWARD_STEP_PERFORMANCE.md) times three fresh runs of each accepted configuration at the same in-plane resolution, dt and final time. It includes OpenFOAM serial and eight-rank MPI results, verifies physical accuracy for every timed run, and distinguishes OpenFOAM's 2D mesh from PolyCFD's 32 periodic spanwise layers.