min_thickness_target_column Subroutine

public pure subroutine min_thickness_target_column(nz, h_old, h_floor, h_new, grounded)

Build the floor-only conservative target thickness column.

grounded (out): .true. iff any layer is strictly below floor. When .false., h_new is an exact copy of h_old (no-op) and the caller must leave the column untouched.

When grounded, each sub-floor layer is inflated to floor and the required volume is removed from the surplus layers (h_old > floor) in proportion to their surplus, so Sigma h_new == Sigma h_old and every returned h_new(k) >= floor (feasible whenever the column can hold nz*floor). The largest-surplus layer absorbs the summation round-off so the column total is exact to a single ULP.

Degenerate fallback: if the whole column cannot hold nz*floor (never reached in a deep isopycnal ocean), the mass is spread uniformly — still conservative, floor not guaranteed.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nz
real(kind=wp), intent(in) :: h_old(nz)
real(kind=wp), intent(in) :: h_floor
real(kind=wp), intent(out) :: h_new(nz)
logical, intent(out) :: grounded

Called by

proc~~min_thickness_target_column~~CalledByGraph proc~min_thickness_target_column min_thickness_target_column proc~build_target_field build_target_field proc~build_target_field->proc~min_thickness_target_column proc~ocean_apply_conservative_min_thickness ocean_apply_conservative_min_thickness proc~ocean_apply_conservative_min_thickness->proc~build_target_field proc~run_continuity_chain run_continuity_chain proc~run_continuity_chain->proc~ocean_apply_conservative_min_thickness proc~run_stage_split run_stage_split proc~run_stage_split->proc~run_continuity_chain proc~ocean_dyn_step_split ocean_dyn_step_split proc~ocean_dyn_step_split->proc~run_stage_split

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: best_surplus
real(kind=wp), private :: deficit_sum
real(kind=wp), private :: give
integer, private :: k
integer, private :: k_donor
real(kind=wp), private :: sum_new
real(kind=wp), private :: surplus_k
real(kind=wp), private :: surplus_sum
real(kind=wp), private :: total

Source Code

   pure subroutine min_thickness_target_column(nz, h_old, h_floor, h_new, grounded)
      !$acc routine seq
      !$omp declare target
      !! Build the floor-only conservative target thickness column.
      !!
      !! `grounded` (out): `.true.` iff any layer is strictly below `floor`.
      !! When `.false.`, `h_new` is an exact copy of `h_old` (no-op) and the
      !! caller must leave the column untouched.
      !!
      !! When grounded, each sub-floor layer is inflated to `floor` and the
      !! required volume is removed from the surplus layers (`h_old > floor`)
      !! in proportion to their surplus, so `Sigma h_new == Sigma h_old` and
      !! every returned `h_new(k) >= floor` (feasible whenever the column can
      !! hold `nz*floor`).  The largest-surplus layer absorbs the summation
      !! round-off so the column total is exact to a single ULP.
      !!
      !! Degenerate fallback: if the whole column cannot hold `nz*floor`
      !! (never reached in a deep isopycnal ocean), the mass is spread
      !! uniformly — still conservative, floor not guaranteed.
      integer, intent(in) :: nz
      real(wp), intent(in) :: h_old(nz)
      real(wp), intent(in) :: h_floor
      real(wp), intent(out) :: h_new(nz)
      logical, intent(out) :: grounded

      integer :: k, k_donor
      real(wp) :: total, surplus_sum, deficit_sum, surplus_k
      real(wp) :: give, sum_new, best_surplus

      grounded = .false.
      total = 0.0_wp
      do k = 1, nz
         h_new(k) = h_old(k)
         total = total + h_old(k)
         if (h_old(k) < h_floor) grounded = .true.
      end do
      if (.not. grounded) return

      ! Degenerate: not enough water to floor every layer -> spread uniformly.
      if (total <= real(nz, wp)*h_floor) then
         do k = 1, nz
            h_new(k) = total/real(nz, wp)
         end do
         return
      end if

      ! Surplus available above the floor and total deficit below it.
      surplus_sum = 0.0_wp
      deficit_sum = 0.0_wp
      do k = 1, nz
         surplus_k = h_old(k) - h_floor
         if (surplus_k > 0.0_wp) then
            surplus_sum = surplus_sum + surplus_k
         else
            deficit_sum = deficit_sum - surplus_k
         end if
      end do
      ! total > nz*floor guarantees surplus_sum >= deficit_sum (feasible).

      ! Inflate sub-floor layers to the floor; draw the deficit from surplus
      ! layers proportionally to their surplus.
      do k = 1, nz
         surplus_k = h_old(k) - h_floor
         if (surplus_k > 0.0_wp) then
            give = (surplus_k/surplus_sum)*deficit_sum
            h_new(k) = h_old(k) - give
         else
            h_new(k) = h_floor
         end if
      end do

      ! Absorb summation round-off into the largest-surplus layer so the
      ! column total is preserved to a single ULP (exact conservation of h).
      k_donor = 1
      best_surplus = -1.0_wp
      sum_new = 0.0_wp
      do k = 1, nz
         sum_new = sum_new + h_new(k)
         surplus_k = h_old(k) - h_floor
         if (surplus_k > best_surplus) then
            best_surplus = surplus_k
            k_donor = k
         end if
      end do
      h_new(k_donor) = h_new(k_donor) + (total - sum_new)
   end subroutine min_thickness_target_column