remap_fold_filler_defect Subroutine

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

Why it is needed. remap_column conserves only when Σ h_old == Σ h_new, and the target builders reach that sum by a different arithmetic route than continuity does, so they differ by a few ulp every step (OCEAN_REMAP_PRECOND_RTOL). The unmatched sliver is at the TOP of the column, and it goes with its content. Under I1 that sliver was an empty filler and the loss was invisible; under I1′ the filler carries c_live, and on a quasi-steady column the sliver has the same sign every step: cavity_flat_lid_rest_zfixed.nml AT REST lost salt at -1.2e-13/day (the whole run’s residual: -3.2e-12 at day 30, against -1.4e-13 under I1) until this fold.

Bit-identity: a column with no layer at or below H_VANISHED on either grid returns before touching anything, so every family without fillers (sigma, z*-lite, eulerian_z) is unchanged. A column with no live target layer is left to the pool (land: zero).

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.


Calls

proc~~remap_fold_filler_defect~~CallsGraph proc~remap_fold_filler_defect remap_fold_filler_defect rdb_vl_is_live rdb_vl_is_live proc~remap_fold_filler_defect->rdb_vl_is_live

Called by

proc~~remap_fold_filler_defect~~CalledByGraph proc~remap_fold_filler_defect remap_fold_filler_defect proc~ocean_remap_tracer_column ocean_remap_tracer_column proc~ocean_remap_tracer_column->proc~remap_fold_filler_defect proc~ocean_remap_tracer_field ocean_remap_tracer_field proc~ocean_remap_tracer_field->proc~remap_fold_filler_defect 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

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: defect
logical, private :: has_filler
integer, private :: k
integer, private :: k_top_live

Source Code

   pure subroutine remap_fold_filler_defect(nz, h_old_col, h_new_col, q_src, q_new)
      !$acc routine seq
      !! 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).
      !!
      !! Why it is needed.  `remap_column` conserves only when `Σ h_old ==
      !! Σ h_new`, and the target builders reach that sum by a different
      !! arithmetic route than continuity does, so they differ by a few ulp
      !! every step (`OCEAN_REMAP_PRECOND_RTOL`).  The unmatched sliver is at
      !! the TOP of the column, and it goes with its content.  Under I1 that
      !! sliver was an empty filler and the loss was invisible; under I1′ the
      !! filler carries `c_live`, and on a quasi-steady column the sliver has
      !! the same sign every step: `cavity_flat_lid_rest_zfixed.nml` AT REST
      !! lost salt at `-1.2e-13`/day (the whole run's residual: `-3.2e-12` at
      !! day 30, against `-1.4e-13` under I1) until this fold.
      !!
      !! **Bit-identity:** a column with no layer at or below `H_VANISHED`
      !! on either grid returns before touching anything, so every family
      !! without fillers (sigma, z*-lite, `eulerian_z`) is unchanged.  A
      !! column with no live target layer is left to the pool (land: zero).
      integer, intent(in) :: nz
      real(wp), intent(in) :: h_old_col(NZ_STACK_MAX)
      real(wp), intent(in) :: h_new_col(NZ_STACK_MAX)
      real(wp), intent(in) :: q_src(NZ_STACK_MAX)
         !! Source content the remap was handed (after the read-side pool).
      real(wp), intent(inout) :: q_new(NZ_STACK_MAX)
         !! Target content `c_new·h_new`, before the write-side pool.
      integer :: k, k_top_live
      logical :: has_filler
      real(wp) :: defect

      has_filler = .false.
      k_top_live = 0
      do k = 1, nz
         if (.not. rdb_vl_is_live(h_old_col(k)) .or. .not. rdb_vl_is_live(h_new_col(k))) then
            has_filler = .true.
         end if
         if (rdb_vl_is_live(h_new_col(k))) k_top_live = k
      end do
      if (.not. has_filler .or. k_top_live == 0) return
      defect = 0.0_wp
      do k = 1, nz
         defect = defect + (q_src(k) - q_new(k))
      end do
      q_new(k_top_live) = q_new(k_top_live) + defect
   end subroutine remap_fold_filler_defect