(vc_stratified_neutral_limit)= # Stratified-ABL Neutral-Limit Regression ```{admonition} Status: VALIDATED (neutral-limit regression PASSES on GPU) --- class: tip --- Run on GPU (RTX 3060, single precision, all six simulations). The regression **passes** on both the single block and the 2:1-refined (multiblock) configuration: the feature-inert `neutral_limit` run reproduces the feature-off `baseline` to the solver noise floor in both cases. Because the multiblock run matches its baseline to the same floor that the single-block run does, the inert feature composes across the refinement interface (F2C/C2F/border reconstruction) without introducing any discontinuity. See {ref}`Results `. This case makes no physics claim against any external reference - it is a **self-regression**: the feature-off path IS the reference. ``` ## Why this case matters This is the mandatory **neutral-limit regression** for the stratified-ABL feature - the single most important case in the validation ladder and the one that protects every other developer's work. A new physical capability (here the Monin-Obukhov stratified IBM ground wall model and the Boussinesq buoyancy coupling) must, with the feature **off or at its inert parameter**, recover the solver's pre-feature behaviour **exactly**. If the feature-off path has moved, the feature has silently changed unrelated physics, and nothing else in the ladder can be trusted until that is fixed. The stratified-ABL feature's own development case (`examples/mo_stability_validation/mo_stability.nassu.yaml`) checks the *differential* sign of the stability correction (unstable fuller than stable), but there was no committed case asserting that the **inert** setting is a true no-op. This case fills that gap, on both a single block and, crucially, across a 2:1 refinement interface. ## Physical description A minimal half-channel ABL-like box: a flat IBM ground floor (EqLog wall model) at $z = 1$ in a $64 \times 32 \times 64$ domain, periodic in $x$ (streamwise) and $y$ (spanwise), no-slip at the bottom, free-slip at the top. A streamwise body force $F_x$ drives the flow against the wall drag, LES Smagorinsky is on, and one coupling scalar `temperature` rides the shared DDF scalar path (advected and diffused, with a mild vertical gradient from a warm floor). All quantities are in **lattice units**; the setup is modelled directly on the stratified-ABL development case so the regression exercises the identical code path. ## The regression pair Two simulations that **must produce statistically identical results**: | Simulation | `mo_stability` | Buoyancy | Meaning | | --------------- | ----------------------- | ---------- | -------------------------------------- | | `baseline` | absent | `beta = 0` | pre-feature neutral path (feature OFF) | | `neutral_limit` | `surface_heat_flux = 0` | `beta = 0` | feature code path ACTIVE but inert | - In `baseline` the feature is **entirely off**: no `mo_stability` block, and the buoyancy is inert - $f_\mathrm{buoy} = -\rho_0\,\beta\,(\phi - \phi_\mathrm{ref})\,g$ is exactly zero because $\beta = 0$. The wall model is the plain EqLog log law; `temperature` is a passive tracer. - In `neutral_limit` the feature is **present but at its inert parameter**: `mo_stability` with `surface_heat_flux = 0` drives the Obukhov length $L \to \infty$, so $\zeta = z/L \to 0$ and the momentum stability function $\psi_m = 0$ - the neutral log law (the schema documents `surface_heat_flux = 0` as "recovers the neutral log law"). Buoyancy stays inert ($\beta = 0$). The `mo_stability` code path executes but must reproduce `baseline`. ## Multiblock variant The same pair (`baseline_mb`, `neutral_limit_mb`) is run across a **2:1 refinement slab**: a full $x$-$y$ band at $z \in [16, 32]$. This puts two $z$-normal coarse-fine interfaces directly in the path of the vertical temperature gradient, so the regression exercises **F2C** (fine->coarse), **C2F** (coarse->fine spatial + temporal interpolation) and the **same-level border population reconstruction / init-borders** path. This is the highest-value composition rung: it is exactly where Nassu's most damaging bugs have lived (a term correct in bulk collision but omitted from border reconstruction or the level-transfer rescale - e.g. the porous Darcy-force sawtooth, the forked-scalar C2F bug). The inert buoyancy force and the temperature field must stay **continuous across the interface, with no per-block sawtooth**. ## Validation ladder and composition matrix This case fills the entire **neutral-limit-regression row** of the stratified-ABL feature's composition matrix. LES, the `temperature` scalar and the IBM ground wall model are all present simultaneously in both the single-block and the multiblock cells, so every applicable cell of the row is covered by this one case: ``` | single-block | multiblock | +LES | +scalar | +IBM neutral limit (07) | reg | reg | reg | reg | reg ``` `reg` = neutral-limit regression, covered here (feature-off / inert recovers the pre-feature path to the solver noise floor). The `X` benchmark rungs of the ladder (canonical stratified references + acceptance criteria) live in the sibling cases 05 (`vc_stratified_street_canyon`) and 06 (`vc_stratified_building`); this case is the regression foundation they rest on. ## Numerical acceptance criterion The GPU solver is **not bit-reproducible run-to-run** (atomicAdd ordering, ~$10^{-6}$ relative in float32), so the regression validates **statistics, not instantaneous fields**, and proves parity the robust way - by comparing against the solver's own noise floor. Concretely, using the time-averaged (mean) profiles over $[10000, 20000]$ steps, $x$-$y$-averaged into $z$-profiles of $u(z)$, $\rho(z)$ and $\mathrm{temperature}(z)$: ```{math} \Delta_\mathrm{feature} = \big\| \overline{q}_{\,\mathrm{neutral\_limit}}(z) - \overline{q}_{\,\mathrm{baseline}}(z) \big\| \;\; \lesssim \;\; \Delta_\mathrm{noise} = \big\| \overline{q}_{\,\mathrm{baseline\_rerun}}(z) - \overline{q}_{\,\mathrm{baseline}}(z) \big\| \qquad (\sim 10^{-6}\ \text{relative}), ``` for each profiled quantity $q \in \{u, \rho, \mathrm{temperature}\}$. That is: **the neutral_limit-vs-baseline difference must be the same order as a baseline-vs-baseline rerun difference** (pure solver noise). The `baseline_rerun` / `baseline_mb_rerun` simulations exist solely to establish that noise floor within a single `nassu run` invocation. For the **multiblock** variant, additionally require the temperature (and hence the inert buoyancy) field to be **continuous across the $z = 16$ and $z = 32$ refinement interfaces** to the same noise floor - no per-block sawtooth or jump in the mean field straddling the interface. The regression **fails** if $\Delta_\mathrm{feature} \gg \Delta_\mathrm{noise}$ for any profiled quantity, or if a sawtooth appears at the multiblock interface: either means the (supposedly inert) feature code path has perturbed the pre-feature physics and must be fixed before any benchmark rung is trusted. ## Simulation setup All values are in lattice units (modelled on the stratified-ABL development case). Single-block level-0 grid; the multiblock variants add one refinement level over the mid slab. | Parameter | Value (lattice) | | ----------------------------- | -------------------------------------------------------------- | | Domain $(x, y, z)$ | $64 \times 32 \times 64$, `block_size` 8 | | Periodicity | $x$, $y$ periodic; $z$ walls (B / F) | | Bottom / top BC | RegularizedHWBB (no-slip) / RegularizedNeumannSlip (free-slip) | | Driving force $F_x$ | $1.7\times10^{-6}$ | | Relaxation time $\tau$ | 0.51 ($\nu = 3.33\times10^{-3}$, $\mathrm{Ma}$ well below 0.1) | | Fluid velocity set / operator | D3Q19 / RRBGK | | LES model | Smagorinsky $C_S = 0.17$ | | Ground wall model | IBM EqLog ($z_0 = 0.1$, `dist_ref` 5, `dist_shell` 1.5) | | Coupling scalar | `temperature` (D3Q7 / RRBGK, $D = 5\times10^{-3}$) | | Buoyancy | INERT ($\beta = 0 \Rightarrow f_\mathrm{buoy} = 0$) | | MO stability (neutral_limit) | `surface_heat_flux = 0` ($\Rightarrow$ neutral log law) | | Multiblock refinement | full $x$-$y$ slab at $z \in [16, 32]$, level 1 (2:1) | | Steps / stats window | 20000 / $[10000, 20000]$ (P5-tunable) | There is no external reference dataset; the `baseline` run **is** the reference (see `reference/README.md`). (results)= ## Results The comparison notebook (`07_stratified_neutral_limit.ipynb`) is executed against the GPU run and presents results as PLOTS (overlaid neutral_limit-vs-baseline profiles and a parity bar chart against the solver noise floor), never a bare table. Measured relative-L2 profile differences: | Quantity | Single block $\Delta_\mathrm{noise}$ / $\Delta_\mathrm{feature}$ | Multiblock $\Delta_\mathrm{noise}$ / $\Delta_\mathrm{feature}$ | | ----------- | ---------------------------------------------------------------- | -------------------------------------------------------------- | | $u$ | $5.5\times10^{-7}$ / $3.4\times10^{-7}$ | $1.1\times10^{-6}$ / $8.5\times10^{-7}$ | | $\rho$ | $3.0\times10^{-8}$ / $1.5\times10^{-8}$ | $2.6\times10^{-8}$ / $1.5\times10^{-8}$ | | temperature | $6.0\times10^{-7}$ / $3.0\times10^{-7}$ | $1.8\times10^{-7}$ / $1.8\times10^{-7}$ | For every quantity, in both topologies, $\Delta_\mathrm{feature} \leq \Delta_\mathrm{noise}$ - the feature-inert path differs from baseline by no more than a baseline-vs-baseline rerun does, i.e. by pure solver noise. The multiblock pair sits at the same floor as the single-block pair, so the refinement interface (F2C/C2F/border reconstruction) introduces no feature-induced discontinuity. The neutral-limit gate is met. (Table shown beneath its plots in the notebook, per the plots-not-tables convention.) ```{toctree} --- hidden: --- 07_stratified_neutral_limit.ipynb ```