rdb_ocean_remap Module

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”).


Uses

  • module~~rdb_ocean_remap~~UsesGraph module~rdb_ocean_remap rdb_ocean_remap module~rdb_constants rdb_constants module~rdb_ocean_remap->module~rdb_constants module~rdb_eos rdb_eos module~rdb_ocean_remap->module~rdb_eos module~rdb_grid rdb_grid module~rdb_ocean_remap->module~rdb_grid module~rdb_multilayer_state rdb_multilayer_state module~rdb_ocean_remap->module~rdb_multilayer_state module~rdb_ocean_vcoord rdb_ocean_vcoord module~rdb_ocean_remap->module~rdb_ocean_vcoord module~rdb_remap_column rdb_remap_column module~rdb_ocean_remap->module~rdb_remap_column module~rdb_tracer rdb_tracer module~rdb_ocean_remap->module~rdb_tracer pic_types pic_types module~rdb_constants->pic_types module~rdb_eos->module~rdb_constants module~rdb_eos->module~rdb_grid module~rdb_grid->module~rdb_constants module~rdb_multilayer_state->module~rdb_constants module~rdb_multilayer_state->module~rdb_grid module~rdb_multilayer_state->module~rdb_tracer iso_fortran_env iso_fortran_env module~rdb_multilayer_state->iso_fortran_env module~rdb_efp rdb_efp module~rdb_multilayer_state->module~rdb_efp module~rdb_error_ring rdb_error_ring module~rdb_multilayer_state->module~rdb_error_ring module~rdb_mem_report rdb_mem_report module~rdb_multilayer_state->module~rdb_mem_report pic_logger pic_logger module~rdb_multilayer_state->pic_logger module~rdb_ocean_vcoord->module~rdb_constants module~rdb_ocean_vcoord->module~rdb_eos module~rdb_ocean_vcoord->module~rdb_grid module~rdb_ocean_vcoord->iso_fortran_env module~rdb_ocean_vcoord->module~rdb_mem_report module~rdb_vcoord rdb_vcoord module~rdb_ocean_vcoord->module~rdb_vcoord module~rdb_remap_column->module~rdb_constants module~rdb_tracer->module~rdb_constants module~rdb_tracer->module~rdb_grid module~rdb_tracer->iso_fortran_env module~rdb_tracer->module~rdb_mem_report module~rdb_efp->iso_fortran_env ieee_arithmetic ieee_arithmetic module~rdb_efp->ieee_arithmetic module~rdb_error_ring->pic_logger module~rdb_mem_report->module~rdb_constants module~rdb_mem_report->iso_fortran_env module~rdb_mem_report->pic_logger pic_strings pic_strings module~rdb_mem_report->pic_strings module~rdb_vcoord->module~rdb_constants module~rdb_vcoord->pic_logger module~rdb_vcoord->pic_strings

Used by

  • module~~rdb_ocean_remap~~UsedByGraph module~rdb_ocean_remap rdb_ocean_remap module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_remap module~rdb_driver rdb_driver module~rdb_driver->module~rdb_ocean_dyn module~rdb_ocean_engine rdb_ocean_engine module~rdb_driver->module~rdb_ocean_engine module~rdb_ocean_state rdb_ocean_state module~rdb_driver->module~rdb_ocean_state module~rdb_ocean_api rdb_ocean_api module~rdb_ocean_api->module~rdb_ocean_dyn module~rdb_ocean_api->module~rdb_ocean_engine module~rdb_handle rdb_handle module~rdb_ocean_api->module~rdb_handle module~rdb_ocean_diag_derived rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_diag_derived module~rdb_ocean_diag_fills rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_ocean_diag_fills module~rdb_ocean_engine->module~rdb_ocean_dyn module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_state module~rdb_ocean_engine->module~rdb_ocean_diag_derived module~rdb_ocean_engine->module~rdb_ocean_diag_fills module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_dyn module~rdb_handle->module~rdb_ocean_engine module~rdb_handle->module~rdb_ocean_state module~rdb_ocean_diag_derived->module~rdb_ocean_state module~rdb_ocean_diag_derived->module~rdb_ocean_diag_fills module~rdb_ocean_diag_fills->module~rdb_ocean_state

Variables

Type Visibility Attributes Name Initial
real(kind=wp), public, parameter :: OCEAN_REMAP_PRECOND_RTOL = 1.0e-9_wp

Relative tolerance on sum(h_old) == sum(target_h) for the precondition assertion. The target builders reach the sum by a different arithmetic route than the continuity update does, so a few ulp of drift per layer is expected and is not the failure mode being hunted: the violations that matter (a degenerate column that manufactures nz*h_min of water, a short target that deletes its tail) are percent-level, decades above this.

real(kind=wp), private, parameter :: H_FLOOR = H_VANISHED

Subroutines

public pure subroutine ocean_apply_ale_remap_centres(grid, vcoord, ms, bt_eta, bt_H_ref, method, eos, dt)

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.

Arguments

Type IntentOptional 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 sum_k(h_layer) - bt_H_ref on exit (step 7).

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 VCOORD_RHO (isopycnal density inversion); ignored by the geometric coords.

real(kind=wp), intent(in), optional :: dt

Outer/thermo timestep (s) for the grid time-filter. Absent or regrid_time_scale = 0 (default) ⇒ filter skipped ⇒ bit-identical. See ocean_apply_ale_remap_step.

public subroutine ocean_apply_ale_remap_faces(grid, h_old, h_new, u_face_x, v_face_y, method, conserve_ke, zlevel_faces, bnd_extrap, nonunif)

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).

Arguments

Type IntentOptional 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 (nx+1, ny, nz).

real(kind=wp), intent(inout) :: v_face_y(:,:,:)

Northward face velocity, shape (nx, ny+1, nz).

integer, intent(in), optional :: method
logical, intent(in), optional :: conserve_ke

Enable the KE-conserving baroclinic-anomaly rescale (default .false. ⇒ momentum-only remap, bit-identical).

logical, intent(in), optional :: zlevel_faces

&vcoord_nml zfixed_closed_faces — build the face columns as min(h_L, h_R) and drop the closed layers, so the remap neither fills nor drains an inert filler. Default .false. ⇒ bit-identical. See remap_x_face_velocity.

logical, intent(in), optional :: bnd_extrap

Linear-exact boundary-cell reconstruction (default .false. ⇒ the PCM flatten, bit-identical).

logical, intent(in), optional :: nonunif

Non-uniform-grid PLM/PPM weights (default .false. ⇒ the equal-thickness specialisations, bit-identical).

public pure subroutine ocean_apply_ale_remap_step(grid, vcoord, ms, bt_eta, bt_H_ref, method, eos, dt)

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.

Arguments

Type IntentOptional 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 pure subroutine ocean_remap_merge_vanished_content(nz, h_col, q_col)

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.

Arguments

Type IntentOptional 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)

public pure subroutine ocean_remap_scan_preconditions(nx, ny, nz, h_old, h_new, rel_tol, n_bad, worst_rel, worst_neg)

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.

Read more…

Arguments

Type IntentOptional 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 h_layer snapshot).

real(kind=wp), intent(in) :: h_new(nx,ny,nz)

Target thicknesses (vcoord%target_h, after any time filter).

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).

public subroutine ocean_remap_tracer_column(nz, h_old, h_new, hTr_inout, method)

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.

Arguments

Type IntentOptional 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

private pure subroutine build_ts_concentration(nx, ny, nz, h_old, hTr_T, hTr_S, conc_t, conc_s)

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.

Arguments

Type IntentOptional 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)

private pure subroutine ocean_remap_tracer_field(nx, ny, nz, h_old, h_new, hTr, method, bnd_extrap, nonunif, budget)

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.

Read more…

Arguments

Type IntentOptional 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 (&vcoord_nml remap_boundary_extrap); .false. ⇒ the PCM flatten, i.e. bit-identical to the pre-knob behaviour.

logical, intent(in) :: nonunif

Non-uniform-grid PLM/PPM reconstruction weights in the column kernel (&vcoord_nml remap_nonuniform_weights); .false. ⇒ the equal-thickness specialisations, i.e. bit-identical.

real(kind=wp), intent(inout), optional :: budget(nx,ny,nz)

private pure subroutine remap_fold_filler_defect(nz, h_old_col, h_new_col, q_src, q_new)

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).

Read more…

Arguments

Type IntentOptional 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 c_new·h_new, before the write-side pool.

private pure subroutine remap_x_face_velocity(nx, ny, nz, h_old, h_new, u_face_x, method, conserve_ke, zlevel_faces, bnd_extrap, nonunif)

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.

Arguments

Type IntentOptional 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

&vcoord_nml zfixed_closed_faces — z-level partial steps. Builds the face column as the OVERLAP of the two cell columns, min(h_L, h_R), instead of their arithmetic mean, and then drops any layer at or below H_VANISHED from BOTH the source and the target column. A layer that is an inert filler on one side then has an exactly-zero target thickness, which is the one case every remap_column variant already short-circuits (dz_new <= 0 ⇒ q_new = 0), so no momentum is poured INTO a closed layer and none is carried OUT of one.

Read more…
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.

private pure subroutine remap_y_face_velocity(nx, ny, nz, h_old, h_new, v_face_y, method, conserve_ke, zlevel_faces, bnd_extrap, nonunif)

Flat-impl y-face remap, mirror of remap_x_face_velocity. See that routine for the conserve_ke / bnd_extrap / nonunif semantics.

Arguments

Type IntentOptional 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

&vcoord_nml zfixed_closed_faces — z-level partial steps. Builds the face column as the OVERLAP of the two cell columns, min(h_L, h_R), instead of their arithmetic mean, and then drops any layer at or below H_VANISHED from BOTH the source and the target column. A layer that is an inert filler on one side then has an exactly-zero target thickness, which is the one case every remap_column variant already short-circuits (dz_new <= 0 ⇒ q_new = 0), so no momentum is poured INTO a closed layer and none is carried OUT of one.

Read more…
logical, intent(in) :: bnd_extrap
logical, intent(in) :: nonunif

private pure subroutine rescale_anomaly_ke(nz, h_old_face, h_new_face, u_old_col, u_new_col)

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.

Arguments

Type IntentOptional 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)