top_drag_stress_mag_impl Subroutine

public pure subroutine top_drag_stress_mag_impl(stress_top, u_face, v_face, h_layer, wet_mask, cover_frac, k_top, h_vanished, variant, r, c_d, h_floor, htbl, bg_vel, tbl_min, rho0, nx_u, ny_u, nx_v, ny_v, nx, ny, nz)

Cell-centred magnitude of the top stress (N/m^2), for the later ustar_shelf consumer:

quadratic |tau| = rho_0 * C_d * |U_tbl_eff|^2 linear |tau| = rho_0 * r * |U_tbl| * h_tbl

Both are rho_0 * (drag acceleration) * (band thickness), so the two forms are one definition, and sqrt(|tau|/rho_0) is the friction velocity either way. Cell-centred velocities come from the ordinary 2-point face averages; no cover interpolation is needed because cover_frac IS cell-centred here.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(out) :: stress_top(nx,ny)
real(kind=wp), intent(in) :: u_face(nx_u,ny_u,nz)
real(kind=wp), intent(in) :: v_face(nx_v,ny_v,nz)
real(kind=wp), intent(in) :: h_layer(nx,ny,nz)
real(kind=wp), intent(in) :: wet_mask(nx,ny)
real(kind=wp), intent(in) :: cover_frac(nx,ny)
integer, intent(in) :: k_top(nx,ny)

ms%k_top – the first LIVE layer, nz off a rigid top. stress_top is the one number the boundary-layer schemes turn into u_* under the shelf (through ocean_surface_stress_t%stress_shelf), so a band mean built from a filler is a wrong u_* in BOTH KPP and EPBL.

real(kind=wp), intent(in) :: h_vanished

H_VANISHED; see top_drag_tendencies_impl.

integer, intent(in) :: variant
real(kind=wp), intent(in) :: r
real(kind=wp), intent(in) :: c_d
real(kind=wp), intent(in) :: h_floor
real(kind=wp), intent(in) :: htbl
real(kind=wp), intent(in) :: bg_vel
real(kind=wp), intent(in) :: tbl_min
real(kind=wp), intent(in) :: rho0
integer, intent(in) :: nx_u
integer, intent(in) :: ny_u
integer, intent(in) :: nx_v
integer, intent(in) :: ny_v
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz

Calls

proc~~top_drag_stress_mag_impl~~CallsGraph proc~top_drag_stress_mag_impl top_drag_stress_mag_impl local local proc~top_drag_stress_mag_impl->local

Called by

proc~~top_drag_stress_mag_impl~~CalledByGraph proc~top_drag_stress_mag_impl top_drag_stress_mag_impl proc~ocean_top_drag_compute_tendencies ocean_top_drag_compute_tendencies proc~ocean_top_drag_compute_tendencies->proc~top_drag_stress_mag_impl proc~run_stage run_stage proc~run_stage->proc~ocean_top_drag_compute_tendencies proc~run_stage_split run_stage_split proc~run_stage_split->proc~ocean_top_drag_compute_tendencies proc~ocean_dyn_step ocean_dyn_step proc~ocean_dyn_step->proc~run_stage 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 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 :: abs_u_eff
real(kind=wp), private :: cumul_h
real(kind=wp), private :: h_eff
real(kind=wp), private :: h_in
real(kind=wp), private :: h_in_total
real(kind=wp), private :: h_k
integer, private :: i
integer, private :: j
integer, private :: k
integer, private :: kt
logical, private :: layer_only
logical, private :: quad
real(kind=wp), private :: spd
real(kind=wp), private :: u_c
real(kind=wp), private :: u_int
real(kind=wp), private :: u_tbl
real(kind=wp), private :: v_c
real(kind=wp), private :: v_int
real(kind=wp), private :: v_tbl

Source Code

   pure subroutine top_drag_stress_mag_impl(stress_top, u_face, v_face, &
                                            h_layer, wet_mask, cover_frac, &
                                            k_top, h_vanished, &
                                            variant, r, c_d, h_floor, &
                                            htbl, bg_vel, tbl_min, rho0, &
                                            nx_u, ny_u, nx_v, ny_v, nx, ny, nz)
      !! Cell-centred magnitude of the top stress (N/m^2), for the
      !! later `ustar_shelf` consumer:
      !!
      !!   quadratic  `|tau| = rho_0 * C_d * |U_tbl_eff|^2`
      !!   linear     `|tau| = rho_0 * r * |U_tbl| * h_tbl`
      !!
      !! Both are `rho_0 * (drag acceleration) * (band thickness)`, so the
      !! two forms are one definition, and `sqrt(|tau|/rho_0)` is the
      !! friction velocity either way.  Cell-centred velocities come from
      !! the ordinary 2-point face averages; no cover interpolation is
      !! needed because `cover_frac` IS cell-centred here.
      integer, intent(in) :: nx_u, ny_u, nx_v, ny_v, nx, ny, nz, variant
      real(wp), intent(in) :: r, c_d, h_floor, htbl, bg_vel, tbl_min, rho0
      real(wp), intent(in) :: u_face(nx_u, ny_u, nz), v_face(nx_v, ny_v, nz)
      real(wp), intent(in) :: h_layer(nx, ny, nz)
      real(wp), intent(in) :: wet_mask(nx, ny), cover_frac(nx, ny)
      integer, intent(in) :: k_top(nx, ny)
         !! `ms%k_top` -- the first LIVE layer, `nz` off a rigid top.
         !! `stress_top` is the one number the boundary-layer schemes
         !! turn into `u_*` under the shelf (through
         !! `ocean_surface_stress_t%stress_shelf`), so a band mean built
         !! from a filler is a wrong `u_*` in BOTH KPP and EPBL.
      real(wp), intent(in) :: h_vanished
         !! `H_VANISHED`; see `top_drag_tendencies_impl`.
      real(wp), intent(out) :: stress_top(nx, ny)

      integer :: i, j, k, kt
      logical :: layer_only, quad
      real(wp) :: cumul_h, h_k, h_in, u_int, v_int, h_in_total
      real(wp) :: u_c, v_c, u_tbl, v_tbl, h_eff, abs_u_eff, spd

      layer_only = (htbl <= 0.0_wp)
      quad = (variant == TDRAG_QUADRATIC)

      do concurrent(j=1:ny, i=1:nx) &
         local(k, kt, cumul_h, h_k, h_in, u_int, v_int, h_in_total, &
               u_c, v_c, u_tbl, v_tbl, h_eff, abs_u_eff, spd)
         kt = k_top(i, j)
         cumul_h = 0.0_wp
         u_int = 0.0_wp
         v_int = 0.0_wp
         h_in_total = 0.0_wp
         do k = kt, 1, -1
            if (layer_only .and. k < kt) exit
            if ((.not. layer_only) .and. cumul_h >= htbl) exit
            h_k = h_layer(i, j, k)
            if (h_k <= h_vanished) exit
            if (layer_only) then
               h_in = h_k
            else
               h_in = max(0.0_wp, min(h_k, htbl - cumul_h))
            end if
            u_c = 0.5_wp*(u_face(i, j, k) + u_face(i + 1, j, k))
            v_c = 0.5_wp*(v_face(i, j, k) + v_face(i, j + 1, k))
            u_int = u_int + u_c*h_in
            v_int = v_int + v_c*h_in
            h_in_total = h_in_total + h_in
            cumul_h = cumul_h + h_k
         end do
         h_eff = max(max(h_in_total, tbl_min), h_floor)
         u_tbl = u_int/h_eff
         v_tbl = v_int/h_eff
         spd = sqrt(u_tbl*u_tbl + v_tbl*v_tbl)
         abs_u_eff = max(bg_vel, spd)
         if (quad) then
            stress_top(i, j) = rho0*c_d*abs_u_eff*abs_u_eff* &
                               wet_mask(i, j)*cover_frac(i, j)
         else
            stress_top(i, j) = rho0*r*spd*h_eff* &
                               wet_mask(i, j)*cover_frac(i, j)
         end if
      end do
   end subroutine top_drag_stress_mag_impl