check_remap_preconditions_or_die Subroutine

private subroutine check_remap_preconditions_or_die(grid, vcoord, nz, outer_step)

&vcoord_nml remap_check_preconditions guard (audit findings V5, V6).

The per-column overlap sweep every remap method shares has two standing preconditions that nothing has ever asserted:

  • non-negative thicknesses — a negative source h makes the cumulative interface stack NON-MONOTONE, and the sweep then integrates the reversed interval twice, CREATING tracer mass with no NaN, no bounds hit and no budget entry;
  • equal column totals — the sweep integrates only over the overlap of the two stacks, so a SHORT target silently deletes the non-overlapping tail and a LONG one integrates it as q = 0.

Both are caller obligations, so a trip here localises a defect in the PRODUCER (a vcoord target builder that manufactures thickness on a degenerate column, or a continuity overshoot that wrote a negative h) rather than in the remap — which is why this aborts instead of clamping. Clamping would convert a conservation break into a plausible number, the exact failure mode the audit found.

Runs AFTER ocean_apply_ale_remap_step on purpose: the pair it has to judge is (vcoord%remap_h_old, vcoord%target_h), and neither is overwritten by the remap, while the step routine itself is pure and so cannot log or abort. The run is dying either way, so the one remap that already ran on the bad column costs nothing.

Cheap on the healthy path: one device-side reduction per THERMO step, three scalars back to the host, no field copy. Default off.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_vcoord_t), intent(in) :: vcoord
integer, intent(in) :: nz

Number of layers (ms%nz_ml).

integer, intent(in) :: outer_step

Outer-step index, for the abort message.


Calls

proc~~check_remap_preconditions_or_die~~CallsGraph proc~check_remap_preconditions_or_die check_remap_preconditions_or_die error error proc~check_remap_preconditions_or_die->error proc~ocean_remap_scan_preconditions ocean_remap_scan_preconditions proc~check_remap_preconditions_or_die->proc~ocean_remap_scan_preconditions

Called by

proc~~check_remap_preconditions_or_die~~CalledByGraph proc~check_remap_preconditions_or_die check_remap_preconditions_or_die proc~ocean_dyn_step_split ocean_dyn_step_split proc~ocean_dyn_step_split->proc~check_remap_preconditions_or_die 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
character(len=320), private :: msg
integer, private :: n_bad
real(kind=wp), private :: worst_neg
real(kind=wp), private :: worst_rel

Source Code

   subroutine check_remap_preconditions_or_die(grid, vcoord, nz, outer_step)
      !! `&vcoord_nml remap_check_preconditions` guard (audit findings V5, V6).
      !!
      !! The per-column overlap sweep every remap method shares has two
      !! standing preconditions that nothing has ever asserted:
      !!
      !!   * non-negative thicknesses — a negative source `h` makes the
      !!     cumulative interface stack NON-MONOTONE, and the sweep then
      !!     integrates the reversed interval twice, CREATING tracer mass
      !!     with no NaN, no bounds hit and no budget entry;
      !!   * equal column totals — the sweep integrates only over the overlap
      !!     of the two stacks, so a SHORT target silently deletes the
      !!     non-overlapping tail and a LONG one integrates it as `q = 0`.
      !!
      !! Both are caller obligations, so a trip here localises a defect in
      !! the PRODUCER (a vcoord target builder that manufactures thickness on
      !! a degenerate column, or a continuity overshoot that wrote a negative
      !! `h`) rather than in the remap — which is why this aborts instead of
      !! clamping.  Clamping would convert a conservation break into a
      !! plausible number, the exact failure mode the audit found.
      !!
      !! Runs AFTER `ocean_apply_ale_remap_step` on purpose: the pair it has
      !! to judge is `(vcoord%remap_h_old, vcoord%target_h)`, and neither is
      !! overwritten by the remap, while the step routine itself is `pure`
      !! and so cannot log or abort.  The run is dying either way, so the
      !! one remap that already ran on the bad column costs nothing.
      !!
      !! Cheap on the healthy path: one device-side reduction per THERMO
      !! step, three scalars back to the host, no field copy.  Default off.
      type(hgrid_t), intent(in) :: grid
      type(ocean_vcoord_t), intent(in) :: vcoord
      integer, intent(in) :: nz
         !! Number of layers (`ms%nz_ml`).
      integer, intent(in) :: outer_step
         !! Outer-step index, for the abort message.

      integer :: n_bad
      real(wp) :: worst_rel, worst_neg
      character(len=320) :: msg

      if (.not. vcoord%remap_check_preconditions) return
      if (.not. vcoord%is_init) return

      call ocean_remap_scan_preconditions(grid%nx_total, grid%ny_total, nz, &
                                          vcoord%remap_h_old, vcoord%target_h, &
                                          OCEAN_REMAP_PRECOND_RTOL, &
                                          n_bad, worst_rel, worst_neg)
      if (n_bad <= 0) return

      write (msg, '("ALE remap preconditions violated at outer step ", i0, ": ", i0, &
             &" column(s); worst relative column-total mismatch ", es12.5, &
             &" (tolerance ", es12.5, "); most negative thickness ", es12.5)') &
         outer_step, n_bad, worst_rel, OCEAN_REMAP_PRECOND_RTOL, worst_neg
      call logger%error(trim(msg))
      call logger%error("The overlap sweep assumes non-negative thicknesses and "// &
                        "equal column totals; outside them it silently creates or "// &
                        "deletes tracer mass.  Fix the producer (the vcoord target "// &
                        "builder, or continuity), not the remap.")
      error stop "ALE remap precondition violated (remap_check_preconditions)"
   end subroutine check_remap_preconditions_or_die