add_top_drag_into_F_slow Subroutine

public pure subroutine add_top_drag_into_F_slow(bt_work, td, ms)

Add the ice-shelf top-drag tendency into the already-summed slow forcing. Separate from sum_slow_tendencies_into_F_slow (rather than a sixth term in it) for one reason: the top-drag slot is OPTIONAL all the way down the driver chain, and the sum above must stay a single unconditional kernel with no present branch inside its do concurrent.

Why it has to be here at all. F_slow is depth-meaned into F_bt, the barotropic substep integrates F_bt, and apply_bt_correction subtracts dt*F_bt back out of the layer update. A layer tendency that is applied to the layers but NOT in F_slow is therefore (a) invisible to the fast mode — a barotropic cavity flow would feel no top friction at all inside the substep loop — and (b) not subtracted by the correction, so its damping re-enters the barotropic state one stage late as an uncorrected residue. Bottom drag is in the sum for exactly this reason; the side-wall (channel) drag is NOT, and is the standing counter-example of the bug this avoids.

The buffer is added whether or not the explicit apply runs: when the drag is folded into the vdiff k = nz diagonal the layers get it implicitly AFTER the barotropic correction, while the fast mode still needs the explicit estimate — the same split the bottom drag’s implicit_drag path already takes.

No-op (and no kernel launch) when the slot is disabled: its buffers are (1,1,1) placeholders then.

Arguments

Type IntentOptional Attributes Name
type(barotropic_workstate_t), intent(inout) :: bt_work
type(ocean_top_drag_t), intent(in) :: td
type(multilayer_state_t), intent(in) :: ms

Called by

proc~~add_top_drag_into_f_slow~~CalledByGraph proc~add_top_drag_into_f_slow add_top_drag_into_F_slow proc~run_stage_split run_stage_split proc~run_stage_split->proc~add_top_drag_into_f_slow proc~ocean_dyn_step_split ocean_dyn_step_split proc~ocean_dyn_step_split->proc~run_stage_split 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
integer, private :: i
integer, private :: j
integer, private :: k
integer, private :: nu
integer, private :: nv
integer, private :: nx
integer, private :: ny
integer, private :: nz

Source Code

   pure subroutine add_top_drag_into_F_slow(bt_work, td, ms)
      !! Add the ice-shelf top-drag tendency into the already-summed
      !! slow forcing.  Separate from `sum_slow_tendencies_into_F_slow`
      !! (rather than a sixth term in it) for one reason: the top-drag
      !! slot is OPTIONAL all the way down the driver chain, and the sum
      !! above must stay a single unconditional kernel with no `present`
      !! branch inside its `do concurrent`.
      !!
      !! **Why it has to be here at all.**  `F_slow` is depth-meaned into
      !! `F_bt`, the barotropic substep integrates `F_bt`, and
      !! `apply_bt_correction` subtracts `dt*F_bt` back out of the layer
      !! update.  A layer tendency that is applied to the layers but NOT
      !! in `F_slow` is therefore (a) invisible to the fast mode — a
      !! barotropic cavity flow would feel no top friction at all inside
      !! the substep loop — and (b) not subtracted by the correction, so
      !! its damping re-enters the barotropic state one stage late as an
      !! uncorrected residue.  Bottom drag is in the sum for exactly this
      !! reason; the side-wall (channel) drag is NOT, and is the standing
      !! counter-example of the bug this avoids.
      !!
      !! The buffer is added whether or not the explicit apply runs: when
      !! the drag is folded into the vdiff `k = nz` diagonal the layers
      !! get it implicitly AFTER the barotropic correction, while the fast
      !! mode still needs the explicit estimate — the same split the
      !! bottom drag's `implicit_drag` path already takes.
      !!
      !! No-op (and no kernel launch) when the slot is disabled: its
      !! buffers are `(1,1,1)` placeholders then.
      type(barotropic_workstate_t), intent(inout) :: bt_work
      type(ocean_top_drag_t), intent(in) :: td
      type(multilayer_state_t), intent(in) :: ms

      integer :: i, j, k, nu, nv, nx, ny, nz

      if (.not. td%enable) return

      nu = size(bt_work%F_slow_u, 1)
      nv = size(bt_work%F_slow_v, 2)
      nx = size(bt_work%F_slow_v, 1)
      ny = size(bt_work%F_slow_u, 2)
      nz = ms%nz_ml

      do concurrent(k=1:nz, j=1:ny, i=1:nu)
         bt_work%F_slow_u(i, j, k) = bt_work%F_slow_u(i, j, k) + &
                                     td%du_drag%data(i, j, k)
      end do
      do concurrent(k=1:nz, j=1:nv, i=1:nx)
         bt_work%F_slow_v(i, j, k) = bt_work%F_slow_v(i, j, k) + &
                                     td%dv_drag%data(i, j, k)
      end do
   end subroutine add_top_drag_into_F_slow