Skip to content

Add a parabolic vertical reconstruction to the FiniteVolume pressure gradient - #636

Draft
xylar wants to merge 60 commits into
E3SM-Project:developfrom
xylar:omega/add-finite-volume-horiz-press-grad-phase2
Draft

xylar wants to merge 60 commits into
E3SM-Project:developfrom
xylar:omega/add-finite-volume-horiz-press-grad-phase2

Conversation

@xylar

@xylar xylar commented Oct 25, 2026 •

Copy link
Copy Markdown

Add a parabolic vertical reconstruction to the FiniteVolume pressure gradient, selected with VerticalReconstruction: ppm. It makes the scheme exact for resting profiles quadratic in pressure, not only linear ones, and it is more accurate than the linear reconstruction on most of the Polaris two-column tests. The linear reconstruction stays the default until a realistic configuration shows the gain is worth the cost. Builds on #635 and the design in #448; only the last six commits are new.


The design is revised here rather than in #448, which records it as it stood when the second-order scheme merged. The first three new commits update PGradHighOrder.md (rendered).

On sigma layers over the seamount, ppm makes the existing instability grow faster, which is one more reason linear stays the default.

The Polaris reference and tests are in E3SM-Project/polaris#902.

Checklist

  • Documentation:

  • Linting

  • Building

    • CMake build does not produce any new warnings from changes in this PR
  • Testing

    aurora, intel, mpich

    • CTests Pass
    • Polaris omega_pr Pass

    aurora, intelgpu, mpich

    • CTests Pass
    • Polaris omega_pr Pass

    chrysalis, intel, openmpi

    • CTests Pass
    • Polaris omega_pr Pass

    frontier, craygnu, mpich

    • CTests Pass
    • Polaris omega_pr Pass

    frontier, craygnu-mphipcc, mpich

    • CTests Pass
    • Polaris omega_pr Pass

    pm-cpu, gnu, mpich

    • CTests Pass
    • Polaris omega_pr Pass

    pm-gpu, gnugpu, mpich

    • CTests Pass
    • Polaris omega_pr Pass
  • Provide relevant details in a comment to the PR titled Testing

  • New tests:

    • CTest unit tests for new features have been added per the approved design.
    • Polaris tests for new features have been added per the approved design (and included in a test suite)

Posted by Claude Code on @xylar's behalf. The wording above is AI-authored; please check it accordingly.

🤖 Generated with Claude Code

xylar and others added 30 commits October 12, 2026 01:59
Rename PressureGradType::HighOrder1 to FiniteVolume and drop the
unimplemented HighOrder2, leaving a commented stub for a future variant.
Rename the functor class PressureGradHighOrder to
PressureGradFiniteVolume and the PressureGrad member HighOrderPGrad to
FiniteVolumePGrad.  Accept 'FiniteVolume' or 'finiteVolume' in place of
'HighOrder1' when parsing PressureGradType, and update the PGrad dev and
user guides accordingly.

The new scheme uses the same two-cell horizontal stencil as the centered
scheme and is second order, so naming the class for an order it does
not have would misdescribe what ships.  FiniteVolume names the
layer-integrated control-volume form instead.

This is answer-neutral: a pure rename plus a config-facing string change.
PressureGradCentered is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add HorzOrder, VerticalReconstruction and QuadraturePoints to the
PressureGrad configuration group, parsed and validated in the
PressureGrad constructor and cached on the PressureGradFiniteVolume
functor.  All three are optional, so a configuration written before they
existed still parses; where a key is absent the default
(HorzOrder 2, VerticalReconstruction 'linear', QuadraturePoints 2) is
used.

Reject values that are not implemented, such as HorzOrder 4 and
VerticalReconstruction 'ppm', with a clear "not implemented" error
rather than falling back silently, which would make a run requesting
them look like a run that used them.
QuadraturePoints is an accuracy knob only: the matched-pressure integrand
is zero pointwise on the exact set, so no quadrature rule can break the
robustness property.  There is no 'constant' reconstruction and no
setting that reduces the scheme to Centered.

Add accessors for the configured type and options, and extend PGradTest
with a parse and dispatch check that creates a FiniteVolume instance.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Widen PressureGrad::computePressureGrad and
PressureGradFiniteVolume::operator() to take the layer-mean conservative
temperature and absolute salinity and the Eos specific volume
derivatives.  PressureGradCentered is untouched: its operator() keeps its
existing signature and the Centered dispatch branch passes the same
arguments it always did.  Update the Tendencies call site to supply Theta
and S from the tracer array and the Eos instance it already holds.

Switch AuxiliaryState::computeMomVertAux to call
Eos::computeSpecVolAndDerivs in place of Eos::computeSpecVol when the
FiniteVolume scheme is selected.  computeSpecVolAndDerivs fills SpecVol
as well, so it replaces rather than accompanies computeSpecVol; the
branch keeps a Centered run from paying for the derivative arithmetic.

The FiniteVolume path is still a no-op, so Centered answers are
unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Assert design section 3.9's identity directly in PGradTest: with the
tidal and self-attraction-and-loading potentials zero,
PressureGradCentered is exactly -g/d_e times the fixed-pressure shift

   S = 1/2 (dZ_k + dZ_k+1) + alphaBar / (2 g) (dq_k + dq_k+1)

with dZ and dq the cross-edge differences of GeomZInterface and
PressureInterface.  The check runs over a sweep of interface tilts and is
scaled by the size of the hydrostatic terms the centered functor forms
and cancels, since agreement is to round-off rather than bit-for-bit.

Factor the two-column state construction out of the refinement loop into
setupTwoColumnState so the sweep can rebuild it at each tilt.  The
refinement loop is unchanged in what it computes.

This is the permanent regression test of design section 5.5, not a
transitional one.  Because the two expressions 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 pressure gradient arithmetic.  A guard
asserts that dropping the pressure half of S misses by far more than the
tolerance, so a pass cannot come from both sides being trivially equal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Make an unrecognized PressureGradType a fatal error instead of falling
back to the centered scheme with an informational message.  A silent
fallback turns a typo, or a configuration naming a scheme that no longer
exists such as the former 'HighOrder1', into a run that looks like a
passing centered run.  This is the same hazard unimplemented
sub-option values are already rejected for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add PGradRecon.h, holding the mean-preserving linear reconstruction of
conservative temperature and absolute salinity in pressure that the
FiniteVolume pressure gradient uses.  The slope is a centered difference
of the layer means with respect to mid-layer pressure, one-sided in the
shallowest and deepest valid layer of a column and zero where a column
has a single valid layer.

Differencing against the actual mid-layer pressures rather than against
layer index is what makes the estimator exact for a profile linear in
pressure on Omega's non-uniform vertical grid: the mean of a linear
function over a layer is its value at the layer's midpoint, so the layer
means lie exactly on the line as a function of mid-layer pressure.  A
formula that assumed uniform thickness would pass a uniform-thickness
test and fail on a real grid.

The deviation integrates to zero over the layer because PressureMid is
the exact arithmetic midpoint of the two interface pressures, which is
also what makes VertCoord's midpoint rule the exact layer integral of a
linear reconstruction and so spares VertCoord any change.  There is no
limiter.

The functions take scalars so they can be unit tested without a mesh.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Check the mean-preserving linear reconstruction on a single column,
without a mesh.  Layer means are sampled from a profile exactly linear in
pressure, so the recovered slope must match the profile's slope to
round-off in every layer, including the two that use a one-sided
difference.

The layer thicknesses are deliberately non-uniform, which is the case the
test exists for: a formula that assumed uniform thickness would pass the
uniform control that runs alongside and fail here.  Running both means a
failure says which of the two it is.

Also asserted are the two properties the scheme leans on: that the
reconstruction reproduces the layer mean at mid-layer pressure, and that
its deviation integrates to zero over the layer, by two-point Gauss
quadrature which is exact for a linear integrand.  A single-valid-layer
column must give a zero slope, a constant being the only mean-preserving
reconstruction available there.

This is worth testing separately because it is the most likely place for
the exactness gate to fail, and it localizes such a failure immediately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add PGradFiniteVolume.h with the first-order equation-of-state expansion
shared across an edge layer, built by averaging the two adjacent cells'
coefficients and reference states.  One set multiplies both columns,
which is what the robustness property rests on: give each column its own
expansion point and the alpha0 and alphaP terms no longer cancel in the
matched-pressure difference, and the scheme generates spurious flow out
of nothing but its own equation-of-state approximation.  Which set is
used is an ordinary accuracy question and cannot break exactness.

Add findLayerForPress to PGradRecon.h, the lookup that makes the scheme a
fixed-pressure comparison rather than a fixed-layer-index one.  At a
pressure in edge layer K each column supplies its state from whichever of
its own layers contains that pressure, which under tilt is generally not
layer K.  A pressure outside the column clamps to the outermost valid
layer and extrapolates its reconstruction, which is the rule where the
edge control volume extends past a column's own floor; exactness survives
extrapolation because an extrapolated reconstruction still reproduces a
resolved profile.

Pin the lookup with direct property tests, on a fabricated column pair
without a mesh.  These are not optional: no answer-level check anywhere
in the test plan can distinguish this from a layer-index lookup, since on
a profile linear in pressure every layer's reconstruction is the same
line and looking up the wrong layer costs nothing.  The tests assert that
the returned layer brackets the pressure, that it differs from the edge
layer index by up to three layers so the lookup is demonstrably not an
index lookup, that the answer is independent of the starting hint so the
column scan's incremented cursors cannot disagree with a search, and that
a pressure outside the column clamps to the outermost valid layer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add matchedPressSpecVolDiff, the central quantity of the scheme: the
difference in specific volume between an edge's two columns, evaluated at
one pressure with one shared expansion.  Because both columns use the
same expansion, the SpecVol0 and SpecVolDP terms are identical and cancel,
leaving a coefficient times the horizontal contrast in reconstructed
temperature and salinity at matched pressure.  Compressibility drops out
entirely, which is correct physics rather than an approximation: a
horizontally uniform compressibility exerts no horizontal pressure
gradient.

Add the Gauss-Legendre rule for 1 to 4 points, and move
MaxPGradQuadPoints alongside it.  The number of points is an accuracy
setting only, since the integrand is zero at every point on a resolved
profile.

Unit test on a fabricated column pair, without a mesh, exercising the
reconstruction, the pressure lookup and the shared expansion together.
Both columns' layer means are the exact layer averages of one prescribed
continuous profile, so under the offset between the columns those means
genuinely differ.  On a profile linear in pressure the integrand is zero
at every quadrature point, not merely in the integral, measured at
5.8e-21 m3/kg or 0.9 eps of the terms that had to cancel.  A quadratic
profile runs as a control and gives 5.3e-10 m3/kg, eleven orders larger,
so the linear result is not a statement that everything in the test is
zero.  The tolerance is scaled by the cancelling terms rather than being
an absolute constant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Accumulate the fixed-pressure height difference down each edge's column,
into a per-edge array of interface values.  This is a prefix sum with
edge-dependent coefficients, so it is not expressible as an independent
per-vertical-chunk operation and cannot live in the functor; it is the one
structural addition beyond the per-edge, per-chunk pattern the centered
scheme uses.  It runs as a parallelForOuter over edges with a
parallelScanInner down the column, in the same shape as
VertCoord::computeGeomZHeight.

The scan runs in two passes.  The first evaluates the matched-pressure
integrand at each edge layer's quadrature points and forms two integrals
of it over the same points: the increment of the recurrence, and its
first moment about the layer's top interface, which the layer mean will
need.  The second anchors the column and turns the increments into the
height difference at every interface.  The per-cell reconstruction slopes
are computed once and reused across each cell's edges, so the per-edge
work is polynomial arithmetic on cached values.

Anchor at the sea floor, per design section 3.7.4, which leaves the end
open and prefers this one on conditioning grounds.  There turns out to be
a second and stronger reason.  VertCoord builds geometric height by
accumulating a midpoint rule over each column's own layers, and on a
curved profile two columns with different layer partitions give sums that
differ at second order in layer thickness.  Anchored at the surface that
discrepancy enters the height difference directly and the exactness gate
would not be machine-zero; anchored at the sea floor over a flat floor the
height difference is exact input and vanishes identically, and the
discrepancy never enters, because the scheme integrates its own
reconstruction rather than accumulating VertCoord's height.  This is a
prediction to be checked against the measurement.

The anchor is computed, not assumed: each column's height at the deepest
shared interface is shifted to the common pressure by integrating its own
reconstruction over half the cross-edge pressure difference, and both
short integrals vanish where the two columns' interface pressures agree.

Test that the height difference is zero at every interface, not merely in
the layer mean, on a two-column state whose layer means are the exact
layer averages of one profile linear in pressure -- so that under the
offset between the columns those means genuinely differ.  The shape of a
failure is reported as well as its size, since a residual growing with
depth points at the recurrence while one flat with depth points at the
anchor.  The tolerance is provisional pending the first measurement.

Allocate the working arrays only when the FiniteVolume scheme is
selected, so a Centered run pays no memory for them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Turn the column scan's output into the tendency: form the layer mean of
the fixed-pressure height difference from its value at the layer's bottom
interface and the first moment of the integrand over the layer, scale by
-g/d_e, subtract the tidal and self-attraction-and-loading difference, and
accumulate into Tend with EdgeMask exactly as the centered functor does.
The edge control volume's pressure thickness is exactly the edge average
of the two columns' own.

This is the first point at which the FiniteVolume scheme produces a
number.

Narrow the functor's arguments to the two arrays the column scan fills.
Design section 4.1.3's illustrative signature lists the temperature,
salinity and specific volume derivative arrays, but it also omits the
scan's own array while describing the functor as reading it "like any
other input", so it is not self-consistent.  With both integrals formed
in the scan over one set of quadrature points, which section 3.5.1
requires, the functor reads none of the state the scan consumed; passing
it would only invite evaluating the integrand a second time.

Report the tendency on the exact-set state alongside PressureGradCentered's
on the same state, and require the centered value to be nonzero, so that
the FiniteVolume result is a cancellation against a known nonzero
reference rather than a comparison with zero.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The gating test of design section 5.2, in three groups.

Exactness.  On a two-column state whose layer means are the exact layer
averages of one profile linear in pressure, with a horizontally uniform
surface pressure, the tendency and the fixed-pressure height difference
must both be zero to machine precision.  Measured at commit 10: tendency
1.6e-18 m/s2 against PressureGradCentered's 1.6e-05 m/s2 on the same
state, and height difference 6.7e-16 m, both 0.027 eps of the terms that
had to cancel.  The gates replace commit 9's provisional value with four
eps, which leaves over a hundredfold margin while still catching drift,
and they track Real's epsilon and the size of the hydrostatic terms
rather than a physical tolerance.  Absolute tendencies are reported
alongside the centered scheme's, so a pass is a cancellation of thirteen
orders against a known nonzero reference.  The maximum is the right norm
here, since the claim is a zero at every edge and layer.

Convergence.  Quadratic and cubic profiles, which the linear
reconstruction does not resolve, over 15, 30 and 60 layers at fixed tilt.
The residual must shrink at second order in layer thickness; a rate below
that means one of the scheme's conditions has been broken somewhere and
is a bug to find, not a tolerance to widen.  The rate is measured on the
RMS rather than the maximum: a maximum is set by whichever layer happens
to be worst, and that layer moves under refinement, which makes the rate
noisy and non-monotone.  RMS is also the norm the design's measured rates
were taken in, so the two are comparable.

Guards.  Guard (a), tilt sensitivity, runs on the kernel and is the only
one that can fire where every other check passes.  Guards (b), (c) and
(d) need the scheme's rules switched off one at a time, so they run
against a host reference assembled from the same helper functions the
kernel uses.  That reference is only trusted after it reproduces the
kernel, and the fidelity check that has content is on a curved profile
where both sides are large -- agreeing at 1e-18 on the exact set would
also be satisfied by a harness that computed nothing.  Note that the
reference shares the helper functions, so the guards establish that the
three rules are load-bearing rather than independently verifying the
arithmetic; that verification comes from the centered identity and from
the Omega-versus-Polaris comparison.

Guard (b), a cell-local expansion point, must fire: two expansion points
mean the SpecVol0 and SpecVolDP terms no longer cancel.  Guard (d), the
anchor taken as the raw height difference, must fire where the two
columns' end pressures differ and must be flat with depth, which is what
distinguishes it from (b); at a sea-floor anchor that means a surface
pressure contrast reaching the bottom interface.

Guard (c), a layer-index lookup in place of the pressure lookup, is
recorded rather than required to fire.  It cannot fire on the exact set,
because the profile is a single line in pressure and every layer's
reconstruction is that same line, so writing it as a guard that must fire
would assert something false.  It is logged either way, and if it ever
does fire an answer-level check on the lookup has become available.  Until
then the lookup is pinned only by the property tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add PGRAD_SINGLE_PRECISION_TEST, which builds PGradTest against the
single-precision library.  Design section 3.7.5 predicts the exactness
gate should pass there: the scheme differences the integrand before
integrating it, so every quantity in the column scan is already a
horizontal contrast and no large quantity is formed anywhere.  Running
PressureGradCentered alongside, which does form and cancel quantities of
order a hundred metres, is what makes the result interpretable.

The gate is loosened from four epsilons to sixteen in single precision.
A build with fewer guard digits accumulates more round-off down the
column, so the same measurement in epsilons is expected to be somewhat
larger; the tolerance moves with that rather than the claim changing.

Skip the convergence rates and guards (b) to (d) in single precision.
Those measure truncation errors, and this build cannot resolve them: the
round-off floor of the tendency is about 3e-8 m/s2, which swamps the
quadratic profile's residual at 60 layers and leaves only a factor of ten
between guard (b)'s signal and the noise.  They are statements about the
discretization rather than about precision, so measuring them once in
double precision is enough.  The exactness gate and guard (a) run in
both, which is what design section 5.2 asks for.

Make the matched-pressure integrand's control a ratio of the quadratic
result to the linear one rather than a count of epsilons.  In single
precision the linear result rises with the round-off floor while the
quadratic one, being a truncation error, does not, so an absolute epsilon
count would fail for a reason that has nothing to do with the property
being tested.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Instrument Eos with a count of specific-volume evaluations, one per cell
per active layer per call, and assert against it in PGradTest.

Requirement 2.2 of the design bounds the number of equation-of-state
evaluations at about one per cell per layer per step, independent of the
reconstruction order, the stencil width and the quadrature.  Nothing else
in the test suite would notice that being violated: an evaluation inside
the quadrature loop would change run time without changing any answer, so
every accuracy gate would still pass.

The check is sharper than the requirement.  The pressure gradient
performs no equation-of-state evaluations at all -- the one per cell per
layer the requirement allows is paid once by AuxiliaryState, before the
tendency is computed, and the scheme works from the specific volume and
derivatives that call leaves behind.  So the count across a call to
computePressureGrad must be exactly zero, and it is asserted at
QuadraturePoints 1 through 4, the quadrature being where a call would
most naturally creep in.

A count of zero would also be produced by broken instrumentation, so the
test additionally confirms that one call to computeSpecVolAndDerivs
registers exactly one evaluation per cell per layer.

This is a counter comparison rather than a timing measurement, so it is
deterministic and suitable for continuous integration.  The wall-time
comparison against PressureGradCentered remains a separate, non-CI
measurement for the pull request description.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bring the PGrad dev and user guides up to what ships.

The user guide gains the three sub-options and their defaults, and says
plainly that QuadraturePoints is an accuracy setting only, since the
integrand is zero at every point on a resolved profile and no quadrature
rule can affect the exactness.  It records that unimplemented values
are rejected rather than falling back, that an unrecognized PressureGradType
aborts, and that no setting reduces the finite-volume scheme to the
centered one.

The dev guide gains four things the code alone does not make obvious: why
the per-edge column scan cannot live in the functor, that it anchors at
the sea floor and why, that each column's state is looked up by pressure
rather than by layer index -- with the warning that no answer-level test
can catch getting that wrong, so the property tests pinning it are not
optional -- and that the equation-of-state expansion is shared across each
edge, with what is and is not load-bearing about that.

Also correct the computePressureGrad call signature in the dev guide,
which described arguments the method has never taken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The dispatch check in PGradTest asserted only that the tendency came out
finite, which is weak enough to pass on garbage: a specific volume
derivative array still holding the fill value its field was attached
with, 9.969e36, propagates through the arithmetic without overflowing a
double.

Require instead that the tendency be nonzero and no more than three
orders of magnitude larger than PressureGradCentered's on the same state.
The bound is one-sided on purpose.  The two schemes agree to second order
in the cross-edge pressure difference, which limits how much larger the
finite-volume answer can be but says nothing about how much smaller; on a
state whose profile is close to linear in pressure it is legitimately far
smaller, which is the whole point of the scheme.  A fill value misses the
upper bound by thirty orders, in either precision.

Also check the result of every PressureGrad::create in this test.  create
returns null if an instance of that name already exists, and
dereferencing that gives a segmentation fault with no message rather than
a diagnosable failure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Make computeReconSlopes and computeColumnScan public.  nvcc rejects an
extended host-device lambda whose enclosing function is private or
protected in its class, which broke the build on GPUs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Template buildEdgeEos on the array type, as findLayerForPress already
is.  PGradTest's host-side reference scan calls it with host arrays,
which are the same type as device arrays on CPUs but not on GPUs, so
PGradTest would not have compiled with nvcc.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The counter only saw host-side calls to the Eos compute methods, which
the pressure gradient cannot make through its const Eos pointer. An
evaluation inside the quadrature loop would be a device-side call the
counter never sees, so the cost check could not catch the regression it
was written for. Remove the counter, the check and the references to it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Launch the reconstruction slopes and the matched-pressure integrals as
team loops over each column's active layers, as the other pressure
gradient kernels do, instead of flat loops over every layer that skip
the inactive ones. The integrals now share the column scan's per-edge
team, with a barrier before the scan, so the two passes run as one
kernel. Nothing reads these arrays outside the active layers, so the
inactive entries no longer need zeroing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pressure gradient is exact for linear-in-pressure water only where
the two columns' sea floors are at the same pressure. Over a sloping
floor the sea-floor anchor leaves a residual that grows with the cube
of the floor pressure difference, and on terrain-following layers it
approaches the centered scheme's error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Where the two columns' floors are more than a layer apart in pressure, as
with terrain-following layers over a steep slope, compare the shallower
floor with the deeper column's own interface just below it, then carry
the anchor down to the edge's deepest interface with the matched-pressure
integrand. Shifting both floors to their mean pressure with one
first-order expansion left an error that grows with the cube of the
offset and is the same at every depth.

Where the floors are within one layer of each other, on a flat floor or
where partial bottom cells cut a sloping one, the anchor is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A resting, linear-in-pressure state on terrain-following layers whose
floors are 6.4 layers apart. The host reference mirrors the new anchor
and must reproduce the kernel, the tendency must stay well below the
centered scheme's, and the mean-pressure anchor must fail that gate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
xylar and others added 23 commits October 25, 2026 11:25
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
…dition

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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
The pressure gradient holds a const Eos pointer, so it cannot call the
Eos compute methods, and a counter in those methods could not see an
evaluation inside the device-side quadrature loop. Rest the cost
requirement on the interface and the wall-time check instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The finite-volume pressure gradient is now implemented (Omega E3SM-Project#493,
with the anchor refined in E3SM-Project#635), so describe what that code does:

- FiniteVolume is the default and Centered is kept as an option and a
  cross-check; the requirement no longer fixes the default.
- The sea-floor anchor's shift to a common pressure never spans more
  than one layer: the shallower floor is compared with the deeper
  column's own interface just below it, then carried down with the
  matched-pressure integrand.  Exactness is qualified to columns whose
  floors share depth and pressure.
- The column scan is two passes in one team per edge, filling three
  per-edge arrays, after a separate kernel forms the reconstruction
  slopes; the layer mean uses the first moment, not a second one.
- Record the reconstruction estimator, the option validation, where
  the Eos derivatives are computed, and the two helper headers.
- Fix the algorithm summary, which still scanned from the sea surface.
- Say where the fourth-order scheme attaches to this code.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Add the sloping-floor anchor test and its guard to the unit test
  section, and name the unit test's parts.
- Replace the August seamount figures with the runs made with tracer
  diffusion explicitly off, and record what has been ruled out as the
  cause of the sigma instability: the anchor, unlimited tracer
  advection and vertical resolution.  It tracks the slope.
- Record the 10-day realistic global run, which supports A4 over the
  open ocean, and the measured cost of the pressure gradient.
- Note that the Omega-vs-Polaris check caught the anchor rule, that
  only an overflow smoke test has been run, and which horiz_press_grad
  steps the anchor rule changes.
- Close the harness limits that the Polaris task runs have since
  covered, and update the coverage summary.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PGrad.md records the reasoning behind the centered pressure gradient
as it was developed, so restore its text and keep only one change:
the sentence promising a future design document now points to the
higher-order design, which also revises the form given there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The functor's inputs now match the design's signature, so drop the claim
that they differ and keep only the reason. The sea-floor anchor is chosen
for exactness, not conditioning, as design section 3.7.4 now says.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bring in the design document (design branch at 6fbe875), which also
brings this branch up to develop at 23b13af.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Choose the unlimited piecewise parabolic method of Colella and
  Woodward: interface values from the polynomial through the
  cumulative integral at the five nearest interfaces, built from
  divided differences of the layer means, and a mean-preserving
  parabola through them.  Short columns take the polynomial through
  all their interfaces.
- At the ends of a column take the coefficients from that
  polynomial's own derivatives at the layer midpoint, so a thin
  bottom cell does not amplify round-off when its reconstruction is
  extrapolated below the floor.
- Record the measurements behind the choice over a parabola fitted to
  three layer means, and what the default two-point rule costs the
  parabolic reconstruction.
- Say what the reconstruction adds to the tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The parabolic reconstruction ships first, on its own with the
  two-cell stencil, then the wide stencil, then the second-order
  equation-of-state expansion; in each, Polaris gains the change
  first, written from the design.
- The second-order expansion is kept unless measurement with the
  parabolic reconstruction and the wide stencil shows it does not
  help.
- The defaults stay linear with the two-cell stencil until a realistic
  configuration shows the gain is worth the cost.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Confirm the parabolic reconstruction in Omega: the unit test, the
  ten horiz_press_grad variants against the Polaris kernel, and the
  seamount for six days.
- On the sigma seamount it makes the instability grow three to five
  times faster; record that where the instability is described.
- Qualify the third-order statement of section 6.7, whose refinement
  holds the displacement at a fixed number of layers, against the
  rates the unit test measures at fixed tilt.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
VerticalReconstruction: ppm now selects the unlimited piecewise
parabolic method that the design specifies. Each layer's parabola keeps
the layer mean and takes, at its interfaces, the derivative of the
polynomial through the cumulative integral at the five nearest
interfaces, built from divided differences of the layer means. Short
columns use the polynomial through all their interfaces, and at the ends
of a column the coefficients come from that polynomial's own derivatives,
so a thin bottom cell does not amplify round-off when it is extrapolated
below the floor.

The column scan's three evaluation sites -- the integrand of each edge
layer, the anchor's short integrals and its carry-down -- all go through
one function, reconEval, so they cannot describe different water. The
linear reconstruction is evaluated exactly as before and remains the
default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The estimator on a single column: a quadratic reproduced everywhere,
  beyond the column included; a cubic met at every interface; the
  layer integral of the deviation; columns of one to three layers; and a
  thin bottom cell extrapolated below the floor, against the interface
  form, which this test shows amplifying round-off.
- The matched-pressure integrand zero at every quadrature point on a
  quadratic, with a cubic as the control.
- On the two-column state: the exactness gate on linear and quadratic
  profiles in both precisions, the linear reconstruction as the control,
  the host assembly's fidelity to the kernel, and a cubic converging
  faster than with the linear reconstruction.

The host assembly now evaluates the reconstruction through reconEval,
as the kernel does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The user guide gives VerticalReconstruction's two values and what 'ppm'
makes exact. The developer guide describes how the coefficients are
formed, why the end layers take theirs from the polynomial's own
derivatives, and that every evaluation goes through reconEval, and it
lists the curvature arrays.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@xylar

xylar commented Oct 25, 2026

Copy link
Copy Markdown
Author

Testing

Chrysalis, Intel, OpenMPI: CTests 62/62 at 88631ec, including the new parabolic tests in double and single precision, with no new build warnings. With E3SM-Project/polaris#902, run on an earlier build of the same model source, all 10 horiz_press_grad tasks pass with ppm as a third scheme, Omega matching the Polaris parabolic reference to 1.6e-13 m/s², and all 224 centered and linear forward steps are bit-for-bit with #635. omega_pr has not been run.

/lcrc/group/e3sm/ac.xylar/polaris_1.2/chrysalis/test_20261025/fv-ppm
/lcrc/group/e3sm/ac.xylar/polaris_1.2/chrysalis/test_20261025/fv-ppm-seamount

Posted by Claude Code on @xylar's behalf. The testing, analysis and wording above are AI-authored; please check them accordingly.

@xylar

xylar commented Oct 25, 2026

Copy link
Copy Markdown
Author

What the parabolic reconstruction does

two-column refinement

Against the quasi-analytic reference, ppm is 2.8 to 3.0 times more accurate than linear where the coordinate tilts the layers, and 1.5 times where surface pressure does, at every resolution. With level layers (temperature_gradient and salinity_gradient, not shown) the two are the same.

resting states, tilted layers

At rest, any tendency is error. With T and S quadratic in pressure, ppm brings it down to 1 to 4% of Centered's, close to the floor both reconstructions reach when T and S are linear in pressure, which comes from the sea-floor anchor rather than the reconstruction. At the steepest tilts linear is sometimes 1.6 times better. On the curved profile ppm is 1.4 to 2.6 times more accurate.

resting states, stepped floor

Over a stepped sea floor with T and S quadratic in pressure, ppm is 74 to 1.5×10⁷ times more accurate than linear. On the curved profile it is up to 960 times more accurate on 128 m layers, but up to 3 times less accurate on 256 m layers, where the profile's curvature jumps inside the bottom layers' window.

seamount

On the z-star seamount, kinetic energy after 6 days is 3.7 times lower with ppm. On sigma layers ppm makes the existing instability grow faster: between 6 hours and 1 day, mean kinetic energy grows at an e-folding rate of 11.6 per day with the exponential profile, against 2.3 with linear, and 7.9 against 2.8 with T and S linear in pressure. These runs use the seamount stratification variants on Polaris's fv-pgf-integration branch, with the finite-volume runs switched to ppm.

Scripts: https://web.lcrc.anl.gov/public/e3sm/diagnostic_output/xasaydavis/fv_hpg_ppm_20261025/scripts/


Posted by Claude Code on @xylar's behalf. The figures, analysis and wording above are AI-authored; please check them accordingly.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request Omega

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants