Drives the conservative vertical remap of multilayer.h_layer + every
registered multilayer.tracers(t)%hTr from the current (Lagrangian) grid
to vcoord%target_h. The kernel is the per-column remap_column from
rdb_remap_column (shared with coastal); this module wires it across the
registered tracer slot list plus the face-velocity pass.
Per-column conservation: sum_k(hTr) is preserved to machine precision.
The c = hTr/h ↔ hTr = c·h round trip is protected by a TWO-SIDED
vanishing-layer guard (rdb_vl_merge_content, invariant I1′) which
keeps the content of a sub-threshold layer in the column instead of
deleting it, and leaves every sub-threshold layer holding h·c_live,
the concentration of its donor live layer. See
src/core/ocean/README.md (“The vanished-layer content rule”).
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public, | parameter | :: | OCEAN_REMAP_PRECOND_RTOL | = | 1.0e-9_wp |
Relative tolerance on |
| real(kind=wp), | private, | parameter | :: | H_FLOOR | = | H_VANISHED |
Orchestrate the centre-cell pass of the ALE remap step (h_layer +
tracers). Public only for the unit-test suite.
Sequence: skip if EULERIAN_Z/LAGRANGIAN; snapshot column total + h_old;
build vcoord%target_h; remap each tracer h_old→target_h via the PPM
column kernel; set h_layer = target_h; recompute
bt_eta = sum_k(h_layer) - bt_H_ref. Face velocities remapped separately.
Takes bt_eta/bt_H_ref directly (not ocean_dyn_t) so this module sits
below the split driver in the dependency tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_vcoord_t), | intent(inout) | :: | vcoord | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(inout) | :: | bt_eta(:,:) |
Free-surface anomaly η at cell centres (m). Updated to
|
||
| real(kind=wp), | intent(in) | :: | bt_H_ref(:,:) |
Reference column depth H (m, positive-down). Constant for the ocean path; passed in so the routine doesn’t need a handle on the split-driver state. |
||
| integer, | intent(in), | optional | :: | method |
REMAP_PCM / REMAP_PLM / REMAP_PPM. Defaults to PPM (parabolic stencil cuts the spurious vertical mixing a 1st-order limiter introduces). |
|
| type(eos_t), | intent(in), | optional | :: | eos |
Device-resident EOS handle — required only for |
|
| real(kind=wp), | intent(in), | optional | :: | dt |
Outer/thermo timestep (s) for the grid time-filter. Absent or
|
Face-velocity pass of the ALE remap. Remaps u_face_x_layer and v_face_y_layer h_old→h_new using arithmetic-mean face thicknesses and the per-column kernel. Public only for the unit-test suite. Velocity treated as the face “concentration” (analogous to T=hTr/h at centres); per-face conservation sum_k(h_face·u_face) preserved (momentum-conserving). Outer-wall faces take the adjacent cell’s thickness verbatim (no across-cell to average).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| real(kind=wp), | intent(in) | :: | h_old(:,:,:) | |||
| real(kind=wp), | intent(in) | :: | h_new(:,:,:) | |||
| real(kind=wp), | intent(inout) | :: | u_face_x(:,:,:) |
Eastward face velocity, shape |
||
| real(kind=wp), | intent(inout) | :: | v_face_y(:,:,:) |
Northward face velocity, shape |
||
| integer, | intent(in), | optional | :: | method | ||
| logical, | intent(in), | optional | :: | conserve_ke |
Enable the KE-conserving baroclinic-anomaly rescale (default
|
|
| logical, | intent(in), | optional | :: | zlevel_faces |
|
|
| logical, | intent(in), | optional | :: | bnd_extrap |
Linear-exact boundary-cell reconstruction (default |
|
| logical, | intent(in), | optional | :: | nonunif |
Non-uniform-grid PLM/PPM weights (default |
Top-level entry the driver calls between outer steps: snapshot h_old once,
remap centres (h_layer + tracers) AND faces using the same snapshot, then
re-derive bt_eta. Returns early for EULERIAN_Z/LAGRANGIAN.
eos (optional): required ONLY for VCOORD_RHO (isopycnal density inversion).
dt (optional, s): only for the grid time-filter (regrid_time_scale > 0);
absent or τ=0 (default) ⇒ filter skipped, bit-identical.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_vcoord_t), | intent(inout) | :: | vcoord | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(inout) | :: | bt_eta(:,:) | |||
| real(kind=wp), | intent(in) | :: | bt_H_ref(:,:) | |||
| integer, | intent(in), | optional | :: | method | ||
| type(eos_t), | intent(in), | optional | :: | eos | ||
| real(kind=wp), | intent(in), | optional | :: | dt |
Public test shim over the included rdb_vl_merge_content — the ONE
definition of the vanished-layer content rule
(src/shared_module_utilities/rdb_vanished_layer.inc). Production
code calls the included copy directly; this exists so
tests/test_ocean_remap_vanished.F90 can assert the rule’s own
properties without a second transcription of it.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_col(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(inout) | :: | q_col(NZ_STACK_MAX) |
Scan every column for the two remap preconditions and report how
badly they are missed — the domain-wide counterpart of
rdb_remap_column :: remap_column_preconditions_ok.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old(nx,ny,nz) |
Source thicknesses (the pre-remap |
||
| real(kind=wp), | intent(in) | :: | h_new(nx,ny,nz) |
Target thicknesses ( |
||
| real(kind=wp), | intent(in) | :: | rel_tol |
Relative tolerance on the column-total match. |
||
| integer, | intent(out) | :: | n_bad |
Number of columns violating either precondition. |
||
| real(kind=wp), | intent(out) | :: | worst_rel |
Largest relative column-total mismatch over the domain. |
||
| real(kind=wp), | intent(out) | :: | worst_neg |
Most negative thickness found (0 when there is none). |
Single-column unit-test entry: wraps remap_column with the
c = hTr/h ↔ hTr_new = c_new·h_new pattern, including the SAME two-sided
vanishing-layer merge the production kernel runs
(rdb_vl_merge_content + rdb_vl_column_conc), so this entry cannot drift from
ocean_remap_tracer_field. Production callers go through that one.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old(nz) | |||
| real(kind=wp), | intent(in) | :: | h_new(nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr_inout(nz) | |||
| integer, | intent(in) | :: | method |
Build layer-mean T/S concentrations (c = hTr/h) from extensive tracer
content + pre-remap thicknesses, for the VCOORD_RHO density inversion.
Per-layer rdb_vl_conc (a filler reads hTr/h, its donor’s
concentration by I1′; a zero-thickness layer reads 0). Flat-impl,
explicit-shape; one cadence-bounded launch per remap.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hTr_T(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hTr_S(nx,ny,nz) | |||
| real(kind=wp), | intent(out) | :: | conc_t(nx,ny,nz) | |||
| real(kind=wp), | intent(out) | :: | conc_s(nx,ny,nz) |
Flat-impl tracer remap. Per (i,j) column: c = hTr/h (vanishing-layer-
guarded) → per-column remap kernel → hTr_new = c_new·h_new. Conservative.
budget (optional): when present, the per-cell hTr_new−hTr_old increment
is accumulated into the slot (heat/salt remap deltas) before overwriting.
Flat-arg so GPU codegen doesn’t chase the array-of-derived-types pointer.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | h_new(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| integer, | intent(in) | :: | method | |||
| logical, | intent(in) | :: | bnd_extrap |
Linear-exact boundary-cell reconstruction in the column kernel
( |
||
| logical, | intent(in) | :: | nonunif |
Non-uniform-grid PLM/PPM reconstruction weights in the column
kernel ( |
||
| real(kind=wp), | intent(inout), | optional | :: | budget(nx,ny,nz) |
On a column that carries a vanished layer (source or target), make
the tracer remap conservative EXACTLY, not just on a matched column:
the content the remap failed to place, Σ q_src − Σ q_new, is
handed to the topmost live target layer (the donor of any fillers
above it, so the write-side pool that follows shares it with them).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old_col(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | h_new_col(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | q_src(NZ_STACK_MAX) |
Source content the remap was handed (after the read-side pool). |
||
| real(kind=wp), | intent(inout) | :: | q_new(NZ_STACK_MAX) |
Target content |
Flat-impl x-face remap. East faces at i+1/2; u_face_x(1..nx+1) covers
west wall (I=1), interior (I=2..nx), east wall (I=nx+1).
conserve_ke (default .false.): rescale the baroclinic anomaly so column
anomaly KE matches pre-remap, barotropic mean preserved. See
rescale_anomaly_ke.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | h_new(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | u_face_x(nx+1,ny,nz) | |||
| integer, | intent(in) | :: | method | |||
| logical, | intent(in) | :: | conserve_ke | |||
| logical, | intent(in) | :: | zlevel_faces |
|
||
| logical, | intent(in) | :: | bnd_extrap |
Linear-exact boundary-cell reconstruction in the column kernel. |
||
| logical, | intent(in) | :: | nonunif |
Non-uniform-grid PLM/PPM weights in the column kernel. |
Flat-impl y-face remap, mirror of remap_x_face_velocity. See
that routine for the conserve_ke / bnd_extrap / nonunif
semantics.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | h_new(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | v_face_y(nx,ny+1,nz) | |||
| integer, | intent(in) | :: | method | |||
| logical, | intent(in) | :: | conserve_ke | |||
| logical, | intent(in) | :: | zlevel_faces |
|
||
| logical, | intent(in) | :: | bnd_extrap | |||
| logical, | intent(in) | :: | nonunif |
KE-conserving rescale of a remapped face-velocity column. The column remap conserves momentum (Σ h·u) but not KE; restore it by rescaling ONLY the baroclinic anomaly (Adcroft & Hallberg 2006): scale = sqrt(KE_old_anom/KE_new_anom), clamped to [0, 1.25] u_new(k) = u_bar_new + scale·(u_new(k) - u_bar_new) Barotropic mean u_bar preserved verbatim; degenerate columns untouched.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_old_face(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | h_new_face(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(in) | :: | u_old_col(NZ_STACK_MAX) | |||
| real(kind=wp), | intent(inout) | :: | u_new_col(NZ_STACK_MAX) |