Redi neutral (along-isopycnal) tracer diffusion. Continuous (non-iterative) neutral-surface geometry of the Griffies rotated-diffusion tensor + the two-phase GPU flux kernel. Clean-room from Redi (1982), Griffies et al. (1998), Griffies (2004).
INDEXING CONVENTION (load-bearing). The neutral-surface sweep routines are transcribed TOP-DOWN — k=1 surface interface, k=nk+1 bed. rdb is bottom-up (k=1 bed, k=nk surface); the k-flip is confined to the Phase-B flux scatter (native k = nz+1-Ko). Do NOT call the sweep routines with bottom-up arrays without flipping first.
&vcoord_nml zfixed_closed_faces)Under z_fixed a face column is not the whole water column: a layer that
is an inert FILLER on either side (inside the bed, or inside the ice
draft) is a WALL for that layer at that face (metrics%open_u/open_v ==
0). Neutral diffusion pairs the two columns of a face by sweeping
neutral surfaces through BOTH columns, so without a seam it pairs a layer
that is closed at the face (live on the deep side, below the shallow
side’s bed) with live water on the other side — a tracer flux THROUGH
the wall, as large as any open-face flux once the isopycnals tilt by more
than a bed step — plus an O(h_min) one into the fillers themselves
(test_ocean_redi_zfixed).
With the knob on (metrics%use_closed_faces) each face is reduced to its
OPEN WINDOW before anything else is done with it:
ok(k) = open(k) .and. live(h_W(k)) .and. live(h_E(k))
kt = the topmost ok layer
kb..kt = the contiguous run of ok layers counted down from kt
(rdb_vl_is_live, the one vanished-layer predicate; ok is the set
GM’s open-column streamfunction uses). Phase A builds both columns’
interface T/S/P and runs the continuous sweep on the nk = kt-kb+1
window layers ONLY, so a neutral surface can neither start nor end in a
filler or a closed face-layer, and the PPM edge reconstruction never
reads a filler (PCM ends at the window edges — the sweep’s own
b_method = 1). Phase B rebuilds the tracer columns on the same window
and scatters only into native layers inside it, so the flux on every
closed face-layer and every filler is EXACTLY zero.
ok is contiguous
by construction; a gap (a layer that thinned to the marker in
mid-column) would cut the window there — the layers below it take no
Redi flux at that face — rather than be paired across.P is the surface-relative hydrostatic pressure
of the FULL column sliced to the window (fillers above it add their
h_min), so an all-open face is the original arithmetic operation
for operation.Ko stays in the full TOP-DOWN frame (Ko_win + nz -
kt), so the Phase-B scatter native k = nz+1-Ko is unchanged; the
trailing 2*(nz-nk) surfaces of a short window are inert padding
(hEff = 0, never read). The window is stored per face (uKb/uKt,
vKb/vKt) because Phase B runs at later time levels than Phase A; a
window layer that is no longer live on both sides when Phase B runs
skips the whole face — both cells of the face read the same h, so
the skip is symmetric and content is still conserved.Content is conserved exactly as before (each sublayer flux is formed
identically by both cells of the face and enters one with +, the other
with -), and the down-gradient sign guard is untouched, so the flux is
still down the along-neutral gradient. Every divisor in the window is a
live thickness (> H_VANISHED), so the port opens no new non-finite
path. Knob OFF ⇒ kb = 1, kt = nz on every face, the window IS the
column and the arithmetic is the full-column form ⇒ byte-identical.
Redi continuous neutral-diffusion state. Defaults inert
(enable=.false.) ⇒ bit-identical. Reads the prognostic T/S + EOS
directly (recomputes its own interface dR/dT, dR/dS — does NOT
consume GM slopes). Augments rdb_ocean_hdiff_tracer.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| logical, | public | :: | continuous | = | .true. |
Continuous variant (the only one shipped). Discontinuous
deferred (R4); a |
|
| logical, | public | :: | enable | = | .false. |
Master switch. Off => |
|
| logical, | public | :: | is_init | = | .false. |
True between init/destroy; gate on this, not on |
|
| real(kind=wp), | public | :: | khtr | = | 0.0_wp |
Scalar Redi neutral diffusivity (m^2/s); the FALLBACK used when
VarMix is off (0 => no flux). When VarMix is enabled its
spatially-varying |
|
| real(kind=wp), | public, | allocatable | :: | khtr_u(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | khtr_v(:,:) | |||
| integer, | public | :: | nsurf | = | 0 |
2*nz_ml + 2 (the neutral-surface count of the continuous sweep). |
|
| integer, | public | :: | nx_total | = | 0 | ||
| integer, | public | :: | ny_total | = | 0 | ||
| integer, | public | :: | nz_ml | = | 0 | ||
| real(kind=wp), | public, | allocatable | :: | tr_snap(:,:,:) | |||
| integer, | public, | allocatable | :: | uKb(:,:) | |||
| integer, | public, | allocatable | :: | uKoL(:,:,:) | |||
| integer, | public, | allocatable | :: | uKoR(:,:,:) | |||
| integer, | public, | allocatable | :: | uKt(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | uPoL(:,:,:) | |||
| real(kind=wp), | public, | allocatable | :: | uPoR(:,:,:) | |||
| real(kind=wp), | public, | allocatable | :: | uhEff(:,:,:) | |||
| integer, | public, | allocatable | :: | vKb(:,:) | |||
| integer, | public, | allocatable | :: | vKoL(:,:,:) | |||
| integer, | public, | allocatable | :: | vKoR(:,:,:) | |||
| integer, | public, | allocatable | :: | vKt(:,:) | |||
| real(kind=wp), | public, | allocatable | :: | vPoL(:,:,:) | |||
| real(kind=wp), | public, | allocatable | :: | vPoR(:,:,:) | |||
| real(kind=wp), | public, | allocatable | :: | vhEff(:,:,:) |
| procedure, public, non_overridable :: bytes => ocean_redi_bytes | |
| procedure, public, non_overridable :: destroy => ocean_redi_destroy | |
| procedure, public, non_overridable :: enter_data => ocean_redi_enter_data | |
| procedure, public, non_overridable :: exit_data => ocean_redi_exit_data | |
| procedure, public, non_overridable :: init => ocean_redi_init |
Non-dimensional position in [0,1] where the interpolated density difference is zero. Guards the vanished/inverted (Ppos==Pneg) and degenerate (dRhoPos==dRhoNeg) cases device-safely (clamped values, no host I/O).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | dRhoNeg |
negative density difference |
||
| real(kind=wp), | intent(in) | :: | Pneg |
position of the negative difference |
||
| real(kind=wp), | intent(in) | :: | dRhoPos |
positive density difference |
||
| real(kind=wp), | intent(in) | :: | Ppos |
position of the positive difference |
Counted allocatable footprint of the Redi 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(ocean_redi_t), | intent(in) | :: | this |
Absolute (pressure) position of neutral surface ks in a column
(MOM6 absolute_position): Pint(K) + frac*(Pint(K+1)-Pint(K)).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nk | |||
| real(kind=wp), | intent(in) | :: | Pint(nk+1) |
interface pressures |
||
| integer, | intent(in) | :: | Karr |
layer index for this surface |
||
| real(kind=wp), | intent(in) | :: | frac |
fractional position within the layer |
Second-order centred finite-volume slope of a layer scalar (MOM6
fv_diff; Colella & Woodward 1984). Returns the cell-centred difference
across layer k given the three layer thicknesses and values.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | hkm1 |
layer thicknesses (above/centre/below) |
||
| real(kind=wp), | intent(in) | :: | hk |
layer thicknesses (above/centre/below) |
||
| real(kind=wp), | intent(in) | :: | hkp1 |
layer thicknesses (above/centre/below) |
||
| real(kind=wp), | intent(in) | :: | skm1 |
layer scalar values |
||
| real(kind=wp), | intent(in) | :: | sk |
layer scalar values |
||
| real(kind=wp), | intent(in) | :: | skp1 |
layer scalar values |
Mean of a PPM parabola between fractional positions xL,xR in [0,1]
(MOM6 ppm_ave). Device-safe: dx<0 / dx>1 FATALs collapse to the
dx==0 branch value (no host I/O on device).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | xL | |||
| real(kind=wp), | intent(in) | :: | xR | |||
| real(kind=wp), | intent(in) | :: | aL | |||
| real(kind=wp), | intent(in) | :: | aR | |||
| real(kind=wp), | intent(in) | :: | aMean |
PPM quasi-fourth-order edge value at interface k+1/2 (MOM6 ppm_edge;
Colella & Woodward 1984 eq. 1.6).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | hkm1 |
widths of cells k-1..k+2 |
||
| real(kind=wp), | intent(in) | :: | hk |
widths of cells k-1..k+2 |
||
| real(kind=wp), | intent(in) | :: | hkp1 |
widths of cells k-1..k+2 |
||
| real(kind=wp), | intent(in) | :: | hkp2 |
widths of cells k-1..k+2 |
||
| real(kind=wp), | intent(in) | :: | ak |
cell averages k, k+1 |
||
| real(kind=wp), | intent(in) | :: | akp1 |
cell averages k, k+1 |
||
| real(kind=wp), | intent(in) | :: | pk |
PLM slopes k, k+1 |
||
| real(kind=wp), | intent(in) | :: | pkp1 |
PLM slopes k, k+1 |
||
| real(kind=wp), | intent(in) | :: | h_neglect |
negligible thickness floor |
A true signum: -|a| if x<0, +|a| if x>0, 0 if x==0 (MOM6 signum).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | a | |||
| real(kind=wp), | intent(in) | :: | x |
signum(1.,x): -1 if x<0, +1 if x>0, 0 if x==0 (MOM6 sign guard).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | x |
Along-neutral tracer difference for one sublayer (MOM6 neutral_surface_flux continuous branch). TOP-DOWN layer indices (klt/klb = KoL at the surface/bed bound of the sublayer; krt/krb mirror) and fractional positions. Returns dT_layer when the top/bottom/ave/layer triad is sign-consistent, else 0 (the down-gradient guard that prevents up-gradient transport).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | klt | |||
| integer, | intent(in) | :: | klb | |||
| integer, | intent(in) | :: | krt | |||
| integer, | intent(in) | :: | krb | |||
| real(kind=wp), | intent(in) | :: | PoLt | |||
| real(kind=wp), | intent(in) | :: | PoLb | |||
| real(kind=wp), | intent(in) | :: | PoRt | |||
| real(kind=wp), | intent(in) | :: | PoRb | |||
| real(kind=wp), | intent(in) | :: | TlL(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | TiL(NZ_STACK_MAX+1) | |||
| real(kind=wp), | intent(in) | :: | aLL(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | aRL(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | TlR(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | TiR(NZ_STACK_MAX+1) | |||
| real(kind=wp), | intent(in) | :: | aLR(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | aRR(NZ_STACK_MAX) |
Public Phase-B entry: apply the neutral-diffusion tracer update for
every registered tracer. No-op if absent / uninit / disabled / zero
diffusivity. Run at thermo cadence after redi_calc_coeffs and the
along-coordinate tracer_hdiff (Redi augments it). Per-face KhTr
comes from khtr_u_ext/khtr_v_ext (VarMix) when supplied, else the
scalar this%khtr broadcast onto every face.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(ocean_redi_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(in), | optional | :: | khtr_u_ext(:,:) |
VarMix per-face KhTr at u-faces |
|
| real(kind=wp), | intent(in), | optional | :: | khtr_v_ext(:,:) |
VarMix per-face KhTr at v-faces |
|
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
Per-edge OBC tags. No along-isopycnal flux crosses a
no-normal-flow ( |
Public entry: fill the Phase-A coefficient arrays. No-op if absent / uninitialised / disabled. Run once per outer step at THERMO cadence (a slow, tracer-independent geometry). Outer-shim: dereference the tracer-registry hTr arrays on the host, pass the flat top-level allocatables to the flat-impl kernels.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(eos_t), | intent(in) | :: | eos | |||
| type(ocean_redi_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(in) | :: | ms |
PPM continuous edge reconstruction of a layer scalar to interfaces
(MOM6 interface_scalar with i_method=2). edge(1)=surface,
edge(nk+1)=bed in the MOM6 top-down sense (see module header on the
deferred k-flip).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nk | |||
| real(kind=wp), | intent(in) | :: | h(nk) |
layer thicknesses |
||
| real(kind=wp), | intent(in) | :: | tr(nk) |
layer scalar (e.g. T) |
||
| real(kind=wp), | intent(out) | :: | edge(nk+1) |
interface scalar |
||
| real(kind=wp), | intent(in), | optional | :: | h_neglect |
negligible thickness (default 1e-30) |
The continuous neutral-surface sweep over a column pair. A single
deterministic top→bottom sweep of 2*nk+2 surfaces walking two interface
pointers; closed-form linear crossing per step (no inner iteration).
Inputs are interface T/S/P + interface dR/dT, dR/dS (nk+1 each). Outputs
PoL/PoR (fractional position within layer KoL/KoR) and hEff
(harmonic-mean effective thickness between consecutive neutral surfaces;
outcrops get hEff=0, not skipped). TOP-DOWN indexing (see module header).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nk | |||
| real(kind=wp), | intent(in) | :: | Pl(nk+1) |
left interface P, T, S |
||
| real(kind=wp), | intent(in) | :: | Tl(nk+1) |
left interface P, T, S |
||
| real(kind=wp), | intent(in) | :: | Sl(nk+1) |
left interface P, T, S |
||
| real(kind=wp), | intent(in) | :: | dRdTl(nk+1) |
left interface dR/dT, dR/dS |
||
| real(kind=wp), | intent(in) | :: | dRdSl(nk+1) |
left interface dR/dT, dR/dS |
||
| real(kind=wp), | intent(in) | :: | Pr(nk+1) |
right interface P, T, S |
||
| real(kind=wp), | intent(in) | :: | Tr(nk+1) |
right interface P, T, S |
||
| real(kind=wp), | intent(in) | :: | Sr(nk+1) |
right interface P, T, S |
||
| real(kind=wp), | intent(in) | :: | dRdTr(nk+1) |
right interface dR/dT, dR/dS |
||
| real(kind=wp), | intent(in) | :: | dRdSr(nk+1) |
right interface dR/dT, dR/dS |
||
| real(kind=wp), | intent(out) | :: | PoL(2*nk+2) |
fractional positions |
||
| real(kind=wp), | intent(out) | :: | PoR(2*nk+2) |
fractional positions |
||
| integer, | intent(out) | :: | KoL(2*nk+2) |
layer indices |
||
| integer, | intent(out) | :: | KoR(2*nk+2) |
layer indices |
||
| real(kind=wp), | intent(out) | :: | hEff(2*nk+1) |
effective thicknesses |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_redi_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_redi_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_redi_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_redi_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_redi_t), | intent(inout) | :: | this |
Allocate the Phase-A coefficient arrays. Always allocates
(configure runs after init); off-state footprint is the six
face-shaped (nsurf) coefficient arrays. Plain host allocation
(no do concurrent before enter_data).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_redi_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in), | optional | :: | nz_ml |
Flat-impl Phase-B kernel for ONE tracer. Cell-centric double-visit
(no-scatter rule on the C-grid): cell (i,j) recomputes the
along-neutral flux on each of its four bounding faces and accumulates
ONLY into its own dTr; interior-face fluxes are computed twice but
no thread writes a neighbour ⇒ race-free.
Face sign: the LEFT (west/south) cell of a face gets +Flx into
native layer nz+1-KoL; the RIGHT (east/north) cell gets -Flx into
nz+1-KoR. The top-down→native flip k=nz+1-Ko is the only k-flip.
Flux = dT_layer * hEff * Coef, Coef_u = dtkhtr_udy_cu*idxCu;
divergence hTr(k) += dTr(k)/areaT (conservative).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | ns | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| integer, | intent(in) | :: | nghost | |||
| integer, | intent(in) | :: | nxp | |||
| integer, | intent(in) | :: | nyp | |||
| logical, | intent(in) | :: | wall_w | |||
| logical, | intent(in) | :: | wall_e | |||
| logical, | intent(in) | :: | wall_s | |||
| logical, | intent(in) | :: | wall_n | |||
| real(kind=wp), | intent(in) | :: | khtr_u(nx+1,ny) | |||
| real(kind=wp), | intent(in) | :: | khtr_v(nx,ny+1) | |||
| real(kind=wp), | intent(in) | :: | dy_cu(nx+1,ny) | |||
| real(kind=wp), | intent(in) | :: | dx_cv(nx,ny+1) | |||
| real(kind=wp), | intent(in) | :: | idxCu(nx+1,ny) | |||
| real(kind=wp), | intent(in) | :: | idyCv(nx,ny+1) | |||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hTr_in(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | uPoL(nx+1,ny,ns) | |||
| real(kind=wp), | intent(in) | :: | uPoR(nx+1,ny,ns) | |||
| integer, | intent(in) | :: | uKoL(nx+1,ny,ns) | |||
| integer, | intent(in) | :: | uKoR(nx+1,ny,ns) | |||
| real(kind=wp), | intent(in) | :: | uhEff(nx+1,ny,ns-1) | |||
| real(kind=wp), | intent(in) | :: | vPoL(nx,ny+1,ns) | |||
| real(kind=wp), | intent(in) | :: | vPoR(nx,ny+1,ns) | |||
| integer, | intent(in) | :: | vKoL(nx,ny+1,ns) | |||
| integer, | intent(in) | :: | vKoR(nx,ny+1,ns) | |||
| real(kind=wp), | intent(in) | :: | vhEff(nx,ny+1,ns-1) | |||
| integer, | intent(in) | :: | uKb(nx+1,ny) |
Phase-A u-face open windows ( |
||
| integer, | intent(in) | :: | uKt(nx+1,ny) |
Phase-A u-face open windows ( |
||
| integer, | intent(in) | :: | vKb(nx,ny+1) |
Phase-A v-face open windows. |
||
| integer, | intent(in) | :: | vKt(nx,ny+1) |
Phase-A v-face open windows. |
||
| logical, | intent(in) | :: | use_open |
z-level closed faces active: re-check window liveness. |
budget += hTr - snap (device-side): book the realised Redi
increment of one budgeted tracer into its lateral-diffusion
budget accumulator (ms%salt_budget_hdiff / heat_budget_hdiff).
| 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) | :: | snap(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | budget(nx,ny,nz) |
Build one column’s TOP-DOWN interface P/T/S + density derivs from the
BOTTOM-UP native column, restricted to the face’s open window
kb..kt (nk = kt-kb+1 layers; the whole column 1..nz off the
z-level closed-face path). Layer T/S = the I1′ column read
(rdb_vl_column_conc: hTr/h on a live layer, the donor’s
concentration on a vanished one); interface
T/S = PPM edge reconstruction on the flipped window; interface P =
surface-relative hydrostatic, seeded with the column ABOVE the
window (fillers under an ice draft; nothing — exactly 0 — when
kt = nz); dR/dT, dR/dS = -rho² dSV/dX at each interface. Only
the first nk+1 entries of the outputs are written.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | kb |
Native (bottom-up) open window, |
||
| integer, | intent(in) | :: | kt |
Native (bottom-up) open window, |
||
| real(kind=wp), | intent(in) | :: | h_col(nz) | |||
| real(kind=wp), | intent(in) | :: | thtr_col(nz) | |||
| real(kind=wp), | intent(in) | :: | shtr_col(nz) | |||
| type(eos_t), | intent(in) | :: | eos | |||
| real(kind=wp), | intent(out) | :: | Pint(nz+1) | |||
| real(kind=wp), | intent(out) | :: | Tint(nz+1) | |||
| real(kind=wp), | intent(out) | :: | Sint(nz+1) | |||
| real(kind=wp), | intent(out) | :: | dRdT(nz+1) | |||
| real(kind=wp), | intent(out) | :: | dRdS(nz+1) |
Flat-impl Phase-A u-face kernel. Parallel over (i,j) interior
u-faces (i=2..nx); the 2*nz+2 sweep runs serially inside each
thread over a column pair (iw=i-1 west, i east). Wall faces and
land faces leave the inert (zero/identity) coefficients. The
sweep runs on each face’s open window uKb..uKt (1..nz off the
z-level closed-face path; module header); a face with no open
layer (uKt < uKb) is inert.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | ns | |||
| type(eos_t), | intent(in) | :: | eos | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | t_htr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | s_htr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_u(nx+1,ny) | |||
| integer, | intent(in) | :: | uKb(nx+1,ny) |
Per-face open window (native layers). |
||
| integer, | intent(in) | :: | uKt(nx+1,ny) |
Per-face open window (native layers). |
||
| real(kind=wp), | intent(out) | :: | uPoL(nx+1,ny,ns) | |||
| real(kind=wp), | intent(out) | :: | uPoR(nx+1,ny,ns) | |||
| integer, | intent(out) | :: | uKoL(nx+1,ny,ns) | |||
| integer, | intent(out) | :: | uKoR(nx+1,ny,ns) | |||
| real(kind=wp), | intent(out) | :: | uhEff(nx+1,ny,ns-1) |
Flat-impl Phase-A v-face kernel — mirror of _x with v-stagger
(js=j-1 south, j north), loop j=2..ny, open window vKb..vKt.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | ns | |||
| type(eos_t), | intent(in) | :: | eos | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | t_htr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | s_htr(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_v(nx,ny+1) | |||
| integer, | intent(in) | :: | vKb(nx,ny+1) |
Per-face open window (native layers). |
||
| integer, | intent(in) | :: | vKt(nx,ny+1) |
Per-face open window (native layers). |
||
| real(kind=wp), | intent(out) | :: | vPoL(nx,ny+1,ns) | |||
| real(kind=wp), | intent(out) | :: | vPoR(nx,ny+1,ns) | |||
| integer, | intent(out) | :: | vKoL(nx,ny+1,ns) | |||
| integer, | intent(out) | :: | vKoR(nx,ny+1,ns) | |||
| real(kind=wp), | intent(out) | :: | vhEff(nx,ny+1,ns-1) |
The per-face Phase-A core: build both columns TOP-DOWN on the open
window kb..kt (the whole column off the closed-face path), run the
sweep on its nk = kt-kb+1 layers, and store PoL/PoR/KoL/KoR/hEff in
the FULL top-down frame (Ko + nz - kt). The k-flip is confined to
the Phase-B scatter; keeping Po/Ko top-down here lets the flux re-use
the sweep’s interface-edge convention with no position arithmetic on
the flipped frame. A short window (nk < nz) leaves 2*(nz-nk)
trailing surfaces, filled as inert padding: the last surface
repeated and hEff = 0, which Phase B skips.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | ns | |||
| integer, | intent(in) | :: | kb |
Native (bottom-up) open window, |
||
| integer, | intent(in) | :: | kt |
Native (bottom-up) open window, |
||
| real(kind=wp), | intent(in) | :: | hL(nz) | |||
| real(kind=wp), | intent(in) | :: | tL(nz) | |||
| real(kind=wp), | intent(in) | :: | sL(nz) | |||
| real(kind=wp), | intent(in) | :: | hR(nz) | |||
| real(kind=wp), | intent(in) | :: | tR(nz) | |||
| real(kind=wp), | intent(in) | :: | sR(nz) | |||
| type(eos_t), | intent(in) | :: | eos | |||
| real(kind=wp), | intent(out) | :: | PoLo(ns) | |||
| real(kind=wp), | intent(out) | :: | PoRo(ns) | |||
| integer, | intent(out) | :: | KoLo(ns) | |||
| integer, | intent(out) | :: | KoRo(ns) | |||
| real(kind=wp), | intent(out) | :: | hEffo(ns-1) |
Broadcast the scalar KhTr val onto every face of dst (n1, n2).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | n1 | |||
| integer, | intent(in) | :: | n2 | |||
| real(kind=wp), | intent(in) | :: | val | |||
| real(kind=wp), | intent(inout) | :: | dst(n1,n2) |
Copy a face KhTr field src -> dst (both (n1, n2)), device-side.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | n1 | |||
| integer, | intent(in) | :: | n2 | |||
| real(kind=wp), | intent(in) | :: | src(n1,n2) | |||
| real(kind=wp), | intent(inout) | :: | dst(n1,n2) |
Accumulate ONE C-grid face’s neutral-surface tracer flux into the
owning cell’s dTr. Builds the left/right tracer columns from the
READ-ONLY snapshot hTr_in (the live hTr is also written by the
loop — reading it would be a do-concurrent read-write race) and loops
the ns-1 neutral sublayers. The per-face column locals live in this
frame to keep the caller’s loop-body footprint small.
is_left: this cell is the LEFT (west/south) column ⇒ +flx into
native layer nz+1-KoL; else the RIGHT column ⇒ -flx into
nz+1-KoR. (iL,jL)/(iR,jR) index the columns; (fa,fb) the faces.
kb..kt is the face’s Phase-A open window (1..nz off the z-level
closed-face path): the tracer columns are reconstructed on it alone
and the full-frame Ko are read in the window frame (Ko - nz +
kt). An empty window, or (use_open) one whose layers are no
longer all live on both sides, contributes nothing — both cells of
the face take the same decision from the same h.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | ns | |||
| integer, | intent(in) | :: | nxc | |||
| integer, | intent(in) | :: | nyc | |||
| integer, | intent(in) | :: | nfa | |||
| integer, | intent(in) | :: | nfb | |||
| real(kind=wp), | intent(in) | :: | h_layer(nxc,nyc,nz) | |||
| real(kind=wp), | intent(in) | :: | hTr_in(nxc,nyc,nz) | |||
| integer, | intent(in) | :: | iL | |||
| integer, | intent(in) | :: | jL | |||
| integer, | intent(in) | :: | iR | |||
| integer, | intent(in) | :: | jR | |||
| integer, | intent(in) | :: | fa | |||
| integer, | intent(in) | :: | fb | |||
| real(kind=wp), | intent(in) | :: | PoL(nfa,nfb,ns) | |||
| real(kind=wp), | intent(in) | :: | PoR(nfa,nfb,ns) | |||
| integer, | intent(in) | :: | KoL(nfa,nfb,ns) | |||
| integer, | intent(in) | :: | KoR(nfa,nfb,ns) | |||
| real(kind=wp), | intent(in) | :: | hEff(nfa,nfb,ns-1) | |||
| integer, | intent(in) | :: | kb | |||
| integer, | intent(in) | :: | kt | |||
| logical, | intent(in) | :: | use_open | |||
| real(kind=wp), | intent(in) | :: | coef | |||
| logical, | intent(in) | :: | is_left | |||
| real(kind=wp), | intent(inout) | :: | dTr(nz) |
A face’s OPEN WINDOW from its per-layer ok flags (open .and.
live on both sides; module header): kt the topmost ok layer,
kb..kt the contiguous ok run counted down from it. No ok
layer ⇒ kb = 1, kt = 0 (an empty window, kt < kb).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| logical, | intent(in) | :: | ok(NZ_STACK_MAX) | |||
| integer, | intent(out) | :: | kb | |||
| integer, | intent(out) | :: | kt |
Fill every interior u-face’s OPEN WINDOW (&vcoord_nml
zfixed_closed_faces; module header): ok(k) = open_u .and. live
on both sides (rdb_vl_is_live), then redi_open_window.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | open_u(nx+1,ny,nz) |
Per-layer 0/1 u-face open mask ( |
||
| integer, | intent(inout) | :: | uKb(nx+1,ny) | |||
| integer, | intent(inout) | :: | uKt(nx+1,ny) |
v-face twin of redi_open_windows_x (south j-1, north j).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | open_v(nx,ny+1,nz) |
Per-layer 0/1 v-face open mask ( |
||
| integer, | intent(inout) | :: | vKb(nx,ny+1) | |||
| integer, | intent(inout) | :: | vKt(nx,ny+1) |
PLM van-Leer-limited layer-difference array (MOM6 PLM_diff with
c_method=2 finite-volume slope, b_method=1 PCM ends) — the slope input to
the PPM edge interpolation.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nk | |||
| real(kind=wp), | intent(in) | :: | h(nk) |
layer thicknesses |
||
| real(kind=wp), | intent(in) | :: | s(nk) |
layer scalar values |
||
| real(kind=wp), | intent(out) | :: | diff(nk) |
limited layer difference (PCM ends) |
Device-side copy dst = src of a (nx,ny,nz) tracer field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | src(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | dst(nx,ny,nz) |
Build one column’s TOP-DOWN layer-average tracer Tlay, PPM
interface edges Tint, and per-layer limited PPM left/right edges
aLe/aRe from the bottom-up native (h, hTr) column (fixed-size
NZ_STACK_MAX copies), restricted to the face’s open window
kb..kt (1..nz off the z-level closed-face path) — indexed in
the WINDOW top-down frame, 1..nk, nk = kt-kb+1. Tlay = the I1′
column read (rdb_vl_column_conc, see redi_build_column).
Mirrors MOM6 interface_scalar + ppm_left_right_edge_values.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | kb |
Native (bottom-up) open window, |
||
| integer, | intent(in) | :: | kt |
Native (bottom-up) open window, |
||
| real(kind=wp), | intent(in) | :: | h_col(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | htr_col(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(out) | :: | Tlay(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(out) | :: | Tint(NZ_STACK_MAX+1) | |||
| real(kind=wp), | intent(out) | :: | aLe(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(out) | :: | aRe(NZ_STACK_MAX) |