cavity_ustar Subroutine

public pure subroutine cavity_ustar(u, v, cd, u_tide, ustar_min, u_star, ierr)

Interface friction velocity (m/s),

u* = max( sqrt( cd*(u^2 + v^2 + u_tide^2) ), ustar_min )

Jenkins, Nicholls & Corr (2010) eq. (10) p. 2309 introduces the tidal variance term u*^2 = C_d (U^2 + <U_T^2>); the ISOMIP+ protocol adopts it as eq. (27) p. 2485 with u_tidal = 0.01 m/s RMS. The floor ustar_min is Yung et al. (2025) eq. (14) p. 5836. Both exist for the same stated reason: an ocean at rest under an ice shelf would otherwise melt exactly nothing even with heat available. With u = v = 0, cd = 2.5e-3 and u_tide = 0.01 this returns 5e-4 m/s, the operative ISOMIP+ floor.

TRAP: the tidal term belongs to the MELT friction velocity only — ISOMIP+ p. 2486, “The computation of top and bottom drag do not incorporate utidal”. Do not reuse this u* for the momentum drag.

GUARD: the max() is reached only after every input has been PROVEN finite. Reversing that order is the documented NaN-laundering bug — a NaN velocity would come back out as ustar_min and produce a small, plausible melt rate forever.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: u

Far-field velocity component (m/s).

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

Far-field velocity component (m/s).

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

Top drag coefficient (dimensionless), >= 0.

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

RMS tidal velocity (m/s), >= 0 by squaring.

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

Friction-velocity floor (m/s), >= 0.

real(kind=wp), intent(out) :: u_star

Friction velocity (m/s). Exactly zero on any non-OK status.

integer, intent(out) :: ierr

CAVITY_MELT_* status.


Called by

proc~~cavity_ustar~~CalledByGraph proc~cavity_ustar cavity_ustar proc~cavity_melt_columns_2d cavity_melt_columns_2d proc~cavity_melt_columns_2d->proc~cavity_ustar proc~ocean_cavity_flux_step ocean_cavity_flux_step proc~ocean_cavity_flux_step->proc~cavity_melt_columns_2d proc~engine_step_finalize engine_step_finalize proc~engine_step_finalize->proc~ocean_cavity_flux_step proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_step_finalize proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step_finalize proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: us

Source Code

   pure subroutine cavity_ustar(u, v, cd, u_tide, ustar_min, u_star, ierr)
      !! Interface friction velocity (m/s),
      !!
      !!   `u* = max( sqrt( cd*(u^2 + v^2 + u_tide^2) ), ustar_min )`
      !!
      !! Jenkins, Nicholls & Corr (2010) eq. (10) p. 2309 introduces the
      !! tidal variance term `u*^2 = C_d (U^2 + <U_T^2>)`; the ISOMIP+
      !! protocol adopts it as eq. (27) p. 2485 with `u_tidal = 0.01 m/s`
      !! RMS.  The floor `ustar_min` is Yung et al. (2025) eq. (14)
      !! p. 5836.  Both exist for the same stated reason: an ocean at rest
      !! under an ice shelf would otherwise melt exactly nothing even with
      !! heat available.  With `u = v = 0`, `cd = 2.5e-3` and
      !! `u_tide = 0.01` this returns 5e-4 m/s, the operative ISOMIP+
      !! floor.
      !!
      !! TRAP: the tidal term belongs to the MELT friction velocity only —
      !! ISOMIP+ p. 2486, "The computation of top and bottom drag do not
      !! incorporate utidal".  Do not reuse this `u*` for the momentum
      !! drag.
      !!
      !! GUARD: the `max()` is reached only after every input has been
      !! PROVEN finite.  Reversing that order is the documented
      !! NaN-laundering bug — a NaN velocity would come back out as
      !! `ustar_min` and produce a small, plausible melt rate forever.
      !$acc routine seq
      real(wp), intent(in) :: u
         !! Far-field velocity component (m/s).
      real(wp), intent(in) :: v
         !! Far-field velocity component (m/s).
      real(wp), intent(in) :: cd
         !! Top drag coefficient (dimensionless), >= 0.
      real(wp), intent(in) :: u_tide
         !! RMS tidal velocity (m/s), >= 0 by squaring.
      real(wp), intent(in) :: ustar_min
         !! Friction-velocity floor (m/s), >= 0.
      real(wp), intent(out) :: u_star
         !! Friction velocity (m/s).  Exactly zero on any non-OK status.
      integer, intent(out) :: ierr
         !! `CAVITY_MELT_*` status.
      real(wp) :: us

      ierr = CAVITY_MELT_OK
      u_star = 0.0_wp
      if (.not. (ieee_is_finite(u) .and. ieee_is_finite(v) .and. &
                 ieee_is_finite(cd) .and. ieee_is_finite(u_tide) .and. &
                 ieee_is_finite(ustar_min))) then
         ierr = CAVITY_MELT_NONFINITE_INPUT
         return
      end if
      if (cd < 0.0_wp .or. ustar_min < 0.0_wp) then
         ierr = CAVITY_MELT_BAD_INPUT
         return
      end if
      us = sqrt(cd*(u*u + v*v + u_tide*u_tide))
      if (us > ustar_min) then
         u_star = us
      else
         u_star = ustar_min
      end if
   end subroutine cavity_ustar