ocean_apply_ale_remap_centres Subroutine

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.


Calls

proc~~ocean_apply_ale_remap_centres~~CallsGraph proc~ocean_apply_ale_remap_centres ocean_apply_ale_remap_centres local local proc~ocean_apply_ale_remap_centres->local proc~build_ts_concentration build_ts_concentration proc~ocean_apply_ale_remap_centres->proc~build_ts_concentration proc~ocean_remap_tracer_field ocean_remap_tracer_field proc~ocean_apply_ale_remap_centres->proc~ocean_remap_tracer_field proc~ocean_vcoord_compute_target_h ocean_vcoord_t%ocean_vcoord_compute_target_h proc~ocean_apply_ale_remap_centres->proc~ocean_vcoord_compute_target_h proc~ocean_vcoord_compute_target_h_rho ocean_vcoord_t%ocean_vcoord_compute_target_h_rho proc~ocean_apply_ale_remap_centres->proc~ocean_vcoord_compute_target_h_rho rdb_vl_conc rdb_vl_conc proc~build_ts_concentration->rdb_vl_conc proc~ocean_remap_tracer_field->local proc~remap_column remap_column proc~ocean_remap_tracer_field->proc~remap_column proc~remap_fold_filler_defect remap_fold_filler_defect proc~ocean_remap_tracer_field->proc~remap_fold_filler_defect rdb_vl_column_conc rdb_vl_column_conc proc~ocean_remap_tracer_field->rdb_vl_column_conc rdb_vl_merge_content rdb_vl_merge_content proc~ocean_remap_tracer_field->rdb_vl_merge_content proc~ocean_vcoord_compute_target_h_impl ocean_vcoord_compute_target_h_impl proc~ocean_vcoord_compute_target_h->proc~ocean_vcoord_compute_target_h_impl proc~ocean_vcoord_compute_target_h_rho_impl ocean_vcoord_compute_target_h_rho_impl proc~ocean_vcoord_compute_target_h_rho->proc~ocean_vcoord_compute_target_h_rho_impl proc~ocean_vcoord_geometric_target ocean_vcoord_geometric_target proc~ocean_vcoord_compute_target_h_impl->proc~ocean_vcoord_geometric_target proc~ocean_vcoord_z_fixed_target ocean_vcoord_z_fixed_target proc~ocean_vcoord_compute_target_h_impl->proc~ocean_vcoord_z_fixed_target proc~ocean_vcoord_zstar_target ocean_vcoord_zstar_target proc~ocean_vcoord_compute_target_h_impl->proc~ocean_vcoord_zstar_target proc~ocean_vcoord_rho_target ocean_vcoord_rho_target proc~ocean_vcoord_compute_target_h_rho_impl->proc~ocean_vcoord_rho_target proc~remap_column_pcm remap_column_pcm proc~remap_column->proc~remap_column_pcm proc~remap_column_plm remap_column_plm proc~remap_column->proc~remap_column_plm proc~remap_column_ppm remap_column_ppm proc~remap_column->proc~remap_column_ppm proc~remap_column_ppm_h4 remap_column_ppm_h4 proc~remap_column->proc~remap_column_ppm_h4 proc~remap_column_pqm remap_column_pqm proc~remap_column->proc~remap_column_pqm rdb_vl_is_live rdb_vl_is_live proc~remap_fold_filler_defect->rdb_vl_is_live proc~ocean_vcoord_geometric_target->local proc~ocean_vcoord_rho_target_column ocean_vcoord_rho_target_column proc~ocean_vcoord_rho_target->proc~ocean_vcoord_rho_target_column proc~ocean_vcoord_z_fixed_target->local proc~ocean_vcoord_zstar_target->local proc~boundary_half_jump boundary_half_jump proc~remap_column_plm->proc~boundary_half_jump proc~plm_slope_nonuniform plm_slope_nonuniform proc~remap_column_plm->proc~plm_slope_nonuniform proc~remap_column_ppm->proc~remap_column_plm proc~remap_column_ppm->proc~boundary_half_jump proc~ppm_edge_nonuniform ppm_edge_nonuniform proc~remap_column_ppm->proc~ppm_edge_nonuniform proc~ppm_edge_two_cell ppm_edge_two_cell proc~remap_column_ppm->proc~ppm_edge_two_cell proc~ppm_jump_nonuniform ppm_jump_nonuniform proc~remap_column_ppm->proc~ppm_jump_nonuniform proc~remap_column_ppm_h4->proc~remap_column_plm proc~remap_column_ppm_h4->proc~boundary_half_jump proc~remap_column_pqm->proc~remap_column_ppm proc~remap_column_pqm->proc~boundary_half_jump proc~pqm_end_value_h4 pqm_end_value_h4 proc~remap_column_pqm->proc~pqm_end_value_h4 proc~pqm_solve_diag_dominant pqm_solve_diag_dominant proc~remap_column_pqm->proc~pqm_solve_diag_dominant proc~eos_density_point eos_density_point proc~ocean_vcoord_rho_target_column->proc~eos_density_point proc~invert_density_targets invert_density_targets proc~ocean_vcoord_rho_target_column->proc~invert_density_targets

Variables

Type Visibility Attributes Name Initial
logical, private :: do_tfilter
integer, private :: i
integer, private :: j
integer, private :: k
integer, private :: m
integer, private :: nx
integer, private :: ny
integer, private :: nz
integer, private :: t
real(kind=wp), private :: wtd

Source Code

   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.
      type(hgrid_t), intent(in) :: grid
      type(ocean_vcoord_t), intent(inout) :: vcoord
      type(multilayer_state_t), intent(inout) :: ms
      ! assumed-shape-ok: outer-driver allocatable; grid%nx_total available; deferred.
      real(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(wp), intent(in) :: bt_H_ref(:, :)  ! assumed-shape-ok: same as bt_eta above
         !! 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.
      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(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`.
      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).

      integer :: t, m, nx, ny, nz, i, j, k
      real(wp) :: wtd
      logical :: do_tfilter

      ! Eulerian-z and Lagrangian/isopycnal both skip remap: the former
      ! holds h at H·dsig via vert-advection cancellation, the latter
      ! lets h evolve freely (target = current h).
      if (vcoord%coord_type == VCOORD_EULERIAN_Z .or. &
          vcoord%coord_type == VCOORD_LAGRANGIAN) return
      if (.not. vcoord%is_init) return
      if (.not. allocated(ms%h_layer)) return

      m = REMAP_PPM
      if (present(method)) m = method
      nx = grid%nx_total
      ny = grid%ny_total
      nz = ms%nz_ml

      ! --- 2. Current column total (persistent device-mapped scratch on vcoord)
      do concurrent(j=1:ny, i=1:nx) local(k)
         vcoord%remap_total_h(i, j) = 0.0_wp
         do k = 1, nz
            vcoord%remap_total_h(i, j) = vcoord%remap_total_h(i, j) &
                                         + ms%h_layer(i, j, k)
         end do
      end do

      ! --- 3. Snapshot h_old on-device (host source= reads stale memory after a
      ! dynamics-side OpenACC kernel). Before target_h so VCOORD_RHO can read it.
      do concurrent(k=1:nz, j=1:ny, i=1:nx)
         vcoord%remap_h_old(i, j, k) = ms%h_layer(i, j, k)
      end do

      ! --- 4. Populate target_h (geometric vs isopycnal dispatch) ---
      do concurrent(j=1:ny, i=1:nx)
         vcoord%remap_h_ref(i, j) = vcoord%remap_total_h(i, j) - bt_eta(i, j)
      end do
      if ((vcoord%coord_type == VCOORD_RHO .or. vcoord%coord_type == VCOORD_HYCOM) &
          .and. present(eos) .and. allocated(ms%tracers) &
          .and. ms%idx_temperature > 0 .and. ms%idx_salinity > 0) then
         call build_ts_concentration(nx, ny, nz, vcoord%remap_h_old, &
                                     ms%tracers(ms%idx_temperature)%hTr, &
                                     ms%tracers(ms%idx_salinity)%hTr, &
                                     vcoord%remap_conc_t, vcoord%remap_conc_s)
         ! HYCOM = RHO inversion + z*-floor/monotonize deltas (hybrid=.true.);
         ! pure RHO passes hybrid=.false. (bit-identical to RHO-only kernel).
         call vcoord%compute_target_h_rho(vcoord%remap_h_ref, bt_eta, &
                                          vcoord%remap_conc_t, vcoord%remap_conc_s, eos, &
                                          hybrid=(vcoord%coord_type == VCOORD_HYCOM))
      else
         call vcoord%compute_target_h(vcoord%remap_h_ref, bt_eta)
      end if

      ! --- 4b. Grid time-filter (White & Adcroft 2008): relax target toward it
      ! from the old grid by wtd = dt/(τ+dt). Convex blend ⇒ column total
      ! conserved. τ=0 (default) or dt absent ⇒ skipped, bit-identical.
      do_tfilter = vcoord%regrid_time_scale > 0.0_wp .and. present(dt)
      if (do_tfilter) then
         wtd = dt/(vcoord%regrid_time_scale + dt)
         do concurrent(k=1:nz, j=1:ny, i=1:nx)
            vcoord%target_h(i, j, k) = vcoord%remap_h_old(i, j, k) &
                                       + wtd*(vcoord%target_h(i, j, k) - vcoord%remap_h_old(i, j, k))
         end do
      end if

      ! --- 5. Remap every tracer ---
      if (allocated(ms%tracers)) then
         do t = 1, size(ms%tracers)
            if (.not. allocated(ms%tracers(t)%hTr)) cycle
            select case (ms%tracers(t)%budget_id)
            case (TRACER_BUDGET_HEAT)
               call ocean_remap_tracer_field( &
                  nx, ny, nz, vcoord%remap_h_old, vcoord%target_h, ms%tracers(t)%hTr, m, &
                  vcoord%remap_boundary_extrap, vcoord%remap_nonuniform_weights, &
                  budget=ms%heat_budget_remap)
            case (TRACER_BUDGET_SALT)
               call ocean_remap_tracer_field( &
                  nx, ny, nz, vcoord%remap_h_old, vcoord%target_h, ms%tracers(t)%hTr, m, &
                  vcoord%remap_boundary_extrap, vcoord%remap_nonuniform_weights, &
                  budget=ms%salt_budget_remap)
            case default
               call ocean_remap_tracer_field( &
                  nx, ny, nz, vcoord%remap_h_old, vcoord%target_h, ms%tracers(t)%hTr, m, &
                  vcoord%remap_boundary_extrap, vcoord%remap_nonuniform_weights)
            end select
         end do
      end if

      ! --- 6. h_layer = target_h; capture mass-budget delta ---
      do concurrent(k=1:nz, j=1:ny, i=1:nx)
         ms%mass_budget_remap(i, j, k) = ms%mass_budget_remap(i, j, k) &
                                         + (vcoord%target_h(i, j, k) - vcoord%remap_h_old(i, j, k))
         ms%h_layer(i, j, k) = vcoord%target_h(i, j, k)
      end do

      ! --- 7. Recompute bt_eta from new sum (round-off-tight) ---
      do concurrent(j=1:ny, i=1:nx) local(k)
         bt_eta(i, j) = -bt_H_ref(i, j)
         do k = 1, nz
            bt_eta(i, j) = bt_eta(i, j) + ms%h_layer(i, j, k)
         end do
      end do
   end subroutine ocean_apply_ale_remap_centres