# 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/2515fae75250ee310a783c96057bc4b0a4fa9ee6/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.
