ocean_apply_ale_remap_step Subroutine

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

Calls

proc~~ocean_apply_ale_remap_step~~CallsGraph proc~ocean_apply_ale_remap_step ocean_apply_ale_remap_step local local proc~ocean_apply_ale_remap_step->local proc~build_ts_concentration build_ts_concentration proc~ocean_apply_ale_remap_step->proc~build_ts_concentration proc~ocean_remap_tracer_field ocean_remap_tracer_field proc~ocean_apply_ale_remap_step->proc~ocean_remap_tracer_field proc~ocean_vcoord_compute_target_h ocean_vcoord_t%ocean_vcoord_compute_target_h proc~ocean_apply_ale_remap_step->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_step->proc~ocean_vcoord_compute_target_h_rho proc~remap_x_face_velocity remap_x_face_velocity proc~ocean_apply_ale_remap_step->proc~remap_x_face_velocity proc~remap_y_face_velocity remap_y_face_velocity proc~ocean_apply_ale_remap_step->proc~remap_y_face_velocity 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~remap_x_face_velocity->local proc~remap_x_face_velocity->proc~remap_column proc~rescale_anomaly_ke rescale_anomaly_ke proc~remap_x_face_velocity->proc~rescale_anomaly_ke proc~remap_y_face_velocity->local proc~remap_y_face_velocity->proc~remap_column proc~remap_y_face_velocity->proc~rescale_anomaly_ke 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

Called by

proc~~ocean_apply_ale_remap_step~~CalledByGraph proc~ocean_apply_ale_remap_step ocean_apply_ale_remap_step proc~ocean_dyn_step_split ocean_dyn_step_split proc~ocean_dyn_step_split->proc~ocean_apply_ale_remap_step proc~engine_step engine_step proc~engine_step->proc~ocean_dyn_step_split proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_step proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean

Variables

Type Visibility Attributes Name Initial
logical, private :: bnd_extrap
logical, private :: conserve_ke
logical, private :: do_tfilter
integer, private :: i
integer, private :: j
integer, private :: k
integer, private :: m
logical, private :: nonunif
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_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.
      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(:, :)
      real(wp), intent(in) :: bt_H_ref(:, :)  ! assumed-shape-ok: outer-driver allocatable; grid%nx_total available; deferred
      integer, intent(in), optional :: method
      type(eos_t), intent(in), optional :: eos
      real(wp), intent(in), optional :: dt

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

      ! 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
      bnd_extrap = vcoord%remap_boundary_extrap
      nonunif = vcoord%remap_nonuniform_weights
      nx = grid%nx_total
      ny = grid%ny_total
      nz = ms%nz_ml

      ! 1. Column total + target_h (persistent scratch on vcoord — per-call
      ! allocates here generate H↔D transfers, not being in the present table).
      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
      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

      ! 2. Snapshot h_old on-device (host source= reads stale memory after a
      ! dynamics-side OpenACC kernel). Before target_h for VCOORD_RHO's inversion.
      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

      ! 3. Populate target_h. Geometric coords use compute_target_h; isopycnal
      ! needs per-layer T/S concentrations + EOS via compute_target_h_rho.
      ! Concentrations built into persistent scratch (guarded c = hTr/h).
      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

      ! 3b. 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

      ! `vcoord%remap_h_old` and `vcoord%target_h` are the exact pair every
      ! column kernel below consumes, and neither is overwritten by steps 4-7
      ! — so `ocean_remap_scan_preconditions` can assert them from the
      ! (impure) driver AFTER this call.  See `&vcoord_nml
      ! remap_check_preconditions` and `rdb_ocean_dyn :: ocean_dyn_step_split`.

      ! 4. Tracer remap (centre cells)
      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, &
                  bnd_extrap, nonunif, 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, &
                  bnd_extrap, nonunif, 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, &
                  bnd_extrap, nonunif)
            end select
         end do
      end if

      ! 5. Face-velocity remap (h_old → target_h). KE-conserving anomaly rescale
      ! gated on the vcoord knob (default off ⇒ momentum-only, bit-identical).
      conserve_ke = vcoord%remap_vel_conserve_ke
      if (allocated(ms%u_face_x_layer) .and. allocated(ms%v_face_y_layer)) then
         call remap_x_face_velocity(nx, ny, nz, vcoord%remap_h_old, vcoord%target_h, &
                                    ms%u_face_x_layer, m, conserve_ke, &
                                    vcoord%zfixed_closed_faces, bnd_extrap, nonunif)
         call remap_y_face_velocity(nx, ny, nz, vcoord%remap_h_old, vcoord%target_h, &
                                    ms%v_face_y_layer, m, conserve_ke, &
                                    vcoord%zfixed_closed_faces, bnd_extrap, nonunif)
      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. Re-derive bt_eta
      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_step