corner_abs_vort Function

private pure function corner_abs_vort(ic, jc, k, nx, ny, nz, q_val, h, wet_T, areaT, use_mom6_ch) result(av)

BOUND_CORIOLIS abs_vort recovery: return (f+ζ) at corner (ic,jc) by multiplying the PV q_val back by the corner thickness Pass 2 divided abs_vort by — recovering (f+ζ) to round-off. Recomputes the SAME wet-area-weighted 4-cell hm_num/hm_den, then reconstructs the effective corner thickness with the SAME formula (and floors) the active corner_h variant used in Pass 2: cell_mean (default): h_corner = max(hm_num/max(hm_den,H_DIV_EPS), CORIOLIS_H_MIN_PV); av = q·h_corner. mom6_area (use_mom6_ch): Pass 2 formed q = abs_vort·hm_den/ (hm_num + PV_VOL_NEGLECT), so the consistent inverse is av = q·(hm_num + PV_VOL_NEGLECT)/hm_den (hm_den guarded by H_DIV_EPS for the fully-land corner, where q≡0 ⇒ av≡0 anyway). Without matching the variant the recovered abs_vort would be slightly inconsistent with how q was made whenever BOTH bound_coriolis and corner_h=”mom6_area” are on — visible only in the truly-vanishing- thickness limit. Chosen over a persistent abs_vort buffer so the default-off knob costs ZERO memory.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: ic
integer, intent(in) :: jc
integer, intent(in) :: k
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz
real(kind=wp), intent(in) :: q_val
real(kind=wp), intent(in) :: h(nx,ny,nz)
real(kind=wp), intent(in) :: wet_T(nx,ny)
real(kind=wp), intent(in) :: areaT(nx,ny)
logical, intent(in) :: use_mom6_ch

Return Value real(kind=wp)


Called by

proc~~corner_abs_vort~~CalledByGraph proc~corner_abs_vort corner_abs_vort proc~coriolis_adv_compute_tendencies_sadourny_energy coriolis_adv_compute_tendencies_sadourny_energy proc~coriolis_adv_compute_tendencies_sadourny_energy->proc~corner_abs_vort proc~coriolis_adv_compute_tendencies coriolis_adv_compute_tendencies proc~coriolis_adv_compute_tendencies->proc~coriolis_adv_compute_tendencies_sadourny_energy proc~run_stage run_stage proc~run_stage->proc~coriolis_adv_compute_tendencies proc~run_stage_split run_stage_split proc~run_stage_split->proc~coriolis_adv_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

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: aNE
real(kind=wp), private :: aNW
real(kind=wp), private :: aSE
real(kind=wp), private :: aSW
real(kind=wp), private :: h_corner
real(kind=wp), private :: hm_den
real(kind=wp), private :: hm_num
integer, private :: ie
integer, private :: iw
integer, private :: jn
integer, private :: js

Source Code

   pure function corner_abs_vort(ic, jc, k, nx, ny, nz, q_val, h, wet_T, areaT, &
                                 use_mom6_ch) result(av)
      !$acc routine seq
      !! BOUND_CORIOLIS abs_vort recovery: return `(f+ζ)` at corner `(ic,jc)`
      !! by multiplying the PV `q_val` back by the corner thickness Pass 2
      !! divided abs_vort by — recovering `(f+ζ)` to round-off.  Recomputes
      !! the SAME wet-area-weighted 4-cell `hm_num`/`hm_den`, then reconstructs
      !! the effective corner thickness with the SAME formula (and floors) the
      !! active `corner_h` variant used in Pass 2:
      !!   `cell_mean` (default): h_corner = max(hm_num/max(hm_den,H_DIV_EPS),
      !!     CORIOLIS_H_MIN_PV); av = q·h_corner.
      !!   `mom6_area` (`use_mom6_ch`): Pass 2 formed q = abs_vort·hm_den/
      !!     (hm_num + PV_VOL_NEGLECT), so the consistent inverse is
      !!     av = q·(hm_num + PV_VOL_NEGLECT)/hm_den (hm_den guarded by
      !!     H_DIV_EPS for the fully-land corner, where q≡0 ⇒ av≡0 anyway).
      !! Without matching the variant the recovered abs_vort would be slightly
      !! inconsistent with how q was made whenever BOTH bound_coriolis and
      !! corner_h="mom6_area" are on — visible only in the truly-vanishing-
      !! thickness limit.  Chosen over a persistent abs_vort buffer so the
      !! default-off knob costs ZERO memory.
      integer, intent(in) :: ic, jc, k, nx, ny, nz
      real(wp), intent(in) :: q_val
      real(wp), intent(in) :: h(nx, ny, nz)
      real(wp), intent(in) :: wet_T(nx, ny), areaT(nx, ny)
      logical, intent(in) :: use_mom6_ch
      real(wp) :: av
      integer :: iw, ie, js, jn
      real(wp) :: aSW, aSE, aNW, aNE, hm_num, hm_den, h_corner
      iw = max(1, ic - 1)
      ie = min(nx, ic)
      js = max(1, jc - 1)
      jn = min(ny, jc)
      aSW = wet_T(iw, js)*areaT(iw, js)
      aSE = wet_T(ie, js)*areaT(ie, js)
      aNW = wet_T(iw, jn)*areaT(iw, jn)
      aNE = wet_T(ie, jn)*areaT(ie, jn)
      hm_num = aSW*h(iw, js, k) + aSE*h(ie, js, k) + &
               aNW*h(iw, jn, k) + aNE*h(ie, jn, k)
      hm_den = aSW + aSE + aNW + aNE
      if (use_mom6_ch) then
         ! Algebraic inverse of Pass 2's mom6_area form (no thickness cap;
         ! PV_VOL_NEGLECT is the same 1/0 armor Pass 2 added to hm_num).
         h_corner = (hm_num + PV_VOL_NEGLECT)/max(hm_den, H_DIV_EPS)
      else
         h_corner = hm_num/max(hm_den, H_DIV_EPS)
         h_corner = max(h_corner, CORIOLIS_H_MIN_PV)
      end if
      av = q_val*h_corner
   end function corner_abs_vort