ocean_remap_tracer_field Subroutine

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.

The vanishing-layer guard is two-sided (rdb_vl_merge_content, invariant I1′): on the READ side a SOURCE filler is pooled with its donor live layer, and the reconstruction is handed the donor’s concentration for it (rdb_vl_column_conc) — never one recovered from a near-zero divisor; on the WRITE side a TARGET filler is pooled with ITS donor live target layer, so it receives h_new·c_live, taken from that layer. Without the write half the remap parks arbitrary content in a filler (the day-16 z_fixed salt/heat break, when the read side then zeroed it); with a write half that ZEROES the filler (the previous I1), a uniform tracer stops being uniform — the thickness the continuity step later moves out of the filler arrives in the live layers carrying no content. Post-condition (I1′): h_new <= H_VANISHED ⇒ hTr = h_new·c_live, column sum conserved to round-off, so budget still telescopes per column.

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)

Calls

proc~~ocean_remap_tracer_field~~CallsGraph proc~ocean_remap_tracer_field ocean_remap_tracer_field local local 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~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~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

Called by

proc~~ocean_remap_tracer_field~~CalledByGraph proc~ocean_remap_tracer_field ocean_remap_tracer_field proc~ocean_apply_ale_remap_centres ocean_apply_ale_remap_centres proc~ocean_apply_ale_remap_centres->proc~ocean_remap_tracer_field proc~ocean_apply_ale_remap_step ocean_apply_ale_remap_step proc~ocean_apply_ale_remap_step->proc~ocean_remap_tracer_field 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
real(kind=wp), private :: c_new_col(NZ_STACK_MAX)
real(kind=wp), private :: c_old_col(NZ_STACK_MAX)
real(kind=wp), private :: hTr_col(NZ_STACK_MAX)
real(kind=wp), private :: hTr_new_col(NZ_STACK_MAX)
real(kind=wp), private :: h_new_col(NZ_STACK_MAX)
real(kind=wp), private :: h_old_col(NZ_STACK_MAX)
integer, private :: i
integer, private :: j
integer, private :: k

Source Code

   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.
      !!
      !! **The vanishing-layer guard is two-sided** (`rdb_vl_merge_content`,
      !! invariant I1′): on the READ side a SOURCE filler is pooled with its
      !! donor live layer, and the reconstruction is handed the donor's
      !! concentration for it (`rdb_vl_column_conc`) — never one recovered
      !! from a near-zero divisor; on the WRITE side a TARGET filler is pooled
      !! with ITS donor live target layer, so it receives `h_new·c_live`,
      !! taken from that layer. Without the write half the remap parks
      !! arbitrary content in a filler (the day-16 z_fixed salt/heat break,
      !! when the read side then zeroed it); with a write half that ZEROES the
      !! filler (the previous I1), a uniform tracer stops being uniform — the
      !! thickness the continuity step later moves out of the filler arrives
      !! in the live layers carrying no content.
      !! Post-condition (I1′): `h_new <= H_VANISHED ⇒ hTr = h_new·c_live`,
      !! column sum conserved to round-off, so `budget` still telescopes per
      !! column.
      integer, intent(in) :: nx, ny, nz, method
      real(wp), intent(in) :: h_old(nx, ny, nz)
      real(wp), intent(in) :: h_new(nx, ny, nz)
      real(wp), intent(inout) :: hTr(nx, ny, nz)
      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(wp), intent(inout), optional :: budget(nx, ny, nz)
      integer :: i, j, k
      real(wp) :: h_old_col(NZ_STACK_MAX), h_new_col(NZ_STACK_MAX)
      real(wp) :: c_old_col(NZ_STACK_MAX), c_new_col(NZ_STACK_MAX)
      real(wp) :: hTr_col(NZ_STACK_MAX), hTr_new_col(NZ_STACK_MAX)

      ! Gate the budget write INSIDE the one loop (as vdiff does); splitting
      ! present(budget) into two loops makes NVHPC compile the no-budget branch
      ! ~25x slower. Bit-identical to the split form.
      do concurrent(j=1:ny, i=1:nx) &
         local(k, h_old_col, h_new_col, c_old_col, c_new_col, hTr_col, hTr_new_col)
         do k = 1, nz
            h_old_col(k) = h_old(i, j, k)
            h_new_col(k) = h_new(i, j, k)
            hTr_col(k) = hTr(i, j, k)
         end do
         ! Read side. `hTr_col` is a LOCAL copy — the budget below still
         ! differences against the original `hTr` array, so the merge is
         ! invisible to the leak detector.
         call rdb_vl_merge_content(nz, h_old_col, hTr_col)
         call rdb_vl_column_conc(nz, h_old_col, hTr_col, c_old_col)
         call remap_column(method, nz, &
                           h_old_col(1:nz), h_new_col(1:nz), &
                           c_old_col(1:nz), c_new_col(1:nz), bnd_extrap, nonunif)
         ! Write side.
         do k = 1, nz
            hTr_new_col(k) = c_new_col(k)*h_new_col(k)
         end do
         call remap_fold_filler_defect(nz, h_old_col, h_new_col, hTr_col, hTr_new_col)
         call rdb_vl_merge_content(nz, h_new_col, hTr_new_col)
         if (present(budget)) then
            do k = 1, nz
               budget(i, j, k) = budget(i, j, k) + (hTr_new_col(k) - hTr(i, j, k))
               hTr(i, j, k) = hTr_new_col(k)
            end do
         else
            do k = 1, nz
               hTr(i, j, k) = hTr_new_col(k)
            end do
         end if
      end do
   end subroutine ocean_remap_tracer_field