EOS and Vertical-Coordinate Variants of the Overflow Tasks

date: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

Summary

The overflow task family currently supports only the linear equation of state (EOS) with the z-star vertical coordinate. Instabilities have been observed in realistic-global tests, which use the p-star vertical coordinate together with a nonlinear EOS (TEOS-10 in Omega). This work adds variants of all overflow tasks that mirror that configuration in a small, idealized, fast-running setting, so that the two new ingredients (nonlinear EOS and p-star coordinate) can be varied independently:

z-star init

p-star init

linear EOS

existing tasks (baselines preserved)

coordinate discriminator

nonlinear EOS

not included

mirrors realistic-global

The nonlinear EOS is TEOS-10 for Omega and Jackett-McDougall (jm) for MPAS-Ocean.

The result is three task trees under ocean/planar/overflow/, each with its own shared config file and its own shared init step. Paths have two levels below overflow — the EOS type, then the vertical coordinate — for symmetry and so more combinations can be added later:

ocean/planar/overflow/
├── linear/
│   ├── zstar/      # existing tasks: z-star + linear EOS (answers unchanged)
│   │   ├── init                                  (shared step)
│   │   ├── smoke_test_horiz_adv_order_{2,3,4}
│   │   ├── smoke_test_horiz_adv_order_{2,3,4}_del4
│   │   └── rpe
│   └── pstar/      # p-star init + linear EOS
│       └── (same tasks)
└── nonlinear/
    └── pstar/      # p-star init + TEOS-10 (Omega) / jm (MPAS-Ocean)
        └── (same tasks)

This is 21 tasks total (7 per tree). The linear/zstar tree is the current set of tasks with only the path changed; its answers must not change during the refactoring. Since the goal is debugging, the full matrix makes it possible to bisect where problems enter. The smoke tests are the primary debugging vehicle. The RPE tasks are included in the new trees for completeness but are too expensive to run routinely; if supporting them under p-star or the nonlinear EOS proves difficult, they can be deferred without blocking the rest of this work.

A follow-on piece of this work re-enables vertical mixing in all three trees. It is only partially related to the EOS and coordinate variants but serves the same purpose: making the overflow tasks resemble the realistic-global configurations where instabilities are being seen, which run with CVMix-style vertical mixing enabled. The compass version of the overflow test ran with constant background mixing and convective mixing; these were disabled in the Polaris port (PR #572) because Omega had no vertical-mixing support at the time. Omega’s VertMix now provides both, so background and convective mixing are restored for both models, matching the compass configuration. (An interim background-only configuration was tried, but when bottom drag is enabled, plume overrides the ambient bottom water at its nose, creating static instability that only convective mixing removes; review therefore restored convection and reduced the bottom-drag coefficient, see below.) Unlike the refactoring, this change is intentionally answer-changing (see the answer-preservation requirement, which is scoped to the commits before vertical mixing is enabled).

Success means: the linear/zstar tree is bit-for-bit with the current tasks before vertical mixing is enabled, the two new trees set up and run their smoke tests with both models, vertical mixing is active in both models in all three trees, and the shared framework pieces (a TEOS-10 EOS config and a p-star state-conversion module) are reusable by the realistic-global initialization work.

Requirements

Requirement: A shared mechanism for selecting a nonlinear EOS

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

Tasks must be able to select a nonlinear EOS via a shared config file, in the same way polaris.ocean.eos linear.cfg and constant.cfg select the linear and constant EOS today. The forward step must translate this selection into valid model config options for both Omega (TEOS-10) and MPAS-Ocean (Jackett-McDougall, the closest available nonlinear EOS), without requiring the linear-EOS options to be defined.

Requirement: Overflow initial conditions on the p-star coordinate

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

The overflow initial condition (tanh shelf bathymetry, a block of cold water on the shelf, constant salinity, quiescent velocity, zero surface pressure) must be producible on the p-star vertical coordinate, with output files compatible with the existing overflow Forward, Viz, and RPE Analysis steps (same filenames and required variables).

Requirement: Model-specific tracer and state conversions are shared framework code

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

The conversions from a converged p-star state to model input files — layer thickness from geometric interfaces, quiescent velocity, density from specific volume, and conversion of conservative temperature / absolute salinity to MPAS-Ocean’s potential temperature / practical salinity — must live in a shared, dependency-light framework module so that both the overflow p-star init and the realistic-global initialization (on the add-realistic-ocean-init branch) can use them.

Requirement: Existing overflow answers are preserved during refactoring

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

The existing z-star + linear-EOS tasks move to ocean/planar/overflow/linear/zstar/ with no answer changes. Test suites that reference the old paths must be updated.

This requirement is scoped to the refactoring and variant commits. The subsequent vertical-mixing commit (next requirement) intentionally changes answers in all three trees and requires baselines to be re-blessed.

Requirement: Vertical mixing uses background and convective mixing

Date last modified: 2026/07/24

Contributors: Xylar Asay-Davis, Claude

The overflow tasks must run with the constant background and convective vertical mixing that the compass version of the test used (background diffusivity 1.0e-5 m²/s, viscosity 1.0e-4 m²/s; convective diffusivity and viscosity 1.0 m²/s), with shear mixing off, in both MPAS-Ocean and Omega. The configuration must work with the RK4 time integrator and with both the linear and nonlinear EOS.

Algorithm Design

Algorithm Design: A shared mechanism for selecting a nonlinear EOS

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

No new algorithms. Omega’s Eos.cpp accepts teos10, teos-10, and TEOS-10 for EosType, so the Polaris eos_type = teos-10 value passes through unchanged. MPAS-Ocean has no TEOS-10 option; its Jackett-McDougall EOS (config_eos_type = jm) is used as a documented approximation. Polaris-side (Python) density calculations use TEOS-10 via the gsw package for both models; the initial-condition density is diagnostic only (neither model reads it), so the TEOS-10-vs-jm mismatch for MPAS-Ocean is acceptable.

Algorithm Design: Overflow initial conditions on the p-star coordinate

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

The p-star initialization uses the fixed-point iteration from the p-star init design (PStarInitStep.run_pstar_init()) with zero surface pressure. The overflow tracer profile (cold block on the shelf, constant salinity) is evaluated at the current p-star layer midpoints each outer iteration and interpreted as conservative temperature (CT) and absolute salinity (SA).

Because pseudo-depth is not geometric depth (\(dz_{geom} = \nu \, \rho_{sw} \, d\tilde{z}\), with specific volume \(\nu\) and \(\rho_{sw} = 1026\) kg m\(^{-3}\)), the pseudo grid must reach deeper than the pressure at the deepest geometric bathymetry or the domain would be artificially truncated. The pseudo-depth needed for the 2000 m geometric bottom is roughly \(2000 \, \bar{\rho} / \rho_{sw}\): ~1950 m for the linear EOS (mean density ≈ 998 kg m\(^{-3}\) with the shared linear.cfg values) and ~2015 m for TEOS-10 (in-situ density up to ~1037 kg m\(^{-3}\) at depth). The pseudo grid is therefore 2400 m deep (~19% buffer over the worst case) with 72 uniform levels, preserving the ~33.3 m layer spacing of the 60-level, 2000 m z-star grid while making the number of levels a multiple of 16, which is preferred for Omega performance. This mirrors the buffer used in horiz_press_grad (576 m pseudo bottom for a 500 m geometric bottom).

Algorithm Design: Model-specific tracer and state conversions are shared framework code

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

Omega receives CT and SA directly. For MPAS-Ocean, CT is converted to potential temperature via gsw.pt_from_CT and SA to practical salinity via gsw.SP_from_SA, with pressure from the p-star product. The SP_from_SA conversion needs a nominal longitude/latitude on a planar mesh; this defaults to (0°, 0°) and is exposed as config options.

Note that the add-realistic-ocean-init branch currently uses gsw.t_from_CT (in-situ temperature); MPAS-Ocean expects potential temperature, so the shared helper uses pt_from_CT and that branch picks up the fix when it adopts this module.

Algorithm Design: Vertical mixing uses background and convective mixing

Date last modified: 2026/07/24

Contributors: Xylar Asay-Davis, Claude

No new algorithms in Polaris; both models already implement the needed schemes. MPAS-Ocean uses CVMix with the constant background scheme. Omega’s VertMix provides the equivalent constant Background diffusivity/viscosity, plus the matching Convective mixing. Omega applies the mixing implicitly via a tridiagonal solve, operator-split at the end of each step in all its time steppers (including RungeKutta4), so no time-step or EOS-specific changes are needed. Convective mixing is enabled in both models (matching compass); shear mixing remains off.

Bottom drag: both models run with explicit bottom drag (coefficient 1.0e-3). MPAS-Ocean uses config_bottom_drag_mode = explicit; Omega has no equivalent of the bottom-drag mode option, so its BottomDragTendencyEnable is turned on through the mapped MPAS-Ocean debug flag (config_disable_vel_explicit_bottom_drag = false in the shared debug section of forward.yaml) — an interim approach suggested in review. Omega’s implicit bottom drag is pending (polaris #659, Omega #469); once that merges, both models are expected to switch to implicit drag, and whichever PR merges second will need a small rebase of this configuration.

Implementation

Implementation: A shared mechanism for selecting a nonlinear EOS

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

A new shared config file polaris/ocean/eos/teos10.cfg contains only

[ocean]
eos_type = teos-10

(no linear parameters). OceanModelStep.update_namelist_eos(), which currently reads the eos_linear_* options unconditionally, is restructured to branch on eos_type:

  • linear / constant: current behavior (read eos_linear_*, map constantlinear for MPAS-Ocean, reject nonzero Tref/Sref for Omega).

  • teos-10: for MPAS-Ocean, set config_eos_type = jm and do not touch config_eos_linear_*; for Omega, pass teos-10 through unchanged. The eos_linear_* options are not read at all.

Implementation: Overflow initial conditions on the p-star coordinate

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

A new PStarInit(PStarInitStep) step in polaris/tasks/ocean/overflow/pstar_init.py:

  • builds the same planar hex mesh as the existing Init step, culls it, and adds Coriolis via a helper in the shared init_utils module factored out of Init.run(); writes base_mesh.nc, culled_mesh.nc, and culled_graph.info;

  • computes geom_z_bot from the existing tanh shelf profile;

  • uses zero surface pressure;

  • implements init_tracers() as the existing cold-block-on-the-shelf profile evaluated at the current p-star layer midpoints, interpreted as CT/SA;

  • after run_pstar_init() converges, uses the shared state-conversion helpers to add layer thickness, quiescent velocity, and density, converts tracers for MPAS-Ocean, and writes vert_coord.nc and init.nc with the same filenames as the existing Init step so Forward, Viz, and Analysis need no retargeting.

add_overflow_tasks() loops over the three variants:

subdir

EOS cfg

init step class

coord

planar/overflow/linear/zstar

linear.cfg

Init

z-star

planar/overflow/linear/pstar

linear.cfg

PStarInit

p-star

planar/overflow/nonlinear/pstar

teos10.cfg

PStarInit

p-star

Each variant gets its own PolarisConfigParser and its own shared init step, and the same set of smoke-test and RPE tasks as today. A new overflow_pstar.cfg adds the p-star [vertical_grid] overrides (including the 2400 m / 72-level pseudo grid) for the two p-star trees. The p-star iteration uses the shared ocean.cfg defaults (pseudothickness_iter_count = 6, water_col_adjust_frac_change_threshold = 1.0e-12).

forward.py / forward.yaml are expected to be unchanged: update_eos=True already routes EOS settings through update_namelist_eos(), and horiz_press_grad demonstrates that Omega needs no extra VertCoord settings in the forward yaml for p-star (the coordinate comes from vert_coord.nc). MPAS-Ocean runs its usual coordinate initialized from the converged geometric thicknesses.

In passing, two pieces of cleanup in overflow.cfg:

  • The [overflow] options eos_linear_beta and eos_linear_Sref are dead leftovers from the compass port (the shared linear.cfg [ocean] section is the source of truth) and are deleted.

  • rpe/analysis.py reads min_temp and max_temp from [overflow_rpe], which never defines them, so the RPE analysis step would fail at runtime today. They are added following the baroclinic_channel precedent, tracking the initial-condition temperatures.

Implementation: Model-specific tracer and state conversions are shared framework code

Date last modified: 2026/07/23

Contributors: Xylar Asay-Davis, Claude

Dependency-light helpers factored out of InitialStateStep on the add-realistic-ocean-init branch, in a new polaris/ocean/init_state/ package (per review feedback: the helpers are general initial-state utilities, not p-star specific, and a package rather than a single module leaves room to grow without bloat; one small module per concern):

  • thickness.py: layer_thickness_from_geom_interfaces(ds)restingThickness and layerThickness from converged GeomZInterface, masked by cellMask;

  • velocity.py: add_quiescent_normal_velocity(ds, ds_mesh) — zero normalVelocity;

  • density.py: add_density_from_specvol(ds)Density = 1 / SpecVol with attributes.

All three are re-exported from polaris.ocean.init_state.

The CT/SA conversion helper convert_tracers_to_mpas_ocean(ds, lon, lat) — CT → potential temperature via gsw.pt_from_CT and SA → practical salinity via gsw.SP_from_SA, with pressure from the p-star product — lives in polaris/ocean/eos/teos10.py and is exported from polaris.ocean.eos (per review feedback: it is an EOS/tracer-convention conversion, so developers should find it with the other TEOS-10 code rather than reimplementing it).

When add-realistic-ocean-init merges, its InitialStateStep is refactored to call these (a follow-up on that branch).

Implementation: Existing overflow answers are preserved during refactoring

Date last modified: 2026/07/23

Contributors: Xylar Asay-Davis, Claude

The existing tasks keep their step and task classes; only the task directory changes from planar/overflow to planar/overflow/linear/zstar. The overflow paths in polaris/suites/ocean/omega_nightly.txt, omega_pr.txt, and mpaso_pr.txt are updated accordingly. In addition, one new suite entry is added (per review feedback, to keep TEOS-10 coverage in PR testing until more tests use it): planar/overflow/nonlinear/pstar/smoke_test_horiz_adv_order_4_del4 in both mpaso_pr.txt and omega_pr.txt.

Implementation: Vertical mixing uses background and convective mixing

Date last modified: 2026/07/24

Contributors: Xylar Asay-Davis, Claude

The change is config-only. In the shared ocean: section of polaris/tasks/ocean/overflow/forward.yaml, the cvmix options that Polaris maps to Omega’s VertMix config restore the compass background and convective mixing values, with shear mixing off:

  cvmix:
    config_use_cvmix_convection: true
    config_cvmix_convective_diffusion: 1.0
    config_cvmix_convective_triggerBVF: 0.0
    config_use_cvmix_shear: false
    config_cvmix_background_diffusion: 1.0e-5
    config_cvmix_background_viscosity: 1.0e-4

The mpas-ocean: section adds the MPAS-only master switch with no Omega equivalent (config_use_cvmix = true; the background scheme already defaults to constant) and the MPAS-only convective viscosity (config_cvmix_convective_viscosity = 1.0; Omega uses a single convective coefficient for both diffusivity and viscosity). Omega’s tendency enable flags (VelVertMixTendencyEnable, TracerVertMixTendencyEnable) already default to true, so no yaml change is needed for them.

In passing, the cvmix [VertMix, Shear] entry in polaris/ocean/model/mpaso_to_omega.yaml is corrected: it mapped the MPAS-Ocean Pacanowski–Philander parameter names (config_cvmix_shear_PP_*NuZero/Alpha/Exponent), but Omega’s shear scheme is the LMD94/KPP interior scheme, so the KPP names are the correct correspondence (config_cvmix_shear_KPP_nu_zeroBaseShearValue, config_cvmix_shear_KPP_Ri_zeroRiCrit, config_cvmix_shear_KPP_expExponent). No current test sets the PP options, so this mapping fix changes no answers.

Testing

Testing and Validation: A shared mechanism for selecting a nonlinear EOS

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

Unit tests cover update_namelist_eos() for all eos_type × model combinations. Manual testing: set up and run the smoke tests from the nonlinear/pstar tree with both models (where builds are available).

Testing and Validation: Overflow initial conditions on the p-star coordinate

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

Manual testing: set up and run the smoke tests from the linear/pstar and nonlinear/pstar trees with both models, checking that the converged bathymetry matches the tanh shelf profile and the runs are stable. The RPE tasks are validated opportunistically; note that sorting in-situ density from a nonlinear EOS gives only an approximate RPE measure (documented in the user’s guide).

Testing and Validation: Model-specific tracer and state conversions are shared framework code

Date last modified: 2026/07/23

Contributors: Xylar Asay-Davis, Claude

Unit tests for each helper in the polaris.ocean.init_state package (tests/ocean/init_state/test_init_state.py) and for convert_tracers_to_mpas_ocean() in tests/ocean/eos/test_teos10.py, including the CT/SA → potential-temperature/practical-salinity round trip against direct gsw calls.

Testing and Validation: Existing overflow answers are preserved during refactoring

Date last modified: 2026/07/22

Contributors: Xylar Asay-Davis, Claude

Manual testing: compare the linear/zstar smoke tests against a baseline from main to confirm answers are unchanged (only the path moved). The updated suites are exercised by the usual nightly and PR testing. This comparison applies to the refactoring commits only, before vertical mixing is enabled.

Testing and Validation: Vertical mixing uses background and convective mixing

Date last modified: 2026/07/24

Contributors: Xylar Asay-Davis, Claude

Manual testing: run the smoke tests for all three trees with both models and compare against pre-change baselines (test_20260722/overflow-4th-order-del4-{omega2,mpaso} on chrysalis). Diffs are expected in both models — vertical mixing was previously off — and are blessed after inspection. Checks:

  • the background and convective coefficients appear in the generated omega.yml and the Omega log reports convective mixing as enabled;

  • the viz transects show a plume with qualitatively similar structure in the two models, with the dense plume hugging the bottom and no spurious warm layer beneath the cold plume nose.