Holds scheme-variant flags and reusable workspace for the C-grid continuity-PPM (Lin & Rood) thickness-flux kernel, plus the public step routines that the split-explicit driver calls per barotropic substep. The kernel is the primary mass-flux producer for the ocean path: it consumes face velocities + cell-centred thickness and emits per-face mass fluxes that the tracer-advection kernels then reuse under CWC for free.
Phase 2b: method-of-lines PPM face reconstruction (Colella & Woodward 1984, eq 1.6 face value + eq 1.10 monotonic limiter) on the barotropic C-grid state. Closed-wall BC. Cells too close to a wall (< 2 cells from the boundary) fall back to first-order (h_L = h_R = h_centre); the resulting kernel preserves uniform fields bit-for-bit (the constancy-preservation property the lake-at-rest tests guard) and propagates Gaussian humps with < 5% peak diffusion over their own width.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public, | parameter | :: | TR_MODE_ACCUMULATE | = | 1 | |
| integer, | public, | parameter | :: | TR_MODE_ADVECT | = | 0 |
Every-step fused mode: advance h AND advect tracers each call (the historical default; ratio = 1 bypass). |
| integer, | public, | parameter | :: | TR_MODE_NONE | = | 2 |
h-only continuity: skip tracer advection AND window accumulation entirely. Used by the pred_corr predictor (SPEC §2 P9 — MOM6’s predictor continuity advances hp but never touches tracers; the predictor state is discarded except for u_av / h_av). Windowed mode (ratio > 1): advance h, accumulate 0.5·mass_flux·dt into uhtr/vhtr, SKIP the per-step tracer advect (hTr held frozen until the boundary drain). |
| integer, | private, | parameter | :: | AVAIL_LIMIT_PASS | = | 8 | |
| real(kind=wp), | private, | parameter | :: | DRAIN_BUDGET_IN_STAGE_WEIGHT | = | 1.0_wp | |
| real(kind=wp), | private, | parameter | :: | DRAIN_BUDGET_POST_AVERAGE_WEIGHT | = | 2.0_wp | |
| real(kind=wp), | private, | parameter | :: | DRAIN_MIN_H | = | 1.0e-10_wp | |
| real(kind=wp), | private, | parameter | :: | DRAIN_MIN_VOL | = | 1.0e-10_wp | |
| real(kind=wp), | private, | parameter | :: | RENORM_CFL | = | 0.25_wp |
CFL cap on the reconciliation correction (MOM6 CONTINUITY_CFL_LIMIT,
default 0.5). MOM6 brackets its Newton solve by this and will ACCEPT
a residual |
| integer, | private, | parameter | :: | RENORM_MAXIT | = | 8 |
Newton iterations for the |
| integer, | private, | parameter | :: | RENORM_MAXIT_CONSISTENT | = | 20 |
Iteration cap when |
| real(kind=wp), | private, | parameter | :: | RENORM_TOL | = | 1.0e-12_wp |
Relative convergence tolerance on |
| real(kind=wp), | private, | parameter | :: | RENORM_VR_MIN | = | 1.0e-12_wp |
Floor below which a layer’s viscous remnant γ_k is treated as zero
when bracketing |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public | :: | angstrom_h | = | 0.0_wp |
Phase-1 Lagrangian minimum-thickness floor (m). Set from cfg%ocean%isopycnal%angstrom_h at setup, but only PASSED to the h-update kernels when the active vcoord is VCOORD_LAGRANGIAN (gated at the dyn call site). 0 ⇒ off ⇒ bit-identical. R7: floor lifts h but NOT hTr, so Tr=hTr/h shifts on a floored layer. Harmless for the adiabatic isopycnal config; thermo-on isopycnal correctness is OUT OF SCOPE for v1. |
|
| real(kind=wp), | public | :: | cfl_max | = | 0.5_wp |
Soft cap on per-face CFL before falling back to upwind. |
|
| logical, | public | :: | conservative_floor | = | .false. |
When |
|
| logical, | public | :: | hTr_holds_conc | = | .false. |
True while the frozen tracer content |
|
| type(scratch_3d_buffer_t), | public | :: | h_face_left_x |
Left-state thickness at east faces. |
|||
| type(scratch_3d_buffer_t), | public | :: | h_face_left_y |
Left-state thickness at north faces. |
|||
| type(scratch_3d_buffer_t), | public | :: | h_face_right_x |
Right-state thickness at east faces. |
|||
| type(scratch_3d_buffer_t), | public | :: | h_face_right_y |
Right-state thickness at north faces. |
|||
| real(kind=wp), | public | :: | h_lim | = | 0.0_wp |
Positive-definite thickness floor (m). Derived at setup:
|
|
| real(kind=wp), | public | :: | h_min | = | 1.0e-6_wp |
Lower clip on cell-centred thickness during the update.
Also used as the floor for |
|
| real(kind=wp), | public, | allocatable | :: | h_win_start(:,:,:) |
Layer thickness captured when an accumulation window OPENS.
Paired with |
||
| real(kind=wp), | public, | allocatable | :: | hprev_work(:,:,:) | |||
| logical, | public | :: | is_init | = | .false. |
True between |
|
| type(scratch_3d_buffer_t), | public | :: | mt_grounded |
|
|||
| type(scratch_3d_buffer_t), | public | :: | mt_h_new |
Cell-centred |
|||
| integer, | public | :: | n_limited_step | = | 0 |
P2 diagnostic counter: number of interior faces whose mass flux
the positive-definite limiter scaled (θ_donor < 1) this outer-step
call, summed over the zonal + meridional passes. Host-side scalar
(the |
|
| integer(kind=int64), | public | :: | n_limited_total | = | 0_int64 |
P3 running total of |
|
| real(kind=wp), | public, | allocatable | :: | pa6(:,:,:) |
CW parabola curvature a6 = 6·Tr − 3·(aL+aR) (rebuilt per pass). |
||
| real(kind=wp), | public, | allocatable | :: | pal(:,:,:) |
CW parabola left-edge value per cell (rebuilt per pass). |
||
| real(kind=wp), | public, | allocatable | :: | par(:,:,:) |
CW parabola right-edge value per cell (rebuilt per pass). |
||
| type(scratch_3d_buffer_t), | public | :: | pd_theta |
|
|||
| logical, | public | :: | positive_definite | = | .false. |
Positive-definite split continuity master switch. When |
|
| logical, | public | :: | renorm_consistent_flux | = | .true. |
|
|
| logical, | public | :: | renorm_legacy_single_step | = | .false. |
Use the pre-Newton single-linear-step uhbt renormalisation
(donors picked at the UNCORRECTED velocity, no CFL bracket,
no iteration) — wet/dry composition, set from
|
|
| real(kind=wp), | public | :: | t_dyn_rel_adv | = | 0.0_wp |
Elapsed dynamics time (s) accumulated since the last tracer
advect / accumulator reset. Adds |
|
| real(kind=wp), | public, | allocatable | :: | tr_flux_x(:,:,:) |
Per-pass zonal tracer flux F (m^3 · concentration). |
||
| real(kind=wp), | public, | allocatable | :: | tr_flux_y(:,:,:) |
Per-pass meridional tracer flux F (m^3 · concentration). |
||
| real(kind=wp), | public, | allocatable | :: | tr_work(:,:,:) |
Current concentration Tr = hTr/hprev_work (rebuilt per pass). |
||
| integer, | public | :: | tracer_recon | = | TRACER_RECON_PPM |
Face-reconstruction scheme for the WINDOWED tracer-advection
drain (Q6; |
|
| real(kind=wp), | public, | allocatable | :: | uhh_x(:,:,:) |
Per-pass limited zonal transport portion (m^3). |
||
| real(kind=wp), | public, | allocatable | :: | uhh_y(:,:,:) |
Per-pass limited meridional transport portion (m^3). |
||
| real(kind=wp), | public, | allocatable | :: | uhr_x(:,:,:) |
Remaining unspent zonal transport this window (m^3). |
||
| real(kind=wp), | public, | allocatable | :: | uhr_y(:,:,:) |
Remaining unspent meridional transport this window (m^3). |
||
| real(kind=wp), | public, | allocatable | :: | uhtr(:,:,:) |
Accumulated zonal face transport (m^3, area-weighted ·dt). |
||
| logical, | public | :: | use_ppm_limit_pos | = | .false. |
MOM6 |
|
| real(kind=wp), | public, | allocatable | :: | vhtr(:,:,:) |
Accumulated meridional face transport (m^3, area-weighted ·dt). |
||
| logical, | public | :: | vol_cfl | = | .false. |
MOM6 |
|
| logical, | public | :: | windowed_advection | = | .false. |
Gates the ALLOCATION of the Phase-2 windowed-advection state (13
3D arrays: |
| procedure, public, non_overridable :: bytes => continuity_bytes | |
| procedure, public, non_overridable :: destroy => continuity_destroy | |
| procedure, public, non_overridable :: enter_data => continuity_enter_data | |
| procedure, public, non_overridable :: exit_data => continuity_exit_data | |
| procedure, public, non_overridable :: init => continuity_init |
Mirror-h at a land neighbour (spec §14 C2 / MOM6’s
reflected-coast PPM): substitute the LOCAL cell’s
thickness (or tracer) for a LAND neighbour’s held floor value
so the PPM parabola sees a flat, reflected coast and the
wet-side face value is not biased by the dry column. Branchless:
h_out = w_nbr·h_nbr + (1-w_nbr)·h_loc.
Wet neighbour (w_nbr=1) ⇒ h_out = h_nbr (literal no-op);
land neighbour (w_nbr=0) ⇒ h_out = h_loc.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_nbr |
neighbour value |
||
| real(kind=wp), | intent(in) | :: | h_loc |
local-cell value (the mirror target) |
||
| real(kind=wp), | intent(in) | :: | w_nbr |
neighbour wet mask (0/1) |
MOM6 swept-volume continuity-PPM face thickness (Lin & Rood
/ MOM_continuity_PPM flux_elem). Integrates the donor
cell’s reconstructed parabola over the swept volume rather
than sampling the edge value, adding the O(CFL) correction:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_edge |
downwind-facing donor PPM edge value |
||
| real(kind=wp), | intent(in) | :: | dh |
swept-oriented donor edge difference |
||
| real(kind=wp), | intent(in) | :: | curv3 |
donor parabola curvature (h_L+h_R−2h) |
||
| real(kind=wp), | intent(in) | :: | cfl |
donor-cell Courant number (>= 0) |
Counted allocatable footprint of the continuity-PPM slot (0 when unallocated). One arr_bytes term per array — add a term here when a new allocatable joins the type.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(continuity_t), | intent(in) | :: | this |
Swept-average WENO donor concentration at a zonal face. cc is
the donor cell (i-index), d = +1 (u>0, downwind toward +i) or
d = -1 (u<0, downwind toward -i). Gathers the mirrored/clamped
stencil in downwind-positive order and dispatches to the coastal
swept-average face helper at the highest feasible rung.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | tr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| integer, | intent(in) | :: | cc | |||
| integer, | intent(in) | :: | jj | |||
| integer, | intent(in) | :: | kk | |||
| integer, | intent(in) | :: | d | |||
| integer, | intent(in) | :: | avail_up | |||
| integer, | intent(in) | :: | avail_down | |||
| integer, | intent(in) | :: | rung_max | |||
| real(kind=wp), | intent(in) | :: | cfl |
Meridional analogue of weno_face_conc_x. cc is the donor cell
(j-index); the stencil steps along j with d = +1 (u>0) / -1 (u<0).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | tr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| integer, | intent(in) | :: | ii | |||
| integer, | intent(in) | :: | cc | |||
| integer, | intent(in) | :: | kk | |||
| integer, | intent(in) | :: | d | |||
| integer, | intent(in) | :: | avail_up | |||
| integer, | intent(in) | :: | avail_down | |||
| integer, | intent(in) | :: | rung_max | |||
| real(kind=wp), | intent(in) | :: | cfl |
Forward-Euler step: h <- h - dt * flux_h. The full split-explicit RK2 scheme (Phase 4) wraps two of these calls around an RK2 averaging pass; for Phase 2 this single-stage step is enough to exercise the kernel under the lake-at-rest, Gaussian-hump, and mass-conservation tests.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(barotropic_state_t), | intent(inout) | :: | bs | |||
| real(kind=wp), | intent(in) | :: | dt |
PPM face reconstruction + per-face mass flux + cell-centred flux divergence for the barotropic C-grid state.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(barotropic_state_t), | intent(inout) | :: | bs |
Gent-McWilliams thickness diffusion as its OWN sequential operator:
move h_layer AND every tracer by the bolus transport gm%uhD/
gm%vhD, which gm_compute_transports has JUST filled from this
same, untouched h_layer with this same dt.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| type(ocean_gm_t), | intent(inout) | :: | gm |
|
||
| real(kind=wp), | intent(in) | :: | dt |
The step the transports were capped for (s). |
||
| real(kind=wp), | intent(in) | :: | budget_w |
Budget bookkeeping weight (see above). |
||
| integer, | intent(in) | :: | tracer_mode |
|
||
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
Edge tags (absent ⇒ every edge a wall). |
|
| logical, | intent(in), | optional | :: | set_flux_h |
Leave the bolus divergence in |
Phase-2 (6b) windowed horizontal tracer-advection drain.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| integer, | intent(in) | :: | ratio |
|
||
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
Production entry point for the directionally-split continuity + tracer step. Interleaves the two so the CWC discrete theorem holds in the split form:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in), | optional | :: | uhbt(:,:) | ||
| real(kind=wp), | intent(in), | optional | :: | vhbt(:,:) | ||
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
When present, per-edge OBC tags gate the wall-zero step inside the flux kernels. OBC_WALL keeps the Phase 3 closure; OBC_OPEN (and other non-wall tags) leaves the computed mass flux at the wall face for the downstream transport. Absent ⇒ closed-wall everywhere. |
|
| type(ocean_mle_t), | intent(in), | optional | :: | mle |
Fox-Kemper mixed-layer-eddy transports (B5). When present
and enabled, |
|
| logical, | intent(in), | optional | :: | mle_fold_active |
Gates the Fox-Kemper fold to the THERMO cadence. Absent or
|
|
| integer, | intent(in), | optional | :: | tracer_mode |
Phase 2 (6b) windowed-advection mode. |
|
| real(kind=wp), | intent(in), | optional | :: | h_min |
Phase-1 Lagrangian minimum-thickness floor (m). When > 0, passed
to |
|
| real(kind=wp), | intent(in), | optional | :: | visc_rem_u(:,:,:) |
Per-layer viscous remnant gamma_k on east / north faces. Forwarded
to the flux renormalisers, where it weights the barotropic
increment (MOM6 |
|
| real(kind=wp), | intent(in), | optional | :: | visc_rem_v(:,:,:) |
Per-layer viscous remnant gamma_k on east / north faces. Forwarded
to the flux renormalisers, where it weights the barotropic
increment (MOM6 |
|
| real(kind=wp), | intent(inout), | optional | :: | u_cor(:,:,:) |
MOM6 |
|
| real(kind=wp), | intent(inout), | optional | :: | v_cor(:,:,:) |
MOM6 |
Colella-Woodward 1984 eq 1.10 monotonic limiter on the parabolic profile in a single cell. Three branches:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_centre | |||
| real(kind=wp), | intent(inout) | :: | h_left | |||
| real(kind=wp), | intent(inout) | :: | h_right |
Positivity-preserving limiter on the PPM reconstruction.
Mirrors MOM6’s PPM_limit_pos:
when the parabolic fit predicts a minimum interior to the
cell that dips below h_min, shrink h_left / h_right toward
h_centre so the minimum sits at exactly h_min. Pure
scalar form per cell; runs after ppm_cell_limiter so the
monotonic-limited reconstruction is the input.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_centre | |||
| real(kind=wp), | intent(inout) | :: | h_left | |||
| real(kind=wp), | intent(inout) | :: | h_right | |||
| real(kind=wp), | intent(in) | :: | h_min |
Van Leer monotonized centred slope for cell i. Returns 0 at local extrema (sign change between left and right differences) and the slope-limited centred derivative otherwise. Standard PPM convention; see Colella-Woodward 1984.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_im1 | |||
| real(kind=wp), | intent(in) | :: | h_i | |||
| real(kind=wp), | intent(in) | :: | h_ip1 | |||
| real(kind=wp), | intent(out) | :: | dh |
Accumulate one RK2 stage’s zonal mass flux into the windowed
accumulator with the ½ RK2 weight baked in:
uhtr += 0.5·mass_flux_x·dt. mass_flux_x is already
area-weighted (m³/s = u·h_face·dy_cu); the product is m³.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx_face | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | mass_flux_x(nx_face,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | uhtr(nx_face,ny,nz) |
Meridional analogue of accumulate_flux_x.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny_face | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | mass_flux_y(nx,ny_face,nz) | |||
| real(kind=wp), | intent(inout) | :: | vhtr(nx,ny_face,nz) |
Test-only (no production caller): unsplit apply, paired with
continuity_compute_fluxes as the split path’s reference oracle.
Per-layer forward-Euler thickness update.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in), | optional | :: | h_min |
Minimum-thickness floor (m). 0 or absent ⇒ off ⇒ bit-identical. |
Apply the meridional (y-flux) thickness update on top of
the zonally-updated state:
h(i,j,k) ← h(i,j,k) - dt · (Φy(i,j+1,k) - Φy(i,j,k)) · iareaT
Adds the y-divergence to flux_h_layer so the field ends
the split step holding the total horizontal divergence
that the vertical-advection kernel consumes
(w_interface(k+1) = w(k) - flux_h_layer(k)). Φy carries
dx_cv; iareaT = inv_dy on uniform metrics.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in), | optional | :: | h_min |
Minimum-thickness floor (m). 0 or absent ⇒ off ⇒ bit-identical. |
Apply the zonal (x-flux) thickness update:
h(i,j,k) ← h(i,j,k) - dt · (Φx(i+1,j,k) - Φx(i,j,k)) · iareaT
Overwrites flux_h_layer with the x-divergence so the
companion meridional apply can accumulate the total. Φx is
the width-weighted transport (m³/s); iareaT closes the
divergence to a per-area rate (= inv_dx on uniform metrics).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in), | optional | :: | h_min |
Minimum-thickness floor (m). 0 or absent ⇒ off ⇒ bit-identical. |
Test-only (no production caller): the unsplit reference path,
kept as the oracle the split production path is checked against.
Multilayer counterpart to
continuity_compute_fluxes_barotropic: identical PPM
reconstruction + upwind face pick + flux divergence, lifted
per-layer. Each k-slice is independent (the PPM stencil
reads only the same k), so the do-concurrent kernels
parallelize over (k, j, i) simultaneously for GPU
occupancy.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(continuity_t), | intent(inout) | :: | this |
Bare copyin(this) removed (stack-descriptor map → AMD cross-slot
overlap; see ocean_surfstress_enter_data). The face buffers attach
below; ct-descriptor presence (so DCs touching ct%h_face_left_x%data
don’t per-launch memcpy) comes from the root copyin(state) in
ocean_state_enter_data. A V100 A/B with copyin(this) gone is
bit-identical and faster overall, so the root copy fully covers it.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(continuity_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(continuity_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(continuity_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(continuity_t), | intent(inout) | :: | this |
Allocate the 4 face-reconstruction scratch buffers sized at
(nx_face, ny_face, nz). Default nz=1 covers the barotropic
kernel; passing nz_ml sizes them for the multilayer
kernel without forcing a separate init routine. Ocean
init passes state%multilayer%nz_ml when the multilayer
state is in play.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(continuity_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in), | optional | :: | nz_ml |
Meridional (y-only) PPM reconstruction + per-face mass
flux. Mirror of continuity_zonal_flux, with the same
optional vhbt transport-constraint renormalisation.
Writes ms%mass_flux_y_layer. Walls at j=1 and j=ny+1
zeroed. In the Lie split this runs after the zonal
apply, so it reconstructs against the already-updated
ms%h_layer.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt |
Time increment (s). Used only for the swept-volume CFL when
|
||
| real(kind=wp), | intent(in), | optional | :: | vhbt(:,:) |
Time-mean north-face transport from barotropic substep (m³/s),
shape |
|
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc | ||
| real(kind=wp), | intent(in), | optional | :: | visc_rem(:,:,:) |
Per-layer viscous remnant gamma_k. Absent => 1, bit-identical. |
|
| real(kind=wp), | intent(inout), | optional | :: | v_cor(:,:,:) |
Forwarded MOM6 |
Test-only (no production caller): continuity-only split wrapper;
production runs the tracer-interleaved continuity_tracer_step_split.
Directionally-split (Lie) PPM continuity step over dt:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt |
Zonal (x-only) PPM reconstruction + per-face mass flux on
the multilayer C-grid. Companion to
continuity_meridional_flux for the
directionally-split (Lie) continuity step. Writes
ms%mass_flux_x_layer and leaves mass_flux_y_layer /
flux_h_layer untouched. Wall faces at i=1 and i=nx+1
are zeroed (closed-wall BC).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt |
Time increment (s). Used only for the swept-volume CFL when
|
||
| real(kind=wp), | intent(in), | optional | :: | uhbt(:,:) |
Time-mean east-face transport from barotropic substep (m³/s),
shape |
|
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
Per-edge OBC tags. Default (absent) -> OBC_WALL on both ends. Non-WALL tags skip the wall-zero step at that edge. |
|
| real(kind=wp), | intent(in), | optional | :: | visc_rem(:,:,:) |
Per-layer viscous remnant γ_k, forwarded to
|
|
| real(kind=wp), | intent(inout), | optional | :: | u_cor(:,:,:) |
Forwarded MOM6 |
Conservative upfront availability limiter on the accumulated window
transports uhtr/vhtr, applied BEFORE drain_reconstruct_hprev.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_min | |||
| real(kind=wp), | intent(in) | :: | h_end(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | uhtr(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | vhtr(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | scratch(nx,ny,nz) |
Per-cell inflow scale factor in [0,1] (centre-shaped slot). |
Scale each interior x-face transport by its INFLOW-receiving cell’s factor (drain_avail_limit step 2). Face i between cell (i-1) and cell (i): uhtr(i)>0 ⇒ receiver i, uhtr(i)<0 ⇒ receiver i-1.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | scratch(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | uhtr(nx+1,ny,nz) |
Meridional analogue of drain_avail_scale_x. Face j between cell (j-1) and cell (j): vhtr(j)>0 ⇒ receiver j, vhtr(j)<0 ⇒ receiver j-1.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | scratch(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | vhtr(nx,ny+1,nz) |
dst = src (explicit-shape device copy).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | n1 | |||
| integer, | intent(in) | :: | n2 | |||
| integer, | intent(in) | :: | n3 | |||
| real(kind=wp), | intent(in) | :: | src(n1,n2,n3) | |||
| real(kind=wp), | intent(inout) | :: | dst(n1,n2,n3) |
Concentration field Tr = hTr / max(hprev, DRAIN_MIN_H) for the WENO drain (the CW path builds the same field as the first loop of drain_parabola_*; factored out so the WENO path can reuse it without the parabola coefficients).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | tr(nx,ny,nz) |
MOM6 hup/hlos/min_h two-test limiter on the zonal face transport (volume units). Face i between cell (i-1) and cell (i). Positive flow (uhr_x(i) > 0), donor = cell (i-1): hup = areaT(i-1)·hprev(i-1) − areaT(i-1)·min_h hlos = max(0, −uhr_x(i-1)) (already-committed outflow via the donor’s OTHER (west) face) cap when (hup−hlos)−uhr < 0 AND 0.5·hup−uhr < 0. Negative flow mirror, donor = cell (i).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_min | |||
| real(kind=wp), | intent(in) | :: | uhr_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | uhh_x(nx+1,ny,nz) |
Meridional analogue of drain_limit_x. Face j between cell (i,j-1) and cell (i,j); positive donor = cell (i,j-1).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_min | |||
| real(kind=wp), | intent(in) | :: | uhr_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | uhh_y(nx,ny+1,nz) |
Rebuild the per-cell zonal CW PPM parabola from the CURRENT Tr =
hTr/hprev (V2 — per pass). Interior cells (3..nx-2) use the
limited PPM edges; the 2-cell boundary band falls back to PCM
(aL=aR=Tr ⇒ swept reduces to the donor value, 1st order),
matching tracer_advect_zonal_one_impl’s near-wall band.
TODO(MOM6-fidelity): MOM6 advect_tracer keeps full PPM up to the wall
(dropping to PCM only at genuine local extrema / zero mask2dCu
faces), so we are 1st-order in the 2 cells nearest a true WALL where
MOM6 is PPM-with-mask (periodic seams are fine — the wrap restores
full PPM). Tracked divergence; revisit if near-wall tracer
diffusion matters.
a6 = 6·Tr − 3·(aL+aR). Mirror-T at land neighbours (C2);
bit-identical for all-wet (wet_T≡1).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | tr(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | aL(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | aR(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | a6(nx,ny,nz) |
Meridional analogue of drain_parabola_x. aL = south-edge, aR = north-edge value of each cell. Mirror-T at land neighbours (C2); bit-identical for all-wet.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | tr(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | aL(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | aR(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | a6(nx,ny,nz) |
hprev = max(0, areaT·h_end + div(uhtr,vhtr)) · iareaT, then the
vanishing-layer hatch hprev += max(0, 1e-13·hprev − h_end)
(Adcroft & Hallberg 2006; reuse of VANISHING_LAYER_TOL thinking).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_end(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | uhtr(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | vhtr(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | hprev(nx,ny,nz) |
Re-weight a tracer’s thickness-weighted content onto a new layer thickness, holding the CONCENTRATION fixed:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_new(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | h_old(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) |
drain_rescale_hTr + the closed-budget fill. The concentration
hold / un-hold pair is NOT content-conserving cell by cell –
hTr := Tr·h moves Σ areaT·hTr by Σ areaT·Tr·δh, which is only
zero when Tr is uniform – so both halves have to be recorded or
the closed budget is only valid on window boundaries and wobbles at
every mid-window report. Recording both makes them cancel exactly,
since the un-hold is the arithmetic inverse of the accumulated hold.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_new(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | h_old(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | w | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | budget_adv(nx,ny,nz) |
fld = fld - sub (uhr -= uhh).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | n1 | |||
| integer, | intent(in) | :: | n2 | |||
| integer, | intent(in) | :: | n3 | |||
| real(kind=wp), | intent(in) | :: | sub(n1,n2,n3) | |||
| real(kind=wp), | intent(inout) | :: | fld(n1,n2,n3) |
MOM6 swept-average CW parabola flux for the zonal faces. Face i, donor = cell (i-1) if uhh>0 else cell (i). Per-pass Courant CFL = |uhh| / (areaT·hprev) on the donor, clamped [0,1]. uhh >= 0: F = uhh·( aR − 0.5·CFL·((aR−aL) − a6·(1 − ⅔·CFL)) ) uhh < 0: F = uhh·( aL + 0.5·CFL·((aR−aL) + a6·(1 − ⅔·CFL)) )
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | uhh(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | aL(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | aR(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | a6(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | F(nx+1,ny,nz) |
WENO analogue of drain_swept_flux_x: swept-average zonal face flux
from the concentration field tr using the WENO rung ladder.
recon is TRACER_RECON_WENO5/7/9 (1/2/3); the internal rung_max is
recon + 1 (WENO5→2, WENO7→3, WENO9→4).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nghost | |||
| logical, | intent(in) | :: | periodic | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | uhh(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | tr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| integer, | intent(in) | :: | recon | |||
| real(kind=wp), | intent(inout) | :: | F(nx+1,ny,nz) |
Meridional analogue of drain_swept_flux_x.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | uhh(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | aL(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | aR(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | a6(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | F(nx,ny+1,nz) |
Meridional analogue of drain_swept_flux_x_weno.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nghost | |||
| logical, | intent(in) | :: | periodic | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | uhh(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | hprev(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | tr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| integer, | intent(in) | :: | recon | |||
| real(kind=wp), | intent(inout) | :: | F(nx,ny+1,nz) |
hprev(i) -= (uhh(i+1) - uhh(i))·iareaT (volume div → thickness).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | uhh(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hprev(nx,ny,nz) |
Meridional analogue of drain_update_h_x.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | uhh(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | hprev(nx,ny,nz) |
hTr(i) -= (F(i+1) - F(i))·iareaT (zonal flux divergence; dt is already baked into uhh⊂uhtr, so no dt here).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | F(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) |
drain_update_tracer_x + the closed-budget fill: the SAME increment
written to hTr is accumulated (times w) into budget_adv, so the
console out term sees the horizontal tracer transport the windowed
drain performs. Without this the drain moves tracer that
ms%*_budget_horiz_adv never records, and the Heat/Salt Error
column has to fall back to raw drift (which then reports a live
surface flux as a “leak”). w is
DRAIN_BUDGET_POST_AVERAGE_WEIGHT for every drain call site.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | F(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | w | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | budget_adv(nx,ny,nz) |
Meridional analogue of drain_update_tracer_x.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | F(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) |
Meridional analogue of drain_update_tracer_x_budget.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | F(nx,ny+1,nz) | |||
| real(kind=wp), | intent(in) | :: | w | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | budget_adv(nx,ny,nz) |
Periodic wrap (+ north fold) of a cell-centred drain field.
no_wait (optional): when .true. AND not folding, the periodic wrap
is issued async on queue 1 without syncing, so a caller can batch
several independent wraps (e.g. the pal/par/pa6 parabola triple) and
!$acc wait(1) once. Ignored when fold_n (the fold reads the wrapped
field, so the periodic wrap must complete first).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(nx,ny,nz) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nx_phys | |||
| integer, | intent(in) | :: | ny_phys | |||
| integer, | intent(in) | :: | nghost | |||
| logical, | intent(in) | :: | per_x | |||
| logical, | intent(in) | :: | per_y | |||
| logical, | intent(in) | :: | fold_n | |||
| logical, | intent(in), | optional | :: | no_wait |
Periodic wrap (+ north fold) of an x-face drain field (nx+1,ny,nz).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(nx+1,ny,nz) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nx_phys | |||
| integer, | intent(in) | :: | ny_phys | |||
| integer, | intent(in) | :: | nghost | |||
| logical, | intent(in) | :: | per_x | |||
| logical, | intent(in) | :: | per_y | |||
| logical, | intent(in) | :: | fold_n |
Periodic wrap (+ north fold) of a y-face drain field (nx,ny+1,nz).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(nx,ny+1,nz) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nx_phys | |||
| integer, | intent(in) | :: | ny_phys | |||
| integer, | intent(in) | :: | nghost | |||
| logical, | intent(in) | :: | per_x | |||
| logical, | intent(in) | :: | per_y | |||
| logical, | intent(in) | :: | fold_n |
fld = 0.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | n1 | |||
| integer, | intent(in) | :: | n2 | |||
| integer, | intent(in) | :: | n3 | |||
| real(kind=wp), | intent(inout) | :: | fld(n1,n2,n3) |
Zonal PPM tracer advection of every horizontally-advected tracer by
the GM bolus flux uflux (the resolved path’s own kernel,
tracer_advect_zonal_one_impl; heat/salt budgets weighted by
budget_w). No OBC ghost override: continuity_gm_apply has
closed every non-periodic edge face.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | uflux(grid%nx_total+1,grid%ny_total,ms%nz_ml) |
GM zonal bolus transport (m^3/s). |
||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | budget_w |
Meridional twin of gm_tracer_advect_x.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | vflux(grid%nx_total,grid%ny_total+1,ms%nz_ml) |
GM meridional bolus transport (m^3/s). |
||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | budget_w |
Positive-definite per-donor outflux limiter — meridional (y) pass
(P2). Mirror of pd_limit_zonal_impl; reads the post-zonal-apply
h_layer (= h*), which is exactly the availability the second Lie
pass must respect, and scales mass_flux_y so h_layer >= h_lim
holds after continuity_apply_meridional. Cell (i,j,k) outflow =
(north face j+1 when positive) + (south face j when negative);
interior face j ∈ 2..ny scaled by its upwind donor’s θ (south cell
j−1 when the face flux ≥ 0, else north cell j). See the zonal
twin for the θ construction, ghost range, MPI-seam determinism, and
the v1.1 v_cor re-matching rationale (MOM6 v_cor scaled by the same
per-face θ so it stays consistent with the limited flux).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | h_lim | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | mass_flux_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | theta(nx,ny,nz) | |||
| integer, | intent(inout) | :: | n_limited | |||
| real(kind=wp), | intent(inout), | optional | :: | v_cor(nx,ny+1,nz) |
MOM6 |
Positive-definite per-donor outflux limiter — zonal (x) pass (P2,
plan §P2 / decision D2). Scales the per-layer east-face mass fluxes
DOWN so no donor cell loses more thickness than it holds above the
floor h_lim: guarantees h_layer >= h_lim after
continuity_apply_zonal, with ZERO mass created — outfluxes shrink,
thickness is never inflated (the deliberate contrast with MOM6’s
max(h, Angstrom) injection; the conservative borrow stays the
backstop). Two device passes:
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | h_lim | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | mass_flux_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | theta(nx,ny,nz) | |||
| integer, | intent(inout) | :: | n_limited | |||
| real(kind=wp), | intent(inout), | optional | :: | u_cor(nx+1,ny,nz) |
MOM6 |
Apply a uniform per-face velocity correction so
Σ_k mass_flux_y_layer(i, j, k) = vhbt(i, j) at every face.
Mirror of renormalise_zonal_flux_to_uhbt. See that routine
for the skip_walls and has_* (MPI seam, O4 fix) semantics.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(in) | :: | this |
Read-only here (only the PPM edge buffers are consulted).
|
||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | vhbt(:,:) | |||
| real(kind=wp), | intent(in) | :: | dt |
Outer-step dt (s), for the CFL bracket on |
||
| logical, | intent(in), | optional | :: | skip_walls | ||
| logical, | intent(in), | optional | :: | has_south |
Physical-edge flags (default .true. = single-rank behaviour, bit-identical); .false. at a y-decomposition seam forces the local wall-position face to be renormalised as interior. |
|
| logical, | intent(in), | optional | :: | has_north |
Physical-edge flags (default .true. = single-rank behaviour, bit-identical); .false. at a y-decomposition seam forces the local wall-position face to be renormalised as interior. |
|
| real(kind=wp), | intent(in), | optional | :: | visc_rem(:,:,:) |
Per-layer viscous remnant γ_k. Absent ⇒ γ ≡ 1, bit-identical.
See |
|
| real(kind=wp), | intent(inout), | optional | :: | v_cor(:,:,:) |
MOM6 |
|
| logical, | intent(in) | :: | use_por |
Porous barriers active. |
||
| real(kind=wp), | intent(in) | :: | por(grid%nx_total,grid%ny_total+1,ms%nz_ml) |
Layer-averaged open-area fraction at this stagger (nondim),
read ONLY when |
||
| logical, | intent(in) | :: | use_open |
z-level closed faces active. |
||
| real(kind=wp), | intent(in) | :: | open_f(grid%nx_total,grid%ny_total+1,ms%nz_ml) |
Per-layer 0/1 face-open mask at this stagger, read ONLY when
|
Apply a uniform per-face velocity correction so
Σ_k mass_flux_x_layer(i, j, k) = uhbt(i, j) at every face.
Helper for continuity_zonal_flux.
skip_walls (default true) bypasses the physical-wall faces
where mass_flux was zeroed; pass .false. for periodic axes
so the wall faces (which carry real transport) are renormalised.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(in) | :: | this |
Read-only here (only the PPM edge buffers are consulted).
|
||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | uhbt(:,:) | |||
| real(kind=wp), | intent(in) | :: | dt |
Outer-step dt (s), for the CFL bracket on |
||
| logical, | intent(in), | optional | :: | skip_walls |
When .true. (default), cycle the physical-wall faces. When .false. (periodic axis), include them in the renorm. |
|
| logical, | intent(in), | optional | :: | has_west |
Physical-edge flags (default .true. = single-rank behaviour,
bit-identical). .false. at an MPI seam: the local “wall
position” face |
|
| logical, | intent(in), | optional | :: | has_east |
Physical-edge flags (default .true. = single-rank behaviour,
bit-identical). .false. at an MPI seam: the local “wall
position” face |
|
| real(kind=wp), | intent(in), | optional | :: | visc_rem(:,:,:) |
Per-layer viscous remnant γ_k weighting the barotropic increment
(MOM6 |
|
| real(kind=wp), | intent(inout), | optional | :: | u_cor(:,:,:) |
MOM6’s |
|
| logical, | intent(in) | :: | use_por |
Porous barriers active. |
||
| real(kind=wp), | intent(in) | :: | por(grid%nx_total+1,grid%ny_total,ms%nz_ml) |
Layer-averaged open-area fraction at this stagger (nondim),
read ONLY when |
||
| logical, | intent(in) | :: | use_open |
z-level closed faces active ( |
||
| real(kind=wp), | intent(in) | :: | open_f(grid%nx_total+1,grid%ny_total,ms%nz_ml) |
Per-layer 0/1 face-open mask at this stagger, read ONLY when
|
Test-only (no production caller): unsplit 2-D tracer advection,
the reference oracle for split tracer_advect_zonal/_meridional.
Per-layer PPM tracer advection — iterates over the tracer
registry on the multilayer C-grid state and forwards each
tracer’s hTr array to the flat-impl below. Extendable by
construction: appending a new entry to ms%tracers(:) (BGC,
sediment, passive scalar) drops it in without touching this
routine. Per-tracer behaviour gates on
tracer_t%do_horizontal_advection — set to .false. for
tracers that should be diagnostic / forced externally.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt |
Meridional half of the direction-split tracer advection.
Reads the post-zonal h_layer (since
continuity_apply_zonal has already updated h
in the split flow) and the just-computed
mass_flux_y_layer from
continuity_meridional_flux.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
Meridional half of tracer_advect_one_impl. Same shape
as the zonal impl, applied to y. In the split flow, h
here is the post-zonal-apply thickness so the Tr = hTr/h
reconstruction stays consistent with what continuity used
in continuity_meridional_flux. iareaT = inv_dy on
uniform metrics; mass_flux_y carries dx_cv. Mirror-T at
land neighbours (C2); bit-identical for all-wet.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | mass_flux_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_left_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_right_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout), | optional | :: | budget_adv(nx,ny,nz) |
Per-cell meridional-advection budget accumulator (PSU·m or °C·m per cell). Added to the same array as the zonal half so the net entry covers both directions. Absent ⇒ inert. |
|
| real(kind=wp), | intent(in), | optional | :: | budget_w |
Bookkeeping weight on the |
One-tracer PPM advection. Flat-impl: takes bare 3D arrays (no derived-type deref inside do-concurrent), so NVHPC stdpar handles it cleanly even for tracers stored in an array-of-derived-types registry.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | mass_flux_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | mass_flux_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_left_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_right_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_left_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_right_y(nx,ny+1,nz) |
Zonal half of the direction-split tracer advection.
Mirrors tracer_advect but updates hTr using
only the x-direction tracer mass flux. Companion to
tracer_advect_meridional. Both are called
interleaved with the continuity substeps by
continuity_tracer_step_split to preserve CWC.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(continuity_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
Zonal half of tracer_advect_one_impl. Same three-pass
pattern (PPM reconstruction → upwind pick into tracer mass
flux → forward-Euler update) but only the x-direction half.
Reads the input h for the Tr = hTr/h reconstruction. The
tracer transport mass_flux_x·Tr_face inherits dy_cu, and
the divergence closes with iareaT (= inv_dx on uniform).
Mirror-T at land neighbours (C2): a held land column’s tracer
is reflected to the local cell so the wet-side face value is
unbiased; bit-identical for all-wet (wet_T≡1).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | wet_T(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | mass_flux_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_left_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_right_x(nx+1,ny,nz) | |||
| real(kind=wp), | intent(inout), | optional | :: | budget_adv(nx,ny,nz) |
Per-cell accumulator for the horizontal-advection budget (same sign/units as hTr). When present, the zonal-flux divergence is added (+=) here after the prognostic update. Absent ⇒ inert (byte-identical to the pre-feature build). |
|
| real(kind=wp), | intent(in), | optional | :: | budget_w |
Bookkeeping weight on the |