From ba88041beccc8de778a205e429c2da28405e997b Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 28 Jun 2026 12:28:14 +0200 Subject: [PATCH 01/22] Add higher-order horizontal pressure gradient design doc --- components/omega/doc/design/PGrad.md | 28 +- components/omega/doc/design/PGradHighOrder.md | 558 ++++++++++++++++++ components/omega/doc/index.md | 1 + 3 files changed, 566 insertions(+), 21 deletions(-) create mode 100644 components/omega/doc/design/PGradHighOrder.md diff --git a/components/omega/doc/design/PGrad.md b/components/omega/doc/design/PGrad.md index b263bb2e37a4..8deb976d40aa 100644 --- a/components/omega/doc/design/PGrad.md +++ b/components/omega/doc/design/PGrad.md @@ -90,22 +90,8 @@ $$ $$ ### 3.2 High-order Pressure Gradient -The high order pressure gradient will be based on the {ref}`full volume integral form ` of the geopotential and pressure terms: -$$ -T^p &= - \int_A \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \, \left( \nabla \left<\Phi\right> \right) \, d\tilde{z} \, dA \\ -& - \int_{\partial A} \left( \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \left(\left< \alpha \right> \left

+ \left<\alpha^\prime p^\prime\right> \right) \, d\tilde{z} \right) dl \\ -& - \int_A \rho_0 \left[ \left< \alpha \right> \left

+ \left<\alpha^\prime \left(p \nabla \tilde{z}_k^{\text{top}}\right)^\prime\right> \right]_{\tilde{z} = \tilde{z}_k^{\text{top}}} \, dA \\ -& + \int_A \rho_0 \left[ \left< \alpha \right> \left

+ \left<\alpha^\prime \left(p \nabla \tilde{z}_k^{\text{bot}}\right)^\prime\right> \right]_{\tilde{z} = \tilde{z}_k^{\text{bot}}} \, dA. -$$ -To obtain the expression that will be used, we neglect the turbulent correlations and drop the Reynold's average notation for single variables: -$$ -T^p &= - \int_A \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \, \left( \nabla \Phi \right) \, d\tilde{z} \, dA \\ -& - \int_{\partial A} \left( \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \left(\alpha p \right) \, d\tilde{z} \right) dl \\ -& - \int_A \rho_0 \left[ \alpha \left

\right]_{\tilde{z} = \tilde{z}_k^{\text{top}}} \, dA \\ -& + \int_A \rho_0 \left[ \alpha \left

\right]_{\tilde{z} = \tilde{z}_k^{\text{bot}}} \, dA. -$$ -These volume and area integrals will be computed using quadrature to account for the variability of $\alpha$ with the reconstructed values of temperature, salinity, and pressure at the quadrature points. -The complete details for the high-order pressure gradient will be the subject of a future design document. +The high order pressure gradient will be based on the {ref}`full volume integral form ` of the geopotential and pressure terms, evaluating the side-wall integral of $\alpha p$ together with the sloping-interface metric terms by quadrature and accounting for the variability of $\alpha$ with reconstructed temperature, salinity, and pressure. +The complete design — including the reference-state equation-of-state expansion that bounds TEOS-10 cost, the mean-preserving reconstructions, and the discrete hydrostatic consistency property that keeps thin, steeply sloped layers robust — is given in the {ref}`Higher-Order Horizontal Pressure Gradient ` design document. %### 3.3 Barotropic Pressure Gradient % @@ -162,8 +148,8 @@ class PressureGrad{ // Instances of functors PressureGradCentered CenteredPGrad; - PressureGradHighOrder HighOrderPGrad1; // To be implemented later - PressureGradHighOrder HighOrderPGrad2; // Multiple high order options are likely in the future + PressureGradHighOrder HighOrderPGrad; // high-order finite-volume scheme (see PGradHighOrder.md) + // Additional high-order variants may be added in the future // Pressure gradient choice from config PressureGradType PressureGradChoice; @@ -187,9 +173,9 @@ The user will select a pressure gradient option at runtime in the input yaml fil An `enum class` will be used to specify options for the pressure gradient used for an Omega simulation: ```c++ enum class PressureGradType{ - Centered, - HighOrder1, - HighOrder2 + Centered, // 2nd-order Montgomery scheme (this document) + FiniteVolume // high-order finite-volume scheme (see PGradHighOrder.md) + // , // additional high-order option, added when implemented } ``` ### 4.2 Methods diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md new file mode 100644 index 000000000000..1ceb6b4931bb --- /dev/null +++ b/components/omega/doc/design/PGradHighOrder.md @@ -0,0 +1,558 @@ +(omega-design-pressure-grad-high-order)= +# Higher-Order Horizontal Pressure Gradient + +**Table of Contents** +1. [Overview](#1-overview) +2. [Requirements](#2-requirements) +3. [Algorithmic Formulation](#3-algorithmic-formulation) +4. [Design](#4-design) +5. [Verification and Testing](#5-verification-and-testing) + +## 1 Overview + +This document specifies a higher-order discretization of the horizontal pressure +gradient force (PGF) in Omega's momentum equation. It is the "future design document" +promised in {ref}`Pressure Gradient ` (§2.3, §3.2), +which commits Omega to a high-order option "similar to +[Adcroft et al. 2008](https://doi.org/10.1016/j.ocemod.2008.02.001)" but defers the +details. The existing centered, second-order Montgomery-potential scheme +(`PressureGradCentered`) remains the default and the reference implementation; +this design adds the high-order option that the `PressureGrad` class and its +`PressureGradType` enum already anticipate (the placeholder high-order entry, named +`FiniteVolume` here; see §4.1.1). + +The PGF is the single most error-sensitive term in a layered ocean model. In the +non-Boussinesq, hydrostatic momentum equation +({ref}`layered momentum equation `) the horizontal acceleration +from pressure and gravity is + +$$ +-\left(\alpha \nabla p + \nabla \Phi \right)_{e,k}, +$$ + +in which $\alpha\nabla p$ and $\nabla\Phi = g\nabla z + \nabla(\phi_{TP}+\phi_{SAL})$ +are individually large and nearly cancel. The residual is the dynamically relevant +baroclinic signal. When layers are tilted in geometric height — as they always are in +a general ALE coordinate, and severely so for thin, steeply sloped layers near shelf +breaks and (future) ice-shelf cavities — truncation error in this cancellation appears +directly as spurious velocity (the classic "pressure gradient error"). Experience with +MPAS-Ocean and published results for other models show that an accurate PGF goes a long +way toward making thin, steeply sloped layers usable. + +This design is shaped by three competing principles: + +1. **Accuracy.** The PGF must be markedly more accurate than the centered scheme, + especially in the presence of sloping layers. +2. **Cost.** Omega uses TEOS-10 (a 75-term polynomial) for specific volume $\alpha$. + Naively evaluating $\alpha$ at every quadrature point would dominate run time. The + design must bound TEOS-10 evaluations. +3. **General ALE coordinate.** The scheme must remain accurate and stable for thin, + steeply sloped layers. The PGF alone cannot guarantee this, but it is a necessary + ingredient. + +A guiding choice that follows from principles 2 and 3 is that the relevant metric of +success is **low absolute PGF error at affordable (coarse) resolution**, not high +asymptotic order of convergence. Omega will be strongly resource-limited in how fine a +mesh it can run, so a scheme whose error is small at coarse resolution is preferred over +one with a steeper convergence slope but larger coarse-resolution error. Order of +accuracy is configurable and a fourth-order variant is targeted, but it is a means to the +end of coarse-resolution accuracy, not the objective itself. + +## 2 Requirements + +### 2.1 Requirement: Higher accuracy than the centered scheme at affordable resolution + +The high-order PGF must produce substantially lower absolute error than +`PressureGradCentered` at the coarse-to-moderate resolutions Omega can afford to run, +for representative stratified columns with horizontal gradients of temperature, salinity, +surface pressure, and coordinate slope. Convergence rate is a secondary diagnostic, not +the primary acceptance criterion. + +### 2.2 Requirement: Bounded TEOS-10 cost + +The number of TEOS-10 specific-volume evaluations performed by the PGF must be +independent of the quadrature order and bounded at approximately one evaluation (plus its +first derivatives) per cell per layer per time step — comparable to the cost Omega already +pays to compute the `Eos::SpecVol` field. The scheme must not require evaluating the full +TEOS-10 polynomial at each quadrature point, nor integrating the TEOS-10 polynomial +itself semi-analytically. + +### 2.3 Requirement: Robustness for thin, steeply sloped layers via discrete hydrostatic consistency + +The scheme must suppress spurious pressure-gradient accelerations when layers are thin and +steeply sloped in geometric height. The primary guarantee is **discrete hydrostatic +consistency**: for a physically resting ocean with horizontally uniform conservative +temperature and absolute salinity but coordinate surfaces tilted arbitrarily, the scheme +must return **exactly zero** horizontal PGF, to machine precision, regardless of the vertical +profile or the steepness of the tilt. This property is *structural* — it depends only on the +construction of the discretization, not on any background reference state — and therefore +holds uniformly across the global ocean. The residual error for non-uniform $T$/$S$ is then +genuine truncation error, reduced by the high-order, mean-preserving reconstruction (§3.4) +and by evaluating the equation of state consistently, including its pressure dependence +(compressibility $\alpha_p$), so that thermobaric effects under tilted layers are not aliased +into spurious flow. + +### 2.4 Requirement: Consistency with the rest of the model state + +The reconstructions used by the PGF must be **mean-preserving** (reproduce each layer's +prognostic mean $\Theta_{i,k}$, $S_{i,k}$ exactly) and **anchored to `VertCoord`** +(use the model's diagnostic interface pressures and geometric heights). The PGF must +therefore see the same layer-mean state the tracer and thickness equations evolve, and the +same hydrostatic pressure the rest of the model uses. It may assume a smoother sub-layer +profile for integration, but it must not introduce a second, inconsistent representation +of $\Theta$, $S$, $p$, or $z$. + +### 2.5 Requirement: Runtime-selectable, backward-compatible option + +The high-order scheme must be selectable at runtime through the existing `PressureGrad` +configuration group and `PressureGradType` enum, leaving `Centered` as the default. Its +sub-options (horizontal reconstruction order, vertical-reconstruction mode, quadrature) must +be configurable, and the centered scheme must be recoverable as the lowest-order limit. + +### 2.6 Desired: Extensibility to sixth order and to tidal/geoid geopotential terms + +The framework should accommodate a future higher-order variant (e.g. sixth order, added to +the `PressureGradType` enum when implemented) and the +tidal-potential and self-attraction-and-loading contributions to the geopotential +(supplied by `VertCoord`; see {ref}`Pressure Gradient ` +§2.4), without restructuring. + +## 3 Algorithmic Formulation + +### 3.1 Continuous target form + +The high-order PGF starts from the layer-integrated, finite-volume form of the pressure +and geopotential terms derived in +{ref}`the governing equations ` +(the {ref}`full volume-integral form `). Neglecting the +turbulent correlations and dropping the resolved-component notation, the layer tendency is +({ref}`Pressure Gradient ` §3.2): + +$$ +T^p &= - \int_A \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \, \left( \nabla \Phi \right) \, d\tilde{z} \, dA \\ +& - \int_{\partial A} \left( \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \left(\alpha p \right) \, d\tilde{z} \right) dl \\ +& - \int_A \rho_0 \left[ \alpha \, p \, \nabla \tilde{z}_k^{\text{top}} \right]_{\tilde{z} = \tilde{z}_k^{\text{top}}} \, dA \\ +& + \int_A \rho_0 \left[ \alpha \, p \, \nabla \tilde{z}_k^{\text{bot}} \right]_{\tilde{z} = \tilde{z}_k^{\text{bot}}} \, dA. +$$ (ho-target) + +The four terms are: the geopotential (gravity) body force integrated over the layer +volume; the side-wall integral of $\alpha p$ (the pressure traction on the cell faces); and +two metric terms accounting for the pressure traction on the sloping top and bottom layer +interfaces. This is the Adcroft et al. (2008) finite-volume route — the net pressure force +on each control volume is obtained by integrating in-situ pressure over the faces, rather +than by forming the pointwise product $\alpha\nabla p$. We adopt this form because it +matches Omega's non-Boussinesq layer-integral momentum equation exactly and is the form +MOM6 uses successfully for the same problem. + +Adcroft et al. (2008) were targeting an isopycnal model (constant density within a layer) +and the analytically integrable Wright equation of state. Omega differs on both counts: +density varies within a layer in a general ALE coordinate, and TEOS-10 is far more +expensive and not practical to integrate in closed form. The remainder of this section +adapts the form [](#ho-target) to those two realities. + +### 3.2 A key simplification: pressure is linear in pseudo-height + +Omega's vertical coordinate is pseudo-height, +$\tilde z \equiv -p/(\rho_0 g)$ ({ref}`omega-design-governing-eqns-omega1` §5). Pressure is +therefore, by definition, an **exactly linear function of $\tilde z$**: + +$$ +p(\tilde z) = p_{k}^{\text{top}} - \rho_0 g \left( \tilde z - \tilde z_k^{\text{top}} \right), +\qquad \tilde z_k^{\text{bot}} \le \tilde z \le \tilde z_k^{\text{top}}, +$$ (p-linear) + +anchored at the interface pressures $p_k^{\text{top}}$, $p_k^{\text{bot}}$ that `VertCoord` +already provides (`PressureInterface`). No reconstruction of $p$ within a layer is needed +or permitted — using [](#p-linear) is exactly the `VertCoord` anchoring required by +Requirement 2.4. Consequently, the only within-layer nonlinearity in the integrand +$\alpha p$ comes from the variation of $\alpha$ through the reconstructed $\Theta$ and $S$. + +### 3.3 Reference-state expansion of the equation of state + +This is the core device that satisfies Requirement 2.2. We **never integrate TEOS-10**. +Instead, for each cell $i$ and layer $k$ we expand $\alpha$ in a Taylor series about the +layer's reference state $(\Theta_{i,k}, S_{i,k}, p_{i,k}^{\text{mid}})$, where +$\Theta_{i,k}$ and $S_{i,k}$ are the prognostic layer means and $p_{i,k}^{\text{mid}}$ is +the mid-layer pressure from `VertCoord` (`PressureMid`): + +$$ +\alpha(\Theta, S, p) \approx \alpha_{0} + \alpha_{\Theta}\,(\Theta - \Theta_{i,k}) + \alpha_{S}\,(S - S_{i,k}) + \alpha_{p}\,(p - p_{i,k}^{\text{mid}}), +$$ (alpha-taylor) + +with + +$$ +\alpha_0 = \alpha(\Theta_{i,k}, S_{i,k}, p_{i,k}^{\text{mid}}), \quad +\alpha_\Theta = \left.\frac{\partial \alpha}{\partial \Theta}\right|_0, \quad +\alpha_S = \left.\frac{\partial \alpha}{\partial S}\right|_0, \quad +\alpha_p = \left.\frac{\partial \alpha}{\partial p}\right|_0. +$$ (alpha-derivs) + +The four coefficients in [](#alpha-derivs) are obtained from a **single** evaluation of the +TEOS-10 polynomial, since the first derivatives reuse the same polynomial coefficients (the +same quantities computed by `gsw.specvol_first_derivatives`, which the Polaris reference +solution already uses). Indeed $\alpha_0$ is exactly the `Eos::SpecVol` field Omega already +computes, so only the three derivative fields are additional work. + +The first-order expansion [](#alpha-taylor) is the default. A second-order expansion (adding +$\alpha_{\Theta\Theta}$, $\alpha_{SS}$, $\alpha_{\Theta S}$, $\alpha_{pp}$, …) is an option +where stratification is strong; it adds derivative evaluations but still no in-integral +TEOS-10 calls. + +Because $\Theta$, $S$ are reconstructed as low-order polynomials in $\tilde z$ (and across +edges) and $p$ is linear in $\tilde z$ by [](#p-linear), the expansion [](#alpha-taylor) +makes $\alpha$ a **low-order polynomial** whose product with $p$ integrates **exactly** by a +low-order Gauss rule. The semi-analytic integration is performed on the cheap Taylor model, +not on TEOS-10 — directly resolving the feasibility and cost concerns with applying +Adcroft-style analytic integration to TEOS-10. + +### 3.4 Mean-preserving vertical reconstruction + +Within layer $k$ of column $i$ we reconstruct the conservative temperature and absolute +salinity as + +$$ +\Theta(\tilde z) = \Theta_{i,k} + \Theta'_{i,k}(\tilde z), \qquad +S(\tilde z) = S_{i,k} + S'_{i,k}(\tilde z), +$$ (vert-recon) + +where $\Theta'_{i,k}$, $S'_{i,k}$ are parabolic (PPM-style) deviations built from the +neighboring layer means and constrained to **integrate to zero over the layer** +($\int_{\tilde z_k^{\text{bot}}}^{\tilde z_k^{\text{top}}} \Theta'_{i,k}\, d\tilde z = 0$). +This mean-preserving property (Requirement 2.4) guarantees the PGF uses the same layer-mean +state as the rest of the model; the reconstruction only supplies the smoother sub-layer +shape needed to integrate $\alpha p$ to high order. The "constant density within a layer" +assumption of an isopycnal model is recovered exactly by the degenerate choice +$\Theta'_{i,k} = S'_{i,k} = 0$, which is available as the cheapest configuration. + +### 3.5 Analytic layer integral of the side-wall term + +Combining [](#p-linear), [](#alpha-taylor), and [](#vert-recon), the side-wall integrand +$\alpha p$ in a single column/layer is a polynomial in $\tilde z$: with first-order $\alpha$ +and parabolic $\Theta', S'$, $\alpha$ is parabolic and $p$ is linear, so $\alpha p$ is cubic +and is integrated **exactly** by a two-point Gauss-Legendre rule over the layer: + +$$ +\Pi_{i,k} \equiv \int_{\tilde z_k^{\text{bot}}}^{\tilde z_k^{\text{top}}} \alpha\, p \; d\tilde z +\;=\; \tilde h_{i,k} \sum_{q} w_q \, \alpha\!\left(\tilde z_q\right) p\!\left(\tilde z_q\right), +$$ (sidewall-int) + +with Gauss nodes $\tilde z_q$ and weights $w_q$ on the layer, and $\alpha(\tilde z_q)$, +$p(\tilde z_q)$ from [](#alpha-taylor) and [](#p-linear). No TEOS-10 calls occur inside the +sum. The quadrature order is configurable and is matched to the reconstruction so the +integral is exact for the reconstructed polynomial. + +### 3.6 Horizontal reconstruction and the edge gradient + +The discrete tendency lives at edge $e$ and is the edge-normal projection of the PGF. The +side-wall line integral $\int_{\partial A}(\cdots)\,dl$ in [](#ho-target) becomes, on the +TRiSK C-grid, the difference of the two adjacent columns' face contributions across the +edge, divided by the cell-center distance $d_e$: + +$$ +\left[\nabla_n \Pi\right]_{e,k} = \frac{1}{d_e}\sum_{i \in CE(e)} -n_{e,i}\, \widehat{\Pi}_{i,k}, +$$ (edge-grad) + +where $\widehat\Pi_{i,k}$ is the column integral [](#sidewall-int) reconstructed to the edge. +To reach fourth order, $\Theta$, $S$ (and hence $\alpha$ and $\Pi$) are reconstructed from +cell centers to the edge with a **cubic** reconstruction consistent with the TRiSK edge +stencils used elsewhere in Omega (the same neighborhood used for high-order tracer +reconstruction; cf. the third-order interface reconstruction noted at +{ref}`omega-design-governing-eqns-omega1` §10, White & Adcroft 2008). The lowest-order limit +(two-cell, centered) reproduces the operator already used by `PressureGradCentered`. We do +**not** assume anything constant across the edge — the horizontal density contrast between +adjacent columns is fully reconstructed. + +### 3.7 Discrete hydrostatic consistency (the steep-layer robustness property) + +Robustness for thin, steeply sloped layers (Requirement 2.3) is delivered not by subtracting +a background profile but by a structural property of the discretization. We require **discrete +hydrostatic consistency**: + +> When $\Theta$ and $S$ are horizontally uniform — a physically resting, flat-isopycnal ocean +> — the discrete horizontal PGF at every edge and layer must be **exactly zero, to machine +> precision**, for arbitrary tilt of the coordinate surfaces $\tilde z_k^{\text{top}}$, +> $\tilde z_k^{\text{bot}}$ between the two columns and for an arbitrary vertical profile. + +The finite-volume form [](#ho-target) is constructed to satisfy this exactly: with $\Theta$, +$S$ horizontally uniform, $\alpha(\Theta,S,p)$ is the same function of pressure in both +columns, so the side-wall integral [](#sidewall-int) and the sloping-interface metric terms +(§3.8) combine to the net pressure force on a control volume with horizontally uniform density, +which is balanced exactly by the geopotential term. The cancellation must be enforced +*discretely*: the pressure term and the geopotential term must share the same interface +locations (from `VertCoord`), the same edge reconstruction [](#edge-grad), and the same +quadrature nodes, so that their difference vanishes term by term rather than only in the +continuum limit. + +This property is the reason the scheme is robust: it is *reference-free* (it depends on no +background state, so it holds identically in the warm pool, at the poles, and over a seamount) +and it is directly *testable* (§5.1, §5.2). It strictly supersedes a Shchepetkin–McWilliams +(2003)-style reference-profile subtraction, which only approximates this cancellation to the +extent the local column resembles a global reference and therefore degrades precisely in the +strong-gradient, steep-layer regions of interest. For non-uniform $\Theta$/$S$ the remaining +error is genuine truncation error, controlled by the reconstruction order (§3.4, §3.6) and by +the consistent treatment of compressibility $\alpha_p$ (§3.3); no formulation removes it, and +a reference subtraction would not help. Because the consistency cancellation is exact in +exact arithmetic, the only residual in the resting state is round-off, which is at the +machine-precision floor in double precision; single-precision builds (`OMEGA_SINGLE_PRECISION`) +may expose a small floor, addressed if needed as a local implementation-level conditioning +choice rather than a physics option. + +### 3.8 Geopotential and metric terms + +The geopotential body-force term (first line of [](#ho-target)) is +$g\,\nabla z + \nabla(\phi_{TP}+\phi_{SAL})$. The geometric height $z$ and geopotential are +provided by `VertCoord` (`GeomZMid`/`GeomZInterface`, `GeopotentialMid`; computed via +{ref}`omega-design-governing-eqns-omega1` Eqs. discrete-z and the geopotential relation). +Its layer average and edge-normal gradient are evaluated with the same high-order edge +reconstruction [](#edge-grad). The tidal-potential and self-attraction-and-loading +contributions enter through `VertCoord` and are differenced identically (Requirement 2.6); +they are zero in early Omega versions. + +The two metric terms (third and fourth lines of [](#ho-target)) use the **same** edge-normal +operator to evaluate the interface slopes $\nabla \tilde z_k^{\text{top}}$, +$\nabla \tilde z_k^{\text{bot}}$, with $\alpha\,p$ evaluated at the interfaces from +[](#alpha-taylor) and [](#p-linear). These terms vanish for flat interfaces and supply the +leading correction for sloping layers; together with the side-wall integral [](#sidewall-int) +they form a discretely consistent finite-volume pressure force on the layer control volume. + +### 3.9 Reduction to the centered scheme + +As a consistency check, the high-order scheme collapses to the implemented +`PressureGradCentered` form +($T^p_{e,k} = -\nabla M + \tfrac12(p_0+p_1)\nabla\alpha - \nabla\Phi$, with +$M = \alpha p + g z$) in the joint limit of: constant in-layer reconstruction +($\Theta' = S' = 0$, §3.4), midpoint quadrature in place of [](#sidewall-int), and two-cell +centered horizontal differencing (§3.6). This guarantees the new code reproduces the existing +scheme in its lowest-order configuration and provides a direct path for regression testing. + +### 3.10 Per-step algorithm summary + +1. From `VertCoord`: read `PressureInterface`, `PressureMid`, `GeomZInterface`/`GeomZMid`, + geopotential, and interface pseudo-heights (already computed diagnostically each step). +2. Per cell-layer: obtain $\alpha_0$ (= existing `Eos::SpecVol`) and the derivatives + $\alpha_\Theta, \alpha_S, \alpha_p$ from one TEOS-10 evaluation ([](#alpha-derivs)). +3. Per cell-layer: build mean-preserving PPM deviations $\Theta', S'$ ([](#vert-recon)). +4. Per edge-layer: reconstruct edge quantities (cubic, §3.6) using interface locations and + quadrature nodes shared by the pressure and geopotential terms (the discrete hydrostatic + consistency requirement, §3.7); evaluate the analytic layer integral [](#sidewall-int), + the geopotential gradient, and the metric terms (§3.8); assemble $T^p_{e,k}$ and accumulate + into the tendency with `EdgeMask`. + +## 4 Design + +The high-order scheme extends the existing `PressureGrad` class in +`components/omega/src/ocn/PGrad.{h,cpp}`. The class manager, creation/retrieval/removal +methods, named-instance map, and dispatch logic are unchanged; the work is to flesh out the +`PressureGradHighOrder` functor (currently a no-op placeholder) and to widen the inputs the +manager hands to it. + +### 4.1 Data types and parameters + +#### 4.1.1 Parameters + +Configuration lives under the existing `PressureGrad` YAML group. The `PressureGradType` +enum (PGrad.h:22) is updated to give the high-order scheme a descriptive name and to drop +the unimplemented second placeholder, leaving a commented stub for a future variant: + +```c++ +enum class PressureGradType { + Centered, // existing 2nd-order Montgomery scheme + FiniteVolume // high-order finite-volume analytic-integration scheme (this design) + // , // e.g. a 6th-order option, added when implemented +}; +``` + +New sub-options for the high-order scheme: + +```yaml + PressureGrad: + PressureGradType: 'FiniteVolume' # Centered | FiniteVolume + ReconstructionOrder: 4 # horizontal cell->edge order (2 = centered limit) + VerticalReconstruction: 'ppm' # 'constant' (isopycnal limit) | 'ppm' + QuadraturePoints: 2 # per-layer Gauss points for the side-wall integral +``` + +The fourth-order target is `ReconstructionOrder: 4` with parabolic (`ppm`) vertical +reconstruction. The centered scheme is recovered by `ReconstructionOrder: 2` and +`VerticalReconstruction: 'constant'` (§3.9). + +#### 4.1.2 New EOS support + +`PressureGradHighOrder` needs $\alpha$ together with its first derivatives. The `Eos` class +(Eos.h) currently exposes `computeSpecVol`, `computeSpecVolDisp`, and +`computeBruntVaisalaFreqSq`, but no specific-volume derivatives. This design adds one method +and three device fields: + +```c++ +// New on the Eos class +Array2DReal SpecVolDThetaCons; ///< d(alpha)/d(ConservTemp) at cell centers +Array2DReal SpecVolDSalt; ///< d(alpha)/d(AbsSalinity) at cell centers +Array2DReal SpecVolDPressure; ///< d(alpha)/d(Pressure) at cell centers + +/// Compute specific volume AND its first derivatives in one TEOS-10 pass +void computeSpecVolAndDerivs(const Array2DReal &ConservTemp, + const Array2DReal &AbsSalinity, + const Array2DReal &Pressure); +``` + +The TEOS-10 derivatives reuse the polynomial coefficients already assembled inside the +`Teos10Eos` functor (`calcPCoeffs`/`calcDelta`), so the marginal cost over `computeSpecVol` +is the derivative arithmetic only (Requirement 2.2). The linear and constant EOS options +supply trivial analytic derivatives. + +#### 4.1.3 `PressureGradHighOrder` functor + +The functor mirrors `PressureGradCentered` (cached mesh/coordinate arrays, `Enabled` flag, +`chunkStart`/`chunkLength` vertical iteration) but takes the additional reconstruction and +EOS-derivative inputs. Its `operator()` signature is widened from the placeholder to: + +```c++ +KOKKOS_FUNCTION void operator()(const Array2DReal &Tend, I4 IEdge, I4 KChunk, + const Array2DReal &PressureMid, + const Array2DReal &PressureInterface, + const Array2DReal &GeomZInterface, + const Array1DReal &TidalPotential, + const Array1DReal &SelfAttractionLoading, + const Array2DReal &SpecVol, + const Array2DReal &ConservTemp, // new + const Array2DReal &AbsSalinity, // new + const Array2DReal &SpecVolDThetaCons, // new + const Array2DReal &SpecVolDSalt, // new + const Array2DReal &SpecVolDPressure) // new + const; +``` + +(The existing centered signature is unchanged.) Additional cached members hold the cubic +edge-reconstruction stencil and weights. The functor implements §3.3–§3.8 per edge and +vertical chunk — sharing interface locations and quadrature nodes between the pressure and +geopotential terms to satisfy discrete hydrostatic consistency (§3.7) — accumulating into +`Tend` with `EdgeMask`, exactly as the centered functor does. + +### 4.2 Methods + +`PressureGrad::computePressureGrad` keeps its role of selecting the configured option, but +its input list grows so the high-order branch can reach $\Theta$, $S$, and the EOS +derivatives. The signature becomes: + +```c++ +void computePressureGrad(Array2DReal &Tend, const Array2DReal &PressureMid, + const Array2DReal &PressureInterface, + const Array2DReal &SpecVol, + const Array2DReal &GeomZInterface, + const Array2DReal &PseudoThick, + const Array2DReal &ConservTemp, // new + const Array2DReal &AbsSalinity, // new + const Eos *EqState) const; // new: derivative fields +``` + +The `Centered` branch ignores the new arguments and is byte-for-byte unchanged; the +`FiniteVolume` branch dispatches to `PressureGradHighOrder` through the same +`parallelForOuter`/`parallelForInner` team pattern used today (PGrad.cpp). The call site in +`Tendencies.cpp` is updated to pass $\Theta$, $S$ (from the tracer state) and the `Eos` +instance, which it already references for `SpecVol`. + +Creation, retrieval, and removal (`init`, `create`, `get`, `getDefault`, `clear`, `erase`) +are unchanged. The high-order constructor additionally caches the reconstruction stencil and +quadrature weights from config. + +### 4.3 Consistency and follow-up work + +The high-order PGF is deliberately more accurate in the vertical than the rest of Omega's +layer-mean operators. This is sanctioned by {ref}`omega-design-governing-eqns-omega1` §9, +which singles out the PGF as **the** exception to the piecewise-constant assumption ("we will +ignore most of these [within-layer deviation] terms in Omega. The exception is the pressure +gradient force … appropriate for the *simple* pressure gradient force targeted for *early* +versions of Omega. This assumption will be revisited at a later date."). The mean-preserving, +`VertCoord`-anchored constraints (Requirement 2.4) keep the PGF consistent with the model +state at the layer-mean level. For completeness, the following terms would need higher-order +vertical treatment to make the **whole** model consistent with this PGF; they are explicitly +out of scope here and flagged as follow-up: + +- **Vertical remapping and advection** ({ref}`omega-design-vert-adv` and the ALE + remap): a mean-preserving PPM remap consistent with §3.4. +- **EOS evaluation point**: buoyancy and $N^2$ ({ref}`omega-design-eos`) are currently + evaluated at layer mid; consistency with the reconstructed profile would evaluate them on + the same reconstruction. +- **Dropped within-layer products** $\overline{\delta\varphi\,\delta u}$ in the tracer and + momentum equations ({ref}`omega-design-governing-eqns-omega1` §9), which become non-negligible + only at much higher resolution. + +## 5 Verification and Testing + +Testing reuses and extends the Polaris `horiz_press_grad` task family +(`polaris/tasks/ocean/horiz_press_grad`), which is already Omega-only and built around a +quasi-analytic, layer-mean TEOS-10 reference solution (`reference.py`, surface-anchored, +4-point Gauss). That analytic reference remains valid as "truth" for the high-order scheme, +so the principal changes are scheme selection and revised pass criteria, plus two full-model +acceptance tests. + +Because the design optimizes for **coarse-resolution accuracy** rather than convergence rate +(§1), the primary pass/fail gate is an absolute error tolerance at a representative coarse +resolution, with the convergence slope demoted to a loose secondary diagnostic. + +### 5.1 Test: Two-column HPGA convergence (extend existing) + +Extend the four existing variants — `temperature_gradient`, `salinity_gradient`, +`surface_pressure_gradient`, `ztilde_gradient` — to run both the centered and high-order +schemes: + +- **Scheme selection.** Add `PressureGrad: { PressureGradType: FiniteVolume, … }` to + `forward.yaml` and parametrize each task over `centered` vs. `high_order`. The forward step + still runs a single time step with only `PressureGradTendencyEnable: true`, reading the PGF + acceleration from `NormalVelocityTend`. +- **Reference.** `reference.py`/`analysis.py` compare `NormalVelocityTend` against the + layer-mean analytic HPGA (unchanged). For the high-order scheme the layer-mean comparison + remains the correct target, since the scheme is a finite-volume, layer-averaged + discretization. +- **Primary pass criterion (new):** at a representative coarse resolution (e.g. the coarsest + in `horiz_resolutions`), the absolute RMS HPGA error vs. the reference must be below a + tolerance, **and** the high-order RMS error must be below the centered RMS error at that + same resolution (the scheme must demonstrably help where it matters). +- **Consistency check (retained):** `omega_vs_polaris_rms_threshold` (~1e-10 m/s²) — Omega's + forward output must still match the Python-computed HPGA, confirming the implementation + matches the intended discretization. +- **Secondary diagnostic (loosened):** the `omega_vs_reference_convergence_rate_*` band and + `omega_vs_reference_high_res_rms_threshold` are retained but relaxed/retuned; the + convergence slope is reported and required only to be no worse than the centered scheme, + not to hit a specific order. New cfg keys mirror the existing ones + (`horiz_press_grad.cfg`), e.g. a coarse-resolution tolerance and a + `high_order_vs_centered` ratio gate. + +Tests Requirements 2.1, 2.2 (via the bounded-EOS implementation exercised), 2.4, 2.5. + +### 5.2 Unit test: Discrete hydrostatic consistency (exact resting state) + +This is the primary test of the steep-layer robustness property (Requirement 2.3, §3.7). +Construct a two-column (or seamount) configuration with **horizontally uniform** conservative +temperature and absolute salinity but with the coordinate interfaces +$\tilde z_k^{\text{top}}$, $\tilde z_k^{\text{bot}}$ deliberately tilted between the columns +(arbitrary, including steep slopes and thin layers), over an arbitrary vertical $T$/$S$ +profile. **Pass:** the high-order PGF is zero at every edge and layer to **machine precision** +(double-precision builds; the threshold tracks `Real`'s epsilon and the magnitude of the +hydrostatic terms, not a physical tolerance). This verifies that the pressure and geopotential +terms cancel discretely, term by term, independent of any background state. It is implemented +as a fast C++ unit test and also exercised as a configuration of the Polaris two-column task. + +### 5.3 Test: Seamount resting state (steep-layer robustness) + +Use the Polaris seamount task with tilted layers over a seamount and a horizontally uniform +$T$/$S$ stratification, integrated for a fixed period. **Pass:** the maximum spurious velocity +stays below a threshold and is substantially smaller for the high-order scheme than for the +centered scheme. This is the dynamical counterpart of §5.2 (the same resting state, now run +forward in the full solver) and the direct test of Requirement 2.3. + +### 5.4 Test: Overflow (full non-Boussinesq dynamics) + +Use the Polaris overflow task to exercise the PGF within the full non-Boussinesq equations +with strongly sloping layers and active dynamics. **Pass:** the solution remains stable and +the down-slope evolution agrees with the reference behavior; spurious mixing/velocity +attributable to PGF error is reduced relative to the centered scheme. This tests Requirements +2.1 and 2.3 under realistic, coupled conditions. + +### 5.5 Test: Reduction to the centered scheme (regression) + +Configure the high-order option in its lowest-order limit (§3.9: +`ReconstructionOrder: 2`, `VerticalReconstruction: constant`, midpoint quadrature) and confirm +it reproduces `PressureGradCentered` to round-off on the two-column test. This guards +Requirement 2.5 and protects the existing default during refactoring. diff --git a/components/omega/doc/index.md b/components/omega/doc/index.md index dfc81a284670..310bde8e8799 100644 --- a/components/omega/doc/index.md +++ b/components/omega/doc/index.md @@ -128,6 +128,7 @@ design/Logging design/MachEnv design/Metadata design/PGrad +design/PGradHighOrder design/IO design/IOStreams design/Reductions From 5907fb7f422cdb75e3f5ca209fe088e57723803f Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 21 Jul 2026 14:23:31 +0200 Subject: [PATCH 02/22] Promote convergence rate to a verification requirement Convergence rate was framed as a secondary diagnostic subordinate to absolute error. Absolute error is the metric that matters for simulations, but the measured convergence rate verifies that the implementation achieves its designed order. Add Requirement 2.6 for verified order of accuracy, make the rate band in the Polaris test a gating criterion rather than a loosened diagnostic, and note that the resolution sweep may need retuning to resolve a fourth-order slope. Co-Authored-By: Claude Opus 4.8 --- components/omega/doc/design/PGradHighOrder.md | 72 +++++++++++++------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 1ceb6b4931bb..242ee94adbed 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -50,14 +50,21 @@ This design is shaped by three competing principles: steeply sloped layers. The PGF alone cannot guarantee this, but it is a necessary ingredient. -A guiding choice that follows from principles 2 and 3 is that the relevant metric of -success is **low absolute PGF error at affordable (coarse) resolution**, not high +A guiding choice that follows from principles 2 and 3 is that the metric of success *for +simulations* is **low absolute PGF error at affordable (coarse) resolution**, not high asymptotic order of convergence. Omega will be strongly resource-limited in how fine a mesh it can run, so a scheme whose error is small at coarse resolution is preferred over one with a steeper convergence slope but larger coarse-resolution error. Order of accuracy is configurable and a fourth-order variant is targeted, but it is a means to the end of coarse-resolution accuracy, not the objective itself. +The measured convergence rate plays a different but equally essential role: it is the +**verification** metric. A scheme that does not converge at its designed order is +mis-implemented, and no amount of favorable absolute error excuses that. The two metrics +therefore answer two different questions and both must be satisfied — *is the code correct?* +(convergence rate at the designed order) and *is it useful at the resolutions we can run?* +(absolute error). + ## 2 Requirements ### 2.1 Requirement: Higher accuracy than the centered scheme at affordable resolution @@ -65,8 +72,9 @@ end of coarse-resolution accuracy, not the objective itself. The high-order PGF must produce substantially lower absolute error than `PressureGradCentered` at the coarse-to-moderate resolutions Omega can afford to run, for representative stratified columns with horizontal gradients of temperature, salinity, -surface pressure, and coordinate slope. Convergence rate is a secondary diagnostic, not -the primary acceptance criterion. +surface pressure, and coordinate slope. Absolute error at affordable resolution is what +determines whether the scheme is *useful*; it is complemented by the separate verification +requirement in §2.6, which determines whether it is *correct*. ### 2.2 Requirement: Bounded TEOS-10 cost @@ -109,7 +117,20 @@ configuration group and `PressureGradType` enum, leaving `Centered` as the defau sub-options (horizontal reconstruction order, vertical-reconstruction mode, quadrature) must be configurable, and the centered scheme must be recoverable as the lowest-order limit. -### 2.6 Desired: Extensibility to sixth order and to tidal/geoid geopotential terms +### 2.6 Requirement: Verified order of accuracy + +The implemented scheme must converge, under refinement of a smooth manufactured or +quasi-analytic reference solution, at the order of accuracy it is configured for +(nominally fourth order for the targeted variant, second order when reduced to the +centered limit). This is a verification requirement: a measured slope that falls short of +the designed order indicates a defect in the implementation — a mis-weighted quadrature +point, an inconsistent reconstruction stencil, a dropped correction term — and must be +diagnosed rather than accepted, even when the absolute error at coarse resolution already +satisfies Requirement 2.1. The two requirements are independent and both are gating: +Requirement 2.1 establishes that the scheme is useful at the resolutions Omega can afford, +Requirement 2.6 establishes that it is the scheme the design describes. + +### 2.7 Desired: Extensibility to sixth order and to tidal/geoid geopotential terms The framework should accommodate a future higher-order variant (e.g. sixth order, added to the `PressureGradType` enum when implemented) and the @@ -306,7 +327,7 @@ provided by `VertCoord` (`GeomZMid`/`GeomZInterface`, `GeopotentialMid`; compute {ref}`omega-design-governing-eqns-omega1` Eqs. discrete-z and the geopotential relation). Its layer average and edge-normal gradient are evaluated with the same high-order edge reconstruction [](#edge-grad). The tidal-potential and self-attraction-and-loading -contributions enter through `VertCoord` and are differenced identically (Requirement 2.6); +contributions enter through `VertCoord` and are differenced identically (Requirement 2.7); they are zero in early Omega versions. The two metric terms (third and fourth lines of [](#ho-target)) use the **same** edge-normal @@ -487,9 +508,11 @@ quasi-analytic, layer-mean TEOS-10 reference solution (`reference.py`, surface-a so the principal changes are scheme selection and revised pass criteria, plus two full-model acceptance tests. -Because the design optimizes for **coarse-resolution accuracy** rather than convergence rate -(§1), the primary pass/fail gate is an absolute error tolerance at a representative coarse -resolution, with the convergence slope demoted to a loose secondary diagnostic. +The testing plan applies the two independent gates set out in §1: an **absolute error +tolerance at a representative coarse resolution** (Requirement 2.1), which establishes that +the scheme helps at the resolutions Omega can afford, and a **measured order of convergence** +(Requirement 2.6), which verifies that the implementation is the scheme this design +describes. Neither substitutes for the other, and both must pass. ### 5.1 Test: Two-column HPGA convergence (extend existing) @@ -505,21 +528,30 @@ schemes: layer-mean analytic HPGA (unchanged). For the high-order scheme the layer-mean comparison remains the correct target, since the scheme is a finite-volume, layer-averaged discretization. -- **Primary pass criterion (new):** at a representative coarse resolution (e.g. the coarsest - in `horiz_resolutions`), the absolute RMS HPGA error vs. the reference must be below a - tolerance, **and** the high-order RMS error must be below the centered RMS error at that +- **Accuracy gate (new, Requirement 2.1):** at a representative coarse resolution (e.g. the + coarsest in `horiz_resolutions`), the absolute RMS HPGA error vs. the reference must be below + a tolerance, **and** the high-order RMS error must be below the centered RMS error at that same resolution (the scheme must demonstrably help where it matters). +- **Verification gate (Requirement 2.6):** the measured slope of RMS error vs. resolution, + `omega_vs_reference_convergence_rate_*`, must fall within a band around the configured order + of accuracy — nominally ~4 for the fourth-order variant and ~2 when the scheme is run in its + centered limit. This band is retuned from its present values rather than loosened; a slope + outside it fails the test and is treated as an implementation defect to be diagnosed, not as + a tolerance to be widened. +- **Asymptotic range (implementation-time task):** it is not yet established that the existing + `horiz_resolutions` sweep spans a range where a fourth-order slope is cleanly measurable — + the sweep may be too coarse to have entered the asymptotic regime at its fine end, or fine + enough that the reference solution's own quadrature error and roundoff contaminate the slope. + Determining the usable window, and extending or tightening the sweep (and, if needed, the + order of the Gauss quadrature in `reference.py`) so the designed order can be resolved, is + part of implementing this test. - **Consistency check (retained):** `omega_vs_polaris_rms_threshold` (~1e-10 m/s²) — Omega's forward output must still match the Python-computed HPGA, confirming the implementation matches the intended discretization. -- **Secondary diagnostic (loosened):** the `omega_vs_reference_convergence_rate_*` band and - `omega_vs_reference_high_res_rms_threshold` are retained but relaxed/retuned; the - convergence slope is reported and required only to be no worse than the centered scheme, - not to hit a specific order. New cfg keys mirror the existing ones - (`horiz_press_grad.cfg`), e.g. a coarse-resolution tolerance and a - `high_order_vs_centered` ratio gate. - -Tests Requirements 2.1, 2.2 (via the bounded-EOS implementation exercised), 2.4, 2.5. +- **Cfg keys.** New keys mirror the existing ones (`horiz_press_grad.cfg`): a coarse-resolution + absolute tolerance, a `high_order_vs_centered` ratio gate, and per-scheme expected-rate bands. + +Tests Requirements 2.1, 2.2 (via the bounded-EOS implementation exercised), 2.4, 2.5, 2.6. ### 5.2 Unit test: Discrete hydrostatic consistency (exact resting state) From a6b45e9f36126325fbf4606dc6f660b5aa6d124f Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 21 Jul 2026 14:28:31 +0200 Subject: [PATCH 03/22] Verify the centered limit of the new scheme, not the legacy functor The convergence test parametrized only over the legacy centered functor and the fourth-order scheme, so the order-2 verification gate would have measured code this design does not change and left the new scheme's lowest-order path unverified. Add a third test configuration running the new implementation at ReconstructionOrder 2. Record the decision to keep PressureGradCentered as a separate functor rather than reimplementing it as the lowest-order configuration of the new scheme. Keeping it preserves an independent cross-check of shared upstream state and avoids an answer-changing change to the default, at the cost of ~40 redundant lines. Its eventual removal is follow-up work once FiniteVolume becomes the default. Co-Authored-By: Claude Opus 4.8 --- components/omega/doc/design/PGradHighOrder.md | 72 ++++++++++++++++--- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 242ee94adbed..02345928d06d 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -499,6 +499,29 @@ out of scope here and flagged as follow-up: momentum equations ({ref}`omega-design-governing-eqns-omega1` §9), which become non-negligible only at much higher resolution. +### 4.4 Retention of the centered implementation + +`PressureGradCentered` (PGrad.h:25) is deliberately **kept as a separate functor** rather +than reimplemented as the lowest-order configuration of `PressureGradHighOrder`, even though +§3.9 shows the latter reduces to it. The redundancy is small — the centered functor is a +header-only, ~40-line loop body with no supporting machinery of its own — and it buys two +things that a single implementation cannot provide: + +1. **An independent cross-check.** The two functors read the mesh, `VertCoord`, and EOS state + through separately written code. Their agreement to round-off (§5.5) therefore tests the + shared upstream state — edge masks, interface indexing, `VertCoord` conventions — and not + just the PGF arithmetic. Collapsing them would make that comparison self-referential: a + defect upstream of the order switch would appear identically in both limits and cancel. +2. **A stable default.** The algebraic reduction of §3.9 does not imply bit-for-bit agreement, + because the reduced high-order path performs the same operations in a different order. + Replacing the default PGF would be an answer-changing change for every existing + configuration, which this design does not require. + +Removing `PressureGradCentered` becomes reasonable once `FiniteVolume` is promoted to the +default and has served out its period as the reference implementation. That is deliberately +left as **follow-up work**, to be taken up as a separate, answer-changing change with its own +baseline step — not as part of this design. + ## 5 Verification and Testing Testing reuses and extends the Polaris `horiz_press_grad` task family @@ -517,13 +540,28 @@ describes. Neither substitutes for the other, and both must pass. ### 5.1 Test: Two-column HPGA convergence (extend existing) Extend the four existing variants — `temperature_gradient`, `salinity_gradient`, -`surface_pressure_gradient`, `ztilde_gradient` — to run both the centered and high-order -schemes: +`surface_pressure_gradient`, `ztilde_gradient` — to run the centered scheme and the new +scheme at two orders: - **Scheme selection.** Add `PressureGrad: { PressureGradType: FiniteVolume, … }` to - `forward.yaml` and parametrize each task over `centered` vs. `high_order`. The forward step - still runs a single time step with only `PressureGradTendencyEnable: true`, reading the PGF - acceleration from `NormalVelocityTend`. + `forward.yaml` and parametrize each task over three configurations: + - `centered` — the legacy `PressureGradCentered` functor, unchanged; + - `finite_volume_order4` — `ReconstructionOrder: 4`, `VerticalReconstruction: ppm` (the + target); + - `finite_volume_order2` — the same code in its centered limit (`ReconstructionOrder: 2`, + `VerticalReconstruction: constant`, midpoint quadrature). + + (These variant names are provisional; the final spelling follows Polaris' naming conventions + and is settled on the Polaris side. What matters here is that the last two are the *same* + implementation at two orders, distinct from the legacy functor.) + + The third configuration exists because the order-2 verification gate below must exercise the + *new* implementation. Running the legacy functor under a "second order" label would measure + the convergence of code this design does not change, and would leave the new code's + lowest-order path unverified. It also supplies the round-off comparison of §5.5 at every + resolution rather than at a single configuration. The forward step still runs a single time + step with only `PressureGradTendencyEnable: true`, reading the PGF acceleration from + `NormalVelocityTend`. - **Reference.** `reference.py`/`analysis.py` compare `NormalVelocityTend` against the layer-mean analytic HPGA (unchanged). For the high-order scheme the layer-mean comparison remains the correct target, since the scheme is a finite-volume, layer-averaged @@ -534,10 +572,10 @@ schemes: same resolution (the scheme must demonstrably help where it matters). - **Verification gate (Requirement 2.6):** the measured slope of RMS error vs. resolution, `omega_vs_reference_convergence_rate_*`, must fall within a band around the configured order - of accuracy — nominally ~4 for the fourth-order variant and ~2 when the scheme is run in its - centered limit. This band is retuned from its present values rather than loosened; a slope - outside it fails the test and is treated as an implementation defect to be diagnosed, not as - a tolerance to be widened. + of accuracy — nominally ~4 for `finite_volume_order4` and ~2 for `finite_volume_order2` + (and for `centered`, whose band is unchanged from today). This band is retuned from its + present values rather than loosened; a slope outside it fails the test and is treated as an + implementation defect to be diagnosed, not as a tolerance to be widened. - **Asymptotic range (implementation-time task):** it is not yet established that the existing `horiz_resolutions` sweep spans a range where a fourth-order slope is cleanly measurable — the sweep may be too coarse to have entered the asymptotic regime at its fine end, or fine @@ -549,7 +587,8 @@ schemes: forward output must still match the Python-computed HPGA, confirming the implementation matches the intended discretization. - **Cfg keys.** New keys mirror the existing ones (`horiz_press_grad.cfg`): a coarse-resolution - absolute tolerance, a `high_order_vs_centered` ratio gate, and per-scheme expected-rate bands. + absolute tolerance, a `finite_volume_vs_centered` ratio gate, and per-scheme expected-rate + bands. Tests Requirements 2.1, 2.2 (via the bounded-EOS implementation exercised), 2.4, 2.5, 2.6. @@ -582,9 +621,20 @@ the down-slope evolution agrees with the reference behavior; spurious mixing/vel attributable to PGF error is reduced relative to the centered scheme. This tests Requirements 2.1 and 2.3 under realistic, coupled conditions. -### 5.5 Test: Reduction to the centered scheme (regression) +### 5.5 Test: Reduction to the centered scheme (permanent regression) Configure the high-order option in its lowest-order limit (§3.9: `ReconstructionOrder: 2`, `VerticalReconstruction: constant`, midpoint quadrature) and confirm it reproduces `PressureGradCentered` to round-off on the two-column test. This guards Requirement 2.5 and protects the existing default during refactoring. + +This test is retained permanently rather than treated as a one-time transition check, and +that choice is the reason `PressureGradCentered` is kept as a separate implementation rather +than reimplemented as the lowest-order configuration of `PressureGradHighOrder` (§4.4). The +two functors read the mesh, `VertCoord`, and EOS state through independently written code, so +their agreement to round-off is evidence about *shared upstream* state as well as about the +PGF arithmetic: a wrong edge mask, a mis-indexed interface array, or a misinterpreted +`VertCoord` convention shows up as a disagreement. Were the centered scheme replaced by an +order-2 configuration of the new code, this comparison would reduce to comparing an +implementation against itself, and any defect upstream of the order switch would cancel out +of it. From 1109a314611db1000ce2d1da5c8a45498962b92c Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 28 Jul 2026 08:29:53 -0500 Subject: [PATCH 04/22] Restate the hydrostatic consistency claim with its real conditions The previous draft required the scheme to return zero PGF whenever layer means are horizontally uniform, for arbitrary tilt and arbitrary vertical profile. That cannot be delivered: under tilt each column reconstructs on its own interfaces, so the two columns describe different water and a nonzero PGF is the correct answer. Replace the claim with the three conditions the implementation must actually meet, and state for each phase which water columns cancel to machine precision. Also record two constraints the earlier draft missed: the EOS expansion point must be shared across an edge rather than taken per cell, and the sloping-interface term needs the pressure-averaged alpha*p along the interface, not the average of the two cells' values. Flag the VertCoord geopotential as an unmet prerequisite, since computeGeomZHeight integrates the layer-mean specific volume and so works from a different alpha than the pressure term would. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 417 +++++++++++++++--- 1 file changed, 355 insertions(+), 62 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 02345928d06d..f7fcd819f7ef 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -87,18 +87,34 @@ itself semi-analytically. ### 2.3 Requirement: Robustness for thin, steeply sloped layers via discrete hydrostatic consistency -The scheme must suppress spurious pressure-gradient accelerations when layers are thin and -steeply sloped in geometric height. The primary guarantee is **discrete hydrostatic -consistency**: for a physically resting ocean with horizontally uniform conservative -temperature and absolute salinity but coordinate surfaces tilted arbitrarily, the scheme -must return **exactly zero** horizontal PGF, to machine precision, regardless of the vertical -profile or the steepness of the tilt. This property is *structural* — it depends only on the -construction of the discretization, not on any background reference state — and therefore -holds uniformly across the global ocean. The residual error for non-uniform $T$/$S$ is then -genuine truncation error, reduced by the high-order, mean-preserving reconstruction (§3.4) -and by evaluating the equation of state consistently, including its pressure dependence -(compressibility $\alpha_p$), so that thermobaric effects under tilted layers are not aliased -into spurious flow. +The scheme must suppress spurious pressure-gradient accelerations when layers are thin and steeply +sloped relative to surfaces of constant pressure. Four things are required. + +**2.3.1 No spurious PGF for water columns the scheme resolves exactly.** For any resting ocean +whose temperature and salinity profile the scheme's vertical reconstruction reproduces exactly, the +computed horizontal PGF must be **zero to machine precision** at every edge and layer — for any +tilt of the coordinate surfaces, any layer thickness, and any bathymetry. This is the core +robustness property: it says the scheme adds nothing of its own when there is nothing to add. + +**2.3.2 The design must say which water columns those are.** "Water columns the scheme resolves +exactly" is not a fixed set; it depends on the reconstruction, and it widens as the reconstruction +order increases. Each phase of this design must state its own set explicitly (§3.7.3) so that the +guarantee in §2.3.1 can be tested rather than assumed. + +**2.3.3 That set must be large enough to matter.** A scheme that is exact only for an ocean of +uniform temperature and salinity would satisfy §2.3.1 trivially and be of no practical use, since +no such ocean exists. The set must at minimum include profiles that vary **linearly with +pressure**, which captures both compressibility and smooth stratification to leading order. + +**2.3.4 Everywhere else, substantially smaller error than the centered scheme.** For realistic +profiles, which no reconstruction reproduces exactly, some residual PGF is unavoidable and is +*correct* — the two neighboring columns genuinely do hold slightly different water (§3.7.1). The +requirement is that this residual shrink at least one order faster in layer thickness than +`PressureGradCentered` does, and that it not be swamped by errors the scheme itself introduces +through inexact integration or an inconsistent geopotential. + +These properties must hold without reference to any background or reference profile, so that they +hold equally in the warm pool, at the poles, and over a seamount. ### 2.4 Requirement: Consistency with the rest of the model state @@ -171,6 +187,41 @@ density varies within a layer in a general ALE coordinate, and TEOS-10 is far mo expensive and not practical to integrate in closed form. The remainder of this section adapts the form [](#ho-target) to those two realities. +#### 3.1.1 The four terms are one control volume and must be built together + +The four terms of [](#ho-target) are not independent pieces to be discretized separately and added +up. They are the pressure forces on the four faces of a single control volume — the two vertical +faces where the layer meets its neighboring columns, and the sloping top and bottom interfaces — +together with the weight of the water inside. In a genuinely resting ocean these forces balance +exactly. Whether the *discrete* forces balance depends entirely on whether they are built from a +common description of the water column, and that is what §3.7 is about. + +Two observations make this practical to enforce. + +First, use pressure itself as the vertical integration variable within a column. It is equivalent +to $\tilde z$ by [](#p-linear), but unlike $\tilde z$ it means the same thing in every column +regardless of surface pressure. In terms of $p$, the hydrostatic relation is +$\partial z / \partial p = -\alpha/g$, so the side-wall pressure force and the geometric height +entering the geopotential are integrals of **the same specific volume over pressure**: + +$$ +\Pi_{i,k} = \frac{1}{g}\int_{p_{i,k}^{\text{top}}}^{p_{i,k}^{\text{bot}}} \hat\alpha_{i,k}(p)\, p \; dp, +\qquad +z_{i}(p) = z_{i}^{\text{anchor}} + \frac{1}{g}\int_{p}^{p_i^{\text{anchor}}} \hat\alpha_{i}(p')\, dp', +$$ (layer-integrals) + +where $\hat\alpha_{i,k}(p)$ is the reconstructed specific volume in column $i$, layer $k$ +(§3.3–§3.4). Writing both terms this way makes the shared ingredient explicit: it is +$\hat\alpha(p)$, and if the pressure term and the geopotential term use different versions of it, +they cannot balance. + +Second, the layer's top and bottom interfaces are *sloping*, so the pressure force on them is an +integral along the slope, not a value at a point. Between two cell centers the interface sweeps +through a range of pressures, and the force per unit slope is the **average of $\hat\alpha p$ over +that pressure range** — not the average of the two cells' interface values. The two agree only when +the tilt is small. Supplying this integral is the piece `PressureGradCentered` omits altogether, +and it is the central content of Phase 1; the explicit form is given in §3.8. + ### 3.2 A key simplification: pressure is linear in pseudo-height Omega's vertical coordinate is pseudo-height, @@ -220,6 +271,46 @@ $\alpha_{\Theta\Theta}$, $\alpha_{SS}$, $\alpha_{\Theta S}$, $\alpha_{pp}$, …) where stratification is strong; it adds derivative evaluations but still no in-integral TEOS-10 calls. +#### 3.3.1 The expansion point must be shared across the edge + +Expanding about the *cell-local* reference state $(\Theta_{i,k}, S_{i,k}, p_{i,k}^{\text{mid}})$ +would quietly defeat the robustness property of §3.7. Two neighboring columns would then be using +two slightly different approximations to the *same* equation of state, taken at two different +points. Their specific-volume profiles $\hat\alpha_{L,k}(p)$ and $\hat\alpha_{R,k}(p)$ would then +disagree — by $O(\alpha_{pp}\,\Delta p^{\text{mid}}_e\, \tilde h)$ — even for a resting ocean the +reconstruction reproduces perfectly. The forces on the two vertical faces would no longer balance, +and the scheme would generate spurious flow from nothing but its own EOS approximation. + +The design therefore **shares the expansion point across each edge**. The coefficients +[](#alpha-derivs) are computed once per cell per layer, exactly as described above (one TEOS-10 +evaluation, Requirement 2.2), and are then averaged to the edge together with the reference state +itself: + +$$ +\bar\alpha_{0}^{e,k}, \; \bar\alpha_{\Theta}^{e,k}, \; \bar\alpha_{S}^{e,k}, \; \bar\alpha_{p}^{e,k}, +\qquad +\left(\bar\Theta^{e,k}, \bar S^{e,k}, \bar p^{e,k}\right) = \tfrac12 \sum_{i \in CE(e)} \left(\Theta_{i,k}, S_{i,k}, p_{i,k}^{\text{mid}}\right), +$$ (edge-ref) + +and **both** columns' contributions to edge $e$ are evaluated with this single set, so that the two +sides of the edge see one and the same equation of state. + +Two consequences must be recorded: + +- **Cost.** The column integral $\Pi_{i,k}$ is no longer a per-cell quantity that can be computed + once and then differenced across each of the cell's edges; it depends on the edge through + [](#edge-ref) and must be evaluated per edge, twice. On a hexagonal TRiSK mesh this is roughly + three times as many integral evaluations as a cell-based formulation. The TEOS-10 call count is + unaffected, which is the cost Requirement 2.2 binds; the extra work is polynomial arithmetic on + coefficients already in cache. +- **The PGF is no longer the gradient of a single scalar.** With the expansion point depending on + the edge, the discrete PGF is not exactly a discrete gradient, so it is not automatically + curl-free and could in principle inject spurious vorticity. It is zero at every edge for a resting + ocean the scheme resolves exactly, so nothing is injected in that case; elsewhere the effect + enters at truncation order. This trade is deliberate — a robustness property that holds exactly, + in exchange for a potential-form property that held exactly — but the magnitude of any spurious + vorticity is something §5 must measure rather than assume away. + Because $\Theta$, $S$ are reconstructed as low-order polynomials in $\tilde z$ (and across edges) and $p$ is linear in $\tilde z$ by [](#p-linear), the expansion [](#alpha-taylor) makes $\alpha$ a **low-order polynomial** whose product with $p$ integrates **exactly** by a @@ -284,40 +375,188 @@ reconstruction; cf. the third-order interface reconstruction noted at **not** assume anything constant across the edge — the horizontal density contrast between adjacent columns is fully reconstructed. -### 3.7 Discrete hydrostatic consistency (the steep-layer robustness property) - -Robustness for thin, steeply sloped layers (Requirement 2.3) is delivered not by subtracting -a background profile but by a structural property of the discretization. We require **discrete -hydrostatic consistency**: - -> When $\Theta$ and $S$ are horizontally uniform — a physically resting, flat-isopycnal ocean -> — the discrete horizontal PGF at every edge and layer must be **exactly zero, to machine -> precision**, for arbitrary tilt of the coordinate surfaces $\tilde z_k^{\text{top}}$, -> $\tilde z_k^{\text{bot}}$ between the two columns and for an arbitrary vertical profile. - -The finite-volume form [](#ho-target) is constructed to satisfy this exactly: with $\Theta$, -$S$ horizontally uniform, $\alpha(\Theta,S,p)$ is the same function of pressure in both -columns, so the side-wall integral [](#sidewall-int) and the sloping-interface metric terms -(§3.8) combine to the net pressure force on a control volume with horizontally uniform density, -which is balanced exactly by the geopotential term. The cancellation must be enforced -*discretely*: the pressure term and the geopotential term must share the same interface -locations (from `VertCoord`), the same edge reconstruction [](#edge-grad), and the same -quadrature nodes, so that their difference vanishes term by term rather than only in the -continuum limit. - -This property is the reason the scheme is robust: it is *reference-free* (it depends on no -background state, so it holds identically in the warm pool, at the poles, and over a seamount) -and it is directly *testable* (§5.1, §5.2). It strictly supersedes a Shchepetkin–McWilliams -(2003)-style reference-profile subtraction, which only approximates this cancellation to the -extent the local column resembles a global reference and therefore degrades precisely in the -strong-gradient, steep-layer regions of interest. For non-uniform $\Theta$/$S$ the remaining -error is genuine truncation error, controlled by the reconstruction order (§3.4, §3.6) and by -the consistent treatment of compressibility $\alpha_p$ (§3.3); no formulation removes it, and -a reference subtraction would not help. Because the consistency cancellation is exact in -exact arithmetic, the only residual in the resting state is round-off, which is at the -machine-precision floor in double precision; single-precision builds (`OMEGA_SINGLE_PRECISION`) -may expose a small floor, addressed if needed as a local implementation-level conditioning -choice rather than a physics option. +### 3.7 Where the cancellation is exact, and where it is not + +This section makes Requirement 2.3 concrete: it explains why the obvious version of the robustness +property cannot be delivered, states the three conditions the implementation must meet, lists the +water columns that cancel exactly under each phase, and records what the design is still assuming +and must therefore test. It does *not* rely on subtracting a background profile. + +#### 3.7.1 Why "uniform $\Theta$ and $S$" is the wrong condition + +An earlier draft of this design required the scheme to return zero whenever the layer means +$\Theta_{i,k}$, $S_{i,k}$ are the same in both cells of an edge, for any tilt and any vertical +profile. **That requirement cannot be met, and asking for it would send the implementation chasing +an impossible target.** + +When coordinate surfaces tilt relative to surfaces of constant pressure, layer $k$ in one column and +layer $k$ in its neighbor cover *different pressure ranges*. Each column builds its own +specific-volume profile from its own layer means on its own set of interfaces. Unless the vertical +reconstruction happens to reproduce the true profile exactly, the two columns therefore describe +slightly *different water*. Real water columns that differ do exert a real pressure gradient on one +another. A scheme that returned zero there would be hiding an error, not avoiding one. + +The same argument runs the other way, and this is the more useful half: take a perfectly uniform +ocean whose temperature and salinity depend only on pressure, and sample it onto tilted layers. The +resulting layer means are **different in the two columns**, because the layers average over +different pressure ranges. So "uniform layer means" is neither necessary nor sufficient for the +cancellation we want. The condition that matters is a property of the reconstructed profiles, not of +the layer means, and it is stated next. + +#### 3.7.2 Three conditions the implementation must meet + +For each edge and layer: + +1. **Both sides of the edge use the same specific-volume profile.** The two columns must evaluate + $\hat\alpha$ as one and the same function of pressure over the pressure range the layer spans. + This is what the edge-shared expansion point of §3.3.1 delivers, and it is why that choice is + load-bearing rather than cosmetic. +2. **Every face integral is exact for that profile.** The side-wall integrals must be exact for + $\hat\alpha(p)\,p$ (§3.5 chooses the quadrature to guarantee this), and the sloping top and + bottom interfaces must use the pressure-averaged $\hat\alpha p$ of §3.8, not the average of the + two cells' interface values. +3. **The geopotential is built from that same profile.** The geometric height entering + $g\nabla z$ must be the integral of the same $\hat\alpha$, layer by layer, down to a common + anchor. This one is currently *not* satisfied; see §3.7.4. + +Conditions 2 and 3 are about the discretization alone and are under the implementation's control. +Meeting them means the scheme returns the **exact pressure gradient of the water column it has +reconstructed** — it contributes no error of its own beyond the reconstruction. Condition 1 is +about the state: it holds when the reconstruction reproduces the true profile, and fails, by +however much the reconstruction misses, when it does not. Meeting all three gives a PGF that is +**zero to machine precision**, for any tilt, any layer thickness, and any bathymetry. + +The point worth carrying away, because it is what makes this tractable, is that **the reconstructed +profile does not have to be accurate for the cancellation to be exact — it only has to be shared.** +The scheme needs the two columns to describe *one* water column, not the *right* one. Accuracy is a +separate concern, addressed by reconstruction order. + +#### 3.7.3 Which water columns cancel exactly + +Condition 1 holds whenever the true vertical profile is one the reconstruction reproduces exactly: +two mean-preserving reconstructions of such a profile, built on *different* sets of interfaces from +*different* layer means, recover the identical profile anyway. Together with the edge-shared +expansion point [](#edge-ref) this gives, for each phase: + +| Vertical profile of $\Theta$, $S$ | `Centered` | Phase 1 (linear reconstruction) | Phase 2 (parabolic reconstruction) | +|---|---|---|---| +| Uniform ($\alpha$ constant) | exact | exact | exact | +| Uniform $\Theta$, $S$; compressibility only | $O(\tilde h)$ | **exact** | **exact** | +| Linear in pressure | $O(\tilde h)$ | **exact** | **exact** | +| Quadratic in pressure | $O(\tilde h)$ | $O(\tilde h^2)$ | **exact** | +| Realistic (general smooth) | $O(\tilde h)$ | $O(\tilde h^2)$ | $O(\tilde h^3)$ | +| Horizontal structure in $\Theta$, $S$ | $O(d_e^2)$ | $O(d_e^2)$ | $O(d_e^4)$ | + +"Exact" means zero to machine precision. Orders are in layer thickness $\tilde h$ at fixed tilt, and +in cell spacing $d_e$ for the last row. The $\tilde h$ entries carry a factor set by how strongly +the profile curves and by how far the interfaces are displaced between the two columns, so they +shrink as either shrinks. + +Two consequences deserve emphasis: + +- Phase 1 is exact for profiles that are **linear in pressure**, not merely for vertically uniform + ones. That distinction is the whole reason Phase 1 is worth doing on its own: a vertically uniform + ocean does not exist, but linear-in-pressure captures compressibility exactly and smooth + stratification to leading order, which is most of what a real column looks like over a single + layer. It satisfies Requirement 2.3.3. +- `PressureGradCentered` is only first order in layer thickness for *every* stratified profile, + including a horizontally uniform one. + +That last point is worth showing, since it identifies the error Phase 1 targets. Take specific +volume uniform in the horizontal within each layer, and let the coordinate merely redistribute +thickness between the two columns ($\sum_j \Delta \tilde h_j = 0$). The centered scheme's +edge-normal Montgomery-potential difference is then + +$$ +\Delta \bar M_k = g \rho_0 \sum_{j>k} \left( \alpha_j - \alpha_k \right) \Delta \tilde h_j, +$$ (centered-error) + +which is nonzero whenever $\alpha$ varies with depth and interfaces are displaced, and which +**accumulates downward**: the deeper the layer, the more layers contribute to the sum. The vertical +contrast in *in-situ* $\alpha$ is dominated by compressibility (a few percent over the full ocean +depth, against a few tenths of a percent from $\Theta$ and $S$), and that is exactly the part +Phase 1 cancels. Whether this downward accumulation is in fact what produces the bottom-layer noise +seen in realistic global configurations is a plausible diagnosis, not an established one; it is +carried as A4 in §3.7.6 and tested in §5.3. + +#### 3.7.4 A prerequisite in `VertCoord` + +Condition 3 is a constraint on `VertCoord`, not on `PGrad`, and **it is not currently satisfied**. +`VertCoord::computeGeomZHeight` builds $z$ by accumulating +$\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — a midpoint rule using the layer-mean specific +volume, working upward from the bottom. If the pressure term integrates a reconstructed +$\hat\alpha$ while the geopotential term differences a $z$ built this way, the two are working from +**different specific volumes**, and the cancellation fails at $O(\alpha_{pp}\tilde h^2)$ — precisely +the order Phase 1 exists to recover. Worse, because $z$ is a running sum up the column, the mismatch +**accumulates over every layer between the anchor and the layer in question** rather than staying +local. + +This is a prerequisite for Phase 1, not an implementation detail. There are three ways to resolve +it: + +1. **Align `VertCoord`.** Integrate $z$ using the same reconstruction the PGF uses. Satisfies + condition 3 outright, but changes answers for every existing configuration and modifies a module + the PGF does not own. +2. **Build $z$ increments inside the PGF.** Leave `VertCoord` alone and have the PGF form its own + layer $z$ increments from its own $\hat\alpha$. No answer change elsewhere, but it creates a + second, slightly different $z$ in the model, which Requirement 2.4 exists to prevent. +3. **Accept the mismatch and document the error floor.** The guarantee of §3.7.2 weakens from "zero + to machine precision" to "zero to $O(\alpha_{pp}\tilde h^2)$ accumulated over the column", and the + test in §5.2 cannot pass. + +**Recommendation: option 1.** Options 2 and 3 both give up the property this phase exists to +deliver. The change is answer-changing but small and well contained, and it is worth having on its +own merits: it makes the model's $z$ a more accurate integral of the hydrostatic relation. The +decision must be made before Phase 1 implementation begins, and it needs a baseline step (§5). + +One related question is deliberately left to implementation time: `VertCoord` builds $z$ upward from +the bathymetry while pressure is built downward from the surface, so the two accumulate round-off +from opposite ends of the column. Whether the PGF should re-anchor its own accumulation is a +round-off question (§3.7.5), not a consistency one — condition 3 is satisfied either way. + +#### 3.7.5 Round-off in the deep ocean + +Separate from everything above, and not fixed by it, is how much precision the cancellation itself +consumes. At 4000 m the side-wall integrand $\hat\alpha p$ is about +$4\times10^{4}\ \mathrm{m^2\,s^{-2}}$, while the baroclinic signal that survives in the edge +tendency is of order $10^{-6}\ \mathrm{m\,s^{-2}}$ times $d_e$. Roughly ten significant digits are +consumed before any physics appears. Double precision leaves adequate margin; a +`OMEGA_SINGLE_PRECISION` build does not, and the machine-precision cancellation of §3.7.2 would +simply be invisible beneath round-off. + +If that turns out to matter, the fix is to compute in **perturbation form**: subtract a local +reference profile from $\hat\alpha$ before integrating and add its contribution back analytically. +This is *not* a Shchepetkin–McWilliams (2003)-style reference-profile subtraction in the usual +sense. The reference here is local to the edge and layer, its contribution cancels identically +rather than approximately, and the accuracy of the scheme does not depend at all on how well it +matches the local column — so it does not degrade in the strong-gradient, steep-layer regions where +a global reference profile would. It changes nothing in exact arithmetic. Whether it is needed is a +measurement (§5.2, run in both precisions), not an assumption. + +#### 3.7.6 Assumptions that still need testing + +Everything above concerns properties the implementation can be built to have. The following are +assumptions this design is making that only testing can confirm: + +- **A1 — Accuracy at cell centers does not imply accuracy at edges.** The cancellation above is a + statement about a *pair* of columns at an edge. Reconstructing $\Theta$ and $S$ accurately at each + cell center does not by itself make the combination $\hat\alpha(\Theta,S,p)\,p$ accurate at the + edge between them, because that combination is nonlinear. The horizontal order claimed in §3.6 is + therefore a design target to be confirmed by measured convergence (Requirement 2.6), not something + that follows from the cell-centered reconstruction order. +- **A2 — The EOS expansion is good enough across the edge.** [](#alpha-taylor) is expanded about the + shared edge state [](#edge-ref), and its error grows with the horizontal contrast in $\Theta$ and + $S$ across the edge and with the layer's pressure range. Whether the first-order expansion suffices + in frontal regions, or whether the second-order option of §3.3 is needed, is an open question. +- **A3 — The residual outside the exact set is small enough in practice.** The $O(\tilde h^2)$ and + $O(\tilde h^3)$ entries in §3.7.3 describe how the error *scales*; how large it actually is at the + vertical resolutions Omega can afford is unknown. +- **A4 — PGF error is what is driving the observed instability.** Identifying [](#centered-error) + with bottom-layer noise in realistic global runs is a plausible diagnosis, not a demonstrated one. + A configuration whose profile falls in Phase 1's exact set gives a direct test: if spurious + bottom-layer flow persists there, the cause lies elsewhere — most likely in the layer-mean + treatment in the tracer and remapping operators (§4.3) — and Phase 1 will not cure it. See §5.3. +- **A5 — Spurious vorticity from the edge-shared expansion point is negligible** (§3.3.1). ### 3.8 Geopotential and metric terms @@ -330,12 +569,35 @@ reconstruction [](#edge-grad). The tidal-potential and self-attraction-and-loadi contributions enter through `VertCoord` and are differenced identically (Requirement 2.7); they are zero in early Omega versions. -The two metric terms (third and fourth lines of [](#ho-target)) use the **same** edge-normal -operator to evaluate the interface slopes $\nabla \tilde z_k^{\text{top}}$, -$\nabla \tilde z_k^{\text{bot}}$, with $\alpha\,p$ evaluated at the interfaces from -[](#alpha-taylor) and [](#p-linear). These terms vanish for flat interfaces and supply the -leading correction for sloping layers; together with the side-wall integral [](#sidewall-int) -they form a discretely consistent finite-volume pressure force on the layer control volume. +The two metric terms (third and fourth lines of [](#ho-target)) are the pressure force on the +layer's sloping top and bottom interfaces. They use the **same** edge-normal operator to evaluate +the interface slopes $\nabla \tilde z_k^{\text{top}}$, $\nabla \tilde z_k^{\text{bot}}$, but the +quantity multiplying each slope needs care. Because the interface is sloping, it sweeps through a +range of pressures between the two cell centers, and the force is an integral along it. The correct +factor is therefore the **average of $\hat\alpha p$ over that pressure range**, + +$$ +\left\langle \hat\alpha p \right\rangle_{e,k}^{\text{top}} += \frac{1}{p_{R,k}^{\text{top}} - p_{L,k}^{\text{top}}} + \int_{p_{L,k}^{\text{top}}}^{p_{R,k}^{\text{top}}} \hat\alpha(p)\, p \; dp, +$$ (metric-divdiff) + +and likewise at the bottom interface, reducing to +$\hat\alpha\!\left(p^{\text{top}}\right) p^{\text{top}}$ when the interface is level in the two +columns. Because $\hat\alpha(p)$ is a low-order polynomial (§3.3), this integral is evaluated in +closed form at no meaningful cost. + +The tempting alternative — averaging the two cells' interface values, +$\tfrac12[(\hat\alpha p)_L + (\hat\alpha p)_R]$ — agrees with [](#metric-divdiff) only when the +tilt is small, and leaves behind a residual that grows with the square of the tilt and does *not* +vanish for the water columns §3.7.3 says should cancel exactly. It would therefore break +condition 2 of §3.7.2 and forfeit the robustness property in exactly the steeply sloped regions +this design is meant to fix. + +This integral is what `PressureGradCentered` omits altogether, and supplying it is the central +content of Phase 1. These terms vanish for level interfaces and supply the leading correction for +sloping layers; together with the side-wall integral [](#sidewall-int) and the geopotential term +they complete the force balance on the layer's control volume (§3.1.1). ### 3.9 Reduction to the centered scheme @@ -594,16 +856,37 @@ Tests Requirements 2.1, 2.2 (via the bounded-EOS implementation exercised), 2.4, ### 5.2 Unit test: Discrete hydrostatic consistency (exact resting state) -This is the primary test of the steep-layer robustness property (Requirement 2.3, §3.7). -Construct a two-column (or seamount) configuration with **horizontally uniform** conservative -temperature and absolute salinity but with the coordinate interfaces -$\tilde z_k^{\text{top}}$, $\tilde z_k^{\text{bot}}$ deliberately tilted between the columns -(arbitrary, including steep slopes and thin layers), over an arbitrary vertical $T$/$S$ -profile. **Pass:** the high-order PGF is zero at every edge and layer to **machine precision** -(double-precision builds; the threshold tracks `Real`'s epsilon and the magnitude of the -hydrostatic terms, not a physical tolerance). This verifies that the pressure and geopotential -terms cancel discretely, term by term, independent of any background state. It is implemented -as a fast C++ unit test and also exercised as a configuration of the Polaris two-column task. +This is the primary test of the steep-layer robustness property (Requirement 2.3, §3.7). It follows +the table in §3.7.3 row by row rather than being a single pass/fail. + +Set up a two-column (or seamount) configuration with the coordinate interfaces deliberately tilted +between the columns — including steep slopes and thin layers — and initialize the layer means as the +**exact layer averages** of a prescribed continuous profile $\Theta(p)$, $S(p)$. Under tilt those +averages come out *different in the two columns*, and that is the point: a configuration built by +copying identical layer means into both columns would not exercise the property at all (§3.7.1). +Three groups of profiles are run: + +- **Profiles the scheme resolves exactly:** $\Theta$, $S$ linear in pressure, including the constant + case, which isolates compressibility on its own. **Pass:** the PGF is zero at every edge and layer + to **machine precision** (double-precision builds; the threshold tracks `Real`'s epsilon and the + size of the hydrostatic terms, not a physical tolerance). Phase 1 and Phase 2 must both pass. +- **Profiles it does not:** $\Theta$, $S$ quadratic in pressure, then a realistic profile. + **Pass:** the residual shrinks like $\tilde h^2$ (Phase 1) and $\tilde h^3$ (Phase 2) as the + vertical grid is refined at fixed tilt, matching §3.7.3. A residual that does not shrink at the + tabulated rate means one of the three conditions in §3.7.2 has been broken somewhere in the + implementation; it is a bug to find, not a tolerance to widen. +- **Guard tests:** rerun an exactly resolved profile with (a) the endpoint-average interface term in + place of [](#metric-divdiff), and (b) a cell-local expansion point in place of [](#edge-ref). + Both must *fail* the machine-precision check. Without these, a passing result could just as easily + come from a symmetry of the test setup as from the scheme being right. + +The test is also run in a single-precision build, to measure the round-off floor of §3.7.5 and +settle whether the perturbation form is needed. + +Condition 3 of §3.7.2 depends on `VertCoord` (§3.7.4), so the machine-precision check cannot pass +until whichever resolution is chosen there is in place; this test therefore doubles as the +acceptance criterion for that prerequisite. It is implemented as a fast C++ unit test and also run +as a configuration of the Polaris two-column task. ### 5.3 Test: Seamount resting state (steep-layer robustness) @@ -613,6 +896,16 @@ stays below a threshold and is substantially smaller for the high-order scheme t centered scheme. This is the dynamical counterpart of §5.2 (the same resting state, now run forward in the full solver) and the direct test of Requirement 2.3. +**Testing assumption A4 (§3.7.6).** Run the seamount case twice: once with a stratification Phase 1 +resolves exactly ($\Theta$, $S$ linear in pressure) and once with a realistic profile. Spurious +velocity that survives the first run cannot be PGF truncation error, since the PGF is zero there to +machine precision, and must come from somewhere else in the model — most likely the layer-mean +treatment in the tracer and remapping operators (§4.3). This is the cheapest available check on +whether accelerating this work will actually cure the bottom-layer instability that motivated the +phasing, and it should be run **before** Phase 1 implementation is finished, with the centered +scheme on the realistic profile as the control. A null result would not invalidate the design, but +it would change its priority. + ### 5.4 Test: Overflow (full non-Boussinesq dynamics) Use the Polaris overflow task to exercise the PGF within the full non-Boussinesq equations From b7215198e2a06c15fc1be2a27706fbe313056a8a Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 28 Jul 2026 08:36:27 -0500 Subject: [PATCH 05/22] Split the implementation into two phases Phase 1 delivers the consistency fix at second order: the control-volume form, the sloping-interface integral the centered scheme omits, the equation-of-state expansion shared across each edge, and a linear mean-preserving reconstruction of temperature and salinity in pressure. Phase 2 adds the parabolic reconstruction and the wide horizontal stencil that reach fourth order. Mark the phase each part of the formulation belongs to, and record what each phase delivers, depends on, and leaves open. Resolve two things the phase split exposed. The horizontal reconstruction of section 3.6 as previously written would have interpolated temperature and salinity to the edge and formed alpha*p there, which does not belong to any control volume and would give up the cancellation; require instead that the wide stencil be a weighted sum of two-column pair contributions. And require the vertical reconstruction to recover its own degree exactly on non-uniform layer thicknesses, without which the exact set does not hold. Keep constant in-layer specific volume as a verification-only setting so the reduction to the centered scheme survives as a permanent regression test. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 416 +++++++++++++----- 1 file changed, 317 insertions(+), 99 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index f7fcd819f7ef..551e608c8000 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -65,6 +65,34 @@ therefore answer two different questions and both must be satisfied — *is the (convergence rate at the designed order) and *is it useful at the resolutions we can run?* (absolute error). +### 1.1 Why this work is delivered in two phases + +Realistic global configurations run with `PressureGradCentered` show spurious flow in the +bottom layer over sloping bathymetry, large enough to drive numerical instability. What is +missing there is not high-order accuracy — it is *consistency*: the centered scheme does not +account for the pressure force on a layer's sloping top and bottom interfaces at all, and the +resulting error accumulates downward through the column (§3.7.3). That error is present at +second order and does not require a fourth-order scheme to remove. + +The work is therefore split so the consistency fix can be delivered and tested on its own: + +- **Phase 1 — a consistent second-order scheme.** The finite-volume control-volume form, + the sloping-interface integral, the equation-of-state expansion about a state shared across + each edge, and a mean-preserving *linear* reconstruction of $\Theta$ and $S$ in pressure. + The horizontal operator is the same two-cell stencil the centered scheme already uses, so + the scheme remains second order in the horizontal. What Phase 1 buys is the robustness + property of Requirement 2.3: the pressure gradient is zero to machine precision for any + resting ocean whose profile varies linearly with pressure, no matter how the layers tilt. +- **Phase 2 — fourth order.** A parabolic vertical reconstruction and a wider horizontal + stencil, plus the option of a second-order equation-of-state expansion. This raises the + order of accuracy; it does not change the robustness property, which Phase 1 already + establishes and Phase 2 must preserve. + +The two phases share one implementation, one set of configuration options, and one test +suite; Phase 2 widens settings that Phase 1 puts in place. Section 3 marks which parts of +the formulation belong to which phase, and §4.5 records what each phase delivers and what it +depends on. + ## 2 Requirements ### 2.1 Requirement: Higher accuracy than the centered scheme at affordable resolution @@ -130,8 +158,10 @@ of $\Theta$, $S$, $p$, or $z$. The high-order scheme must be selectable at runtime through the existing `PressureGrad` configuration group and `PressureGradType` enum, leaving `Centered` as the default. Its -sub-options (horizontal reconstruction order, vertical-reconstruction mode, quadrature) must -be configurable, and the centered scheme must be recoverable as the lowest-order limit. +sub-options (edge stencil width, vertical-reconstruction mode, quadrature) must be configurable, +and the centered scheme must be recoverable as a configuration of the new one. The two phases must +share one set of configuration keys, so that a configuration written for Phase 1 continues to work +unchanged when Phase 2 lands. ### 2.6 Requirement: Verified order of accuracy @@ -321,59 +351,119 @@ Adcroft-style analytic integration to TEOS-10. ### 3.4 Mean-preserving vertical reconstruction Within layer $k$ of column $i$ we reconstruct the conservative temperature and absolute -salinity as +salinity as deviations from the prognostic layer means, $$ -\Theta(\tilde z) = \Theta_{i,k} + \Theta'_{i,k}(\tilde z), \qquad -S(\tilde z) = S_{i,k} + S'_{i,k}(\tilde z), +\Theta(p) = \Theta_{i,k} + \Theta'_{i,k}(p), \qquad +S(p) = S_{i,k} + S'_{i,k}(p), $$ (vert-recon) -where $\Theta'_{i,k}$, $S'_{i,k}$ are parabolic (PPM-style) deviations built from the -neighboring layer means and constrained to **integrate to zero over the layer** -($\int_{\tilde z_k^{\text{bot}}}^{\tilde z_k^{\text{top}}} \Theta'_{i,k}\, d\tilde z = 0$). -This mean-preserving property (Requirement 2.4) guarantees the PGF uses the same layer-mean -state as the rest of the model; the reconstruction only supplies the smoother sub-layer -shape needed to integrate $\alpha p$ to high order. The "constant density within a layer" -assumption of an isopycnal model is recovered exactly by the degenerate choice -$\Theta'_{i,k} = S'_{i,k} = 0$, which is available as the cheapest configuration. +where the deviations are polynomials in pressure built from the neighboring layer means and +constrained to **integrate to zero over the layer** +($\int_{p_{i,k}^{\text{top}}}^{p_{i,k}^{\text{bot}}} \Theta'_{i,k}\, dp = 0$). Because pressure +and $\tilde z$ differ within a column only by a fixed linear map [](#p-linear), a polynomial in +one is a polynomial of the same degree in the other; pressure is used here because it is the +variable in which the profiles of two neighboring columns can be compared (§3.7). + +The mean-preserving property (Requirement 2.4) guarantees the PGF uses the same layer-mean state +as the rest of the model; the reconstruction only supplies the sub-layer shape needed to integrate +$\alpha p$. + +**Phase 1 uses linear deviations; Phase 2 uses parabolic (PPM-style) ones.** The degree sets the +scheme's exact set in §3.7.3 directly: linear deviations make the scheme exact for profiles that +vary linearly with pressure, parabolic ones for profiles that vary quadratically. + +That correspondence only holds if the reconstruction actually reproduces those profiles, which +places two requirements on how the deviations are built: + +- **The estimator must be exact on a non-uniform vertical grid.** Omega's layers are not of equal + thickness, and a slope or curvature formula derived assuming equal thickness will not recover a + linear profile exactly when they are not. The estimator must be built from the layer means and + the actual interface pressures, and must return the exact slope (Phase 1) or slope and curvature + (Phase 2) when the underlying profile is of that degree, for any distribution of layer + thicknesses. This is testable directly and is part of the unit test in §5.2. +- **Any limiter must be inactive on such profiles.** Monotonicity limiters are not required by the + PGF and are not applied by default here, since the reconstruction feeds an integral rather than + an advective flux. If one is later added for robustness, it must leave smooth monotone data + untouched, or it will break the cancellation of §3.7.2 precisely where the profile is well + resolved. + +The isopycnal-model assumption of constant properties within a layer is the degenerate choice +$\Theta'_{i,k} = S'_{i,k} = 0$. This is retained as a **verification-only** configuration — it is +what makes the reduction to the centered scheme in §3.9 possible, and it isolates compressibility +on its own in §5.2 — but it is not a supported production setting in either phase, because it +gives up the exactness for linearly varying profiles that Requirement 2.3.3 asks for. ### 3.5 Analytic layer integral of the side-wall term -Combining [](#p-linear), [](#alpha-taylor), and [](#vert-recon), the side-wall integrand -$\alpha p$ in a single column/layer is a polynomial in $\tilde z$: with first-order $\alpha$ -and parabolic $\Theta', S'$, $\alpha$ is parabolic and $p$ is linear, so $\alpha p$ is cubic -and is integrated **exactly** by a two-point Gauss-Legendre rule over the layer: +Combining [](#p-linear), [](#alpha-taylor), and [](#vert-recon), the side-wall integrand $\alpha p$ +within a single column and layer is a polynomial in pressure. With the first-order equation-of-state +expansion, $\alpha$ inherits the degree of the reconstruction: linear in Phase 1, parabolic in +Phase 2. Multiplying by $p$ gives a quadratic (Phase 1) or cubic (Phase 2) integrand, and in both +cases the layer integral $$ -\Pi_{i,k} \equiv \int_{\tilde z_k^{\text{bot}}}^{\tilde z_k^{\text{top}}} \alpha\, p \; d\tilde z -\;=\; \tilde h_{i,k} \sum_{q} w_q \, \alpha\!\left(\tilde z_q\right) p\!\left(\tilde z_q\right), +\Pi_{i,k} \equiv \frac{1}{g}\int_{p_{i,k}^{\text{top}}}^{p_{i,k}^{\text{bot}}} \alpha\, p \; dp +\;=\; \frac{\Delta p_{i,k}}{g} \sum_{q} w_q \, \alpha\!\left(p_q\right) p\!\left(p_q\right), $$ (sidewall-int) -with Gauss nodes $\tilde z_q$ and weights $w_q$ on the layer, and $\alpha(\tilde z_q)$, -$p(\tilde z_q)$ from [](#alpha-taylor) and [](#p-linear). No TEOS-10 calls occur inside the -sum. The quadrature order is configurable and is matched to the reconstruction so the -integral is exact for the reconstructed polynomial. +is evaluated **exactly** by a two-point Gauss–Legendre rule, which is exact through cubic. The nodes +$p_q$ and weights $w_q$ are on the layer's pressure interval, and $\alpha(p_q)$ comes from +[](#alpha-taylor). No TEOS-10 calls occur inside the sum. + +The quadrature is configurable, but it is not a free accuracy knob: it must be **at least** exact for +the reconstructed integrand, or condition 2 of §3.7.2 fails and the cancellation is lost. Raising it +beyond that changes nothing, since the integrand is a polynomial of known degree. Lowering it — to +midpoint, say — is meaningful only as the verification configuration of §3.9. -### 3.6 Horizontal reconstruction and the edge gradient +### 3.6 The edge operator -The discrete tendency lives at edge $e$ and is the edge-normal projection of the PGF. The -side-wall line integral $\int_{\partial A}(\cdots)\,dl$ in [](#ho-target) becomes, on the -TRiSK C-grid, the difference of the two adjacent columns' face contributions across the -edge, divided by the cell-center distance $d_e$: +The discrete tendency lives at edge $e$ and is the edge-normal projection of the PGF. The side-wall +line integral $\int_{\partial A}(\cdots)\,dl$ in [](#ho-target) becomes, on the TRiSK C-grid, the +difference of the two adjacent columns' contributions across the edge, divided by the cell-center +distance $d_e$: $$ -\left[\nabla_n \Pi\right]_{e,k} = \frac{1}{d_e}\sum_{i \in CE(e)} -n_{e,i}\, \widehat{\Pi}_{i,k}, +\left[\nabla_n \Pi\right]_{e,k} = \frac{1}{d_e}\sum_{i \in CE(e)} -n_{e,i}\, \Pi_{i,k}^{(e)}, $$ (edge-grad) -where $\widehat\Pi_{i,k}$ is the column integral [](#sidewall-int) reconstructed to the edge. -To reach fourth order, $\Theta$, $S$ (and hence $\alpha$ and $\Pi$) are reconstructed from -cell centers to the edge with a **cubic** reconstruction consistent with the TRiSK edge -stencils used elsewhere in Omega (the same neighborhood used for high-order tracer -reconstruction; cf. the third-order interface reconstruction noted at -{ref}`omega-design-governing-eqns-omega1` §10, White & Adcroft 2008). The lowest-order limit -(two-cell, centered) reproduces the operator already used by `PressureGradCentered`. We do -**not** assume anything constant across the edge — the horizontal density contrast between -adjacent columns is fully reconstructed. +where $\Pi_{i,k}^{(e)}$ is column $i$'s layer integral [](#sidewall-int) evaluated with the +equation-of-state coefficients shared across edge $e$ [](#edge-ref). **Phase 1 uses this operator as +written** — the same two-cell stencil `PressureGradCentered` uses, so the horizontal accuracy is +unchanged from today. Everything Phase 1 gains is in the vertical and in the interface terms. + +Nothing is assumed constant across the edge: the horizontal contrast in $\Theta$ and $S$ between the +two columns enters at full strength through the two column integrals. What Phase 1 does *not* do is +raise the order of the horizontal difference, which is Phase 2's job. + +#### 3.6.1 Raising the horizontal order without losing the cancellation (Phase 2) + +The natural way to reach fourth order — reconstruct $\Theta$ and $S$ from cell centers to the edge +with a cubic stencil, then form $\alpha p$ there — **would forfeit the robustness property of §3.7**. +It is worth being explicit about this, because it is the approach a reader would reasonably assume. +The cancellation is a statement about a *pair* of columns bounding one control volume; a quantity +interpolated to the edge from four or more cells does not belong to any control volume, and there is +no reason for the pressure and geopotential terms built from it to balance. Accuracy at the cell +centers does not carry over to a cancellation at the edge between them (assumption A1, §3.7.6). + +The constraint Phase 2 must satisfy instead is: + +> The higher-order edge operator must be expressible as a **weighted sum of two-column pair +> contributions**, each pair built exactly as in Phase 1 — with its own shared expansion point and +> its own control volume. + +Because each pair contribution is individually zero for a resting ocean in the exact set, any +weighted sum of them is zero as well, and the machine-precision property is inherited rather than +re-derived. A fourth-order edge-normal difference built from the nearest and next-nearest cells +along the normal, with each cell pair contributing its own Phase 1 integral, satisfies this; a +scheme that reconstructs to the edge first does not. + +Constructing such a stencil on Omega's unstructured TRiSK mesh is the **principal open design +question of Phase 2** and is deliberately not settled here. The relevant machinery — the wider edge +neighborhoods used for high-order tracer reconstruction, cf. +{ref}`omega-design-governing-eqns-omega1` §10 and White & Adcroft (2008) — exists, but its accuracy +on variable-resolution meshes and the cost of the extra pair evaluations both need assessment before +the form is fixed. Phase 1 does not depend on the answer. ### 3.7 Where the cancellation is exact, and where it is not @@ -384,10 +474,10 @@ and must therefore test. It does *not* rely on subtracting a background profile. #### 3.7.1 Why "uniform $\Theta$ and $S$" is the wrong condition -An earlier draft of this design required the scheme to return zero whenever the layer means -$\Theta_{i,k}$, $S_{i,k}$ are the same in both cells of an edge, for any tilt and any vertical -profile. **That requirement cannot be met, and asking for it would send the implementation chasing -an impossible target.** +The natural way to state the robustness property is to require the scheme to return zero whenever +the layer means $\Theta_{i,k}$, $S_{i,k}$ are the same in both cells of an edge, for any tilt and +any vertical profile. **That requirement cannot be met, and asking for it would send the +implementation chasing an impossible target.** When coordinate surfaces tilt relative to surfaces of constant pressure, layer $k$ in one column and layer $k$ in its neighbor cover *different pressure ranges*. Each column builds its own @@ -601,26 +691,46 @@ they complete the force balance on the layer's control volume (§3.1.1). ### 3.9 Reduction to the centered scheme -As a consistency check, the high-order scheme collapses to the implemented -`PressureGradCentered` form -($T^p_{e,k} = -\nabla M + \tfrac12(p_0+p_1)\nabla\alpha - \nabla\Phi$, with -$M = \alpha p + g z$) in the joint limit of: constant in-layer reconstruction -($\Theta' = S' = 0$, §3.4), midpoint quadrature in place of [](#sidewall-int), and two-cell -centered horizontal differencing (§3.6). This guarantees the new code reproduces the existing -scheme in its lowest-order configuration and provides a direct path for regression testing. +The new scheme collapses to the implemented `PressureGradCentered` form +($T^p_{e,k} = -\nabla M + \tfrac12(p_0+p_1)\nabla\alpha - \nabla\Phi$, with $M = \alpha p + g z$) +in one configuration: **specific volume constant within each layer**, meaning both +$\Theta' = S' = 0$ and the equation-of-state expansion [](#alpha-taylor) truncated to $\alpha_0$, +combined with the two-cell edge operator [](#edge-grad). This is the isopycnal-model assumption, +and it is the verification-only mode of §3.4. + +Two things fall out of that configuration that are worth noting, because they show the reduction is +structural rather than a special case bolted on: + +- With $\alpha$ constant in the layer, $\alpha p$ is linear in pressure, so the sloping-interface + average [](#metric-divdiff) reduces *exactly* to the average of the two cells' interface values. + The interface term does not need to be switched off to recover the centered scheme; it degenerates + on its own. +- For the same reason, the layer integral [](#sidewall-int) is exact under any symmetric quadrature + rule, midpoint included, so the quadrature setting does not enter the reduction either. + +What remains is the Montgomery-potential algebra, and the two forms agree. This gives a direct +regression path (§5.5) and confirms the new code reproduces the existing scheme where it should. +The agreement is algebraic, not bit-for-bit — the operations are performed in a different order +(§4.4). ### 3.10 Per-step algorithm summary +Steps 1–3 are per cell and layer; step 4 is per edge and layer. Phase differences are marked. + 1. From `VertCoord`: read `PressureInterface`, `PressureMid`, `GeomZInterface`/`GeomZMid`, - geopotential, and interface pseudo-heights (already computed diagnostically each step). -2. Per cell-layer: obtain $\alpha_0$ (= existing `Eos::SpecVol`) and the derivatives - $\alpha_\Theta, \alpha_S, \alpha_p$ from one TEOS-10 evaluation ([](#alpha-derivs)). -3. Per cell-layer: build mean-preserving PPM deviations $\Theta', S'$ ([](#vert-recon)). -4. Per edge-layer: reconstruct edge quantities (cubic, §3.6) using interface locations and - quadrature nodes shared by the pressure and geopotential terms (the discrete hydrostatic - consistency requirement, §3.7); evaluate the analytic layer integral [](#sidewall-int), - the geopotential gradient, and the metric terms (§3.8); assemble $T^p_{e,k}$ and accumulate - into the tendency with `EdgeMask`. + geopotential, and interface pseudo-heights (already computed diagnostically each step). The + geometric height must satisfy condition 3 of §3.7.2; see the prerequisite in §3.7.4. +2. Obtain $\alpha_0$ (= the existing `Eos::SpecVol` field) and the derivatives + $\alpha_\Theta, \alpha_S, \alpha_p$ from one TEOS-10 evaluation ([](#alpha-derivs)). Both phases + need all four; Phase 2 optionally adds second derivatives (§3.3). +3. Build the mean-preserving deviations $\Theta', S'$ ([](#vert-recon)) — **linear in Phase 1, + parabolic in Phase 2** — using the actual non-uniform interface pressures (§3.4). +4. For each edge: form the shared expansion point [](#edge-ref) from the two adjacent cells; + evaluate each column's layer integral [](#sidewall-int) with those shared coefficients; add the + sloping-interface terms [](#metric-divdiff) and the geopotential difference (§3.8); assemble + $T^p_{e,k}$ and accumulate into the tendency with `EdgeMask`. **Phase 1** uses the two-cell + operator [](#edge-grad); **Phase 2** uses the wider stencil of §3.6.1, built as a weighted sum of + such two-cell pair contributions. ## 4 Design @@ -646,19 +756,34 @@ enum class PressureGradType { }; ``` -New sub-options for the high-order scheme: +New sub-options for the high-order scheme. Both phases use the same keys; Phase 2 adds values +rather than keys, so no configuration written for Phase 1 needs to change when Phase 2 lands: ```yaml PressureGrad: PressureGradType: 'FiniteVolume' # Centered | FiniteVolume - ReconstructionOrder: 4 # horizontal cell->edge order (2 = centered limit) - VerticalReconstruction: 'ppm' # 'constant' (isopycnal limit) | 'ppm' + HorzOrder: 2 # 2 = two-cell stencil (Phase 1); 4 = wide stencil (Phase 2) + VerticalReconstruction: 'linear' # 'linear' (Phase 1) | 'ppm' (Phase 2) + # | 'constant' (verification only, see below) QuadraturePoints: 2 # per-layer Gauss points for the side-wall integral ``` -The fourth-order target is `ReconstructionOrder: 4` with parabolic (`ppm`) vertical -reconstruction. The centered scheme is recovered by `ReconstructionOrder: 2` and -`VerticalReconstruction: 'constant'` (§3.9). +- **Phase 1 default and target:** `HorzOrder: 2`, `VerticalReconstruction: 'linear'`. +- **Phase 2 target:** `HorzOrder: 4`, `VerticalReconstruction: 'ppm'`. +- `QuadraturePoints: 2` is exact for the integrand in both phases (§3.5) and should not normally be + changed. It is a knob because lowering it is needed for the verification configuration below, not + because raising it buys accuracy. + +`VerticalReconstruction: 'constant'` sets the specific volume constant within each layer — both +$\Theta' = S' = 0$ and the equation-of-state expansion truncated to $\alpha_0$. It is **verification +only**: combined with `HorzOrder: 2` it recovers `PressureGradCentered` (§3.9) and supports the +permanent regression test of §5.5, and it isolates compressibility in §5.2. It is not a supported +production setting, because it gives up the exactness for linearly varying profiles that +Requirement 2.3.3 asks for. The implementation should log a warning if it is selected outside a +test. + +`HorzOrder` selects the width of the edge *stencil* — how many cell pairs contribute — not the order +of an interpolation of $\Theta$ and $S$ onto the edge. The distinction is not cosmetic; see §3.6.1. #### 4.1.2 New EOS support @@ -706,11 +831,28 @@ KOKKOS_FUNCTION void operator()(const Array2DReal &Tend, I4 IEdge, I4 KChunk, const; ``` -(The existing centered signature is unchanged.) Additional cached members hold the cubic -edge-reconstruction stencil and weights. The functor implements §3.3–§3.8 per edge and -vertical chunk — sharing interface locations and quadrature nodes between the pressure and -geopotential terms to satisfy discrete hydrostatic consistency (§3.7) — accumulating into -`Tend` with `EdgeMask`, exactly as the centered functor does. +(The existing centered signature is unchanged.) Additional cached members hold the quadrature nodes +and weights and, in Phase 2, the wide-stencil cell lists and weights. The functor implements +§3.3–§3.8 per edge and vertical chunk, accumulating into `Tend` with `EdgeMask`, exactly as the +centered functor does. + +Two aspects of the loop structure follow from §3.3.1 and are worth stating here, because they differ +from the obvious implementation: + +- **The layer integral is computed inside the edge loop, not cached per cell.** Both adjacent + columns' integrals [](#sidewall-int) use equation-of-state coefficients formed at the edge + [](#edge-ref), so the same cell yields a different integral at each of its edges. The per-cell + quantities that *can* be cached are the four EOS coefficients and the reconstruction slopes, which + is where the TEOS-10 cost lives; the per-edge work is polynomial arithmetic on those cached + values. This is what keeps Requirement 2.2 satisfied despite roughly three times as many integral + evaluations on a hexagonal mesh. +- **Phase 2's wide stencil is a loop over cell pairs, not a wider interpolation.** Each pair + contributes a complete Phase 1 evaluation with its own shared expansion point, and the pair + results are combined with the stencil weights (§3.6.1). Implementing Phase 2 as a wider + reconstruction feeding a single evaluation would be simpler and would break the property of §3.7. + +The Phase 1 and Phase 2 code paths differ only in the reconstruction degree (§3.4) and in whether +the pair loop has one entry or several. There is one functor, not two. ### 4.2 Methods @@ -784,6 +926,55 @@ default and has served out its period as the reference implementation. That is d left as **follow-up work**, to be taken up as a separate, answer-changing change with its own baseline step — not as part of this design. +### 4.5 What each phase delivers and depends on + +#### 4.5.1 Phase 1 — a consistent second-order scheme + +**Delivers.** The finite-volume control-volume form (§3.1.1); the sloping-interface integral +(§3.8), which the centered scheme omits entirely; the equation-of-state expansion about a state +shared across each edge (§3.3.1); mean-preserving linear reconstruction of $\Theta$ and $S$ in +pressure (§3.4). The result is a pressure gradient that is zero to machine precision for any +resting ocean whose profile varies linearly with pressure, at any tilt, thickness, or bathymetry +(§3.7.3) — Requirement 2.3 in full. + +**Does not deliver.** Fourth-order accuracy. The horizontal operator is the same two-cell stencil +in use today (§3.6), so horizontal truncation error is unchanged from `PressureGradCentered`. +Requirements 2.1 and 2.6 are met at second order only. + +**Depends on.** The `VertCoord` geopotential decision of §3.7.4, which must be settled *before* +implementation starts — the machine-precision property is unreachable without it, and option 1 (the +recommendation) is answer-changing and needs its own baseline step. Nothing else in Phase 1 depends +on unresolved questions. + +**Code and cost.** Three new `Eos` derivative fields and one new method (§4.1.2); the +`PressureGradHighOrder` functor; no new TEOS-10 evaluations per cell and layer (Requirement 2.2), +with roughly three times as many polynomial layer integrals on a hexagonal mesh (§4.1.3). + +#### 4.5.2 Phase 2 — fourth order + +**Delivers.** Parabolic vertical reconstruction (§3.4), widening the exact set to profiles that vary +quadratically with pressure; a wide horizontal stencil (§3.6.1); optionally a second-order +equation-of-state expansion (§3.3). Requirements 2.1 and 2.6 at fourth order. + +**Must preserve.** Everything Phase 1 establishes. In particular the machine-precision property must +survive the wider stencil, which is why §3.6.1 constrains that stencil to be a weighted sum of +two-column pair contributions rather than a reconstruction to the edge. The §5.2 gate is rerun +unchanged for Phase 2. + +**Open question.** The form of the wide stencil on Omega's unstructured, variable-resolution TRiSK +mesh is not settled by this design (§3.6.1). Resolving it — including the cost of the additional +pair evaluations — is the first task of Phase 2 and does not block Phase 1. + +#### 4.5.3 Suggested order of work + +1. Settle the `VertCoord` geopotential question (§3.7.4) and take the baseline step it requires. +2. Run the assumption-A4 diagnostic of §5.3, which uses the *existing* centered scheme and so can be + done immediately and in parallel with step 1. If spurious bottom-layer flow survives a profile + that Phase 1 would resolve exactly, the cause is elsewhere in the model and the priority of this + work should be reconsidered before it is built. +3. Implement and verify Phase 1 against §5.1, §5.2, §5.3, and §5.5. +4. Take up Phase 2, starting from the stencil question in §3.6.1. + ## 5 Verification and Testing Testing reuses and extends the Polaris `horiz_press_grad` task family @@ -799,52 +990,67 @@ the scheme helps at the resolutions Omega can afford, and a **measured order of (Requirement 2.6), which verifies that the implementation is the scheme this design describes. Neither substitutes for the other, and both must pass. +Which tests gate which phase: + +| Test | Phase 1 | Phase 2 | +|---|---|---| +| §5.1 Two-column convergence | gates, at second order | gates, at fourth order | +| §5.2 Machine-precision cancellation | gates | rerun unchanged; must still pass | +| §5.3 Seamount resting state | gates | rerun; error should drop further | +| §5.4 Overflow | gates | rerun | +| §5.5 Reduction to centered | gates | rerun unchanged | + +The A4 diagnostic within §5.3 is run *before* Phase 1 implementation and uses the existing centered +scheme, so it gates nothing but informs whether the work should proceed as prioritized (§4.5.3). + ### 5.1 Test: Two-column HPGA convergence (extend existing) Extend the four existing variants — `temperature_gradient`, `salinity_gradient`, -`surface_pressure_gradient`, `ztilde_gradient` — to run the centered scheme and the new -scheme at two orders: +`surface_pressure_gradient`, `ztilde_gradient` — to run the centered scheme alongside the new one: - **Scheme selection.** Add `PressureGrad: { PressureGradType: FiniteVolume, … }` to `forward.yaml` and parametrize each task over three configurations: - `centered` — the legacy `PressureGradCentered` functor, unchanged; - - `finite_volume_order4` — `ReconstructionOrder: 4`, `VerticalReconstruction: ppm` (the - target); - - `finite_volume_order2` — the same code in its centered limit (`ReconstructionOrder: 2`, - `VerticalReconstruction: constant`, midpoint quadrature). + - `finite_volume_phase1` — `HorzOrder: 2`, `VerticalReconstruction: linear`; + - `finite_volume_phase2` — `HorzOrder: 4`, `VerticalReconstruction: ppm` (added when Phase 2 + lands). - (These variant names are provisional; the final spelling follows Polaris' naming conventions - and is settled on the Polaris side. What matters here is that the last two are the *same* + (These variant names are provisional; the final spelling follows Polaris' naming conventions and + is settled on the Polaris side. What matters here is that the last two are the *same* implementation at two orders, distinct from the legacy functor.) - The third configuration exists because the order-2 verification gate below must exercise the - *new* implementation. Running the legacy functor under a "second order" label would measure - the convergence of code this design does not change, and would leave the new code's - lowest-order path unverified. It also supplies the round-off comparison of §5.5 at every - resolution rather than at a single configuration. The forward step still runs a single time - step with only `PressureGradTendencyEnable: true`, reading the PGF acceleration from - `NormalVelocityTend`. + `finite_volume_phase1` is not a stand-in for the legacy scheme: it is second order in the + horizontal like `centered`, but it is *consistent*, so its absolute error should be markedly + lower even though its convergence slope is the same. Both must be run, and the comparison between + them is the clearest single measure of what Phase 1 buys. Running only the legacy functor under a + "second order" label would measure the convergence of code this design does not change and leave + the new code's Phase 1 path unverified. + + The forward step still runs a single time step with only `PressureGradTendencyEnable: true`, + reading the PGF acceleration from `NormalVelocityTend`. - **Reference.** `reference.py`/`analysis.py` compare `NormalVelocityTend` against the layer-mean analytic HPGA (unchanged). For the high-order scheme the layer-mean comparison remains the correct target, since the scheme is a finite-volume, layer-averaged discretization. - **Accuracy gate (new, Requirement 2.1):** at a representative coarse resolution (e.g. the coarsest in `horiz_resolutions`), the absolute RMS HPGA error vs. the reference must be below - a tolerance, **and** the high-order RMS error must be below the centered RMS error at that - same resolution (the scheme must demonstrably help where it matters). + a tolerance, **and** the new scheme's RMS error must be below the centered RMS error at that + same resolution (the scheme must demonstrably help where it matters). This gate applies to + Phase 1, where it is the primary measure of value, since Phase 1 does not change the + convergence slope. - **Verification gate (Requirement 2.6):** the measured slope of RMS error vs. resolution, `omega_vs_reference_convergence_rate_*`, must fall within a band around the configured order - of accuracy — nominally ~4 for `finite_volume_order4` and ~2 for `finite_volume_order2` - (and for `centered`, whose band is unchanged from today). This band is retuned from its + of accuracy — nominally ~2 for `finite_volume_phase1` and for `centered` (whose band is + unchanged from today), and ~4 for `finite_volume_phase2`. This band is retuned from its present values rather than loosened; a slope outside it fails the test and is treated as an implementation defect to be diagnosed, not as a tolerance to be widened. -- **Asymptotic range (implementation-time task):** it is not yet established that the existing - `horiz_resolutions` sweep spans a range where a fourth-order slope is cleanly measurable — - the sweep may be too coarse to have entered the asymptotic regime at its fine end, or fine - enough that the reference solution's own quadrature error and roundoff contaminate the slope. - Determining the usable window, and extending or tightening the sweep (and, if needed, the - order of the Gauss quadrature in `reference.py`) so the designed order can be resolved, is - part of implementing this test. +- **Asymptotic range (Phase 2 implementation-time task):** it is not yet established that the + existing `horiz_resolutions` sweep spans a range where a fourth-order slope is cleanly + measurable — the sweep may be too coarse to have entered the asymptotic regime at its fine end, + or fine enough that the reference solution's own quadrature error and roundoff contaminate the + slope. Determining the usable window, and extending or tightening the sweep (and, if needed, the + order of the Gauss quadrature in `reference.py`) so the designed order can be resolved, is part + of implementing Phase 2. Phase 1's second-order slope is measurable on the existing sweep. - **Consistency check (retained):** `omega_vs_polaris_rms_threshold` (~1e-10 m/s²) — Omega's forward output must still match the Python-computed HPGA, confirming the implementation matches the intended discretization. @@ -880,6 +1086,13 @@ Three groups of profiles are run: Both must *fail* the machine-precision check. Without these, a passing result could just as easily come from a symmetry of the test setup as from the scheme being right. +A separate and much smaller unit test covers the reconstruction estimator on its own (§3.4): given +layer means sampled from a profile of the reconstruction's own degree on a **deliberately +non-uniform** set of layer thicknesses, the recovered slope (Phase 1) or slope and curvature +(Phase 2) must match the exact values to round-off. This is worth testing separately because it is +the most likely place for the machine-precision gate above to fail, and it localizes the failure +immediately. + The test is also run in a single-precision build, to measure the round-off floor of §3.7.5 and settle whether the perturbation form is needed. @@ -916,10 +1129,15 @@ attributable to PGF error is reduced relative to the centered scheme. This tests ### 5.5 Test: Reduction to the centered scheme (permanent regression) -Configure the high-order option in its lowest-order limit (§3.9: -`ReconstructionOrder: 2`, `VerticalReconstruction: constant`, midpoint quadrature) and confirm -it reproduces `PressureGradCentered` to round-off on the two-column test. This guards -Requirement 2.5 and protects the existing default during refactoring. +Configure the new scheme in the verification-only mode of §3.9 — `HorzOrder: 2`, +`VerticalReconstruction: constant` — and confirm it reproduces `PressureGradCentered` to round-off +on the two-column test. This guards Requirement 2.5 and protects the existing default during +refactoring. The test is established with Phase 1 and rerun unchanged for Phase 2, where it also +confirms the wider stencil collapses correctly to the two-cell one. + +Note that this configuration is not a supported production setting (§4.1.1); it exists so that this +comparison is possible. Keeping it costs one branch in the reconstruction and one in the +equation-of-state expansion. This test is retained permanently rather than treated as a one-time transition check, and that choice is the reason `PressureGradCentered` is kept as a separate implementation rather From 6a23d5e86d3b258e02075a4044594326861950f7 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 28 Jul 2026 09:06:10 -0500 Subject: [PATCH 06/22] Say what each test covers and close three gaps Give every test an explicit statement of the requirements, table rows and assumptions it exercises, and add a coverage summary. Three things had no test. The adequacy of the equation-of-state expansion across an edge now gets a horizontal-contrast sweep in the two-column task, confirmed under dynamics by the overflow task. The vorticity question gets a diagnostic in the seamount task. The bound on TEOS-10 evaluations gets an instrumented count that must not change with quadrature points or stencil width. Also correct the seamount setup description: a stratification that is a function of pressure alone gives layer means that differ between columns where layers tilt, which is the situation the test needs, not the horizontally uniform means the earlier text asked for. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 105 +++++++++++++++--- 1 file changed, 92 insertions(+), 13 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 551e608c8000..c2517c546809 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -999,6 +999,7 @@ Which tests gate which phase: | §5.3 Seamount resting state | gates | rerun; error should drop further | | §5.4 Overflow | gates | rerun | | §5.5 Reduction to centered | gates | rerun unchanged | +| §5.6 Cost check | gates | gates; stencil width must not change the EOS count | The A4 diagnostic within §5.3 is run *before* Phase 1 implementation and uses the existing centered scheme, so it gates nothing but informs whether the work should proceed as prioritized (§4.5.3). @@ -1054,11 +1055,20 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient - **Consistency check (retained):** `omega_vs_polaris_rms_threshold` (~1e-10 m/s²) — Omega's forward output must still match the Python-computed HPGA, confirming the implementation matches the intended discretization. +- **Horizontal-contrast sweep (new, assumption A2):** the `temperature_gradient` and + `salinity_gradient` variants are run at several amplitudes of the horizontal contrast, up to and + beyond values typical of ocean fronts. The equation-of-state expansion [](#alpha-taylor) is taken + about a state shared across the edge, so its error grows with that contrast, and A2 (§3.7.6) is + the assumption that the first-order expansion remains adequate. **Pass:** the error at fixed + resolution grows no faster than linearly with the contrast amplitude, and repeating the largest + amplitude with the second-order expansion of §3.3 changes the answer by less than the accuracy + gate above. If it does not, the second-order expansion becomes the default rather than an option. - **Cfg keys.** New keys mirror the existing ones (`horiz_press_grad.cfg`): a coarse-resolution - absolute tolerance, a `finite_volume_vs_centered` ratio gate, and per-scheme expected-rate - bands. + absolute tolerance, a `finite_volume_vs_centered` ratio gate, per-scheme expected-rate bands, and + the contrast amplitudes for the sweep. -Tests Requirements 2.1, 2.2 (via the bounded-EOS implementation exercised), 2.4, 2.5, 2.6. +**Covers:** Requirements 2.1, 2.2 (the bounded-EOS path is exercised), 2.4, 2.5, 2.6; the last row +of the §3.7.3 table (horizontal structure in $\Theta$, $S$); assumptions A1, A2, A3. ### 5.2 Unit test: Discrete hydrostatic consistency (exact resting state) @@ -1101,13 +1111,17 @@ until whichever resolution is chosen there is in place; this test therefore doub acceptance criterion for that prerequisite. It is implemented as a fast C++ unit test and also run as a configuration of the Polaris two-column task. +**Covers:** Requirement 2.3 in full; rows 1–5 of the §3.7.3 table; the round-off floor of §3.7.5. + ### 5.3 Test: Seamount resting state (steep-layer robustness) -Use the Polaris seamount task with tilted layers over a seamount and a horizontally uniform -$T$/$S$ stratification, integrated for a fixed period. **Pass:** the maximum spurious velocity -stays below a threshold and is substantially smaller for the high-order scheme than for the -centered scheme. This is the dynamical counterpart of §5.2 (the same resting state, now run -forward in the full solver) and the direct test of Requirement 2.3. +Use the Polaris seamount task with layers tilted over a seamount and a stratification that is a +function of pressure alone — note that this gives layer means that *differ* between neighboring +columns wherever the layers tilt (§3.7.1), which is the situation the test is meant to create. +Integrate for a fixed period. **Pass:** the maximum spurious velocity stays below a threshold and +is substantially smaller for the new scheme than for the centered scheme. This is the dynamical +counterpart of §5.2 — the same resting state, now run forward in the full solver — and the direct +test of Requirement 2.3. **Testing assumption A4 (§3.7.6).** Run the seamount case twice: once with a stratification Phase 1 resolves exactly ($\Theta$, $S$ linear in pressure) and once with a realistic profile. Spurious @@ -1119,13 +1133,36 @@ phasing, and it should be run **before** Phase 1 implementation is finished, wit scheme on the realistic profile as the control. A null result would not invalidate the design, but it would change its priority. +**Testing assumption A5 (§3.3.1).** Because the expansion point is shared per edge, the discrete PGF +is no longer exactly the gradient of a single scalar, and could in principle inject vorticity. Add a +diagnostic that takes the curl of the PGF tendency on this task. For a profile the scheme resolves +exactly it must be zero to machine precision, since the tendency itself is; that case is a +consistency check on the diagnostic rather than a test of A5. The test of A5 is the realistic +profile: **pass** if the resulting vorticity tendency is small compared with the physical vorticity +tendencies in the same run, and no larger than the corresponding quantity from the centered scheme. +If it is not, the shared expansion point needs to be revisited — for instance by holding it fixed +over a cell's edges at the cost of a weaker cancellation. + +**Covers:** Requirement 2.3 under dynamics; assumptions A3, A4, A5. + ### 5.4 Test: Overflow (full non-Boussinesq dynamics) -Use the Polaris overflow task to exercise the PGF within the full non-Boussinesq equations -with strongly sloping layers and active dynamics. **Pass:** the solution remains stable and -the down-slope evolution agrees with the reference behavior; spurious mixing/velocity -attributable to PGF error is reduced relative to the centered scheme. This tests Requirements -2.1 and 2.3 under realistic, coupled conditions. +Use the Polaris overflow task to exercise the PGF within the full non-Boussinesq equations with +strongly sloping layers and active dynamics. Unlike the seamount task, the state here is neither +resting nor close to a profile the scheme resolves exactly, so this is the test of how the scheme +behaves where none of the exact-cancellation results apply and the residual of §2.3.4 is all there +is. **Pass:** the solution remains stable and the down-slope evolution agrees with the reference +behavior; spurious mixing and velocity attributable to PGF error are reduced relative to the +centered scheme. + +This is also the most demanding test of assumption A2: the overflow front carries a large horizontal +temperature contrast across edges with steeply sloping layers, which is exactly where the shared +edge expansion point [](#edge-ref) is worked hardest. If the §5.1 contrast sweep indicates the +second-order equation-of-state expansion is needed, this task is where that judgment is confirmed +under dynamics. + +**Covers:** Requirements 2.1 and 2.3 under realistic, coupled conditions; the last two rows of the +§3.7.3 table; assumptions A2, A3. ### 5.5 Test: Reduction to the centered scheme (permanent regression) @@ -1139,6 +1176,48 @@ Note that this configuration is not a supported production setting (§4.1.1); it comparison is possible. Keeping it costs one branch in the reconstruction and one in the equation-of-state expansion. +**Covers:** Requirement 2.5; §3.9. + +### 5.6 Cost check + +Requirement 2.2 bounds the number of TEOS-10 evaluations, and nothing above tests it — the scheme +could satisfy every accuracy gate while quietly calling the equation of state inside the quadrature +loop. Two cheap checks close that: + +- **Evaluation count.** With an instrumented `Eos`, confirm the number of specific-volume + evaluations per time step is one per cell per layer and is **unchanged** when `QuadraturePoints` + and `HorzOrder` are varied. This is the property Requirement 2.2 actually states, and it is a + counter comparison, not a timing measurement, so it is deterministic and suitable for CI. +- **Wall time.** Record PGF kernel time relative to `PressureGradCentered` on a representative + configuration, as a performance regression guard. The expected cost is dominated by the per-edge + layer integrals (§4.1.3), roughly three times as many as a cell-based formulation on a hexagonal + mesh; a result far above that suggests the per-cell coefficients are being recomputed per edge + rather than cached. + +**Covers:** Requirement 2.2. + +### 5.7 Coverage summary + +| Requirement / assumption | Verified by | +|---|---| +| 2.1 Accuracy at affordable resolution | §5.1 accuracy gate; §5.3; §5.4 | +| 2.2 Bounded TEOS-10 cost | §5.6 | +| 2.3 Robustness for thin, sloped layers | §5.2 (machine precision); §5.3 (under dynamics) | +| 2.4 Consistency with model state | §5.1 (layer-mean reference); §5.2 (reconstruction unit test) | +| 2.5 Runtime-selectable, backward compatible | §5.1 (three configurations); §5.5 | +| 2.6 Verified order of accuracy | §5.1 verification gate | +| A1 Edge accuracy ≠ cell accuracy | §5.1 verification gate (Phase 2) | +| A2 EOS expansion adequate across an edge | §5.1 contrast sweep; §5.4 | +| A3 Residual small enough in practice | §5.1 accuracy gate; §5.3; §5.4 | +| A4 PGF error causes the instability | §5.3 diagnostic, run before Phase 1 completes | +| A5 Spurious vorticity negligible | §5.3 curl diagnostic | +| §3.7.4 `VertCoord` prerequisite | §5.2 (cannot pass until resolved) | +| §3.7.5 Round-off floor | §5.2, run in both precisions | + +Requirement 2.7 (extensibility) is not testable directly; it is addressed by the configuration +design of §4.1.1 and by the phase structure of §4.5, which is itself the evidence that the framework +extends without restructuring. + This test is retained permanently rather than treated as a one-time transition check, and that choice is the reason `PressureGradCentered` is kept as a separate implementation rather than reimplemented as the lowest-order configuration of `PressureGradHighOrder` (§4.4). The From bfe454d9d924929526c5dff21b0925df144ed38c Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 28 Jul 2026 09:11:56 -0500 Subject: [PATCH 07/22] Drop the vorticity discussion The claim that sharing the equation-of-state expansion point across an edge costs a potential-form property was wrong. In a general ALE coordinate the layers are neither isopycnal nor isobaric, so the pressure gradient force is not the gradient of a scalar to begin with and the centered scheme already carries the non-gradient term explicitly. Nothing is given up, so the discussion, the assumption it introduced, and the test for it are all removed rather than corrected. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index c2517c546809..539a92c6aae8 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -325,21 +325,12 @@ $$ (edge-ref) and **both** columns' contributions to edge $e$ are evaluated with this single set, so that the two sides of the edge see one and the same equation of state. -Two consequences must be recorded: - -- **Cost.** The column integral $\Pi_{i,k}$ is no longer a per-cell quantity that can be computed - once and then differenced across each of the cell's edges; it depends on the edge through - [](#edge-ref) and must be evaluated per edge, twice. On a hexagonal TRiSK mesh this is roughly - three times as many integral evaluations as a cell-based formulation. The TEOS-10 call count is - unaffected, which is the cost Requirement 2.2 binds; the extra work is polynomial arithmetic on - coefficients already in cache. -- **The PGF is no longer the gradient of a single scalar.** With the expansion point depending on - the edge, the discrete PGF is not exactly a discrete gradient, so it is not automatically - curl-free and could in principle inject spurious vorticity. It is zero at every edge for a resting - ocean the scheme resolves exactly, so nothing is injected in that case; elsewhere the effect - enters at truncation order. This trade is deliberate — a robustness property that holds exactly, - in exchange for a potential-form property that held exactly — but the magnitude of any spurious - vorticity is something §5 must measure rather than assume away. +This has a cost consequence worth recording. The column integral $\Pi_{i,k}$ is no longer a per-cell +quantity that can be computed once and then differenced across each of the cell's edges; it depends +on the edge through [](#edge-ref) and must be evaluated per edge, twice. On a hexagonal TRiSK mesh +this is roughly three times as many integral evaluations as a cell-based formulation. The TEOS-10 +call count is unaffected, which is the cost Requirement 2.2 binds; the extra work is polynomial +arithmetic on coefficients already in cache. Because $\Theta$, $S$ are reconstructed as low-order polynomials in $\tilde z$ (and across edges) and $p$ is linear in $\tilde z$ by [](#p-linear), the expansion [](#alpha-taylor) @@ -646,7 +637,6 @@ assumptions this design is making that only testing can confirm: A configuration whose profile falls in Phase 1's exact set gives a direct test: if spurious bottom-layer flow persists there, the cause lies elsewhere — most likely in the layer-mean treatment in the tracer and remapping operators (§4.3) — and Phase 1 will not cure it. See §5.3. -- **A5 — Spurious vorticity from the edge-shared expansion point is negligible** (§3.3.1). ### 3.8 Geopotential and metric terms @@ -1133,17 +1123,7 @@ phasing, and it should be run **before** Phase 1 implementation is finished, wit scheme on the realistic profile as the control. A null result would not invalidate the design, but it would change its priority. -**Testing assumption A5 (§3.3.1).** Because the expansion point is shared per edge, the discrete PGF -is no longer exactly the gradient of a single scalar, and could in principle inject vorticity. Add a -diagnostic that takes the curl of the PGF tendency on this task. For a profile the scheme resolves -exactly it must be zero to machine precision, since the tendency itself is; that case is a -consistency check on the diagnostic rather than a test of A5. The test of A5 is the realistic -profile: **pass** if the resulting vorticity tendency is small compared with the physical vorticity -tendencies in the same run, and no larger than the corresponding quantity from the centered scheme. -If it is not, the shared expansion point needs to be revisited — for instance by holding it fixed -over a cell's edges at the cost of a weaker cancellation. - -**Covers:** Requirement 2.3 under dynamics; assumptions A3, A4, A5. +**Covers:** Requirement 2.3 under dynamics; assumptions A3, A4. ### 5.4 Test: Overflow (full non-Boussinesq dynamics) @@ -1210,7 +1190,6 @@ loop. Two cheap checks close that: | A2 EOS expansion adequate across an edge | §5.1 contrast sweep; §5.4 | | A3 Residual small enough in practice | §5.1 accuracy gate; §5.3; §5.4 | | A4 PGF error causes the instability | §5.3 diagnostic, run before Phase 1 completes | -| A5 Spurious vorticity negligible | §5.3 curl diagnostic | | §3.7.4 `VertCoord` prerequisite | §5.2 (cannot pass until resolved) | | §3.7.5 Round-off floor | §5.2, run in both precisions | From 08ef74a9edd2adf4491dec17e7c3f29c00b5082b Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 29 Jul 2026 09:19:53 -0500 Subject: [PATCH 08/22] Update design to reflect EOS derivative implementation Record the final shape of the Eos derivative API in PGradHighOrder.md 4.1.2: Eos owns the SpecVolDCt/SpecVolDSa/SpecVolDP arrays exactly as it owns SpecVol, allocating them in its constructor and registering them as fields in the Eos group, so any number of consumers can read them without each allocating a copy. The names match the Ct/Sa abbreviations the TEOS-10 helpers already use, and their valid range must admit negative values. Note also that computeSpecVolAndDerivs fills SpecVol too, so it replaces rather than accompanies a call to computeSpecVol. Correct the cost claim in 3.3. The first derivatives do not reuse the same polynomial coefficients as the specific volume: the pressure derivative does, but the temperature and salinity derivatives need coefficient sets of their own. What is actually bounded, and what Requirement 2.2 states, is the TEOS-10 call count. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 53 +++++++++++++------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 539a92c6aae8..6590a68c9903 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -291,10 +291,15 @@ $$ $$ (alpha-derivs) The four coefficients in [](#alpha-derivs) are obtained from a **single** evaluation of the -TEOS-10 polynomial, since the first derivatives reuse the same polynomial coefficients (the +TEOS-10 polynomial: the derivatives are analytic derivatives of that same polynomial, taken +at the same normalized state, so no second call to the equation of state occurs (they are the same quantities computed by `gsw.specvol_first_derivatives`, which the Polaris reference -solution already uses). Indeed $\alpha_0$ is exactly the `Eos::SpecVol` field Omega already -computes, so only the three derivative fields are additional work. +solution already uses). The arithmetic is not free — $\alpha_p$ reuses the pressure +coefficients assembled for $\alpha_0$, but $\alpha_\Theta$ and $\alpha_S$ need coefficient +sets of their own — though it shares the square root and the normalization, and it is the +*call count*, not the polynomial arithmetic, that Requirement 2.2 bounds. Indeed $\alpha_0$ is +exactly the `Eos::SpecVol` field Omega already computes, so only the three derivative fields +are additional work. The first-order expansion [](#alpha-taylor) is the default. A second-order expansion (adding $\alpha_{\Theta\Theta}$, $\alpha_{SS}$, $\alpha_{\Theta S}$, $\alpha_{pp}$, …) is an option @@ -780,24 +785,38 @@ of an interpolation of $\Theta$ and $S$ onto the edge. The distinction is not co `PressureGradHighOrder` needs $\alpha$ together with its first derivatives. The `Eos` class (Eos.h) currently exposes `computeSpecVol`, `computeSpecVolDisp`, and `computeBruntVaisalaFreqSq`, but no specific-volume derivatives. This design adds one method -and three device fields: +and three device arrays: ```c++ // New on the Eos class -Array2DReal SpecVolDThetaCons; ///< d(alpha)/d(ConservTemp) at cell centers -Array2DReal SpecVolDSalt; ///< d(alpha)/d(AbsSalinity) at cell centers -Array2DReal SpecVolDPressure; ///< d(alpha)/d(Pressure) at cell centers +Array2DReal SpecVolDCt; ///< d(alpha)/d(ConservTemp) at cell centers +Array2DReal SpecVolDSa; ///< d(alpha)/d(AbsSalinity) at cell centers +Array2DReal SpecVolDP; ///< d(alpha)/d(Pressure) at cell centers -/// Compute specific volume AND its first derivatives in one TEOS-10 pass +// Pressure is relative pressure in Pa; the derivatives are returned per degC, +// per (g/kg), and per Pa respectively, into the members above and SpecVol. void computeSpecVolAndDerivs(const Array2DReal &ConservTemp, const Array2DReal &AbsSalinity, const Array2DReal &Pressure); ``` -The TEOS-10 derivatives reuse the polynomial coefficients already assembled inside the -`Teos10Eos` functor (`calcPCoeffs`/`calcDelta`), so the marginal cost over `computeSpecVol` -is the derivative arithmetic only (Requirement 2.2). The linear and constant EOS options -supply trivial analytic derivatives. +`Eos` owns the derivative arrays exactly as it owns `SpecVol`, `SpecVolDisplaced` and +`BruntVaisalaFreqSq`: they are allocated in the constructor and registered as `Field`s in the +`Eos` group, so they can be written to a stream and any number of consumers can read them +without each allocating its own copy. Their valid range must permit negative values — +$\alpha_S < 0$ everywhere, and $\alpha_\Theta < 0$ in cold fresh water — unlike `SpecVol`. + +Because `computeSpecVolAndDerivs` fills `SpecVol` as well, it replaces rather than accompanies +a call to `computeSpecVol`; the two are kept separate so that the derivative arithmetic is +paid only where it is needed. + +The TEOS-10 derivatives are obtained by differentiating the 75-term polynomial analytically. +The pressure derivative reuses the coefficients `calcPCoeffs` already assembles for +$\alpha$ itself and so is free; the $\Theta$ and $S_A$ derivatives need their own coefficient +sets, built from the same $s$ and $t$ (no additional square root). The marginal cost over +`computeSpecVol` is therefore roughly two extra coefficient assemblies and no additional +TEOS-10 evaluation, which is what Requirement 2.2 bounds. The linear and constant EOS +options supply trivial analytic derivatives. #### 4.1.3 `PressureGradHighOrder` functor @@ -813,11 +832,11 @@ KOKKOS_FUNCTION void operator()(const Array2DReal &Tend, I4 IEdge, I4 KChunk, const Array1DReal &TidalPotential, const Array1DReal &SelfAttractionLoading, const Array2DReal &SpecVol, - const Array2DReal &ConservTemp, // new - const Array2DReal &AbsSalinity, // new - const Array2DReal &SpecVolDThetaCons, // new - const Array2DReal &SpecVolDSalt, // new - const Array2DReal &SpecVolDPressure) // new + const Array2DReal &ConservTemp, // new + const Array2DReal &AbsSalinity, // new + const Array2DReal &SpecVolDCt, // new + const Array2DReal &SpecVolDSa, // new + const Array2DReal &SpecVolDP) // new const; ``` From 394f6d644626c17699253b339395a195736e33eb Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 29 Jul 2026 14:22:53 -0500 Subject: [PATCH 09/22] Update the finite-volume HPG design with phase 1 findings These particularly relate to a correction of the geopotential at edges needed to achieve machine-precision consisency. --- components/omega/doc/design/PGradHighOrder.md | 242 +++++++++++++----- 1 file changed, 175 insertions(+), 67 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 6590a68c9903..27190ed677f7 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -205,7 +205,21 @@ $$ (ho-target) The four terms are: the geopotential (gravity) body force integrated over the layer volume; the side-wall integral of $\alpha p$ (the pressure traction on the cell faces); and two metric terms accounting for the pressure traction on the sloping top and bottom layer -interfaces. This is the Adcroft et al. (2008) finite-volume route — the net pressure force +interfaces. + +```{note} +The signs on the two metric terms are inherited from +{ref}`omega-design-governing-eqns-omega1` and have not been independently re-derived here. Applying +Leibniz' rule to lines 2–4 so that they telescope to $-\int\rho_0\nabla(\alpha p)\,d\tilde z$ +appears to require the opposite signs on those two lines; with the signs as printed, the discrete +resting-state cancellation of §3.7 leaves a factor of two rather than zero. This may be a difference +in how $\nabla\tilde z^{\text{top}}$ or the traction normal is defined rather than an error. +`OmegaV1GoverningEqns.md` is not maintained against the code and cannot settle it. The convention +must be re-derived from $\tilde z \equiv -p/(\rho_0 g)$ against the conventions the code actually +fixes — `PressureGradCentered` for the tendency sign, `CellsOnEdge` ordering and `EdgeMask`, and +`VertCoord` for accumulation direction and interface indexing — before implementation, using the +§3.9 reduction to the centered scheme as the check with a known answer. +``` This is the Adcroft et al. (2008) finite-volume route — the net pressure force on each control volume is obtained by integrating in-situ pressure over the faces, rather than by forming the pointwise product $\alpha\nabla p$. We adopt this form because it matches Omega's non-Boussinesq layer-integral momentum equation exactly and is the form @@ -503,7 +517,8 @@ For each edge and layer: two cells' interface values. 3. **The geopotential is built from that same profile.** The geometric height entering $g\nabla z$ must be the integral of the same $\hat\alpha$, layer by layer, down to a common - anchor. This one is currently *not* satisfied; see §3.7.4. + anchor. Satisfying this requires a per-edge correction to the geometric height difference; + see §3.7.4. Conditions 2 and 3 are about the discretization alone and are under the implementation's control. Meeting them means the scheme returns the **exact pressure gradient of the water column it has @@ -561,44 +576,80 @@ which is nonzero whenever $\alpha$ varies with depth and interfaces are displace **accumulates downward**: the deeper the layer, the more layers contribute to the sum. The vertical contrast in *in-situ* $\alpha$ is dominated by compressibility (a few percent over the full ocean depth, against a few tenths of a percent from $\Theta$ and $S$), and that is exactly the part -Phase 1 cancels. Whether this downward accumulation is in fact what produces the bottom-layer noise +Phase 1 cancels. + +This first-order behaviour has since been **measured**, and it is no longer an assertion. On the +Polaris `horiz_press_grad` resting-state configurations (uniform $\Theta$, $S$, flat floor, tilted +coordinate), `PressureGradCentered` gives a fitted exponent of $1.0000$ in the coordinate tilt at +three vertical resolutions, and the `ztilde_gradient` variant converges at $\approx 1.1$ in +horizontal resolution once the bottom layer is included in the comparison. Two independent +measurements of the same first-order behaviour, in agreement. The corresponding absolute errors reach +$2\times10^{-5}\ \mathrm{m\,s^{-2}}$ at a coordinate tilt of 50 m/km with 256 m layers — the order of +the bottom-layer error seen in realistic global configurations. Whether this downward accumulation is in fact what produces the bottom-layer noise seen in realistic global configurations is a plausible diagnosis, not an established one; it is carried as A4 in §3.7.6 and tested in §5.3. -#### 3.7.4 A prerequisite in `VertCoord` - -Condition 3 is a constraint on `VertCoord`, not on `PGrad`, and **it is not currently satisfied**. -`VertCoord::computeGeomZHeight` builds $z$ by accumulating -$\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — a midpoint rule using the layer-mean specific -volume, working upward from the bottom. If the pressure term integrates a reconstructed -$\hat\alpha$ while the geopotential term differences a $z$ built this way, the two are working from -**different specific volumes**, and the cancellation fails at $O(\alpha_{pp}\tilde h^2)$ — precisely -the order Phase 1 exists to recover. Worse, because $z$ is a running sum up the column, the mismatch -**accumulates over every layer between the anchor and the layer in question** rather than staying -local. - -This is a prerequisite for Phase 1, not an implementation detail. There are three ways to resolve -it: - -1. **Align `VertCoord`.** Integrate $z$ using the same reconstruction the PGF uses. Satisfies - condition 3 outright, but changes answers for every existing configuration and modifies a module - the PGF does not own. -2. **Build $z$ increments inside the PGF.** Leave `VertCoord` alone and have the PGF form its own - layer $z$ increments from its own $\hat\alpha$. No answer change elsewhere, but it creates a - second, slightly different $z$ in the model, which Requirement 2.4 exists to prevent. -3. **Accept the mismatch and document the error floor.** The guarantee of §3.7.2 weakens from "zero - to machine precision" to "zero to $O(\alpha_{pp}\tilde h^2)$ accumulated over the column", and the - test in §5.2 cannot pass. - -**Recommendation: option 1.** Options 2 and 3 both give up the property this phase exists to -deliver. The change is answer-changing but small and well contained, and it is worth having on its -own merits: it makes the model's $z$ a more accurate integral of the hydrostatic relation. The -decision must be made before Phase 1 implementation begins, and it needs a baseline step (§5). - -One related question is deliberately left to implementation time: `VertCoord` builds $z$ upward from -the bathymetry while pressure is built downward from the surface, so the two accumulate round-off -from opposite ends of the column. Whether the PGF should re-anchor its own accumulation is a -round-off question (§3.7.5), not a consistency one — condition 3 is satisfied either way. +#### 3.7.4 Condition 3 and the geopotential + +Condition 3 constrains how the geopotential term is built. Two questions arise, and they have +different answers; an earlier revision of this design conflated them and drew the wrong conclusion +from the first. + +**The quadrature question, which is already settled.** `VertCoord::computeGeomZHeight` builds $z$ by +accumulating $\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — apparently a midpoint rule, where +condition 3 asks for the integral of the reconstructed $\hat\alpha$. For a Phase 1 reconstruction +these are **the same quantity**. Integrating [](#alpha-taylor) with the linear deviations of §3.4 +over the layer, + +$$ +\frac{1}{g}\int_{p^{\text{top}}_{i,k}}^{p^{\text{bot}}_{i,k}} \hat\alpha_{i,k}(p)\,dp += \frac{\alpha_{0}\,\Delta p_{i,k}}{g} = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}, +$$ (z-increment-exact) + +because $\int \Theta'\,dp = \int S'\,dp = 0$ by the mean-preserving constraint, and +$\int (p - p^{\text{mid}})\,dp = 0$ because $p^{\text{mid}}$ is the exact arithmetic midpoint of the +two interface pressures. The midpoint rule *is* the exact layer integral of a Phase 1 +$\hat\alpha$. No change to `VertCoord` is required, there is no answer-changing baseline step, and +Requirement 2.4 is satisfied by construction rather than by negotiation — the PGF and the rest of +the model share one $z$ because they compute the same thing. + +This is a Phase-1-only result and Phase 2 must re-examine it. Parabolic deviations are fine provided +they remain mean-preserving, but the second-order equation-of-state expansion of §3.3 contributes +$\tfrac12\alpha_{pp}(p-p^{\text{mid}})^2$ and cross terms such as +$\tfrac12\alpha_{\Theta\Theta}\Theta'^2$, none of which integrate to zero over the layer. If that +option is adopted, [](#z-increment-exact) no longer holds and the question returns. + +**The sharing question, which is the real constraint.** What condition 3 actually requires is that +the geopotential be built from the *same* $\hat\alpha$ the pressure terms use — and §3.3.1 makes +that an **edge** quantity, since its coefficients and expansion point are averages over the two +cells of the edge. A cell-based $z$ cannot carry an edge-dependent $\hat\alpha$ however it is +integrated. Two mismatches follow, both $O(\alpha_{pp}(\Delta p^{\text{mid}}_e)^2)$ per layer and +both accumulating down the column: + +1. `VertCoord`'s $z$ uses the exact per-cell TEOS-10 $\alpha$; the PGF uses the edge-shared + linearized $\hat\alpha$. The residual is the + $\tfrac12\alpha_{pp}(p^{\text{mid}}_i - \bar p^e)^2$ term. +2. The geopotential body force is the gradient of $\Phi$ **at fixed pseudo-height**, i.e. at fixed + pressure. Differencing each column's layer-mean $\Phi$ across the edge compares layer means taken + over *different* pressure ranges whenever the interfaces tilt, and that difference does not + vanish for a resting ocean. + +**Resolution: the PGF computes a per-edge correction to the `VertCoord` $z$ difference**, built from +the edge-shared $\hat\alpha$ and accumulated down the column. Stated as a correction rather than a +replacement, this does not create the second, slightly different $z$ that Requirement 2.4 exists to +prevent: `GeomZInterface`/`GeomZMid` remain the model's one geometric height and are unchanged, and +the PGF adds a term to a *difference* that is identically zero when the two columns' interfaces are +level. Accumulating only the correction, rather than re-deriving $z$, also preserves most of the +precision headroom §3.7.5 warns is otherwise consumed, since the correction is small by +construction. + +The implementation consequence is recorded in §4.1.3: the correction is a column prefix sum and +therefore cannot live inside a per-edge, per-vertical-chunk kernel call. + +One related question is left to implementation time: `VertCoord` builds $z$ upward from the +bathymetry while pressure is built downward from the surface, so the two accumulate round-off from +opposite ends of the column. Which end the correction accumulates from is a round-off question +(§3.7.5), not a consistency one — condition 3 is satisfied either way. #### 3.7.5 Round-off in the deep ocean @@ -672,6 +723,19 @@ $\hat\alpha\!\left(p^{\text{top}}\right) p^{\text{top}}$ when the interface is l columns. Because $\hat\alpha(p)$ is a low-order polynomial (§3.3), this integral is evaluated in closed form at no meaningful cost. +**Implement this as an integral, not as an average multiplied by a slope.** Since +$\nabla_n\tilde z^{\text{top}}_{e,k} = -(p^{\text{top}}_{R} - p^{\text{top}}_{L})/(\rho_0 g\,d_e)$, +the divisor in [](#metric-divdiff) and the slope it multiplies cancel identically, and the whole +term is + +$$ +\frac{1}{g\,d_e}\int_{p^{\text{top}}_{L,k}}^{p^{\text{top}}_{R,k}} \hat\alpha(p)\, p \; dp . +$$ (metric-integral) + +Forming the average literally divides by a quantity that is zero wherever the interfaces are level, +which is most of the domain; the reduction noted above is a $0/0$ in that form and is well defined +only in [](#metric-integral). + The tempting alternative — averaging the two cells' interface values, $\tfrac12[(\hat\alpha p)_L + (\hat\alpha p)_R]$ — agrees with [](#metric-divdiff) only when the tilt is small, and leaves behind a residual that grows with the square of the tilt and does *not* @@ -714,7 +778,8 @@ Steps 1–3 are per cell and layer; step 4 is per edge and layer. Phase differen 1. From `VertCoord`: read `PressureInterface`, `PressureMid`, `GeomZInterface`/`GeomZMid`, geopotential, and interface pseudo-heights (already computed diagnostically each step). The - geometric height must satisfy condition 3 of §3.7.2; see the prerequisite in §3.7.4. + geometric height must satisfy condition 3 of §3.7.2, which requires the per-edge correction of + §3.7.4; `VertCoord` itself needs no change. 2. Obtain $\alpha_0$ (= the existing `Eos::SpecVol` field) and the derivatives $\alpha_\Theta, \alpha_S, \alpha_p$ from one TEOS-10 evaluation ([](#alpha-derivs)). Both phases need all four; Phase 2 optionally adds second derivatives (§3.3). @@ -722,7 +787,8 @@ Steps 1–3 are per cell and layer; step 4 is per edge and layer. Phase differen parabolic in Phase 2** — using the actual non-uniform interface pressures (§3.4). 4. For each edge: form the shared expansion point [](#edge-ref) from the two adjacent cells; evaluate each column's layer integral [](#sidewall-int) with those shared coefficients; add the - sloping-interface terms [](#metric-divdiff) and the geopotential difference (§3.8); assemble + sloping-interface terms [](#metric-integral) and the corrected geopotential difference (§3.8, + §3.7.4); assemble $T^p_{e,k}$ and accumulate into the tendency with `EdgeMask`. **Phase 1** uses the two-cell operator [](#edge-grad); **Phase 2** uses the wider stencil of §3.6.1, built as a weighted sum of such two-cell pair contributions. @@ -772,10 +838,17 @@ rather than keys, so no configuration written for Phase 1 needs to change when P `VerticalReconstruction: 'constant'` sets the specific volume constant within each layer — both $\Theta' = S' = 0$ and the equation-of-state expansion truncated to $\alpha_0$. It is **verification only**: combined with `HorzOrder: 2` it recovers `PressureGradCentered` (§3.9) and supports the -permanent regression test of §5.5, and it isolates compressibility in §5.2. It is not a supported -production setting, because it gives up the exactness for linearly varying profiles that -Requirement 2.3.3 asks for. The implementation should log a warning if it is selected outside a -test. +permanent regression test of §5.5. It is not a supported production setting, because it gives up the +exactness for linearly varying profiles that Requirement 2.3.3 asks for. The implementation should +log a warning if it is selected outside a test. + +`'constant'` is **not** the compressibility-only configuration, and the two are easy to confuse. +Truncating the expansion to $\alpha_0$ discards $\alpha_p$, which is exactly the term that makes the +scheme exact for the "uniform $\Theta$, $S$; compressibility only" row of §3.7.3. The configuration +that isolates compressibility is `'linear'` applied to a vertically uniform $\Theta$, $S$ profile: +the reconstruction slopes are then zero on their own, $\alpha_p$ is retained, and no separate +setting is needed. Tests that mean to isolate compressibility — including §5.2 — must select +`'linear'`, not `'constant'`. `HorzOrder` selects the width of the edge *stencil* — how many cell pairs contribute — not the order of an interpolation of $\Theta$ and $S$ onto the edge. The distinction is not cosmetic; see §3.6.1. @@ -859,6 +932,19 @@ from the obvious implementation: contributes a complete Phase 1 evaluation with its own shared expansion point, and the pair results are combined with the stencil weights (§3.6.1). Implementing Phase 2 as a wider reconstruction feeding a single evaluation would be simpler and would break the property of §3.7. +- **The geopotential correction of §3.7.4 is a column scan and cannot live in this functor.** It is a + prefix sum down each column with edge-dependent coefficients, so it is not expressible as an + independent per-vertical-chunk operation. It is computed in a separate kernel that fills a per-edge + array, + + ```c++ + Array2DReal GeopotCorrection; ///< (NEdgesAll, NVertLayers), owned by PressureGrad + ``` + + with a `parallelForOuter` over edges and a `parallelScanInner` down the column, in the same shape + as `VertCoord::computeGeomZHeight`. The functor then reads it chunk-wise like any other input. The + cost is one edge-sized 2-D array and one column scan per edge per step. This is the one structural + addition Phase 1 makes beyond the per-edge, per-chunk pattern the centered scheme uses. The Phase 1 and Phase 2 code paths differ only in the reconstruction degree (§3.4) and in whether the pair loop has one entry or several. There is one functor, not two. @@ -950,14 +1036,16 @@ resting ocean whose profile varies linearly with pressure, at any tilt, thicknes in use today (§3.6), so horizontal truncation error is unchanged from `PressureGradCentered`. Requirements 2.1 and 2.6 are met at second order only. -**Depends on.** The `VertCoord` geopotential decision of §3.7.4, which must be settled *before* -implementation starts — the machine-precision property is unreachable without it, and option 1 (the -recommendation) is answer-changing and needs its own baseline step. Nothing else in Phase 1 depends -on unresolved questions. +**Depends on.** Nothing unresolved. The `VertCoord` geopotential question of §3.7.4 is settled +there: no change to `VertCoord` is needed and no baseline step is required, because the midpoint rule +is already the exact layer integral of a Phase 1 $\hat\alpha$. What condition 3 does require — the +per-edge geopotential correction — is part of this phase's own implementation (§4.1.3), not a +prerequisite in another module. **Code and cost.** Three new `Eos` derivative fields and one new method (§4.1.2); the -`PressureGradHighOrder` functor; no new TEOS-10 evaluations per cell and layer (Requirement 2.2), -with roughly three times as many polynomial layer integrals on a hexagonal mesh (§4.1.3). +`PressureGradHighOrder` functor; the per-edge geopotential correction array and its column scan +(§3.7.4, §4.1.3); no new TEOS-10 evaluations per cell and layer (Requirement 2.2), with roughly +three times as many polynomial layer integrals on a hexagonal mesh (§4.1.3). #### 4.5.2 Phase 2 — fourth order @@ -976,13 +1064,18 @@ pair evaluations — is the first task of Phase 2 and does not block Phase 1. #### 4.5.3 Suggested order of work -1. Settle the `VertCoord` geopotential question (§3.7.4) and take the baseline step it requires. +1. Write the discrete form out in full — including the interface-metric sign convention, which + $\hat\alpha$ the interface integral uses when the two columns' reconstructions differ, and the + exact form of the per-edge geopotential correction (§3.7.4) — and confirm numerically that it + returns zero for a profile linear in pressure at large tilt. Doing this in the Polaris + two-column harness makes it executable and doubles as the reference implementation §5.1 needs. 2. Run the assumption-A4 diagnostic of §5.3, which uses the *existing* centered scheme and so can be done immediately and in parallel with step 1. If spurious bottom-layer flow survives a profile that Phase 1 would resolve exactly, the cause is elsewhere in the model and the priority of this work should be reconsidered before it is built. 3. Implement and verify Phase 1 against §5.1, §5.2, §5.3, and §5.5. -4. Take up Phase 2, starting from the stencil question in §3.6.1. +4. Take up Phase 2, starting from the stencil question in §3.6.1. Re-examine [](#z-increment-exact) + before adopting the second-order equation-of-state expansion. ## 5 Verification and Testing @@ -1021,7 +1114,8 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient - **Scheme selection.** Add `PressureGrad: { PressureGradType: FiniteVolume, … }` to `forward.yaml` and parametrize each task over three configurations: - `centered` — the legacy `PressureGradCentered` functor, unchanged; - - `finite_volume_phase1` — `HorzOrder: 2`, `VerticalReconstruction: linear`; + - `finite_volume_phase1` — `HorzOrder: 2`, `VerticalReconstruction: linear`, + `QuadraturePoints: 2`; - `finite_volume_phase2` — `HorzOrder: 4`, `VerticalReconstruction: ppm` (added when Phase 2 lands). @@ -1050,10 +1144,17 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient convergence slope. - **Verification gate (Requirement 2.6):** the measured slope of RMS error vs. resolution, `omega_vs_reference_convergence_rate_*`, must fall within a band around the configured order - of accuracy — nominally ~2 for `finite_volume_phase1` and for `centered` (whose band is - unchanged from today), and ~4 for `finite_volume_phase2`. This band is retuned from its - present values rather than loosened; a slope outside it fails the test and is treated as an - implementation defect to be diagnosed, not as a tolerance to be widened. + of accuracy — nominally ~2 for `finite_volume_phase1` and ~4 for `finite_volume_phase2`. This band + is retuned from its present values rather than loosened; a slope outside it fails the test and is + treated as an implementation defect to be diagnosed, not as a tolerance to be widened. + + **The `centered` bands are *not* uniform across the four variants and must be set per variant from + measurement.** Measured on chrysalis with the bottom layer included, `PressureGradCentered` gives + $\approx 1.6$ (`temperature_gradient`), $\approx 1.8$ (`salinity_gradient`), $\approx 2.0$ + (`surface_pressure_gradient`) and $\approx 1.1$ (`ztilde_gradient`). The last is the first-order + resting-state behaviour of §3.7.3 showing up directly, and it is the reason a single "~2 for + centered" band would fail three variants out of four. This corrects an earlier statement here that + the `centered` band was unchanged from its present values. - **Asymptotic range (Phase 2 implementation-time task):** it is not yet established that the existing `horiz_resolutions` sweep spans a range where a fourth-order slope is cleanly measurable — the sweep may be too coarse to have entered the asymptotic regime at its fine end, @@ -1092,18 +1193,25 @@ copying identical layer means into both columns would not exercise the property Three groups of profiles are run: - **Profiles the scheme resolves exactly:** $\Theta$, $S$ linear in pressure, including the constant - case, which isolates compressibility on its own. **Pass:** the PGF is zero at every edge and layer - to **machine precision** (double-precision builds; the threshold tracks `Real`'s epsilon and the - size of the hydrostatic terms, not a physical tolerance). Phase 1 and Phase 2 must both pass. + case, which isolates compressibility on its own. Run these with + `VerticalReconstruction: 'linear'`, **not** `'constant'` — see §4.1.1; `'constant'` discards + $\alpha_p$ and so cannot be exact for compressibility. **Pass:** the PGF is zero at every edge and + layer to **machine precision** (double-precision builds; the threshold tracks `Real`'s epsilon and + the size of the hydrostatic terms, not a physical tolerance). Phase 1 and Phase 2 must both pass. - **Profiles it does not:** $\Theta$, $S$ quadratic in pressure, then a realistic profile. **Pass:** the residual shrinks like $\tilde h^2$ (Phase 1) and $\tilde h^3$ (Phase 2) as the vertical grid is refined at fixed tilt, matching §3.7.3. A residual that does not shrink at the tabulated rate means one of the three conditions in §3.7.2 has been broken somewhere in the implementation; it is a bug to find, not a tolerance to widen. - **Guard tests:** rerun an exactly resolved profile with (a) the endpoint-average interface term in - place of [](#metric-divdiff), and (b) a cell-local expansion point in place of [](#edge-ref). - Both must *fail* the machine-precision check. Without these, a passing result could just as easily - come from a symmetry of the test setup as from the scheme being right. + place of [](#metric-integral), (b) a cell-local expansion point in place of [](#edge-ref), and + (c) the per-edge geopotential correction of §3.7.4 disabled. All three must *fail* the + machine-precision check. Without these, a passing result could just as easily come from a symmetry + of the test setup as from the scheme being right — and guard (c) in particular is the direct + evidence that the geopotential correction is load-bearing rather than decorative. + + Guards must be checked against a deliberately broken configuration, not only against a passing + one. A guard that cannot fire is worse than no guard, because it looks like protection. A separate and much smaller unit test covers the reconstruction estimator on its own (§3.4): given layer means sampled from a profile of the reconstruction's own degree on a **deliberately @@ -1115,10 +1223,10 @@ immediately. The test is also run in a single-precision build, to measure the round-off floor of §3.7.5 and settle whether the perturbation form is needed. -Condition 3 of §3.7.2 depends on `VertCoord` (§3.7.4), so the machine-precision check cannot pass -until whichever resolution is chosen there is in place; this test therefore doubles as the -acceptance criterion for that prerequisite. It is implemented as a fast C++ unit test and also run -as a configuration of the Polaris two-column task. +Condition 3 of §3.7.2 requires the per-edge geopotential correction of §3.7.4, so the +machine-precision check cannot pass until that is in place; this test, together with guard (c) +above, is its acceptance criterion. It is implemented as a fast C++ unit test and also run as a +configuration of the Polaris two-column task. **Covers:** Requirement 2.3 in full; rows 1–5 of the §3.7.3 table; the round-off floor of §3.7.5. @@ -1209,7 +1317,7 @@ loop. Two cheap checks close that: | A2 EOS expansion adequate across an edge | §5.1 contrast sweep; §5.4 | | A3 Residual small enough in practice | §5.1 accuracy gate; §5.3; §5.4 | | A4 PGF error causes the instability | §5.3 diagnostic, run before Phase 1 completes | -| §3.7.4 `VertCoord` prerequisite | §5.2 (cannot pass until resolved) | +| §3.7.4 per-edge geopotential correction | §5.2 (cannot pass without it; guard (c) tests it directly) | | §3.7.5 Round-off floor | §5.2, run in both precisions | Requirement 2.7 (extensibility) is not testable directly; it is addressed by the configuration From cd6618bdb79f494c143ab59184dc59a9c6c1f4e2 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 30 Jul 2026 04:58:12 -0500 Subject: [PATCH 10/22] Reduce the finite-volume HPG target to the fixed-pressure geopotential Omega defines pseudo-height as z-tilde = -p/(rho0 g) with no offset, so surfaces of constant z-tilde are surfaces of constant pressure and the pressure-gradient term vanishes along a coordinate surface. The four pressure terms of the inherited control-volume form therefore sum identically to zero, and the entire horizontal PGF is the geopotential compared at fixed pressure. Correct that inherited form first: it is missing a p grad(alpha) term, without which the scheme does not converge at all, and the signs on its two metric terms are reversed. Both follow from Leibniz' rule and are owed back to OmegaV1GoverningEqns.md. State the reduced target, and evaluate it as PressureGradCentered plus a remainder. The centered scheme is exactly the first-order conversion of a height difference at fixed layer index into one at fixed pressure, so the remainder is the centered scheme's error and setting it to zero recovers that scheme at any tilt. Give the remainder's four sources, three local to the layer and one a column prefix sum, and require each to be formed without subtracting large quantities. The reduction is a statement about coordinate surfaces, not layer interfaces: interfaces remain tilted, time-varying and at different pressures in neighbouring columns under any ALE layering of pseudo-height, and every term the scheme computes is a tilt term. Say so explicitly and bound the scope. Consequently drop the side-wall integral, both metric integrals, the quadrature option and the 'constant' reconstruction; drop the pair-decomposition constraint on the phase 2 stencil, which exactness no longer requires; and rename the functor to PressureGradFiniteVolume, since phase 1 is second order and not higher order than the scheme it replaces. Add a guard test asserting the scheme responds to tilt at all, and record the supporting measurements and their limits. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGrad.md | 21 +- components/omega/doc/design/PGradHighOrder.md | 1292 +++++++++++------ 2 files changed, 844 insertions(+), 469 deletions(-) diff --git a/components/omega/doc/design/PGrad.md b/components/omega/doc/design/PGrad.md index 8deb976d40aa..d906daf0f433 100644 --- a/components/omega/doc/design/PGrad.md +++ b/components/omega/doc/design/PGrad.md @@ -89,8 +89,11 @@ $$ T^p_{e,k} = \frac{1}{2d_e}\left(\sum_{i\in CE(e)} -n_{e,i} M_{i,k+1/2} + \sum_{i\in CE(e)} -n_{e,i} M_{i,k-1/2}\right) + \frac{1}{2}\left(\sum_{i\in CE(e)} p_{i,k}\right) \frac{1}{d_e} \sum_{i\in CE(e)} -n_{e,i}\alpha_{i,k} + \frac{1}{d_e} \sum_{i\in CE(e)} -n_{e,i} (\phi_{TP,i} + \phi_{SAL,i}). $$ -### 3.2 High-order Pressure Gradient -The high order pressure gradient will be based on the {ref}`full volume integral form ` of the geopotential and pressure terms, evaluating the side-wall integral of $\alpha p$ together with the sloping-interface metric terms by quadrature and accounting for the variability of $\alpha$ with reconstructed temperature, salinity, and pressure. +### 3.2 Finite-volume Pressure Gradient +The `FiniteVolume` pressure gradient starts from the {ref}`full volume integral form ` of the geopotential and pressure terms. +Because Omega's pseudo-height coordinate is defined as $\tilde{z} = -p/(\rho_0 g)$ with no offset, surfaces of constant $\tilde{z}$ are surfaces of constant pressure, so $\nabla_{\tilde{z}} p \equiv 0$ and that form's pressure terms — the side-wall integral of $\alpha p$ and the two sloping-interface metric terms — sum identically to zero. +The scheme therefore reduces to the geopotential compared at constant pressure, with the variability of $\alpha$ entering through reconstructed temperature, salinity, and pressure. +Note that this holds for any ALE layering of pseudo-height: the layer interfaces themselves are tilted and move in time, and it is precisely their differing pressures in neighbouring columns that the scheme has to resolve. The complete design — including the reference-state equation-of-state expansion that bounds TEOS-10 cost, the mean-preserving reconstructions, and the discrete hydrostatic consistency property that keeps thin, steeply sloped layers robust — is given in the {ref}`Higher-Order Horizontal Pressure Gradient ` design document. %### 3.3 Barotropic Pressure Gradient @@ -148,8 +151,8 @@ class PressureGrad{ // Instances of functors PressureGradCentered CenteredPGrad; - PressureGradHighOrder HighOrderPGrad; // high-order finite-volume scheme (see PGradHighOrder.md) - // Additional high-order variants may be added in the future + PressureGradFiniteVolume FiniteVolumePGrad; // see PGradHighOrder.md + // Additional variants may be added in the future // Pressure gradient choice from config PressureGradType PressureGradChoice; @@ -174,8 +177,8 @@ An `enum class` will be used to specify options for the pressure gradient used f ```c++ enum class PressureGradType{ Centered, // 2nd-order Montgomery scheme (this document) - FiniteVolume // high-order finite-volume scheme (see PGradHighOrder.md) - // , // additional high-order option, added when implemented + FiniteVolume // layer-integrated finite-volume scheme (see PGradHighOrder.md) + // , // additional option, added when implemented } ``` ### 4.2 Methods @@ -246,7 +249,7 @@ void PressureGrad::computePressureGrad(const Array2DReal &Tend, const I4 TimeLevel) { OMEGA_SCOPE(LocCenteredPGrad, CenteredPGrad); - OMEGA_SCOPE(LocHighOrderPGrad, HighOrderPGrad); + OMEGA_SCOPE(LocFiniteVolumePGrad, FiniteVolumePGrad); OMEGA_SCOPE(LocMinLayerEdgeBot, MinLayerEdgeBot); OMEGA_SCOPE(LocMaxLayerEdgeTop, MaxLayerEdgeTop); @@ -291,8 +294,8 @@ void PressureGrad::computePressureGrad(const Array2DReal &Tend, parallelForInner( Team, KRange, INNER_LAMBDA(int KChunk) { - LocHighOrderPGrad(Tend, IEdge, KChunk, PressureMid, - Geopotential, SpecVol); + LocFiniteVolumePGrad(Tend, IEdge, KChunk, PressureMid, + Geopotential, SpecVol); }); }); diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 27190ed677f7..fd1d71c58d87 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -7,19 +7,27 @@ 3. [Algorithmic Formulation](#3-algorithmic-formulation) 4. [Design](#4-design) 5. [Verification and Testing](#5-verification-and-testing) +6. [Supporting evidence](#6-supporting-evidence) ## 1 Overview -This document specifies a higher-order discretization of the horizontal pressure -gradient force (PGF) in Omega's momentum equation. It is the "future design document" -promised in {ref}`Pressure Gradient ` (§2.3, §3.2), -which commits Omega to a high-order option "similar to -[Adcroft et al. 2008](https://doi.org/10.1016/j.ocemod.2008.02.001)" but defers the -details. The existing centered, second-order Montgomery-potential scheme -(`PressureGradCentered`) remains the default and the reference implementation; -this design adds the high-order option that the `PressureGrad` class and its -`PressureGradType` enum already anticipate (the placeholder high-order entry, named -`FiniteVolume` here; see §4.1.1). +This document specifies a more accurate discretization of the horizontal pressure gradient force +(PGF) in Omega's momentum equation, delivered in two phases: a consistent second-order scheme, then +a fourth-order one. It is the "future design document" promised in +{ref}`Pressure Gradient ` (§2.3, §3.2), which commits Omega to a +high-order option "similar to +[Adcroft et al. 2008](https://doi.org/10.1016/j.ocemod.2008.02.001)" but defers the details. The +existing centered, second-order Montgomery-potential scheme (`PressureGradCentered`) remains the +default and the reference implementation; this design fills in the second `PressureGradType` entry, +which the `PressureGrad` class already anticipates as a placeholder. + +That entry, and the functor behind it, are named **`FiniteVolume`** and +**`PressureGradFiniteVolume`** — not anything containing "high order" (§4.1.1). The choice is +deliberate. Phase 1 uses the same two-cell horizontal stencil as the centered scheme and is second +order, not higher order, so naming the class for an order it does not have would misdescribe what +ships first; and what Phase 1 does deliver is *consistency* (§1.1), which is a separate property from +order of accuracy. `FiniteVolume` refers to the layer-integrated control-volume form of §3.1, which +both phases share. The PGF is the single most error-sensitive term in a layered ocean model. In the non-Boussinesq, hydrostatic momentum equation @@ -39,6 +47,37 @@ directly as spurious velocity (the classic "pressure gradient error"). Experienc MPAS-Ocean and published results for other models show that an accurate PGF goes a long way toward making thin, steeply sloped layers usable. +One property of Omega's vertical coordinate simplifies the *pressure* part of this problem, +and §3.1.1–§3.2 turn on it. Pseudo-height is defined as $\tilde z \equiv -p/(\rho_0 g)$ with +**no offset** ({ref}`omega-design-governing-eqns-omega1` §5.1, which considers adding one and +rejects it so that "$\tilde z$ varies identically to pressure"). A surface of constant +$\tilde z$ is therefore a surface of constant $p$ in every column and at every time, so +$\nabla_{\tilde z}\,p \equiv 0$: the pressure-gradient term vanishes when the gradient is taken +along a coordinate surface, and the entire horizontal PGF is the geopotential compared at fixed +pressure. + +**This is a statement about coordinate surfaces, not about layer interfaces, and the distinction is +the whole subject of this document.** Layer interfaces sit at $\tilde z^{\text{top}}_{i,k}(x,y,t)$ — +wherever the ALE coordinate puts them. They are tilted, they move in time, and layer $k$ occupies a +*different pressure range* in every column. Nothing here assumes otherwise, and a scheme that did +would be worthless: it is exactly that difference in pressure range between neighbouring columns that +produces the pressure-gradient error this design exists to remove. + +The two facts coexist because $\nabla_{\tilde z}$ differentiates along a coordinate surface, while the +layer interfaces enter the layer-integrated form of §3.1 as the *limits of integration*. Their +horizontal variation is what generates that form's two metric terms, through Leibniz' rule, and those +terms are individually large. What §3.1.1 shows is that four individually nonzero terms **sum** to +zero — not that any one of them vanishes, and not that the interfaces are level. Every quantity the +resulting scheme actually computes is a tilt term: if interfaces were isobaric, the cross-edge +interface pressure differences would vanish, the scheme would collapse to a plain difference of +`GeomZInterface`, and there would be nothing left to design. + +The reduction accordingly holds for any ALE layering *of pseudo-height* — p-star, sigma-p, +z-tilde-star, or any hybrid — because all of them relocate interfaces within $\tilde z$ and none of +them redefines $\tilde z$. It would fail only if Omega replaced pseudo-height with a coordinate that +is not a function of pressure alone: geometric $z$, a true $z$-star, or a genuine isopycnal +coordinate. §3.8 states the scope precisely and records what would have to come back in that event. + This design is shaped by three competing principles: 1. **Accuracy.** The PGF must be markedly more accurate than the centered scheme, @@ -69,24 +108,28 @@ therefore answer two different questions and both must be satisfied — *is the Realistic global configurations run with `PressureGradCentered` show spurious flow in the bottom layer over sloping bathymetry, large enough to drive numerical instability. What is -missing there is not high-order accuracy — it is *consistency*: the centered scheme does not -account for the pressure force on a layer's sloping top and bottom interfaces at all, and the -resulting error accumulates downward through the column (§3.7.3). That error is present at -second order and does not require a fourth-order scheme to remove. +missing there is not high-order accuracy — it is *consistency*. §3.9 shows that +`PressureGradCentered` is, exactly and identically, the **first-order** conversion of a +height difference taken at fixed layer index into one taken at fixed pressure. Its error is +therefore the truncation of that conversion, and it accumulates downward through the column +(§3.7.3). That error is present at second order and does not require a fourth-order scheme +to remove. The work is therefore split so the consistency fix can be delivered and tested on its own: -- **Phase 1 — a consistent second-order scheme.** The finite-volume control-volume form, - the sloping-interface integral, the equation-of-state expansion about a state shared across - each edge, and a mean-preserving *linear* reconstruction of $\Theta$ and $S$ in pressure. - The horizontal operator is the same two-cell stencil the centered scheme already uses, so - the scheme remains second order in the horizontal. What Phase 1 buys is the robustness - property of Requirement 2.3: the pressure gradient is zero to machine precision for any - resting ocean whose profile varies linearly with pressure, no matter how the layers tilt. +- **Phase 1 — a consistent second-order scheme.** The exact fixed-pressure geopotential + difference: the equation-of-state expansion about a state shared across each edge, a + mean-preserving *linear* reconstruction of $\Theta$ and $S$ in pressure, and the remainder + by which the exact fixed-pressure height difference exceeds the centered scheme's + first-order estimate of it (§3.5). The horizontal operator is the same two-cell stencil the + centered scheme already uses, so the scheme remains second order in the horizontal. What + Phase 1 buys is the robustness property of Requirement 2.3: the pressure gradient is zero to + machine precision for any resting ocean whose profile varies linearly with pressure, no + matter how the layers tilt. - **Phase 2 — fourth order.** A parabolic vertical reconstruction and a wider horizontal stencil, plus the option of a second-order equation-of-state expansion. This raises the - order of accuracy; it does not change the robustness property, which Phase 1 already - establishes and Phase 2 must preserve. + order of accuracy; it does not change the robustness property, which Phase 1 establishes and + Phase 2 inherits by construction rather than having to re-establish (§3.6.1). The two phases share one implementation, one set of configuration options, and one test suite; Phase 2 widens settings that Phase 1 puts in place. Section 3 marks which parts of @@ -97,7 +140,7 @@ depends on. ### 2.1 Requirement: Higher accuracy than the centered scheme at affordable resolution -The high-order PGF must produce substantially lower absolute error than +The new PGF must produce substantially lower absolute error than `PressureGradCentered` at the coarse-to-moderate resolutions Omega can afford to run, for representative stratified columns with horizontal gradients of temperature, salinity, surface pressure, and coordinate slope. Absolute error at affordable resolution is what @@ -107,11 +150,11 @@ requirement in §2.6, which determines whether it is *correct*. ### 2.2 Requirement: Bounded TEOS-10 cost The number of TEOS-10 specific-volume evaluations performed by the PGF must be -independent of the quadrature order and bounded at approximately one evaluation (plus its -first derivatives) per cell per layer per time step — comparable to the cost Omega already -pays to compute the `Eos::SpecVol` field. The scheme must not require evaluating the full -TEOS-10 polynomial at each quadrature point, nor integrating the TEOS-10 polynomial -itself semi-analytically. +independent of the reconstruction order and the horizontal stencil width, and bounded at +approximately one evaluation (plus its first derivatives) per cell per layer per time step — +comparable to the cost Omega already pays to compute the `Eos::SpecVol` field. The scheme +must not require evaluating the full TEOS-10 polynomial at sub-layer sample points, nor +integrating the TEOS-10 polynomial itself semi-analytically. ### 2.3 Requirement: Robustness for thin, steeply sloped layers via discrete hydrostatic consistency @@ -139,7 +182,7 @@ profiles, which no reconstruction reproduces exactly, some residual PGF is unavo *correct* — the two neighboring columns genuinely do hold slightly different water (§3.7.1). The requirement is that this residual shrink at least one order faster in layer thickness than `PressureGradCentered` does, and that it not be swamped by errors the scheme itself introduces -through inexact integration or an inconsistent geopotential. +through an inconsistent geopotential or a truncated fixed-pressure comparison. These properties must hold without reference to any background or reference profile, so that they hold equally in the warm pool, at the poles, and over a seamount. @@ -156,7 +199,7 @@ of $\Theta$, $S$, $p$, or $z$. ### 2.5 Requirement: Runtime-selectable, backward-compatible option -The high-order scheme must be selectable at runtime through the existing `PressureGrad` +The new scheme must be selectable at runtime through the existing `PressureGrad` configuration group and `PressureGradType` enum, leaving `Centered` as the default. Its sub-options (edge stencil width, vertical-reconstruction mode, quadrature) must be configurable, and the centered scheme must be recoverable as a configuration of the new one. The two phases must @@ -188,7 +231,7 @@ tidal-potential and self-attraction-and-loading contributions to the geopotentia ### 3.1 Continuous target form -The high-order PGF starts from the layer-integrated, finite-volume form of the pressure +The scheme starts from the layer-integrated, finite-volume form of the pressure and geopotential terms derived in {ref}`the governing equations ` (the {ref}`full volume-integral form `). Neglecting the @@ -198,79 +241,108 @@ turbulent correlations and dropping the resolved-component notation, the layer t $$ T^p &= - \int_A \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \, \left( \nabla \Phi \right) \, d\tilde{z} \, dA \\ & - \int_{\partial A} \left( \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \left(\alpha p \right) \, d\tilde{z} \right) dl \\ -& - \int_A \rho_0 \left[ \alpha \, p \, \nabla \tilde{z}_k^{\text{top}} \right]_{\tilde{z} = \tilde{z}_k^{\text{top}}} \, dA \\ -& + \int_A \rho_0 \left[ \alpha \, p \, \nabla \tilde{z}_k^{\text{bot}} \right]_{\tilde{z} = \tilde{z}_k^{\text{bot}}} \, dA. +& + \int_A \rho_0 \left[ \alpha \, p \, \nabla \tilde{z}_k^{\text{top}} \right]_{\tilde{z} = \tilde{z}_k^{\text{top}}} \, dA \\ +& - \int_A \rho_0 \left[ \alpha \, p \, \nabla \tilde{z}_k^{\text{bot}} \right]_{\tilde{z} = \tilde{z}_k^{\text{bot}}} \, dA \\ +& + \int_A \int_{\tilde{z}_k^{\text{bot}}}^{\tilde{z}_k^{\text{top}}} \rho_0 \, p \, \nabla \alpha \, d\tilde{z} \, dA. $$ (ho-target) -The four terms are: the geopotential (gravity) body force integrated over the layer -volume; the side-wall integral of $\alpha p$ (the pressure traction on the cell faces); and -two metric terms accounting for the pressure traction on the sloping top and bottom layer -interfaces. - -```{note} -The signs on the two metric terms are inherited from -{ref}`omega-design-governing-eqns-omega1` and have not been independently re-derived here. Applying -Leibniz' rule to lines 2–4 so that they telescope to $-\int\rho_0\nabla(\alpha p)\,d\tilde z$ -appears to require the opposite signs on those two lines; with the signs as printed, the discrete -resting-state cancellation of §3.7 leaves a factor of two rather than zero. This may be a difference -in how $\nabla\tilde z^{\text{top}}$ or the traction normal is defined rather than an error. -`OmegaV1GoverningEqns.md` is not maintained against the code and cannot settle it. The convention -must be re-derived from $\tilde z \equiv -p/(\rho_0 g)$ against the conventions the code actually -fixes — `PressureGradCentered` for the tendency sign, `CellsOnEdge` ordering and `EdgeMask`, and -`VertCoord` for accumulation direction and interface indexing — before implementation, using the -§3.9 reduction to the centered scheme as the check with a known answer. -``` This is the Adcroft et al. (2008) finite-volume route — the net pressure force -on each control volume is obtained by integrating in-situ pressure over the faces, rather -than by forming the pointwise product $\alpha\nabla p$. We adopt this form because it -matches Omega's non-Boussinesq layer-integral momentum equation exactly and is the form -MOM6 uses successfully for the same problem. - -Adcroft et al. (2008) were targeting an isopycnal model (constant density within a layer) -and the analytically integrable Wright equation of state. Omega differs on both counts: -density varies within a layer in a general ALE coordinate, and TEOS-10 is far more -expensive and not practical to integrate in closed form. The remainder of this section -adapts the form [](#ho-target) to those two realities. - -#### 3.1.1 The four terms are one control volume and must be built together - -The four terms of [](#ho-target) are not independent pieces to be discretized separately and added -up. They are the pressure forces on the four faces of a single control volume — the two vertical -faces where the layer meets its neighboring columns, and the sloping top and bottom interfaces — -together with the weight of the water inside. In a genuinely resting ocean these forces balance -exactly. Whether the *discrete* forces balance depends entirely on whether they are built from a -common description of the water column, and that is what §3.7 is about. - -Two observations make this practical to enforce. - -First, use pressure itself as the vertical integration variable within a column. It is equivalent -to $\tilde z$ by [](#p-linear), but unlike $\tilde z$ it means the same thing in every column -regardless of surface pressure. In terms of $p$, the hydrostatic relation is -$\partial z / \partial p = -\alpha/g$, so the side-wall pressure force and the geometric height -entering the geopotential are integrals of **the same specific volume over pressure**: +The five terms are: the geopotential (gravity) body force integrated over the layer volume; +the side-wall integral of $\alpha p$ (the pressure traction on the cell faces); two metric +terms accounting for the pressure traction on the sloping top and bottom layer interfaces; +and a $p\nabla\alpha$ term. + +**Two of those terms differ from [](#ho-target) as inherited from +{ref}`omega-design-governing-eqns-omega1`, and the differences are corrections.** The fifth term is +**absent** there; omitting it leaves a scheme that does not converge at all. The signs on lines 3 and 4 +are **opposite** to those printed there; with the inherited signs the cancellation of §3.1.1 doubles +rather than vanishing. Both follow from applying Leibniz' rule directly, immediately below, and neither +is a convention difference in how the traction normal or $\nabla\tilde z^{\text{top}}$ is defined. +`OmegaV1GoverningEqns.md` is not maintained against the code and should be corrected there rather than +overridden here; §6.2 states what is owed to it and §6.1 the supporting measurements. + +The derivation is short enough to give in full, because everything in §3 rests on it. +Differentiating $\tilde z \equiv -p/(\rho_0 g)$ and applying the hydrostatic relation gives the mass +element $\rho\,dz = \rho_0\,d\tilde z$ ({ref}`omega-design-governing-eqns-omega1` §5). The layer +integral of the pointwise acceleration $-(\alpha\nabla p + \nabla\Phi)$ at fixed $\tilde z$ is +therefore +$-\int\rho_0(\alpha\nabla p + \nabla\Phi)\,d\tilde z$. Writing +$\alpha\nabla p = \nabla(\alpha p) - p\nabla\alpha$ and applying Leibniz' rule to the first +piece, $$ -\Pi_{i,k} = \frac{1}{g}\int_{p_{i,k}^{\text{top}}}^{p_{i,k}^{\text{bot}}} \hat\alpha_{i,k}(p)\, p \; dp, -\qquad -z_{i}(p) = z_{i}^{\text{anchor}} + \frac{1}{g}\int_{p}^{p_i^{\text{anchor}}} \hat\alpha_{i}(p')\, dp', -$$ (layer-integrals) - -where $\hat\alpha_{i,k}(p)$ is the reconstructed specific volume in column $i$, layer $k$ -(§3.3–§3.4). Writing both terms this way makes the shared ingredient explicit: it is -$\hat\alpha(p)$, and if the pressure term and the geopotential term use different versions of it, -they cannot balance. - -Second, the layer's top and bottom interfaces are *sloping*, so the pressure force on them is an -integral along the slope, not a value at a point. Between two cell centers the interface sweeps -through a range of pressures, and the force per unit slope is the **average of $\hat\alpha p$ over -that pressure range** — not the average of the two cells' interface values. The two agree only when -the tilt is small. Supplying this integral is the piece `PressureGradCentered` omits altogether, -and it is the central content of Phase 1; the explicit form is given in §3.8. +\int_{\tilde z_k^{\text{bot}}}^{\tilde z_k^{\text{top}}} \nabla(\alpha p)\,d\tilde z += \nabla \int_{\tilde z_k^{\text{bot}}}^{\tilde z_k^{\text{top}}} \alpha p \,d\tilde z +- (\alpha p)_{\text{top}}\,\nabla \tilde z_k^{\text{top}} ++ (\alpha p)_{\text{bot}}\,\nabla \tilde z_k^{\text{bot}}, +$$ (leibniz) + +gives exactly lines 2–5 of [](#ho-target), with the divergence theorem turning the first +term on the right into the side-wall line integral. This is the Adcroft et al. (2008) +finite-volume route — the net pressure force on each control volume obtained by integrating +in-situ pressure over its faces, rather than by forming the pointwise product +$\alpha\nabla p$ — and it is the form MOM6 uses successfully for the same problem. + +#### 3.1.1 In pseudo-height the four pressure terms cancel identically + +Lines 2–5 of [](#ho-target) are, by construction, nothing but +$-\int_A\int\rho_0\,\alpha\nabla_{\tilde z} p\,d\tilde z\,dA$ rewritten. In Omega's +coordinate that quantity is **identically zero**. + +Pseudo-height is $\tilde z \equiv -p/(\rho_0 g)$ with no offset, per +{ref}`omega-design-governing-eqns-omega1` §5.1, which considers adding one and rejects it so +that "$\tilde z$ varies identically to pressure". The map $p \leftrightarrow \tilde z$ is +therefore *universal*: it is the same in every column, at every time, irrespective of surface +pressure. A surface of constant $\tilde z$ is a surface of constant $p$, so -### 3.2 A key simplification: pressure is linear in pseudo-height - -Omega's vertical coordinate is pseudo-height, -$\tilde z \equiv -p/(\rho_0 g)$ ({ref}`omega-design-governing-eqns-omega1` §5). Pressure is -therefore, by definition, an **exactly linear function of $\tilde z$**: +$$ +\nabla_{\tilde z}\, p \;\equiv\; 0, +$$ (grad-p-zero) + +and lines 2–5 of [](#ho-target) sum to zero — not approximately, and not only for a resting +ocean, but as an algebraic identity for any state whatsoever. This is the standard result that +in an isobaric coordinate the horizontal pressure gradient force is $-\nabla_p\Phi$. + +**What [](#grad-p-zero) does and does not say.** It says the coordinate *surfaces* are isobars. +It says nothing about the layer *interfaces*, which are at $\tilde z^{\text{top}}_{i,k}(x,y,t)$ +and are tilted, moving, and at different pressures in different columns — as they must be in an +ALE coordinate. The horizontal variation of those limits of integration is precisely what +produces the two metric terms through [](#leibniz), and each of the four pressure terms is +individually large: measured on a two-column state at 50 m/km tilt, the side-wall term alone is +$0.55$ m s$^{-2}$. The cancellation is a property of their *sum*. Read the other way, it is a +statement that the four terms carry no information the geopotential term does not already carry, +so discretizing them can only add error — not a statement that the tilt they describe is absent. + +Three things follow, and they set the shape of the rest of §3. + +1. **The entire horizontal PGF is the geopotential compared at fixed pressure.** §3.2 states + the resulting target. Comparing "at fixed pressure" is hard exactly because the interfaces + are not at fixed pressure; the difficulty of the original problem is preserved, relocated + into a single term. +2. **Adcroft's problem is not Omega's problem.** Adcroft et al. (2008) needed the face-integral + form because their coordinate was *not* isobaric, so $\alpha\nabla_r p$ was a real term + requiring careful treatment. Omega's coordinate is isobaric by definition, and remains so + under ALE: p-star, sigma-p and any other layering Omega adopts move interfaces *within* + $\tilde z$ without redefining $\tilde z$, so [](#grad-p-zero) is untouched. The remaining + problem is not a force-balance problem at all — it is the problem of integrating the + hydrostatic relation accurately enough that two columns' geopotentials can be differenced at + a common pressure. +3. **Discretizing the four terms separately is worse than not discretizing them.** Because they + must cancel, any discretization of them contributes only error — and the cancellation is + delicate in a way that is not apparent from [](#ho-target). It requires the $p\nabla\alpha$ + term to be integrated over the mean of the *two columns' own* layer pressure ranges rather + than over the edge-mean range, which is the choice an edge-centred implementation invites; + mispaired, the residual is $O(\tilde h^0)$ and does not converge under vertical refinement at + all, while remaining invisible to every gate in §5 — on the exact set the mispaired term is + identically zero. The reduced target of §3.2 has no such requirement, because it has no terms + to pair. + +[](#grad-p-zero) has been confirmed to hold discretely as well as continuously: the four pressure +terms were measured to sum to $3\times10^{-15}$ of the size of the side-wall term alone, at 50 m/km +tilt, for every profile tried. §6.1 gives the numbers and the harness. + +### 3.2 The exact target + +Pressure is an exactly linear function of $\tilde z$, $$ p(\tilde z) = p_{k}^{\text{top}} - \rho_0 g \left( \tilde z - \tilde z_k^{\text{top}} \right), @@ -278,10 +350,54 @@ p(\tilde z) = p_{k}^{\text{top}} - \rho_0 g \left( \tilde z - \tilde z_k^{\text{ $$ (p-linear) anchored at the interface pressures $p_k^{\text{top}}$, $p_k^{\text{bot}}$ that `VertCoord` -already provides (`PressureInterface`). No reconstruction of $p$ within a layer is needed -or permitted — using [](#p-linear) is exactly the `VertCoord` anchoring required by -Requirement 2.4. Consequently, the only within-layer nonlinearity in the integrand -$\alpha p$ comes from the variation of $\alpha$ through the reconstructed $\Theta$ and $S$. +already provides (`PressureInterface`). No reconstruction of $p$ within a layer is needed or +permitted — using [](#p-linear) is exactly the `VertCoord` anchoring required by +Requirement 2.4. Within a column, pressure is used from here on as the vertical integration +variable in place of $\tilde z$; the two are interchangeable by [](#p-linear), and pressure is +the variable in which two columns' profiles can be compared. + +Combining [](#grad-p-zero) with [](#ho-target) and mass-weighting the layer average with +$\rho_0\,d\tilde z = -dp/g$, the exact edge-normal acceleration at edge $e$, layer $k$ is + +$$ +T^p_{e,k} = -\,\frac{g}{\Delta p_{e,k}} \int_{p_{e,k}^{\text{top}}}^{p_{e,k}^{\text{bot}}} +\left[\nabla_n z\right]_{p} \; dp +\;-\; \left[\nabla_n \left(\phi_{TP} + \phi_{SAL}\right)\right]_{e}, +$$ (ho-exact) + +in which $[\nabla_n z]_p$ is the edge-normal gradient of geometric height taken **at fixed +pressure**, $\Delta p_{e,k} = p^{\text{bot}}_{e,k} - p^{\text{top}}_{e,k}$ is the edge control +volume's pressure range, and the geometric height of column $i$ as a function of pressure is +the hydrostatic integral + +$$ +z_{i}(p) = z_{i}^{\text{anchor}} + \frac{1}{g}\int_{p}^{p_i^{\text{anchor}}} +\hat\alpha_{i}(p')\, dp', +$$ (z-of-p) + +with $\hat\alpha_{i}(p)$ the reconstructed specific volume in column $i$ (§3.3–§3.4). +Equation [](#ho-exact) is the whole scheme. Everything that follows is either an ingredient of +$\hat\alpha$ (§3.3, §3.4), a statement about how [](#ho-exact) is evaluated without losing +precision (§3.5), or a statement about when it returns zero (§3.7). + +Two properties of [](#ho-exact) are worth noticing immediately, because between them they do the work +that a four-term force balance would need several delicate arguments to secure. + +- **The robustness property is structural, not a cancellation.** If the two columns' reconstructed + profiles agree as functions of pressure, $\hat\alpha_L(p) \equiv \hat\alpha_R(p)$, then by + [](#z-of-p) the two $z_i(p)$ differ by a constant fixed by the anchors, and $[\nabla_n z]_p$ is + *pointwise* zero at every pressure. The integral in [](#ho-exact) is then zero regardless of + the tilt, the layer thicknesses, the bathymetry, or the quadrature used to evaluate it. There + are no terms to pair and no signs to get right. For a resting ocean the anchors agree by the + inverse-barometer relation — $z^{\text{surf}}_i$ tilts exactly so as to compensate a horizontal + gradient in $p^{\text{surf}}_i$ — which is the state the `surface_pressure_gradient` Polaris + variant initializes. +- **The vertical quadrature is not an accuracy knob.** $[\nabla_n z]_p$ varies across the layer + only through $\frac{d}{dp}[\nabla_n z]_p = -\frac{1}{g}[\nabla_n\hat\alpha]_p$, the horizontal + contrast in specific volume at fixed pressure — a quantity that is *small* and that vanishes + identically on the exact set. The layer average in [](#ho-exact) is therefore a nearly-constant + integrand, handled in closed form for a polynomial $\hat\alpha$. There is no quadrature setting + (§4.1.1). ### 3.3 Reference-state expansion of the equation of state @@ -327,8 +443,11 @@ would quietly defeat the robustness property of §3.7. Two neighboring columns w two slightly different approximations to the *same* equation of state, taken at two different points. Their specific-volume profiles $\hat\alpha_{L,k}(p)$ and $\hat\alpha_{R,k}(p)$ would then disagree — by $O(\alpha_{pp}\,\Delta p^{\text{mid}}_e\, \tilde h)$ — even for a resting ocean the -reconstruction reproduces perfectly. The forces on the two vertical faces would no longer balance, -and the scheme would generate spurious flow from nothing but its own EOS approximation. +reconstruction reproduces perfectly. By [](#z-of-p) the two columns' $z_i(p)$ would then differ by +more than a constant, $[\nabla_n z]_p$ would be nonzero, and the scheme would generate spurious +flow from nothing but its own EOS approximation. This choice remains load-bearing under the reduced +target of §3.2 — it is the *only* remaining way for the exactness of [](#ho-exact) to fail on a +resolved profile — and guard test (b) of §5.2 confirms it fires. The design therefore **shares the expansion point across each edge**. The coefficients [](#alpha-derivs) are computed once per cell per layer, exactly as described above (one TEOS-10 @@ -344,19 +463,20 @@ $$ (edge-ref) and **both** columns' contributions to edge $e$ are evaluated with this single set, so that the two sides of the edge see one and the same equation of state. -This has a cost consequence worth recording. The column integral $\Pi_{i,k}$ is no longer a per-cell -quantity that can be computed once and then differenced across each of the cell's edges; it depends -on the edge through [](#edge-ref) and must be evaluated per edge, twice. On a hexagonal TRiSK mesh -this is roughly three times as many integral evaluations as a cell-based formulation. The TEOS-10 -call count is unaffected, which is the cost Requirement 2.2 binds; the extra work is polynomial -arithmetic on coefficients already in cache. - -Because $\Theta$, $S$ are reconstructed as low-order polynomials in $\tilde z$ (and across -edges) and $p$ is linear in $\tilde z$ by [](#p-linear), the expansion [](#alpha-taylor) -makes $\alpha$ a **low-order polynomial** whose product with $p$ integrates **exactly** by a -low-order Gauss rule. The semi-analytic integration is performed on the cheap Taylor model, -not on TEOS-10 — directly resolving the feasibility and cost concerns with applying -Adcroft-style analytic integration to TEOS-10. +This has a cost consequence worth recording. The column quantity built from $\hat\alpha$ — under §3.2 +the hydrostatic integral [](#z-of-p) — is not a per-cell quantity that can be computed once and +differenced across each of the cell's edges. It depends on the edge through [](#edge-ref) and must be +evaluated per edge, twice. On a hexagonal TRiSK mesh this is roughly three times as many column evaluations as a +cell-based formulation. The TEOS-10 call count is unaffected, which is the cost Requirement 2.2 +binds; the extra work is polynomial arithmetic on coefficients already in cache. §3.5 shows how to +arrange it so that only a *small* correction is accumulated per edge, which bounds both the cost +and the round-off. + +Because $\Theta$, $S$ are reconstructed as low-order polynomials in pressure and the expansion +[](#alpha-taylor) is linear in $\Theta$, $S$ and $p$, $\hat\alpha$ is a **low-order polynomial in +pressure** and every integral of it required by §3.2 and §3.5 is available in closed form. No +TEOS-10 evaluation occurs inside any integral — which is what resolves the feasibility and cost +concerns with applying Adcroft-style analytic integration to TEOS-10. ### 3.4 Mean-preserving vertical reconstruction @@ -404,76 +524,216 @@ what makes the reduction to the centered scheme in §3.9 possible, and it isolat on its own in §5.2 — but it is not a supported production setting in either phase, because it gives up the exactness for linearly varying profiles that Requirement 2.3.3 asks for. -### 3.5 Analytic layer integral of the side-wall term +### 3.5 The remainder relative to the centered scheme -Combining [](#p-linear), [](#alpha-taylor), and [](#vert-recon), the side-wall integrand $\alpha p$ -within a single column and layer is a polynomial in pressure. With the first-order equation-of-state -expansion, $\alpha$ inherits the degree of the reconstruction: linear in Phase 1, parabolic in -Phase 2. Multiplying by $p$ gives a quadratic (Phase 1) or cubic (Phase 2) integrand, and in both -cases the layer integral +Equation [](#ho-exact) is not evaluated directly. It is evaluated as the centered scheme plus a +remainder, for one reason: the fixed-pressure height difference is a small residual of two large +quantities, and grouping the large parts so that they cancel *analytically* rather than in floating +point is what preserves the precision §3.7.5 is about. + +**`PressureGradCentered` is the first-order fixed-pressure shift, exactly.** This is an algebraic +identity about the code in `PGrad.h`, not an approximation, and it is the pivot of this section. +Write $\Delta_e f \equiv \sum_{i\in CE(e)} -n_{e,i}\,f_i$ so that $[\nabla_n f]_e = \Delta_e f/d_e$, +and let $q_{i,k}$ = `PressureInterface`, $Z_{i,k}$ = `GeomZInterface`, $\alpha_{i,k}$ = `SpecVol`, +with layer $k$ bounded by interfaces $k$ and $k+1$. Define $$ -\Pi_{i,k} \equiv \frac{1}{g}\int_{p_{i,k}^{\text{top}}}^{p_{i,k}^{\text{bot}}} \alpha\, p \; dp -\;=\; \frac{\Delta p_{i,k}}{g} \sum_{q} w_q \, \alpha\!\left(p_q\right) p\!\left(p_q\right), -$$ (sidewall-int) +\mathcal{S}_{e,k} \;\equiv\; \tfrac{1}{2}\left(\Delta_e Z_{k} + \Delta_e Z_{k+1}\right) +\;+\; \frac{\bar\alpha_{e,k}}{2g}\left(\Delta_e q_{k} + \Delta_e q_{k+1}\right), +\qquad +\bar\alpha_{e,k} = \tfrac{1}{2}\!\!\sum_{i \in CE(e)}\!\! \alpha_{i,k}. +$$ (centered-shift) -is evaluated **exactly** by a two-point Gauss–Legendre rule, which is exact through cubic. The nodes -$p_q$ and weights $w_q$ are on the layer's pressure interval, and $\alpha(p_q)$ comes from -[](#alpha-taylor). No TEOS-10 calls occur inside the sum. +Then $T^{p,\text{ctr}}_{e,k} = -\frac{g}{d_e}\,\mathcal{S}_{e,k} - \left[\nabla_n(\phi_{TP}+\phi_{SAL})\right]_e$. The proof is two lines: with +$M_{i,k\pm} = \alpha_{i,k}\,q_{i,\cdot} + g Z_{i,\cdot}$, the identity +$\Delta_e(\alpha q) = \bar\alpha\,\Delta_e q + \bar q\,\Delta_e \alpha$ splits the Montgomery +difference, and the $\bar q\,\Delta_e\alpha$ halves cancel the scheme's $\bar p\,\nabla\alpha$ term +**term for term**, because $\tfrac12(\bar q_{k} + \bar q_{k+1}) = \bar p^{\text{mid}}_{e,k}$ exactly +— `PressureMid` is the exact arithmetic midpoint of the two interface pressures +(`VertCoord.cpp:1067`). -The quadrature is configurable, but it is not a free accuracy knob: it must be **at least** exact for -the reconstructed integrand, or condition 2 of §3.7.2 fails and the cancellation is lost. Raising it -beyond that changes nothing, since the integrand is a polynomial of known degree. Lowering it — to -midpoint, say — is meaningful only as the verification configuration of §3.9. +What [](#centered-shift) *is*, physically: Taylor-shifting each column's height from its own +interface pressure to a pressure common to both gives +$z_i(p) = Z_{i,k} - \frac{\alpha}{g}\left(p - q_{i,k}\right) + O\!\left((p-q_{i,k})^2\right)$, hence + +$$ +g\left[\nabla_n z\right]_{p} \;=\; g\left[\nabla_n Z\right]_{k} +\;+\; \alpha \left[\nabla_n q\right]_{k} \;+\; O\!\left(\frac{\alpha_p}{g}(\Delta_e q)^2\right). +$$ (first-order-shift) + +So $\mathcal{S}_{e,k}$ is the trapezoidal average over the layer's two interfaces of the +**first-order** conversion from fixed layer index to fixed pressure, with the layer-mean $\alpha$ +standing in for $\hat\alpha$ at the interface. The centered scheme's entire Montgomery-potential +apparatus is that conversion and nothing else, and its error is the conversion's truncation. This is +why §3.7.3's first-order behaviour is what it is, and it is the sharpest available statement of what +Phase 1 fixes: **Phase 1 computes the centered scheme's error and removes it.** + +**The remainder.** Define + +$$ +\mathcal{R}_{e,k} \;\equiv\; \frac{1}{\Delta p_{e,k}} +\int_{p^{\text{top}}_{e,k}}^{p^{\text{bot}}_{e,k}} \Delta_e z(p)\; dp \;-\; \mathcal{S}_{e,k}, +\qquad +T^p_{e,k} = -\frac{g}{d_e}\left(\mathcal{S}_{e,k} + \mathcal{R}_{e,k}\right) +- \left[\nabla_n(\phi_{TP}+\phi_{SAL})\right]_e , +$$ (ho-discrete) + +with $z_i(p)$ from [](#z-of-p) built on the edge-shared $\hat\alpha^{(e)}$. Equation +[](#ho-discrete) is exactly [](#ho-exact) rewritten; `VertCoord`'s $Z$ enters through +$\mathcal{S}$ and leaves again through $\mathcal{R}$, and cancels in exact arithmetic. That is what +keeps Requirement 2.4 satisfied — the scheme does not construct a second geometric height, it +constructs a correction to a difference — and it is why the split is a numerical device rather than +a change of target. + +$\mathcal{R}$ has four sources. Three are local to the layer; the fourth is not. + +1. **Interface value versus layer mean.** [](#centered-shift) weights $\Delta_e q$ by the layer-mean + $\bar\alpha_{e,k}$ where [](#first-order-shift) calls for $\hat\alpha^{(e)}$ evaluated *at the + interface*. Contributes $\propto \hat\alpha'\,\Delta p_{k}\,\Delta_e q_{k}$ per interface, with + opposite sign at the layer's top and bottom. +2. **Second and higher order in the shift.** The $O((\Delta_e q)^2)$ term of + [](#first-order-shift). Its column-symmetric part cancels in the edge difference; what survives + is $-\frac{(\Delta_e q_k)^2}{8g}\,\Delta_e \hat\alpha'$ and higher, i.e. it is driven by the + *horizontal contrast* in compressibility, not by compressibility itself. +3. **Layer average versus interface trapezoid.** [](#ho-discrete) averages $\Delta_e z(p)$ over the + edge control volume's pressure range; [](#centered-shift) takes the mean of two interface values. + The gap is set by the curvature $\frac{d^2}{dp^2}\Delta_e z = -\frac{1}{g}\Delta_e\hat\alpha'$. +4. **The `VertCoord` height is built from a different $\hat\alpha$.** `VertCoord` accumulates + $\Delta Z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$, which by §3.7.4's [](#z-increment-exact) is the + exact layer integral of a *cell-local* Phase 1 $\hat\alpha$. The scheme's water column is the + *edge-shared* one, whose layer mean is + + $$ + \left\langle\hat\alpha^{(e)}_{i,k}\right\rangle = \bar\alpha_0^{e,k} + \bar\alpha_\Theta^{e,k}\left(\Theta_{i,k}-\bar\Theta^{e,k}\right) + \bar\alpha_S^{e,k}\left(S_{i,k}-\bar S^{e,k}\right) + \bar\alpha_p^{e,k}\left(p^{\text{mid}}_{i,k}-\bar p^{e,k}\right), + $$ (alpha-edge-layer-mean) + + the first-order Taylor estimate of $\alpha_{i,k}$ from the edge state. The per-layer mismatch + + $$ + \varepsilon_{i,k} = \rho_0\,\tilde h_{i,k}\left(\alpha_{i,k} - \left\langle\hat\alpha^{(e)}_{i,k}\right\rangle\right) + $$ (eos-remainder) + + is therefore precisely the **second-order Taylor remainder of the equation of state across the + edge**, and its edge difference **accumulates down the column**. This is the one non-local source, + and it is why Phase 1 needs a column scan (§4.1.3). It also identifies source 4 with assumption A2 + (§3.7.6): the same second-order EOS expansion that would answer A2 shrinks this source directly. + +Three requirements on how $\mathcal{R}$ is built, all of them testable: + +- **R1 — built from the edge-shared $\hat\alpha^{(e)}$** of [](#edge-ref), so that condition 1 of + §3.7.2 is met. Guard test (b) of §5.2 checks this. +- **R2 — evaluated analytically, never as a numerical difference.** Each of the four sources above + is a small quantity with a closed form. Forming $\mathcal{R}$ by computing + $\frac{1}{\Delta p}\int \Delta_e z\,dp$ and $\mathcal{S}$ separately and subtracting them would + throw away exactly the precision the split exists to protect. +- **R3 — $\mathcal{R}_{e,k} = -\mathcal{S}_{e,k}$ to round-off whenever + $\hat\alpha^{(e)}_L(p) \equiv \hat\alpha^{(e)}_R(p)$.** This is the machine-precision property of + Requirement 2.3.1 restated in the form the implementation must satisfy, and it is what §5.2 tests. + Note that it makes the test *sharper* than a check that the tendency is small: $\mathcal{S}$ is + the centered scheme's answer on the same state, which §3.7.3 measures at $2\times10^{-5}$ + m s$^{-2}$, so R3 asserts a cancellation of ten orders of magnitude against a known nonzero + reference rather than against zero. + +#### 3.5.1 Accumulating without cancellation + +$\mathcal{S}_{e,k}$ as written in [](#centered-shift) is the sum of two terms of order 200 m, at a +coordinate tilt of 50 m/km over a 4 km edge, that cancel to a few millimetres. That is +`PressureGradCentered`'s existing round-off exposure, not something the new scheme introduces +(§3.7.5), but the same algebra that produced [](#centered-shift) removes it, and the design +recommends doing so. + +Let $\Gamma_{e,k} = \Delta_e Z_{k} + \frac{\bar\alpha_{e,k}}{g}\Delta_e q_{k}$ and +$\Gamma^{+}_{e,k} = \Delta_e Z_{k+1} + \frac{\bar\alpha_{e,k}}{g}\Delta_e q_{k+1}$, so that +$\mathcal{S}_{e,k} = \tfrac12(\Gamma_{e,k} + \Gamma^{+}_{e,k})$. Using +$Z_{i,k+1} - Z_{i,k} = -\rho_0\alpha_{i,k}\tilde h_{i,k}$ and +$q_{i,k+1} - q_{i,k} = \rho_0 g \tilde h_{i,k}$ together with the same product rule as before, + +$$ +\Gamma^{+}_{e,k} - \Gamma_{e,k} = -\,\rho_0 \, \overline{\tilde h}_{e,k}\, \Delta_e \alpha_{k}, +\qquad +\Gamma_{e,k+1} - \Gamma^{+}_{e,k} += \frac{\Delta_e q_{k+1}}{g}\left(\bar\alpha_{e,k+1} - \bar\alpha_{e,k}\right). +$$ (gamma-increments) + +Both increments are products of a small factor with a bounded one — the *horizontal* contrast in +specific volume within a layer, and the *vertical* contrast between adjacent layers — so +$\mathcal{S}$ can be walked down the column with no cancellation of large numbers anywhere, starting +from $\Gamma_{e,1}$, which is the inverse-barometer residual at the sea surface and is itself small +for a state at rest. + +[](#gamma-increments) should be reconciled against §3.7.3's [](#centered-error), which describes the +same quantity in a different grouping, as a check on both. In the limit [](#centered-error) is written +for — specific volume horizontally uniform within each layer, thickness merely redistributed — the +first increment vanishes identically and the second one carries the whole signal, reproducing +[](#centered-error)'s downward accumulation through the horizontal displacement of the interfaces. +The two expressions are expected to agree up to a $k$-independent constant fixed by the anchor, and +confirming that (including the constant, and without assuming +$\sum_j \Delta_e\tilde h_j = 0$) is one of the algebraic checks assigned to the reference derivation +in §4.5.3. + +Consequences worth stating, because they change several things downstream: + +- Both $\mathcal{S}$ and source 4 of $\mathcal{R}$ are column prefix sums. They should be + accumulated in the same scan, from the same end of the column (§3.7.4 closing note), and cost one + scan rather than two. +- The perturbation form §3.7.5 holds in reserve becomes unnecessary in double precision and probably + in single as well. That is now a measurement (§5.2 in both precisions) with a plausible expected + answer rather than an open question. +- The reduction to `PressureGradCentered` (§3.9) becomes *algebraic* rather than bit-for-bit, + because [](#gamma-increments) evaluates $\mathcal{S}$ in a different order from `PGrad.h`. This is + the trade the design accepts: §4.4 already expects agreement to round-off rather than bit-for-bit, + and it is a better cross-check for being arithmetically independent. ### 3.6 The edge operator -The discrete tendency lives at edge $e$ and is the edge-normal projection of the PGF. The side-wall -line integral $\int_{\partial A}(\cdots)\,dl$ in [](#ho-target) becomes, on the TRiSK C-grid, the -difference of the two adjacent columns' contributions across the edge, divided by the cell-center -distance $d_e$: +The discrete tendency lives at edge $e$ and is the edge-normal projection of the PGF. Every +horizontal difference in §3.5 is the two-cell TRiSK operator $$ -\left[\nabla_n \Pi\right]_{e,k} = \frac{1}{d_e}\sum_{i \in CE(e)} -n_{e,i}\, \Pi_{i,k}^{(e)}, +\left[\nabla_n f\right]_{e} = \frac{1}{d_e}\sum_{i \in CE(e)} -n_{e,i}\, f_{i}^{(e)}, $$ (edge-grad) -where $\Pi_{i,k}^{(e)}$ is column $i$'s layer integral [](#sidewall-int) evaluated with the -equation-of-state coefficients shared across edge $e$ [](#edge-ref). **Phase 1 uses this operator as -written** — the same two-cell stencil `PressureGradCentered` uses, so the horizontal accuracy is -unchanged from today. Everything Phase 1 gains is in the vertical and in the interface terms. +applied to column quantities $f_i^{(e)}$ evaluated with the equation-of-state coefficients shared +across edge $e$ [](#edge-ref). **Phase 1 uses this operator as written** — the same two-cell stencil +`PressureGradCentered` uses, so the horizontal accuracy is unchanged from today. Everything Phase 1 +gains is in the vertical and in the fixed-pressure comparison. Nothing is assumed constant across the edge: the horizontal contrast in $\Theta$ and $S$ between the -two columns enters at full strength through the two column integrals. What Phase 1 does *not* do is -raise the order of the horizontal difference, which is Phase 2's job. - -#### 3.6.1 Raising the horizontal order without losing the cancellation (Phase 2) - -The natural way to reach fourth order — reconstruct $\Theta$ and $S$ from cell centers to the edge -with a cubic stencil, then form $\alpha p$ there — **would forfeit the robustness property of §3.7**. -It is worth being explicit about this, because it is the approach a reader would reasonably assume. -The cancellation is a statement about a *pair* of columns bounding one control volume; a quantity -interpolated to the edge from four or more cells does not belong to any control volume, and there is -no reason for the pressure and geopotential terms built from it to balance. Accuracy at the cell -centers does not carry over to a cancellation at the edge between them (assumption A1, §3.7.6). - -The constraint Phase 2 must satisfy instead is: - -> The higher-order edge operator must be expressible as a **weighted sum of two-column pair -> contributions**, each pair built exactly as in Phase 1 — with its own shared expansion point and -> its own control volume. - -Because each pair contribution is individually zero for a resting ocean in the exact set, any -weighted sum of them is zero as well, and the machine-precision property is inherited rather than -re-derived. A fourth-order edge-normal difference built from the nearest and next-nearest cells -along the normal, with each cell pair contributing its own Phase 1 integral, satisfies this; a -scheme that reconstructs to the edge first does not. - -Constructing such a stencil on Omega's unstructured TRiSK mesh is the **principal open design -question of Phase 2** and is deliberately not settled here. The relevant machinery — the wider edge -neighborhoods used for high-order tracer reconstruction, cf. -{ref}`omega-design-governing-eqns-omega1` §10 and White & Adcroft (2008) — exists, but its accuracy -on variable-resolution meshes and the cost of the extra pair evaluations both need assessment before -the form is fixed. Phase 1 does not depend on the answer. +two columns enters at full strength through the two columns' $\hat\alpha^{(e)}_i(p)$ and hence +through $z_i(p)$. What Phase 1 does *not* do is raise the order of the horizontal difference, which +is Phase 2's job. + +#### 3.6.1 Raising the horizontal order (Phase 2) + +**The robustness property of §3.7 places no constraint on the wide stencil.** This is worth stating +explicitly, because the opposite would be true of a four-term force-balance formulation, where a +quantity interpolated to the edge from four or more cells belongs to no control volume and so has no +reason to balance. That would force the stencil to be a weighted sum of two-column pair +contributions, and settling its form on an unstructured, variable-resolution mesh would be a +prerequisite for Phase 2. Under [](#ho-exact) it is not. + +The reason is that the quantity being differenced is $z_i(p)$ — a *per-column function of pressure*, +not a nonlinear product formed at the edge. For a resting ocean in the exact set, [](#z-of-p) makes +$z_i(p)$ the same function of $p$ in every cell of the neighbourhood, up to the constant set by each +column's anchor, and for a resting ocean those constants agree as well. **Any** consistent +edge-normal gradient operator — any operator that annihilates a constant, which every consistent +gradient operator does — therefore returns zero. The machine-precision property is inherited by +construction, and there is no pair-decomposition requirement. + +What remains for Phase 2 is an ordinary accuracy question rather than a structural one: + +- The **stencil width and weights** are chosen for order of accuracy on Omega's unstructured, + variable-resolution TRiSK mesh, drawing on the wider edge neighbourhoods used for high-order + tracer reconstruction (cf. {ref}`omega-design-governing-eqns-omega1` §10 and White & Adcroft + (2008)). Assumption A1 (§3.7.6) still applies: the achieved order must be measured, not assumed. +- The **expansion point** of [](#alpha-taylor) must be shared across whatever set of cells the + stencil couples, for the same reason §3.3.1 gives at a two-cell edge. Sharing one point across the + whole neighbourhood is the simplest option and is sufficient for exactness; building the stencil as + a weighted sum of pairs, each with its own shared point, keeps the expansion error smaller and is + therefore preferable on assumption-A2 grounds. Both work; the choice is now a trade-off to be + measured rather than a constraint imposed by the robustness property. + +Phase 1 does not depend on either answer. ### 3.7 Where the cancellation is exact, and where it is not @@ -509,16 +769,18 @@ For each edge and layer: 1. **Both sides of the edge use the same specific-volume profile.** The two columns must evaluate $\hat\alpha$ as one and the same function of pressure over the pressure range the layer spans. - This is what the edge-shared expansion point of §3.3.1 delivers, and it is why that choice is - load-bearing rather than cosmetic. -2. **Every face integral is exact for that profile.** The side-wall integrals must be exact for - $\hat\alpha(p)\,p$ (§3.5 chooses the quadrature to guarantee this), and the sloping top and - bottom interfaces must use the pressure-averaged $\hat\alpha p$ of §3.8, not the average of the - two cells' interface values. -3. **The geopotential is built from that same profile.** The geometric height entering - $g\nabla z$ must be the integral of the same $\hat\alpha$, layer by layer, down to a common - anchor. Satisfying this requires a per-edge correction to the geometric height difference; - see §3.7.4. + This is what the edge-shared expansion point of §3.3.1 delivers, and under the reduced target of + §3.2 it is the *only* remaining mechanism by which exactness can fail on a resolved profile. +2. **The two columns are compared at a common pressure, to all orders retained.** Layer $k$ spans + different pressure ranges in the two columns, so $[\nabla_n z]_p$ requires shifting each + column's height from its own interface pressures to a pressure shared with its neighbour. + Truncating that shift at first order is what `PressureGradCentered` does, and its truncation is + the whole of the error Phase 1 removes; the shift must therefore be carried to the order of the + reconstruction, which is what §3.5's sources 1–3 supply. +3. **The height being shifted is the hydrostatic integral of that same profile.** `VertCoord`'s + $Z$ is built from each cell's own exact TEOS-10 $\alpha$, not from the edge-shared + $\hat\alpha^{(e)}$, so the difference between the two must be accounted for. This is §3.5's + source 4, and it is a column prefix sum; see §3.7.4. Conditions 2 and 3 are about the discretization alone and are under the implementation's control. Meeting them means the scheme returns the **exact pressure gradient of the water column it has @@ -527,6 +789,12 @@ about the state: it holds when the reconstruction reproduces the true profile, a however much the reconstruction misses, when it does not. Meeting all three gives a PGF that is **zero to machine precision**, for any tilt, any layer thickness, and any bathymetry. +Note that conditions 2 and 3 are, between them, exactly the requirement R3 of §3.5 — that +$\mathcal{R}$ cancel $\mathcal{S}$ to round-off on a resolved profile. Stating them separately is +useful because they fail in distinguishable ways: a defect in condition 2 leaves a residual local +to the layer, while a defect in condition 3 leaves one that grows with depth. §5.2's guard tests +are arranged to tell them apart. + The point worth carrying away, because it is what makes this tractable, is that **the reconstructed profile does not have to be accurate for the cancellation to be exact — it only has to be shared.** The scheme needs the two columns to describe *one* water column, not the *right* one. Accuracy is a @@ -589,13 +857,13 @@ the bottom-layer error seen in realistic global configurations. Whether this dow seen in realistic global configurations is a plausible diagnosis, not an established one; it is carried as A4 in §3.7.6 and tested in §5.3. -#### 3.7.4 Condition 3 and the geopotential +#### 3.7.4 Condition 3 and the column scan -Condition 3 constrains how the geopotential term is built. Two questions arise, and they have -different answers; an earlier revision of this design conflated them and drew the wrong conclusion -from the first. +Condition 3 constrains how the height being shifted is built. Two questions arise, and they have +different answers; they are easy to conflate, and doing so leads to the conclusion that `VertCoord` +must be changed, which it need not be. -**The quadrature question, which is already settled.** `VertCoord::computeGeomZHeight` builds $z$ by +**The quadrature question, which is settled.** `VertCoord::computeGeomZHeight` builds $z$ by accumulating $\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — apparently a midpoint rule, where condition 3 asks for the integral of the reconstructed $\hat\alpha$. For a Phase 1 reconstruction these are **the same quantity**. Integrating [](#alpha-taylor) with the linear deviations of §3.4 @@ -620,71 +888,97 @@ $\tfrac12\alpha_{\Theta\Theta}\Theta'^2$, none of which integrate to zero over t option is adopted, [](#z-increment-exact) no longer holds and the question returns. **The sharing question, which is the real constraint.** What condition 3 actually requires is that -the geopotential be built from the *same* $\hat\alpha$ the pressure terms use — and §3.3.1 makes -that an **edge** quantity, since its coefficients and expansion point are averages over the two -cells of the edge. A cell-based $z$ cannot carry an edge-dependent $\hat\alpha$ however it is -integrated. Two mismatches follow, both $O(\alpha_{pp}(\Delta p^{\text{mid}}_e)^2)$ per layer and -both accumulating down the column: - -1. `VertCoord`'s $z$ uses the exact per-cell TEOS-10 $\alpha$; the PGF uses the edge-shared - linearized $\hat\alpha$. The residual is the - $\tfrac12\alpha_{pp}(p^{\text{mid}}_i - \bar p^e)^2$ term. -2. The geopotential body force is the gradient of $\Phi$ **at fixed pseudo-height**, i.e. at fixed - pressure. Differencing each column's layer-mean $\Phi$ across the edge compares layer means taken - over *different* pressure ranges whenever the interfaces tilt, and that difference does not - vanish for a resting ocean. - -**Resolution: the PGF computes a per-edge correction to the `VertCoord` $z$ difference**, built from -the edge-shared $\hat\alpha$ and accumulated down the column. Stated as a correction rather than a -replacement, this does not create the second, slightly different $z$ that Requirement 2.4 exists to -prevent: `GeomZInterface`/`GeomZMid` remain the model's one geometric height and are unchanged, and -the PGF adds a term to a *difference* that is identically zero when the two columns' interfaces are -level. Accumulating only the correction, rather than re-deriving $z$, also preserves most of the -precision headroom §3.7.5 warns is otherwise consumed, since the correction is small by -construction. - -The implementation consequence is recorded in §4.1.3: the correction is a column prefix sum and -therefore cannot live inside a per-edge, per-vertical-chunk kernel call. +the height be the hydrostatic integral of the *same* $\hat\alpha$ the fixed-pressure shift uses — +and §3.3.1 makes that an **edge** quantity, since its coefficients and expansion point are averages +over the two cells of the edge. A cell-based $Z$ cannot carry an edge-dependent $\hat\alpha$ however +it is integrated. This is §3.5's source 4, and it is $O(\alpha_{pp}(\Delta p^{\text{mid}}_e)^2)$ per +layer, accumulating down the column. §3.5 gives its closed form: the edge-shared profile's layer mean +is [](#alpha-edge-layer-mean), the per-layer mismatch against `VertCoord`'s increment is the +second-order equation-of-state remainder [](#eos-remainder), and what the scheme needs is $\Delta_e$ +of its running sum down the column. + +**Resolution: the PGF accumulates $\Delta_e$ of $\varepsilon_{i,k}$ down each edge's column**, built +from the edge-shared $\hat\alpha$, and adds it to the local terms of $\mathcal{R}$. This does not +create the second, slightly different $z$ that Requirement 2.4 exists to prevent: +`GeomZInterface`/`GeomZMid` remain the model's one geometric height and are unchanged, and what the +PGF accumulates is a per-edge *difference* of second-order EOS remainders, identically zero when the +two columns' states coincide. + +Two things about it are easy to get wrong. + +- **This piece is genuinely small; the scheme as a whole is not a small correction.** Source 4 is + second order in the cross-edge pressure contrast, so accumulating it consumes little precision. But + sources 1–3, and $\mathcal{S}$ itself, are the same size as the terms they correct — at 50 m/km both + are $\approx 0.5$ m s$^{-2}$ before cancellation. Writing something as a "correction" therefore buys + no precision on its own; what buys it is [](#gamma-increments) and §3.5.1, which remove the + cancellation algebraically. +- **The scan is not optional and not a detail.** §4.1.3 records the implementation consequence: a + column prefix sum cannot live inside a per-edge, per-vertical-chunk kernel call. Both this scan and + $\mathcal{S}$'s accumulation via [](#gamma-increments) are prefix sums and should share one pass. One related question is left to implementation time: `VertCoord` builds $z$ upward from the bathymetry while pressure is built downward from the surface, so the two accumulate round-off from -opposite ends of the column. Which end the correction accumulates from is a round-off question -(§3.7.5), not a consistency one — condition 3 is satisfied either way. +opposite ends of the column. Which end the scan of this section and the accumulation of +[](#gamma-increments) run from is a round-off question (§3.7.5), not a consistency one — condition 3 +is satisfied either way. It is now a single decision rather than two, since both should share one +pass. #### 3.7.5 Round-off in the deep ocean -Separate from everything above, and not fixed by it, is how much precision the cancellation itself -consumes. At 4000 m the side-wall integrand $\hat\alpha p$ is about -$4\times10^{4}\ \mathrm{m^2\,s^{-2}}$, while the baroclinic signal that survives in the edge -tendency is of order $10^{-6}\ \mathrm{m\,s^{-2}}$ times $d_e$. Roughly ten significant digits are -consumed before any physics appears. Double precision leaves adequate margin; a +Separate from everything above, and not fixed by it, is how much precision the cancellation +consumes. At 4000 m the hydrostatic height difference across a steeply tilted edge is of order +$10^{2}$ m, while the part of it that survives in the edge tendency is of order +$10^{-3}$ m — the millimetre-scale residual of [](#centered-shift). Roughly five significant digits +are consumed there, and roughly ten by the time the tendency is formed against a signal of order +$10^{-6}\ \mathrm{m\,s^{-2}}$ times $d_e$. Double precision leaves adequate margin; a `OMEGA_SINGLE_PRECISION` build does not, and the machine-precision cancellation of §3.7.2 would simply be invisible beneath round-off. -If that turns out to matter, the fix is to compute in **perturbation form**: subtract a local -reference profile from $\hat\alpha$ before integrating and add its contribution back analytically. -This is *not* a Shchepetkin–McWilliams (2003)-style reference-profile subtraction in the usual -sense. The reference here is local to the edge and layer, its contribution cancels identically -rather than approximately, and the accuracy of the scheme does not depend at all on how well it -matches the local column — so it does not degrade in the strong-gradient, steep-layer regions where -a global reference profile would. It changes nothing in exact arithmetic. Whether it is needed is a -measurement (§5.2, run in both precisions), not an assumption. +Three points. + +- **This exposure belongs to `PressureGradCentered`, not to the new scheme.** It is entirely in + $\mathcal{S}_{e,k}$ as [](#centered-shift) writes it — two terms of order 200 m cancelling to + millimetres — which is what the default PGF has always computed. $\mathcal{R}$ adds none of its + own: requirement R2 of §3.5 exists precisely so that every one of its four sources is formed from + quantities that are individually small. Any conclusion reached here therefore applies to the + centered scheme as well, and it would be wrong to treat a single-precision round-off floor as an + objection to `FiniteVolume` specifically. +- **§3.5.1 removes it, in both schemes.** Accumulating $\mathcal{S}$ through + [](#gamma-increments) never forms the two large terms at all. If that form is adopted — and the + design recommends it — the ten-digit estimate above does not apply to the implemented scheme, and + the expected answer to the single-precision question changes from "probably fails" to "probably + passes". That is a prediction to be measured (§5.2, run in both precisions), not an assumption. +- **The perturbation form remains in reserve and is probably not needed.** It would subtract a local + reference profile from $\hat\alpha$ before integrating and add its contribution back analytically. + This is *not* a Shchepetkin–McWilliams (2003)-style reference-profile subtraction in the usual + sense: the reference is local to the edge and layer, its contribution cancels identically rather + than approximately, and the accuracy of the scheme does not depend at all on how well it matches + the local column — so it does not degrade in the strong-gradient, steep-layer regions where a + global reference profile would. It changes nothing in exact arithmetic. With + [](#gamma-increments) in place it addresses a problem that has already been removed + algebraically, so it should be adopted only against a measurement. #### 3.7.6 Assumptions that still need testing Everything above concerns properties the implementation can be built to have. The following are assumptions this design is making that only testing can confirm: -- **A1 — Accuracy at cell centers does not imply accuracy at edges.** The cancellation above is a - statement about a *pair* of columns at an edge. Reconstructing $\Theta$ and $S$ accurately at each - cell center does not by itself make the combination $\hat\alpha(\Theta,S,p)\,p$ accurate at the - edge between them, because that combination is nonlinear. The horizontal order claimed in §3.6 is +- **A1 — Accuracy at cell centers does not imply accuracy at edges.** Reconstructing $\Theta$ and + $S$ accurately at each cell center does not by itself make $z_i(p)$, and hence + $[\nabla_n z]_p$, accurate at the edge between them, because $\hat\alpha(\Theta,S,p)$ is a + nonlinear function of the reconstructed quantities. The horizontal order claimed in §3.6 is therefore a design target to be confirmed by measured convergence (Requirement 2.6), not something - that follows from the cell-centered reconstruction order. + that follows from the cell-centered reconstruction order. Note that A1 is now purely an *accuracy* + assumption: the reformulation of §3.2 removes its consequences for the machine-precision property, + which is why §3.6.1's stencil constraint could be dropped. - **A2 — The EOS expansion is good enough across the edge.** [](#alpha-taylor) is expanded about the shared edge state [](#edge-ref), and its error grows with the horizontal contrast in $\Theta$ and $S$ across the edge and with the layer's pressure range. Whether the first-order expansion suffices in frontal regions, or whether the second-order option of §3.3 is needed, is an open question. + A2 is now measurable more directly than by an accuracy sweep alone: §3.5's source 4 *is* the + second-order remainder of that expansion, so the magnitude of the accumulated part of + $\mathcal{R}$ relative to its local part is a running diagnostic of how hard the expansion is being + worked. Reporting that ratio is cheap and should be done. - **A3 — The residual outside the exact set is small enough in practice.** The $O(\tilde h^2)$ and $O(\tilde h^3)$ entries in §3.7.3 describe how the error *scales*; how large it actually is at the vertical resolutions Omega can afford is unknown. @@ -693,112 +987,90 @@ assumptions this design is making that only testing can confirm: A configuration whose profile falls in Phase 1's exact set gives a direct test: if spurious bottom-layer flow persists there, the cause lies elsewhere — most likely in the layer-mean treatment in the tracer and remapping operators (§4.3) — and Phase 1 will not cure it. See §5.3. - -### 3.8 Geopotential and metric terms - -The geopotential body-force term (first line of [](#ho-target)) is -$g\,\nabla z + \nabla(\phi_{TP}+\phi_{SAL})$. The geometric height $z$ and geopotential are -provided by `VertCoord` (`GeomZMid`/`GeomZInterface`, `GeopotentialMid`; computed via -{ref}`omega-design-governing-eqns-omega1` Eqs. discrete-z and the geopotential relation). -Its layer average and edge-normal gradient are evaluated with the same high-order edge -reconstruction [](#edge-grad). The tidal-potential and self-attraction-and-loading -contributions enter through `VertCoord` and are differenced identically (Requirement 2.7); -they are zero in early Omega versions. - -The two metric terms (third and fourth lines of [](#ho-target)) are the pressure force on the -layer's sloping top and bottom interfaces. They use the **same** edge-normal operator to evaluate -the interface slopes $\nabla \tilde z_k^{\text{top}}$, $\nabla \tilde z_k^{\text{bot}}$, but the -quantity multiplying each slope needs care. Because the interface is sloping, it sweeps through a -range of pressures between the two cell centers, and the force is an integral along it. The correct -factor is therefore the **average of $\hat\alpha p$ over that pressure range**, - -$$ -\left\langle \hat\alpha p \right\rangle_{e,k}^{\text{top}} -= \frac{1}{p_{R,k}^{\text{top}} - p_{L,k}^{\text{top}}} - \int_{p_{L,k}^{\text{top}}}^{p_{R,k}^{\text{top}}} \hat\alpha(p)\, p \; dp, -$$ (metric-divdiff) - -and likewise at the bottom interface, reducing to -$\hat\alpha\!\left(p^{\text{top}}\right) p^{\text{top}}$ when the interface is level in the two -columns. Because $\hat\alpha(p)$ is a low-order polynomial (§3.3), this integral is evaluated in -closed form at no meaningful cost. - -**Implement this as an integral, not as an average multiplied by a slope.** Since -$\nabla_n\tilde z^{\text{top}}_{e,k} = -(p^{\text{top}}_{R} - p^{\text{top}}_{L})/(\rho_0 g\,d_e)$, -the divisor in [](#metric-divdiff) and the slope it multiplies cancel identically, and the whole -term is - -$$ -\frac{1}{g\,d_e}\int_{p^{\text{top}}_{L,k}}^{p^{\text{top}}_{R,k}} \hat\alpha(p)\, p \; dp . -$$ (metric-integral) - -Forming the average literally divides by a quantity that is zero wherever the interfaces are level, -which is most of the domain; the reduction noted above is a $0/0$ in that form and is well defined -only in [](#metric-integral). - -The tempting alternative — averaging the two cells' interface values, -$\tfrac12[(\hat\alpha p)_L + (\hat\alpha p)_R]$ — agrees with [](#metric-divdiff) only when the -tilt is small, and leaves behind a residual that grows with the square of the tilt and does *not* -vanish for the water columns §3.7.3 says should cancel exactly. It would therefore break -condition 2 of §3.7.2 and forfeit the robustness property in exactly the steeply sloped regions -this design is meant to fix. - -This integral is what `PressureGradCentered` omits altogether, and supplying it is the central -content of Phase 1. These terms vanish for level interfaces and supply the leading correction for -sloping layers; together with the side-wall integral [](#sidewall-int) and the geopotential term -they complete the force balance on the layer's control volume (§3.1.1). +- **A5 — The treatment at the top and bottom of the column is adequate.** [](#ho-exact) averages over + the edge control volume's pressure range $[p^{\text{top}}_{e,k}, p^{\text{bot}}_{e,k}]$, which in + general is not either column's own range, so each column's reconstruction must be evaluated + slightly outside the layer it was built for. In the interior this is a small extrapolation across a + smooth reconstruction and is harmless. At the surface, where the two columns have different + $p^{\text{surf}}$, and at the sea floor, where they may have different `maxLevelCell` and where a + partial cell carries the whole signal for the Polaris `bathymetry_step` configuration, it is not + obviously harmless and **has not been tested** — the reference derivation was run with equal layer + counts in both columns. The extrapolation must be defined explicitly, and whichever choice is made + must reduce to a single function when the two reconstructions coincide, or condition 1 of §3.7.2 + fails at the column ends. §5.1's `bathymetry_step` and `surface_pressure_gradient` variants are + where it is measured. + +### 3.8 Scope: the reduction and the vertical coordinate + +The reduction of §3.1.1 rests on one property of Omega — that $\tilde z$ is a function of pressure +alone — so it is worth recording precisely how much freedom that leaves and where the boundary is. + +**It holds for any ALE layering of pseudo-height.** p-star, sigma-p, z-tilde-star and hybrid schemes +all relocate layer interfaces within $\tilde z$, in space and in time, and none of them redefines +$\tilde z$. Interfaces may be arbitrarily tilted, arbitrarily thin, and at wholly different pressures +in neighbouring columns; [](#grad-p-zero) is untouched, because it is a statement about coordinate +surfaces (§3.1.1). Every term the scheme computes is a tilt term, so there is no configuration in +which the reduction quietly turns the scheme into a no-op. + +**It fails only if Omega abandons pseudo-height.** A coordinate $r$ that is not a function of pressure +alone — geometric $z$, a true $z$-star, or a genuine isopycnal coordinate — gives $\nabla_r p \neq 0$, +and then all four pressure terms of [](#ho-target) become real work rather than a discretization of +zero. Should such a change ever be contemplated, [](#ho-target) as corrected here and the derivation in +§3.1 are the starting point, and §3.1.1's third consequence is the pitfall to carry forward with them. + +**The geopotential body force** — the first line of [](#ho-target) — is the whole target. It is +$g\,\nabla z + \nabla(\phi_{TP}+\phi_{SAL})$; $z$ enters as `VertCoord`'s `GeomZInterface` through +[](#centered-shift), and the tidal-potential and self-attraction-and-loading contributions are +supplied by `VertCoord` and differenced with [](#edge-grad) (Requirement 2.7). They are zero in early +Omega versions and are unaffected by anything in §3.5. ### 3.9 Reduction to the centered scheme -The new scheme collapses to the implemented `PressureGradCentered` form -($T^p_{e,k} = -\nabla M + \tfrac12(p_0+p_1)\nabla\alpha - \nabla\Phi$, with $M = \alpha p + g z$) -in one configuration: **specific volume constant within each layer**, meaning both -$\Theta' = S' = 0$ and the equation-of-state expansion [](#alpha-taylor) truncated to $\alpha_0$, -combined with the two-cell edge operator [](#edge-grad). This is the isopycnal-model assumption, -and it is the verification-only mode of §3.4. - -Two things fall out of that configuration that are worth noting, because they show the reduction is -structural rather than a special case bolted on: +Setting $\mathcal{R}_{e,k} \equiv 0$ in [](#ho-discrete) recovers `PressureGradCentered` exactly. +That is the content of [](#centered-shift), which is an algebraic identity about the implemented +code rather than a limit reached by tuning options, so the reduction is **structural in the strict +sense**: there is one term, the reduction is switching it off, and it holds at any tilt, any layer +thickness and any stratification. -- With $\alpha$ constant in the layer, $\alpha p$ is linear in pressure, so the sloping-interface - average [](#metric-divdiff) reduces *exactly* to the average of the two cells' interface values. - The interface term does not need to be switched off to recover the centered scheme; it degenerates - on its own. -- For the same reason, the layer integral [](#sidewall-int) is exact under any symmetric quadrature - rule, midpoint included, so the quadrature setting does not enter the reduction either. +The reduction is therefore exercised by a single configuration switch, `RemainderEnable: false` +(§4.1.1), which doubles as guard test (c) of §5.2. The agreement is algebraic rather than bit-for-bit +if §3.5.1's accumulation is used, since that evaluates $\mathcal{S}$ in a different order from +`PGrad.h` (§4.4); it would be bit-for-bit if [](#centered-shift) were assembled literally, and that is +a deliberate trade against round-off. -What remains is the Montgomery-potential algebra, and the two forms agree. This gives a direct -regression path (§5.5) and confirms the new code reproduces the existing scheme where it should. -The agreement is algebraic, not bit-for-bit — the operations are performed in a different order -(§4.4). +Because the reduction holds at any tilt, §5.5 should be run *at* nonzero tilt and over a sweep of +tilts. That is not merely permitted, it is the stronger test: the whole of the difference between the +two schemes is $\mathcal{R}$, so a tilt sweep confirms that $\mathcal{S}$ alone reproduces +`PressureGradCentered` and that both schemes are in fact responding to tilt. A reduction demonstrated +only on level interfaces would establish much less. ### 3.10 Per-step algorithm summary -Steps 1–3 are per cell and layer; step 4 is per edge and layer. Phase differences are marked. +Steps 1–3 are per cell and layer; step 4 is a per-edge column scan; step 5 is per edge and layer. +Phase differences are marked. -1. From `VertCoord`: read `PressureInterface`, `PressureMid`, `GeomZInterface`/`GeomZMid`, - geopotential, and interface pseudo-heights (already computed diagnostically each step). The - geometric height must satisfy condition 3 of §3.7.2, which requires the per-edge correction of - §3.7.4; `VertCoord` itself needs no change. +1. From `VertCoord`: read `PressureInterface`, `PressureMid`, `GeomZInterface`, `PseudoThickness`, + and the tidal/SAL potentials (already computed diagnostically each step). `VertCoord` itself + needs no change and no baseline step (§3.7.4). 2. Obtain $\alpha_0$ (= the existing `Eos::SpecVol` field) and the derivatives $\alpha_\Theta, \alpha_S, \alpha_p$ from one TEOS-10 evaluation ([](#alpha-derivs)). Both phases need all four; Phase 2 optionally adds second derivatives (§3.3). 3. Build the mean-preserving deviations $\Theta', S'$ ([](#vert-recon)) — **linear in Phase 1, parabolic in Phase 2** — using the actual non-uniform interface pressures (§3.4). -4. For each edge: form the shared expansion point [](#edge-ref) from the two adjacent cells; - evaluate each column's layer integral [](#sidewall-int) with those shared coefficients; add the - sloping-interface terms [](#metric-integral) and the corrected geopotential difference (§3.8, - §3.7.4); assemble - $T^p_{e,k}$ and accumulate into the tendency with `EdgeMask`. **Phase 1** uses the two-cell - operator [](#edge-grad); **Phase 2** uses the wider stencil of §3.6.1, built as a weighted sum of - such two-cell pair contributions. +4. For each edge, in one column scan: form the shared expansion point [](#edge-ref) layer by layer; + accumulate $\mathcal{S}_{e,k}$ through [](#gamma-increments) and the source-4 part of + $\mathcal{R}_{e,k}$ through §3.7.4, from the same end of the column (§3.7.4 closing note). +5. For each edge and layer: add the local sources 1–3 of $\mathcal{R}_{e,k}$ (§3.5), assemble + [](#ho-discrete) with the tidal/SAL difference, and accumulate into `Tend` with `EdgeMask`. + **Phase 1** uses the two-cell operator [](#edge-grad); **Phase 2** uses the wider stencil of + §3.6.1. ## 4 Design -The high-order scheme extends the existing `PressureGrad` class in +The `FiniteVolume` scheme extends the existing `PressureGrad` class in `components/omega/src/ocn/PGrad.{h,cpp}`. The class manager, creation/retrieval/removal methods, named-instance map, and dispatch logic are unchanged; the work is to flesh out the -`PressureGradHighOrder` functor (currently a no-op placeholder) and to widen the inputs the +`PressureGradFiniteVolume` functor (currently a no-op placeholder) and to widen the inputs the manager hands to it. ### 4.1 Data types and parameters @@ -806,18 +1078,18 @@ manager hands to it. #### 4.1.1 Parameters Configuration lives under the existing `PressureGrad` YAML group. The `PressureGradType` -enum (PGrad.h:22) is updated to give the high-order scheme a descriptive name and to drop +enum (PGrad.h:22) is updated to give the new scheme a descriptive name and to drop the unimplemented second placeholder, leaving a commented stub for a future variant: ```c++ enum class PressureGradType { Centered, // existing 2nd-order Montgomery scheme - FiniteVolume // high-order finite-volume analytic-integration scheme (this design) + FiniteVolume // layer-integrated finite-volume scheme (this design) // , // e.g. a 6th-order option, added when implemented }; ``` -New sub-options for the high-order scheme. Both phases use the same keys; Phase 2 adds values +New sub-options for `FiniteVolume`. Both phases use the same keys; Phase 2 adds values rather than keys, so no configuration written for Phase 1 needs to change when Phase 2 lands: ```yaml @@ -825,37 +1097,35 @@ rather than keys, so no configuration written for Phase 1 needs to change when P PressureGradType: 'FiniteVolume' # Centered | FiniteVolume HorzOrder: 2 # 2 = two-cell stencil (Phase 1); 4 = wide stencil (Phase 2) VerticalReconstruction: 'linear' # 'linear' (Phase 1) | 'ppm' (Phase 2) - # | 'constant' (verification only, see below) - QuadraturePoints: 2 # per-layer Gauss points for the side-wall integral + RemainderEnable: true # false = verification only, reduces to Centered (§3.9) ``` -- **Phase 1 default and target:** `HorzOrder: 2`, `VerticalReconstruction: 'linear'`. +- **Phase 1 default and target:** `HorzOrder: 2`, `VerticalReconstruction: 'linear'`, + `RemainderEnable: true`. - **Phase 2 target:** `HorzOrder: 4`, `VerticalReconstruction: 'ppm'`. -- `QuadraturePoints: 2` is exact for the integrand in both phases (§3.5) and should not normally be - changed. It is a knob because lowering it is needed for the verification configuration below, not - because raising it buys accuracy. - -`VerticalReconstruction: 'constant'` sets the specific volume constant within each layer — both -$\Theta' = S' = 0$ and the equation-of-state expansion truncated to $\alpha_0$. It is **verification -only**: combined with `HorzOrder: 2` it recovers `PressureGradCentered` (§3.9) and supports the -permanent regression test of §5.5. It is not a supported production setting, because it gives up the -exactness for linearly varying profiles that Requirement 2.3.3 asks for. The implementation should -log a warning if it is selected outside a test. - -`'constant'` is **not** the compressibility-only configuration, and the two are easy to confuse. -Truncating the expansion to $\alpha_0$ discards $\alpha_p$, which is exactly the term that makes the -scheme exact for the "uniform $\Theta$, $S$; compressibility only" row of §3.7.3. The configuration -that isolates compressibility is `'linear'` applied to a vertically uniform $\Theta$, $S$ profile: -the reconstruction slopes are then zero on their own, $\alpha_p$ is retained, and no separate -setting is needed. Tests that mean to isolate compressibility — including §5.2 — must select -`'linear'`, not `'constant'`. - -`HorzOrder` selects the width of the edge *stencil* — how many cell pairs contribute — not the order -of an interpolation of $\Theta$ and $S$ onto the edge. The distinction is not cosmetic; see §3.6.1. + +`RemainderEnable: false` switches off $\mathcal{R}_{e,k}$, which by [](#centered-shift) leaves +exactly `PressureGradCentered` (§3.9). It is **verification only**: it supports the permanent +regression test of §5.5 and serves as guard test (c) of §5.2. It is not a supported production +setting — it *is* the default scheme, reached by a more expensive path — and the implementation +should log a warning if it is selected outside a test. + +`HorzOrder` selects the width of the edge stencil used by [](#edge-grad). It is purely an accuracy +setting: it carries no constraint from the robustness property (§3.6.1). + +There is no vertical quadrature setting: the one integrand in [](#ho-discrete) is nearly constant +across the layer and is evaluated in closed form (§3.2). `FiniteVolume` names the layer-integrated +control-volume form of §3.1 rather than a face-by-face assembly of the pressure traction, which is +the narrower sense Adcroft et al. (2008) use. + +The configuration that isolates compressibility on its own is `'linear'` applied to a vertically uniform +$\Theta$, $S$ profile — the reconstruction slopes are then zero and $\alpha_p$ is retained — and it +needs no setting of its own. Tests that mean to isolate compressibility, including §5.2, select +`'linear'`. #### 4.1.2 New EOS support -`PressureGradHighOrder` needs $\alpha$ together with its first derivatives. The `Eos` class +`PressureGradFiniteVolume` needs $\alpha$ together with its first derivatives. The `Eos` class (Eos.h) currently exposes `computeSpecVol`, `computeSpecVolDisp`, and `computeBruntVaisalaFreqSq`, but no specific-volume derivatives. This design adds one method and three device arrays: @@ -891,7 +1161,7 @@ sets, built from the same $s$ and $t$ (no additional square root). The marginal TEOS-10 evaluation, which is what Requirement 2.2 bounds. The linear and constant EOS options supply trivial analytic derivatives. -#### 4.1.3 `PressureGradHighOrder` functor +#### 4.1.3 `PressureGradFiniteVolume` functor The functor mirrors `PressureGradCentered` (cached mesh/coordinate arrays, `Enabled` flag, `chunkStart`/`chunkLength` vertical iteration) but takes the additional reconstruction and @@ -913,46 +1183,46 @@ KOKKOS_FUNCTION void operator()(const Array2DReal &Tend, I4 IEdge, I4 KChunk, const; ``` -(The existing centered signature is unchanged.) Additional cached members hold the quadrature nodes -and weights and, in Phase 2, the wide-stencil cell lists and weights. The functor implements -§3.3–§3.8 per edge and vertical chunk, accumulating into `Tend` with `EdgeMask`, exactly as the -centered functor does. +(The existing centered signature is unchanged.) Additional cached members hold, in Phase 2, the +wide-stencil cell lists and weights. The functor implements step 5 of §3.10 per edge and vertical +chunk, accumulating into `Tend` with `EdgeMask`, exactly as the centered functor does. -Two aspects of the loop structure follow from §3.3.1 and are worth stating here, because they differ -from the obvious implementation: +Three aspects of the loop structure differ from the obvious implementation: -- **The layer integral is computed inside the edge loop, not cached per cell.** Both adjacent - columns' integrals [](#sidewall-int) use equation-of-state coefficients formed at the edge - [](#edge-ref), so the same cell yields a different integral at each of its edges. The per-cell +- **Column quantities built from $\hat\alpha$ are computed per edge, not cached per cell.** Both + adjacent columns' contributions use equation-of-state coefficients formed at the edge + [](#edge-ref), so the same cell yields a different result at each of its edges. The per-cell quantities that *can* be cached are the four EOS coefficients and the reconstruction slopes, which is where the TEOS-10 cost lives; the per-edge work is polynomial arithmetic on those cached - values. This is what keeps Requirement 2.2 satisfied despite roughly three times as many integral + values. This is what keeps Requirement 2.2 satisfied despite roughly three times as many column evaluations on a hexagonal mesh. -- **Phase 2's wide stencil is a loop over cell pairs, not a wider interpolation.** Each pair - contributes a complete Phase 1 evaluation with its own shared expansion point, and the pair - results are combined with the stencil weights (§3.6.1). Implementing Phase 2 as a wider - reconstruction feeding a single evaluation would be simpler and would break the property of §3.7. -- **The geopotential correction of §3.7.4 is a column scan and cannot live in this functor.** It is a - prefix sum down each column with edge-dependent coefficients, so it is not expressible as an - independent per-vertical-chunk operation. It is computed in a separate kernel that fills a per-edge - array, +- **The column scan of §3.10 step 4 cannot live in this functor.** $\mathcal{S}_{e,k}$ via + [](#gamma-increments) and source 4 of $\mathcal{R}_{e,k}$ are both prefix sums down each column + with edge-dependent coefficients, so neither is expressible as an independent per-vertical-chunk + operation. They are computed together in a separate kernel filling two per-edge arrays, ```c++ - Array2DReal GeopotCorrection; ///< (NEdgesAll, NVertLayers), owned by PressureGrad + Array2DReal ShiftFirstOrder; ///< (NEdgesAll, NVertLayers) — S_{e,k}, eq. (centered-shift) + Array2DReal RemainderAccum; ///< (NEdgesAll, NVertLayers) — source 4 of R_{e,k}, §3.7.4 ``` with a `parallelForOuter` over edges and a `parallelScanInner` down the column, in the same shape - as `VertCoord::computeGeomZHeight`. The functor then reads it chunk-wise like any other input. The - cost is one edge-sized 2-D array and one column scan per edge per step. This is the one structural - addition Phase 1 makes beyond the per-edge, per-chunk pattern the centered scheme uses. - -The Phase 1 and Phase 2 code paths differ only in the reconstruction degree (§3.4) and in whether -the pair loop has one entry or several. There is one functor, not two. + as `VertCoord::computeGeomZHeight`. The functor then reads them chunk-wise like any other input. + The cost is two edge-sized 2-D arrays and one column scan per edge per step. This is the one + structural addition Phase 1 makes beyond the per-edge, per-chunk pattern the centered scheme uses, + and it is not optional: §3.5's requirement R2 rules out forming either quantity by subtracting + large numbers inside the chunk loop. +- **$\mathcal{R}$'s local sources are the only part that is a plain per-chunk computation.** Sources + 1–3 of §3.5 depend on the layer's own interface pressures, thicknesses and reconstruction slopes, + and belong in the functor. + +The Phase 1 and Phase 2 code paths differ only in the reconstruction degree (§3.4) and in the width +of the edge stencil (§3.6.1). There is one functor, not two. ### 4.2 Methods `PressureGrad::computePressureGrad` keeps its role of selecting the configured option, but -its input list grows so the high-order branch can reach $\Theta$, $S$, and the EOS +its input list grows so the `FiniteVolume` branch can reach $\Theta$, $S$, and the EOS derivatives. The signature becomes: ```c++ @@ -967,18 +1237,18 @@ void computePressureGrad(Array2DReal &Tend, const Array2DReal &PressureMid, ``` The `Centered` branch ignores the new arguments and is byte-for-byte unchanged; the -`FiniteVolume` branch dispatches to `PressureGradHighOrder` through the same +`FiniteVolume` branch dispatches to `PressureGradFiniteVolume` through the same `parallelForOuter`/`parallelForInner` team pattern used today (PGrad.cpp). The call site in `Tendencies.cpp` is updated to pass $\Theta$, $S$ (from the tracer state) and the `Eos` instance, which it already references for `SpecVol`. Creation, retrieval, and removal (`init`, `create`, `get`, `getDefault`, `clear`, `erase`) -are unchanged. The high-order constructor additionally caches the reconstruction stencil and +are unchanged. The `FiniteVolume` constructor additionally caches the reconstruction stencil and quadrature weights from config. ### 4.3 Consistency and follow-up work -The high-order PGF is deliberately more accurate in the vertical than the rest of Omega's +This PGF is deliberately more accurate in the vertical than the rest of Omega's layer-mean operators. This is sanctioned by {ref}`omega-design-governing-eqns-omega1` §9, which singles out the PGF as **the** exception to the piecewise-constant assumption ("we will ignore most of these [within-layer deviation] terms in Omega. The exception is the pressure @@ -1001,7 +1271,7 @@ out of scope here and flagged as follow-up: ### 4.4 Retention of the centered implementation `PressureGradCentered` (PGrad.h:25) is deliberately **kept as a separate functor** rather -than reimplemented as the lowest-order configuration of `PressureGradHighOrder`, even though +than reimplemented as the lowest-order configuration of `PressureGradFiniteVolume`, even though §3.9 shows the latter reduces to it. The redundancy is small — the centered functor is a header-only, ~40-line loop body with no supporting machinery of its own — and it buys two things that a single implementation cannot provide: @@ -1012,7 +1282,7 @@ things that a single implementation cannot provide: just the PGF arithmetic. Collapsing them would make that comparison self-referential: a defect upstream of the order switch would appear identically in both limits and cancel. 2. **A stable default.** The algebraic reduction of §3.9 does not imply bit-for-bit agreement, - because the reduced high-order path performs the same operations in a different order. + because the reduced `FiniteVolume` path performs the same operations in a different order. Replacing the default PGF would be an answer-changing change for every existing configuration, which this design does not require. @@ -1025,27 +1295,33 @@ baseline step — not as part of this design. #### 4.5.1 Phase 1 — a consistent second-order scheme -**Delivers.** The finite-volume control-volume form (§3.1.1); the sloping-interface integral -(§3.8), which the centered scheme omits entirely; the equation-of-state expansion about a state -shared across each edge (§3.3.1); mean-preserving linear reconstruction of $\Theta$ and $S$ in -pressure (§3.4). The result is a pressure gradient that is zero to machine precision for any -resting ocean whose profile varies linearly with pressure, at any tilt, thickness, or bathymetry -(§3.7.3) — Requirement 2.3 in full. +**Delivers.** The exact fixed-pressure geopotential difference [](#ho-exact), evaluated as +`PressureGradCentered` plus the remainder $\mathcal{R}_{e,k}$ (§3.5); the equation-of-state expansion +about a state shared across each edge (§3.3.1); mean-preserving linear reconstruction of $\Theta$ and +$S$ in pressure (§3.4); the per-edge column scan that supplies $\mathcal{S}$ and $\mathcal{R}$'s +accumulated part (§3.7.4, §4.1.3). The result is a pressure gradient that is zero to machine +precision for any resting ocean whose profile varies linearly with pressure, at any tilt, thickness, +or bathymetry (§3.7.3) — Requirement 2.3 in full. **Does not deliver.** Fourth-order accuracy. The horizontal operator is the same two-cell stencil in use today (§3.6), so horizontal truncation error is unchanged from `PressureGradCentered`. Requirements 2.1 and 2.6 are met at second order only. -**Depends on.** Nothing unresolved. The `VertCoord` geopotential question of §3.7.4 is settled -there: no change to `VertCoord` is needed and no baseline step is required, because the midpoint rule -is already the exact layer integral of a Phase 1 $\hat\alpha$. What condition 3 does require — the -per-edge geopotential correction — is part of this phase's own implementation (§4.1.3), not a -prerequisite in another module. +**Depends on.** Nothing unresolved. The `VertCoord` question of §3.7.4 is settled there: no change to +`VertCoord` is needed and no baseline step is required, because the midpoint rule is already the exact +layer integral of a Phase 1 $\hat\alpha$. What condition 3 does require — the column scan — is part +of this phase's own implementation (§4.1.3), not a prerequisite in another module. + +**Open at implementation time.** Two items, neither of them blocking. Which end of the column the +scan accumulates from (§3.7.4 closing note) is a round-off question, settled by measurement. And the +treatment at the top and bottom of the column, assumption A5 of §3.7.6, has to be defined explicitly +rather than inherited — it is the one part of the formulation the reference derivation did not cover, +since it ran with equal layer counts in both columns. **Code and cost.** Three new `Eos` derivative fields and one new method (§4.1.2); the -`PressureGradHighOrder` functor; the per-edge geopotential correction array and its column scan -(§3.7.4, §4.1.3); no new TEOS-10 evaluations per cell and layer (Requirement 2.2), with roughly -three times as many polynomial layer integrals on a hexagonal mesh (§4.1.3). +`PressureGradFiniteVolume` functor; two per-edge arrays and one column scan (§3.7.4, §4.1.3); no new +TEOS-10 evaluations per cell and layer (Requirement 2.2), with roughly three times as many column +evaluations on a hexagonal mesh (§4.1.3). Most of the arithmetic is in the column scan. #### 4.5.2 Phase 2 — fourth order @@ -1053,36 +1329,50 @@ three times as many polynomial layer integrals on a hexagonal mesh (§4.1.3). quadratically with pressure; a wide horizontal stencil (§3.6.1); optionally a second-order equation-of-state expansion (§3.3). Requirements 2.1 and 2.6 at fourth order. -**Must preserve.** Everything Phase 1 establishes. In particular the machine-precision property must -survive the wider stencil, which is why §3.6.1 constrains that stencil to be a weighted sum of -two-column pair contributions rather than a reconstruction to the edge. The §5.2 gate is rerun -unchanged for Phase 2. +**Must preserve.** Everything Phase 1 establishes. The machine-precision property is inherited by any +consistent edge-normal stencil (§3.6.1) rather than having to be re-established, so what Phase 2 must +not break is narrower than it appears: it must keep the expansion point shared across whatever cells +the stencil couples, and it must re-examine [](#z-increment-exact) before adopting the second-order +equation-of-state expansion, which would otherwise reopen the §3.7.4 question. The §5.2 gate is rerun +unchanged. -**Open question.** The form of the wide stencil on Omega's unstructured, variable-resolution TRiSK -mesh is not settled by this design (§3.6.1). Resolving it — including the cost of the additional -pair evaluations — is the first task of Phase 2 and does not block Phase 1. +**No blocking open question.** The form of the wide stencil on Omega's unstructured, +variable-resolution TRiSK mesh is an ordinary accuracy-and-cost choice, settled by measurement against +Requirement 2.6, because exactness does not constrain it (§3.6.1). #### 4.5.3 Suggested order of work -1. Write the discrete form out in full — including the interface-metric sign convention, which - $\hat\alpha$ the interface integral uses when the two columns' reconstructions differ, and the - exact form of the per-edge geopotential correction (§3.7.4) — and confirm numerically that it - returns zero for a profile linear in pressure at large tilt. Doing this in the Polaris - two-column harness makes it executable and doubles as the reference implementation §5.1 needs. +1. **Write the discrete form out in full, in the Polaris two-column harness, before writing C++.** + Doing it there makes it executable — exactness becomes a pytest that runs in seconds on a login + node — and doubles as the independent reference implementation §5.1 needs, which it would not be + if written by reading the finished C++. *Substantially done*: the derivation of §3.1, the + corrected [](#ho-target), the cancellation [](#grad-p-zero) and the numerical zero for a profile + linear in pressure at large tilt have all been established this way. What remains is to re-express + the confirmed result in the reduced form of §3.5, and to settle four things this design leaves to + it: + + - the closed form of each of $\mathcal{R}$'s four sources, with requirement R2 of §3.5 satisfied — + no source formed by subtracting large numbers; + - the reconciliation of [](#gamma-increments) against [](#centered-error), including the anchor + constant (§3.5.1); + - which end of the column the scan accumulates from (§3.7.4); + - the top- and bottom-of-column treatment, assumption A5 (§3.7.6), which the existing derivation + did not cover. 2. Run the assumption-A4 diagnostic of §5.3, which uses the *existing* centered scheme and so can be done immediately and in parallel with step 1. If spurious bottom-layer flow survives a profile that Phase 1 would resolve exactly, the cause is elsewhere in the model and the priority of this work should be reconsidered before it is built. 3. Implement and verify Phase 1 against §5.1, §5.2, §5.3, and §5.5. -4. Take up Phase 2, starting from the stencil question in §3.6.1. Re-examine [](#z-increment-exact) - before adopting the second-order equation-of-state expansion. +4. Take up Phase 2. Re-examine [](#z-increment-exact) before adopting the second-order + equation-of-state expansion; that, and not the stencil, is the item that could reopen a settled + question. ## 5 Verification and Testing Testing reuses and extends the Polaris `horiz_press_grad` task family (`polaris/tasks/ocean/horiz_press_grad`), which is already Omega-only and built around a quasi-analytic, layer-mean TEOS-10 reference solution (`reference.py`, surface-anchored, -4-point Gauss). That analytic reference remains valid as "truth" for the high-order scheme, +4-point Gauss). That analytic reference remains valid as "truth" for `FiniteVolume`, so the principal changes are scheme selection and revised pass criteria, plus two full-model acceptance tests. @@ -1114,8 +1404,7 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient - **Scheme selection.** Add `PressureGrad: { PressureGradType: FiniteVolume, … }` to `forward.yaml` and parametrize each task over three configurations: - `centered` — the legacy `PressureGradCentered` functor, unchanged; - - `finite_volume_phase1` — `HorzOrder: 2`, `VerticalReconstruction: linear`, - `QuadraturePoints: 2`; + - `finite_volume_phase1` — `HorzOrder: 2`, `VerticalReconstruction: linear`; - `finite_volume_phase2` — `HorzOrder: 4`, `VerticalReconstruction: ppm` (added when Phase 2 lands). @@ -1133,7 +1422,7 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient The forward step still runs a single time step with only `PressureGradTendencyEnable: true`, reading the PGF acceleration from `NormalVelocityTend`. - **Reference.** `reference.py`/`analysis.py` compare `NormalVelocityTend` against the - layer-mean analytic HPGA (unchanged). For the high-order scheme the layer-mean comparison + layer-mean analytic HPGA (unchanged). For `FiniteVolume` the layer-mean comparison remains the correct target, since the scheme is a finite-volume, layer-averaged discretization. - **Accuracy gate (new, Requirement 2.1):** at a representative coarse resolution (e.g. the @@ -1194,21 +1483,38 @@ Three groups of profiles are run: - **Profiles the scheme resolves exactly:** $\Theta$, $S$ linear in pressure, including the constant case, which isolates compressibility on its own. Run these with - `VerticalReconstruction: 'linear'`, **not** `'constant'` — see §4.1.1; `'constant'` discards - $\alpha_p$ and so cannot be exact for compressibility. **Pass:** the PGF is zero at every edge and - layer to **machine precision** (double-precision builds; the threshold tracks `Real`'s epsilon and - the size of the hydrostatic terms, not a physical tolerance). Phase 1 and Phase 2 must both pass. + `VerticalReconstruction: 'linear'` (§4.1.1). **Pass:** the PGF is zero at every edge and layer to + **machine precision** (double-precision builds; the threshold tracks `Real`'s epsilon and the size + of the hydrostatic terms, not a physical tolerance). Phase 1 and Phase 2 must both pass. + + Assert this in the sharper form of §3.5's requirement R3 — that + $\mathcal{R}_{e,k} = -\mathcal{S}_{e,k}$ to round-off — and report both quantities, not only their + sum. $\mathcal{S}$ is the centered scheme's answer on the same state and is nonzero and + tilt-dependent; checking against it turns a comparison with zero into a cancellation of ten orders + of magnitude against a known reference, and it is what distinguishes a working scheme from one that + has stopped responding to tilt at all. - **Profiles it does not:** $\Theta$, $S$ quadratic in pressure, then a realistic profile. **Pass:** the residual shrinks like $\tilde h^2$ (Phase 1) and $\tilde h^3$ (Phase 2) as the vertical grid is refined at fixed tilt, matching §3.7.3. A residual that does not shrink at the tabulated rate means one of the three conditions in §3.7.2 has been broken somewhere in the implementation; it is a bug to find, not a tolerance to widen. -- **Guard tests:** rerun an exactly resolved profile with (a) the endpoint-average interface term in - place of [](#metric-integral), (b) a cell-local expansion point in place of [](#edge-ref), and - (c) the per-edge geopotential correction of §3.7.4 disabled. All three must *fail* the - machine-precision check. Without these, a passing result could just as easily come from a symmetry - of the test setup as from the scheme being right — and guard (c) in particular is the direct - evidence that the geopotential correction is load-bearing rather than decorative. +- **Guard tests.** Rerun an exactly resolved profile with each of the following, and require each to + *fail* the machine-precision check. Without them, a passing result could as easily come from a + symmetry of the test setup, or from the scheme having become insensitive to tilt, as from the scheme + being right. + + | guard | breaks | expected to fire because | + |---|---|---| + | (a) **tilt sensitivity** — assert $\mathcal{S}_{e,k}$ and $\mathcal{R}_{e,k}$ are *individually* nonzero and grow with tilt | nothing; this one runs on the passing configuration | a bug that zeroed the tilt response would satisfy every other check in this section perfectly. This is the guard against mistaking "no tilt terms" for "correct tilt terms" | + | (b) cell-local expansion point in place of [](#edge-ref) | condition 1, §3.7.2 | the two columns then use different approximations to one equation of state, so $z_i(p)$ differ by more than a constant (§3.3.1) | + | (c) `RemainderEnable: false` | conditions 2 and 3 | this is exactly `PressureGradCentered` (§3.9), whose error on this state is the thing Phase 1 removes | + | (d) source 4 of $\mathcal{R}$ omitted, local sources retained | condition 3 only | isolates the column scan: a residual that grows with depth rather than being flat down the column | + | (e) $\mathcal{R}$'s local sources truncated at first order | condition 2 only | isolates the fixed-pressure shift, leaving a residual local to each layer | + + Guards (d) and (e) are the pair that makes a failure diagnosable: condition 2 and condition 3 fail + in distinguishable ways (§3.7.2), and running both tells the implementer which one is broken without + another round trip. Guard (a) is the one to write first, because it is the only one that can fire on + a configuration where every other check passes. Guards must be checked against a deliberately broken configuration, not only against a passing one. A guard that cannot fire is worse than no guard, because it looks like protection. @@ -1220,13 +1526,15 @@ non-uniform** set of layer thicknesses, the recovered slope (Phase 1) or slope a the most likely place for the machine-precision gate above to fail, and it localizes the failure immediately. -The test is also run in a single-precision build, to measure the round-off floor of §3.7.5 and -settle whether the perturbation form is needed. +The test is also run in a single-precision build, to measure the round-off floor of §3.7.5. Note that +§3.7.5 now predicts this should *pass* if [](#gamma-increments) is used for $\mathcal{S}$, and that +the same measurement applies to `PressureGradCentered`; running the centered scheme alongside is what +makes the result interpretable. -Condition 3 of §3.7.2 requires the per-edge geopotential correction of §3.7.4, so the -machine-precision check cannot pass until that is in place; this test, together with guard (c) -above, is its acceptance criterion. It is implemented as a fast C++ unit test and also run as a -configuration of the Polaris two-column task. +Condition 3 of §3.7.2 requires the column scan of §3.7.4, so the machine-precision check cannot pass +until that is in place; this test, together with guards (c) and (d) above, is its acceptance +criterion. It is implemented as a fast C++ unit test and also run as a configuration of the Polaris +two-column task. **Covers:** Requirement 2.3 in full; rows 1–5 of the §3.7.3 table; the round-off floor of §3.7.5. @@ -1273,33 +1581,46 @@ under dynamics. ### 5.5 Test: Reduction to the centered scheme (permanent regression) -Configure the new scheme in the verification-only mode of §3.9 — `HorzOrder: 2`, -`VerticalReconstruction: constant` — and confirm it reproduces `PressureGradCentered` to round-off -on the two-column test. This guards Requirement 2.5 and protects the existing default during -refactoring. The test is established with Phase 1 and rerun unchanged for Phase 2, where it also -confirms the wider stencil collapses correctly to the two-cell one. - -Note that this configuration is not a supported production setting (§4.1.1); it exists so that this -comparison is possible. Keeping it costs one branch in the reconstruction and one in the -equation-of-state expansion. +Configure the new scheme with `HorzOrder: 2`, `RemainderEnable: false` and confirm it reproduces +`PressureGradCentered` to round-off on the two-column test. This guards Requirement 2.5 and protects +the existing default during refactoring. The test is established with Phase 1 and rerun unchanged for +Phase 2, where it also confirms the wider stencil collapses correctly to the two-cell one. + +**Run it at nonzero tilt, and at several tilts.** Per §3.9 the reduction is exact at any tilt, so a +level-interface configuration would be a weaker test than the design supports — and a tilt sweep here +is what confirms that $\mathcal{S}$ alone is reproducing the centered scheme rather than the two +schemes agreeing because neither is responding to tilt. + +Note that `RemainderEnable: false` is not a supported production setting (§4.1.1); it exists so that +this comparison is possible. Keeping it costs one branch. + +This test is retained permanently rather than treated as a one-time transition check, and that choice +is the reason `PressureGradCentered` is kept as a separate implementation rather than reimplemented as +the lowest-order configuration of `PressureGradFiniteVolume` (§4.4). The two functors read the mesh, +`VertCoord`, and EOS state through independently written code, so their agreement to round-off is +evidence about *shared upstream* state as well as about the PGF arithmetic: a wrong edge mask, a +mis-indexed interface array, or a misinterpreted `VertCoord` convention shows up as a disagreement. +Were the centered scheme replaced by an order-2 configuration of the new code, this comparison would +reduce to comparing an implementation against itself, and any defect upstream of the order switch +would cancel out of it. **Covers:** Requirement 2.5; §3.9. ### 5.6 Cost check Requirement 2.2 bounds the number of TEOS-10 evaluations, and nothing above tests it — the scheme -could satisfy every accuracy gate while quietly calling the equation of state inside the quadrature -loop. Two cheap checks close that: +could satisfy every accuracy gate while quietly calling the equation of state inside the column loop. +Two cheap checks close that: - **Evaluation count.** With an instrumented `Eos`, confirm the number of specific-volume - evaluations per time step is one per cell per layer and is **unchanged** when `QuadraturePoints` - and `HorzOrder` are varied. This is the property Requirement 2.2 actually states, and it is a - counter comparison, not a timing measurement, so it is deterministic and suitable for CI. + evaluations per time step is one per cell per layer and is **unchanged** when `HorzOrder` and + `VerticalReconstruction` are varied. This is the property Requirement 2.2 actually states, and it is + a counter comparison, not a timing measurement, so it is deterministic and suitable for CI. - **Wall time.** Record PGF kernel time relative to `PressureGradCentered` on a representative configuration, as a performance regression guard. The expected cost is dominated by the per-edge - layer integrals (§4.1.3), roughly three times as many as a cell-based formulation on a hexagonal - mesh; a result far above that suggests the per-cell coefficients are being recomputed per edge - rather than cached. + column scan (§4.1.3), roughly three times as many column evaluations as a cell-based formulation on + a hexagonal mesh; a result far above that suggests the per-cell coefficients are being recomputed + per edge rather than cached. **Covers:** Requirement 2.2. @@ -1314,23 +1635,74 @@ loop. Two cheap checks close that: | 2.5 Runtime-selectable, backward compatible | §5.1 (three configurations); §5.5 | | 2.6 Verified order of accuracy | §5.1 verification gate | | A1 Edge accuracy ≠ cell accuracy | §5.1 verification gate (Phase 2) | -| A2 EOS expansion adequate across an edge | §5.1 contrast sweep; §5.4 | +| A2 EOS expansion adequate across an edge | §5.1 contrast sweep; §5.4; the source-4 diagnostic of §3.7.6 | | A3 Residual small enough in practice | §5.1 accuracy gate; §5.3; §5.4 | | A4 PGF error causes the instability | §5.3 diagnostic, run before Phase 1 completes | -| §3.7.4 per-edge geopotential correction | §5.2 (cannot pass without it; guard (c) tests it directly) | -| §3.7.5 Round-off floor | §5.2, run in both precisions | +| A5 Top- and bottom-of-column treatment | §5.1 `bathymetry_step` and `surface_pressure_gradient` | +| §3.5 remainder is load-bearing | §5.2 guards (c), (d), (e); §5.5 at nonzero tilt | +| §3.5 the scheme responds to tilt at all | §5.2 guard (a); §5.5 tilt sweep | +| §3.7.4 column scan | §5.2 (cannot pass without it; guard (d) isolates it) | +| §3.7.5 Round-off floor | §5.2, run in both precisions, alongside `Centered` | Requirement 2.7 (extensibility) is not testable directly; it is addressed by the configuration design of §4.1.1 and by the phase structure of §4.5, which is itself the evidence that the framework extends without restructuring. -This test is retained permanently rather than treated as a one-time transition check, and -that choice is the reason `PressureGradCentered` is kept as a separate implementation rather -than reimplemented as the lowest-order configuration of `PressureGradHighOrder` (§4.4). The -two functors read the mesh, `VertCoord`, and EOS state through independently written code, so -their agreement to round-off is evidence about *shared upstream* state as well as about the -PGF arithmetic: a wrong edge mask, a mis-indexed interface array, or a misinterpreted -`VertCoord` convention shows up as a disagreement. Were the centered scheme replaced by an -order-2 configuration of the new code, this comparison would reduce to comparing an -implementation against itself, and any defect upstream of the order switch would cancel out -of it. +## 6 Supporting evidence + +Two things §3 asserts are not self-evident from the algebra alone: that the cancellation of §3.1.1 +survives discretization, and that the form of [](#ho-target) used here is the correct one. This +section supplies the evidence for both. + +### 6.1 Numerical confirmation of the reduction and the exact set + +The claims below were established in a purpose-built two-column Python harness before any C++ was +written, and they are the reason §3.2 takes [](#ho-exact) as its target rather than assembling the +four pressure terms. The harness builds its state on the Polaris `horiz_press_grad` initialization: +interface pressures prescribed directly, $\Theta$ and $S$ sampled as `Init._interpolate_t_s` does, +equation-of-state coefficients from one `gsw.specvol_first_derivatives` call per cell per layer, $z$ +accumulated as `VertCoord` does, geometry from `hydrostatic_consistency.cfg` +($d_e = 4$ km, $\tilde z_{\text{bot}} = -4096$ m). Where a truth value is needed it is +$-g\,\partial z/\partial x|_p$ by direct segment-wise Gauss integration of the true TEOS-10 +$\alpha(p)$, sharing no code with the scheme under test. + +| claim | §ref | measurement | +|---|---|---| +| the four pressure terms of [](#ho-target) sum to zero | §3.1.1 | $1.4$–$5.0\times10^{-15}$ m s$^{-2}$ against a side-wall term of $0.55$; relative $3\times10^{-15}$, at 50 m/km tilt, for profiles linear in $p$, quadratic in $p$, and with a horizontal temperature contrast | +| the $p\nabla\alpha$ term of [](#ho-target) is required | §3.1 | with it, error $1.45\times10^{-9} \to 2.26\times10^{-11}$ at rate $2.00$ per refinement; without it, error pinned at $4.55\times10^{-6}$ at rate $0.00$ — the scheme returns $9.0\times10^{-7}$ against a true $5.42\times10^{-6}$ | +| exactness on the exact set, independent of tilt | §3.7.3 | residual at the round-off floor, $9\times10^{-16}$ to $9\times10^{-15}$, **not growing** across 0.5–200 m/km at 16 and 64 layers. `Centered` on the same states is exactly first order in tilt | +| $O(\tilde h^2)$ off the exact set | §3.7.3 | quadratic-in-$p$ profile at 50 m/km: rates 2.21, 2.14, 2.09, 2.05 under vertical refinement | +| the edge-shared expansion point is load-bearing | §3.3.1 | replacing it with a cell-local one costs $2.2\times10^{-9}$ to $3.0\times10^{-5}$ across the tilt range — §5.2 guard (b) | +| the fixed-pressure comparison is the whole scheme, not a correction | §3.5, §3.7.4 | omitting it costs $2.8\times10^{-3}$ to $1.1$ m s$^{-2}$ — three to five orders larger than any other guard, and the reason §3.5 presents $\mathcal{R}$ as a component rather than a refinement | + +Three limits on what this establishes, all of them live. + +- **Differing `maxLevelCell` is untested.** The harness gave both columns the same layer count, so the + `bathymetry_step` case — where a bottom partial cell carries the whole signal — is not covered. This + is assumption A5 of §3.7.6. +- **Nothing has been run in Omega**, or through the real Polaris task machinery, so the interaction + with p-star initialization and partial cells is untested. +- **The rows above were measured on an assembly of all four pressure terms**, not on [](#ho-discrete). + Given that those terms cancel to $3\times10^{-15}$ relative, what the exactness and $O(\tilde h^2)$ + rows measured *was* the geopotential term alone, so they carry over — but by that argument rather + than by direct measurement, and confirming it against [](#ho-discrete) is the first task of §4.5.3 + step 1. + +### 6.2 Corrections owed to `OmegaV1GoverningEqns.md` + +[](#ho-target) is inherited from {ref}`omega-design-governing-eqns-omega1`, which is not maintained +against the code. Three corrections are owed to it, all following from [](#leibniz), and they should +be made there rather than left as local overrides here. + +1. **The $+\int_A\int\rho_0\,p\,\nabla\alpha\,d\tilde z\,dA$ term is missing.** Row 2 of §6.1 is what + it costs: a scheme built on the four-term form without it does not converge at all. The omission is + invisible in every resting-state configuration, because $\partial_x\alpha|_{\tilde z} = 0$ when + $\Theta$ and $S$ are horizontally uniform, which is why it survived review. +2. **The signs on the two metric terms are reversed.** [](#leibniz) gives + $+(\alpha p)_{\text{top}}\nabla\tilde z^{\text{top}}$ and + $-(\alpha p)_{\text{bot}}\nabla\tilde z^{\text{bot}}$. With the signs as printed there, the + cancellation of §3.1.1 doubles rather than vanishing. +3. **The small-slope interface normals are not needed.** Its §6 reaches [](#ho-target) through + $\mathbf n^{\text{top}} \approx (-\nabla\tilde z^{\text{top}}, 1)$, unnormalized. The derivation in + §3.1 here uses Leibniz' rule directly, so neither the corrected [](#ho-target) nor [](#ho-exact) + depends on that approximation. From 6b5ee5ad2dafd633e7502975419aea956fb5dfd2 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 30 Jul 2026 09:11:31 -0500 Subject: [PATCH 11/22] Difference the fixed-pressure integrand before integrating it The previous formulation built each column's hydrostatic integral separately and reconciled the two as the centered scheme plus a remainder. A reference implementation showed it misses exactness by ~2e-3 of the centered scheme's answer on a profile inside the exact set, flat across three decades of tilt, where the requirement is round-off. A brute-force evaluation of the target, sharing no code with the closed forms, misses by the same amount, which places the fault in the target rather than the algebra. The cause is that the equation-of-state expansion was shared across the edge at fixed layer *index*. Under tilt that is not fixed pressure, so the two columns evaluated specific volume as piecewise-linear functions whose breakpoints sat at different pressures, and integrated genuinely different functions even for a profile both reconstructed exactly. Every other comparison in the design had been moved to fixed pressure; this one had not. Difference the integrand instead. With one shared coefficient set per edge layer and each column supplying its own theta(p), S(p) from whichever of its own layers contains p, the alpha_0 and alpha_p terms are common to both columns and cancel, leaving the horizontal contrast in reconstructed theta and S at matched pressure. That is identically zero pointwise on the exact set, so exactness no longer depends on the coefficients, the quadrature, or the interfaces lining up. Restate condition 1 accordingly: the columns must agree at every pressure from the anchor down, not merely within a layer. Consequences. Compressibility drops out of the horizontal gradient entirely, which is correct physics and means the scheme needs alpha_theta and alpha_S but not alpha_p. No large quantities are formed anywhere, so the round-off exposure belongs to the centered scheme alone and single precision is now expected to pass. Assumption A5 demotes from an exactness risk to an accuracy question, since an extrapolated reconstruction still reproduces a profile it resolves. The quadrature setting returns as a pure accuracy knob. No configuration reduces the scheme to the centered one, so the regression test asserts the centered identity standalone instead; that identity is confirmed to 0.5 eps over fifty states. Fold in five corrections from the reference implementation, including two to this document: the claim that each component of a correction is individually small, and the reconciliation with the accumulated centered error, which holds only when the two columns have equal total pseudo-thickness. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 852 +++++++++--------- 1 file changed, 445 insertions(+), 407 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index fd1d71c58d87..a8a45b0a8ab8 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -524,165 +524,98 @@ what makes the reduction to the centered scheme in §3.9 possible, and it isolat on its own in §5.2 — but it is not a supported production setting in either phase, because it gives up the exactness for linearly varying profiles that Requirement 2.3.3 asks for. -### 3.5 The remainder relative to the centered scheme +### 3.5 Evaluating the fixed-pressure difference -Equation [](#ho-exact) is not evaluated directly. It is evaluated as the centered scheme plus a -remainder, for one reason: the fixed-pressure height difference is a small residual of two large -quantities, and grouping the large parts so that they cancel *analytically* rather than in floating -point is what preserves the precision §3.7.5 is about. +Equation [](#ho-exact) is not evaluated by building each column's $z_i(p)$ and subtracting. It is +evaluated by **differencing the integrand first and integrating the difference**, which is what +makes the exactness of §3.7 structural rather than the outcome of a cancellation. -**`PressureGradCentered` is the first-order fixed-pressure shift, exactly.** This is an algebraic -identity about the code in `PGrad.h`, not an approximation, and it is the pivot of this section. -Write $\Delta_e f \equiv \sum_{i\in CE(e)} -n_{e,i}\,f_i$ so that $[\nabla_n f]_e = \Delta_e f/d_e$, -and let $q_{i,k}$ = `PressureInterface`, $Z_{i,k}$ = `GeomZInterface`, $\alpha_{i,k}$ = `SpecVol`, -with layer $k$ bounded by interfaces $k$ and $k+1$. Define +Write $\Delta_e f \equiv \sum_{i\in CE(e)} -n_{e,i}\,f_i$, so that $[\nabla_n f]_e = \Delta_e f/d_e$, +and let $\Delta_e z(p)$ be the fixed-pressure height difference [](#ho-exact) integrates. +Differentiating [](#z-of-p) gives the relation the whole scheme rests on: $$ -\mathcal{S}_{e,k} \;\equiv\; \tfrac{1}{2}\left(\Delta_e Z_{k} + \Delta_e Z_{k+1}\right) -\;+\; \frac{\bar\alpha_{e,k}}{2g}\left(\Delta_e q_{k} + \Delta_e q_{k+1}\right), +\frac{d}{dp}\,\Delta_e z(p) \;=\; -\,\frac{1}{g}\,\Delta_e \hat\alpha(p), \qquad -\bar\alpha_{e,k} = \tfrac{1}{2}\!\!\sum_{i \in CE(e)}\!\! \alpha_{i,k}. -$$ (centered-shift) +\Delta_e \hat\alpha(p) \equiv \hat\alpha^{(e)}_R(p) - \hat\alpha^{(e)}_L(p), +$$ (dz-dp) + +in which both columns are evaluated at **the same pressure** $p$. Two rules fix what that means, +and between them they are the whole of the robustness property: -Then $T^{p,\text{ctr}}_{e,k} = -\frac{g}{d_e}\,\mathcal{S}_{e,k} - \left[\nabla_n(\phi_{TP}+\phi_{SAL})\right]_e$. The proof is two lines: with -$M_{i,k\pm} = \alpha_{i,k}\,q_{i,\cdot} + g Z_{i,\cdot}$, the identity -$\Delta_e(\alpha q) = \bar\alpha\,\Delta_e q + \bar q\,\Delta_e \alpha$ splits the Montgomery -difference, and the $\bar q\,\Delta_e\alpha$ halves cancel the scheme's $\bar p\,\nabla\alpha$ term -**term for term**, because $\tfrac12(\bar q_{k} + \bar q_{k+1}) = \bar p^{\text{mid}}_{e,k}$ exactly -— `PressureMid` is the exact arithmetic midpoint of the two interface pressures -(`VertCoord.cpp:1067`). +- **One shared coefficient set at each pressure.** For $p$ in edge layer $k$, both columns use the + edge-shared coefficients and expansion state [](#edge-ref) of *that edge layer* — not of each + column's own layer $k$, which under tilt spans a different pressure range (§3.7.2, condition 1). +- **Each column supplies its own $\Theta(p)$, $S(p)$**, from whichever of *its own* layers contains + $p$, using that layer's mean-preserving reconstruction (§3.4). -What [](#centered-shift) *is*, physically: Taylor-shifting each column's height from its own -interface pressure to a pressure common to both gives -$z_i(p) = Z_{i,k} - \frac{\alpha}{g}\left(p - q_{i,k}\right) + O\!\left((p-q_{i,k})^2\right)$, hence +With those, the $\bar\alpha_0$ and $\bar\alpha_p\,(p-\bar p^{e})$ terms of [](#alpha-taylor) are +identical in the two columns and cancel in the difference, leaving $$ -g\left[\nabla_n z\right]_{p} \;=\; g\left[\nabla_n Z\right]_{k} -\;+\; \alpha \left[\nabla_n q\right]_{k} \;+\; O\!\left(\frac{\alpha_p}{g}(\Delta_e q)^2\right). -$$ (first-order-shift) +\Delta_e \hat\alpha(p) \;=\; \bar\alpha_{\Theta}^{e,k}\,\Delta_e\Theta(p) +\;+\; \bar\alpha_{S}^{e,k}\,\Delta_e S(p). +$$ (dalpha) + +**This is the central property of the scheme.** [](#dalpha) is a product of a coefficient with the +horizontal contrast in reconstructed $\Theta$ and $S$ *at matched pressure*, and that contrast is +**identically zero, pointwise**, whenever the two columns' reconstructions describe the same water +(§3.7.2, condition 1). Four consequences follow, and they replace a chain of separate arguments an +earlier formulation of this section needed: + +1. **Exactness does not depend on the coefficients.** Whatever $\bar\alpha_\Theta$, + $\bar\alpha_S$ are, they multiply zero. The edge-shared expansion point of §3.3.1 remains the + right choice on *accuracy* grounds, but the robustness property no longer rests on it. +2. **Exactness does not depend on the quadrature.** The integrand is zero at every point, so any + rule integrates it to zero. Quadrature order is therefore an ordinary accuracy knob (§4.1.1), + not a correctness requirement. +3. **Exactness does not depend on the interfaces lining up.** Where the two columns' layers are + offset — at 50 m/km and 64 m layers they are offset by nearly three layer thicknesses, and + overlap not at all — [](#dalpha) is still evaluated at matched pressure and is still zero. +4. **Compressibility drops out of the horizontal gradient entirely.** $\bar\alpha_p$ does not appear + in [](#dalpha). This is correct physics rather than an approximation: if $\Theta$ and $S$ are + horizontally uniform then so is $\alpha(p)$, and a horizontally uniform compressibility exerts no + horizontal pressure gradient. It is *only* because `PressureGradCentered` compares at fixed layer + index that compressibility appears in its error at all (§3.9). + +#### 3.5.1 The column scan + +$\Delta_e z$ is accumulated down each edge's column from the sea surface. Let $\bar q_k$ be the +edge-layer interface pressures and $D_k \equiv \Delta_e z(\bar q_k)$. Then -So $\mathcal{S}_{e,k}$ is the trapezoidal average over the layer's two interfaces of the -**first-order** conversion from fixed layer index to fixed pressure, with the layer-mean $\alpha$ -standing in for $\hat\alpha$ at the interface. The centered scheme's entire Montgomery-potential -apparatus is that conversion and nothing else, and its error is the conversion's truncation. This is -why §3.7.3's first-order behaviour is what it is, and it is the sharpest available statement of what -Phase 1 fixes: **Phase 1 computes the centered scheme's error and removes it.** +$$ +D_{k+1} \;=\; D_k \;-\; \frac{1}{g}\int_{\bar q_k}^{\bar q_{k+1}} \Delta_e\hat\alpha(p)\; dp, +$$ (d-recurrence) -**The remainder.** Define +and the layer mean [](#ho-exact) needs is obtained from $D_k$ and a second moment of the same +integrand over the same interval. Both integrals use the same quadrature points, and at each point +each column's $\Theta$, $S$ come from the layer of that column containing the point. -$$ -\mathcal{R}_{e,k} \;\equiv\; \frac{1}{\Delta p_{e,k}} -\int_{p^{\text{top}}_{e,k}}^{p^{\text{bot}}_{e,k}} \Delta_e z(p)\; dp \;-\; \mathcal{S}_{e,k}, -\qquad -T^p_{e,k} = -\frac{g}{d_e}\left(\mathcal{S}_{e,k} + \mathcal{R}_{e,k}\right) -- \left[\nabla_n(\phi_{TP}+\phi_{SAL})\right]_e , -$$ (ho-discrete) - -with $z_i(p)$ from [](#z-of-p) built on the edge-shared $\hat\alpha^{(e)}$. Equation -[](#ho-discrete) is exactly [](#ho-exact) rewritten; `VertCoord`'s $Z$ enters through -$\mathcal{S}$ and leaves again through $\mathcal{R}$, and cancels in exact arithmetic. That is what -keeps Requirement 2.4 satisfied — the scheme does not construct a second geometric height, it -constructs a correction to a difference — and it is why the split is a numerical device rather than -a change of target. - -$\mathcal{R}$ has four sources. Three are local to the layer; the fourth is not. - -1. **Interface value versus layer mean.** [](#centered-shift) weights $\Delta_e q$ by the layer-mean - $\bar\alpha_{e,k}$ where [](#first-order-shift) calls for $\hat\alpha^{(e)}$ evaluated *at the - interface*. Contributes $\propto \hat\alpha'\,\Delta p_{k}\,\Delta_e q_{k}$ per interface, with - opposite sign at the layer's top and bottom. -2. **Second and higher order in the shift.** The $O((\Delta_e q)^2)$ term of - [](#first-order-shift). Its column-symmetric part cancels in the edge difference; what survives - is $-\frac{(\Delta_e q_k)^2}{8g}\,\Delta_e \hat\alpha'$ and higher, i.e. it is driven by the - *horizontal contrast* in compressibility, not by compressibility itself. -3. **Layer average versus interface trapezoid.** [](#ho-discrete) averages $\Delta_e z(p)$ over the - edge control volume's pressure range; [](#centered-shift) takes the mean of two interface values. - The gap is set by the curvature $\frac{d^2}{dp^2}\Delta_e z = -\frac{1}{g}\Delta_e\hat\alpha'$. -4. **The `VertCoord` height is built from a different $\hat\alpha$.** `VertCoord` accumulates - $\Delta Z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$, which by §3.7.4's [](#z-increment-exact) is the - exact layer integral of a *cell-local* Phase 1 $\hat\alpha$. The scheme's water column is the - *edge-shared* one, whose layer mean is - - $$ - \left\langle\hat\alpha^{(e)}_{i,k}\right\rangle = \bar\alpha_0^{e,k} + \bar\alpha_\Theta^{e,k}\left(\Theta_{i,k}-\bar\Theta^{e,k}\right) + \bar\alpha_S^{e,k}\left(S_{i,k}-\bar S^{e,k}\right) + \bar\alpha_p^{e,k}\left(p^{\text{mid}}_{i,k}-\bar p^{e,k}\right), - $$ (alpha-edge-layer-mean) - - the first-order Taylor estimate of $\alpha_{i,k}$ from the edge state. The per-layer mismatch - - $$ - \varepsilon_{i,k} = \rho_0\,\tilde h_{i,k}\left(\alpha_{i,k} - \left\langle\hat\alpha^{(e)}_{i,k}\right\rangle\right) - $$ (eos-remainder) - - is therefore precisely the **second-order Taylor remainder of the equation of state across the - edge**, and its edge difference **accumulates down the column**. This is the one non-local source, - and it is why Phase 1 needs a column scan (§4.1.3). It also identifies source 4 with assumption A2 - (§3.7.6): the same second-order EOS expansion that would answer A2 shrinks this source directly. - -Three requirements on how $\mathcal{R}$ is built, all of them testable: - -- **R1 — built from the edge-shared $\hat\alpha^{(e)}$** of [](#edge-ref), so that condition 1 of - §3.7.2 is met. Guard test (b) of §5.2 checks this. -- **R2 — evaluated analytically, never as a numerical difference.** Each of the four sources above - is a small quantity with a closed form. Forming $\mathcal{R}$ by computing - $\frac{1}{\Delta p}\int \Delta_e z\,dp$ and $\mathcal{S}$ separately and subtracting them would - throw away exactly the precision the split exists to protect. -- **R3 — $\mathcal{R}_{e,k} = -\mathcal{S}_{e,k}$ to round-off whenever - $\hat\alpha^{(e)}_L(p) \equiv \hat\alpha^{(e)}_R(p)$.** This is the machine-precision property of - Requirement 2.3.1 restated in the form the implementation must satisfy, and it is what §5.2 tests. - Note that it makes the test *sharper* than a check that the tendency is small: $\mathcal{S}$ is - the centered scheme's answer on the same state, which §3.7.3 measures at $2\times10^{-5}$ - m s$^{-2}$, so R3 asserts a cancellation of ten orders of magnitude against a known nonzero - reference rather than against zero. - -#### 3.5.1 Accumulating without cancellation - -$\mathcal{S}_{e,k}$ as written in [](#centered-shift) is the sum of two terms of order 200 m, at a -coordinate tilt of 50 m/km over a 4 km edge, that cancel to a few millimetres. That is -`PressureGradCentered`'s existing round-off exposure, not something the new scheme introduces -(§3.7.5), but the same algebra that produced [](#centered-shift) removes it, and the design -recommends doing so. - -Let $\Gamma_{e,k} = \Delta_e Z_{k} + \frac{\bar\alpha_{e,k}}{g}\Delta_e q_{k}$ and -$\Gamma^{+}_{e,k} = \Delta_e Z_{k+1} + \frac{\bar\alpha_{e,k}}{g}\Delta_e q_{k+1}$, so that -$\mathcal{S}_{e,k} = \tfrac12(\Gamma_{e,k} + \Gamma^{+}_{e,k})$. Using -$Z_{i,k+1} - Z_{i,k} = -\rho_0\alpha_{i,k}\tilde h_{i,k}$ and -$q_{i,k+1} - q_{i,k} = \rho_0 g \tilde h_{i,k}$ together with the same product rule as before, +**The anchor.** $D_1 = \Delta_e z(\bar q_1)$ at the sea surface, where the two columns are at +different surface pressures. It is the sea-surface height difference corrected to a common pressure, $$ -\Gamma^{+}_{e,k} - \Gamma_{e,k} = -\,\rho_0 \, \overline{\tilde h}_{e,k}\, \Delta_e \alpha_{k}, -\qquad -\Gamma_{e,k+1} - \Gamma^{+}_{e,k} -= \frac{\Delta_e q_{k+1}}{g}\left(\bar\alpha_{e,k+1} - \bar\alpha_{e,k}\right). -$$ (gamma-increments) - -Both increments are products of a small factor with a bounded one — the *horizontal* contrast in -specific volume within a layer, and the *vertical* contrast between adjacent layers — so -$\mathcal{S}$ can be walked down the column with no cancellation of large numbers anywhere, starting -from $\Gamma_{e,1}$, which is the inverse-barometer residual at the sea surface and is itself small -for a state at rest. - -[](#gamma-increments) should be reconciled against §3.7.3's [](#centered-error), which describes the -same quantity in a different grouping, as a check on both. In the limit [](#centered-error) is written -for — specific volume horizontally uniform within each layer, thickness merely redistributed — the -first increment vanishes identically and the second one carries the whole signal, reproducing -[](#centered-error)'s downward accumulation through the horizontal displacement of the interfaces. -The two expressions are expected to agree up to a $k$-independent constant fixed by the anchor, and -confirming that (including the constant, and without assuming -$\sum_j \Delta_e\tilde h_j = 0$) is one of the algebraic checks assigned to the reference derivation -in §4.5.3. - -Consequences worth stating, because they change several things downstream: - -- Both $\mathcal{S}$ and source 4 of $\mathcal{R}$ are column prefix sums. They should be - accumulated in the same scan, from the same end of the column (§3.7.4 closing note), and cost one - scan rather than two. -- The perturbation form §3.7.5 holds in reserve becomes unnecessary in double precision and probably - in single as well. That is now a measurement (§5.2 in both precisions) with a plausible expected - answer rather than an open question. -- The reduction to `PressureGradCentered` (§3.9) becomes *algebraic* rather than bit-for-bit, - because [](#gamma-increments) evaluates $\mathcal{S}$ in a different order from `PGrad.h`. This is - the trade the design accepts: §4.4 already expects agreement to round-off rather than bit-for-bit, - and it is a better cross-check for being arithmetically independent. +D_1 \;=\; \Delta_e Z_1 \;-\; \frac{1}{g}\sum_{i \in CE(e)} -n_{e,i} \int_{p^{\text{surf}}_i}^{\bar q_1} \hat\alpha^{(e)}_i(p)\,dp , +$$ (anchor) + +with both short integrals in closed form and taken inside each column's own top layer. For a resting +ocean whose sea surface satisfies the inverse-barometer relation, $D_1$ is zero exactly — the surface +tilts precisely so as to compensate the horizontal gradient in $p^{\text{surf}}$. **Exactness of the +scheme therefore inherits the consistency of `VertCoord`'s sea-surface height with its surface +pressure**, which is a dependency worth stating: it is the one place the PGF's robustness reaches +outside the PGF. + +**Every quantity in the scan is small.** $D_k$ is the fixed-pressure height difference — of order +$10^{-1}$ m for a realistic baroclinic column and zero for a resting one, against the $10^{2}$ m +height *differences at fixed layer index* that a scheme comparing at fixed index has to form and +cancel. The increments in [](#d-recurrence) are smaller still, being integrals of a horizontal +contrast. There is no cancellation of large quantities anywhere in the scheme, which is what §3.7.5 +is about. + +**`VertCoord`'s geometric height is used once**, for $\Delta_e Z_1$ in [](#anchor) — the free-surface +height difference. It is not accumulated and not re-derived, so Requirement 2.4 is met by the PGF +not constructing a geometric height at all: it constructs a *difference*, which is not a height +field. ### 3.6 The edge operator @@ -767,38 +700,47 @@ the layer means, and it is stated next. For each edge and layer: -1. **Both sides of the edge use the same specific-volume profile.** The two columns must evaluate - $\hat\alpha$ as one and the same function of pressure over the pressure range the layer spans. - This is what the edge-shared expansion point of §3.3.1 delivers, and under the reduced target of - §3.2 it is the *only* remaining mechanism by which exactness can fail on a resolved profile. -2. **The two columns are compared at a common pressure, to all orders retained.** Layer $k$ spans - different pressure ranges in the two columns, so $[\nabla_n z]_p$ requires shifting each - column's height from its own interface pressures to a pressure shared with its neighbour. - Truncating that shift at first order is what `PressureGradCentered` does, and its truncation is - the whole of the error Phase 1 removes; the shift must therefore be carried to the order of the - reconstruction, which is what §3.5's sources 1–3 supply. -3. **The height being shifted is the hydrostatic integral of that same profile.** `VertCoord`'s - $Z$ is built from each cell's own exact TEOS-10 $\alpha$, not from the edge-shared - $\hat\alpha^{(e)}$, so the difference between the two must be accounted for. This is §3.5's - source 4, and it is a column prefix sum; see §3.7.4. - -Conditions 2 and 3 are about the discretization alone and are under the implementation's control. -Meeting them means the scheme returns the **exact pressure gradient of the water column it has -reconstructed** — it contributes no error of its own beyond the reconstruction. Condition 1 is -about the state: it holds when the reconstruction reproduces the true profile, and fails, by -however much the reconstruction misses, when it does not. Meeting all three gives a PGF that is -**zero to machine precision**, for any tilt, any layer thickness, and any bathymetry. - -Note that conditions 2 and 3 are, between them, exactly the requirement R3 of §3.5 — that -$\mathcal{R}$ cancel $\mathcal{S}$ to round-off on a resolved profile. Stating them separately is -useful because they fail in distinguishable ways: a defect in condition 2 leaves a residual local -to the layer, while a defect in condition 3 leaves one that grows with depth. §5.2's guard tests -are arranged to tell them apart. - -The point worth carrying away, because it is what makes this tractable, is that **the reconstructed -profile does not have to be accurate for the cancellation to be exact — it only has to be shared.** -The scheme needs the two columns to describe *one* water column, not the *right* one. Accuracy is a -separate concern, addressed by reconstruction order. +1. **Both columns describe the same water, as a function of pressure, over the whole column.** The + two columns must evaluate $\hat\alpha$ as one and the same function of $p$ — not merely within a + layer, but at **every pressure from the anchor down**, since [](#z-of-p) integrates from the + surface and [](#d-recurrence) accumulates from it. + + **This is stronger than it looks, and stating it per layer is a trap.** An earlier revision of this + design required only that the two columns agree "over the pressure range the layer spans", and + satisfied it by sharing the equation-of-state expansion across the edge **at fixed layer index** + ([](#edge-ref)). Under tilt, fixed layer index is not fixed pressure: column $L$'s layer $k$ and + column $R$'s layer $k$ span different pressure ranges, so at a given pressure the two columns were + using expansions about different states, and $\hat\alpha^{(e)}$ became a *discontinuous + piecewise-linear function whose breakpoints sat at different pressures in the two columns*. The two + columns then integrated genuinely different functions even for a profile both reconstructed + exactly, and the scheme missed exactness by + $O(\alpha_{pp}\,\delta p\,\Delta_e p^{\text{mid}})$ — first order in tilt, and therefore a + *tilt-independent fraction* of the signal. Measured at $2\times10^{-3}$ of the centered scheme's + answer, flat across three decades of tilt (§6.3). + + Every other comparison in this design had already been moved to fixed pressure; that one had not. + [](#dalpha) is the repair: differencing at matched pressure before integrating makes the condition + hold pointwise and by construction. + +2. **The two columns are differenced at a common pressure, before integration.** This is + [](#dz-dp)–[](#dalpha). Integrating each column separately and subtracting satisfies condition 1 + only to the order of whatever shift is used to reconcile the two, and reintroduces the + large-number cancellation §3.7.5 is about. +3. **The anchor is consistent.** [](#anchor) must be zero for a resting ocean, which requires + `VertCoord`'s sea-surface height to satisfy the inverse-barometer relation against its own surface + pressure. Unlike conditions 1 and 2 this is not under the PGF's control; it is a dependency on + upstream state, and §5.2 tests it by construction. + +Conditions 2 and 3 are about the discretization and the state it is handed. Condition 1 is about +whether the *reconstruction* reproduces the true profile: it holds exactly for profiles in the exact +set of §3.7.3, and fails by however much the reconstruction misses when it does not. Meeting all +three gives a PGF that is **zero to machine precision**, for any tilt, any layer thickness, and any +bathymetry. + +What makes this tractable, and is worth carrying away, is that condition 1 is now checked *pointwise* +rather than assembled: [](#dalpha) is zero at each quadrature point or it is not. There is no +cancellation between terms to get right, and consequently no way to satisfy the resting-state gate +while being subtly wrong — which the previous formulation permitted (§6.3). #### 3.7.3 Which water columns cancel exactly @@ -857,106 +799,84 @@ the bottom-layer error seen in realistic global configurations. Whether this dow seen in realistic global configurations is a plausible diagnosis, not an established one; it is carried as A4 in §3.7.6 and tested in §5.3. -#### 3.7.4 Condition 3 and the column scan +#### 3.7.4 What `VertCoord` supplies, and what it does not + +`VertCoord` is the source of `PressureInterface`, `PressureMid`, `PseudoThickness` and the +sea-surface height that [](#anchor) differences. It is **not** the source of the height the scheme +integrates: [](#d-recurrence) builds $\Delta_e z$ from the reconstruction alone, so the question of +whether `VertCoord`'s $z$ is built from the same $\hat\alpha$ the PGF uses does not arise. -Condition 3 constrains how the height being shifted is built. Two questions arise, and they have -different answers; they are easy to conflate, and doing so leads to the conclusion that `VertCoord` -must be changed, which it need not be. +That is a simplification worth recording, because it disposes of two questions earlier revisions of +this design spent effort on. -**The quadrature question, which is settled.** `VertCoord::computeGeomZHeight` builds $z$ by -accumulating $\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — apparently a midpoint rule, where -condition 3 asks for the integral of the reconstructed $\hat\alpha$. For a Phase 1 reconstruction -these are **the same quantity**. Integrating [](#alpha-taylor) with the linear deviations of §3.4 -over the layer, +**The quadrature question, which is settled and now moot.** +`VertCoord::computeGeomZHeight` accumulates $\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — +apparently a midpoint rule. For a Phase 1 reconstruction it is the exact layer integral: $$ \frac{1}{g}\int_{p^{\text{top}}_{i,k}}^{p^{\text{bot}}_{i,k}} \hat\alpha_{i,k}(p)\,dp = \frac{\alpha_{0}\,\Delta p_{i,k}}{g} = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}, $$ (z-increment-exact) -because $\int \Theta'\,dp = \int S'\,dp = 0$ by the mean-preserving constraint, and -$\int (p - p^{\text{mid}})\,dp = 0$ because $p^{\text{mid}}$ is the exact arithmetic midpoint of the -two interface pressures. The midpoint rule *is* the exact layer integral of a Phase 1 -$\hat\alpha$. No change to `VertCoord` is required, there is no answer-changing baseline step, and -Requirement 2.4 is satisfied by construction rather than by negotiation — the PGF and the rest of -the model share one $z$ because they compute the same thing. - -This is a Phase-1-only result and Phase 2 must re-examine it. Parabolic deviations are fine provided -they remain mean-preserving, but the second-order equation-of-state expansion of §3.3 contributes -$\tfrac12\alpha_{pp}(p-p^{\text{mid}})^2$ and cross terms such as -$\tfrac12\alpha_{\Theta\Theta}\Theta'^2$, none of which integrate to zero over the layer. If that -option is adopted, [](#z-increment-exact) no longer holds and the question returns. - -**The sharing question, which is the real constraint.** What condition 3 actually requires is that -the height be the hydrostatic integral of the *same* $\hat\alpha$ the fixed-pressure shift uses — -and §3.3.1 makes that an **edge** quantity, since its coefficients and expansion point are averages -over the two cells of the edge. A cell-based $Z$ cannot carry an edge-dependent $\hat\alpha$ however -it is integrated. This is §3.5's source 4, and it is $O(\alpha_{pp}(\Delta p^{\text{mid}}_e)^2)$ per -layer, accumulating down the column. §3.5 gives its closed form: the edge-shared profile's layer mean -is [](#alpha-edge-layer-mean), the per-layer mismatch against `VertCoord`'s increment is the -second-order equation-of-state remainder [](#eos-remainder), and what the scheme needs is $\Delta_e$ -of its running sum down the column. - -**Resolution: the PGF accumulates $\Delta_e$ of $\varepsilon_{i,k}$ down each edge's column**, built -from the edge-shared $\hat\alpha$, and adds it to the local terms of $\mathcal{R}$. This does not -create the second, slightly different $z$ that Requirement 2.4 exists to prevent: -`GeomZInterface`/`GeomZMid` remain the model's one geometric height and are unchanged, and what the -PGF accumulates is a per-edge *difference* of second-order EOS remainders, identically zero when the -two columns' states coincide. - -Two things about it are easy to get wrong. - -- **This piece is genuinely small; the scheme as a whole is not a small correction.** Source 4 is - second order in the cross-edge pressure contrast, so accumulating it consumes little precision. But - sources 1–3, and $\mathcal{S}$ itself, are the same size as the terms they correct — at 50 m/km both - are $\approx 0.5$ m s$^{-2}$ before cancellation. Writing something as a "correction" therefore buys - no precision on its own; what buys it is [](#gamma-increments) and §3.5.1, which remove the - cancellation algebraically. -- **The scan is not optional and not a detail.** §4.1.3 records the implementation consequence: a - column prefix sum cannot live inside a per-edge, per-vertical-chunk kernel call. Both this scan and - $\mathcal{S}$'s accumulation via [](#gamma-increments) are prefix sums and should share one pass. - -One related question is left to implementation time: `VertCoord` builds $z$ upward from the -bathymetry while pressure is built downward from the surface, so the two accumulate round-off from -opposite ends of the column. Which end the scan of this section and the accumulation of -[](#gamma-increments) run from is a round-off question (§3.7.5), not a consistency one — condition 3 -is satisfied either way. It is now a single decision rather than two, since both should share one -pass. +because $\int \Theta'\,dp = \int S'\,dp = 0$ by the mean-preserving constraint and +$\int (p - p^{\text{mid}})\,dp = 0$ because `PressureMid` is the exact arithmetic midpoint of the two +interface pressures. This remains true and remains useful — it is why no change to `VertCoord` and no +answer-changing baseline step is required — but the scheme no longer depends on it, since it no +longer accumulates `VertCoord`'s $z$. + +**The sharing question, which [](#dalpha) answers directly.** Whether a cell-based $z$ can carry an +edge-dependent $\hat\alpha$ was the right question to ask of a formulation that differenced two +separately accumulated column integrals. It does not arise for one that differences the integrand: +there is no per-column integral to reconcile, and the per-layer mismatch between `VertCoord`'s +increment and the edge-shared profile's — which an earlier revision carried as a column prefix sum — +is not part of the scheme. + +**Two exact simplifications** follow from taking the edge control volume as the average of the two +columns' interface pressures, $p^{\text{top}}_{e,k} = \bar q_k$ and +$p^{\text{bot}}_{e,k} = \bar q_{k+1}$, and are worth using in the implementation: + +- $p^{\text{mid}}_{e,k}$ is **exactly** the edge average of the two columns' own layer midpoints; +- $\Delta p_{e,k}$ is **exactly** the edge average of the two columns' own layer thicknesses. + +Both follow from `PressureMid` being the exact arithmetic midpoint, and both were confirmed +numerically. + +**One question is left to implementation time**: which end of the column [](#d-recurrence) +accumulates from. `VertCoord` builds $z$ upward from the bathymetry while pressure is built downward +from the surface. Accumulating from the surface is the natural choice, since [](#anchor) is a surface +condition and the sea-surface height difference is small and well conditioned; accumulating from the +sea floor requires an anchor at the bathymetry, where the two columns may have different bottom +pressures. Measured in double precision the two agree to round-off, so this is a round-off question +(§3.7.5) and not a consistency one. #### 3.7.5 Round-off in the deep ocean -Separate from everything above, and not fixed by it, is how much precision the cancellation -consumes. At 4000 m the hydrostatic height difference across a steeply tilted edge is of order -$10^{2}$ m, while the part of it that survives in the edge tendency is of order -$10^{-3}$ m — the millimetre-scale residual of [](#centered-shift). Roughly five significant digits -are consumed there, and roughly ten by the time the tendency is formed against a signal of order -$10^{-6}\ \mathrm{m\,s^{-2}}$ times $d_e$. Double precision leaves adequate margin; a -`OMEGA_SINGLE_PRECISION` build does not, and the machine-precision cancellation of §3.7.2 would -simply be invisible beneath round-off. - -Three points. - -- **This exposure belongs to `PressureGradCentered`, not to the new scheme.** It is entirely in - $\mathcal{S}_{e,k}$ as [](#centered-shift) writes it — two terms of order 200 m cancelling to - millimetres — which is what the default PGF has always computed. $\mathcal{R}$ adds none of its - own: requirement R2 of §3.5 exists precisely so that every one of its four sources is formed from - quantities that are individually small. Any conclusion reached here therefore applies to the - centered scheme as well, and it would be wrong to treat a single-precision round-off floor as an - objection to `FiniteVolume` specifically. -- **§3.5.1 removes it, in both schemes.** Accumulating $\mathcal{S}$ through - [](#gamma-increments) never forms the two large terms at all. If that form is adopted — and the - design recommends it — the ten-digit estimate above does not apply to the implemented scheme, and - the expected answer to the single-precision question changes from "probably fails" to "probably - passes". That is a prediction to be measured (§5.2, run in both precisions), not an assumption. -- **The perturbation form remains in reserve and is probably not needed.** It would subtract a local - reference profile from $\hat\alpha$ before integrating and add its contribution back analytically. - This is *not* a Shchepetkin–McWilliams (2003)-style reference-profile subtraction in the usual - sense: the reference is local to the edge and layer, its contribution cancels identically rather - than approximately, and the accuracy of the scheme does not depend at all on how well it matches - the local column — so it does not degrade in the strong-gradient, steep-layer regions where a - global reference profile would. It changes nothing in exact arithmetic. With - [](#gamma-increments) in place it addresses a problem that has already been removed - algebraically, so it should be adopted only against a measurement. +An earlier formulation of this scheme differenced two column integrals of order $10^{2}$ m to obtain +a residual of order $10^{-3}$ m, consuming roughly five significant digits before the physics +appeared and roughly ten by the time the tendency was formed. That is `PressureGradCentered`'s +existing arithmetic, and it is the reason this section exists. + +**[](#dz-dp) removes the exposure rather than managing it.** Every quantity in the scan is a +difference *before* it is an integral: [](#dalpha) is a horizontal contrast, [](#d-recurrence) +accumulates integrals of that contrast, and $D_k$ is the answer itself. No large quantity is formed +anywhere, so nothing large has to cancel. The scheme's conditioning is therefore set by the size of +the baroclinic signal, not by the size of the hydrostatic terms. + +Three consequences. + +- **The ten-digit estimate does not apply to this scheme.** It applies to `PressureGradCentered`, + which still forms and cancels $10^{2}$ m quantities, and to any formulation that reconciles two + separately accumulated column integrals. Measured, restructuring the accumulation this way + recovered about three decimal digits of headroom on a tilted coordinate — the largest increment + being $\sim 10^{-3}$ of the height difference it replaces (§6.3). +- **A single-precision build is expected to pass §5.2**, where previously it was expected to fail. + That is a prediction to be measured (§5.2 is run in both precisions), not an assumption, and it + should be measured alongside `PressureGradCentered` so the comparison is interpretable. +- **The perturbation form is not needed and is not specified.** It would have subtracted a local + reference profile from $\hat\alpha$ before integrating and added its contribution back + analytically. It addressed a problem that differencing first removes algebraically. If a + single-precision measurement ever contradicts the paragraph above, this is the direction to look, + but it should not be built speculatively. #### 3.7.6 Assumptions that still need testing @@ -973,12 +893,13 @@ assumptions this design is making that only testing can confirm: which is why §3.6.1's stencil constraint could be dropped. - **A2 — The EOS expansion is good enough across the edge.** [](#alpha-taylor) is expanded about the shared edge state [](#edge-ref), and its error grows with the horizontal contrast in $\Theta$ and - $S$ across the edge and with the layer's pressure range. Whether the first-order expansion suffices - in frontal regions, or whether the second-order option of §3.3 is needed, is an open question. - A2 is now measurable more directly than by an accuracy sweep alone: §3.5's source 4 *is* the - second-order remainder of that expansion, so the magnitude of the accumulated part of - $\mathcal{R}$ relative to its local part is a running diagnostic of how hard the expansion is being - worked. Reporting that ratio is cheap and should be done. + $S$ across the edge. Whether the first-order expansion suffices in frontal regions, or whether the + second-order option of §3.3 is needed, is an open question — though a narrower one than it was, since + [](#dalpha) makes the coefficients multiply a quantity that is zero on the exact set, so A2 bears on + accuracy only and not on robustness. Measured, the second-order remainder relative to $\alpha$ is + $8\times10^{-6}$ on the hardest configuration available (a 12 °C contrast across a 4 km edge) and + $\le 2\times10^{-9}$ on the resting-state variants (§6.3). The first-order expansion is not being + worked near its limit, and `temperature_gradient` at coarse resolution is the configuration to watch. - **A3 — The residual outside the exact set is small enough in practice.** The $O(\tilde h^2)$ and $O(\tilde h^3)$ entries in §3.7.3 describe how the error *scales*; how large it actually is at the vertical resolutions Omega can afford is unknown. @@ -988,17 +909,18 @@ assumptions this design is making that only testing can confirm: bottom-layer flow persists there, the cause lies elsewhere — most likely in the layer-mean treatment in the tracer and remapping operators (§4.3) — and Phase 1 will not cure it. See §5.3. - **A5 — The treatment at the top and bottom of the column is adequate.** [](#ho-exact) averages over - the edge control volume's pressure range $[p^{\text{top}}_{e,k}, p^{\text{bot}}_{e,k}]$, which in - general is not either column's own range, so each column's reconstruction must be evaluated - slightly outside the layer it was built for. In the interior this is a small extrapolation across a - smooth reconstruction and is harmless. At the surface, where the two columns have different - $p^{\text{surf}}$, and at the sea floor, where they may have different `maxLevelCell` and where a - partial cell carries the whole signal for the Polaris `bathymetry_step` configuration, it is not - obviously harmless and **has not been tested** — the reference derivation was run with equal layer - counts in both columns. The extrapolation must be defined explicitly, and whichever choice is made - must reduce to a single function when the two reconstructions coincide, or condition 1 of §3.7.2 - fails at the column ends. §5.1's `bathymetry_step` and `surface_pressure_gradient` variants are - where it is measured. + the edge control volume's pressure range, which in general is not either column's own, so near the + sea floor — where the two columns may have different `maxLevelCell`, and where a partial cell carries + the whole signal for the Polaris `bathymetry_step` configuration — a column's deepest reconstruction + must be evaluated slightly below its own floor. + + **A5 is an accuracy assumption, not a robustness one.** [](#dalpha) is evaluated at matched pressure + whether or not the evaluation point lies inside the layer the reconstruction was built for, and on + the exact set an extrapolated reconstruction still reproduces the true profile, so $\Delta_e\Theta(p)$ + is still zero and exactness survives. What extrapolation costs is accuracy off the exact set, and how + much is unmeasured: the derivation harness ran with equal layer counts in both columns. §5.1's + `bathymetry_step` and `surface_pressure_gradient` variants are where it is measured, and the rule + used must be stated explicitly rather than left to fall out of the implementation. ### 3.8 Scope: the reduction and the vertical coordinate @@ -1024,46 +946,84 @@ $g\,\nabla z + \nabla(\phi_{TP}+\phi_{SAL})$; $z$ enters as `VertCoord`'s `GeomZ supplied by `VertCoord` and differenced with [](#edge-grad) (Requirement 2.7). They are zero in early Omega versions and are unaffected by anything in §3.5. -### 3.9 Reduction to the centered scheme +### 3.9 Relationship to the centered scheme -Setting $\mathcal{R}_{e,k} \equiv 0$ in [](#ho-discrete) recovers `PressureGradCentered` exactly. -That is the content of [](#centered-shift), which is an algebraic identity about the implemented -code rather than a limit reached by tuning options, so the reduction is **structural in the strict -sense**: there is one term, the reduction is switching it off, and it holds at any tilt, any layer -thickness and any stratification. +`PressureGradCentered` is **exactly** the first-order conversion of a height difference taken at +fixed layer index into one taken at fixed pressure. This is an algebraic identity about the +implemented code rather than an approximate correspondence, and it has been confirmed numerically to +$0.5\,\epsilon$ of the hydrostatic scale over fifty states, including the bottom partial cell and +configurations where the two columns' `maxLevelCell` differ (§6.2). -The reduction is therefore exercised by a single configuration switch, `RemainderEnable: false` -(§4.1.1), which doubles as guard test (c) of §5.2. The agreement is algebraic rather than bit-for-bit -if §3.5.1's accumulation is used, since that evaluates $\mathcal{S}$ in a different order from -`PGrad.h` (§4.4); it would be bit-for-bit if [](#centered-shift) were assembled literally, and that is -a deliberate trade against round-off. +Let $q_{i,k}$ = `PressureInterface`, $Z_{i,k}$ = `GeomZInterface`, $\alpha_{i,k}$ = `SpecVol`, and -Because the reduction holds at any tilt, §5.5 should be run *at* nonzero tilt and over a sweep of -tilts. That is not merely permitted, it is the stronger test: the whole of the difference between the -two schemes is $\mathcal{R}$, so a tilt sweep confirms that $\mathcal{S}$ alone reproduces -`PressureGradCentered` and that both schemes are in fact responding to tilt. A reduction demonstrated -only on level interfaces would establish much less. +$$ +\mathcal{S}_{e,k} \;=\; \tfrac{1}{2}\left(\Delta_e Z_{k} + \Delta_e Z_{k+1}\right) +\;+\; \frac{\bar\alpha_{e,k}}{2g}\left(\Delta_e q_{k} + \Delta_e q_{k+1}\right), +\qquad +\bar\alpha_{e,k} = \tfrac{1}{2}\!\!\sum_{i \in CE(e)}\!\! \alpha_{i,k}. +$$ (centered-shift) + +Then the centered tendency is exactly + +$$ +T^{p,\text{ctr}}_{e,k} = -\frac{g}{d_e}\,\mathcal{S}_{e,k} - \left[\nabla_n(\phi_{TP}+\phi_{SAL})\right]_e . +$$ (centered-identity) + +The proof is two lines: with +$M = gZ + \alpha q$, the identity $\Delta_e(\alpha q) = \bar\alpha\,\Delta_e q + \bar q\,\Delta_e\alpha$ +splits the Montgomery difference, and the $\bar q\,\Delta_e\alpha$ halves cancel the scheme's +$\bar p\,\nabla\alpha$ term **term for term**, because +$\tfrac12(\bar q_{k} + \bar q_{k+1}) = \bar p^{\text{mid}}_{e,k}$ exactly — `PressureMid` is the exact +arithmetic midpoint (`VertCoord.cpp:1067`). + +Three things this buys, and one it does not. + +- **It explains the error the centered scheme makes.** Taylor-shifting each column's height from its + own interface pressure to a common one gives + $z_i(p) = Z_{i,k} - \tfrac{\alpha}{g}(p - q_{i,k}) + O((p-q_{i,k})^2)$, so $\mathcal{S}$ is the + first-order truncation of what [](#ho-exact) asks for. `PressureGradCentered`'s entire + Montgomery-potential apparatus is that conversion and nothing else, and its error is the + conversion's truncation — which is why §3.7.3's first-order behaviour is what it is, and why + compressibility appears in that error even though it cannot appear in the true horizontal gradient + (§3.5, consequence 4). +- **It gives a regression test with a known answer.** §5.5 asserts [](#centered-shift) against + `PressureGradCentered` directly. Because the two functors read the mesh, `VertCoord` and EOS state + through independently written code, their agreement tests the shared upstream state — edge masks, + interface indexing, `VertCoord` conventions — and not just the PGF arithmetic (§4.4). +- **It bounds the difference between the two schemes.** They agree to + $O\!\left((\Delta_e p)^2\right)$, so a `FiniteVolume` answer far from `Centered` at small tilt + indicates a defect in one of them rather than a property of the physics. + +**What it does not give is a configuration switch that reduces one scheme to the other.** +[](#dz-dp) is not built by adding a correction to [](#centered-shift); it differences the integrand +and never forms $\mathcal{S}$ at all. There is therefore no `FiniteVolume` setting that recovers +`PressureGradCentered` bit-for-bit or to round-off, and §5.5 tests the identity above rather than a +reduced configuration. An earlier revision of this design proposed such a switch; it was a property +of a formulation that has been replaced, and the identity is the more useful half of it in any case, +since it can be asserted as a unit test without running the new scheme at all. ### 3.10 Per-step algorithm summary Steps 1–3 are per cell and layer; step 4 is a per-edge column scan; step 5 is per edge and layer. Phase differences are marked. -1. From `VertCoord`: read `PressureInterface`, `PressureMid`, `GeomZInterface`, `PseudoThickness`, - and the tidal/SAL potentials (already computed diagnostically each step). `VertCoord` itself - needs no change and no baseline step (§3.7.4). +1. From `VertCoord`: read `PressureInterface`, `PressureMid`, `PseudoThickness`, the sea-surface + height and the tidal/SAL potentials (already computed diagnostically each step). `VertCoord` + itself needs no change and no baseline step (§3.7.4). 2. Obtain $\alpha_0$ (= the existing `Eos::SpecVol` field) and the derivatives - $\alpha_\Theta, \alpha_S, \alpha_p$ from one TEOS-10 evaluation ([](#alpha-derivs)). Both phases - need all four; Phase 2 optionally adds second derivatives (§3.3). -3. Build the mean-preserving deviations $\Theta', S'$ ([](#vert-recon)) — **linear in Phase 1, + $\alpha_\Theta$, $\alpha_S$ from one TEOS-10 evaluation ([](#alpha-derivs)). $\alpha_p$ is not + required by [](#dalpha) and is needed only for the anchor [](#anchor); Phase 2 optionally adds + second derivatives (§3.3). +3. Build the mean-preserving deviations $\Theta'$, $S'$ ([](#vert-recon)) — **linear in Phase 1, parabolic in Phase 2** — using the actual non-uniform interface pressures (§3.4). -4. For each edge, in one column scan: form the shared expansion point [](#edge-ref) layer by layer; - accumulate $\mathcal{S}_{e,k}$ through [](#gamma-increments) and the source-4 part of - $\mathcal{R}_{e,k}$ through §3.7.4, from the same end of the column (§3.7.4 closing note). -5. For each edge and layer: add the local sources 1–3 of $\mathcal{R}_{e,k}$ (§3.5), assemble - [](#ho-discrete) with the tidal/SAL difference, and accumulate into `Tend` with `EdgeMask`. - **Phase 1** uses the two-cell operator [](#edge-grad); **Phase 2** uses the wider stencil of - §3.6.1. +4. For each edge, in one column scan from the sea surface: form the anchor [](#anchor); then for each + edge layer form the shared coefficients [](#edge-ref), evaluate [](#dalpha) at the layer's + quadrature points — each column's $\Theta$, $S$ taken from *its own* layer containing that pressure + — and advance $D_k$ by [](#d-recurrence). +5. For each edge and layer: form the layer mean of $\Delta_e z$ from $D_k$ and the second moment of + the same integrand, assemble [](#ho-exact) with the tidal/SAL difference, and accumulate into + `Tend` with `EdgeMask`. **Phase 1** uses the two-cell operator [](#edge-grad); **Phase 2** uses the + wider stencil of §3.6.1. ## 4 Design @@ -1097,24 +1057,28 @@ rather than keys, so no configuration written for Phase 1 needs to change when P PressureGradType: 'FiniteVolume' # Centered | FiniteVolume HorzOrder: 2 # 2 = two-cell stencil (Phase 1); 4 = wide stencil (Phase 2) VerticalReconstruction: 'linear' # 'linear' (Phase 1) | 'ppm' (Phase 2) - RemainderEnable: true # false = verification only, reduces to Centered (§3.9) + QuadraturePoints: 2 # per-edge-layer points for the matched-pressure integrand ``` - **Phase 1 default and target:** `HorzOrder: 2`, `VerticalReconstruction: 'linear'`, - `RemainderEnable: true`. + `QuadraturePoints: 2`. - **Phase 2 target:** `HorzOrder: 4`, `VerticalReconstruction: 'ppm'`. -`RemainderEnable: false` switches off $\mathcal{R}_{e,k}$, which by [](#centered-shift) leaves -exactly `PressureGradCentered` (§3.9). It is **verification only**: it supports the permanent -regression test of §5.5 and serves as guard test (c) of §5.2. It is not a supported production -setting — it *is* the default scheme, reached by a more expensive path — and the implementation -should log a warning if it is selected outside a test. +`QuadraturePoints` sets the number of points at which [](#dalpha) is evaluated within each edge +layer. **It is an accuracy setting only.** Because the integrand is zero *pointwise* on the exact set +(§3.5, consequence 2), no quadrature rule can break the robustness property, and the choice therefore +trades cost against accuracy off the exact set with nothing else at stake. Two points is exact for +the piecewise-linear Phase 1 integrand within a sub-interval and is the default; more is worth +considering only where the two columns' interfaces are strongly offset, since the integrand is +piecewise linear with breakpoints at the union of the two columns' interfaces and a fixed rule does +not resolve those breaks. `HorzOrder` selects the width of the edge stencil used by [](#edge-grad). It is purely an accuracy setting: it carries no constraint from the robustness property (§3.6.1). -There is no vertical quadrature setting: the one integrand in [](#ho-discrete) is nearly constant -across the layer and is evaluated in closed form (§3.2). `FiniteVolume` names the layer-integrated +There is no setting that reduces the scheme to `PressureGradCentered`: [](#dz-dp) differences the +integrand rather than correcting the centered form, so no term can be switched off to recover it +(§3.9). `FiniteVolume` names the layer-integrated control-volume form of §3.1 rather than a face-by-face assembly of the pressure traction, which is the narrower sense Adcroft et al. (2008) use. @@ -1125,7 +1089,11 @@ needs no setting of its own. Tests that mean to isolate compressibility, includi #### 4.1.2 New EOS support -`PressureGradFiniteVolume` needs $\alpha$ together with its first derivatives. The `Eos` class +`PressureGradFiniteVolume` needs $\alpha$ together with its first derivatives. Note that +[](#dalpha) uses only $\alpha_\Theta$ and $\alpha_S$ — $\alpha_p$ cancels in the matched-pressure +difference and is required only by the anchor [](#anchor). The three derivative arrays are provided +together regardless, since `Eos` computes them from one evaluation and `BruntVaisalaFreqSq` already +consumes $\alpha_p$. The `Eos` class (Eos.h) currently exposes `computeSpecVol`, `computeSpecVolDisp`, and `computeBruntVaisalaFreqSq`, but no specific-volume derivatives. This design adds one method and three device arrays: @@ -1196,25 +1164,24 @@ Three aspects of the loop structure differ from the obvious implementation: is where the TEOS-10 cost lives; the per-edge work is polynomial arithmetic on those cached values. This is what keeps Requirement 2.2 satisfied despite roughly three times as many column evaluations on a hexagonal mesh. -- **The column scan of §3.10 step 4 cannot live in this functor.** $\mathcal{S}_{e,k}$ via - [](#gamma-increments) and source 4 of $\mathcal{R}_{e,k}$ are both prefix sums down each column - with edge-dependent coefficients, so neither is expressible as an independent per-vertical-chunk - operation. They are computed together in a separate kernel filling two per-edge arrays, +- **The column scan of §3.10 step 4 cannot live in this functor.** [](#d-recurrence) is a prefix sum + down each column with edge-dependent coefficients, so it is not expressible as an independent + per-vertical-chunk operation. It is computed in a separate kernel filling one per-edge array, ```c++ - Array2DReal ShiftFirstOrder; ///< (NEdgesAll, NVertLayers) — S_{e,k}, eq. (centered-shift) - Array2DReal RemainderAccum; ///< (NEdgesAll, NVertLayers) — source 4 of R_{e,k}, §3.7.4 + Array2DReal DeltaZFixedP; ///< (NEdgesAll, NVertLayers) — D_k, eq. (d-recurrence) ``` - with a `parallelForOuter` over edges and a `parallelScanInner` down the column, in the same shape - as `VertCoord::computeGeomZHeight`. The functor then reads them chunk-wise like any other input. - The cost is two edge-sized 2-D arrays and one column scan per edge per step. This is the one - structural addition Phase 1 makes beyond the per-edge, per-chunk pattern the centered scheme uses, - and it is not optional: §3.5's requirement R2 rules out forming either quantity by subtracting - large numbers inside the chunk loop. -- **$\mathcal{R}$'s local sources are the only part that is a plain per-chunk computation.** Sources - 1–3 of §3.5 depend on the layer's own interface pressures, thicknesses and reconstruction slopes, - and belong in the functor. + with a `parallelForOuter` over edges and a `parallelScanInner` down the column, in the same shape as + `VertCoord::computeGeomZHeight`. The functor then reads it chunk-wise like any other input. The cost + is one edge-sized 2-D array and one column scan per edge per step, and it is the one structural + addition Phase 1 makes beyond the per-edge, per-chunk pattern the centered scheme uses. +- **Each column's $\Theta$, $S$ are looked up by pressure, not by layer index.** At each quadrature + point of edge layer $k$, [](#dalpha) needs the reconstruction of whichever of *that column's* layers + contains the point, which under tilt is generally not layer $k$ (§3.7.2, condition 1). Within the + column scan the two indices advance monotonically alongside $k$, so this is a pair of incremented + cursors rather than a search — but it is a real difference from the obvious implementation, and + getting it wrong reintroduces exactly the defect condition 1 warns about. The Phase 1 and Phase 2 code paths differ only in the reconstruction degree (§3.4) and in the width of the edge stencil (§3.6.1). There is one functor, not two. @@ -1295,11 +1262,11 @@ baseline step — not as part of this design. #### 4.5.1 Phase 1 — a consistent second-order scheme -**Delivers.** The exact fixed-pressure geopotential difference [](#ho-exact), evaluated as -`PressureGradCentered` plus the remainder $\mathcal{R}_{e,k}$ (§3.5); the equation-of-state expansion -about a state shared across each edge (§3.3.1); mean-preserving linear reconstruction of $\Theta$ and -$S$ in pressure (§3.4); the per-edge column scan that supplies $\mathcal{S}$ and $\mathcal{R}$'s -accumulated part (§3.7.4, §4.1.3). The result is a pressure gradient that is zero to machine +**Delivers.** The exact fixed-pressure geopotential difference [](#ho-exact), evaluated by +differencing the integrand at matched pressure and integrating the difference (§3.5); the +equation-of-state expansion about a state shared across each edge (§3.3.1); mean-preserving linear +reconstruction of $\Theta$ and $S$ in pressure (§3.4); the per-edge column scan [](#d-recurrence) and +its anchor [](#anchor). The result is a pressure gradient that is zero to machine precision for any resting ocean whose profile varies linearly with pressure, at any tilt, thickness, or bathymetry (§3.7.3) — Requirement 2.3 in full. @@ -1307,10 +1274,10 @@ or bathymetry (§3.7.3) — Requirement 2.3 in full. in use today (§3.6), so horizontal truncation error is unchanged from `PressureGradCentered`. Requirements 2.1 and 2.6 are met at second order only. -**Depends on.** Nothing unresolved. The `VertCoord` question of §3.7.4 is settled there: no change to -`VertCoord` is needed and no baseline step is required, because the midpoint rule is already the exact -layer integral of a Phase 1 $\hat\alpha$. What condition 3 does require — the column scan — is part -of this phase's own implementation (§4.1.3), not a prerequisite in another module. +**Depends on.** No change to `VertCoord` and no baseline step (§3.7.4); the scheme does not +accumulate `VertCoord`'s geometric height at all, using the sea-surface height once in [](#anchor). +The one genuine dependency on upstream state is condition 3 of §3.7.2 — that `VertCoord`'s +sea-surface height be consistent with its surface pressure — which it already satisfies. **Open at implementation time.** Two items, neither of them blocking. Which end of the column the scan accumulates from (§3.7.4 closing note) is a round-off question, settled by measurement. And the @@ -1319,7 +1286,7 @@ rather than inherited — it is the one part of the formulation the reference de since it ran with equal layer counts in both columns. **Code and cost.** Three new `Eos` derivative fields and one new method (§4.1.2); the -`PressureGradFiniteVolume` functor; two per-edge arrays and one column scan (§3.7.4, §4.1.3); no new +`PressureGradFiniteVolume` functor; one per-edge array and one column scan (§3.5.1, §4.1.3); no new TEOS-10 evaluations per cell and layer (Requirement 2.2), with roughly three times as many column evaluations on a hexagonal mesh (§4.1.3). Most of the arithmetic is in the column scan. @@ -1351,13 +1318,14 @@ Requirement 2.6, because exactness does not constrain it (§3.6.1). the confirmed result in the reduced form of §3.5, and to settle four things this design leaves to it: - - the closed form of each of $\mathcal{R}$'s four sources, with requirement R2 of §3.5 satisfied — - no source formed by subtracting large numbers; - - the reconciliation of [](#gamma-increments) against [](#centered-error), including the anchor - constant (§3.5.1); - - which end of the column the scan accumulates from (§3.7.4); - - the top- and bottom-of-column treatment, assumption A5 (§3.7.6), which the existing derivation - did not cover. + - the closed-form quadrature of [](#dalpha) and of the second moment [](#ho-exact) needs, together + with the per-column pressure lookup that feeds them; + - the anchor [](#anchor), including confirmation that it is zero for a resting ocean at the + initialized sea-surface height; + - which end of the column [](#d-recurrence) accumulates from (§3.7.4); + - the rule used where a column's deepest reconstruction is evaluated below its own floor, and how + much accuracy it costs off the exact set (assumption A5, §3.7.6). + 2. Run the assumption-A4 diagnostic of §5.3, which uses the *existing* centered scheme and so can be done immediately and in parallel with step 1. If spurious bottom-layer flow survives a profile that Phase 1 would resolve exactly, the cause is elsewhere in the model and the priority of this @@ -1487,12 +1455,16 @@ Three groups of profiles are run: **machine precision** (double-precision builds; the threshold tracks `Real`'s epsilon and the size of the hydrostatic terms, not a physical tolerance). Phase 1 and Phase 2 must both pass. - Assert this in the sharper form of §3.5's requirement R3 — that - $\mathcal{R}_{e,k} = -\mathcal{S}_{e,k}$ to round-off — and report both quantities, not only their - sum. $\mathcal{S}$ is the centered scheme's answer on the same state and is nonzero and - tilt-dependent; checking against it turns a comparison with zero into a cancellation of ten orders - of magnitude against a known reference, and it is what distinguishes a working scheme from one that - has stopped responding to tilt at all. + Report the tendency alongside `PressureGradCentered`'s on the same state, which is nonzero and + tilt-dependent (§3.9). A pass is then a cancellation of ten orders of magnitude against a known + nonzero reference rather than a comparison with zero, which is what makes it hard to pass by + accident. + + Also assert the property one level down, at the integrand: [](#dalpha) must be zero **at every + quadrature point**, not merely in the integral. This is the sharpest available form of the test, + it localizes a failure to the layer and column that caused it, and it is the check that a + per-layer-index sharing rule fails (§3.7.2, condition 1). + - **Profiles it does not:** $\Theta$, $S$ quadratic in pressure, then a realistic profile. **Pass:** the residual shrinks like $\tilde h^2$ (Phase 1) and $\tilde h^3$ (Phase 2) as the vertical grid is refined at fixed tilt, matching §3.7.3. A residual that does not shrink at the @@ -1505,16 +1477,20 @@ Three groups of profiles are run: | guard | breaks | expected to fire because | |---|---|---| - | (a) **tilt sensitivity** — assert $\mathcal{S}_{e,k}$ and $\mathcal{R}_{e,k}$ are *individually* nonzero and grow with tilt | nothing; this one runs on the passing configuration | a bug that zeroed the tilt response would satisfy every other check in this section perfectly. This is the guard against mistaking "no tilt terms" for "correct tilt terms" | - | (b) cell-local expansion point in place of [](#edge-ref) | condition 1, §3.7.2 | the two columns then use different approximations to one equation of state, so $z_i(p)$ differ by more than a constant (§3.3.1) | - | (c) `RemainderEnable: false` | conditions 2 and 3 | this is exactly `PressureGradCentered` (§3.9), whose error on this state is the thing Phase 1 removes | - | (d) source 4 of $\mathcal{R}$ omitted, local sources retained | condition 3 only | isolates the column scan: a residual that grows with depth rather than being flat down the column | - | (e) $\mathcal{R}$'s local sources truncated at first order | condition 2 only | isolates the fixed-pressure shift, leaving a residual local to each layer | + | (a) **tilt sensitivity** — assert the tendency and `PressureGradCentered`'s differ, and that the latter grows with tilt | nothing; this one runs on the passing configuration | a bug that zeroed the tilt response would satisfy every other check in this section perfectly. This is the guard against mistaking "no tilt terms" for "correct tilt terms" | + | (b) **coefficients shared by layer index** in place of edge layer | condition 1 | at a given pressure the two columns then use expansions about different states, so [](#dalpha) is no longer identically zero. **This is the defect that made an earlier formulation fail**, and it is the guard most worth having | + | (c) **each column evaluated at its own layer $k$** rather than at matched pressure | condition 2 | differencing at fixed layer index instead of fixed pressure; recovers something close to `PressureGradCentered` | + | (d) **anchor taken as $\Delta_e Z_1$ alone**, dropping the short integrals of [](#anchor) | condition 3 | leaves a depth-independent offset in $D_k$, so the residual is flat down the column rather than growing — distinguishable from (b) and (c) | + | (e) **cell-local expansion point** in place of [](#edge-ref) | accuracy only | should **not** break exactness under [](#dalpha), since the coefficients multiply zero. If it does fire, condition 1 is not implemented as specified | + + Guard (e) is the inverted one and is worth keeping for that reason: under the previous formulation + it broke exactness, and under this one it must not. It is the cheapest available confirmation that + the reformulation did what it was meant to do. - Guards (d) and (e) are the pair that makes a failure diagnosable: condition 2 and condition 3 fail - in distinguishable ways (§3.7.2), and running both tells the implementer which one is broken without - another round trip. Guard (a) is the one to write first, because it is the only one that can fire on - a configuration where every other check passes. + Guards (b), (c) and (d) break conditions 1, 2 and 3 respectively and leave residuals with different + depth structure, so running all three localizes a failure without another round trip. Guard (a) is + the one to write first, because it is the only one that can fire on a configuration where every + other check passes. Guards must be checked against a deliberately broken configuration, not only against a passing one. A guard that cannot fire is worse than no guard, because it looks like protection. @@ -1526,14 +1502,11 @@ non-uniform** set of layer thicknesses, the recovered slope (Phase 1) or slope a the most likely place for the machine-precision gate above to fail, and it localizes the failure immediately. -The test is also run in a single-precision build, to measure the round-off floor of §3.7.5. Note that -§3.7.5 now predicts this should *pass* if [](#gamma-increments) is used for $\mathcal{S}$, and that -the same measurement applies to `PressureGradCentered`; running the centered scheme alongside is what +The test is also run in a single-precision build. §3.7.5 predicts it should *pass*, because +[](#dz-dp) forms no large quantities; running `PressureGradCentered` alongside, which does, is what makes the result interpretable. -Condition 3 of §3.7.2 requires the column scan of §3.7.4, so the machine-precision check cannot pass -until that is in place; this test, together with guards (c) and (d) above, is its acceptance -criterion. It is implemented as a fast C++ unit test and also run as a configuration of the Polaris +It is implemented as a fast C++ unit test and also run as a configuration of the Polaris two-column task. **Covers:** Requirement 2.3 in full; rows 1–5 of the §3.7.3 table; the round-off floor of §3.7.5. @@ -1581,28 +1554,25 @@ under dynamics. ### 5.5 Test: Reduction to the centered scheme (permanent regression) -Configure the new scheme with `HorzOrder: 2`, `RemainderEnable: false` and confirm it reproduces -`PressureGradCentered` to round-off on the two-column test. This guards Requirement 2.5 and protects -the existing default during refactoring. The test is established with Phase 1 and rerun unchanged for -Phase 2, where it also confirms the wider stencil collapses correctly to the two-cell one. - -**Run it at nonzero tilt, and at several tilts.** Per §3.9 the reduction is exact at any tilt, so a -level-interface configuration would be a weaker test than the design supports — and a tilt sweep here -is what confirms that $\mathcal{S}$ alone is reproducing the centered scheme rather than the two -schemes agreeing because neither is responding to tilt. - -Note that `RemainderEnable: false` is not a supported production setting (§4.1.1); it exists so that -this comparison is possible. Keeping it costs one branch. - -This test is retained permanently rather than treated as a one-time transition check, and that choice -is the reason `PressureGradCentered` is kept as a separate implementation rather than reimplemented as -the lowest-order configuration of `PressureGradFiniteVolume` (§4.4). The two functors read the mesh, -`VertCoord`, and EOS state through independently written code, so their agreement to round-off is -evidence about *shared upstream* state as well as about the PGF arithmetic: a wrong edge mask, a -mis-indexed interface array, or a misinterpreted `VertCoord` convention shows up as a disagreement. -Were the centered scheme replaced by an order-2 configuration of the new code, this comparison would -reduce to comparing an implementation against itself, and any defect upstream of the order switch -would cancel out of it. +Assert [](#centered-identity) against `PressureGradCentered` directly, on the two-column test, across +a sweep of tilts. This is a unit test of the *identity* of §3.9, not of a reduced configuration of the +new scheme: [](#dz-dp) differences the integrand and never forms [](#centered-shift), so there is no +setting that recovers the centered scheme (§3.9, final paragraph). + +It guards Requirement 2.5 and protects the existing default during refactoring, and it is cheap — +[](#centered-shift) is a few lines and needs none of the new machinery. Because the two functors read +the mesh, `VertCoord` and EOS state through independently written code, their agreement tests the +shared upstream state — edge masks, interface indexing, `VertCoord` conventions — and not just the PGF +arithmetic (§4.4). Measured, it holds to $0.5\,\epsilon$ of the hydrostatic scale over fifty states +(§6.2). + +Expect agreement to round-off rather than bit-for-bit. In addition to the operation-order argument of +§4.4, `PressureMid` may be formed as $\tilde z_{\text{bot}} + \tfrac12\tilde h$ rather than as the mean +of the two interface pressures; those are algebraically identical but not bit-for-bit. + +A second, weaker check is worth running alongside: the `FiniteVolume` and `Centered` tendencies must +agree to $O((\Delta_e p)^2)$ as the tilt is reduced. That is the only sense in which the two schemes +now reduce to one another, and a violation indicates a defect in one of them. **Covers:** Requirement 2.5; §3.9. @@ -1613,8 +1583,9 @@ could satisfy every accuracy gate while quietly calling the equation of state in Two cheap checks close that: - **Evaluation count.** With an instrumented `Eos`, confirm the number of specific-volume - evaluations per time step is one per cell per layer and is **unchanged** when `HorzOrder` and - `VerticalReconstruction` are varied. This is the property Requirement 2.2 actually states, and it is + evaluations per time step is one per cell per layer and is **unchanged** when `HorzOrder`, + `VerticalReconstruction` and `QuadraturePoints` are varied. The last is the one that matters most + here, since the quadrature loop is where an equation-of-state call would most naturally creep in. This is the property Requirement 2.2 actually states, and it is a counter comparison, not a timing measurement, so it is deterministic and suitable for CI. - **Wall time.** Record PGF kernel time relative to `PressureGradCentered` on a representative configuration, as a performance regression guard. The expected cost is dominated by the per-edge @@ -1639,9 +1610,11 @@ Two cheap checks close that: | A3 Residual small enough in practice | §5.1 accuracy gate; §5.3; §5.4 | | A4 PGF error causes the instability | §5.3 diagnostic, run before Phase 1 completes | | A5 Top- and bottom-of-column treatment | §5.1 `bathymetry_step` and `surface_pressure_gradient` | -| §3.5 remainder is load-bearing | §5.2 guards (c), (d), (e); §5.5 at nonzero tilt | +| §3.7.2 condition 1, shared at matched pressure | §5.2 guard (b), and the per-quadrature-point assertion | +| §3.7.2 condition 2, differenced before integration | §5.2 guard (c) | +| §3.7.2 condition 3, the anchor | §5.2 guard (d) | | §3.5 the scheme responds to tilt at all | §5.2 guard (a); §5.5 tilt sweep | -| §3.7.4 column scan | §5.2 (cannot pass without it; guard (d) isolates it) | +| §3.9 the centered identity | §5.5, as a standalone unit test | | §3.7.5 Round-off floor | §5.2, run in both precisions, alongside `Centered` | Requirement 2.7 (extensibility) is not testable directly; it is addressed by the configuration @@ -1673,7 +1646,7 @@ $\alpha(p)$, sharing no code with the scheme under test. | exactness on the exact set, independent of tilt | §3.7.3 | residual at the round-off floor, $9\times10^{-16}$ to $9\times10^{-15}$, **not growing** across 0.5–200 m/km at 16 and 64 layers. `Centered` on the same states is exactly first order in tilt | | $O(\tilde h^2)$ off the exact set | §3.7.3 | quadratic-in-$p$ profile at 50 m/km: rates 2.21, 2.14, 2.09, 2.05 under vertical refinement | | the edge-shared expansion point is load-bearing | §3.3.1 | replacing it with a cell-local one costs $2.2\times10^{-9}$ to $3.0\times10^{-5}$ across the tilt range — §5.2 guard (b) | -| the fixed-pressure comparison is the whole scheme, not a correction | §3.5, §3.7.4 | omitting it costs $2.8\times10^{-3}$ to $1.1$ m s$^{-2}$ — three to five orders larger than any other guard, and the reason §3.5 presents $\mathcal{R}$ as a component rather than a refinement | +| the fixed-pressure comparison is the whole scheme, not a correction | §3.5 | omitting it costs $2.8\times10^{-3}$ to $1.1$ m s$^{-2}$ — three to five orders larger than any other guard | Three limits on what this establishes, all of them live. @@ -1682,11 +1655,11 @@ Three limits on what this establishes, all of them live. is assumption A5 of §3.7.6. - **Nothing has been run in Omega**, or through the real Polaris task machinery, so the interaction with p-star initialization and partial cells is untested. -- **The rows above were measured on an assembly of all four pressure terms**, not on [](#ho-discrete). - Given that those terms cancel to $3\times10^{-15}$ relative, what the exactness and $O(\tilde h^2)$ - rows measured *was* the geopotential term alone, so they carry over — but by that argument rather - than by direct measurement, and confirming it against [](#ho-discrete) is the first task of §4.5.3 - step 1. +- **The rows above were measured on an assembly of all four pressure terms**, not on the form §3.5 + specifies. Given that those terms cancel to $3\times10^{-15}$ relative, what the exactness and + $O(\tilde h^2)$ rows measured *was* the geopotential term alone, so they carry over — but by that + argument rather than by direct measurement. §6.3 records what happened when it was measured + directly. ### 6.2 Corrections owed to `OmegaV1GoverningEqns.md` @@ -1706,3 +1679,68 @@ be made there rather than left as local overrides here. $\mathbf n^{\text{top}} \approx (-\nabla\tilde z^{\text{top}}, 1)$, unnormalized. The derivation in §3.1 here uses Leibniz' rule directly, so neither the corrected [](#ho-target) nor [](#ho-exact) depends on that approximation. + +### 6.3 Measurements from the Polaris reference implementation + +A second round of measurement, on the Polaris two-column harness at +`polaris/tasks/ocean/horiz_press_grad` and asserted by `pytest`, confirmed two claims of §3 and +falsified a third. It is the reason §3.5 differences the integrand rather than correcting +[](#centered-shift). + +**Confirmed — the centered identity (§3.9).** [](#centered-shift) reproduces the Polaris centered +HPGA to at most $0.5\,\epsilon$ of the hydrostatic scale, over fifty states: both resting-state tilt +sweeps in full, and the four gradient variants at their coarsest and finest resolution. It holds in +the bottom partial cell and at tilts where the two columns' `maxLevelCell` differ. The check is not +vacuous — plausible mis-derivations miss by $700\times$ the tolerance (cell-local instead of +edge-averaged $\alpha$), $1.2\times10^{6}$ (top interface instead of the trapezoid) and +$2\times10^{9}$ (dropping the pressure term). + +**Confirmed — accumulating small quantities recovers precision (§3.7.5).** The largest increment of +a cancellation-free accumulation, against the fixed-index height difference it replaces: +$1.1\times10^{-3}$ at 256 m layers and 50 m/km, $2.7\times10^{-4}$ at 64 m, $2.0\times10^{-4}$ on a +200 m/km bathymetry step — about three decimal digits of headroom on a tilted coordinate. The +gradient variants gain little only because their coordinate is flat and there is nothing to save. + +**Falsified — sharing the equation-of-state expansion by layer index.** On a configuration inside the +exact set, a formulation that built each column's height integral separately and reconciled the two +missed exactness by $\approx 2\times10^{-3}$ of the centered scheme's answer, **flat across three +decades of tilt**, where the robustness property asks for round-off. A brute-force evaluation of +[](#ho-exact) by direct quadrature — sharing no code with the closed forms — missed by the same +amount, which is what identified the target rather than the algebra as the problem. The tilt +independence is the signature: the mismatch is $O(\alpha_{pp}\,\delta p\,\Delta_e p^{\text{mid}})$, +first order in tilt, as is the signal. §3.7.2's condition 1 records the diagnosis and [](#dalpha) the +repair. + +Worth noting for scale: at 64 m layers and 50 m/km the two columns' layer $k$ are offset by 2.8 layer +thicknesses and **do not overlap in pressure at all**. Any formulation that pairs by layer index is +differencing unrelated water there. + +### 6.4 Corrections carried over from the reference implementation + +Five items, all confirmed numerically on the Polaris side and folded into §3–§5 above. + +1. **[](#centered-error) reconciles only in the redistribution limit.** Summation by parts on a + cancellation-free accumulation gives [](#centered-error) plus a $k$-independent anchor constant + **only when $\sum_j \Delta_e\tilde h_j = 0$** — the two columns having equal total pseudo-thickness. + A `z_tilde_bot` tilt gives them different pseudo-bottom depths, so this does not hold in + `hydrostatic_consistency`, the configuration the design cites. [](#centered-error) should be read + as the redistribution-limit statement its own derivation assumes. +2. **Sources of a correction are not individually small.** An earlier formulation required each + component of its remainder to be "a small quantity". Measured, the largest was exactly the size of + the term it corrected — necessarily, since it is the term that cancels it. The requirement that + matters is that no component be *formed by subtracting large quantities*, which is a statement + about how each is evaluated rather than about its magnitude. §3.5.1 states it that way. +3. **Two exact simplifications** hold when the edge control volume is the average of the two columns' + interface pressures: the edge layer's mid-pressure is exactly the edge average of the two columns' + own layer midpoints, and its thickness exactly the edge average of theirs. Both follow from + `PressureMid` being the exact arithmetic midpoint. §3.7.4 records them. +4. **`gsw` units.** `gsw.specvol_first_derivatives(SA, CT, p)` takes pressure in **dbar** and returns + the pressure derivative of specific volume per **Pa** — the convention of neither argument. The + Omega unit test of §4.1.2 should assert this against a centred finite difference in Pa, and + explicitly against being wrong by the factor $10^{4}$. +5. **Initializing $\Theta$ and $S$ as layer means.** Omega's prognostic $\Theta$, $S$ are layer means + and §3.4 reconstructs them as mean-preserving, so a test initial condition should supply layer + means rather than midpoint samples. Changing this moves the Polaris resting-state baselines by + 3–39% (and the gradient variants by $\le 0.02\%$), so the recorded `Centered` baseline and the + Omega-vs-Polaris comparison both move with it. This is a property of the test configuration, not + of the scheme, but it invalidates any comparison against the earlier baseline. From fd9c663cec3483f0e7850925178f1b79cbe87d78 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Fri, 31 Jul 2026 07:04:32 -0500 Subject: [PATCH 12/22] Correct the design against the reference implementation's measurements The scheme of section 3.5 has now been implemented and measured in the Polaris two-column harness. Exactness holds: the differenced integrand is zero at every quadrature point to 5e-21, the accumulated height difference to 1e-15 m, and the assembled tendency to 2e-18 m/s, across the full tilt sweep at three vertical resolutions. Several claims in this document did not survive contact, and this commit corrects them. Section 3.5's first consequence overreached. Exactness does not depend on the coefficients' values, but it does depend on one set multiplying both columns; give each its own and exactness is lost at 1e-5. The edge-shared expansion point remains load-bearing, for sharing rather than for where the point sits. The recorded diagnosis of the earlier formulation's failure was wrong. It said the cause was sharing the equation-of-state expansion at fixed layer index rather than at fixed pressure. Measured, that choice has no effect at all, because whatever the shared set is, it multiplies a contrast that is zero. The mechanism was never established and, the formulation being abandoned, is left open rather than pursued. State the condition the design actually needs instead: the per-layer version is insufficient because the column integral accumulates from the surface. Requirement 2.3.4 asked for the residual to shrink one order faster in layer thickness than the centered scheme's. It does not, because the premise - that the centered scheme is first order in layer thickness - does not hold on the profiles measured; both converge at roughly second order on a smooth curved resting profile, and the advantage narrows from 6.5x at 256 m layers to 2.4x at 64 m. Express the requirement as absolute error at affordable resolution, which is what section 1 says the metric of success actually is. The first-order behaviour that is robust is in the coordinate tilt, not in layer thickness. The anchor was described in terms of how one test happens to initialize its sea surface, and that had been promoted to a standing condition on the design and a dependency on VertCoord. It is neither. The anchor is computed from the model's sea-surface heights and surface pressures, not assumed, and it is the k=1 instance of the same fixed-pressure comparison every other interface gets. What is a real implementation condition is that the surface difference be shifted to a common pressure rather than taken as the raw height difference, so condition 3 says that. The test-design consequence - that a resting-state gate must be run on a state that is exactly at rest, or must expect the residual its initialization implies - belongs in section 5.2 and is stated there generically. Correct the guard list to match what fires. A cell-local expansion point breaks exactness and is the condition-1 guard; the choice of shared coefficient set does not and is deliberately not a guard. Record prominently that the guard which would catch a column's state being looked up by layer index instead of by pressure cannot be made to fire on any available configuration, so an implementation that gets this wrong will pass every check specified here and must be pinned by direct property tests. Keep the design to requirements and formulation. Statements about what earlier revisions said, and the reasons a requirement changed, belong in section 6 or in the commit history rather than in sections 1 to 5. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 344 ++++++++++++------ 1 file changed, 239 insertions(+), 105 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index a8a45b0a8ab8..e42c2efabaed 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -180,10 +180,15 @@ pressure**, which captures both compressibility and smooth stratification to lea **2.3.4 Everywhere else, substantially smaller error than the centered scheme.** For realistic profiles, which no reconstruction reproduces exactly, some residual PGF is unavoidable and is *correct* — the two neighboring columns genuinely do hold slightly different water (§3.7.1). The -requirement is that this residual shrink at least one order faster in layer thickness than -`PressureGradCentered` does, and that it not be swamped by errors the scheme itself introduces +requirement is that this residual be substantially smaller than `PressureGradCentered`'s at the +resolutions Omega can afford, and that it not be swamped by errors the scheme itself introduces through an inconsistent geopotential or a truncated fixed-pressure comparison. +The comparison is made on **absolute error at the resolutions Omega can afford**, not on relative +convergence order. The two schemes converge at similar rates on smooth profiles, so an +order-of-convergence gate against the centered scheme would not express what this requirement is +for; §6.5 gives the measurements behind that choice and §5.1 the gate that implements it. + These properties must hold without reference to any background or reference profile, so that they hold equally in the warm pool, at the poles, and over a seamount. @@ -388,10 +393,8 @@ that a four-term force balance would need several delicate arguments to secure. [](#z-of-p) the two $z_i(p)$ differ by a constant fixed by the anchors, and $[\nabla_n z]_p$ is *pointwise* zero at every pressure. The integral in [](#ho-exact) is then zero regardless of the tilt, the layer thicknesses, the bathymetry, or the quadrature used to evaluate it. There - are no terms to pair and no signs to get right. For a resting ocean the anchors agree by the - inverse-barometer relation — $z^{\text{surf}}_i$ tilts exactly so as to compensate a horizontal - gradient in $p^{\text{surf}}_i$ — which is the state the `surface_pressure_gradient` Polaris - variant initializes. + are no terms to pair and no signs to get right. For a resting ocean the anchors agree as well, + the sea surface tilting exactly so as to compensate a horizontal gradient in $p^{\text{surf}}$. - **The vertical quadrature is not an accuracy knob.** $[\nabla_n z]_p$ varies across the layer only through $\frac{d}{dp}[\nabla_n z]_p = -\frac{1}{g}[\nabla_n\hat\alpha]_p$, the horizontal contrast in specific volume at fixed pressure — a quantity that is *small* and that vanishes @@ -560,12 +563,17 @@ $$ (dalpha) **This is the central property of the scheme.** [](#dalpha) is a product of a coefficient with the horizontal contrast in reconstructed $\Theta$ and $S$ *at matched pressure*, and that contrast is **identically zero, pointwise**, whenever the two columns' reconstructions describe the same water -(§3.7.2, condition 1). Four consequences follow, and they replace a chain of separate arguments an -earlier formulation of this section needed: - -1. **Exactness does not depend on the coefficients.** Whatever $\bar\alpha_\Theta$, - $\bar\alpha_S$ are, they multiply zero. The edge-shared expansion point of §3.3.1 remains the - right choice on *accuracy* grounds, but the robustness property no longer rests on it. +(§3.7.2, condition 1). Four consequences follow: + +1. **Exactness does not depend on the coefficients' values, but does depend on their being + shared.** Whatever $\bar\alpha_\Theta$, $\bar\alpha_S$ are, they multiply zero — so *which* + shared set is used is an accuracy question, and selecting it by edge layer rather than by some + other rule cannot break the robustness property. What is load-bearing is that **one** set + multiply both columns: [](#dalpha) collapses to a coefficient times a contrast only then. Give + each column its own expansion point and the $\bar\alpha_0$ and $\bar\alpha_p$ terms no longer + cancel, and exactness is lost — measured at $10^{-5}$, which is guard (e) of §5.2. The + edge-shared expansion point of §3.3.1 is therefore load-bearing, and it is load-bearing for + *sharing* rather than for where the point sits. 2. **Exactness does not depend on the quadrature.** The integrand is zero at every point, so any rule integrates it to zero. Quadrature order is therefore an ordinary accuracy knob (§4.1.1), not a correctness requirement. @@ -598,12 +606,34 @@ $$ D_1 \;=\; \Delta_e Z_1 \;-\; \frac{1}{g}\sum_{i \in CE(e)} -n_{e,i} \int_{p^{\text{surf}}_i}^{\bar q_1} \hat\alpha^{(e)}_i(p)\,dp , $$ (anchor) -with both short integrals in closed form and taken inside each column's own top layer. For a resting -ocean whose sea surface satisfies the inverse-barometer relation, $D_1$ is zero exactly — the surface -tilts precisely so as to compensate the horizontal gradient in $p^{\text{surf}}$. **Exactness of the -scheme therefore inherits the consistency of `VertCoord`'s sea-surface height with its surface -pressure**, which is a dependency worth stating: it is the one place the PGF's robustness reaches -outside the PGF. +with both short integrals in closed form and taken inside each column's own top layer, and both +vanishing where the two columns share a surface pressure. + +$D_1$ is **computed, not assumed**: it is whatever the model's geometric heights and surface +pressures imply, evaluated at a common pressure. Like every other quantity in the scan it is a +fixed-pressure height difference, and it is zero exactly when the state carries no horizontal +pressure gradient at the surface — which is what a state at rest means. A state that is only +approximately at rest carries a real gradient there, and the scheme reports it. The anchor is +therefore not a place where the scheme assumes anything about the state; it is the $k=1$ instance +of the same comparison [](#d-recurrence) makes at every other interface. + +**Which end of the column the anchor sits at is a conditioning choice.** +`VertCoord::computeGeomZHeight` sets $Z_{i,\,\text{bot}} = -\text{BottomGeomDepth}_i$ and accumulates +$\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ **upward**: the bathymetry is prescribed and the +sea-surface height is derived, so + +$$ +\Delta_e Z_{\text{surf}} = -\Delta_e H + \frac{1}{g}\,\Delta_e\!\left[\sum_k \alpha_{i,k}\,\Delta p_{i,k}\right]. +$$ (ssh-difference) + +The bracket is not an error. It is how the model defines geometric height, and the PGF must see the +model's own $z$ — a scheme that returns zero for the state the model actually holds is what +Requirement 2.3.1 asks for, so using the derived sea-surface height is self-consistent and correct. +What [](#ssh-difference) does show is that $\Delta_e Z_{\text{surf}}$ is a difference of two +column-length accumulations yielding a small result, where $-\Delta_e H$ is exact input and vanishes +identically for a flat floor. The sea-floor anchor is therefore better conditioned in floating point, +at the cost of a larger common-pressure excursion and a partial cell to handle where `maxLevelCell` +differs. §3.7.4 records what is and is not established about the choice. **Every quantity in the scan is small.** $D_k$ is the fixed-pressure height difference — of order $10^{-1}$ m for a realistic baroclinic column and zero for a resting one, against the $10^{2}$ m @@ -705,33 +735,27 @@ For each edge and layer: layer, but at **every pressure from the anchor down**, since [](#z-of-p) integrates from the surface and [](#d-recurrence) accumulates from it. - **This is stronger than it looks, and stating it per layer is a trap.** An earlier revision of this - design required only that the two columns agree "over the pressure range the layer spans", and - satisfied it by sharing the equation-of-state expansion across the edge **at fixed layer index** - ([](#edge-ref)). Under tilt, fixed layer index is not fixed pressure: column $L$'s layer $k$ and - column $R$'s layer $k$ span different pressure ranges, so at a given pressure the two columns were - using expansions about different states, and $\hat\alpha^{(e)}$ became a *discontinuous - piecewise-linear function whose breakpoints sat at different pressures in the two columns*. The two - columns then integrated genuinely different functions even for a profile both reconstructed - exactly, and the scheme missed exactness by - $O(\alpha_{pp}\,\delta p\,\Delta_e p^{\text{mid}})$ — first order in tilt, and therefore a - *tilt-independent fraction* of the signal. Measured at $2\times10^{-3}$ of the centered scheme's - answer, flat across three decades of tilt (§6.3). - - Every other comparison in this design had already been moved to fixed pressure; that one had not. - [](#dalpha) is the repair: differencing at matched pressure before integrating makes the condition - hold pointwise and by construction. + **The per-layer version of this condition is not sufficient, and the difference is the whole + reason for [](#dalpha).** Requiring the two columns to agree only "over the pressure range the + layer spans" is satisfiable while the scheme still misses exactness by three orders of magnitude, + because [](#z-of-p) integrates from the surface and [](#d-recurrence) accumulates from it: two + column integrals taken over different pressure ranges, with different layer partitions, have + nothing forcing them to agree. Differencing the integrand at matched pressure makes the condition + hold pointwise and by construction, and it is verifiable pointwise — [](#dalpha) is zero at a + quadrature point or it is not. §6.5 gives the measurements. 2. **The two columns are differenced at a common pressure, before integration.** This is [](#dz-dp)–[](#dalpha). Integrating each column separately and subtracting satisfies condition 1 only to the order of whatever shift is used to reconcile the two, and reintroduces the large-number cancellation §3.7.5 is about. -3. **The anchor is consistent.** [](#anchor) must be zero for a resting ocean, which requires - `VertCoord`'s sea-surface height to satisfy the inverse-barometer relation against its own surface - pressure. Unlike conditions 1 and 2 this is not under the PGF's control; it is a dependency on - upstream state, and §5.2 tests it by construction. - -Conditions 2 and 3 are about the discretization and the state it is handed. Condition 1 is about +3. **The anchor is shifted to a common pressure too.** [](#anchor), not $\Delta_e Z_1$. Wherever + surface pressure varies horizontally the two columns' sea surfaces sit at different pressures, so + the comparison condition 2 imposes in the interior must be made at the top of the column as well. + This is the $k=1$ instance of condition 2 rather than a separate idea, but it is stated separately + because it is a distinct place in the code and fails in a distinguishable way — a depth-independent + offset in $D_k$ (§5.2, guard (d)). + +Conditions 2 and 3 are about the discretization alone. Condition 1 is about whether the *reconstruction* reproduces the true profile: it holds exactly for profiles in the exact set of §3.7.3, and fails by however much the reconstruction misses when it does not. Meeting all three gives a PGF that is **zero to machine precision**, for any tilt, any layer thickness, and any @@ -770,8 +794,10 @@ Two consequences deserve emphasis: ocean does not exist, but linear-in-pressure captures compressibility exactly and smooth stratification to leading order, which is most of what a real column looks like over a single layer. It satisfies Requirement 2.3.3. -- `PressureGradCentered` is only first order in layer thickness for *every* stratified profile, - including a horizontally uniform one. +- `PressureGradCentered` carries a first-order-in-tilt error for *every* stratified profile, + including a horizontally uniform one. Its order in layer thickness is profile-dependent (§6.5), so + the advantage Phase 1 offers is best stated as an absolute error ratio at a given resolution rather + than as a difference in convergence rate. That last point is worth showing, since it identifies the error Phase 1 targets. Take specific volume uniform in the horizontal within each layer, and let the coordinate merely redistribute @@ -788,12 +814,12 @@ contrast in *in-situ* $\alpha$ is dominated by compressibility (a few percent ov depth, against a few tenths of a percent from $\Theta$ and $S$), and that is exactly the part Phase 1 cancels. -This first-order behaviour has since been **measured**, and it is no longer an assertion. On the -Polaris `horiz_press_grad` resting-state configurations (uniform $\Theta$, $S$, flat floor, tilted -coordinate), `PressureGradCentered` gives a fitted exponent of $1.0000$ in the coordinate tilt at -three vertical resolutions, and the `ztilde_gradient` variant converges at $\approx 1.1$ in -horizontal resolution once the bottom layer is included in the comparison. Two independent -measurements of the same first-order behaviour, in agreement. The corresponding absolute errors reach +`PressureGradCentered` is exactly first order in the **coordinate tilt**: measured fitted exponent +$1.0000$ at three vertical resolutions on the Polaris resting-state configurations, with the +`ztilde_gradient` variant converging at $\approx 1.1$ in horizontal resolution once the bottom layer +is included. Its order in **layer thickness** is profile-dependent and is not reliably first — it +reaches second order and beyond on smooth resting profiles (§6.5) — so the tilt exponent, not the +thickness order, is the robust statement. The corresponding absolute errors reach $2\times10^{-5}\ \mathrm{m\,s^{-2}}$ at a coordinate tilt of 50 m/km with 256 m layers — the order of the bottom-layer error seen in realistic global configurations. Whether this downward accumulation is in fact what produces the bottom-layer noise seen in realistic global configurations is a plausible diagnosis, not an established one; it is @@ -806,10 +832,9 @@ sea-surface height that [](#anchor) differences. It is **not** the source of the integrates: [](#d-recurrence) builds $\Delta_e z$ from the reconstruction alone, so the question of whether `VertCoord`'s $z$ is built from the same $\hat\alpha$ the PGF uses does not arise. -That is a simplification worth recording, because it disposes of two questions earlier revisions of -this design spent effort on. +Two questions that would otherwise arise therefore do not. -**The quadrature question, which is settled and now moot.** +**The quadrature question.** `VertCoord::computeGeomZHeight` accumulates $\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — apparently a midpoint rule. For a Phase 1 reconstruction it is the exact layer integral: @@ -824,12 +849,11 @@ interface pressures. This remains true and remains useful — it is why no chang answer-changing baseline step is required — but the scheme no longer depends on it, since it no longer accumulates `VertCoord`'s $z$. -**The sharing question, which [](#dalpha) answers directly.** Whether a cell-based $z$ can carry an -edge-dependent $\hat\alpha$ was the right question to ask of a formulation that differenced two -separately accumulated column integrals. It does not arise for one that differences the integrand: -there is no per-column integral to reconcile, and the per-layer mismatch between `VertCoord`'s -increment and the edge-shared profile's — which an earlier revision carried as a column prefix sum — -is not part of the scheme. +**The sharing question.** Whether a cell-based $z$ can carry an edge-dependent $\hat\alpha$ would +matter to a formulation that differenced two separately accumulated column integrals. It does not +arise for one that differences the integrand: there is no per-column integral to reconcile, and the +per-layer mismatch between `VertCoord`'s increment and the edge-shared profile's is not part of the +scheme. **Two exact simplifications** follow from taking the edge control volume as the average of the two columns' interface pressures, $p^{\text{top}}_{e,k} = \bar q_k$ and @@ -841,20 +865,28 @@ $p^{\text{bot}}_{e,k} = \bar q_{k+1}$, and are worth using in the implementation Both follow from `PressureMid` being the exact arithmetic midpoint, and both were confirmed numerically. -**One question is left to implementation time**: which end of the column [](#d-recurrence) -accumulates from. `VertCoord` builds $z$ upward from the bathymetry while pressure is built downward -from the surface. Accumulating from the surface is the natural choice, since [](#anchor) is a surface -condition and the sea-surface height difference is small and well conditioned; accumulating from the -sea floor requires an anchor at the bathymetry, where the two columns may have different bottom -pressures. Measured in double precision the two agree to round-off, so this is a round-off question -(§3.7.5) and not a consistency one. +**Which end of the column to anchor at is left to implementation time.** `VertCoord` builds $z$ +upward from the bathymetry while pressure is built downward from the surface, so the two accumulate +round-off from opposite ends, and [](#ssh-difference) favours the sea floor on conditioning grounds: +$-\Delta_e H$ is exact input where $\Delta_e Z_{\text{surf}}$ is the small residual of two +column-length sums. Either is correct; measured in double precision the two directions agree to +round-off. This is a round-off question, not a consistency one. + +One consequence is worth recording for whoever builds the reference implementation. A test harness +that anchors its geometric column at a *prescribed* sea surface and derives the bathymetry is +constructing the state from the opposite end to `VertCoord`, which prescribes the bathymetry and +derives the sea surface. The two agree only if the derived quantity is what is written to the initial +condition and the same $\Delta z$ increment is used on both sides — a round trip that is easy to +break silently and that nothing in this design would catch. That the existing Omega-vs-Polaris +comparison holds to $10^{-16}$–$10^{-13}$ on the centered scheme, which reads `GeomZInterface` +directly, is the evidence that it currently holds. #### 3.7.5 Round-off in the deep ocean -An earlier formulation of this scheme differenced two column integrals of order $10^{2}$ m to obtain -a residual of order $10^{-3}$ m, consuming roughly five significant digits before the physics -appeared and roughly ten by the time the tendency was formed. That is `PressureGradCentered`'s -existing arithmetic, and it is the reason this section exists. +A scheme that differences two column integrals of order $10^{2}$ m to obtain a residual of order +$10^{-3}$ m consumes roughly five significant digits before the physics appears, and roughly ten by +the time the tendency is formed. That is `PressureGradCentered`'s arithmetic, and it is the reason +this section exists. **[](#dz-dp) removes the exposure rather than managing it.** Every quantity in the scan is a difference *before* it is an integral: [](#dalpha) is a horizontal contrast, [](#d-recurrence) @@ -869,7 +901,7 @@ Three consequences. separately accumulated column integrals. Measured, restructuring the accumulation this way recovered about three decimal digits of headroom on a tilted coordinate — the largest increment being $\sim 10^{-3}$ of the height difference it replaces (§6.3). -- **A single-precision build is expected to pass §5.2**, where previously it was expected to fail. +- **A single-precision build is expected to pass §5.2.** That is a prediction to be measured (§5.2 is run in both precisions), not an assumption, and it should be measured alongside `PressureGradCentered` so the comparison is interpretable. - **The perturbation form is not needed and is not specified.** It would have subtracted a local @@ -998,9 +1030,8 @@ Three things this buys, and one it does not. [](#dz-dp) is not built by adding a correction to [](#centered-shift); it differences the integrand and never forms $\mathcal{S}$ at all. There is therefore no `FiniteVolume` setting that recovers `PressureGradCentered` bit-for-bit or to round-off, and §5.5 tests the identity above rather than a -reduced configuration. An earlier revision of this design proposed such a switch; it was a property -of a formulation that has been replaced, and the identity is the more useful half of it in any case, -since it can be asserted as a unit test without running the new scheme at all. +reduced configuration — which is the more useful test in any case, since it can be asserted without +running the new scheme at all. ### 3.10 Per-step algorithm summary @@ -1276,11 +1307,12 @@ Requirements 2.1 and 2.6 are met at second order only. **Depends on.** No change to `VertCoord` and no baseline step (§3.7.4); the scheme does not accumulate `VertCoord`'s geometric height at all, using the sea-surface height once in [](#anchor). -The one genuine dependency on upstream state is condition 3 of §3.7.2 — that `VertCoord`'s -sea-surface height be consistent with its surface pressure — which it already satisfies. +All three conditions of §3.7.2 are properties of the PGF's own discretization; none is a dependency +on another module. **Open at implementation time.** Two items, neither of them blocking. Which end of the column the -scan accumulates from (§3.7.4 closing note) is a round-off question, settled by measurement. And the +scan anchors at (§3.7.4) — where the sea floor is preferred on conditioning grounds and the +measurement supporting the alternative may not be discriminating. And the treatment at the top and bottom of the column, assumption A5 of §3.7.6, has to be defined explicitly rather than inherited — it is the one part of the formulation the reference derivation did not cover, since it ran with equal layer counts in both columns. @@ -1393,12 +1425,16 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient layer-mean analytic HPGA (unchanged). For `FiniteVolume` the layer-mean comparison remains the correct target, since the scheme is a finite-volume, layer-averaged discretization. -- **Accuracy gate (new, Requirement 2.1):** at a representative coarse resolution (e.g. the - coarsest in `horiz_resolutions`), the absolute RMS HPGA error vs. the reference must be below - a tolerance, **and** the new scheme's RMS error must be below the centered RMS error at that - same resolution (the scheme must demonstrably help where it matters). This gate applies to - Phase 1, where it is the primary measure of value, since Phase 1 does not change the - convergence slope. +- **Accuracy gate (new, Requirements 2.1 and 2.3.4):** at a representative coarse resolution (e.g. + the coarsest in `horiz_resolutions`), the absolute RMS HPGA error vs. the reference must be below + a tolerance, **and** the new scheme's RMS error must be below the centered RMS error at that same + resolution. This gate applies to Phase 1, where it is the primary measure of value. + + **This is also the gate for Requirement 2.3.4.** Set the ratio per variant from the measurements + in §6.5 — the advantage is 6.5× at 256 m layers and 2.4× at 64 m on a smooth curved profile, ~400× + on a stepped bathymetry — and take it at the coarse end of the sweep. Do **not** add a gate + requiring the new scheme's convergence slope to exceed the centered scheme's: the two converge at + similar rates on smooth profiles, so such a gate fails where nothing is wrong. - **Verification gate (Requirement 2.6):** the measured slope of RMS error vs. resolution, `omega_vs_reference_convergence_rate_*`, must fall within a band around the configured order of accuracy — nominally ~2 for `finite_volume_phase1` and ~4 for `finite_volume_phase2`. This band @@ -1442,6 +1478,34 @@ of the §3.7.3 table (horizontal structure in $\Theta$, $S$); assumptions A1, A2 This is the primary test of the steep-layer robustness property (Requirement 2.3, §3.7). It follows the table in §3.7.3 row by row rather than being a single pass/fail. +**Run the machine-precision gate with a horizontally uniform surface pressure.** Both integrals in +[](#anchor) then vanish identically and the two columns' sea-surface heights are equal by +construction, so the anchor contributes nothing and the gate tests the scheme rather than the +initialization. This costs nothing: surface-pressure gradients are exercised separately by §5.1, +where the reference solution supplies the expected value. + +Where surface pressure *does* vary horizontally, the state carries a real fixed-pressure height +difference at the surface and the scheme is right to report it — **expect it, and assert it against a +computed value rather than against zero.** Two things make zero the wrong expectation there, and the +second is not removable: + +- an initialization that balances the surface against a *reference* density $\rho_0$ rather than the + in-situ density leaves a residual of relative size $(\alpha - 1/\rho_0)/\alpha$. In a pressure-based + coordinate the in-situ balance is available in closed form — $z^{\text{surf}}$ is + $-\tfrac1g\int\alpha\,dp$ over the surface pressure, a quadrature of a known integrand rather than + the fixed-point solve a height-based Boussinesq model would need — so this part *can* be removed if + a configuration wants to; +- [](#anchor) integrates $\hat\alpha^{(e)}$, the reconstruction, not the true $\alpha$. Exact + cancellation at the surface would require the sea-surface height to be consistent with the + *scheme's own linearized profile*, which is not something an initializer can reasonably be asked + for. A residual at the equation-of-state linearization level therefore survives any physically + correct initialization. + +The second point is derived here and has not been measured; the estimate is that it is some two +orders below the first. Either way the conclusion for testing is the same, and it is why the first +paragraph exists: **do not put the exactness gate on a configuration with a varying surface +pressure.** + Set up a two-column (or seamount) configuration with the coordinate interfaces deliberately tilted between the columns — including steep slopes and thin layers — and initialize the layer means as the **exact layer averages** of a prescribed continuous profile $\Theta(p)$, $S(p)$. Under tilt those @@ -1475,22 +1539,31 @@ Three groups of profiles are run: symmetry of the test setup, or from the scheme having become insensitive to tilt, as from the scheme being right. - | guard | breaks | expected to fire because | + | guard | breaks | expected | |---|---|---| - | (a) **tilt sensitivity** — assert the tendency and `PressureGradCentered`'s differ, and that the latter grows with tilt | nothing; this one runs on the passing configuration | a bug that zeroed the tilt response would satisfy every other check in this section perfectly. This is the guard against mistaking "no tilt terms" for "correct tilt terms" | - | (b) **coefficients shared by layer index** in place of edge layer | condition 1 | at a given pressure the two columns then use expansions about different states, so [](#dalpha) is no longer identically zero. **This is the defect that made an earlier formulation fail**, and it is the guard most worth having | - | (c) **each column evaluated at its own layer $k$** rather than at matched pressure | condition 2 | differencing at fixed layer index instead of fixed pressure; recovers something close to `PressureGradCentered` | - | (d) **anchor taken as $\Delta_e Z_1$ alone**, dropping the short integrals of [](#anchor) | condition 3 | leaves a depth-independent offset in $D_k$, so the residual is flat down the column rather than growing — distinguishable from (b) and (c) | - | (e) **cell-local expansion point** in place of [](#edge-ref) | accuracy only | should **not** break exactness under [](#dalpha), since the coefficients multiply zero. If it does fire, condition 1 is not implemented as specified | - - Guard (e) is the inverted one and is worth keeping for that reason: under the previous formulation - it broke exactness, and under this one it must not. It is the cheapest available confirmation that - the reformulation did what it was meant to do. - - Guards (b), (c) and (d) break conditions 1, 2 and 3 respectively and leave residuals with different - depth structure, so running all three localizes a failure without another round trip. Guard (a) is - the one to write first, because it is the only one that can fire on a configuration where every - other check passes. + | (a) **tilt sensitivity** — assert the tendency and `PressureGradCentered`'s differ, and that the latter grows with tilt | nothing; runs on the passing configuration | must **pass**. A bug that zeroed the tilt response would satisfy every other check here perfectly | + | (b) **cell-local expansion point** in place of [](#edge-ref) | condition 1 | fires, at $10^{-5}$. Two expansion points mean the $\bar\alpha_0$ and $\bar\alpha_p$ terms no longer cancel in [](#dalpha) (§3.5, consequence 1) | + | (c) **each column's $\Theta$, $S$ taken from its own layer $k$** rather than from the layer containing the pressure | condition 2 | **cannot be made to fire** on any configuration currently available — see the warning below | + | (d) **anchor taken as $\Delta_e Z_1$ alone**, dropping the short integrals of [](#anchor) | condition 3 | fires, but only where the two columns' surface pressures differ; flat with depth, which distinguishes it from (b) | + + Note that *which* shared coefficient set is used — selected by edge layer, by layer index, or + otherwise — is deliberately **not** a guard: §3.5 consequence 1 says exactness cannot depend on it, + and measurement confirms no effect (§6.5). A test asserting otherwise would be asserting something + false. + + Guard (a) is the one to write first, because it is the only one that can fire on a configuration + where every other check passes. + + **A warning that must not be lost, because it is the largest untested risk in the scheme.** Guard + (c) **cannot be made to fire on any configuration in the Polaris family.** The exact-set variant's + profile is a single line in pressure over the whole column, so every layer's mean-preserving + reconstruction is that same line and looking up the wrong layer costs nothing; on the curved + variant the two rules differ by less than a factor of two, which is not a usable discriminator + either. **An implementation that looks up a column's state by layer index will therefore pass + every exactness and accuracy check specified in this section.** The lookup must be pinned by + direct property tests instead — that it returns a layer other than $k$ under tilt, and one whose + interfaces actually bracket the pressure — and those tests are not optional. Whether an + answer-level guard becomes available once the layer *integral* is formed is an open question. Guards must be checked against a deliberately broken configuration, not only against a passing one. A guard that cannot fire is worse than no guard, because it looks like protection. @@ -1701,15 +1774,19 @@ $1.1\times10^{-3}$ at 256 m layers and 50 m/km, $2.7\times10^{-4}$ at 64 m, $2.0 200 m/km bathymetry step — about three decimal digits of headroom on a tilted coordinate. The gradient variants gain little only because their coordinate is flat and there is nothing to save. -**Falsified — sharing the equation-of-state expansion by layer index.** On a configuration inside the -exact set, a formulation that built each column's height integral separately and reconciled the two -missed exactness by $\approx 2\times10^{-3}$ of the centered scheme's answer, **flat across three -decades of tilt**, where the robustness property asks for round-off. A brute-force evaluation of -[](#ho-exact) by direct quadrature — sharing no code with the closed forms — missed by the same -amount, which is what identified the target rather than the algebra as the problem. The tilt -independence is the signature: the mismatch is $O(\alpha_{pp}\,\delta p\,\Delta_e p^{\text{mid}})$, -first order in tilt, as is the signal. §3.7.2's condition 1 records the diagnosis and [](#dalpha) the -repair. +**Falsified — building each column's height integral separately and reconciling the two.** On a +configuration inside the exact set, that formulation missed exactness by +$\approx 2\times10^{-3}$ of the centered scheme's answer, **flat across three decades of tilt**, +where the robustness property asks for round-off. A brute-force evaluation of [](#ho-exact) by direct +quadrature — sharing no code with the closed forms — missed by the same amount, which is what +identified the target rather than the algebra as the problem, and prompted [](#dz-dp). + +**The mechanism of that failure was never established.** Two candidate explanations were proposed +and both were later excluded by measurement: sharing the equation-of-state expansion at fixed layer +index rather than at fixed pressure (no effect at all, §6.5), and extrapolating a reconstruction +beyond its own layer (benign, §6.5). The formulation is abandoned, so the question is left open +rather than pursued. What matters for the design is the positive result in §6.5: differencing the +integrand is exact pointwise, which the failed formulation never was. Worth noting for scale: at 64 m layers and 50 m/km the two columns' layer $k$ are offset by 2.8 layer thicknesses and **do not overlap in pressure at all**. Any formulation that pairs by layer index is @@ -1744,3 +1821,60 @@ Five items, all confirmed numerically on the Polaris side and folded into §3– 3–39% (and the gradient variants by $\le 0.02\%$), so the recorded `Centered` baseline and the Omega-vs-Polaris comparison both move with it. This is a property of the test configuration, not of the scheme, but it invalidates any comparison against the earlier baseline. + +### 6.5 Measurements of the scheme as specified + +The scheme of §3.5 was implemented in the Polaris two-column harness and measured. These are the +numbers Omega should expect to reproduce, and the two places where they contradict this document. + +**Exactness (Requirement 2.3.1) — met.** On a resting profile exactly linear in pressure, across the +full tilt sweep at 256/128/64 m layers: [](#dalpha) is zero at every quadrature point to +$5.3\times10^{-21}$ m³ kg⁻¹, about $10^{-17}$ of specific volume; $D_k$ is zero at every edge +interface to $1.4\times10^{-15}$ m; and the assembled tendency is $2\times10^{-18}$ m s⁻². +`PressureGradCentered` on the same states ranges from $6.8\times10^{-10}$ to $2.6\times10^{-5}$ +m s⁻². On a profile *outside* the exact set the same pointwise quantity is $2.9\times10^{-8}$, eleven +orders larger, so the check is not returning zero unconditionally. + +Report **absolute** tendencies. At the smallest tilts the residual sits at $2\times10^{-14}$ rather +than $2\times10^{-18}$ m s⁻², not because the scheme is worse but because the floor is round-off of +the $\sim\!7\times10^{3}$ m hydrostatic scale. + +**Accuracy off the exact set — the gain is real but modest, and narrows.** On a smooth curved resting +profile the scheme converges at 1.55–2.02, the $O(\tilde h^2)$ §3.7.3 predicts — but +`PressureGradCentered` converges at 1.88–2.93 from a larger starting value, so the advantage falls +from 6.5× at 256 m to 2.4× at 64 m. On a stepped bathymetry it is ~400×. This is what prompted the +restatement of Requirement 2.3.4, and expectations for Omega should be set from these numbers rather +than from the exact-set ones. + +**The anchor (§3.5.1).** Exactly zero where the two columns share a surface pressure, which is why +§5.2 puts the exactness gate there. On the one Polaris configuration where they do not, whose sea +surface is initialized from a reference-density balance, it is $6.1\times10^{-4}$ m — the residual of +two 3.57 m terms, of relative size $(\alpha - 1/\rho_0)/\alpha$. That is a gradient the state genuinely +carries, not a defect: measured against a quasi-analytic reference there, the scheme gives an RMS +error of $3.9\times10^{-10}$ against `PressureGradCentered`'s $8.1\times10^{-10}$. + +Note for anyone tempted to remove that residual by initializing against the in-situ density instead. +It would shrink but not vanish, because [](#anchor) integrates $\hat\alpha^{(e)}$ rather than the true +$\alpha$, so exact cancellation would require the sea surface to be consistent with the scheme's own +linearized profile. Estimated at the equation-of-state linearization level, some two orders below the +$6.1\times10^{-4}$ m above — derived, not measured. + +**Assumption A5 — benign, as §3.7.6 predicted.** Clamping to the outermost valid layer and +extrapolating its reconstruction leaves exactness unaffected, including where the two columns reach +different `maxLevelCell` and where the deepest edge layer extends 65% of its thickness below the +shallower floor. + +**Two claims of this document that measurement contradicted.** + +1. **Selecting the shared coefficient set by layer index rather than by pressure has no effect**: + $5.10\times10^{-21}$ against $5.33\times10^{-21}$. §3.5 consequence 1 explains why — whatever the + set is, it multiplies a contrast that is zero — and §3.7.2 has been corrected accordingly. What + *is* load-bearing is that one set multiply **both** columns: giving each its own breaks exactness + at $10^{-5}$. +2. **`PressureGradCentered` is not first order in layer thickness on these profiles.** On a resting + profile linear in pressure its error falls 3.9× and then 9.8× under successive halvings, checked + at a tilt where both columns have identical valid-layer counts so that masking is excluded. §3.7.3 + and Requirement 2.3.4 have been corrected. + +**Regression status.** `HPGAFiniteVolume` is written alongside the existing `HPGA`, and `HPGA` is +bit-identical to the previous reference run, so adding the scheme moves nothing already measured. From d71926bea833b1b7c0f3dacb13203edd9676d1e7 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 04:44:07 -0500 Subject: [PATCH 13/22] Settle the design's open items against the implementation The scheme has been implemented and measured in Omega. Four things the design left open or predicted are now fixed, and the text is updated to describe the design as it stands rather than as it was proposed. The column scan anchors at the sea floor. Conditioning favoured it already, but exactness decides it: VertCoord accumulates a midpoint rule over each column's own layers, so on an unresolved profile two columns with different layer partitions give sea-surface heights differing at second order in layer thickness. Anchored at the surface that disagreement enters the anchor directly and the machine-precision property is lost; anchored at the sea floor it never enters. The earlier claim that the two ends agree to round-off held only inside the exact set, where the two columns' sums agree term by term. Assumption A5's rule is stated: clamp to the outermost valid layer of the column and extrapolate that layer's reconstruction. Single precision is measured rather than predicted. The exactness gate returns the same result as double precision scaled by epsilon, while PressureGradCentered is essentially unmoved, since its error is truncation rather than round-off. The functor signature is corrected. It takes the column scan's two output arrays, not the temperature, salinity and derivative arrays: both integrals are formed in the scan over one set of quadrature points, as section 3.5.1 requires, so evaluating the integrand again in the functor would double the cost of the most expensive part of the scheme. The scan's arrays are described with their real extents, and the Eos evaluation counter the cost check needs is recorded. The cost check is sharpened to what the design delivers: zero equation-of-state evaluations in the pressure gradient, the one per cell per layer the requirement allows being paid by AuxiliaryState. Section 5.2 records what each guard did, including that guard (c) is confirmed unable to fire, and states that the guards run against a switchable assembly sharing the kernel's helper functions -- so they establish that the three rules are load-bearing without independently verifying the arithmetic. Section 6.1.1 collects the Omega-side measurements. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 153 +++++++++++++----- 1 file changed, 110 insertions(+), 43 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index e42c2efabaed..627dbeb8fdee 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -865,12 +865,22 @@ $p^{\text{bot}}_{e,k} = \bar q_{k+1}$, and are worth using in the implementation Both follow from `PressureMid` being the exact arithmetic midpoint, and both were confirmed numerically. -**Which end of the column to anchor at is left to implementation time.** `VertCoord` builds $z$ -upward from the bathymetry while pressure is built downward from the surface, so the two accumulate -round-off from opposite ends, and [](#ssh-difference) favours the sea floor on conditioning grounds: -$-\Delta_e H$ is exact input where $\Delta_e Z_{\text{surf}}$ is the small residual of two -column-length sums. Either is correct; measured in double precision the two directions agree to -round-off. This is a round-off question, not a consistency one. +**The scan anchors at the sea floor.** `VertCoord` builds $z$ upward from the bathymetry while +pressure is built downward from the surface, so the two accumulate round-off from opposite ends, and +[](#ssh-difference) favours the sea floor on conditioning grounds: $-\Delta_e H$ is exact input +where $\Delta_e Z_{\text{surf}}$ is the small residual of two column-length sums. + +**Conditioning is not the deciding argument, though — exactness is.** `VertCoord` accumulates +$\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ over each column's *own* layers. On a profile +the reconstruction does not resolve, two columns with different layer partitions give sums that +differ at $O(\tilde h^2)$, so their derived sea-surface heights differ by that much even when the +two columns hold the same water. Anchored at the surface that discrepancy enters $D_1$ directly and +the machine-precision property of §2.3.1 is lost; anchored at the sea floor over a flat floor +$\Delta_e Z$ is exact input and vanishes identically, and the discrepancy never enters at all — +because the scheme integrates its own reconstruction rather than accumulating `VertCoord`'s height +(the first paragraph of this section). The two ends are therefore *not* equivalent, and the earlier +statement that they agree to round-off held only for profiles inside the exact set, where both +columns' sums agree term by term. One consequence is worth recording for whoever builds the reference implementation. A test harness that anchors its geometric column at a *prescribed* sea surface and derives the bathymetry is @@ -901,9 +911,13 @@ Three consequences. separately accumulated column integrals. Measured, restructuring the accumulation this way recovered about three decimal digits of headroom on a tilted coordinate — the largest increment being $\sim 10^{-3}$ of the height difference it replaces (§6.3). -- **A single-precision build is expected to pass §5.2.** - That is a prediction to be measured (§5.2 is run in both precisions), not an assumption, and it - should be measured alongside `PressureGradCentered` so the comparison is interpretable. +- **A single-precision build passes §5.2.** Measured in Omega: the exactness gate returns + $3.0\times10^{-9}$ m s$^{-2}$ in single precision against $3.1\times10^{-18}$ in double, which is + $0.09\,\epsilon$ of the cancelling terms in one build and $0.05\,\epsilon$ in the other — the + same result, scaled by the precision. `PressureGradCentered` on the same state is + $3.4\times10^{-5}$ m s$^{-2}$ in single and $3.5\times10^{-5}$ in double, essentially unmoved, + because its error is truncation rather than round-off. The scheme forms no large quantities, and + the reduced precision costs it nothing beyond $\epsilon$ itself. - **The perturbation form is not needed and is not specified.** It would have subtracted a local reference profile from $\hat\alpha$ before integrating and added its contribution back analytically. It addressed a problem that differencing first removes algebraically. If a @@ -951,8 +965,12 @@ assumptions this design is making that only testing can confirm: the exact set an extrapolated reconstruction still reproduces the true profile, so $\Delta_e\Theta(p)$ is still zero and exactness survives. What extrapolation costs is accuracy off the exact set, and how much is unmeasured: the derivation harness ran with equal layer counts in both columns. §5.1's - `bathymetry_step` and `surface_pressure_gradient` variants are where it is measured, and the rule - used must be stated explicitly rather than left to fall out of the implementation. + `bathymetry_step` and `surface_pressure_gradient` variants are where it is measured. + + **The rule is to clamp to the outermost valid layer of the column and extrapolate that layer's + reconstruction.** A pressure above a column's shallowest valid layer uses that layer; a pressure + below its deepest valid layer uses that one. This is stated here rather than left to fall out of + the implementation, and it is the rule the per-column pressure lookup applies at both ends. ### 3.8 Scope: the reduction and the vertical coordinate @@ -1152,6 +1170,13 @@ Because `computeSpecVolAndDerivs` fills `SpecVol` as well, it replaces rather th a call to `computeSpecVol`; the two are kept separate so that the derivative arithmetic is paid only where it is needed. +`Eos` also carries a count of specific-volume evaluations, incremented by one per cell per +active layer in each of `computeSpecVol`, `computeSpecVolDisp` and `computeSpecVolAndDerivs`, +together with a method to reset it. This is the instrumentation §5.6 needs: Requirement 2.2 bounds +a call count, and nothing else in the test suite would notice it being exceeded, since an extra +evaluation changes run time without changing any answer. Maintaining it costs one host addition +per call. + The TEOS-10 derivatives are obtained by differentiating the 75-term polynomial analytically. The pressure derivative reuses the coefficients `calcPCoeffs` already assembles for $\alpha$ itself and so is free; the $\Theta$ and $S_A$ derivatives need their own coefficient @@ -1163,22 +1188,17 @@ options supply trivial analytic derivatives. #### 4.1.3 `PressureGradFiniteVolume` functor The functor mirrors `PressureGradCentered` (cached mesh/coordinate arrays, `Enabled` flag, -`chunkStart`/`chunkLength` vertical iteration) but takes the additional reconstruction and -EOS-derivative inputs. Its `operator()` signature is widened from the placeholder to: +`chunkStart`/`chunkLength` vertical iteration). Almost all of the work of forming the fixed-pressure +comparison happens before it runs, in the column scan below, so what it takes is that scan's two +output arrays rather than the state the scan consumed: ```c++ KOKKOS_FUNCTION void operator()(const Array2DReal &Tend, I4 IEdge, I4 KChunk, - const Array2DReal &PressureMid, const Array2DReal &PressureInterface, - const Array2DReal &GeomZInterface, + const Array2DReal &DeltaZFixedP, + const Array2DReal &DeltaZMoment, const Array1DReal &TidalPotential, - const Array1DReal &SelfAttractionLoading, - const Array2DReal &SpecVol, - const Array2DReal &ConservTemp, // new - const Array2DReal &AbsSalinity, // new - const Array2DReal &SpecVolDCt, // new - const Array2DReal &SpecVolDSa, // new - const Array2DReal &SpecVolDP) // new + const Array1DReal &SelfAttractionLoading) const; ``` @@ -1197,16 +1217,31 @@ Three aspects of the loop structure differ from the obvious implementation: evaluations on a hexagonal mesh. - **The column scan of §3.10 step 4 cannot live in this functor.** [](#d-recurrence) is a prefix sum down each column with edge-dependent coefficients, so it is not expressible as an independent - per-vertical-chunk operation. It is computed in a separate kernel filling one per-edge array, + per-vertical-chunk operation. It is computed in a separate kernel filling per-edge arrays, ```c++ - Array2DReal DeltaZFixedP; ///< (NEdgesAll, NVertLayers) — D_k, eq. (d-recurrence) + Array2DReal DeltaZFixedP; ///< (NEdgesSize, NVertLayersP1) — D_k at edge interfaces + Array2DReal DeltaZMoment; ///< (NEdgesSize, NVertLayers) — first moment over the layer ``` with a `parallelForOuter` over edges and a `parallelScanInner` down the column, in the same shape as - `VertCoord::computeGeomZHeight`. The functor then reads it chunk-wise like any other input. The cost - is one edge-sized 2-D array and one column scan per edge per step, and it is the one structural - addition Phase 1 makes beyond the per-edge, per-chunk pattern the centered scheme uses. + `VertCoord::computeGeomZHeight`. The functor then reads them chunk-wise like any other input. + + $D_k$ is held at interfaces, so its extent is `NVertLayersP1`. The second array holds the first + moment $\int (p - \bar q_k)\,\Delta_e\hat\alpha\,dp$ over each layer, which is what the layer + mean of [](#ho-exact) needs alongside $D_k$; forming it in the same pass over the same quadrature + points is what §3.5.1 requires, and it is why the functor reads neither $\Theta$, $S$ nor the + equation-of-state derivatives. Evaluating the integrand a second time in the functor to recover the + moment would double the cost of the most expensive part of the scheme. + + The layer mean is then + $D_{k+1} + \frac{1}{\Delta p_{e,k}}\int (p - \bar q_k)\,\Delta_e\hat\alpha\,dp$, taken from + the layer's *lower* interface because that is the end nearer the anchor. + + The cost is two edge-sized 2-D arrays, two cell-sized arrays for the reconstruction slopes, and one + column scan per edge per step. This is the one structural addition Phase 1 makes beyond the + per-edge, per-chunk pattern the centered scheme uses. The arrays are allocated only when + `FiniteVolume` is selected, so a `Centered` run pays nothing for them. - **Each column's $\Theta$, $S$ are looked up by pressure, not by layer index.** At each quadrature point of edge layer $k$, [](#dalpha) needs the reconstruction of whichever of *that column's* layers contains the point, which under tilt is generally not layer $k$ (§3.7.2, condition 1). Within the @@ -1310,12 +1345,11 @@ accumulate `VertCoord`'s geometric height at all, using the sea-surface height o All three conditions of §3.7.2 are properties of the PGF's own discretization; none is a dependency on another module. -**Open at implementation time.** Two items, neither of them blocking. Which end of the column the -scan anchors at (§3.7.4) — where the sea floor is preferred on conditioning grounds and the -measurement supporting the alternative may not be discriminating. And the -treatment at the top and bottom of the column, assumption A5 of §3.7.6, has to be defined explicitly -rather than inherited — it is the one part of the formulation the reference derivation did not cover, -since it ran with equal layer counts in both columns. +**Settled at implementation time.** Two items were left open here and are now fixed. The scan +anchors at the **sea floor** (§3.7.4), which conditioning favours and which exactness requires: +anchoring at the surface admits the $O(\tilde h^2)$ disagreement between the two columns' derived +sea-surface heights into $D_1$. And the treatment at the top and bottom of the column, assumption A5 +of §3.7.6, is to **clamp to the outermost valid layer and extrapolate its reconstruction**. **Code and cost.** Three new `Eos` derivative fields and one new method (§4.1.2); the `PressureGradFiniteVolume` functor; one per-edge array and one column scan (§3.5.1, §4.1.3); no new @@ -1542,9 +1576,9 @@ Three groups of profiles are run: | guard | breaks | expected | |---|---|---| | (a) **tilt sensitivity** — assert the tendency and `PressureGradCentered`'s differ, and that the latter grows with tilt | nothing; runs on the passing configuration | must **pass**. A bug that zeroed the tilt response would satisfy every other check here perfectly | - | (b) **cell-local expansion point** in place of [](#edge-ref) | condition 1 | fires, at $10^{-5}$. Two expansion points mean the $\bar\alpha_0$ and $\bar\alpha_p$ terms no longer cancel in [](#dalpha) (§3.5, consequence 1) | - | (c) **each column's $\Theta$, $S$ taken from its own layer $k$** rather than from the layer containing the pressure | condition 2 | **cannot be made to fire** on any configuration currently available — see the warning below | - | (d) **anchor taken as $\Delta_e Z_1$ alone**, dropping the short integrals of [](#anchor) | condition 3 | fires, but only where the two columns' surface pressures differ; flat with depth, which distinguishes it from (b) | + | (b) **cell-local expansion point** in place of [](#edge-ref) | condition 1 | fires. Measured in Omega at $3.4\times10^{-7}$ m s$^{-2}$ against $3.1\times10^{-18}$ with the shared point. Two expansion points mean the $\bar\alpha_0$ and $\bar\alpha_p$ terms no longer cancel in [](#dalpha) (§3.5, consequence 1) | + | (c) **each column's $\Theta$, $S$ taken from its own layer $k$** rather than from the layer containing the pressure | condition 2 | **cannot be made to fire** — confirmed in Omega, which returns $3.4\times10^{-18}$ against $3.1\times10^{-18}$, indistinguishable. See the warning below | + | (d) **anchor taken as the raw $\Delta_e Z$ alone**, dropping the short integrals of [](#anchor) | condition 3 | fires, but only where the two columns' end pressures differ; flat with depth, which distinguishes it from (b). Measured in Omega at $4.8\times10^{-3}$ m s$^{-2}$, with the offset in $D_k$ constant to sixteen digits down the column | Note that *which* shared coefficient set is used — selected by edge layer, by layer index, or otherwise — is deliberately **not** a guard: §3.5 consequence 1 says exactness cannot depend on it, @@ -1568,6 +1602,16 @@ Three groups of profiles are run: Guards must be checked against a deliberately broken configuration, not only against a passing one. A guard that cannot fire is worse than no guard, because it looks like protection. + Guards (b), (c) and (d) need the scheme's rules switched off one at a time, which the shipped + kernel cannot do. They therefore run against an assembly built in the test out of the same helper + functions, with each rule selectable. That assembly is only trustworthy once it reproduces the + kernel, and the fidelity check that has content is on a **curved** profile where both sides are + large: agreeing at $10^{-18}$ on the exact set would also be satisfied by an assembly that + computed nothing. Note what this does and does not establish — the guards show the three rules are + load-bearing; they do not independently verify the arithmetic, since they share the helper + functions with the kernel. That verification comes from §5.5 and from the Omega-versus-Polaris + comparison of §5.1. + A separate and much smaller unit test covers the reconstruction estimator on its own (§3.4): given layer means sampled from a profile of the reconstruction's own degree on a **deliberately non-uniform** set of layer thicknesses, the recovered slope (Phase 1) or slope and curvature @@ -1655,11 +1699,16 @@ Requirement 2.2 bounds the number of TEOS-10 evaluations, and nothing above test could satisfy every accuracy gate while quietly calling the equation of state inside the column loop. Two cheap checks close that: -- **Evaluation count.** With an instrumented `Eos`, confirm the number of specific-volume - evaluations per time step is one per cell per layer and is **unchanged** when `HorzOrder`, - `VerticalReconstruction` and `QuadraturePoints` are varied. The last is the one that matters most - here, since the quadrature loop is where an equation-of-state call would most naturally creep in. This is the property Requirement 2.2 actually states, and it is - a counter comparison, not a timing measurement, so it is deterministic and suitable for CI. +- **Evaluation count.** With an instrumented `Eos` (§4.1.2), confirm the number of specific-volume + evaluations the pressure gradient performs is **zero**, at every setting of `QuadraturePoints` — + the quadrature loop being where an equation-of-state call would most naturally creep in. Zero is + sharper than Requirement 2.2 asks for and is what the design actually delivers: the one evaluation + per cell per layer the requirement allows is paid once by `AuxiliaryState`, before the tendency is + formed, and the scheme works from the specific volume and derivatives that call leaves behind. + Because a count of zero would also be produced by broken instrumentation, confirm alongside it + that one call to `computeSpecVolAndDerivs` registers exactly one evaluation per cell per layer. + This is a counter comparison, not a timing measurement, so it is deterministic and suitable for CI. + Measured in Omega: zero at `QuadraturePoints` 1, 2, 3 and 4. - **Wall time.** Record PGF kernel time relative to `PressureGradCentered` on a representative configuration, as a performance regression guard. The expected cost is dominated by the per-edge column scan (§4.1.3), roughly three times as many column evaluations as a cell-based formulation on @@ -1726,14 +1775,32 @@ Three limits on what this establishes, all of them live. - **Differing `maxLevelCell` is untested.** The harness gave both columns the same layer count, so the `bathymetry_step` case — where a bottom partial cell carries the whole signal — is not covered. This is assumption A5 of §3.7.6. -- **Nothing has been run in Omega**, or through the real Polaris task machinery, so the interaction - with p-star initialization and partial cells is untested. +- **The Polaris task machinery is untested against the new scheme.** The Omega implementation is now + measured (below), but the `horiz_press_grad` variants still select `Centered`, so the interaction + with p-star initialization and partial cells, and the `omega_vs_polaris` comparison for + `FiniteVolume`, are outstanding. - **The rows above were measured on an assembly of all four pressure terms**, not on the form §3.5 specifies. Given that those terms cancel to $3\times10^{-15}$ relative, what the exactness and $O(\tilde h^2)$ rows measured *was* the geopotential term alone, so they carry over — but by that argument rather than by direct measurement. §6.3 records what happened when it was measured directly. +#### 6.1.1 Confirmation in Omega + +The implementation was measured independently of the harness above, on a two-column state whose layer +means are the exact layer averages of one prescribed continuous profile, at 4 km spacing with 32 +layers and interfaces offset by up to three layer thicknesses. + +| claim | §ref | measurement | +|---|---|---| +| exactness on the exact set | §2.3.1, §3.7.3 | $3.1\times10^{-18}$ m s$^{-2}$, against `PressureGradCentered`'s $3.5\times10^{-5}$ on the same state — a ratio of $8.8\times10^{-14}$, and $0.05\,\epsilon$ of the terms that had to cancel | +| $D_k$ zero at every interface, not only in the layer mean | §3.5.1 | $1.4\times10^{-15}$ m, $0.06\,\epsilon$; larger in the upper column than the lower, i.e. growing away from the sea-floor anchor, which is the signature of an exact anchor plus an accumulating recurrence | +| the integrand is zero *pointwise* | §3.5, §3.7.2 | $5.8\times10^{-21}$ m$^3$ kg$^{-1}$ at every quadrature point on a profile linear in pressure, against $5.3\times10^{-10}$ on a quadratic one — the Polaris harness measured $5.3\times10^{-21}$ on the same check | +| $O(\tilde h^2)$ off the exact set | §3.7.3 | rates above 2 on quadratic and cubic profiles over 15, 30 and 60 layers at fixed tilt. The rates *rise* under refinement rather than settling, so the sweep is not yet in the asymptotic regime and the gate is a lower bound | +| the centered identity | §3.9, §5.5 | $0.49\,\epsilon$ of the hydrostatic scale over eight tilts, reproducing the harness' $0.5\,\epsilon$ through independently written code. The dropped-pressure-term guard is exactly linear in tilt, to six significant figures — §3.7.3's first-order-in-tilt statement falling out of a check written for another purpose | +| bounded equation-of-state cost | §2.2, §5.6 | zero evaluations in the pressure gradient at every quadrature setting | +| single precision | §3.7.5 | the exactness gate passes; see §3.7.5 for the numbers | + ### 6.2 Corrections owed to `OmegaV1GoverningEqns.md` [](#ho-target) is inherited from {ref}`omega-design-governing-eqns-omega1`, which is not maintained From 334ff7824fa07a64940d538967b4ff5b7cbcda1b Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 08:49:33 -0500 Subject: [PATCH 14/22] Correct what the exact layer increment claims Equation (z-increment-exact) states that VertCoord's midpoint rule is the exact layer integral. That is true of the linearized specific volume the pressure gradient uses, and the derivation given -- the mean-preserving deviations and the pressure term both integrating to zero over the layer -- establishes exactly that. It is not true of what VertCoord actually accumulates, which is the exact TEOS-10 specific volume evaluated at the layer-mean state. Specific volume is nonlinear in pressure, so its layer average is not its value at the midpoint state, and the increment is a second-order-accurate approximation rather than an exact integral. Measured on the Polaris side, the gap accumulates to 1.1e-3 m over a column. The conclusion the section draws is unchanged: VertCoord needs no change and no answer-changing baseline step. But the reason is not that its rule is exact. It is that the scheme never accumulates VertCoord's height, using it once as the difference the anchor takes at the sea floor, where over a flat floor with matching maxLevelCell it is exact prescribed input. Where the two columns' floors differ the anchor spans a partial accumulation and the gap enters at the level of the difference between the columns' partial sums, which is what bathymetry_step measures. This also corrects the mechanism given for preferring the sea-floor anchor. That was attributed to profiles the reconstruction does not resolve; the disagreement in fact comes from the equation of state's curvature in pressure, so it is present even on the exact set, where two columns with different layer partitions still accumulate different amounts of midpoint-rule error. The claim that the two anchor ends agree to round-off therefore fails on the exact set as well, not only off it. Reported from the Polaris side. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 627dbeb8fdee..3aab08ed8e1b 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -836,7 +836,8 @@ Two questions that would otherwise arise therefore do not. **The quadrature question.** `VertCoord::computeGeomZHeight` accumulates $\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ — -apparently a midpoint rule. For a Phase 1 reconstruction it is the exact layer integral: +apparently a midpoint rule. For the **linearized** $\hat\alpha$ of §3.3 it is the exact layer +integral: $$ \frac{1}{g}\int_{p^{\text{top}}_{i,k}}^{p^{\text{bot}}_{i,k}} \hat\alpha_{i,k}(p)\,dp @@ -845,9 +846,23 @@ $$ (z-increment-exact) because $\int \Theta'\,dp = \int S'\,dp = 0$ by the mean-preserving constraint and $\int (p - p^{\text{mid}})\,dp = 0$ because `PressureMid` is the exact arithmetic midpoint of the two -interface pressures. This remains true and remains useful — it is why no change to `VertCoord` and no -answer-changing baseline step is required — but the scheme no longer depends on it, since it no -longer accumulates `VertCoord`'s $z$. +interface pressures. + +**That is a statement about $\hat\alpha$, not about $\alpha$, and the distinction matters.** +`VertCoord` does not accumulate $\hat\alpha$. It uses the exact TEOS-10 $\alpha$ evaluated at the +layer-mean state $(\Theta_{i,k}, S_{i,k}, p^{\text{mid}}_{i,k})$, and $\alpha$ is nonlinear in +pressure, so its layer average is not its value at the midpoint state. `VertCoord`'s increment is +therefore a second-order-accurate approximation of the true layer integral, not an exact one. +Measured, the gap accumulates to $1.1\times10^{-3}$ m over a column. + +**No change to `VertCoord` and no answer-changing baseline step is required** — but not because +[](#z-increment-exact) makes its rule exact, which it does not. It is because the scheme does not +accumulate `VertCoord`'s $z$ at all. It uses it once, as the difference [](#anchor) takes at the sea +floor, where over a flat floor with matching `maxLevelCell` that difference is $-\Delta_e H$, exact +prescribed input, and no accumulation enters it. Where the two columns' floors differ the anchor +does span a partial accumulation over the layers between them, and the gap enters at the level of +the difference between the two columns' partial sums; §5.1's `bathymetry_step` is where that is +measured. **The sharing question.** Whether a cell-based $z$ can carry an edge-dependent $\hat\alpha$ would matter to a formulation that differenced two separately accumulated column integrals. It does not @@ -871,16 +886,18 @@ pressure is built downward from the surface, so the two accumulate round-off fro where $\Delta_e Z_{\text{surf}}$ is the small residual of two column-length sums. **Conditioning is not the deciding argument, though — exactness is.** `VertCoord` accumulates -$\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ over each column's *own* layers. On a profile -the reconstruction does not resolve, two columns with different layer partitions give sums that -differ at $O(\tilde h^2)$, so their derived sea-surface heights differ by that much even when the -two columns hold the same water. Anchored at the surface that discrepancy enters $D_1$ directly and +$\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ over each column's *own* layers, and that +increment is not the exact layer integral of the true $\alpha$ (previous subsection). The error +comes from the equation of state's curvature in pressure rather than from anything about the +profile, so it is present **even on the exact set**, and two columns with different layer partitions +accumulate different amounts of it. Their derived sea-surface heights therefore differ even when the +two columns hold identical water. Anchored at the surface that difference enters $D_1$ directly and the machine-precision property of §2.3.1 is lost; anchored at the sea floor over a flat floor -$\Delta_e Z$ is exact input and vanishes identically, and the discrepancy never enters at all — -because the scheme integrates its own reconstruction rather than accumulating `VertCoord`'s height -(the first paragraph of this section). The two ends are therefore *not* equivalent, and the earlier -statement that they agree to round-off held only for profiles inside the exact set, where both -columns' sums agree term by term. +$\Delta_e Z$ is exact input and vanishes identically, and none of it enters — because the scheme +integrates its own reconstruction rather than accumulating `VertCoord`'s height. The two ends are +therefore *not* equivalent, and the earlier claim that they agree to round-off does not hold, not +even on the exact set: the two columns' midpoint-rule errors differ there too, because their layer +partitions do. One consequence is worth recording for whoever builds the reference implementation. A test harness that anchors its geometric column at a *prescribed* sea surface and derives the bathymetry is @@ -1347,8 +1364,8 @@ on another module. **Settled at implementation time.** Two items were left open here and are now fixed. The scan anchors at the **sea floor** (§3.7.4), which conditioning favours and which exactness requires: -anchoring at the surface admits the $O(\tilde h^2)$ disagreement between the two columns' derived -sea-surface heights into $D_1$. And the treatment at the top and bottom of the column, assumption A5 +anchoring at the surface admits into $D_1$ the disagreement between the two columns' derived +sea-surface heights, which `VertCoord`'s midpoint rule produces even on the exact set. And the treatment at the top and bottom of the column, assumption A5 of §3.7.6, is to **clamp to the outermost valid layer and extrapolate its reconstruction**. **Code and cost.** Three new `Eos` derivative fields and one new method (§4.1.2); the From fe52f3e3c8d1c52fb6258134e2e4ee61dd4d882e Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 09:24:05 -0500 Subject: [PATCH 15/22] Record what the sea-floor anchor costs where bathymetry steps Section 3.7.5 claimed no large quantity is formed anywhere in the scheme. That is true of the recurrence, every increment of which is a horizontal contrast, and false of the anchor. Where the bathymetry steps, the height difference at the deepest shared interface is of order the step and the anchor's two short integrals span that step and cancel it. Measured on a stepped floor with a profile linear in pressure: 4.0 m cancelled to 1.9e-12 at a floor gradient of 1 m/km, 100 m to 2.6e-8 at 25 m/km, and 205.6 m to 1.7e-7 at 200 m/km -- nine to twelve digits consumed. On the same states the surface anchor forms nothing at all, its height difference being zero and its correction a zero-width integral. The two ends therefore fail in complementary ways, and the choice is a trade-off rather than a settled preference. The sea floor is exact where the coordinate tilts over an unstepped floor, which is the case Requirement 2.3.1 was written for, and the surface is not; the surface forms nothing where the floor steps, and the sea floor does not. Neither gives machine precision at every tilt, thickness and bathymetry, so that requirement is met on an unstepped floor rather than unconditionally. Section 3.7.4 now states this as the open question Phase 1 leaves behind. The stepped-floor residual is not quadrature error: refining from 2 to 16 Gauss points does not move it, which is conclusive rather than suggestive since the reconstruction is linear in pressure and every rule integrates it exactly. What remains is the edge-shared first-order equation-of-state expansion integrated across the whole step, some 2e6 Pa at 200 m/km. That attribution is a scaling argument rather than a measurement; if it holds, the second-order expansion would reduce it, as would re-expanding about the midpoint of each short integral, and neither has been tried. Two things this does not disturb, both measured: the scan stays flat to 1.4e-15 m at every floor gradient, including where a column's reconstruction is evaluated three layers below its own floor, confirming assumption A5 on the geometry it was most doubted on; and the scheme still beats the centered one by a factor of 2e5 on these states. Reported from the Polaris side. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 77 +++++++++++++++---- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 3aab08ed8e1b..0aaf5cbc94df 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -639,8 +639,17 @@ differs. §3.7.4 records what is and is not established about the choice. $10^{-1}$ m for a realistic baroclinic column and zero for a resting one, against the $10^{2}$ m height *differences at fixed layer index* that a scheme comparing at fixed index has to form and cancel. The increments in [](#d-recurrence) are smaller still, being integrals of a horizontal -contrast. There is no cancellation of large quantities anywhere in the scheme, which is what §3.7.5 -is about. +contrast. + +**The anchor is the exception, and only at the sea floor.** Where the bathymetry steps, +$\Delta_e Z$ at the deepest shared interface is of order the step, and the two short integrals of +[](#anchor) span that step and cancel it. Measured on a two-column state with a stepped floor and a +profile linear in pressure: at a floor gradient of 1 m/km the anchor forms and cancels $4.0$ m to +leave $1.9\times10^{-12}$ m; at 25 m/km, $100$ m to leave $2.6\times10^{-8}$; at 200 m/km, +$205.6$ m to leave $1.7\times10^{-7}$ — nine to twelve decimal digits consumed. Anchored at the +surface the same states form nothing at all: $\Delta_e Z$ there is zero and, both columns sharing a +surface pressure, the correction is a zero-width integral. §3.7.4 records what this does to the +choice of end. **`VertCoord`'s geometric height is used once**, for $\Delta_e Z_1$ in [](#anchor) — the free-surface height difference. It is not accumulated and not re-derived, so Requirement 2.4 is met by the PGF @@ -880,7 +889,33 @@ $p^{\text{bot}}_{e,k} = \bar q_{k+1}$, and are worth using in the implementation Both follow from `PressureMid` being the exact arithmetic midpoint, and both were confirmed numerically. -**The scan anchors at the sea floor.** `VertCoord` builds $z$ upward from the bathymetry while +**The scan anchors at the sea floor, and the two ends fail in complementary ways.** The choice is a +trade-off rather than a settled preference, and neither end is uniformly better: + +| | sea-floor anchor | surface anchor | +|---|---|---| +| coordinate tilts, flat floor | exact; $\Delta_e Z = -\Delta_e H$ is exact input | fails; the two columns' derived sea-surface heights differ by $7.1\times10^{-8}$ m, matching the difference of their midpoint-rule truncations to all figures measured | +| bathymetry steps | forms and cancels quantities of order the step; $1.7\times10^{-7}$ m residual at 200 m/km, nine digits consumed | forms nothing; $\Delta_e Z$ at the surface is zero and the correction is a zero-width integral | + +**Requirement 2.3.1 asks for machine precision at any tilt, thickness *and* bathymetry, and neither +end delivers all three.** The sea floor is chosen because it is exact on the case the requirement was +written for — a resting ocean on an unstepped floor at arbitrary coordinate tilt — and because its +stepped-floor residual is comparable to the surface anchor's unconditional one rather than worse. +That is a judgement, and it should be revisited if stepped bathymetry turns out to be the case that +matters; §5.1's `bathymetry_step` variants are where it is measured. + +The stepped-floor residual is **not** quadrature error: refining from 2 to 16 Gauss points does not +move it at all, which is conclusive rather than suggestive, since $\hat\alpha$ is linear in pressure +and every rule integrates it exactly. What remains is the edge-shared first-order equation-of-state +expansion being integrated across the whole step — some $2\times10^{6}$ Pa at 200 m/km, far outside +the range the expansion is accurate over. That attribution is a scaling argument rather than a +measurement. If it is right, the second-order expansion of §3.3 would reduce it, and re-expanding +about the midpoint of each short integral rather than about the edge-layer state would too; neither +has been tried. + +The argument for the sea floor on a tilted coordinate is unchanged and follows. + +**Why the sea floor wins there.** `VertCoord` builds $z$ upward from the bathymetry while pressure is built downward from the surface, so the two accumulate round-off from opposite ends, and [](#ssh-difference) favours the sea floor on conditioning grounds: $-\Delta_e H$ is exact input where $\Delta_e Z_{\text{surf}}$ is the small residual of two column-length sums. @@ -915,11 +950,19 @@ $10^{-3}$ m consumes roughly five significant digits before the physics appears, the time the tendency is formed. That is `PressureGradCentered`'s arithmetic, and it is the reason this section exists. -**[](#dz-dp) removes the exposure rather than managing it.** Every quantity in the scan is a -difference *before* it is an integral: [](#dalpha) is a horizontal contrast, [](#d-recurrence) -accumulates integrals of that contrast, and $D_k$ is the answer itself. No large quantity is formed -anywhere, so nothing large has to cancel. The scheme's conditioning is therefore set by the size of -the baroclinic signal, not by the size of the hydrostatic terms. +**[](#dz-dp) removes the exposure rather than managing it — in the scan.** Every quantity in the +scan is a difference *before* it is an integral: [](#dalpha) is a horizontal contrast, +[](#d-recurrence) accumulates integrals of that contrast, and $D_k$ is the answer itself. No large +quantity is formed there, so nothing large has to cancel, and the scan's conditioning is set by the +size of the baroclinic signal rather than by the size of the hydrostatic terms. Measured, $D_k$ +stays flat to $1.4\times10^{-15}$ m at every floor gradient tried, including where one column's +reconstruction is evaluated three layers below its own floor. + +**The anchor is not covered by that argument.** An earlier version of this section claimed no large +quantity is formed *anywhere*; that is true of [](#d-recurrence) and false of [](#anchor) at the sea +floor, where a stepped bathymetry makes $\Delta_e Z$ of order the step and the short integrals +cancel it — nine to twelve digits, per the measurements in §3.5.1. The exposure the scheme removes +is the column-length one; a step-sized cancellation at a single interface remains. Three consequences. @@ -1362,11 +1405,19 @@ accumulate `VertCoord`'s geometric height at all, using the sea-surface height o All three conditions of §3.7.2 are properties of the PGF's own discretization; none is a dependency on another module. -**Settled at implementation time.** Two items were left open here and are now fixed. The scan -anchors at the **sea floor** (§3.7.4), which conditioning favours and which exactness requires: -anchoring at the surface admits into $D_1$ the disagreement between the two columns' derived -sea-surface heights, which `VertCoord`'s midpoint rule produces even on the exact set. And the treatment at the top and bottom of the column, assumption A5 -of §3.7.6, is to **clamp to the outermost valid layer and extrapolate its reconstruction**. +**Settled at implementation time.** The scan anchors at the **sea floor** (§3.7.4): anchoring at the +surface admits into $D_1$ the disagreement between the two columns' derived sea-surface heights, +which `VertCoord`'s midpoint rule produces even on the exact set. The treatment at the top and bottom +of the column, assumption A5 of §3.7.6, is to **clamp to the outermost valid layer and extrapolate +its reconstruction**; measured, the scan stays flat to $1.4\times10^{-15}$ m even where a column's +reconstruction is evaluated three layers below its own floor, so the rule is confirmed on the +geometry it was most doubted on. + +**Reopened by measurement.** The anchor end is a trade-off, not a settled preference: at the sea +floor a stepped bathymetry makes [](#anchor) form and cancel quantities of order the step, which the +surface anchor does not (§3.7.4). Neither end gives machine precision at *every* tilt, thickness and +bathymetry, so Requirement 2.3.1 is met on an unstepped floor rather than unconditionally. This is +the open question Phase 1 leaves behind. **Code and cost.** Three new `Eos` derivative fields and one new method (§4.1.2); the `PressureGradFiniteVolume` functor; one per-edge array and one column scan (§3.5.1, §4.1.3); no new From 530040a5485065b73ba0c58a03c60a58df948691 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 09:31:47 -0500 Subject: [PATCH 16/22] Move the column scan to the sea-floor anchor and state the gate's condition Section 3.5.1 still described the scan as accumulating from the sea surface and wrote the anchor at k = 1, contradicting section 3.7.4, which settles the sea floor and gives the argument. The implementation follows 3.7.4. Rewrite 3.5.1 to match: the recurrence runs upward, the anchor sits at the deepest interface the two columns share, and its short integrals each span half the cross-edge pressure difference there. The surface form is kept as the alternative it is. Also drop the description of the anchor end as a conditioning choice, which it is not, and qualify the conditioning argument as holding where the floor is unstepped. Section 5.2's machine-precision gate needs a condition on how its state was constructed, which it did not previously state. The anchor is the one place a state can inject a residual the scheme cannot remove, so the gate must be run on a state whose anchor inputs vanish identically: at a sea-floor anchor, two columns sharing both a floor depth and a bottom pressure. A state that pins the opposite end instead carries VertCoord's second-order truncation difference into the anchor's input, and then no scheme however exact returns zero -- measured on Polaris-initialized states, whose columns share a floor depth but reach different bottom pressures under tilt, the sea-floor anchor is -7.1e-8 m where the surface anchor is zero to round-off. That residual is the anchor and nothing else, since every increment of the recurrence is still zero and the height difference is still flat down the column, so it leaves the pointwise cancellation untouched. Omega's gate satisfies the condition by construction: it prescribes the pressure grid, so both columns share a surface and a bottom pressure, and prescribes an equal bottom depth from which VertCoord derives height upward. Both anchor inputs are identically zero, which is why its 3.1e-18 m/s2 is a property of the scan alone; the same scheme run on a Polaris-initialized state should return that state's anchor residual instead, and that is the correct answer there. Reported from the Polaris side. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 59 ++++++++++++++----- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 0aaf5cbc94df..2aec38ce12ea 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -588,8 +588,10 @@ horizontal contrast in reconstructed $\Theta$ and $S$ *at matched pressure*, and #### 3.5.1 The column scan -$\Delta_e z$ is accumulated down each edge's column from the sea surface. Let $\bar q_k$ be the -edge-layer interface pressures and $D_k \equiv \Delta_e z(\bar q_k)$. Then +$\Delta_e z$ is accumulated along each edge's column from an anchor at one end. §3.7.4 settles which +end, and it is the **sea floor**: the recurrence below therefore runs upward, from $k = K+1$ to +$k = 1$. Let $\bar q_k$ be the edge-layer interface pressures and $D_k \equiv \Delta_e z(\bar q_k)$. +Then $$ D_{k+1} \;=\; D_k \;-\; \frac{1}{g}\int_{\bar q_k}^{\bar q_{k+1}} \Delta_e\hat\alpha(p)\; dp, @@ -599,17 +601,20 @@ and the layer mean [](#ho-exact) needs is obtained from $D_k$ and a second momen integrand over the same interval. Both integrals use the same quadrature points, and at each point each column's $\Theta$, $S$ come from the layer of that column containing the point. -**The anchor.** $D_1 = \Delta_e z(\bar q_1)$ at the sea surface, where the two columns are at -different surface pressures. It is the sea-surface height difference corrected to a common pressure, +**The anchor.** $D_{K+1} = \Delta_e z(\bar q_{K+1})$ at the deepest interface the two columns share, +where they are in general at different pressures. It is the height difference there corrected to a +common pressure, $$ -D_1 \;=\; \Delta_e Z_1 \;-\; \frac{1}{g}\sum_{i \in CE(e)} -n_{e,i} \int_{p^{\text{surf}}_i}^{\bar q_1} \hat\alpha^{(e)}_i(p)\,dp , +D_{K+1} \;=\; \Delta_e Z_{K+1} \;+\; \frac{1}{g}\sum_{i \in CE(e)} -n_{e,i} \int_{\bar q_{K+1}}^{q_{i,K+1}} \hat\alpha^{(e)}_i(p)\,dp , $$ (anchor) -with both short integrals in closed form and taken inside each column's own top layer, and both -vanishing where the two columns share a surface pressure. +with both short integrals in closed form, each spanning half the cross-edge pressure difference at +that interface, and both vanishing where the two columns' interface pressures agree. Anchored at the +surface instead, the same expression applies at $k = 1$ with the sea-surface height difference and +the surface pressures. -$D_1$ is **computed, not assumed**: it is whatever the model's geometric heights and surface +$D_{K+1}$ is **computed, not assumed**: it is whatever the model's geometric heights and interface pressures imply, evaluated at a common pressure. Like every other quantity in the scan it is a fixed-pressure height difference, and it is zero exactly when the state carries no horizontal pressure gradient at the surface — which is what a state at rest means. A state that is only @@ -617,7 +622,9 @@ approximately at rest carries a real gradient there, and the scheme reports it. therefore not a place where the scheme assumes anything about the state; it is the $k=1$ instance of the same comparison [](#d-recurrence) makes at every other interface. -**Which end of the column the anchor sits at is a conditioning choice.** +**Which end of the column the anchor sits at is not a conditioning choice**, though it was described +as one here before it was measured; §3.7.4 gives the argument and the trade-off. What follows is the +conditioning half of it. `VertCoord::computeGeomZHeight` sets $Z_{i,\,\text{bot}} = -\text{BottomGeomDepth}_i$ and accumulates $\Delta z = \rho_0\,\alpha_{i,k}\,\tilde h_{i,k}$ **upward**: the bathymetry is prescribed and the sea-surface height is derived, so @@ -631,9 +638,10 @@ model's own $z$ — a scheme that returns zero for the state the model actually Requirement 2.3.1 asks for, so using the derived sea-surface height is self-consistent and correct. What [](#ssh-difference) does show is that $\Delta_e Z_{\text{surf}}$ is a difference of two column-length accumulations yielding a small result, where $-\Delta_e H$ is exact input and vanishes -identically for a flat floor. The sea-floor anchor is therefore better conditioned in floating point, -at the cost of a larger common-pressure excursion and a partial cell to handle where `maxLevelCell` -differs. §3.7.4 records what is and is not established about the choice. +identically for a flat floor. The sea-floor anchor is therefore better conditioned in floating point +*where the floor is unstepped*, at the cost of a larger common-pressure excursion, a partial cell to +handle where `maxLevelCell` differs, and — where the floor does step — a cancellation of order the +step. §3.7.4 records the trade-off and what is and is not established about it. **Every quantity in the scan is small.** $D_k$ is the fixed-pressure height difference — of order $10^{-1}$ m for a realistic baroclinic column and zero for a resting one, against the $10^{2}$ m @@ -1580,10 +1588,29 @@ of the §3.7.3 table (horizontal structure in $\Theta$, $S$); assumptions A1, A2 This is the primary test of the steep-layer robustness property (Requirement 2.3, §3.7). It follows the table in §3.7.3 row by row rather than being a single pass/fail. -**Run the machine-precision gate with a horizontally uniform surface pressure.** Both integrals in -[](#anchor) then vanish identically and the two columns' sea-surface heights are equal by -construction, so the anchor contributes nothing and the gate tests the scheme rather than the -initialization. This costs nothing: surface-pressure gradients are exercised separately by §5.1, +**Run the machine-precision gate on a state whose anchor inputs vanish identically.** The gate is +meant to test the scan, not the initialization, and the anchor is the one place where the state can +inject a residual the scheme is powerless to remove. At a sea-floor anchor that means the two +columns must share both a **floor depth** and a **bottom pressure**, so that $\Delta_e Z$ is zero and +the two short integrals of [](#anchor) are zero-width. At a surface anchor it means a horizontally +uniform surface pressure and equal sea-surface heights. + +**This is a condition on how the state was built, and it does not come for free.** A state +constructed by pinning the end *opposite* the anchor carries `VertCoord`'s $O(\tilde h^2)$ +truncation difference (§3.7.4) into the anchor's input, and then no scheme however exact can return +zero: measured on Polaris-initialized states, whose two columns sit at equal floor depth but reach +*different bottom pressures* under tilt, the sea-floor anchor is $-7.1\times10^{-8}$ m where the +surface anchor is zero to round-off. That residual is the anchor and nothing else — every increment +of [](#d-recurrence) is still zero and $D_k$ is still flat down the column — so it does not +contradict the pointwise cancellation of [](#dalpha); it says the gate must be run on a state that +does not carry it. + +Omega's own gate satisfies the condition by construction: it prescribes the pressure grid, giving +both columns the same surface and bottom pressure, and prescribes an equal `BottomGeomDepth` from +which `VertCoord` derives $z$ upward. Both anchor inputs are then identically zero and the measured +$3.1\times10^{-18}$ m s$^{-2}$ is a property of the scan alone. A run of the same scheme on a +Polaris-initialized state would be expected to return the anchor residual above rather than machine +zero, and that is the correct answer for that state. This costs nothing: surface-pressure gradients are exercised separately by §5.1, where the reference solution supplies the expected value. Where surface pressure *does* vary horizontally, the state carries a real fixed-pressure height From b9fb0c7301c8d9acf9618b6fc7013cb22ebad33d Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 11:51:03 -0500 Subject: [PATCH 17/22] Measure assumption A2 directly instead of by a contrast sweep Section 5.1 called for running the temperature and salinity gradient variants at several amplitudes of the cross-edge contrast and requiring the error to grow no faster than linearly. That test cannot work, for three independent reasons, each established by measurement on the Polaris side. The contrast axis is not independent of the resolution axis. A two-column initialization interpolates at plus and minus half the cell spacing, so the state depends on the contrast and the spacing only through their product; contrast 2 at 2 km reproduces contrast 1 at 4 km to every printed digit. A contrast sweep is a coarsening sweep in disguise, which is why the convergence slope collapses from 1.46 to -0.04 across it. A2 and the horizontal stencil's truncation error are confounded by construction. Both scale with the cross-edge contrast, a comparison against the quasi-analytic reference cannot separate them, and the stencil dominates by enough that the two schemes give identical RMS to four significant figures at every contrast. The initialization's shape-preserving limiter is nonlinear in the node values, so the state is not smooth in the contrast: the second difference of layer-mean salinity is 5.75e-2 g/kg on the shipped profile against 7.1e-15 where the limiter has no freedom, and the nonlinearity saturates with contrast rather than scaling with it. What replaces it is stronger. A2 is the claim that the second-order remainder of the equation-of-state expansion across an edge is small, and that remainder is computable straight from the state with no reference comparison, so it is neither confounded with the stencil nor sensitive to how the state was built. Measured that way it is 8.0e-6 relative on temperature_gradient at 4 km, the hardest configuration in the family, with a companion check confirming it vanishes when the two columns coincide. Section 3.7.6's A2 entry and the section 5.7 coverage table are updated to match. Reported from the Polaris side. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 2aec38ce12ea..9431ab8434af 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -1014,6 +1014,11 @@ assumptions this design is making that only testing can confirm: $8\times10^{-6}$ on the hardest configuration available (a 12 °C contrast across a 4 km edge) and $\le 2\times10^{-9}$ on the resting-state variants (§6.3). The first-order expansion is not being worked near its limit, and `temperature_gradient` at coarse resolution is the configuration to watch. + + **A2 must be measured on the remainder itself, not inferred from a sweep of the contrast.** The + contrast cannot be varied independently of the cell spacing in a two-column configuration, and + A2's error is in any case confounded with the horizontal stencil's, which scales the same way and + dominates. §5.1 gives the measurements behind both statements. - **A3 — The residual outside the exact set is small enough in practice.** The $O(\tilde h^2)$ and $O(\tilde h^3)$ entries in §3.7.3 describe how the error *scales*; how large it actually is at the vertical resolutions Omega can afford is unknown. @@ -1568,17 +1573,36 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient - **Consistency check (retained):** `omega_vs_polaris_rms_threshold` (~1e-10 m/s²) — Omega's forward output must still match the Python-computed HPGA, confirming the implementation matches the intended discretization. -- **Horizontal-contrast sweep (new, assumption A2):** the `temperature_gradient` and - `salinity_gradient` variants are run at several amplitudes of the horizontal contrast, up to and - beyond values typical of ocean fronts. The equation-of-state expansion [](#alpha-taylor) is taken - about a state shared across the edge, so its error grows with that contrast, and A2 (§3.7.6) is - the assumption that the first-order expansion remains adequate. **Pass:** the error at fixed - resolution grows no faster than linearly with the contrast amplitude, and repeating the largest - amplitude with the second-order expansion of §3.3 changes the answer by less than the accuracy - gate above. If it does not, the second-order expansion becomes the default rather than an option. +- **Assumption A2 is measured directly, not by a contrast sweep.** An earlier version of this + section called for running `temperature_gradient` and `salinity_gradient` at several amplitudes of + the horizontal contrast and requiring the error to grow no faster than linearly. **That test + cannot work, for three independent reasons**, all established by measurement: + + - **The contrast axis is not independent of the resolution axis.** The two-column initialization + interpolates at $x = \pm d_e/2$, so the state depends on the contrast $c$ and the spacing $d_e$ + only through their product. Verified exactly: contrast 2 at $d_e = 2$ km reproduces contrast 1 + at $d_e = 4$ km to every printed digit. A contrast sweep is therefore a *coarsening* sweep in + disguise, which is why the convergence slope collapses from $1.46$ to $-0.04$ across it. + - **A2 and the horizontal stencil's truncation error are confounded by construction.** Both scale + with the cross-edge contrast, a comparison against the quasi-analytic reference cannot separate + them, and the stencil term dominates by enough that `Centered` and `FiniteVolume` are + indistinguishable — identical RMS to four significant figures at every contrast. + - **The initialization's shape-preserving limiter is nonlinear in the node values**, so the state + itself is not smooth in the contrast: the second difference of layer-mean salinity is + $5.75\times10^{-2}$ g kg$^{-1}$ on the shipped profile against $7.1\times10^{-15}$ on a + two-node profile where the limiter has no freedom. The nonlinearity saturates with contrast + rather than scaling with it. + + **What replaces it is better.** A2 is the claim that the *second-order remainder* of + [](#alpha-taylor) across an edge is small, and that remainder can be computed straight from the + state without any reference comparison, so it is neither confounded with the stencil nor sensitive + to how the state was built. Measured this way it is $8.0\times10^{-6}$ relative on + `temperature_gradient` at 4 km — the hardest configuration in the family — with a companion check + confirming it vanishes when the two columns coincide. **Pass:** the remainder stays below a stated + fraction of $\alpha$ on the hardest configuration available. Should it ever fail, the second-order + expansion of §3.3 becomes the default rather than an option. - **Cfg keys.** New keys mirror the existing ones (`horiz_press_grad.cfg`): a coarse-resolution - absolute tolerance, a `finite_volume_vs_centered` ratio gate, per-scheme expected-rate bands, and - the contrast amplitudes for the sweep. + absolute tolerance, a `finite_volume_vs_centered` ratio gate, and per-scheme expected-rate bands. **Covers:** Requirements 2.1, 2.2 (the bounded-EOS path is exercised), 2.4, 2.5, 2.6; the last row of the §3.7.3 table (horizontal structure in $\Theta$, $S$); assumptions A1, A2, A3. @@ -1823,7 +1847,7 @@ Two cheap checks close that: | 2.5 Runtime-selectable, backward compatible | §5.1 (three configurations); §5.5 | | 2.6 Verified order of accuracy | §5.1 verification gate | | A1 Edge accuracy ≠ cell accuracy | §5.1 verification gate (Phase 2) | -| A2 EOS expansion adequate across an edge | §5.1 contrast sweep; §5.4; the source-4 diagnostic of §3.7.6 | +| A2 EOS expansion adequate across an edge | §5.1, by direct measurement of the second-order remainder across the edge; §5.4 under dynamics | | A3 Residual small enough in practice | §5.1 accuracy gate; §5.3; §5.4 | | A4 PGF error causes the instability | §5.3 diagnostic, run before Phase 1 completes | | A5 Top- and bottom-of-column treatment | §5.1 `bathymetry_step` and `surface_pressure_gradient` | From ec759b846d9b1eb9b66ce9aecc0b35c1f10ede8d Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 11:56:18 -0500 Subject: [PATCH 18/22] Record the Phase 1 results and retire the tilt exponent as a comparison The eight Polaris horiz_press_grad variants have been run in Omega with both schemes over shared initial conditions. Every prediction in section 6.5 was reproduced, several to four or five significant figures. Section 5.1 was still written as a specification to be implemented. It now records what was built and measured: the two configurations Phase 1 actually offers rather than the three an earlier draft assumed, the per-variant and per-scheme convergence bands, and the accuracy ratios. The headline is ztilde_gradient, which holds temperature and salinity horizontally uniform and tilts only the coordinate, so the first-order term of [centered-error] is exposed with nothing else mixed in: centered converges at 1.068 there and finite volume at 1.971. The resting-state behaviour of section 3.7.3 and its cure, visible in a convergence rate rather than inferred. Two corrections to guidance this section gave. The accuracy gate's default must assert "not worse" rather than "better": on temperature_gradient and salinity_gradient the schemes agree to five figures, correctly, because level coordinates make matched-pressure and matched-index coincide and the residual is a two-column error both share. And the advantage is not always a constant factor -- where the orders genuinely differ it widens under refinement, 1.80x at 4 km to 14.8x at 0.5 km. Add section 3.7.3's warning that the tilt exponent must not be used to compare the schemes. Both give q = 1.000, for unrelated reasons: the centered scheme because alpha is effectively piecewise constant in pressure within a layer, the finite-volume scheme because its one remaining error term is the anchor, which inherits the tilt's own linearity. Reading q alone would report "no better than centered" for a scheme up to 500 times more accurate. Add section 6.6 with the resting-state advantage per variant, spanning four orders of magnitude, and with bathymetry_step_linear -- a new variant that is both inside the exact set and stepped, so it isolates what a bathymetry step costs. It confirms A5 on the geometry where that assumption was least obvious: D_k stays flat to 1.4e-15 m even where the two columns reach different maxLevelCell and the deepest edge layers extend three layers below one column's floor. Record that omega_vs_polaris measures 4e-19 to 5e-16 for the new scheme, better than the legacy scheme's, and note what maintaining that independence required. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 167 +++++++++++++++--- 1 file changed, 140 insertions(+), 27 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 9431ab8434af..8031a8768f91 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -842,6 +842,26 @@ the bottom-layer error seen in realistic global configurations. Whether this dow seen in realistic global configurations is a plausible diagnosis, not an established one; it is carried as A4 in §3.7.6 and tested in §5.3. +**The tilt exponent is a statement about `PressureGradCentered` and must not be used to compare the +two schemes.** Measured in Omega on the Polaris resting-state variants, `PressureGradFiniteVolume` +returns a fitted exponent of $1.000$ as well — the *same* value — while its absolute error is one to +three orders of magnitude smaller: $1.750\times10^{-10}$ against $2.602\times10^{-8}\ \mathrm{m\, +s^{-2}}$ at a tilt of 0.05 m/km, and $2.022\times10^{-7}$ against $2.069\times10^{-5}$ at 50 m/km, +both at 4 km spacing and 256 m layers. + +That is not a failure of the scheme and it is not a coincidence. On a Polaris-initialized state the +finite-volume residual is entirely the anchor of [](#anchor) (§5.2), and the anchor is *linear in +the tilt* because the cross-edge difference it corrects to a common pressure is. So both schemes +give $q = 1$ for unrelated reasons: the centered scheme because $\alpha$ is effectively piecewise +constant in pressure within a layer, the finite-volume scheme because its one remaining error term +inherits the tilt's own linearity. + +**Reading $q$ alone would therefore report "no better than centered" for a scheme that is up to +500 times more accurate.** For comparing the schemes the absolute level is the discriminating +measurement, and it is what §5.1's accuracy gate uses. The exponent retains its original purpose — +calibrating the centered baseline, and detecting a scheme that has become *insensitive* to tilt — +but it no longer separates the two. + #### 3.7.4 What `VertCoord` supplies, and what it does not `VertCoord` is the source of `PressureInterface`, `PressureMid`, `PseudoThickness` and the @@ -1516,23 +1536,24 @@ scheme, so it gates nothing but informs whether the work should proceed as prior Extend the four existing variants — `temperature_gradient`, `salinity_gradient`, `surface_pressure_gradient`, `ztilde_gradient` — to run the centered scheme alongside the new one: -- **Scheme selection.** Add `PressureGrad: { PressureGradType: FiniteVolume, … }` to - `forward.yaml` and parametrize each task over three configurations: +- **Scheme selection.** *(Implemented and run; this bullet records what was built.)* Polaris adds a + `PressureGrad` block to `forward.yaml` and parametrizes each task over the **two** configurations + Phase 1 offers: - `centered` — the legacy `PressureGradCentered` functor, unchanged; - - `finite_volume_phase1` — `HorzOrder: 2`, `VerticalReconstruction: linear`; - - `finite_volume_phase2` — `HorzOrder: 4`, `VerticalReconstruction: ppm` (added when Phase 2 - lands). + - `finite_volume` — `HorzOrder: 2`, `VerticalReconstruction: linear`. - (These variant names are provisional; the final spelling follows Polaris' naming conventions and - is settled on the Polaris side. What matters here is that the last two are the *same* - implementation at two orders, distinct from the legacy functor.) + An earlier version of this bullet listed a third, `finite_volume_phase2`, and described the last + two as "the *same* implementation at two orders". That framing is retired: the Phase 2 values + exist as keys but are **rejected with an error** (§4.1.1), so there is no third configuration to + run until Phase 2 lands, and a configuration written for Phase 2 cannot quietly execute as + Phase 1. - `finite_volume_phase1` is not a stand-in for the legacy scheme: it is second order in the - horizontal like `centered`, but it is *consistent*, so its absolute error should be markedly - lower even though its convergence slope is the same. Both must be run, and the comparison between - them is the clearest single measure of what Phase 1 buys. Running only the legacy functor under a - "second order" label would measure the convergence of code this design does not change and leave - the new code's Phase 1 path unverified. + Both schemes run over **one shared initial condition** — the Polaris `init` step is + scheme-independent and writes both schemes' reference HPGA from the same state — so the + comparison between them is made at an identical state rather than at two states that ought to + match. That comparison is the clearest single measure of what Phase 1 buys. Running only the + legacy functor would measure the convergence of code this design does not change and leave the + new code unverified. The forward step still runs a single time step with only `PressureGradTendencyEnable: true`, reading the PGF acceleration from `NormalVelocityTend`. @@ -1545,24 +1566,53 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient a tolerance, **and** the new scheme's RMS error must be below the centered RMS error at that same resolution. This gate applies to Phase 1, where it is the primary measure of value. - **This is also the gate for Requirement 2.3.4.** Set the ratio per variant from the measurements - in §6.5 — the advantage is 6.5× at 256 m layers and 2.4× at 64 m on a smooth curved profile, ~400× - on a stepped bathymetry — and take it at the coarse end of the sweep. Do **not** add a gate - requiring the new scheme's convergence slope to exceed the centered scheme's: the two converge at - similar rates on smooth profiles, so such a gate fails where nothing is wrong. + **This is also the gate for Requirement 2.3.4.** Set the ratio per variant, at the coarse end of + the sweep. **Measured in Omega** across the four variants, centered RMS over finite-volume RMS at + 4 km: $1.00\times$ (`temperature_gradient`), $1.00\times$ (`salinity_gradient`), $1.80\times$ + (`ztilde_gradient`), $2.19\times$ (`surface_pressure_gradient`). + + **The gate's default must therefore assert "not worse" rather than "better".** On + `temperature_gradient` and `salinity_gradient` the two schemes agree to five significant figures, + and that is correct rather than disappointing: those variants hold the coordinate level, so + comparing at matched pressure and at matched layer index coincide, and the remaining error is the + two-column representation of the tracer gradient, which both schemes share. A gate demanding an + improvement would fail on a configuration where there is nothing to improve. Only the variants + that tilt something raise it. + + Do **not** add a gate requiring the new scheme's convergence slope to exceed the centered + scheme's. The reason is *not* that the two always converge alike — on `ztilde_gradient` they + genuinely differ, and that is the headline result of Phase 1 (below). It is that they converge + alike on three variants out of four, so such a gate fails where nothing is wrong. - **Verification gate (Requirement 2.6):** the measured slope of RMS error vs. resolution, `omega_vs_reference_convergence_rate_*`, must fall within a band around the configured order - of accuracy — nominally ~2 for `finite_volume_phase1` and ~4 for `finite_volume_phase2`. This band + of accuracy — nominally ~2 for `finite_volume` as Phase 1 ships it, and ~4 when Phase 2 lands. This band is retuned from its present values rather than loosened; a slope outside it fails the test and is treated as an implementation defect to be diagnosed, not as a tolerance to be widened. - **The `centered` bands are *not* uniform across the four variants and must be set per variant from - measurement.** Measured on chrysalis with the bottom layer included, `PressureGradCentered` gives - $\approx 1.6$ (`temperature_gradient`), $\approx 1.8$ (`salinity_gradient`), $\approx 2.0$ - (`surface_pressure_gradient`) and $\approx 1.1$ (`ztilde_gradient`). The last is the first-order - resting-state behaviour of §3.7.3 showing up directly, and it is the reason a single "~2 for - centered" band would fail three variants out of four. This corrects an earlier statement here that - the `centered` band was unchanged from its present values. + **The bands are *not* uniform across the four variants, and must be set per variant *and per + scheme*, from measurement.** Measured in Omega on chrysalis with the bottom layer included: + + | variant | `centered` | `finite_volume` | + | --- | --- | --- | + | `temperature_gradient` | 1.631 | 1.632 | + | `salinity_gradient` | 1.801 | 1.802 | + | `surface_pressure_gradient` | 2.000 | 2.003 | + | `ztilde_gradient` | **1.068** | **1.971** | + + A single "~2 for centered" band would fail three variants out of four, which is why the bands are + per variant. Only `ztilde_gradient` needs a band of its own *per scheme*. + + **`ztilde_gradient` is the clearest single demonstration that Phase 1 works.** It holds $\Theta$ + and $S$ horizontally uniform and tilts only the coordinate, so the first-order term of + [](#centered-error) is exposed with nothing else mixed in: the centered scheme is first order + there (1.068) and the finite-volume scheme **restores second** (1.971). This is the resting-state + behaviour of §3.7.3 and its cure, visible in a convergence rate rather than inferred. + + **One consequence for how the advantage is described.** Because the orders genuinely differ on + this variant, its advantage *widens* under refinement rather than staying a constant factor: + $1.80\times$ at 4 km against $14.8\times$ at 0.5 km. Elsewhere it is the constant factor this + section previously assumed throughout — $2.19\times$ at both ends of the sweep on + `surface_pressure_gradient`. Both statements are needed; neither generalizes. - **Asymptotic range (Phase 2 implementation-time task):** it is not yet established that the existing `horiz_resolutions` sweep spans a range where a fourth-order slope is cleanly measurable — the sweep may be too coarse to have entered the asymptotic regime at its fine end, @@ -1573,6 +1623,23 @@ Extend the four existing variants — `temperature_gradient`, `salinity_gradient - **Consistency check (retained):** `omega_vs_polaris_rms_threshold` (~1e-10 m/s²) — Omega's forward output must still match the Python-computed HPGA, confirming the implementation matches the intended discretization. + + **Measured for the new scheme: $4\times10^{-19}$ to $5\times10^{-16}$ m s$^{-2}$**, against + $1\times10^{-16}$ to $2\times10^{-15}$ for `centered` on the same states — six orders inside the + threshold, and *better* than the legacy scheme's. This is the strongest single piece of evidence + that the scheme is implemented as designed, because the Python counterpart was written from this + document rather than from the C++, so the two are independent realizations of the same + specification. + + **That independence has to be maintained deliberately, and it nearly was not.** Reconciling the + two implementations before the comparison was run found two places where they had silently + diverged — the Python integrated with a 4-point Gauss rule where Omega defaults to 2 + (`QuadraturePoints`, §4.1.1), and it anchored the column scan at the sea surface where Omega + anchors at the sea floor (§3.7.4). Neither shows up on the exact set, where the integrand is zero + at every quadrature point and any rule integrates it to zero; both bite off it, which is exactly + where this check operates. Had they not been reconciled first, the disagreement would have + appeared as a single scalar per resolution with no indication which of nine discretization + choices was responsible. - **Assumption A2 is measured directly, not by a contrast sweep.** An earlier version of this section called for running `temperature_gradient` and `salinity_gradient` at several amplitudes of the horizontal contrast and requiring the error to grow no faster than linearly. **That test @@ -2064,3 +2131,49 @@ shallower floor. **Regression status.** `HPGAFiniteVolume` is written alongside the existing `HPGA`, and `HPGA` is bit-identical to the previous reference run, so adding the scheme moves nothing already measured. + +### 6.6 Confirmation from the Omega run + +The eight Polaris `horiz_press_grad` variants were run on chrysalis with both schemes over shared +initial conditions. **Every §6.5 prediction was reproduced**, several to four or five significant +figures — the offline Polaris kernel predicted Omega's answers rather than merely resembling them, +which is what licenses using it to size gates before a run in future. + +**Resting-state advantage, by variant.** The true HPGA is identically zero in all four, so both +schemes' output is pure error and the ratio is a clean statement of what Phase 1 buys. Smallest +ratio anywhere in each sweep: + +| variant | what it tilts | profile | centered / finite-volume | +| --- | --- | --- | --- | +| `hydrostatic_consistency` | the coordinate | curved | $2.58\times$ | +| `hydrostatic_consistency_linear` | the coordinate | in the exact set | $7.71\times$ | +| `bathymetry_step` | the sea floor | curved | $1170\times$ | +| `bathymetry_step_linear` | the sea floor | in the exact set | $58828\times$ | + +The ordering is the result, not an artefact of how the sweeps were chosen: the advantage is +smallest where the profile is unresolved and only the coordinate tilts, and largest where the +profile is resolved and the sea floor steps. **A single shared gate would be vacuous at one end and +unreachable at the other**, which is why Polaris sets this per variant. + +**`bathymetry_step_linear` is new**, added because no existing variant is both inside the exact set +and stepped: `hydrostatic_consistency_linear` is inside the exact set but tilts only the coordinate, +while `bathymetry_step` has the right geometry but a curved profile whose truncation cannot be told +apart from the geometry's. Being both, it isolates what a bathymetry step costs the scheme. + +(Whether coordinate tilt or a stepped floor dominates the bottom-layer error in a realistic global +run is assumption A4, which remains undemonstrated — §5.3 is where it would be settled and has not +been run. Nothing in this section rests on it.) + +**What it establishes, and it is the assumption that was most doubted.** A5 (§3.7.6) — evaluating a +column's deepest reconstruction below its own floor — does **not** break the cancellation. $D_k$ +stays flat to $1.4\times10^{-15}$ m at every sea-floor gradient in the sweep, including at 100 and +200 m/km where the two columns reach different `maxLevelCell` and the deepest edge layers extend two +and three layers below one column's floor. A5 is confirmed as an accuracy question rather than a +robustness one, on the geometry where it was least obvious. + +**What remains there is the anchor**, not the scan: §5.2's construction condition and §3.7.5's +qualification about the cancellation over a bathymetry step both apply, and the residual on that +variant is $4.3\times10^{-10}$ m s⁻² against `PressureGradCentered`'s $9.1\times10^{-5}$. + +**One reading to avoid** is recorded in §3.7.3: the fitted tilt exponent is $1.000$ for *both* +schemes, so it cannot be used to compare them. The absolute level is the discriminating measurement. From abe247f7a21ee610018a3e5a573d0419e33a6ea4 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 12:15:47 -0500 Subject: [PATCH 19/22] Record the global resting-state measurement that bears on A4 Section 6.6 previously asserted that interior coordinate tilt contributes essentially nothing to the global bottom-layer error and attributed that to section 5.3, which contained no such measurement. The claim was ahead of the evidence as the document stood; the assertion was removed, and this restores it properly by putting the measurement itself in section 5.3 with its numbers and provenance. The measurement is an offline evaluation of the centered scheme's PGF on EC30to60E2r2 with horizontally uniform temperature and salinity, which is an exact resting state on the real mesh and bathymetry, so the whole computed PGF is error -- section 5.2's premise at global scale. It establishes three things. The error is concentrated in the bottom layer and is baroclinic there, matching the bottom-trapped character of the KE response; it is 1.28x to 1.55x the pressure gradient the model actually carries in that layer, which sets the bar for Requirement 2.1 at a factor of 5-10 rather than the ~2x a modest gain would give; and the global IC's interior coordinate is 100-1000x less tilted than the smallest tilt in the Polaris sweep, putting that mechanism some 6000x below the observed interior error. It also calibrates bathymetry_step as a quantitative proxy, within 20-35% over the slope range that dominates the mesh and over-predicting steep edges by 3-10x. It does not settle A4, and the subsection says so at length. Every number is the error rather than its dynamical consequence, which is necessary for A4 but not sufficient: it does not show the error produces the observed bottom-layer KE rather than merely coexisting with it. The one forward-run observation, bottom KE 1.19x the fully forced run, is suggestive and no more. Section 6.6's parenthetical now cites the narrow claim the measurement supports and keeps A4 open, rather than conflating the two. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 68 ++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 8031a8768f91..152c33ac9076 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -1834,6 +1834,66 @@ phasing, and it should be run **before** Phase 1 implementation is finished, wit scheme on the realistic profile as the control. A null result would not invalidate the design, but it would change its priority. +#### 5.3.1 What a global resting state already shows, and what it does not + +A measurement bearing on A4 exists and is recorded here so the assumption is argued from numbers +rather than from plausibility. **It does not settle A4**; the end of this subsection says exactly +what it leaves open. + +**What was measured.** The centered scheme's PGF was evaluated **offline** on a realistic global +initial condition — `EC30to60E2r2` with horizontally uniform $\Theta$ and $S$ +(`ocean.EC30to60E2r2.200908.teos10.uniformTS.nc`, by `measure_hpg_error.py`, both in the Polaris run +directory `test_20260727/hpg_uniform_ts/`). Uniform $\Theta$, $S$ as functions of pressure make this +an exact resting state on the real mesh and bathymetry, so **the entire computed PGF is error** — +§5.2's premise at global scale. Split into depth-mean (barotropic) and deviation (baroclinic), in +m s⁻²: + +| | median | p99 | +| --- | --- | --- | +| all active edge-layers, total | $9.30\times10^{-7}$ | $1.13\times10^{-5}$ | +| all active edge-layers, baroclinic | $9.45\times10^{-8}$ | $1.81\times10^{-6}$ | +| deepest common layer, total | $2.70\times10^{-6}$ | $1.62\times10^{-5}$ | +| deepest common layer, baroclinic | $1.81\times10^{-6}$ | $1.40\times10^{-5}$ | + +**Three things this establishes.** + +1. **The error is concentrated in the bottom layer and is baroclinic there.** The interior error is + ~90% barotropic, which a free-surface adjustment removes within hours and which therefore cannot + sustain anything; the bottom layer is 67% baroclinic. That matches the bottom-trapped, 97–98% + baroclinic character of the KE response that motivated this work. +2. **It is large enough to matter.** In the bottom layer the truncation error is $1.28\times$ + (median) and $1.55\times$ (p99) the pressure gradient the model actually carries there — and the + carried gradient itself contains the error, so the ratio to the true signal is worse. **This sets + the bar for Requirement 2.1**: a useful improvement is a factor of 5–10 at the slopes the global + mesh actually has, not the ~2× a modest gain would give. +3. **Interior coordinate tilt is not the mechanism.** The global IC's interior coordinate is + level to 2–18 Pa cross-edge, $2$–$5\times10^{-5}$ of a layer, while the smallest tilt in the + Polaris `hydrostatic_consistency` sweep is $1.74\times10^{3}$ Pa — 100 to 1000 times more. + Scaling the + measured $q = 1$ line (§3.7.3) down to the global tilt gives $\sim1.6\times10^{-10}$ m s⁻², about + 6000× below the global interior error. **Whatever drives the bottom-layer error, it is not the + tilting of interior coordinate surfaces** — which is why §5.2's tilt scan calibrates the scheme + without predicting a global improvement. + +**And one thing it calibrates.** Comparing like with like — baroclinic bottom-layer error, with the +Polaris `bathymetry_step` value scaled by $(199/256)^2$ for layer thickness — the two-column +configuration reproduces the global figure to within 20–35% across the p25–p75 slope range where +most of the mesh sits ($1.20\times$ at 1.7 m/km, $1.34\times$ at 4.5 m/km). It over-predicts steeply +sloped edges by 3–10× ($2.9\times$ at 11 m/km, $9.9\times$ at 30 m/km), presumably because an +isolated two-column step is harsher than a real slope where neighbouring cells share the descent. So +`bathymetry_step` is a quantitative proxy for the global bottom-layer error over the range that +dominates the mesh, and its tail should be read with that in mind. + +**What this does not settle, and it is the whole of A4.** Every number above is the *error*, not its +dynamical consequence. That the PGF error exceeds the gradient the model carries is necessary for +A4 but not sufficient: it does not show this error is what *produces* the observed bottom-layer KE +rather than merely coexisting with it. The one forward-run observation available — the uniform-T/S +state gives bottom KE $1.19\times$ that of the fully forced run — is suggestive and no more. A4 +still +needs the two-run seamount comparison specified above, and **that comparison cannot be run with +the centered scheme as this section currently specifies**, for reasons recorded in the Polaris-side +`a4_diagnostic_issues.md` and still outstanding in this discussion. + **Covers:** Requirement 2.3 under dynamics; assumptions A3, A4. ### 5.4 Test: Overflow (full non-Boussinesq dynamics) @@ -2160,9 +2220,11 @@ and stepped: `hydrostatic_consistency_linear` is inside the exact set but tilts while `bathymetry_step` has the right geometry but a curved profile whose truncation cannot be told apart from the geometry's. Being both, it isolates what a bathymetry step costs the scheme. -(Whether coordinate tilt or a stepped floor dominates the bottom-layer error in a realistic global -run is assumption A4, which remains undemonstrated — §5.3 is where it would be settled and has not -been run. Nothing in this section rests on it.) +(Of the two, the stepped floor is the one that matters globally: §5.3.1 measures the interior +coordinate of a realistic global IC as 100–1000× less tilted than the smallest tilt in the Polaris +sweep, putting its contribution some 6000× below the observed global interior error. That rules out +one mechanism; it does not establish A4, which asks whether PGF error *drives* the bottom-layer +instability and which remains undemonstrated. Nothing in this section rests on either.) **What it establishes, and it is the assumption that was most doubted.** A5 (§3.7.6) — evaluating a column's deepest reconstruction below its own floor — does **not** break the cancellation. $D_k$ From 2a121740686c1446dbffbe7b198377dbc11392f8 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 12:18:11 -0500 Subject: [PATCH 20/22] Connect Requirement 2.1's bar to the measured advantage Section 5.3.1 sets the bar for Requirement 2.1 at a factor of 5-10, from the global resting state where the centered scheme's bottom-layer error is 1.3 to 1.6 times the pressure gradient the model carries there. Section 6.6 reports the advantage per variant. Neither section referred to the other, so the requirement stayed qualitative and the ratios had nothing to be read against. Requirement 2.1 now states the figure and where it comes from. Section 6.6 reads its four ratios against it: three clear the bar, and hydrostatic_consistency does not, at 2.58x. That is not a shortfall, and saying so matters because the number invites the opposite reading. Section 5.3.1 measures the interior coordinate of a realistic global initial condition as 100 to 1000 times less tilted than the smallest tilt in that sweep, putting interior coordinate tilt some 6000 times below the observed global interior error. So the variant is calibrating the scheme on a mechanism that is not the one the bar was set from, and its ratio is not a prediction of global improvement. The stepped-floor variants are the quantitative proxies for that error, and they clear the bar by two to four orders of magnitude. Reported from the Polaris side. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 152c33ac9076..6f38a8513215 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -147,6 +147,12 @@ surface pressure, and coordinate slope. Absolute error at affordable resolution determines whether the scheme is *useful*; it is complemented by the separate verification requirement in §2.6, which determines whether it is *correct*. +**"Substantially" is a factor of 5–10, and that figure comes from measurement rather than from +taste.** On a realistic global resting state the centered scheme's bottom-layer truncation error is +$1.3$–$1.6\times$ the pressure gradient the model actually carries there, so a modest gain of order +$2\times$ would leave the error comparable to the signal. §5.3.1 gives the measurement and §6.6 the +per-variant ratios achieved. + ### 2.2 Requirement: Bounded TEOS-10 cost The number of TEOS-10 specific-volume evaluations performed by the PGF must be @@ -2215,6 +2221,16 @@ smallest where the profile is unresolved and only the coordinate tilts, and larg profile is resolved and the sea floor steps. **A single shared gate would be vacuous at one end and unreachable at the other**, which is why Polaris sets this per variant. +**Read against Requirement 2.1's bar of 5–10×, three of the four clear it and `hydrostatic_consistency` +does not, at $2.58\times$ — and that is not a shortfall.** §5.3.1 measures the interior coordinate of +a realistic global initial condition as 100–1000× less tilted than the smallest tilt in that sweep, +which puts interior coordinate tilt some 6000× below the observed global interior error. So +`hydrostatic_consistency` is calibrating the scheme on a mechanism that is not the one the bar was set +from, and its ratio should not be read as a prediction of global improvement. The variants that *are* +quantitative proxies for the global bottom-layer error are the stepped-floor ones, and they clear the +bar by two to four orders of magnitude. §5.3.1's closing paragraph gives the range over which +`bathymetry_step` tracks the global figure, and where it over-predicts. + **`bathymetry_step_linear` is new**, added because no existing variant is both inside the exact set and stepped: `hydrostatic_consistency_linear` is inside the exact set but tilts only the coordinate, while `bathymetry_step` has the right geometry but a curved profile whose truncation cannot be told From 4118ee8a2984b236d8471272abda73eec56fe2d5 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 2 Aug 2026 12:56:05 -0500 Subject: [PATCH 21/22] Move the A4 diagnostic after Phase 1, where it can actually run The design specified the A4 diagnostic in three places as a pre-Phase-1 check that could be run immediately with the existing centered scheme. That cannot work, and section 3.7.3's own table is what contradicts it: a profile linear in pressure lies in Phase 1's exact set and not in the centered scheme's, where it stays first order in layer thickness with a coefficient proportional to the coordinate tilt. The diagnostic's inference requires the scheme being run to have zero pressure gradient error on that profile. Run with the centered scheme the linear-in-pressure seamount is not a null configuration, only a slightly cleaner non-null one, and a sigma coordinate over a seamount is the largest tilt in the suite, so the contamination is worst exactly there. The test would measure the thing it was designed to exclude and its result would support neither conclusion. A4 is therefore a post-Phase-1 test and became runnable for the first time when FiniteVolume landed. Section 4.5.3's step 2 is rewritten as what a centered run there can legitimately establish -- that the case exercises the pressure gradient at all, and how large the spurious velocity is -- which is worth doing early but answers a different question. Reported from the Polaris side, after the first Omega seamount runs. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 6f38a8513215..8f8dfc61024b 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -1499,10 +1499,11 @@ Requirement 2.6, because exactness does not constrain it (§3.6.1). - the rule used where a column's deepest reconstruction is evaluated below its own floor, and how much accuracy it costs off the exact set (assumption A5, §3.7.6). -2. Run the assumption-A4 diagnostic of §5.3, which uses the *existing* centered scheme and so can be - done immediately and in parallel with step 1. If spurious bottom-layer flow survives a profile - that Phase 1 would resolve exactly, the cause is elsewhere in the model and the priority of this - work should be reconsidered before it is built. +2. Calibrate the seamount configuration with the centered scheme, which can be done immediately and + in parallel with step 1. This establishes that the case exercises the pressure gradient at all — + the coordinate must genuinely tilt, which a clipped p-star would prevent — and sizes the + spurious velocity to expect. It is **not** the A4 diagnostic: §5.3 explains why that one cannot + be run with `Centered` and has to wait for Phase 1. 3. Implement and verify Phase 1 against §5.1, §5.2, §5.3, and §5.5. 4. Take up Phase 2. Re-examine [](#z-increment-exact) before adopting the second-order equation-of-state expansion; that, and not the stencil, is the item that could reopen a settled @@ -1534,8 +1535,9 @@ Which tests gate which phase: | §5.5 Reduction to centered | gates | rerun unchanged | | §5.6 Cost check | gates | gates; stencil width must not change the EOS count | -The A4 diagnostic within §5.3 is run *before* Phase 1 implementation and uses the existing centered -scheme, so it gates nothing but informs whether the work should proceed as prioritized (§4.5.3). +The A4 diagnostic within §5.3 gates nothing — it informs whether the work was prioritized correctly +rather than whether it is correct. It requires `FiniteVolume` and so can only be run *after* Phase 1, +not before it as earlier versions of this document assumed; §5.3 gives the reason. ### 5.1 Test: Two-column HPGA convergence (extend existing) @@ -1830,15 +1832,27 @@ is substantially smaller for the new scheme than for the centered scheme. This i counterpart of §5.2 — the same resting state, now run forward in the full solver — and the direct test of Requirement 2.3. -**Testing assumption A4 (§3.7.6).** Run the seamount case twice: once with a stratification Phase 1 -resolves exactly ($\Theta$, $S$ linear in pressure) and once with a realistic profile. Spurious -velocity that survives the first run cannot be PGF truncation error, since the PGF is zero there to -machine precision, and must come from somewhere else in the model — most likely the layer-mean -treatment in the tracer and remapping operators (§4.3). This is the cheapest available check on -whether accelerating this work will actually cure the bottom-layer instability that motivated the -phasing, and it should be run **before** Phase 1 implementation is finished, with the centered -scheme on the realistic profile as the control. A null result would not invalidate the design, but -it would change its priority. +**Testing assumption A4 (§3.7.6).** Run the seamount case twice: once with a stratification the +scheme resolves exactly ($\Theta$, $S$ linear in pressure) and once with a realistic profile. +Spurious velocity that survives the first run cannot be PGF truncation error, since the PGF is zero +there to machine precision, and must come from somewhere else in the model — most likely the +layer-mean treatment in the tracer and remapping operators (§4.3). + +**The diagnostic must be run with `FiniteVolume`, not with `PressureGradCentered`.** Earlier +versions of this section, of §4.5.3 step 2 and of the gate table above described it as a +*pre*-Phase-1 check that could be done immediately with the existing scheme. That was an error, and +§3.7.3's own table is what contradicts it: a profile linear in pressure is in Phase 1's exact set +and **not** in the centered scheme's, where it remains $O(\tilde h)$ with a coefficient +proportional to the coordinate tilt. Run with `Centered`, the linear-in-pressure seamount is not a +null configuration but merely a slightly cleaner non-null one — and a sigma coordinate over a +seamount is the largest tilt in the suite, so the contamination is at its worst exactly there. The +diagnostic would measure the thing it was designed to exclude, and its result would support neither +"A4 holds" nor "A4 fails". + +The consequence for ordering is the opposite of what §4.5.3 assumed: A4 is a **post**-Phase-1 test, +and it became runnable for the first time when `FiniteVolume` landed. What can be run beforehand is +a *calibration* of the centered scheme's response to tilt, which is useful but answers a different +question; §5.3.1 is the measurement that does bear on A4 without needing the seamount at all. #### 5.3.1 What a global resting state already shows, and what it does not From 8270867466ff52563e225d636bf335a00b2aa7a2 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 3 Aug 2026 03:45:47 -0500 Subject: [PATCH 22/22] Record the seamount result: z-star passes, sigma is unstable Section 5.3 asked for the seamount test and had no measurement. It now has one, run with TEOS-10 over six days with tracer diffusion and hyperviscosity off so the pressure gradient is what remains. On z-star the scheme passes the section's criterion by a wide margin: 44x lower maximum velocity and 3e4 lower mean kinetic energy than the centered scheme on the realistic profile, and 134x and 1780x at one hour before anything else develops. The centered scheme's error sits in the partial bottom cell, matching section 5.1's bathymetry_step. That is Requirement 2.3 under dynamics. On sigma it does not. The scheme develops density inversions at day 1.5 on the realistic profile and day 3 on the linear-in-pressure one, reaching about 5e-1 m/s by day 6 where the centered scheme on the identical configuration is clean and decaying at about 1e-2. It is not an accuracy failure -- before the growth takes hold the new scheme is five times more accurate than the centered one. Three things point at a grid-scale numerical instability: the disturbance sits at a fixed location on the flank, the same under both equations of state, so it follows the geometry rather than the profile; its grid-scale content rises before any inversion appears; and the temperature anomaly reaches a third of the profile's range. Sigma layers follow the bathymetry, which is the steepest tilt against isobars in the suite and is not what Omega runs, so this does not qualify the result on the configurations Omega uses. It does mean the scheme has a limit on steeply tilted layers that the centered scheme does not share, and that the limit is not understood. The next diagnostic is a re-run with monotonic horizontal advection. An earlier reading attributed the sigma behaviour to a Polaris mixing misconfiguration. Removing that mixing fixed the centered runs and made the finite-volume ones worse, so the attribution was wrong: the diffusion had been damping the mode. The former 5.3.1 becomes 5.3.2. Reported from the Polaris side. Co-Authored-By: Claude Opus 5 --- components/omega/doc/design/PGradHighOrder.md | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/components/omega/doc/design/PGradHighOrder.md b/components/omega/doc/design/PGradHighOrder.md index 8f8dfc61024b..0ab5c297f543 100644 --- a/components/omega/doc/design/PGradHighOrder.md +++ b/components/omega/doc/design/PGradHighOrder.md @@ -150,7 +150,7 @@ requirement in §2.6, which determines whether it is *correct*. **"Substantially" is a factor of 5–10, and that figure comes from measurement rather than from taste.** On a realistic global resting state the centered scheme's bottom-layer truncation error is $1.3$–$1.6\times$ the pressure gradient the model actually carries there, so a modest gain of order -$2\times$ would leave the error comparable to the signal. §5.3.1 gives the measurement and §6.6 the +$2\times$ would leave the error comparable to the signal. §5.3.2 gives the measurement and §6.6 the per-variant ratios achieved. ### 2.2 Requirement: Bounded TEOS-10 cost @@ -1852,9 +1852,40 @@ diagnostic would measure the thing it was designed to exclude, and its result wo The consequence for ordering is the opposite of what §4.5.3 assumed: A4 is a **post**-Phase-1 test, and it became runnable for the first time when `FiniteVolume` landed. What can be run beforehand is a *calibration* of the centered scheme's response to tilt, which is useful but answers a different -question; §5.3.1 is the measurement that does bear on A4 without needing the seamount at all. +question; §5.3.2 is the measurement that does bear on A4 without needing the seamount at all. -#### 5.3.1 What a global resting state already shows, and what it does not +#### 5.3.1 Measured: the scheme passes on near-level layers and is unstable on sigma + +Run on the Polaris seamount with TEOS-10 over six days, with tracer diffusion and hyperviscosity +off so that the pressure gradient is what remains. + +**On z-star, `FiniteVolume` passes §5.3's criterion by a wide margin.** Maximum $|u|$ at day 6 is +$1.0\times10^{-3}$ m s$^{-1}$ against `PressureGradCentered`'s $4.6\times10^{-2}$ on the realistic +profile — 44$\times$, and 3$\times10^{4}$ in mean kinetic energy; at one hour, before anything else +develops, 134$\times$ and 1780$\times$. The centered scheme's error sits in the partial bottom cell, +matching §5.1's `bathymetry_step`. This is Requirement 2.3 under dynamics. + +**On sigma it does not.** `FiniteVolume` develops density inversions — day 1.5 on the realistic +profile, day 3 on the linear-in-pressure one — and reaches $\sim5\times10^{-1}$ m s$^{-1}$ by day 6, +where `Centered` on the identical configuration is clean and decaying at $\sim10^{-2}$. + +It is **not an accuracy failure**. Before the growth takes hold the new scheme is five times *more* +accurate than the centered one, and still comparable at day 2. Three things point at a grid-scale +numerical instability rather than a resolved response: the disturbance sits at a fixed location on +the flank, the same under both equations of state, so it follows the geometry rather than the +profile; its grid-scale content rises before any inversion appears; and the temperature anomaly +reaches a third of the profile's whole range. + +**What this does and does not mean.** Sigma layers follow the bathymetry, which is the steepest +tilt against isobars in the whole suite and is not what Omega runs — p-star, like z-star, keeps +layers near level. So this does not qualify the Phase 1 result on the configurations Omega uses. It +does mean the scheme has a limit on steeply tilted layers that the centered scheme does not share, +that the limit is not understood, and that anything relying on sigma-like layering is untested +territory. The next diagnostic is a re-run with monotonic horizontal advection; the working +hypothesis, untested, is that an unlimited horizontal tracer advection admits a mode the more +accurate pressure gradient no longer damps. + +#### 5.3.2 What a global resting state already shows, and what it does not A measurement bearing on A4 exists and is recorded here so the assumption is argued from numbers rather than from plausibility. **It does not settle A4**; the end of this subsection says exactly @@ -2236,13 +2267,13 @@ profile is resolved and the sea floor steps. **A single shared gate would be vac unreachable at the other**, which is why Polaris sets this per variant. **Read against Requirement 2.1's bar of 5–10×, three of the four clear it and `hydrostatic_consistency` -does not, at $2.58\times$ — and that is not a shortfall.** §5.3.1 measures the interior coordinate of +does not, at $2.58\times$ — and that is not a shortfall.** §5.3.2 measures the interior coordinate of a realistic global initial condition as 100–1000× less tilted than the smallest tilt in that sweep, which puts interior coordinate tilt some 6000× below the observed global interior error. So `hydrostatic_consistency` is calibrating the scheme on a mechanism that is not the one the bar was set from, and its ratio should not be read as a prediction of global improvement. The variants that *are* quantitative proxies for the global bottom-layer error are the stepped-floor ones, and they clear the -bar by two to four orders of magnitude. §5.3.1's closing paragraph gives the range over which +bar by two to four orders of magnitude. §5.3.2's closing paragraph gives the range over which `bathymetry_step` tracks the global figure, and where it over-predicts. **`bathymetry_step_linear` is new**, added because no existing variant is both inside the exact set