ocean_state_t Derived Type

type, public :: ocean_state_t


Inherits

type~~ocean_state_t~~InheritsGraph type~ocean_state_t ocean_state_t type~barotropic_state_t barotropic_state_t type~ocean_state_t->type~barotropic_state_t barotropic type~continuity_t continuity_t type~ocean_state_t->type~continuity_t continuity type~coriolis_adv_t coriolis_adv_t type~ocean_state_t->type~coriolis_adv_t coriolis_adv type~eos_t eos_t type~ocean_state_t->type~eos_t eos type~multilayer_state_t multilayer_state_t type~ocean_state_t->type~multilayer_state_t multilayer type~ocean_bc_state_t ocean_bc_state_t type~ocean_state_t->type~ocean_bc_state_t bc type~ocean_bottom_drag_t ocean_bottom_drag_t type~ocean_state_t->type~ocean_bottom_drag_t bdrag type~ocean_cavity_flux_t ocean_cavity_flux_t type~ocean_state_t->type~ocean_cavity_flux_t cavity_flux type~ocean_data_forcing_t ocean_data_forcing_t type~ocean_state_t->type~ocean_data_forcing_t data_forcing type~ocean_data_input_t ocean_data_input_t type~ocean_state_t->type~ocean_data_input_t data_input type~ocean_diag_t ocean_diag_t type~ocean_state_t->type~ocean_diag_t diag type~ocean_dyn_t ocean_dyn_t type~ocean_state_t->type~ocean_dyn_t dyn type~ocean_epbl_t ocean_epbl_t type~ocean_state_t->type~ocean_epbl_t epbl type~ocean_gm_t ocean_gm_t type~ocean_state_t->type~ocean_gm_t gm type~ocean_hdiff_tracer_t ocean_hdiff_tracer_t type~ocean_state_t->type~ocean_hdiff_tracer_t hdiff_tracer type~ocean_horizontal_viscosity_t ocean_horizontal_viscosity_t type~ocean_state_t->type~ocean_horizontal_viscosity_t hvisc type~ocean_kappa_shear_t ocean_kappa_shear_t type~ocean_state_t->type~ocean_kappa_shear_t kshear type~ocean_lateral_mix_t ocean_lateral_mix_t type~ocean_state_t->type~ocean_lateral_mix_t lateral_mix type~ocean_meke_t ocean_meke_t type~ocean_state_t->type~ocean_meke_t meke type~ocean_metrics_t ocean_metrics_t type~ocean_state_t->type~ocean_metrics_t metrics type~ocean_mle_t ocean_mle_t type~ocean_state_t->type~ocean_mle_t mle type~ocean_obc_t ocean_obc_t type~ocean_state_t->type~ocean_obc_t obc type~ocean_p_surf_t ocean_p_surf_t type~ocean_state_t->type~ocean_p_surf_t p_surf type~ocean_pressure_force_t ocean_pressure_force_t type~ocean_state_t->type~ocean_pressure_force_t pressure_force type~ocean_redi_t ocean_redi_t type~ocean_state_t->type~ocean_redi_t redi type~ocean_restart_t ocean_restart_t type~ocean_state_t->type~ocean_restart_t restart type~ocean_sea_ice_t ocean_sea_ice_t type~ocean_state_t->type~ocean_sea_ice_t ice type~ocean_slopes_t ocean_slopes_t type~ocean_state_t->type~ocean_slopes_t slopes type~ocean_sponge_t ocean_sponge_t type~ocean_state_t->type~ocean_sponge_t sponge type~ocean_surface_flux_t ocean_surface_flux_t type~ocean_state_t->type~ocean_surface_flux_t surface_flux type~ocean_surface_stress_t ocean_surface_stress_t type~ocean_state_t->type~ocean_surface_stress_t surface_stress type~ocean_tidal_mixing_t ocean_tidal_mixing_t type~ocean_state_t->type~ocean_tidal_mixing_t vmix_tidal type~ocean_tides_t ocean_tides_t type~ocean_state_t->type~ocean_tides_t tides type~ocean_top_drag_t ocean_top_drag_t type~ocean_state_t->type~ocean_top_drag_t tdrag type~ocean_varmix_t ocean_varmix_t type~ocean_state_t->type~ocean_varmix_t varmix type~ocean_vcoord_t ocean_vcoord_t type~ocean_state_t->type~ocean_vcoord_t vcoord type~ocean_vdiff_t ocean_vdiff_t type~ocean_state_t->type~ocean_vdiff_t vdiff type~ocean_vertical_advection_t ocean_vertical_advection_t type~ocean_state_t->type~ocean_vertical_advection_t vert_advect type~ocean_vmix_t ocean_vmix_t type~ocean_state_t->type~ocean_vmix_t vmix type~ocean_wave_speed_t ocean_wave_speed_t type~ocean_state_t->type~ocean_wave_speed_t wavespeed type~scratch_3d_buffer_t scratch_3d_buffer_t type~continuity_t->type~scratch_3d_buffer_t h_face_left_x, h_face_right_x, h_face_left_y, h_face_right_y, mt_h_new, mt_grounded, pd_theta type~coriolis_adv_t->type~scratch_3d_buffer_t q_corner, ke_centre, pv_flux_x, pv_flux_y, mass_flux_u, mass_flux_v type~tracer_t tracer_t type~multilayer_state_t->type~tracer_t tracers type~ocean_bc_face_tag_t ocean_bc_face_tag_t type~ocean_bc_state_t->type~ocean_bc_face_tag_t west, east, south, north type~ocean_bottom_drag_t->type~scratch_3d_buffer_t du_drag, dv_drag, lambda_side_u, lambda_side_v type~ocean_cavity_const_t ocean_cavity_const_t type~ocean_cavity_flux_t->type~ocean_cavity_const_t const type~ocean_cavity_exchange_t ocean_cavity_exchange_t type~ocean_cavity_flux_t->type~ocean_cavity_exchange_t par type~ocean_cavity_ice_t ocean_cavity_ice_t type~ocean_cavity_flux_t->type~ocean_cavity_ice_t ice type~data_input_field_t data_input_field_t type~ocean_data_input_t->type~data_input_field_t fields type~diag_var_t diag_var_t type~ocean_diag_t->type~diag_var_t vars type~hgrid_t hgrid_t type~ocean_diag_t->type~hgrid_t grid type~ocean_diag_nc_stream_t ocean_diag_nc_stream_t type~ocean_diag_t->type~ocean_diag_nc_stream_t nc_stream type~barotropic_workstate_t barotropic_workstate_t type~ocean_dyn_t->type~barotropic_workstate_t bt_work type~bt_wide_t bt_wide_t type~ocean_dyn_t->type~bt_wide_t bt_wide type~chksum_probe_t chksum_probe_t type~ocean_dyn_t->type~chksum_probe_t chksum_probe type~ke_probe_t ke_probe_t type~ocean_dyn_t->type~ke_probe_t ke_probe type~ocean_epbl_t->type~eos_t eos type~ocean_epbl_t->type~scratch_3d_buffer_t t0, s0, dpe_t, dpe_s, dcolht_t, dcolht_s, ctke_sw type~ocean_hdiff_tracer_t->type~scratch_3d_buffer_t T_centre, F_x_face, F_y_face type~ocean_horizontal_viscosity_t->type~scratch_3d_buffer_t du_visc, dv_visc, lap_u, lap_v, str_xx, str_xy, ah_t, ah_q type~ocean_kappa_shear_t->type~eos_t eos type~ocean_lateral_mix_t->type~scratch_3d_buffer_t vort_corner type~ocean_pressure_force_t->type~scratch_3d_buffer_t p_edge, z_centre, mont_M, rho_insitu, dpdx_face, dpdy_face, e_face, pa, intz_dpa, intx_pa, inty_pa, intx_dpa, inty_dpa, conc_T, conc_S, recon_T_t, recon_T_b, recon_S_t, recon_S_b type~evp_workspace_t evp_workspace_t type~ocean_sea_ice_t->type~evp_workspace_t evp_ws type~ocean_surface_stress_t->type~scratch_3d_buffer_t du_stress, dv_stress type~ocean_tidal_mixing_t->type~eos_t eos type~ocean_top_drag_t->type~scratch_3d_buffer_t du_drag, dv_drag type~ocean_vdiff_t->type~scratch_3d_buffer_t a_diag_t, b_diag_t, c_diag_t, rhs_t, a_diag_u, b_diag_u, c_diag_u, rhs_u, a_diag_v, b_diag_v, c_diag_v, rhs_v, kv_scalar_buf type~ocean_vertical_advection_t->type~scratch_3d_buffer_t F_face type~ocean_vmix_t->type~eos_t eos type~local_bt_cont_u_type local_BT_cont_u_type type~barotropic_workstate_t->type~local_bt_cont_u_type BTCL_u type~local_bt_cont_v_type local_BT_cont_v_type type~barotropic_workstate_t->type~local_bt_cont_v_type BTCL_v type~bt_wide_t->type~ocean_metrics_t metrics_w type~bt_wide_t->type~hgrid_t grid_w type~diag_mask_t diag_mask_t type~diag_var_t->type~diag_mask_t mask

Inherited by

type~~ocean_state_t~~InheritedByGraph type~ocean_state_t ocean_state_t type~ocean_engine_t ocean_engine_t type~ocean_engine_t->type~ocean_state_t state type~ocean_handle_t ocean_handle_t type~ocean_handle_t->type~ocean_state_t state type~ocean_handle_t->type~ocean_engine_t engine

Components

Type Visibility Attributes Name Initial
type(barotropic_state_t), public :: barotropic

Depth-integrated C-grid prognostic state.

type(ocean_bc_state_t), public :: bc

Per-edge OBC config + per-step boundary data. Defaults to all-OBC_WALL (closed wall) until config opens an edge or a data source populates the data_* buffers.

type(ocean_bottom_drag_t), public :: bdrag

Bottom-drag kernel (linear Rayleigh or quadratic log-layer). Acts on the k=1 layer only.

type(ocean_cavity_flux_t), public :: cavity_flux

Ice-shelf basal-melt slot (&ocean_cavity_melt_nml, default off). Holds the sampled far field, u*, the interface state, the melt mass flux and the per-column solver status; its driver fills surface_flux%heat_cavity/salt_cavity. Gated: off ⇒ (1,1) placeholders, no kernel, bit-identical.

integer, public :: column_stride = 1

Outer tile size for column-local kernels. 1 = column, nx = plane. Drives slot workspace allocation shape. Inform restart-roundtrip + cross-rank assertions whether bit-for-bit checks are expected to succeed.

type(continuity_t), public :: continuity

Continuity-PPM kernel state.

type(coriolis_adv_t), public :: coriolis_adv

PV-conserving Coriolis+advection kernel state.

type(ocean_data_forcing_t), public :: data_forcing

File-backed surface forcing (PR-15) — the (file, variable) -> forcing slot binding over data_input. Holds only registration ids + logicals, all read host-side, so unlike every other slot here it deliberately adds NO term to ocean_state_enter_data: there is nothing to map. The arrays it writes are mapped by surface_stress / surface_flux.

type(ocean_data_input_t), public :: data_input

The shared time-varying NetCDF input reader (PR-14). NetCDF- only (mirrors zinit — the slot compiles out entirely with RDB_ENABLE_NETCDF=OFF, and no consumer path exists that would need it live in that build).

type(ocean_diag_t), public :: diag

Diagnostics manager (registry + remap + I/O server hand-off).

type(ocean_dyn_t), public :: dyn

Split-explicit RK2 driver state.

logical, public :: enable_ideal_age = .false.

MOM6 USE_IDEAL_AGE_TRACER. Set by the driver from cfg BEFORE calling init(grid) so the multilayer state registers the age tracer at index 3. Per-step aging + surface reset is then called by the dyn step driver.

logical, public :: enable_pseudo_salt = .false.

&ocean_tracers_nml enable_pseudo_salt. Set by the driver from cfg BEFORE calling init(grid) — pseudo-salt is registered via register_passive_tracer right after multilayer%init, before ocean_bc_state_init sizes bc%n_tracers (registration-order contract, see rdb_ocean_pseudo_salt).

type(eos_t), public :: eos

Equation of state (Wright by default).

type(ocean_epbl_t), public :: epbl
type(ocean_gm_t), public :: gm

Gent-McWilliams thickness diffusion. Injects eddy bolus thickness transports into the continuity mass fluxes before the divergence; reads slopes%slope_x/y. Default off.

type(ocean_hdiff_tracer_t), public :: hdiff_tracer

Constant-coefficient Laplacian horizontal-tracer-diffusion kernel. Tracer-side counterpart of hvisc.

type(ocean_horizontal_viscosity_t), public :: hvisc

Constant-coefficient Laplacian horizontal-viscosity kernel. Reads scalar nu_h.

type(ocean_sea_ice_t), public :: ice

Gated sea-ice slot (SIS2 port, PLAN_SEA_ICE.md). PR 0 scaffold: knobs + lifecycle only, no arrays and no physics. &ocean_ice_nml enable default off ⇒ never initialised / mapped / stepped ⇒ byte-identical.

logical, public :: is_init = .false.

True once every nested slot has been initialised + GPU attached. Set only after the last child %init returns. Prefer this to walking the children with allocated(...).

type(ocean_kappa_shear_t), public :: kshear

Energetics-based PBL. Mutually exclusive with the KPP overlay; folds its interface diffusivity into vmix%kv / vmix%kt each stage.

type(ocean_lateral_mix_t), public :: lateral_mix

Lateral mixing closure (Leith / Smagorinsky / biharmonic); supplies face viscosity coefficients.

type(ocean_meke_t), public :: meke

Prognostic mesoscale eddy kinetic energy. Evolves a 2D eddy-energy field sourced by gm%gm_src, damped by implicit bottom drag, transported laterally, fed back (geom-mean) into varmix%khth_u/v (+ khtr). Requires GM. Default off ⇒ no-op; khth_fac=khtr_fac=0 ⇒ feedback inert even when enabled.

type(ocean_metrics_t), public :: metrics

Orthogonal curvilinear horizontal metrics (lengths, areas, inverses, geography, hvisc ratio bundle). Filled by configure_ocean_metrics.

type(ocean_mle_t), public :: mle

Fox-Kemper mixed-layer-eddy restratification. Injects ML-confined overturning transports into the continuity mass fluxes before the divergence; reads epbl%mld. Default off.

type(multilayer_state_t), public :: multilayer

Per-layer C-grid prognostic state.

type(ocean_obc_t), public :: obc

Open-boundary nest from parent run.

type(ocean_p_surf_t), public :: p_surf

Atmospheric surface-pressure loading / inverse barometer (PR-17). Folds eta_ib = -p_surf/(rho0 g) into the same eta_forcing barotropic seam the tide composes through.

type(ocean_pressure_force_t), public :: pressure_force

FV pressure-force kernel state.

type(ocean_redi_t), public :: redi

Redi continuous neutral (along-isopycnal) tracer diffusion. Two-phase: redi_calc_coeffs fills neutral-surface coeffs at thermo cadence, redi_apply_flux adds the rotated tracer flux after hdiff_tracer. Recomputes its own interface density derivs (does NOT read slopes). Default off.

type(ocean_restart_t), public :: restart

Restart / checkpoint manager.

type(ocean_slopes_t), public :: slopes

Isopycnal (neutral) slope diagnostics (Griffies 1998) at C-grid interfaces — gates the mesoscale-eddy params. Diagnostic, default off; refreshed at thermo cadence.

type(ocean_sponge_t), public :: sponge

Map-driven sponge (PR-23): per-cell idamp_h/u/v + 3-D reference state. enable (default .false.) gates BOTH the allocation (gated init call below, mirrors epbl/kshear) and the device mapping (gated enter_data/exit_data call in the orchestrator) — a disabled sponge costs nothing. Default off ⇒ the legacy bc%<edge>%sponge_* band kernels (rdb_ocean_sponge::ocean_sponge_apply{,_tracers}) run unchanged ⇒ bit-identical.

type(ocean_surface_flux_t), public :: surface_flux

Surface heat + salt flux slot. 2D Q_heat(:,:) / Q_salt(:,:) (W/m^2 and kg/m^2/s, positive downward / salinifying). Seeded at configure from &ocean_thermo_nml q_heat / q_salt; data-override / restoring may overwrite the fields after. Device-mapped via the orchestrator.

type(ocean_surface_stress_t), public :: surface_stress

Surface wind-stress kernel. Acts on the k=nz layer only.

type(ocean_top_drag_t), public :: tdrag

Ice-shelf TOP-drag kernel (&ocean_tdrag_nml, default off). The mirror of bdrag at k = nz, masked by ice cover on faces. Off ⇒ placeholder arrays, no kernel.

type(ocean_tides_t), public :: tides

Equilibrium + SAL + internal-tide drag.

logical, public :: use_multilayer = .true.

Whether the 3D multilayer state is active (always true on the ocean path; flag exposed for symmetry with the coastal state and so 2D-only debug runs can disable it later).

logical, public :: use_nonhydrostatic = .false.

NH-on-ocean toggle. Phase 5f.

type(ocean_varmix_t), public :: varmix

Spatially-varying GM/Redi coefficient fields. Produces the pre-CFL base khth_u/v (+ khtr_u/v) face fields GM consumes as its optional external base. Reads slopes + wavespeed. Default off ⇒ GM uses the scalar khth.

type(ocean_vcoord_t), public :: vcoord

Vertical-coordinate config + per-step ALE remap state. Defaults to VCOORD_EULERIAN_Z (h_layer fixed).

type(ocean_vdiff_t), public :: vdiff

Backward-Euler vertical-diffusion solver (Thomas tridiagonal per column) for momentum + tracers, using the eddy coefficients in vmix%kv / vmix%kt / vmix%ks.

type(ocean_vertical_advection_t), public :: vert_advect

Vertical advection: diagnoses w_interface from horizontal continuity and advects tracers vertically with a matching h_layer update (Eulerian z — horizontal and vertical h updates cancel).

type(ocean_vmix_t), public :: vmix

Vertical mixing (KPP + interior closure).

type(ocean_tidal_mixing_t), public :: vmix_tidal

St-Laurent/Simmons internal-tide interior diapycnal mixing. INTERIOR closure: its Kd adds to the surface PBL + PP81/background/kappa-shear via the additive merge each stage; kd_int refreshes at thermo cadence. Default off.

type(ocean_wave_speed_t), public :: wavespeed

First-baroclinic wave speed + Rossby deformation radius. Diagnostic, default off.


Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_state_bytes

  • private pure function ocean_state_bytes(this) result(nbytes)

    Counted allocatable footprint of the whole ocean god state, summed from each slot’s own bytes() (each term is 0 when that slot’s arrays are unallocated, so the DEFAULT-OFF closures gated in ocean_state_init contribute nothing — the total tracks the conditional allocation directly). Reported before enter_data and reconciled against the measured device mapping — a new array added without a matching bytes() term makes the measured map exceed this count and self-announces the drift (see rdb_mem_report). Slots with no allocatables (eos, restart) carry no term. The diag%vars registry USED to be excluded — it is now counted, per registered variable, by diag_var_bytes (it was the single largest uncounted device block: ~3.2 GB for the default catalog at 1000x800x50). data_input (PR-14) DOES have allocatables (f0/f1 per registered field) and IS device-mapped, so it carries a real term below — zero registered fields on every shipped namelist keeps that term at 0.

    Arguments

    Type IntentOptional Attributes Name
    class(ocean_state_t), intent(in) :: this

    Return Value integer(kind=int64)

procedure, public, non_overridable :: destroy => ocean_state_destroy

procedure, public, non_overridable :: init => ocean_state_init

  • private subroutine ocean_state_init(this, grid)

    Construct the ocean god state. Each slot’s init allocates its own arrays; the DEFAULT-OFF closures (EPBL, kappa-shear, tidal mixing, GM, Redi, MLE/Fox-Kemper, VarMix, MEKE, isopycnal slopes) are gated on their enable flag so a plain run does not pay their multi-GB footprint. This requires the enable flags to be set BEFORE init — ocean_state_init_from_config hoists them above its call this%init(grid) for exactly this reason. The gated closures’ runtime kernels already early-return on .not. enable (and enter_data/exit_data are gated in the parent walk), so a gated-off slot is never touched with unallocated arrays.

    Arguments

    Type IntentOptional Attributes Name
    class(ocean_state_t), intent(inout) :: this
    type(hgrid_t), intent(in) :: grid

procedure, public, non_overridable :: init_from_config => ocean_state_init_from_config

  • private subroutine ocean_state_init_from_config(this, cfg, grid)

    Seed the cfg-derived scalars the slot inits read up front (layer count, ideal-age toggle), allocate via init(grid), then override the linear-EOS params (after eos%init has set its defaults). Carries the ocean branch that state_init_from_config held before the coastal / ocean state split — the order (nz_ml + ideal_age before init, eos after) is load-bearing and matches the pre-split behaviour.

    Arguments

    Type IntentOptional Attributes Name
    class(ocean_state_t), intent(inout) :: this
    type(config_t), intent(in) :: cfg
    type(hgrid_t), intent(in) :: grid

Source Code

   type :: ocean_state_t
      logical :: is_init = .false.
         !! True once every nested slot has been initialised + GPU
         !! attached.  Set only after the last child `%init` returns.
         !! Prefer this to walking the children with `allocated(...)`.

      ! ---- Prognostic state ----
      type(barotropic_state_t) :: barotropic
         !! Depth-integrated C-grid prognostic state.
      type(multilayer_state_t) :: multilayer
         !! Per-layer C-grid prognostic state.
      type(ocean_metrics_t) :: metrics
         !! Orthogonal curvilinear horizontal metrics (lengths, areas,
         !! inverses, geography, hvisc ratio bundle).  Filled by
         !! `configure_ocean_metrics`.

      ! ---- Kernel + driver state ----
      type(ocean_dyn_t) :: dyn
         !! Split-explicit RK2 driver state.
      type(continuity_t) :: continuity
         !! Continuity-PPM kernel state.
      type(coriolis_adv_t) :: coriolis_adv
         !! PV-conserving Coriolis+advection kernel state.
      type(ocean_pressure_force_t) :: pressure_force
         !! FV pressure-force kernel state.

      ! ---- Physics parameterisations ----
      type(ocean_vmix_t) :: vmix
         !! Vertical mixing (KPP + interior closure).
      type(ocean_epbl_t) :: epbl
      type(ocean_wave_speed_t) :: wavespeed
         !! First-baroclinic wave speed + Rossby deformation radius.
         !! Diagnostic, default off.
      type(ocean_tidal_mixing_t) :: vmix_tidal
         !! St-Laurent/Simmons internal-tide interior diapycnal mixing.
         !! INTERIOR closure: its Kd adds to the surface PBL +
         !! PP81/background/kappa-shear via the additive merge each stage;
         !! `kd_int` refreshes at thermo cadence.  Default off.
      type(ocean_kappa_shear_t) :: kshear
         !! Energetics-based PBL.  Mutually exclusive with the KPP
         !! overlay; folds its interface diffusivity into `vmix%kv` /
         !! `vmix%kt` each stage.
      type(ocean_lateral_mix_t) :: lateral_mix
         !! Lateral mixing closure (Leith / Smagorinsky / biharmonic);
         !! supplies face viscosity coefficients.
      type(ocean_slopes_t) :: slopes
         !! Isopycnal (neutral) slope diagnostics (Griffies 1998) at
         !! C-grid interfaces — gates the mesoscale-eddy params.
         !! Diagnostic, default off; refreshed at thermo cadence.
      type(ocean_mle_t) :: mle
         !! Fox-Kemper mixed-layer-eddy restratification.  Injects
         !! ML-confined overturning transports into the continuity mass
         !! fluxes before the divergence; reads `epbl%mld`.  Default off.
      type(ocean_gm_t) :: gm
         !! Gent-McWilliams thickness diffusion.  Injects eddy bolus
         !! thickness transports into the continuity mass fluxes before
         !! the divergence; reads `slopes%slope_x/y`.  Default off.
      type(ocean_redi_t) :: redi
         !! Redi continuous neutral (along-isopycnal) tracer diffusion.
         !! Two-phase: `redi_calc_coeffs` fills neutral-surface coeffs at
         !! thermo cadence, `redi_apply_flux` adds the rotated tracer flux
         !! after `hdiff_tracer`.  Recomputes its own interface density
         !! derivs (does NOT read `slopes`).  Default off.
      type(ocean_varmix_t) :: varmix
         !! Spatially-varying GM/Redi coefficient fields.  Produces the
         !! pre-CFL base `khth_u/v` (+ `khtr_u/v`) face fields GM consumes
         !! as its optional external base.  Reads slopes + wavespeed.
         !! Default off ⇒ GM uses the scalar khth.
      type(ocean_meke_t) :: meke
         !! Prognostic mesoscale eddy kinetic energy.  Evolves a 2D
         !! eddy-energy field sourced by `gm%gm_src`, damped by implicit
         !! bottom drag, transported laterally, fed back (geom-mean) into
         !! `varmix%khth_u/v` (+ khtr).  Requires GM.  Default off ⇒ no-op;
         !! `khth_fac=khtr_fac=0` ⇒ feedback inert even when enabled.
      type(ocean_horizontal_viscosity_t) :: hvisc
         !! Constant-coefficient Laplacian horizontal-viscosity kernel.
         !! Reads scalar `nu_h`.
      type(ocean_bottom_drag_t) :: bdrag
         !! Bottom-drag kernel (linear Rayleigh or quadratic log-layer).
         !! Acts on the k=1 layer only.
      type(ocean_top_drag_t) :: tdrag
         !! Ice-shelf TOP-drag kernel (`&ocean_tdrag_nml`, default off).
         !! The mirror of `bdrag` at `k = nz`, masked by ice cover on
         !! faces.  Off ⇒ placeholder arrays, no kernel.
      type(ocean_surface_stress_t) :: surface_stress
         !! Surface wind-stress kernel.  Acts on the k=nz layer only.
      type(ocean_cavity_flux_t) :: cavity_flux
         !! Ice-shelf basal-melt slot (`&ocean_cavity_melt_nml`, default
         !! off).  Holds the sampled far field, `u*`, the interface
         !! state, the melt mass flux and the per-column solver status;
         !! its driver fills `surface_flux%heat_cavity`/`salt_cavity`.
         !! Gated: off ⇒ `(1,1)` placeholders, no kernel, bit-identical.
      type(ocean_surface_flux_t) :: surface_flux
         !! Surface heat + salt flux slot.  2D `Q_heat(:,:)` / `Q_salt(:,:)`
         !! (W/m^2 and kg/m^2/s, positive downward / salinifying).  Seeded
         !! at configure from `&ocean_thermo_nml q_heat / q_salt`;
         !! data-override / restoring may overwrite the fields after.
         !! Device-mapped via the orchestrator.
      type(ocean_vertical_advection_t) :: vert_advect
         !! Vertical advection: diagnoses `w_interface` from horizontal
         !! continuity and advects tracers vertically with a matching
         !! `h_layer` update (Eulerian z — horizontal and vertical h
         !! updates cancel).
      type(ocean_hdiff_tracer_t) :: hdiff_tracer
         !! Constant-coefficient Laplacian horizontal-tracer-diffusion
         !! kernel.  Tracer-side counterpart of `hvisc`.
      type(ocean_vdiff_t) :: vdiff
         !! Backward-Euler vertical-diffusion solver (Thomas tridiagonal
         !! per column) for momentum + tracers, using the eddy
         !! coefficients in `vmix%kv` / `vmix%kt` / `vmix%ks`.
      type(eos_t) :: eos
         !! Equation of state (Wright by default).

      ! ---- Forcing ----
      type(ocean_tides_t) :: tides
         !! Equilibrium + SAL + internal-tide drag.
      type(ocean_p_surf_t) :: p_surf
         !! Atmospheric surface-pressure loading / inverse barometer
         !! (PR-17).  Folds `eta_ib = -p_surf/(rho0 g)` into the same
         !! `eta_forcing` barotropic seam the tide composes through.

      ! ---- Sea ice ----
      type(ocean_sea_ice_t) :: ice
         !! Gated sea-ice slot (SIS2 port, `PLAN_SEA_ICE.md`).  PR 0
         !! scaffold: knobs + lifecycle only, no arrays and no physics.
         !! `&ocean_ice_nml enable` default off ⇒ never initialised /
         !! mapped / stepped ⇒ byte-identical.

      ! ---- Boundary ----
      type(ocean_obc_t) :: obc
         !! Open-boundary nest from parent run.
      type(ocean_bc_state_t) :: bc
         !! Per-edge OBC config + per-step boundary data.  Defaults to
         !! all-OBC_WALL (closed wall) until config opens an edge or a
         !! data source populates the `data_*` buffers.
      type(ocean_sponge_t) :: sponge
         !! Map-driven sponge (PR-23): per-cell `idamp_h/u/v` + 3-D
         !! reference state.  `enable` (default `.false.`) gates BOTH the
         !! allocation (gated `init` call below, mirrors epbl/kshear) and
         !! the device mapping (gated `enter_data`/`exit_data` call in the
         !! orchestrator) — a disabled sponge costs nothing.  Default off
         !! ⇒ the legacy `bc%<edge>%sponge_*` band kernels
         !! (`rdb_ocean_sponge::ocean_sponge_apply{,_tracers}`) run
         !! unchanged ⇒ bit-identical.

      ! ---- Vertical coordinate ----
      type(ocean_vcoord_t) :: vcoord
         !! Vertical-coordinate config + per-step ALE remap state.
         !! Defaults to `VCOORD_EULERIAN_Z` (`h_layer` fixed).

      ! ---- I/O ----
      type(ocean_diag_t) :: diag
         !! Diagnostics manager (registry + remap + I/O server hand-off).
#ifndef RDB_NO_NETCDF
      type(ocean_data_input_t) :: data_input
         !! The shared time-varying NetCDF input reader (PR-14).  NetCDF-
         !! only (mirrors `zinit` — the slot compiles out entirely with
         !! `RDB_ENABLE_NETCDF=OFF`, and no consumer path exists that
         !! would need it live in that build).
      type(ocean_data_forcing_t) :: data_forcing
         !! File-backed surface forcing (PR-15) — the `(file, variable)
         !! -> forcing slot` binding over `data_input`.  Holds only
         !! registration ids + logicals, all read host-side, so unlike
         !! every other slot here it deliberately adds NO term to
         !! `ocean_state_enter_data`: there is nothing to map.  The
         !! arrays it writes are mapped by `surface_stress` /
         !! `surface_flux`.
#endif
      type(ocean_restart_t) :: restart
         !! Restart / checkpoint manager.

      ! ---- Top-level scalars ----
      logical :: use_multilayer = .true.
         !! Whether the 3D multilayer state is active (always true on
         !! the ocean path; flag exposed for symmetry with the coastal
         !! state and so 2D-only debug runs can disable it later).
      logical :: use_nonhydrostatic = .false.
         !! NH-on-ocean toggle.  Phase 5f.
      logical :: enable_ideal_age = .false.
         !! MOM6 `USE_IDEAL_AGE_TRACER`.  Set by the driver from cfg
         !! BEFORE calling `init(grid)` so the multilayer state
         !! registers the age tracer at index 3.  Per-step aging +
         !! surface reset is then called by the dyn step driver.
      logical :: enable_pseudo_salt = .false.
         !! `&ocean_tracers_nml enable_pseudo_salt`.  Set by the driver
         !! from cfg BEFORE calling `init(grid)` — pseudo-salt is
         !! registered via `register_passive_tracer` right after
         !! `multilayer%init`, before `ocean_bc_state_init` sizes
         !! `bc%n_tracers` (registration-order contract, see
         !! `rdb_ocean_pseudo_salt`).

      ! ---- Tile policy ----
      ! Single knob controlling the strided hybrid column/plane loop
      ! pattern that every column-local kernel (vmix, continuity,
      ! coriolis_adv, lateral_mix, pressure_force) is written against
      ! — see README "Loop pattern" convention.
      !
      !   column_stride = 1        → CPU-optimal (column-based, 1D
      !                              column workspace, cache-friendly)
      !   column_stride = nx       → GPU-optimal (plane-based, full
      !                              3D parallelism, max occupancy)
      !   1 < column_stride < nx   → tiled hybrid (typically 16–64
      !                              saturates an SM on H100/A100)
      !
      ! Phase 5b will auto-pick based on RDB_PARALLEL_BACKEND:
      ! 1 for `-stdpar=multicore`, 32 for `-stdpar=gpu`.  Reference:
      ! Kommera & Appelhans (NVIDIA, CESM SEWG 2026), "One Codebase
      ! with Good Performance on both CPUs and GPUs, for Column-based
      ! Loop Structures".
      integer :: column_stride = 1
         !! Outer tile size for column-local kernels.  1 = column,
         !! `nx` = plane.  Drives slot workspace allocation shape.
         !! Inform restart-roundtrip + cross-rank assertions whether
         !! bit-for-bit checks are expected to succeed.
   contains
      procedure, non_overridable :: init => ocean_state_init
      procedure, non_overridable :: init_from_config => ocean_state_init_from_config
      procedure, non_overridable :: destroy => ocean_state_destroy
      procedure, non_overridable :: bytes => ocean_state_bytes
   end type ocean_state_t