MOM6
mom_set_visc Module Reference

Data Types

type  set_visc_cs
 

Functions/Subroutines

subroutine, public set_viscous_bbl (u, v, h, tv, visc, G, GV, CS)
 The following subroutine calculates the thickness of the bottom boundary layer and the viscosity within that layer. A drag law is used, either linearized about an assumed bottom velocity or using the actual near-bottom velocities combined with an assumed unresolved velocity. The bottom boundary layer thickness is limited by a combination of stratification and rotation, as in the paper of Killworth and Edwards, JPO 1999. It is not necessary to calculate the thickness and viscosity every time step; instead previous values may be used. More...
 
real function set_v_at_u (v, h, G, i, j, k, mask2dCv)
 This subroutine finds a thickness-weighted value of v at the u-points. More...
 
real function set_u_at_v (u, h, G, i, j, k, mask2dCu)
 This subroutine finds a thickness-weighted value of u at the v-points. More...
 
subroutine, public set_viscous_ml (u, v, h, tv, fluxes, visc, dt, G, GV, CS)
 The following subroutine calculates the thickness of the surface boundary layer for applying an elevated viscosity. A bulk Richardson criterion or the thickness of the topmost NKML layers (with a bulk mixed layer) are currently used. The thicknesses are given in terms of fractional layers, so that this thickness will move as the thickness of the topmost layers change. More...
 
subroutine, public set_visc_register_restarts (HI, GV, param_file, visc, restart_CS)
 This subroutine is used to register any fields associated with the vertvisc_type. More...
 
subroutine, public set_visc_init (Time, G, GV, param_file, diag, visc, CS, OBC)
 
subroutine, public set_visc_end (visc, CS)
 

Function/Subroutine Documentation

◆ set_u_at_v()

real function mom_set_visc::set_u_at_v ( real, dimension(szib_(g),szj_(g),szk_(g)), intent(in)  u,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h,
type(ocean_grid_type), intent(in)  G,
integer, intent(in)  i,
integer, intent(in)  j,
integer, intent(in)  k,
real, dimension(szib_(g),szj_(g)), intent(in)  mask2dCu 
)
private

This subroutine finds a thickness-weighted value of u at the v-points.

Parameters
[in]gThe ocean's grid structure
[in]uThe zonal velocity, in m s-1
[in]hLayer thicknesses, in H (usually m or kg m-2)

Definition at line 989 of file MOM_set_viscosity.F90.

Referenced by set_viscous_bbl(), and set_viscous_ml().

989  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
990  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1
991  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
992  real, dimension(SZIB_(G),SZJ_(G)), intent(in) :: mask2dcu
993  integer, intent(in) :: i, j, k
994  real :: set_u_at_v
995 
996  ! This subroutine finds a thickness-weighted value of u at the v-points.
997  real :: hwt(4) ! Masked weights used to average u onto v, in H.
998  real :: hwt_tot ! The sum of the masked thicknesses, in H.
999 
1000  hwt(1) = (h(i-1,j,k) + h(i,j,k)) * mask2dcu(i-1,j)
1001  hwt(2) = (h(i,j,k) + h(i+1,j,k)) * mask2dcu(i,j)
1002  hwt(3) = (h(i-1,j+1,k) + h(i,j+1,k)) * mask2dcu(i-1,j+1)
1003  hwt(4) = (h(i,j+1,k) + h(i+1,j+1,k)) * mask2dcu(i,j+1)
1004 
1005  hwt_tot = (hwt(1) + hwt(4)) + (hwt(2) + hwt(3))
1006  set_u_at_v = 0.0
1007  if (hwt_tot > 0.0) set_u_at_v = &
1008  ((hwt(2) * u(i,j,k) + hwt(3) * u(i-1,j+1,k)) + &
1009  (hwt(1) * u(i-1,j,k) + hwt(4) * u(i,j+1,k))) / hwt_tot
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the caller graph for this function:

◆ set_v_at_u()

real function mom_set_visc::set_v_at_u ( real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(in)  v,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h,
type(ocean_grid_type), intent(in)  G,
integer, intent(in)  i,
integer, intent(in)  j,
integer, intent(in)  k,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb), intent(in)  mask2dCv 
)
private

This subroutine finds a thickness-weighted value of v at the u-points.

Parameters
[in]gThe ocean's grid structure
[in]vThe meridional velocity, in m s-1
[in]hLayer thicknesses, in H (usually m or kg m-2)

Definition at line 964 of file MOM_set_viscosity.F90.

Referenced by set_viscous_bbl(), and set_viscous_ml().

964  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
965  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity, in m s-1
966  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
967  integer, intent(in) :: i, j, k
968  real, dimension(SZI_(G),SZJB_(G)), intent(in) :: mask2dcv
969  real :: set_v_at_u
970 
971  ! This subroutine finds a thickness-weighted value of v at the u-points.
972  real :: hwt(4) ! Masked weights used to average v onto u, in H.
973  real :: hwt_tot ! The sum of the masked thicknesses, in H.
974 
975  hwt(1) = (h(i,j-1,k) + h(i,j,k)) * mask2dcv(i,j-1)
976  hwt(2) = (h(i+1,j-1,k) + h(i+1,j,k)) * mask2dcv(i+1,j-1)
977  hwt(3) = (h(i,j,k) + h(i,j+1,k)) * mask2dcv(i,j)
978  hwt(4) = (h(i+1,j,k) + h(i+1,j+1,k)) * mask2dcv(i+1,j)
979 
980  hwt_tot = (hwt(1) + hwt(4)) + (hwt(2) + hwt(3))
981  set_v_at_u = 0.0
982  if (hwt_tot > 0.0) set_v_at_u = &
983  ((hwt(3) * v(i,j,k) + hwt(2) * v(i+1,j-1,k)) + &
984  (hwt(4) * v(i+1,j,k) + hwt(1) * v(i,j-1,k))) / hwt_tot
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the caller graph for this function:

◆ set_visc_end()

subroutine, public mom_set_visc::set_visc_end ( type(vertvisc_type), intent(inout)  visc,
type(set_visc_cs), pointer  CS 
)

Definition at line 2058 of file MOM_set_viscosity.F90.

2058  type(vertvisc_type), intent(inout) :: visc
2059  type(set_visc_cs), pointer :: cs
2060  if (cs%bottomdraglaw) then
2061  deallocate(visc%bbl_thick_u) ; deallocate(visc%bbl_thick_v)
2062  deallocate(visc%kv_bbl_u) ; deallocate(visc%kv_bbl_v)
2063  endif
2064  if (cs%Channel_drag) then
2065  deallocate(visc%Ray_u) ; deallocate(visc%Ray_v)
2066  endif
2067  if (cs%dynamic_viscous_ML) then
2068  deallocate(visc%nkml_visc_u) ; deallocate(visc%nkml_visc_v)
2069  endif
2070  if (associated(visc%Kd_turb)) deallocate(visc%Kd_turb)
2071  if (associated(visc%TKE_turb)) deallocate(visc%TKE_turb)
2072  if (associated(visc%Kv_turb)) deallocate(visc%Kv_turb)
2073  if (associated(visc%ustar_bbl)) deallocate(visc%ustar_bbl)
2074  if (associated(visc%TKE_bbl)) deallocate(visc%TKE_bbl)
2075  if (associated(visc%taux_shelf)) deallocate(visc%taux_shelf)
2076  if (associated(visc%tauy_shelf)) deallocate(visc%tauy_shelf)
2077  if (associated(visc%tbl_thick_shelf_u)) deallocate(visc%tbl_thick_shelf_u)
2078  if (associated(visc%tbl_thick_shelf_v)) deallocate(visc%tbl_thick_shelf_v)
2079  if (associated(visc%kv_tbl_shelf_u)) deallocate(visc%kv_tbl_shelf_u)
2080  if (associated(visc%kv_tbl_shelf_v)) deallocate(visc%kv_tbl_shelf_v)
2081 
2082  deallocate(cs)

◆ set_visc_init()

subroutine, public mom_set_visc::set_visc_init ( type(time_type), intent(in), target  Time,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(param_file_type), intent(in)  param_file,
type(diag_ctrl), intent(inout), target  diag,
type(vertvisc_type), intent(inout)  visc,
type(set_visc_cs), pointer  CS,
type(ocean_obc_type), pointer  OBC 
)
Parameters
[in]timeThe current model time.
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]param_fileA structure to parse for run-time parameters.
[in,out]diagA structure that is used to regulate diagnostic output.
[in,out]viscA structure containing vertical viscosities and related fields. Allocated here.
csA pointer that is set to point to the control structure for this module

Definition at line 1815 of file MOM_set_viscosity.F90.

References mom_kappa_shear::kappa_shear_is_used(), and mom_error_handler::mom_error().

1815  type(time_type), target, intent(in) :: time !< The current model time.
1816  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
1817  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
1818  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
1819  !! parameters.
1820  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to regulate diagnostic
1821  !! output.
1822  type(vertvisc_type), intent(inout) :: visc !< A structure containing vertical viscosities and
1823  !! related fields. Allocated here.
1824  type(set_visc_cs), pointer :: cs !< A pointer that is set to point to the control
1825  !! structure for this module
1826  type(ocean_obc_type), pointer :: obc
1827 ! Arguments: Time - The current model time.
1828 ! (in) G - The ocean's grid structure.
1829 ! (in) GV - The ocean's vertical grid structure.
1830 ! (in) param_file - A structure indicating the open file to parse for
1831 ! model parameter values.
1832 ! (in) diag - A structure that is used to regulate diagnostic output.
1833 ! (out) visc - A structure containing vertical viscosities and related
1834 ! fields. Allocated here.
1835 ! (in/out) CS - A pointer that is set to point to the control structure
1836 ! for this module
1837  real :: csmag_chan_dflt, smag_const1, tke_decay_dflt, bulk_ri_ml_dflt
1838  real :: kv_background
1839  real :: omega_frac_dflt
1840  integer :: isd, ied, jsd, jed, isdb, iedb, jsdb, jedb, nz, i, j, n
1841  logical :: use_kappa_shear, adiabatic, differential_diffusion, use_omega
1842  type(obc_segment_type), pointer :: segment ! pointer to OBC segment type
1843 ! This include declares and sets the variable "version".
1844 #include "version_variable.h"
1845  character(len=40) :: mdl = "MOM_set_visc" ! This module's name.
1846 
1847  if (associated(cs)) then
1848  call mom_error(warning, "set_visc_init called with an associated "// &
1849  "control structure.")
1850  return
1851  endif
1852  allocate(cs)
1853 
1854  cs%OBC => obc
1855 
1856  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = gv%ke
1857  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1858 
1859 
1860  cs%diag => diag
1861 
1862 ! Set default, read and log parameters
1863  call log_version(param_file, mdl, version, "")
1864  cs%RiNo_mix = .false.
1865  use_kappa_shear = .false. ; differential_diffusion = .false. !; adiabatic = .false. ! Needed? -AJA
1866  call get_param(param_file, mdl, "BOTTOMDRAGLAW", cs%bottomdraglaw, &
1867  "If true, the bottom stress is calculated with a drag \n"//&
1868  "law of the form c_drag*|u|*u. The velocity magnitude \n"//&
1869  "may be an assumed value or it may be based on the \n"//&
1870  "actual velocity in the bottommost HBBL, depending on \n"//&
1871  "LINEAR_DRAG.", default=.true.)
1872  call get_param(param_file, mdl, "CHANNEL_DRAG", cs%Channel_drag, &
1873  "If true, the bottom drag is exerted directly on each \n"//&
1874  "layer proportional to the fraction of the bottom it \n"//&
1875  "overlies.", default=.false.)
1876  call get_param(param_file, mdl, "LINEAR_DRAG", cs%linear_drag, &
1877  "If LINEAR_DRAG and BOTTOMDRAGLAW are defined the drag \n"//&
1878  "law is cdrag*DRAG_BG_VEL*u.", default=.false.)
1879  call get_param(param_file, mdl, "ADIABATIC", adiabatic, default=.false., &
1880  do_not_log=.true.)
1881  if (adiabatic) then
1882  call log_param(param_file, mdl, "ADIABATIC",adiabatic, &
1883  "There are no diapycnal mass fluxes if ADIABATIC is \n"//&
1884  "true. This assumes that KD = KDML = 0.0 and that \n"//&
1885  "there is no buoyancy forcing, but makes the model \n"//&
1886  "faster by eliminating subroutine calls.", default=.false.)
1887  endif
1888 
1889  if (.not.adiabatic) then
1890  use_kappa_shear = kappa_shear_is_used(param_file)
1891  cs%RiNo_mix = use_kappa_shear
1892  call get_param(param_file, mdl, "DOUBLE_DIFFUSION", differential_diffusion, &
1893  "If true, increase diffusivitives for temperature or salt \n"//&
1894  "based on double-diffusive paramaterization from MOM4/KPP.", &
1895  default=.false.)
1896  endif
1897  call get_param(param_file, mdl, "PRANDTL_TURB", visc%Prandtl_turb, &
1898  "The turbulent Prandtl number applied to shear \n"//&
1899  "instability.", units="nondim", default=1.0)
1900  call get_param(param_file, mdl, "DEBUG", cs%debug, default=.false.)
1901 
1902  call get_param(param_file, mdl, "DYNAMIC_VISCOUS_ML", cs%dynamic_viscous_ML, &
1903  "If true, use a bulk Richardson number criterion to \n"//&
1904  "determine the mixed layer thickness for viscosity.", &
1905  default=.false.)
1906  if (cs%dynamic_viscous_ML) then
1907  call get_param(param_file, mdl, "BULK_RI_ML", bulk_ri_ml_dflt, default=0.0)
1908  call get_param(param_file, mdl, "BULK_RI_ML_VISC", cs%bulk_Ri_ML, &
1909  "The efficiency with which mean kinetic energy released \n"//&
1910  "by mechanically forced entrainment of the mixed layer \n"//&
1911  "is converted to turbulent kinetic energy. By default, \n"//&
1912  "BULK_RI_ML_VISC = BULK_RI_ML or 0.", units="nondim", &
1913  default=bulk_ri_ml_dflt)
1914  call get_param(param_file, mdl, "TKE_DECAY", tke_decay_dflt, default=0.0)
1915  call get_param(param_file, mdl, "TKE_DECAY_VISC", cs%TKE_decay, &
1916  "TKE_DECAY_VISC relates the vertical rate of decay of \n"//&
1917  "the TKE available for mechanical entrainment to the \n"//&
1918  "natural Ekman depth for use in calculating the dynamic \n"//&
1919  "mixed layer viscosity. By default, \n"//&
1920  "TKE_DECAY_VISC = TKE_DECAY or 0.", units="nondim", &
1921  default=tke_decay_dflt)
1922  call get_param(param_file, mdl, "ML_USE_OMEGA", use_omega, &
1923  "If true, use the absolute rotation rate instead of the \n"//&
1924  "vertical component of rotation when setting the decay \n"//&
1925  "scale for turbulence.", default=.false., do_not_log=.true.)
1926  omega_frac_dflt = 0.0
1927  if (use_omega) then
1928  call mom_error(warning, "ML_USE_OMEGA is depricated; use ML_OMEGA_FRAC=1.0 instead.")
1929  omega_frac_dflt = 1.0
1930  endif
1931  call get_param(param_file, mdl, "ML_OMEGA_FRAC", cs%omega_frac, &
1932  "When setting the decay scale for turbulence, use this \n"//&
1933  "fraction of the absolute rotation rate blended with the \n"//&
1934  "local value of f, as sqrt((1-of)*f^2 + of*4*omega^2).", &
1935  units="nondim", default=omega_frac_dflt)
1936  call get_param(param_file, mdl, "OMEGA", cs%omega, &
1937  "The rotation rate of the earth.", units="s-1", &
1938  default=7.2921e-5)
1939  ! This give a minimum decay scale that is typically much less than Angstrom.
1940  cs%ustar_min = 2e-4*cs%omega*(gv%Angstrom_z + gv%H_to_m*gv%H_subroundoff)
1941  else
1942  call get_param(param_file, mdl, "OMEGA", cs%omega, &
1943  "The rotation rate of the earth.", units="s-1", &
1944  default=7.2921e-5)
1945  endif
1946 
1947  call get_param(param_file, mdl, "HBBL", cs%Hbbl, &
1948  "The thickness of a bottom boundary layer with a \n"//&
1949  "viscosity of KVBBL if BOTTOMDRAGLAW is not defined, or \n"//&
1950  "the thickness over which near-bottom velocities are \n"//&
1951  "averaged for the drag law if BOTTOMDRAGLAW is defined \n"//&
1952  "but LINEAR_DRAG is not.", units="m", fail_if_missing=.true.)
1953  if (cs%bottomdraglaw) then
1954  call get_param(param_file, mdl, "CDRAG", cs%cdrag, &
1955  "CDRAG is the drag coefficient relating the magnitude of \n"//&
1956  "the velocity field to the bottom stress. CDRAG is only \n"//&
1957  "used if BOTTOMDRAGLAW is defined.", units="nondim", &
1958  default=0.003)
1959  call get_param(param_file, mdl, "DRAG_BG_VEL", cs%drag_bg_vel, &
1960  "DRAG_BG_VEL is either the assumed bottom velocity (with \n"//&
1961  "LINEAR_DRAG) or an unresolved velocity that is \n"//&
1962  "combined with the resolved velocity to estimate the \n"//&
1963  "velocity magnitude. DRAG_BG_VEL is only used when \n"//&
1964  "BOTTOMDRAGLAW is defined.", units="m s-1", default=0.0)
1965  call get_param(param_file, mdl, "BBL_USE_EOS", cs%BBL_use_EOS, &
1966  "If true, use the equation of state in determining the \n"//&
1967  "properties of the bottom boundary layer. Otherwise use \n"//&
1968  "the layer target potential densities.", default=.false.)
1969  endif
1970  call get_param(param_file, mdl, "BBL_THICK_MIN", cs%BBL_thick_min, &
1971  "The minimum bottom boundary layer thickness that can be \n"//&
1972  "used with BOTTOMDRAGLAW. This might be \n"//&
1973  "Kv / (cdrag * drag_bg_vel) to give Kv as the minimum \n"//&
1974  "near-bottom viscosity.", units="m", default=0.0)
1975  call get_param(param_file, mdl, "HTBL_SHELF_MIN", cs%Htbl_shelf_min, &
1976  "The minimum top boundary layer thickness that can be \n"//&
1977  "used with BOTTOMDRAGLAW. This might be \n"//&
1978  "Kv / (cdrag * drag_bg_vel) to give Kv as the minimum \n"//&
1979  "near-top viscosity.", units="m", default=cs%BBL_thick_min)
1980  call get_param(param_file, mdl, "HTBL_SHELF", cs%Htbl_shelf, &
1981  "The thickness over which near-surface velocities are \n"//&
1982  "averaged for the drag law under an ice shelf. By \n"//&
1983  "default this is the same as HBBL", units="m", default=cs%Hbbl)
1984 
1985  call get_param(param_file, mdl, "KV", kv_background, &
1986  "The background kinematic viscosity in the interior. \n"//&
1987  "The molecular value, ~1e-6 m2 s-1, may be used.", &
1988  units="m2 s-1", fail_if_missing=.true.)
1989  call get_param(param_file, mdl, "KV_BBL_MIN", cs%KV_BBL_min, &
1990  "The minimum viscosities in the bottom boundary layer.", &
1991  units="m2 s-1", default=kv_background)
1992  call get_param(param_file, mdl, "KV_TBL_MIN", cs%KV_TBL_min, &
1993  "The minimum viscosities in the top boundary layer.", &
1994  units="m2 s-1", default=kv_background)
1995 
1996  if (cs%Channel_drag) then
1997  call get_param(param_file, mdl, "SMAG_LAP_CONST", smag_const1, default=-1.0)
1998 
1999  csmag_chan_dflt = 0.15
2000  if (smag_const1 >= 0.0) csmag_chan_dflt = smag_const1
2001 
2002  call get_param(param_file, mdl, "SMAG_CONST_CHANNEL", cs%c_Smag, &
2003  "The nondimensional Laplacian Smagorinsky constant used \n"//&
2004  "in calculating the channel drag if it is enabled. The \n"//&
2005  "default is to use the same value as SMAG_LAP_CONST if \n"//&
2006  "it is defined, or 0.15 if it is not. The value used is \n"//&
2007  "also 0.15 if the specified value is negative.", &
2008  units="nondim", default=csmag_chan_dflt)
2009  if (cs%c_Smag < 0.0) cs%c_Smag = 0.15
2010  endif
2011 
2012  if (cs%bottomdraglaw) then
2013  allocate(visc%bbl_thick_u(isdb:iedb,jsd:jed)) ; visc%bbl_thick_u = 0.0
2014  allocate(visc%kv_bbl_u(isdb:iedb,jsd:jed)) ; visc%kv_bbl_u = 0.0
2015  allocate(visc%bbl_thick_v(isd:ied,jsdb:jedb)) ; visc%bbl_thick_v = 0.0
2016  allocate(visc%kv_bbl_v(isd:ied,jsdb:jedb)) ; visc%kv_bbl_v = 0.0
2017  allocate(visc%ustar_bbl(isd:ied,jsd:jed)) ; visc%ustar_bbl = 0.0
2018  allocate(visc%TKE_bbl(isd:ied,jsd:jed)) ; visc%TKE_bbl = 0.0
2019 
2020  cs%id_bbl_thick_u = register_diag_field('ocean_model', 'bbl_thick_u', &
2021  diag%axesCu1, time, 'BBL thickness at u points', 'meter')
2022  cs%id_kv_bbl_u = register_diag_field('ocean_model', 'kv_bbl_u', diag%axesCu1, &
2023  time, 'BBL viscosity at u points', 'meter2 second-1')
2024  cs%id_bbl_thick_v = register_diag_field('ocean_model', 'bbl_thick_v', &
2025  diag%axesCv1, time, 'BBL thickness at v points', 'meter')
2026  cs%id_kv_bbl_v = register_diag_field('ocean_model', 'kv_bbl_v', diag%axesCv1, &
2027  time, 'BBL viscosity at v points', 'meter2 second-1')
2028  endif
2029  if (cs%Channel_drag) then
2030  allocate(visc%Ray_u(isdb:iedb,jsd:jed,nz)) ; visc%Ray_u = 0.0
2031  allocate(visc%Ray_v(isd:ied,jsdb:jedb,nz)) ; visc%Ray_v = 0.0
2032  cs%id_Ray_u = register_diag_field('ocean_model', 'Rayleigh_u', diag%axesCuL, &
2033  time, 'Rayleigh drag velocity at u points', 'meter second-1')
2034  cs%id_Ray_v = register_diag_field('ocean_model', 'Rayleigh_v', diag%axesCvL, &
2035  time, 'Rayleigh drag velocity at v points', 'meter second-1')
2036  endif
2037 
2038  if (differential_diffusion) then
2039  allocate(visc%Kd_extra_T(isd:ied,jsd:jed,nz+1)) ; visc%Kd_extra_T = 0.0
2040  allocate(visc%Kd_extra_S(isd:ied,jsd:jed,nz+1)) ; visc%Kd_extra_S = 0.0
2041  endif
2042 
2043  if (cs%dynamic_viscous_ML) then
2044  allocate(visc%nkml_visc_u(isdb:iedb,jsd:jed)) ; visc%nkml_visc_u = 0.0
2045  allocate(visc%nkml_visc_v(isd:ied,jsdb:jedb)) ; visc%nkml_visc_v = 0.0
2046  cs%id_nkml_visc_u = register_diag_field('ocean_model', 'nkml_visc_u', &
2047  diag%axesCu1, time, 'Number of layers in viscous mixed layer at u points', 'meter')
2048  cs%id_nkml_visc_v = register_diag_field('ocean_model', 'nkml_visc_v', &
2049  diag%axesCv1, time, 'Number of layers in viscous mixed layer at v points', 'meter')
2050  endif
2051 
2052  cs%Hbbl = cs%Hbbl * gv%m_to_H
2053  cs%BBL_thick_min = cs%BBL_thick_min * gv%m_to_H
2054 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:

◆ set_visc_register_restarts()

subroutine, public mom_set_visc::set_visc_register_restarts ( type(hor_index_type), intent(in)  HI,
type(verticalgrid_type), intent(in)  GV,
type(param_file_type), intent(in)  param_file,
type(vertvisc_type), intent(inout)  visc,
type(mom_restart_cs), pointer  restart_CS 
)

This subroutine is used to register any fields associated with the vertvisc_type.

Parameters
[in]hiA horizontal index type structure.
[in]gvThe ocean's vertical grid structure.
[in]param_fileA structure to parse for run-time parameters.
[in,out]viscA structure containing vertical viscosities and related fields. Allocated here.
restart_csA pointer to the restart control structure.

Definition at line 1743 of file MOM_set_viscosity.F90.

References mom_cvmix_shear::cvmix_shear_is_used(), mom_kappa_shear::kappa_shear_is_used(), and mom_io::var_desc().

Referenced by mom::initialize_mom().

1743  type(hor_index_type), intent(in) :: hi !< A horizontal index type structure.
1744  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
1745  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
1746  !! parameters.
1747  type(vertvisc_type), intent(inout) :: visc !< A structure containing vertical
1748  !! viscosities and related fields.
1749  !! Allocated here.
1750  type(mom_restart_cs), pointer :: restart_cs !< A pointer to the restart control
1751  !! structure.
1752 ! This subroutine is used to register any fields associated with the
1753 ! vertvisc_type.
1754 ! Arguments: HI - A horizontal index type structure.
1755 ! (in) GV - The ocean's vertical grid structure.
1756 ! (in) param_file - A structure indicating the open file to parse for
1757 ! model parameter values.
1758 ! (out) visc - A structure containing vertical viscosities and related
1759 ! fields. Allocated here.
1760 ! (in) restart_CS - A pointer to the restart control structure.
1761  type(vardesc) :: vd
1762  logical :: use_kappa_shear, adiabatic, usekpp, useepbl
1763  logical :: use_cvmix, mle_use_pbl_mld
1764  integer :: isd, ied, jsd, jed, nz
1765  character(len=40) :: mdl = "MOM_set_visc" ! This module's name.
1766  isd = hi%isd ; ied = hi%ied ; jsd = hi%jsd ; jed = hi%jed ; nz = gv%ke
1767 
1768  call get_param(param_file, mdl, "ADIABATIC", adiabatic, default=.false., &
1769  do_not_log=.true.)
1770  use_kappa_shear = .false. ; use_cvmix = .false. ;
1771  usekpp = .false. ; useepbl = .false.
1772  if (.not.adiabatic) then
1773  use_kappa_shear = kappa_shear_is_used(param_file)
1774  use_cvmix = cvmix_shear_is_used(param_file)
1775  call get_param(param_file, mdl, "USE_KPP", usekpp, &
1776  "If true, turns on the [CVmix] KPP scheme of Large et al., 1984,\n"// &
1777  "to calculate diffusivities and non-local transport in the OBL.", &
1778  default=.false., do_not_log=.true.)
1779  call get_param(param_file, mdl, "ENERGETICS_SFC_PBL", useepbl, &
1780  "If true, use an implied energetics planetary boundary \n"//&
1781  "layer scheme to determine the diffusivity and viscosity \n"//&
1782  "in the surface boundary layer.", default=.false., do_not_log=.true.)
1783  endif
1784 
1785  if (use_kappa_shear .or. usekpp .or. useepbl .or. use_cvmix) then
1786  allocate(visc%Kd_turb(isd:ied,jsd:jed,nz+1)) ; visc%Kd_turb(:,:,:) = 0.0
1787  allocate(visc%TKE_turb(isd:ied,jsd:jed,nz+1)) ; visc%TKE_turb(:,:,:) = 0.0
1788  allocate(visc%Kv_turb(isd:ied,jsd:jed,nz+1)) ; visc%Kv_turb(:,:,:) = 0.0
1789 
1790  vd = var_desc("Kd_turb","m2 s-1","Turbulent diffusivity at interfaces", &
1791  hor_grid='h', z_grid='i')
1792  call register_restart_field(visc%Kd_turb, vd, .false., restart_cs)
1793 
1794  vd = var_desc("TKE_turb","m2 s-2","Turbulent kinetic energy per unit mass at interfaces", &
1795  hor_grid='h', z_grid='i')
1796  call register_restart_field(visc%TKE_turb, vd, .false., restart_cs)
1797  vd = var_desc("Kv_turb","m2 s-1","Turbulent viscosity at interfaces", &
1798  hor_grid='h', z_grid='i')
1799  call register_restart_field(visc%Kv_turb, vd, .false., restart_cs)
1800  endif
1801 
1802  ! visc%MLD is used to communicate the state of the (e)PBL to the rest of the model
1803  call get_param(param_file, mdl, "MLE_USE_PBL_MLD", mle_use_pbl_mld, &
1804  default=.false., do_not_log=.true.)
1805  if (mle_use_pbl_mld) then
1806  allocate(visc%MLD(isd:ied,jsd:jed)) ; visc%MLD(:,:) = 0.0
1807  vd = var_desc("MLD","m","Instantaneous active mixing layer depth", &
1808  hor_grid='h', z_grid='1')
1809  call register_restart_field(visc%MLD, vd, .false., restart_cs)
1810  endif
1811 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_viscous_bbl()

subroutine, public mom_set_visc::set_viscous_bbl ( real, dimension(szib_(g),szj_(g),szk_(g)), intent(in)  u,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in)  v,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h,
type(thermo_var_ptrs), intent(in)  tv,
type(vertvisc_type), intent(inout)  visc,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(set_visc_cs), pointer  CS 
)

The following subroutine calculates the thickness of the bottom boundary layer and the viscosity within that layer. A drag law is used, either linearized about an assumed bottom velocity or using the actual near-bottom velocities combined with an assumed unresolved velocity. The bottom boundary layer thickness is limited by a combination of stratification and rotation, as in the paper of Killworth and Edwards, JPO 1999. It is not necessary to calculate the thickness and viscosity every time step; instead previous values may be used.

Parameters
[in,out]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]uThe zonal velocity, in m s-1.
[in]vThe meridional velocity, in m s-1.
[in]hLayer thicknesses, in H (usually m or kg m-2).
[in]tvA structure containing pointers to any available thermodynamic fields. Absent fields have NULL ptrs..
[in,out]viscA structure containing vertical viscosities and related fields.
csThe control structure returned by a previous call to vertvisc_init.

Definition at line 147 of file MOM_set_viscosity.F90.

References mom_eos::calculate_density_derivs(), mom_error_handler::mom_error(), set_u_at_v(), and set_v_at_u().

147  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
148  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
149  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
150  intent(in) :: u !< The zonal velocity, in m s-1.
151  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
152  intent(in) :: v !< The meridional velocity, in m s-1.
153  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
154  intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2).
155  type(thermo_var_ptrs), intent(in) :: tv !< A structure containing pointers to any
156  !! available thermodynamic fields. Absent fields
157  !! have NULL ptrs..
158  type(vertvisc_type), intent(inout) :: visc !< A structure containing vertical viscosities and
159  !! related fields.
160  type(set_visc_cs), pointer :: cs !< The control structure returned by a previous
161  !! call to vertvisc_init.
162 ! The following subroutine calculates the thickness of the bottom
163 ! boundary layer and the viscosity within that layer. A drag law is
164 ! used, either linearized about an assumed bottom velocity or using
165 ! the actual near-bottom velocities combined with an assumed
166 ! unresolved velocity. The bottom boundary layer thickness is
167 ! limited by a combination of stratification and rotation, as in the
168 ! paper of Killworth and Edwards, JPO 1999. It is not necessary to
169 ! calculate the thickness and viscosity every time step; instead
170 ! previous values may be used.
171 !
172 ! Arguments: u - Zonal velocity, in m s-1.
173 ! (in) v - Meridional velocity, in m s-1.
174 ! (in) h - Layer thickness, in m or kg m-2. In the comments below,
175 ! the units of h are denoted as H.
176 ! (in) tv - A structure containing pointers to any available
177 ! thermodynamic fields. Absent fields have NULL ptrs.
178 ! (out) visc - A structure containing vertical viscosities and related
179 ! fields.
180 ! (in) G - The ocean's grid structure.
181 ! (in) GV - The ocean's vertical grid structure.
182 ! (in) CS - The control structure returned by a previous call to
183 ! vertvisc_init.
184  real, dimension(SZIB_(G)) :: &
185  ustar, & ! The bottom friction velocity, in m s-1.
186  t_eos, & ! The temperature used to calculate the partial derivatives
187  ! of density with T and S, in deg C.
188  s_eos, & ! The salinity used to calculate the partial derivatives
189  ! of density with T and S, in PSU.
190  dr_dt, & ! Partial derivative of the density in the bottom boundary
191  ! layer with temperature, in units of kg m-3 K-1.
192  dr_ds, & ! Partial derivative of the density in the bottom boundary
193  ! layer with salinity, in units of kg m-3 psu-1.
194  press ! The pressure at which dR_dT and dR_dS are evaluated, in Pa.
195  real :: htot ! Sum of the layer thicknesses up to some
196  ! point, in H (i.e., m or kg m-2).
197  real :: htot_vel ! Sum of the layer thicknesses up to some
198  ! point, in H (i.e., m or kg m-2).
199 
200  real :: rhtot ! Running sum of thicknesses times the
201  ! layer potential densities in H kg m-3.
202  real, dimension(SZIB_(G),SZJ_(G)) :: &
203  d_u, & ! Bottom depth interpolated to u points, in m.
204  mask_u ! A mask that disables any contributions from u points that
205  ! are land or past open boundary conditions, nondim., 0 or 1.
206  real, dimension(SZI_(G),SZJB_(G)) :: &
207  d_v, & ! Bottom depth interpolated to v points, in m.
208  mask_v ! A mask that disables any contributions from v points that
209  ! are land or past open boundary conditions, nondim., 0 or 1.
210  real, dimension(SZIB_(G),SZK_(G)) :: &
211  h_at_vel, & ! Layer thickness at a velocity point, using an upwind-biased
212  ! second order accurate estimate based on the previous velocity
213  ! direction, in H.
214  h_vel, & ! Arithmetic mean of the layer thicknesses adjacent to a
215  ! velocity point, in H.
216  t_vel, & ! Arithmetic mean of the layer temperatures adjacent to a
217  ! velocity point, in deg C.
218  s_vel, & ! Arithmetic mean of the layer salinities adjacent to a
219  ! velocity point, in PSU.
220  rml_vel ! Arithmetic mean of the layer coordinate densities adjacent
221  ! to a velocity point, in kg m-3.
222 
223  real :: h_vel_pos ! The arithmetic mean thickness at a velocity point
224  ! plus H_neglect to avoid 0 values, in H.
225  real :: ustarsq ! 400 times the square of ustar, times
226  ! Rho0 divided by G_Earth and the conversion
227  ! from m to thickness units, in kg m-2 or kg2 m-5.
228  real :: cdrag_sqrt ! Square root of the drag coefficient, nd.
229  real :: oldfn ! The integrated energy required to
230  ! entrain up to the bottom of the layer,
231  ! divided by G_Earth, in H kg m-3.
232  real :: dfn ! The increment in oldfn for entraining
233  ! the layer, in H kg m-3.
234  real :: dh ! The increment in layer thickness from
235  ! the present layer, in H.
236  real :: bbl_thick ! The thickness of the bottom boundary layer in m.
237  real :: c2f ! C2f = 2*f at velocity points.
238 
239  real :: u_bg_sq ! The square of an assumed background
240  ! velocity, for calculating the mean
241  ! magnitude near the bottom for use in the
242  ! quadratic bottom drag, in m2.
243  real :: hwtot ! Sum of the thicknesses used to calculate
244  ! the near-bottom velocity magnitude, in H.
245  real :: hutot ! Running sum of thicknesses times the
246  ! velocity magnitudes, in H m s-1.
247  real :: thtot ! Running sum of thickness times temperature, in H C.
248  real :: shtot ! Running sum of thickness times salinity, in H psu.
249  real :: hweight ! The thickness of a layer that is within Hbbl
250  ! of the bottom, in H.
251  real :: v_at_u, u_at_v ! v at a u point or vice versa, m s-1.
252  real :: rho0x400_g ! 400*Rho0/G_Earth, in kg s2 m-4. The 400 is a
253  ! constant proposed by Killworth and Edwards, 1999.
254  real, dimension(SZI_(G),SZJ_(G),max(GV%nk_rho_varies,1)) :: &
255  rml ! The mixed layer coordinate density, in kg m-3.
256  real :: p_ref(szi_(g)) ! The pressure used to calculate the coordinate
257  ! density, in Pa (usually set to 2e7 Pa = 2000 dbar).
258 
259  ! The units H in the following are thickness units - typically m or kg m-2.
260  real :: d_vel ! The bottom depth at a velocity point, in H.
261  real :: dp, dm ! The depths at the edges of a velocity cell, in H.
262  real :: a ! a is the curvature of the bottom depth across a
263  ! cell, times the cell width squared, in H.
264  real :: a_3, a_12, c24_a ! a/3, a/12, and 24/a, in H, H, and H-1.
265  real :: slope ! The absolute value of the bottom depth slope across
266  ! a cell times the cell width, in H.
267  real :: apb_4a, ax2_3apb ! Various nondimensional ratios of a and slope.
268  real :: a2x48_apb3, iapb, ibma_2 ! Combinations of a and slope with units of H-1.
269  ! All of the following "volumes" have units of meters as they are normalized
270  ! by the full horizontal area of a velocity cell.
271  real :: vol_open ! The cell volume above which it is open, in H.
272  real :: vol_direct ! With less than Vol_direct (in H), there is a direct
273  ! solution of a cubic equation for L.
274  real :: vol_2_reg ! The cell volume above which there are two separate
275  ! open areas that must be integrated, in H.
276  real :: vol ! The volume below the interface whose normalized
277  ! width is being sought, in H.
278  real :: vol_below ! The volume below the interface below the one that
279  ! is currently under consideration, in H.
280  real :: vol_err ! The error in the volume with the latest estimate of
281  ! L, or the error for the interface below, in H.
282  real :: vol_quit ! The volume error below which to quit iterating, in H.
283  real :: vol_tol ! A volume error tolerance, in H.
284  real :: l(szk_(g)+1) ! The fraction of the full cell width that is open at
285  ! the depth of each interface, nondimensional.
286  real :: l_direct ! The value of L above volume Vol_direct, nondim.
287  real :: l_max, l_min ! Upper and lower bounds on the correct value for L.
288  real :: vol_err_max ! The volume errors for the upper and lower bounds on
289  real :: vol_err_min ! the correct value for L, in H.
290  real :: vol_0 ! A deeper volume with known width L0, in H.
291  real :: l0 ! The value of L above volume Vol_0, nondim.
292  real :: dvol ! vol - Vol_0, in H.
293  real :: dv_dl2 ! The partial derivative of volume with L squared
294  ! evaluated at L=L0, in H.
295  real :: h_neglect ! A thickness that is so small it is usually lost
296  ! in roundoff and can be neglected, in H.
297  real :: usth ! ustar converted to units of H s-1.
298  real :: root ! A temporary variable with units of H s-1.
299  real :: h_to_m, m_to_h ! Local copies of unit conversion factors.
300 
301  real :: cell_width ! The transverse width of the velocity cell, in m.
302  real :: rayleigh ! A nondimensional value that is multiplied by the
303  ! layer's velocity magnitude to give the Rayleigh
304  ! drag velocity.
305  real :: gam ! The ratio of the change in the open interface width
306  ! to the open interface width atop a cell, nondim.
307  real :: bbl_frac ! The fraction of a layer's drag that goes into the
308  ! viscous bottom boundary layer, nondim.
309  real :: bbl_visc_frac ! The fraction of all the drag that is expressed as
310  ! a viscous bottom boundary layer, nondim.
311  real, parameter :: c1_3 = 1.0/3.0, c1_6 = 1.0/6.0, c1_12 = 1.0/12.0
312  real :: c2pi_3 ! An irrational constant, 2/3 pi.
313  real :: tmp ! A temporary variable.
314  real :: tmp_val_m1_to_p1
315  logical :: use_bbl_eos, do_i(szib_(g))
316  integer :: i, j, k, is, ie, js, je, isq, ieq, jsq, jeq, nz, m, n, k2, nkmb, nkml
317  integer :: itt, maxitt=20
318  type(ocean_obc_type), pointer :: obc => null()
319 
320  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
321  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
322  nkmb = gv%nk_rho_varies ; nkml = gv%nkml
323  h_neglect = gv%H_subroundoff
324  rho0x400_g = 400.0*(gv%Rho0/gv%g_Earth)*gv%m_to_H
325  vol_quit = 0.9*gv%Angstrom + h_neglect
326  h_to_m = gv%H_to_m ; m_to_h = gv%m_to_H
327  c2pi_3 = 8.0*atan(1.0)/3.0
328 
329  if (.not.associated(cs)) call mom_error(fatal,"MOM_vert_friction(BBL): "//&
330  "Module must be initialized before it is used.")
331  if (.not.cs%bottomdraglaw) return
332 
333  use_bbl_eos = associated(tv%eqn_of_state) .and. cs%BBL_use_EOS
334  obc => cs%OBC
335 
336  u_bg_sq = cs%drag_bg_vel * cs%drag_bg_vel
337  cdrag_sqrt=sqrt(cs%cdrag)
338  k2 = max(nkmb+1, 2)
339 
340 ! With a linear drag law, the friction velocity is already known.
341 ! if (CS%linear_drag) ustar(:) = cdrag_sqrt*CS%drag_bg_vel
342 
343  if ((nkml>0) .and. .not.use_bbl_eos) then
344  do i=g%IscB,g%IecB+1 ; p_ref(i) = tv%P_ref ; enddo
345  !$OMP parallel do default(shared)
346  do j=jsq,jeq+1 ; do k=1,nkmb
347  call calculate_density(tv%T(:,j,k), tv%S(:,j,k), p_ref, &
348  rml(:,j,k), isq, ieq-isq+2, tv%eqn_of_state)
349  enddo ; enddo
350  endif
351 
352  !$OMP parallel do default(shared)
353  do j=js-1,je ; do i=is-1,ie+1
354  d_v(i,j) = 0.5*(g%bathyT(i,j) + g%bathyT(i,j+1))
355  mask_v(i,j) = g%mask2dCv(i,j)
356  enddo ; enddo
357  !$OMP parallel do default(shared)
358  do j=js-1,je+1 ; do i=is-1,ie
359  d_u(i,j) = 0.5*(g%bathyT(i,j) + g%bathyT(i+1,j))
360  mask_u(i,j) = g%mask2dCu(i,j)
361  enddo ; enddo
362 
363  if (associated(obc)) then ; do n=1,obc%number_of_segments
364  if (.not. obc%segment(n)%on_pe) cycle
365  ! Use a one-sided projection of bottom depths at OBC points.
366  i = obc%segment(n)%HI%IsdB ; j = obc%segment(n)%HI%JsdB
367  if (obc%segment(n)%is_N_or_S .and. (j >= js-1) .and. (j <= je)) then
368  do i = max(is-1,obc%segment(n)%HI%isd), min(ie+1,obc%segment(n)%HI%ied)
369  if (obc%segment(n)%direction == obc_direction_n) d_v(i,j) = g%bathyT(i,j)
370  if (obc%segment(n)%direction == obc_direction_s) d_v(i,j) = g%bathyT(i,j+1)
371  enddo
372  elseif (obc%segment(n)%is_E_or_W .and. (i >= is-1) .and. (i <= ie)) then
373  do j = max(js-1,obc%segment(n)%HI%jsd), min(je+1,obc%segment(n)%HI%jed)
374  if (obc%segment(n)%direction == obc_direction_e) d_u(i,j) = g%bathyT(i,j)
375  if (obc%segment(n)%direction == obc_direction_w) d_u(i,j) = g%bathyT(i+1,j)
376  enddo
377  endif
378  enddo ; endif
379  if (associated(obc)) then ; do n=1,obc%number_of_segments
380  ! Now project bottom depths across cell-corner points in the OBCs. The two
381  ! projections have to occur in sequence and can not be combined easily.
382  if (.not. obc%segment(n)%on_pe) cycle
383  ! Use a one-sided projection of bottom depths at OBC points.
384  i = obc%segment(n)%HI%IsdB ; j = obc%segment(n)%HI%JsdB
385  if (obc%segment(n)%is_N_or_S .and. (j >= js-1) .and. (j <= je)) then
386  do i = max(is-1,obc%segment(n)%HI%IsdB), min(ie,obc%segment(n)%HI%IedB)
387  if (obc%segment(n)%direction == obc_direction_n) then
388  d_u(i,j+1) = d_u(i,j) ; mask_u(i,j+1) = 0.0
389  elseif (obc%segment(n)%direction == obc_direction_s) then
390  d_u(i,j) = d_u(i,j+1) ; mask_u(i,j) = 0.0
391  endif
392  enddo
393  elseif (obc%segment(n)%is_E_or_W .and. (i >= is-1) .and. (i <= ie)) then
394  do j = max(js-1,obc%segment(n)%HI%JsdB), min(je,obc%segment(n)%HI%JedB)
395  if (obc%segment(n)%direction == obc_direction_e) then
396  d_v(i+1,j) = d_v(i,j) ; mask_v(i+1,j) = 0.0
397  elseif (obc%segment(n)%direction == obc_direction_w) then
398  d_v(i,j) = d_v(i+1,j) ; mask_v(i,j) = 0.0
399  endif
400  enddo
401  endif
402  enddo ; endif
403 
404  if (.not.use_bbl_eos) rml_vel(:,:) = 0.0
405 
406 !$OMP parallel do default(none) shared(u, v, h, tv, visc, G, GV, CS, Rml, is, ie, js, je, &
407 !$OMP nz, Isq, Ieq, Jsq, Jeq, nkmb, h_neglect, Rho0x400_G,&
408 !$OMP C2pi_3, U_bg_sq, cdrag_sqrt,K2,use_BBL_EOS,OBC, &
409 !$OMP maxitt,nkml,m_to_H,H_to_m,Vol_quit,D_u,D_v,mask_u,mask_v) &
410 !$OMP private(do_i,h_at_vel,htot_vel,hwtot,hutot,Thtot,Shtot, &
411 !$OMP hweight,v_at_u,u_at_v,ustar,T_EOS,S_EOS,press, &
412 !$OMP dR_dT, dR_dS,ustarsq,htot,T_vel,S_vel,Rml_vel, &
413 !$OMP oldfn,Dfn,Dh,Rhtot,C2f,ustH,root,bbl_thick, &
414 !$OMP D_vel,tmp,Dp,Dm,a_3,a,a_12,slope,Vol_open,Vol_2_reg,&
415 !$OMP C24_a,apb_4a,Iapb,a2x48_apb3,ax2_3apb,Vol_direct, &
416 !$OMP L_direct,Ibma_2,L,vol,vol_below,Vol_err,h_vel_pos, &
417 !$OMP BBL_visc_frac,h_vel,L0,Vol_0,dV_dL2,dVol,L_max, &
418 !$OMP L_min,Vol_err_min,Vol_err_max,BBL_frac,Cell_width, &
419 !$OMP gam,Rayleigh, Vol_tol, tmp_val_m1_to_p1)
420  do j=g%JscB,g%JecB ; do m=1,2
421 
422  if (m==1) then
423  if (j<g%Jsc) cycle
424  is = g%IscB ; ie = g%IecB
425  do i=is,ie
426  do_i(i) = .false.
427  if (g%mask2dCu(i,j) > 0) do_i(i) = .true.
428  enddo
429  else
430  is = g%isc ; ie = g%iec
431  do i=is,ie
432  do_i(i) = .false.
433  if (g%mask2dCv(i,j) > 0) do_i(i) = .true.
434  enddo
435  endif
436 
437  if (m==1) then
438  do k=1,nz ; do i=is,ie
439  if (do_i(i)) then
440  if (u(i,j,k) *(h(i+1,j,k) - h(i,j,k)) >= 0) then
441  h_at_vel(i,k) = 2.0*h(i,j,k)*h(i+1,j,k) / &
442  (h(i,j,k) + h(i+1,j,k) + h_neglect)
443  else
444  h_at_vel(i,k) = 0.5 * (h(i,j,k) + h(i+1,j,k))
445  endif
446  endif
447  h_vel(i,k) = 0.5 * (h(i,j,k) + h(i+1,j,k))
448  enddo ; enddo
449  if (use_bbl_eos) then ; do k=1,nz ; do i=is,ie
450  ! Perhaps these should be thickness weighted.
451  t_vel(i,k) = 0.5 * (tv%T(i,j,k) + tv%T(i+1,j,k))
452  s_vel(i,k) = 0.5 * (tv%S(i,j,k) + tv%S(i+1,j,k))
453  enddo ; enddo ; else ; do k=1,nkmb ; do i=is,ie
454  rml_vel(i,k) = 0.5 * (rml(i,j,k) + rml(i+1,j,k))
455  enddo ; enddo ; endif
456  else
457  do k=1,nz ; do i=is,ie
458  if (do_i(i)) then
459  if (v(i,j,k) * (h(i,j+1,k) - h(i,j,k)) >= 0) then
460  h_at_vel(i,k) = 2.0*h(i,j,k)*h(i,j+1,k) / &
461  (h(i,j,k) + h(i,j+1,k) + h_neglect)
462  else
463  h_at_vel(i,k) = 0.5 * (h(i,j,k) + h(i,j+1,k))
464  endif
465  endif
466  h_vel(i,k) = 0.5 * (h(i,j,k) + h(i,j+1,k))
467  enddo ; enddo
468  if (use_bbl_eos) then ; do k=1,nz ; do i=is,ie
469  t_vel(i,k) = 0.5 * (tv%T(i,j,k) + tv%T(i,j+1,k))
470  s_vel(i,k) = 0.5 * (tv%S(i,j,k) + tv%S(i,j+1,k))
471  enddo ; enddo ; else ; do k=1,nkmb ; do i=is,ie
472  rml_vel(i,k) = 0.5 * (rml(i,j,k) + rml(i,j+1,k))
473  enddo ; enddo ; endif
474  endif
475 
476  if (associated(obc)) then ; if (obc%number_of_segments > 0) then
477  ! Apply a zero gradient projection of thickness across OBC points.
478  if (m==1) then
479  do i=is,ie ; if (do_i(i) .and. (obc%segnum_u(i,j) /= obc_none)) then
480  if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_e) then
481  do k=1,nz
482  h_at_vel(i,k) = h(i,j,k) ; h_vel(i,k) = h(i,j,k)
483  enddo
484  if (use_bbl_eos) then
485  do k=1,nz
486  t_vel(i,k) = tv%T(i,j,k) ; s_vel(i,k) = tv%S(i,j,k)
487  enddo
488  else
489  do k=1,nkmb
490  rml_vel(i,k) = rml(i,j,k)
491  enddo
492  endif
493  elseif (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_w) then
494  do k=1,nz
495  h_at_vel(i,k) = h(i+1,j,k) ; h_vel(i,k) = h(i+1,j,k)
496  enddo
497  if (use_bbl_eos) then
498  do k=1,nz
499  t_vel(i,k) = tv%T(i+1,j,k) ; s_vel(i,k) = tv%S(i+1,j,k)
500  enddo
501  else
502  do k=1,nkmb
503  rml_vel(i,k) = rml(i+1,j,k)
504  enddo
505  endif
506  endif
507  endif ; enddo
508  else
509  do i=is,ie ; if (do_i(i) .and. (obc%segnum_v(i,j) /= obc_none)) then
510  if (obc%segment(obc%segnum_v(i,j))%direction == obc_direction_n) then
511  do k=1,nz
512  h_at_vel(i,k) = h(i,j,k) ; h_vel(i,k) = h(i,j,k)
513  enddo
514  if (use_bbl_eos) then
515  do k=1,nz
516  t_vel(i,k) = tv%T(i,j,k) ; s_vel(i,k) = tv%S(i,j,k)
517  enddo
518  else
519  do k=1,nkmb
520  rml_vel(i,k) = rml(i,j,k)
521  enddo
522  endif
523  elseif (obc%segment(obc%segnum_v(i,j))%direction == obc_direction_s) then
524  do k=1,nz
525  h_at_vel(i,k) = h(i,j+1,k) ; h_vel(i,k) = h(i,j+1,k)
526  enddo
527  if (use_bbl_eos) then
528  do k=1,nz
529  t_vel(i,k) = tv%T(i,j+1,k) ; s_vel(i,k) = tv%S(i,j+1,k)
530  enddo
531  else
532  do k=1,nkmb
533  rml_vel(i,k) = rml(i,j+1,k)
534  enddo
535  endif
536  endif
537  endif ; enddo
538  endif
539  endif ; endif
540 
541  if (use_bbl_eos .or. .not.cs%linear_drag) then
542  do i=is,ie ; if (do_i(i)) then
543 ! This block of code calculates the mean velocity magnitude over
544 ! the bottommost CS%Hbbl of the water column for determining
545 ! the quadratic bottom drag.
546  htot_vel = 0.0 ; hwtot = 0.0 ; hutot = 0.0
547  thtot = 0.0 ; shtot = 0.0
548  do k=nz,1,-1
549 
550  if (htot_vel>=cs%Hbbl) exit ! terminate the k loop
551 
552  hweight = min(cs%Hbbl - htot_vel, h_at_vel(i,k))
553  if (hweight < 1.5*gv%Angstrom + h_neglect) cycle
554 
555  htot_vel = htot_vel + h_at_vel(i,k)
556  hwtot = hwtot + hweight
557 
558  if ((.not.cs%linear_drag) .and. (hweight >= 0.0)) then ; if (m==1) then
559  v_at_u = set_v_at_u(v, h, g, i, j, k, mask_v)
560  hutot = hutot + hweight * sqrt(u(i,j,k)*u(i,j,k) + &
561  v_at_u*v_at_u + u_bg_sq)
562  else
563  u_at_v = set_u_at_v(u, h, g, i, j, k, mask_u)
564  hutot = hutot + hweight * sqrt(v(i,j,k)*v(i,j,k) + &
565  u_at_v*u_at_v + u_bg_sq)
566  endif ; endif
567 
568  if (use_bbl_eos .and. (hweight >= 0.0)) then
569  thtot = thtot + hweight * t_vel(i,k)
570  shtot = shtot + hweight * s_vel(i,k)
571  endif
572  enddo ! end of k loop
573 
574  if (.not.cs%linear_drag .and. (hwtot > 0.0)) then
575  ustar(i) = cdrag_sqrt*hutot/hwtot
576  else
577  ustar(i) = cdrag_sqrt*cs%drag_bg_vel
578  endif
579 
580  if (use_bbl_eos) then ; if (hwtot > 0.0) then
581  t_eos(i) = thtot/hwtot ; s_eos(i) = shtot/hwtot
582  else
583  t_eos(i) = 0.0 ; s_eos(i) = 0.0
584  endif ; endif
585  endif ; enddo
586  else
587  do i=is,ie ; ustar(i) = cdrag_sqrt*cs%drag_bg_vel ; enddo
588  endif ! Not linear_drag
589 
590  if (use_bbl_eos) then
591  do i=is,ie
592  press(i) = 0.0 ! or = fluxes%p_surf(i,j)
593  if (.not.do_i(i)) then ; t_eos(i) = 0.0 ; s_eos(i) = 0.0 ; endif
594  enddo
595  do k=1,nz ; do i=is,ie
596  press(i) = press(i) + gv%H_to_Pa * h_vel(i,k)
597  enddo ; enddo
598  call calculate_density_derivs(t_eos, s_eos, press, dr_dt, dr_ds, &
599  is-g%IsdB+1, ie-is+1, tv%eqn_of_state)
600  endif
601 
602  do i=is,ie ; if (do_i(i)) then
603 ! The 400.0 in this expression is the square of a constant proposed
604 ! by Killworth and Edwards, 1999, in equation (2.20).
605  ustarsq = rho0x400_g * ustar(i)**2
606  htot = 0.0
607 
608 ! This block of code calculates the thickness of a stratification
609 ! limited bottom boundary layer, using the prescription from
610 ! Killworth and Edwards, 1999, as described in Stephens and Hallberg
611 ! 2000 (unpublished and lost manuscript).
612  if (use_bbl_eos) then
613  thtot = 0.0 ; shtot = 0.0 ; oldfn = 0.0
614  do k=nz,2,-1
615  if (h_at_vel(i,k) <= 0.0) cycle
616 
617  oldfn = dr_dt(i)*(thtot - t_vel(i,k)*htot) + &
618  dr_ds(i)*(shtot - s_vel(i,k)*htot)
619  if (oldfn >= ustarsq) exit
620 
621  dfn = (dr_dt(i)*(t_vel(i,k) - t_vel(i,k-1)) + &
622  dr_ds(i)*(s_vel(i,k) - s_vel(i,k-1))) * &
623  (h_at_vel(i,k) + htot)
624 
625  if ((oldfn + dfn) <= ustarsq) then
626  dh = h_at_vel(i,k)
627  else
628  dh = h_at_vel(i,k) * sqrt((ustarsq-oldfn)/dfn)
629  endif
630 
631  htot = htot + dh
632  thtot = thtot + t_vel(i,k)*dh ; shtot = shtot + s_vel(i,k)*dh
633  enddo
634  if ((oldfn < ustarsq) .and. h_at_vel(i,1) > 0.0) then
635  ! Layer 1 might be part of the BBL.
636  if (dr_dt(i) * (thtot - t_vel(i,1)*htot) + &
637  dr_ds(i) * (shtot - s_vel(i,1)*htot) < ustarsq) &
638  htot = htot + h_at_vel(i,1)
639  endif ! Examination of layer 1.
640  else ! Use Rlay and/or the coordinate density as density variables.
641  rhtot = 0.0
642  do k=nz,k2,-1
643  oldfn = rhtot - gv%Rlay(k)*htot
644  dfn = (gv%Rlay(k) - gv%Rlay(k-1))*(h_at_vel(i,k)+htot)
645 
646  if (oldfn >= ustarsq) then
647  cycle
648  else if ((oldfn + dfn) <= ustarsq) then
649  dh = h_at_vel(i,k)
650  else
651  dh = h_at_vel(i,k) * sqrt((ustarsq-oldfn)/dfn)
652  endif
653 
654  htot = htot + dh
655  rhtot = rhtot + gv%Rlay(k)*dh
656  enddo
657  if (nkml>0) then
658  do k=nkmb,2,-1
659  oldfn = rhtot - rml_vel(i,k)*htot
660  dfn = (rml_vel(i,k) - rml_vel(i,k-1)) * (h_at_vel(i,k)+htot)
661 
662  if (oldfn >= ustarsq) then
663  cycle
664  else if ((oldfn + dfn) <= ustarsq) then
665  dh = h_at_vel(i,k)
666  else
667  dh = h_at_vel(i,k) * sqrt((ustarsq-oldfn)/dfn)
668  endif
669 
670  htot = htot + dh
671  rhtot = rhtot + rml_vel(i,k)*dh
672  enddo
673  if (rhtot - rml_vel(i,1)*htot < ustarsq) htot = htot + h_at_vel(i,1)
674  else
675  if (rhtot - gv%Rlay(1)*htot < ustarsq) htot = htot + h_at_vel(i,1)
676  endif
677  endif ! use_BBL_EOS
678 
679 ! The Coriolis limit is 0.5*ustar/f. The buoyancy limit here is htot.
680 ! The bottom boundary layer thickness is found by solving the same
681 ! equation as in Killworth and Edwards: (h/h_f)^2 + h/h_N = 1.
682 
683  if (m==1) then ; c2f = (g%CoriolisBu(i,j-1)+g%CoriolisBu(i,j))
684  else ; c2f = (g%CoriolisBu(i-1,j)+g%CoriolisBu(i,j)) ; endif
685 
686  if (cs%cdrag * u_bg_sq <= 0.0) then
687  ! This avoids NaNs and overflows, and could be used in all cases,
688  ! but is not bitwise identical to the current code.
689  usth = ustar(i)*m_to_h ; root = sqrt(0.25*usth**2 + (htot*c2f)**2)
690  if (htot*usth <= (cs%BBL_thick_min+h_neglect) * (0.5*usth + root)) then
691  bbl_thick = cs%BBL_thick_min
692  else
693  bbl_thick = (htot * usth) / (0.5*usth + root)
694  endif
695  else
696  bbl_thick = htot / (0.5 + sqrt(0.25 + htot*htot*c2f*c2f/ &
697  ((ustar(i)*ustar(i)) * (m_to_h**2) )))
698 
699  if (bbl_thick < cs%BBL_thick_min) bbl_thick = cs%BBL_thick_min
700  endif
701 ! If there is Richardson number dependent mixing, that determines
702 ! the vertical extent of the bottom boundary layer, and there is no
703 ! need to set that scale here. In fact, viscously reducing the
704 ! shears over an excessively large region reduces the efficacy of
705 ! the Richardson number dependent mixing.
706  if ((bbl_thick > 0.5*cs%Hbbl) .and. (cs%RiNo_mix)) bbl_thick = 0.5*cs%Hbbl
707 
708  if (cs%Channel_drag) then
709  ! The drag within the bottommost bbl_thick is applied as a part of
710  ! an enhanced bottom viscosity, while above this the drag is applied
711  ! directly to the layers in question as a Rayleigh drag term.
712  if (m==1) then
713  d_vel = d_u(i,j)
714  tmp = g%mask2dCu(i,j+1) * d_u(i,j+1)
715  dp = 2.0 * d_vel * tmp / (d_vel + tmp)
716  tmp = g%mask2dCu(i,j-1) * d_u(i,j-1)
717  dm = 2.0 * d_vel * tmp / (d_vel + tmp)
718  else
719  d_vel = d_v(i,j)
720  tmp = g%mask2dCv(i+1,j) * d_v(i+1,j)
721  dp = 2.0 * d_vel * tmp / (d_vel + tmp)
722  tmp = g%mask2dCv(i-1,j) * d_v(i-1,j)
723  dm = 2.0 * d_vel * tmp / (d_vel + tmp)
724  endif
725  if (dm > dp) then ; tmp = dp ; dp = dm ; dm = tmp ; endif
726 
727  ! Convert the D's to the units of thickness.
728  dp = m_to_h*dp ; dm = m_to_h*dm ; d_vel = m_to_h*d_vel
729 
730  a_3 = (dp + dm - 2.0*d_vel) ; a = 3.0*a_3 ; a_12 = 0.25*a_3
731  slope = dp - dm
732  ! If the curvature is small enough, there is no reason not to assume
733  ! a uniformly sloping or flat bottom.
734  if (abs(a) < 1e-2*(slope + cs%BBL_thick_min)) a = 0.0
735  ! Each cell extends from x=-1/2 to 1/2, and has a topography
736  ! given by D(x) = a*x^2 + b*x + D - a/12.
737 
738  ! Calculate the volume above which the entire cell is open and the
739  ! other volumes at which the equation that is solved for L changes.
740  if (a > 0.0) then
741  if (slope >= a) then
742  vol_open = d_vel - dm ; vol_2_reg = vol_open
743  else
744  tmp = slope/a
745  vol_open = 0.25*slope*tmp + c1_12*a
746  vol_2_reg = 0.5*tmp**2 * (a - c1_3*slope)
747  endif
748  ! Define some combinations of a & b for later use.
749  c24_a = 24.0/a ; iapb = 1.0/(a+slope)
750  apb_4a = (slope+a)/(4.0*a) ; a2x48_apb3 = (48.0*(a*a))*(iapb**3)
751  ax2_3apb = 2.0*c1_3*a*iapb
752  elseif (a == 0.0) then
753  vol_open = 0.5*slope
754  if (slope > 0) iapb = 1.0/slope
755  else ! a < 0.0
756  vol_open = d_vel - dm
757  if (slope >= -a) then
758  iapb = 1.0e30 ; if (slope+a /= 0.0) iapb = 1.0/(a+slope)
759  vol_direct = 0.0 ; l_direct = 0.0 ; c24_a = 0.0
760  else
761  c24_a = 24.0/a ; iapb = 1.0/(a+slope)
762  l_direct = 1.0 + slope/a ! L_direct < 1 because a < 0
763  vol_direct = -c1_6*a*l_direct**3
764  endif
765  ibma_2 = 2.0 / (slope - a)
766  endif
767 
768  l(nz+1) = 0.0 ; vol = 0.0 ; vol_err = 0.0 ; bbl_visc_frac = 0.0
769  ! Determine the normalized open length at each interface.
770  do k=nz,1,-1
771  vol_below = vol
772 
773  vol = vol + h_vel(i,k)
774  h_vel_pos = h_vel(i,k) + h_neglect
775 
776  if (vol >= vol_open) then ; l(k) = 1.0
777  elseif (a == 0) then ! The bottom has no curvature.
778  l(k) = sqrt(2.0*vol*iapb)
779  elseif (a > 0) then
780  ! There may be a minimum depth, and there are
781  ! analytic expressions for L for all cases.
782  if (vol < vol_2_reg) then
783  ! In this case, there is a contiguous open region and
784  ! vol = 0.5*L^2*(slope + a/3*(3-4L)).
785  if (a2x48_apb3*vol < 1e-8) then ! Could be 1e-7?
786  ! There is a very good approximation here for massless layers.
787  l0 = sqrt(2.0*vol*iapb) ; l(k) = l0*(1.0 + ax2_3apb*l0)
788  else
789  l(k) = apb_4a * (1.0 - &
790  2.0 * cos(c1_3*acos(a2x48_apb3*vol - 1.0) - c2pi_3))
791  endif
792  ! To check the answers.
793  ! Vol_err = 0.5*(L(K)*L(K))*(slope + a_3*(3.0-4.0*L(K))) - vol
794  else ! There are two separate open regions.
795  ! vol = slope^2/4a + a/12 - (a/12)*(1-L)^2*(1+2L)
796  ! At the deepest volume, L = slope/a, at the top L = 1.
797  !L(K) = 0.5 - cos(C1_3*acos(1.0 - C24_a*(Vol_open - vol)) - C2pi_3)
798  tmp_val_m1_to_p1 = 1.0 - c24_a*(vol_open - vol)
799  tmp_val_m1_to_p1 = max(-1., min(1., tmp_val_m1_to_p1))
800  l(k) = 0.5 - cos(c1_3*acos(tmp_val_m1_to_p1) - c2pi_3)
801  ! To check the answers.
802  ! Vol_err = Vol_open - a_12*(1.0+2.0*L(K)) * (1.0-L(K))**2 - vol
803  endif
804  else ! a < 0.
805  if (vol <= vol_direct) then
806  ! Both edges of the cell are bounded by walls.
807  l(k) = (-0.25*c24_a*vol)**c1_3
808  else
809  ! x_R is at 1/2 but x_L is in the interior & L is found by solving
810  ! vol = 0.5*L^2*(slope + a/3*(3-4L))
811 
812  ! Vol_err = 0.5*(L(K+1)*L(K+1))*(slope + a_3*(3.0-4.0*L(K+1))) - vol_below
813  ! Change to ...
814  ! if (min(Vol_below + Vol_err, vol) <= Vol_direct) then ?
815  if (vol_below + vol_err <= vol_direct) then
816  l0 = l_direct ; vol_0 = vol_direct
817  else
818  l0 = l(k+1) ; vol_0 = vol_below + vol_err
819  ! Change to Vol_0 = min(Vol_below + Vol_err, vol) ?
820  endif
821 
822  ! Try a relatively simple solution that usually works well
823  ! for massless layers.
824  dv_dl2 = 0.5*(slope+a) - a*l0 ; dvol = (vol-vol_0)
825  ! dV_dL2 = 0.5*(slope+a) - a*L0 ; dVol = max(vol-Vol_0, 0.0)
826 
827  !### The following code is more robust when GV%Angstrom=0, but it
828  !### changes answers.
829  ! Vol_tol = max(0.5*GV%Angstrom + GV%H_subroundoff, 1e-14*vol)
830  ! Vol_quit = max(0.9*GV%Angstrom + GV%H_subroundoff, 1e-14*vol)
831 
832  ! if (dVol <= 0.0) then
833  ! L(K) = L0
834  ! Vol_err = 0.5*(L(K)*L(K))*(slope + a_3*(3.0-4.0*L(K))) - vol
835  ! elseif (a*a*dVol**3 < Vol_tol*dV_dL2**2 * &
836  ! (dV_dL2*Vol_tol - 2.0*a*L0*dVol)) then
837  if (a*a*dvol**3 < gv%Angstrom*dv_dl2**2 * &
838  (0.25*dv_dl2*gv%Angstrom - a*l0*dvol)) then
839  ! One iteration of Newton's method should give an estimate
840  ! that is accurate to within Vol_tol.
841  l(k) = sqrt(l0*l0 + dvol / dv_dl2)
842  vol_err = 0.5*(l(k)*l(k))*(slope + a_3*(3.0-4.0*l(k))) - vol
843  else
844  if (dv_dl2*(1.0-l0*l0) < dvol + &
845  dv_dl2 * (vol_open - vol)*ibma_2) then
846  l_max = sqrt(1.0 - (vol_open - vol)*ibma_2)
847  else
848  l_max = sqrt(l0*l0 + dvol / dv_dl2)
849  endif
850  l_min = sqrt(l0*l0 + dvol / (0.5*(slope+a) - a*l_max))
851 
852  vol_err_min = 0.5*(l_min**2)*(slope + a_3*(3.0-4.0*l_min)) - vol
853  vol_err_max = 0.5*(l_max**2)*(slope + a_3*(3.0-4.0*l_max)) - vol
854  ! if ((abs(Vol_err_min) <= Vol_quit) .or. (Vol_err_min >= Vol_err_max)) then
855  if (abs(vol_err_min) <= vol_quit) then
856  l(k) = l_min ; vol_err = vol_err_min
857  else
858  l(k) = sqrt((l_min**2*vol_err_max - l_max**2*vol_err_min) / &
859  (vol_err_max - vol_err_min))
860  do itt=1,maxitt
861  vol_err = 0.5*(l(k)*l(k))*(slope + a_3*(3.0-4.0*l(k))) - vol
862  if (abs(vol_err) <= vol_quit) exit
863  ! Take a Newton's method iteration. This equation has proven
864  ! robust enough not to need bracketing.
865  l(k) = l(k) - vol_err / (l(k)* (slope + a - 2.0*a*l(k)))
866  ! This would be a Newton's method iteration for L^2:
867  ! L(K) = sqrt(L(K)*L(K) - Vol_err / (0.5*(slope+a) - a*L(K)))
868  enddo
869  endif ! end of iterative solver
870  endif ! end of 1-boundary alternatives.
871  endif ! end of a<0 cases.
872  endif
873 
874  ! Determine the drag contributing to the bottom boundary layer
875  ! and the Raleigh drag that acting on each layer.
876  if (l(k) > l(k+1)) then
877  if (vol_below < bbl_thick) then
878  bbl_frac = (1.0-vol_below/bbl_thick)**2
879  bbl_visc_frac = bbl_visc_frac + bbl_frac*(l(k) - l(k+1))
880  else
881  bbl_frac = 0.0
882  endif
883 
884  if (m==1) then ; cell_width = g%dy_Cu(i,j)
885  else ; cell_width = g%dx_Cv(i,j) ; endif
886  gam = 1.0 - l(k+1)/l(k)
887  rayleigh = cs%cdrag * (l(k)-l(k+1)) * (1.0-bbl_frac) * &
888  (12.0*cs%c_Smag*h_vel_pos) / (12.0*cs%c_Smag*h_vel_pos + m_to_h * &
889  cs%cdrag * gam*(1.0-gam)*(1.0-1.5*gam) * l(k)**2 * cell_width)
890  else ! This layer feels no drag.
891  rayleigh = 0.0
892  endif
893 
894  if (m==1) then
895  if (rayleigh > 0.0) then
896  v_at_u = set_v_at_u(v, h, g, i, j, k, mask_v)
897  visc%Ray_u(i,j,k) = rayleigh*sqrt(u(i,j,k)*u(i,j,k) + &
898  v_at_u*v_at_u + u_bg_sq)
899  else ; visc%Ray_u(i,j,k) = 0.0 ; endif
900  else
901  if (rayleigh > 0.0) then
902  u_at_v = set_u_at_v(u, h, g, i, j, k, mask_u)
903  visc%Ray_v(i,j,k) = rayleigh*sqrt(v(i,j,k)*v(i,j,k) + &
904  u_at_v*u_at_v + u_bg_sq)
905  else ; visc%Ray_v(i,j,k) = 0.0 ; endif
906  endif
907 
908  enddo ! k loop to determine L(K).
909 
910  bbl_thick = bbl_thick * h_to_m
911  if (m==1) then
912  visc%kv_bbl_u(i,j) = max(cs%KV_BBL_min, &
913  cdrag_sqrt*ustar(i)*bbl_thick*bbl_visc_frac)
914  visc%bbl_thick_u(i,j) = bbl_thick
915  else
916  visc%kv_bbl_v(i,j) = max(cs%KV_BBL_min, &
917  cdrag_sqrt*ustar(i)*bbl_thick*bbl_visc_frac)
918  visc%bbl_thick_v(i,j) = bbl_thick
919  endif
920 
921  else ! Not Channel_drag.
922 ! Here the near-bottom viscosity is set to a value which will give
923 ! the correct stress when the shear occurs over bbl_thick.
924  bbl_thick = bbl_thick * h_to_m
925  if (m==1) then
926  visc%kv_bbl_u(i,j) = max(cs%KV_BBL_min, cdrag_sqrt*ustar(i)*bbl_thick)
927  visc%bbl_thick_u(i,j) = bbl_thick
928  else
929  visc%kv_bbl_v(i,j) = max(cs%KV_BBL_min, cdrag_sqrt*ustar(i)*bbl_thick)
930  visc%bbl_thick_v(i,j) = bbl_thick
931  endif
932  endif
933  endif ; enddo ! end of i loop
934  enddo ; enddo ! end of m & j loops
935 
936 ! Offer diagnostics for averaging
937  if (cs%id_bbl_thick_u > 0) &
938  call post_data(cs%id_bbl_thick_u, visc%bbl_thick_u, cs%diag)
939  if (cs%id_kv_bbl_u > 0) &
940  call post_data(cs%id_kv_bbl_u, visc%kv_bbl_u, cs%diag)
941  if (cs%id_bbl_thick_v > 0) &
942  call post_data(cs%id_bbl_thick_v, visc%bbl_thick_v, cs%diag)
943  if (cs%id_kv_bbl_v > 0) &
944  call post_data(cs%id_kv_bbl_v, visc%kv_bbl_v, cs%diag)
945  if (cs%id_Ray_u > 0) &
946  call post_data(cs%id_Ray_u, visc%Ray_u, cs%diag)
947  if (cs%id_Ray_v > 0) &
948  call post_data(cs%id_Ray_v, visc%Ray_v, cs%diag)
949 
950  if (cs%debug) then
951  if (associated(visc%Ray_u) .and. associated(visc%Ray_v)) &
952  call uvchksum("Ray [uv]", visc%Ray_u, visc%Ray_v, g%HI,haloshift=0)
953  if (associated(visc%kv_bbl_u) .and. associated(visc%kv_bbl_v)) &
954  call uvchksum("kv_bbl_[uv]", visc%kv_bbl_u, visc%kv_bbl_v, g%HI,haloshift=0)
955  if (associated(visc%bbl_thick_u) .and. associated(visc%bbl_thick_v)) &
956  call uvchksum("bbl_thick_[uv]", visc%bbl_thick_u, &
957  visc%bbl_thick_v, g%HI,haloshift=0)
958  endif
959 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:

◆ set_viscous_ml()

subroutine, public mom_set_visc::set_viscous_ml ( real, dimension(szib_(g),szj_(g),szk_(g)), intent(in)  u,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in)  v,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h,
type(thermo_var_ptrs), intent(in)  tv,
type(forcing), intent(in)  fluxes,
type(vertvisc_type), intent(inout)  visc,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(set_visc_cs), pointer  CS 
)

The following subroutine calculates the thickness of the surface boundary layer for applying an elevated viscosity. A bulk Richardson criterion or the thickness of the topmost NKML layers (with a bulk mixed layer) are currently used. The thicknesses are given in terms of fractional layers, so that this thickness will move as the thickness of the topmost layers change.

Parameters
[in,out]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]uThe zonal velocity, in m s-1.
[in]vThe meridional velocity, in m s-1.
[in]hLayer thicknesses, in H (usually m or kg m-2).
[in]tvA structure containing pointers to any available thermodynamic fields. Absent fields have NULL ptrs.
[in]fluxesA structure containing pointers to any possible forcing fields. Unused fields have NULL ptrs.
[in,out]viscA structure containing vertical viscosities and related fields.
[in]dtTime increment in s.
csThe control structure returned by a previous call to vertvisc_init.

Definition at line 1018 of file MOM_set_viscosity.F90.

References mom_eos::calculate_density_derivs(), mom_error_handler::mom_error(), set_u_at_v(), and set_v_at_u().

Referenced by mom_dynamics_legacy_split::step_mom_dyn_legacy_split(), mom_dynamics_split_rk2::step_mom_dyn_split_rk2(), mom_dynamics_unsplit::step_mom_dyn_unsplit(), and mom_dynamics_unsplit_rk2::step_mom_dyn_unsplit_rk2().

1018  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
1019  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
1020  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
1021  intent(in) :: u !< The zonal velocity, in m s-1.
1022  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
1023  intent(in) :: v !< The meridional velocity, in m s-1.
1024  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1025  intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2).
1026  type(thermo_var_ptrs), intent(in) :: tv !< A structure containing pointers to any available
1027  !! thermodynamic fields. Absent fields have
1028  !! NULL ptrs.
1029  type(forcing), intent(in) :: fluxes !< A structure containing pointers to any
1030  !! possible forcing fields. Unused fields have
1031  !! NULL ptrs.
1032  type(vertvisc_type), intent(inout) :: visc !< A structure containing vertical viscosities and
1033  !! related fields.
1034  real, intent(in) :: dt !< Time increment in s.
1035  type(set_visc_cs), pointer :: cs !< The control structure returned by a previous
1036  !! call to vertvisc_init.
1037 
1038 ! The following subroutine calculates the thickness of the surface boundary
1039 ! layer for applying an elevated viscosity. A bulk Richardson criterion or
1040 ! the thickness of the topmost NKML layers (with a bulk mixed layer) are
1041 ! currently used. The thicknesses are given in terms of fractional layers, so
1042 ! that this thickness will move as the thickness of the topmost layers change.
1043 !
1044 ! Arguments: u - Zonal velocity, in m s-1.
1045 ! (in) v - Meridional velocity, in m s-1.
1046 ! (in) h - Layer thickness, in m or kg m-2. In the comments below,
1047 ! the units of h are denoted as H.
1048 ! (in) tv - A structure containing pointers to any available
1049 ! thermodynamic fields. Absent fields have NULL ptrs.
1050 ! (in) fluxes - A structure containing pointers to any possible
1051 ! forcing fields. Unused fields have NULL ptrs.
1052 ! (out) visc - A structure containing vertical viscosities and related
1053 ! fields.
1054 ! (in) dt - Time increment in s.
1055 ! (in) G - The ocean's grid structure.
1056 ! (in) GV - The ocean's vertical grid structure.
1057 ! (in) CS - The control structure returned by a previous call to
1058 ! vertvisc_init.
1059 
1060  real, dimension(SZIB_(G)) :: &
1061  htot, & ! The total depth of the layers being that are within the
1062  ! surface mixed layer, in H.
1063  thtot, & ! The integrated temperature of layers that are within the
1064  ! surface mixed layer, in H degC.
1065  shtot, & ! The integrated salt of layers that are within the
1066  ! surface mixed layer H PSU.
1067  rhtot, & ! The integrated density of layers that are within the
1068  ! surface mixed layer, in H kg m-3. Rhtot is only used if no
1069  ! equation of state is used.
1070  uhtot, & ! The depth integrated zonal and meridional velocities within
1071  vhtot, & ! the surface mixed layer, in H m s-1.
1072  idecay_len_tke, & ! The inverse of a turbulence decay length scale, in H-1.
1073  dr_dt, & ! Partial derivative of the density at the base of layer nkml
1074  ! (roughly the base of the mixed layer) with temperature, in
1075  ! units of kg m-3 K-1.
1076  dr_ds, & ! Partial derivative of the density at the base of layer nkml
1077  ! (roughly the base of the mixed layer) with salinity, in units
1078  ! of kg m-3 psu-1.
1079  ustar, & ! The surface friction velocity under ice shelves, in m s-1.
1080  press, & ! The pressure at which dR_dT and dR_dS are evaluated, in Pa.
1081  t_eos, & ! T_EOS and S_EOS are the potential temperature and salnity at which dR_dT and dR_dS
1082  s_eos ! which dR_dT and dR_dS are evaluated, in degC and PSU.
1083  real, dimension(SZIB_(G),SZJ_(G)) :: &
1084  mask_u ! A mask that disables any contributions from u points that
1085  ! are land or past open boundary conditions, nondim., 0 or 1.
1086  real, dimension(SZI_(G),SZJB_(G)) :: &
1087  mask_v ! A mask that disables any contributions from v points that
1088  ! are land or past open boundary conditions, nondim., 0 or 1.
1089  real :: h_at_vel(szib_(g),szk_(g))! Layer thickness at velocity points,
1090  ! using an upwind-biased second order accurate estimate based
1091  ! on the previous velocity direction, in H.
1092  integer :: k_massive(szib_(g)) ! The k-index of the deepest layer yet found
1093  ! that has more than h_tiny thickness and will be in the
1094  ! viscous mixed layer.
1095  real :: uh2 ! The squared magnitude of the difference between the velocity
1096  ! integrated through the mixed layer and the velocity of the
1097  ! interior layer layer times the depth of the the mixed layer,
1098  ! in H2 m2 s-2.
1099  real :: htot_vel ! Sum of the layer thicknesses up to some
1100  ! point, in H (i.e., m or kg m-2).
1101  real :: hwtot ! Sum of the thicknesses used to calculate
1102  ! the near-bottom velocity magnitude, in H.
1103  real :: hutot ! Running sum of thicknesses times the
1104  ! velocity magnitudes, in H m s-1.
1105  real :: hweight ! The thickness of a layer that is within Hbbl
1106  ! of the bottom, in H.
1107 
1108  real :: hlay ! The layer thickness at velocity points, in H.
1109  real :: i_2hlay ! 1 / 2*hlay, in H-1.
1110  real :: t_lay ! The layer temperature at velocity points, in deg C.
1111  real :: s_lay ! The layer salinity at velocity points, in PSU.
1112  real :: rlay ! The layer potential density at velocity points, in kg m-3.
1113  real :: rlb ! The potential density of the layer below, in kg m-3.
1114  real :: v_at_u ! The meridonal velocity at a zonal velocity point in m s-1.
1115  real :: u_at_v ! The zonal velocity at a meridonal velocity point in m s-1.
1116  real :: ghprime ! The mixed-layer internal gravity wave speed squared, based
1117  ! on the mixed layer thickness and density difference across
1118  ! the base of the mixed layer, in m2 s-2.
1119  real :: ribulk ! The bulk Richardson number below which water is in the
1120  ! viscous mixed layer, including reduction for turbulent
1121  ! decay. Nondimensional.
1122  real :: dt_rho0 ! The time step divided by the conversion from the layer
1123  ! thickness to layer mass, in s H m2 kg-1.
1124  real :: g_h_rho0 ! The gravitational acceleration times the conversion from
1125  ! H to m divided by the mean density, in m5 s-2 H-1 kg-1.
1126  real :: ustarsq ! 400 times the square of ustar, times
1127  ! Rho0 divided by G_Earth and the conversion
1128  ! from m to thickness units, in kg m-2 or kg2 m-5.
1129  real :: cdrag_sqrt ! Square root of the drag coefficient, nd.
1130  real :: oldfn ! The integrated energy required to
1131  ! entrain up to the bottom of the layer,
1132  ! divided by G_Earth, in H kg m-3.
1133  real :: dfn ! The increment in oldfn for entraining
1134  ! the layer, in H kg m-3.
1135  real :: dh ! The increment in layer thickness from
1136  ! the present layer, in H.
1137  real :: u_bg_sq ! The square of an assumed background velocity, for
1138  ! calculating the mean magnitude near the top for use in
1139  ! the quadratic surface drag, in m2.
1140  real :: h_tiny ! A very small thickness, in H. Layers that are less than
1141  ! h_tiny can not be the deepest in the viscous mixed layer.
1142  real :: absf ! The absolute value of f averaged to velocity points, s-1.
1143  real :: u_star ! The friction velocity at velocity points, in m s-1.
1144  real :: h_neglect ! A thickness that is so small it is usually lost
1145  ! in roundoff and can be neglected, in H.
1146  real :: rho0x400_g ! 400*Rho0/G_Earth, in kg s2 m-4. The 400 is a
1147  ! constant proposed by Killworth and Edwards, 1999.
1148  real :: h_to_m, m_to_h ! Local copies of unit conversion factors.
1149  real :: ustar1 ! ustar in units of H/s
1150  real :: h2f2 ! (h*2*f)^2
1151  logical :: use_eos, do_any, do_any_shelf, do_i(szib_(g))
1152  integer :: i, j, k, is, ie, js, je, isq, ieq, jsq, jeq, nz, k2, nkmb, nkml, n
1153  type(ocean_obc_type), pointer :: obc => null()
1154 
1155  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1156  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
1157  nkmb = gv%nk_rho_varies ; nkml = gv%nkml
1158 
1159  if (.not.associated(cs)) call mom_error(fatal,"MOM_vert_friction(visc_ML): "//&
1160  "Module must be initialized before it is used.")
1161  if (.not.(cs%dynamic_viscous_ML .or. associated(fluxes%frac_shelf_h))) return
1162 
1163  rho0x400_g = 400.0*(gv%Rho0/gv%g_Earth)*gv%m_to_H
1164  u_bg_sq = cs%drag_bg_vel * cs%drag_bg_vel
1165  cdrag_sqrt=sqrt(cs%cdrag)
1166 
1167  obc => cs%OBC
1168  use_eos = associated(tv%eqn_of_state)
1169  dt_rho0 = dt/gv%H_to_kg_m2
1170  h_neglect = gv%H_subroundoff
1171  h_tiny = 2.0*gv%Angstrom + h_neglect
1172  g_h_rho0 = (gv%g_Earth * gv%H_to_m) / gv%Rho0
1173  h_to_m = gv%H_to_m ; m_to_h = gv%m_to_H
1174 
1175  if (associated(fluxes%frac_shelf_h)) then
1176  ! This configuration has ice shelves, and the appropriate variables need to
1177  ! be allocated.
1178  if (.not.associated(fluxes%frac_shelf_u)) call mom_error(fatal, &
1179  "set_viscous_ML: fluxes%frac_shelf_h is associated, but " // &
1180  "fluxes%frac_shelf_u is not.")
1181  if (.not.associated(fluxes%frac_shelf_v)) call mom_error(fatal, &
1182  "set_viscous_ML: fluxes%frac_shelf_h is associated, but " // &
1183  "fluxes%frac_shelf_v is not.")
1184  if (.not.associated(visc%taux_shelf)) then
1185  allocate(visc%taux_shelf(g%IsdB:g%IedB,g%jsd:g%jed))
1186  visc%taux_shelf(:,:) = 0.0
1187  endif
1188  if (.not.associated(visc%tauy_shelf)) then
1189  allocate(visc%tauy_shelf(g%isd:g%ied,g%JsdB:g%JedB))
1190  visc%tauy_shelf(:,:) = 0.0
1191  endif
1192  if (.not.associated(visc%tbl_thick_shelf_u)) then
1193  allocate(visc%tbl_thick_shelf_u(g%IsdB:g%IedB,g%jsd:g%jed))
1194  visc%tbl_thick_shelf_u(:,:) = 0.0
1195  endif
1196  if (.not.associated(visc%tbl_thick_shelf_v)) then
1197  allocate(visc%tbl_thick_shelf_v(g%isd:g%ied,g%JsdB:g%JedB))
1198  visc%tbl_thick_shelf_v(:,:) = 0.0
1199  endif
1200  if (.not.associated(visc%kv_tbl_shelf_u)) then
1201  allocate(visc%kv_tbl_shelf_u(g%IsdB:g%IedB,g%jsd:g%jed))
1202  visc%kv_tbl_shelf_u(:,:) = 0.0
1203  endif
1204  if (.not.associated(visc%kv_tbl_shelf_v)) then
1205  allocate(visc%kv_tbl_shelf_v(g%isd:g%ied,g%JsdB:g%JedB))
1206  visc%kv_tbl_shelf_v(:,:) = 0.0
1207  endif
1208 
1209  ! With a linear drag law, the friction velocity is already known.
1210 ! if (CS%linear_drag) ustar(:) = cdrag_sqrt*CS%drag_bg_vel
1211  endif
1212 
1213  !$OMP parallel do default(shared)
1214  do j=js-1,je ; do i=is-1,ie+1
1215  mask_v(i,j) = g%mask2dCv(i,j)
1216  enddo ; enddo
1217  !$OMP parallel do default(shared)
1218  do j=js-1,je+1 ; do i=is-1,ie
1219  mask_u(i,j) = g%mask2dCu(i,j)
1220  enddo ; enddo
1221 
1222  if (associated(obc)) then ; do n=1,obc%number_of_segments
1223  ! Now project bottom depths across cell-corner points in the OBCs. The two
1224  ! projections have to occur in sequence and can not be combined easily.
1225  if (.not. obc%segment(n)%on_pe) cycle
1226  ! Use a one-sided projection of bottom depths at OBC points.
1227  i = obc%segment(n)%HI%IsdB ; j = obc%segment(n)%HI%JsdB
1228  if (obc%segment(n)%is_N_or_S .and. (j >= js-1) .and. (j <= je)) then
1229  do i = max(is-1,obc%segment(n)%HI%IsdB), min(ie,obc%segment(n)%HI%IedB)
1230  if (obc%segment(n)%direction == obc_direction_n) mask_u(i,j+1) = 0.0
1231  if (obc%segment(n)%direction == obc_direction_s) mask_u(i,j) = 0.0
1232  enddo
1233  elseif (obc%segment(n)%is_E_or_W .and. (i >= is-1) .and. (i <= je)) then
1234  do j = max(js-1,obc%segment(n)%HI%JsdB), min(je,obc%segment(n)%HI%JedB)
1235  if (obc%segment(n)%direction == obc_direction_e) mask_v(i+1,j) = 0.0
1236  if (obc%segment(n)%direction == obc_direction_w) mask_v(i,j) = 0.0
1237  enddo
1238  endif
1239  enddo ; endif
1240 
1241 !$OMP parallel do default(none) shared(u, v, h, tv, fluxes, visc, dt, G, GV, CS, use_EOS, &
1242 !$OMP dt_Rho0, h_neglect, h_tiny, g_H_Rho0,js,je, &
1243 !$OMP H_to_m, m_to_H, Isq, Ieq, nz, U_bg_sq,mask_v, &
1244 !$OMP cdrag_sqrt,Rho0x400_G,nkml) &
1245 !$OMP private(do_any,htot,do_i,k_massive,Thtot,uhtot,vhtot,U_Star, &
1246 !$OMP Idecay_len_TKE,press,k2,I_2hlay,T_EOS,S_EOS,dR_dT, &
1247 !$OMP dR_dS,hlay,v_at_u,Uh2,T_lay,S_lay,gHprime, &
1248 !$OMP RiBulk,Shtot,Rhtot,absf,do_any_shelf, &
1249 !$OMP h_at_vel,ustar,htot_vel,hwtot,hutot,hweight,ustarsq, &
1250 !$OMP oldfn,Dfn,Dh,Rlay,Rlb,h2f2,ustar1)
1251  do j=js,je ! u-point loop
1252  if (cs%dynamic_viscous_ML) then
1253  do_any = .false.
1254  do i=isq,ieq
1255  htot(i) = 0.0
1256  if (g%mask2dCu(i,j) < 0.5) then
1257  do_i(i) = .false. ; visc%nkml_visc_u(i,j) = nkml
1258  else
1259  do_i(i) = .true. ; do_any = .true.
1260  k_massive(i) = nkml
1261  thtot(i) = 0.0 ; shtot(i) = 0.0 ; rhtot(i) = 0.0
1262  uhtot(i) = dt_rho0 * fluxes%taux(i,j)
1263  vhtot(i) = 0.25 * dt_rho0 * ((fluxes%tauy(i,j) + fluxes%tauy(i+1,j-1)) + &
1264  (fluxes%tauy(i,j-1) + fluxes%tauy(i+1,j)))
1265 
1266  if (cs%omega_frac >= 1.0) then ; absf = 2.0*cs%omega ; else
1267  absf = 0.5*(abs(g%CoriolisBu(i,j)) + abs(g%CoriolisBu(i,j-1)))
1268  if (cs%omega_frac > 0.0) &
1269  absf = sqrt(cs%omega_frac*4.0*cs%omega**2 + (1.0-cs%omega_frac)*absf**2)
1270  endif
1271  u_star = max(cs%ustar_min, 0.5 * (fluxes%ustar(i,j) + fluxes%ustar(i+1,j)))
1272  idecay_len_tke(i) = ((absf / u_star) * cs%TKE_decay) * h_to_m
1273  endif
1274  enddo
1275 
1276  if (do_any) then ; do k=1,nz
1277  if (k > nkml) then
1278  do_any = .false.
1279  if (use_eos .and. (k==nkml+1)) then
1280  ! Find dRho/dT and dRho_dS.
1281  do i=isq,ieq
1282  press(i) = gv%H_to_Pa * htot(i)
1283  k2 = max(1,nkml)
1284  i_2hlay = 1.0 / (h(i,j,k2) + h(i+1,j,k2) + h_neglect)
1285  t_eos(i) = (h(i,j,k2)*tv%T(i,j,k2) + h(i+1,j,k2)*tv%T(i+1,j,k2)) * i_2hlay
1286  s_eos(i) = (h(i,j,k2)*tv%S(i,j,k2) + h(i+1,j,k2)*tv%S(i+1,j,k2)) * i_2hlay
1287  enddo
1288  call calculate_density_derivs(t_eos, s_eos, press, dr_dt, dr_ds, &
1289  isq-g%IsdB+1, ieq-isq+1, tv%eqn_of_state)
1290  endif
1291 
1292  do i=isq,ieq ; if (do_i(i)) then
1293 
1294  hlay = 0.5*(h(i,j,k) + h(i+1,j,k))
1295  if (hlay > h_tiny) then ! Only consider non-vanished layers.
1296  i_2hlay = 1.0 / (h(i,j,k) + h(i+1,j,k))
1297  v_at_u = 0.5 * (h(i,j,k) * (v(i,j,k) + v(i,j-1,k)) + &
1298  h(i+1,j,k) * (v(i+1,j,k) + v(i+1,j-1,k))) * i_2hlay
1299  uh2 = (uhtot(i) - htot(i)*u(i,j,k))**2 + (vhtot(i) - htot(i)*v_at_u)**2
1300 
1301  if (use_eos) then
1302  t_lay = (h(i,j,k)*tv%T(i,j,k) + h(i+1,j,k)*tv%T(i+1,j,k)) * i_2hlay
1303  s_lay = (h(i,j,k)*tv%S(i,j,k) + h(i+1,j,k)*tv%S(i+1,j,k)) * i_2hlay
1304  ghprime = g_h_rho0 * (dr_dt(i) * (t_lay*htot(i) - thtot(i)) + &
1305  dr_ds(i) * (s_lay*htot(i) - shtot(i)))
1306  else
1307  ghprime = g_h_rho0 * (gv%Rlay(k)*htot(i) - rhtot(i))
1308  endif
1309 
1310  if (ghprime > 0.0) then
1311  ribulk = cs%bulk_Ri_ML * exp(-htot(i) * idecay_len_tke(i))
1312  if (ribulk * uh2 <= (htot(i)**2) * ghprime) then
1313  visc%nkml_visc_u(i,j) = real(k_massive(i))
1314  do_i(i) = .false.
1315  elseif (ribulk * uh2 <= (htot(i) + hlay)**2 * ghprime) then
1316  visc%nkml_visc_u(i,j) = real(k-1) + &
1317  ( sqrt(ribulk * uh2 / ghprime) - htot(i) ) / hlay
1318  do_i(i) = .false.
1319  endif
1320  endif
1321  k_massive(i) = k
1322  endif ! hlay > h_tiny
1323 
1324  if (do_i(i)) do_any = .true.
1325  endif ; enddo
1326 
1327  if (.not.do_any) exit ! All columns are done.
1328  endif
1329 
1330  do i=isq,ieq ; if (do_i(i)) then
1331  htot(i) = htot(i) + 0.5 * (h(i,j,k) + h(i+1,j,k))
1332  uhtot(i) = uhtot(i) + 0.5 * (h(i,j,k) + h(i+1,j,k)) * u(i,j,k)
1333  vhtot(i) = vhtot(i) + 0.25 * (h(i,j,k) * (v(i,j,k) + v(i,j-1,k)) + &
1334  h(i+1,j,k) * (v(i+1,j,k) + v(i+1,j-1,k)))
1335  if (use_eos) then
1336  thtot(i) = thtot(i) + 0.5 * (h(i,j,k)*tv%T(i,j,k) + h(i+1,j,k)*tv%T(i+1,j,k))
1337  shtot(i) = shtot(i) + 0.5 * (h(i,j,k)*tv%S(i,j,k) + h(i+1,j,k)*tv%S(i+1,j,k))
1338  else
1339  rhtot(i) = rhtot(i) + 0.5 * (h(i,j,k) + h(i+1,j,k)) * gv%Rlay(k)
1340  endif
1341  endif ; enddo
1342  enddo ; endif
1343 
1344  if (do_any) then ; do i=isq,ieq ; if (do_i(i)) then
1345  visc%nkml_visc_u(i,j) = k_massive(i)
1346  endif ; enddo ; endif
1347  endif ! dynamic_viscous_ML
1348 
1349  do_any_shelf = .false.
1350  if (associated(fluxes%frac_shelf_h)) then
1351  do i=isq,ieq
1352  if (fluxes%frac_shelf_u(i,j)*g%mask2dCu(i,j) == 0.0) then
1353  do_i(i) = .false.
1354  visc%tbl_thick_shelf_u(i,j) = 0.0 ; visc%kv_tbl_shelf_u(i,j) = 0.0
1355  else
1356  do_i(i) = .true. ; do_any_shelf = .true.
1357  endif
1358  enddo
1359  endif
1360 
1361  if (do_any_shelf) then
1362  do k=1,nz ; do i=isq,ieq ; if (do_i(i)) then
1363  if (u(i,j,k) *(h(i+1,j,k) - h(i,j,k)) >= 0) then
1364  h_at_vel(i,k) = 2.0*h(i,j,k)*h(i+1,j,k) / &
1365  (h(i,j,k) + h(i+1,j,k) + h_neglect)
1366  else
1367  h_at_vel(i,k) = 0.5 * (h(i,j,k) + h(i+1,j,k))
1368  endif
1369  else
1370  h_at_vel(i,k) = 0.0 ; ustar(i) = 0.0
1371  endif ; enddo ; enddo
1372 
1373  do i=isq,ieq ; if (do_i(i)) then
1374  htot_vel = 0.0 ; hwtot = 0.0 ; hutot = 0.0
1375  thtot(i) = 0.0 ; shtot(i) = 0.0
1376  if (use_eos .or. .not.cs%linear_drag) then ; do k=1,nz
1377  if (htot_vel>=cs%Htbl_shelf) exit ! terminate the k loop
1378  hweight = min(cs%Htbl_shelf - htot_vel, h_at_vel(i,k))
1379  if (hweight <= 1.5*gv%Angstrom + h_neglect) cycle
1380 
1381  htot_vel = htot_vel + h_at_vel(i,k)
1382  hwtot = hwtot + hweight
1383 
1384  if (.not.cs%linear_drag) then
1385  v_at_u = set_v_at_u(v, h, g, i, j, k, mask_v)
1386  hutot = hutot + hweight * sqrt(u(i,j,k)**2 + &
1387  v_at_u**2 + u_bg_sq)
1388  endif
1389  if (use_eos) then
1390  thtot(i) = thtot(i) + hweight * 0.5 * (tv%T(i,j,k) + tv%T(i+1,j,k))
1391  shtot(i) = shtot(i) + hweight * 0.5 * (tv%S(i,j,k) + tv%S(i+1,j,k))
1392  endif
1393  enddo ; endif
1394 
1395  if ((.not.cs%linear_drag) .and. (hwtot > 0.0)) then
1396  ustar(i) = cdrag_sqrt*hutot/hwtot
1397  else
1398  ustar(i) = cdrag_sqrt*cs%drag_bg_vel
1399  endif
1400 
1401  if (use_eos) then ; if (hwtot > 0.0) then
1402  t_eos(i) = thtot(i)/hwtot ; s_eos(i) = shtot(i)/hwtot
1403  else
1404  t_eos(i) = 0.0 ; s_eos(i) = 0.0
1405  endif ; endif
1406  endif ; enddo ! I-loop
1407 
1408  if (use_eos) then
1409  call calculate_density_derivs(t_eos, s_eos, fluxes%p_surf(:,j), &
1410  dr_dt, dr_ds, isq-g%IsdB+1, ieq-isq+1, tv%eqn_of_state)
1411  endif
1412 
1413  do i=isq,ieq ; if (do_i(i)) then
1414  ! The 400.0 in this expression is the square of a constant proposed
1415  ! by Killworth and Edwards, 1999, in equation (2.20).
1416  ustarsq = rho0x400_g * ustar(i)**2
1417  htot(i) = 0.0
1418  if (use_eos) then
1419  thtot(i) = 0.0 ; shtot(i) = 0.0
1420  do k=1,nz-1
1421  if (h_at_vel(i,k) <= 0.0) cycle
1422  t_lay = 0.5 * (tv%T(i,j,k) + tv%T(i+1,j,k))
1423  s_lay = 0.5 * (tv%S(i,j,k) + tv%S(i+1,j,k))
1424  oldfn = dr_dt(i)*(t_lay*htot(i) - thtot(i)) + dr_ds(i)*(s_lay*htot(i) - shtot(i))
1425  if (oldfn >= ustarsq) exit
1426 
1427  dfn = (dr_dt(i)*(0.5*(tv%T(i,j,k+1)+tv%T(i+1,j,k+1)) - t_lay) + &
1428  dr_ds(i)*(0.5*(tv%S(i,j,k+1)+tv%S(i+1,j,k+1)) - s_lay)) * &
1429  (h_at_vel(i,k)+htot(i))
1430  if ((oldfn + dfn) <= ustarsq) then
1431  dh = h_at_vel(i,k)
1432  else
1433  dh = h_at_vel(i,k) * sqrt((ustarsq-oldfn)/dfn)
1434  endif
1435 
1436  htot(i) = htot(i) + dh
1437  thtot(i) = thtot(i) + t_lay*dh ; shtot(i) = shtot(i) + s_lay*dh
1438  enddo
1439  if ((oldfn < ustarsq) .and. (h_at_vel(i,nz) > 0.0)) then
1440  t_lay = 0.5*(tv%T(i,j,nz) + tv%T(i+1,j,nz))
1441  s_lay = 0.5*(tv%S(i,j,nz) + tv%S(i+1,j,nz))
1442  if (dr_dt(i)*(t_lay*htot(i) - thtot(i)) + &
1443  dr_ds(i)*(s_lay*htot(i) - shtot(i)) < ustarsq) &
1444  htot(i) = htot(i) + h_at_vel(i,nz)
1445  endif ! Examination of layer nz.
1446  else ! Use Rlay as the density variable.
1447  rhtot = 0.0
1448  do k=1,nz-1
1449  rlay = gv%Rlay(k) ; rlb = gv%Rlay(k+1)
1450 
1451  oldfn = rlay*htot(i) - rhtot(i)
1452  if (oldfn >= ustarsq) exit
1453 
1454  dfn = (rlb - rlay)*(h_at_vel(i,k)+htot(i))
1455  if ((oldfn + dfn) <= ustarsq) then
1456  dh = h_at_vel(i,k)
1457  else
1458  dh = h_at_vel(i,k) * sqrt((ustarsq-oldfn)/dfn)
1459  endif
1460 
1461  htot(i) = htot(i) + dh
1462  rhtot(i) = rhtot(i) + rlay*dh
1463  enddo
1464  if (gv%Rlay(nz)*htot(i) - rhtot(i) < ustarsq) &
1465  htot(i) = htot(i) + h_at_vel(i,nz)
1466  endif ! use_EOS
1467 
1468  !visc%tbl_thick_shelf_u(I,j) = max(CS%Htbl_shelf_min, &
1469  ! htot(I) / (0.5 + sqrt(0.25 + &
1470  ! (htot(i)*(G%CoriolisBu(I,J-1)+G%CoriolisBu(I,J)))**2 / &
1471  ! (ustar(i)*m_to_H)**2 )) )
1472  ustar1 = ustar(i)*m_to_h
1473  h2f2 = (htot(i)*(g%CoriolisBu(i,j-1)+g%CoriolisBu(i,j)) + h_neglect*cs%Omega)**2
1474  visc%tbl_thick_shelf_u(i,j) = max(cs%Htbl_shelf_min, &
1475  ( htot(i)*ustar1 ) / ( 0.5*ustar1 + sqrt((0.5*ustar1)**2 + h2f2 ) ) )
1476  visc%kv_tbl_shelf_u(i,j) = max(cs%KV_TBL_min, &
1477  cdrag_sqrt*ustar(i)*visc%tbl_thick_shelf_u(i,j))
1478  endif ; enddo ! I-loop
1479  endif ! do_any_shelf
1480 
1481  enddo ! j-loop at u-points
1482 
1483 !$OMP parallel do default(none) shared(u, v, h, tv, fluxes, visc, dt, G, GV, CS, use_EOS,&
1484 !$OMP dt_Rho0, h_neglect, h_tiny, g_H_Rho0,is,ie, &
1485 !$OMP Jsq,Jeq,nz,U_bg_sq,cdrag_sqrt,Rho0x400_G,nkml, &
1486 !$OMP m_to_H,H_to_m,mask_u) &
1487 !$OMP private(do_any,htot,do_i,k_massive,Thtot,vhtot,uhtot,absf,&
1488 !$OMP U_Star,Idecay_len_TKE,press,k2,I_2hlay,T_EOS, &
1489 !$OMP S_EOS,dR_dT, dR_dS,hlay,u_at_v,Uh2, &
1490 !$OMP T_lay,S_lay,gHprime,RiBulk,do_any_shelf, &
1491 !$OMP Shtot,Rhtot,ustar,h_at_vel,htot_vel,hwtot, &
1492 !$OMP hutot,hweight,ustarsq,oldfn,Dh,Rlay,Rlb,Dfn, &
1493 !$OMP h2f2,ustar1)
1494  do j=jsq,jeq ! v-point loop
1495  if (cs%dynamic_viscous_ML) then
1496  do_any = .false.
1497  do i=is,ie
1498  htot(i) = 0.0
1499  if (g%mask2dCv(i,j) < 0.5) then
1500  do_i(i) = .false. ; visc%nkml_visc_v(i,j) = nkml
1501  else
1502  do_i(i) = .true. ; do_any = .true.
1503  k_massive(i) = nkml
1504  thtot(i) = 0.0 ; shtot(i) = 0.0 ; rhtot(i) = 0.0
1505  vhtot(i) = dt_rho0 * fluxes%tauy(i,j)
1506  uhtot(i) = 0.25 * dt_rho0 * ((fluxes%taux(i,j) + fluxes%taux(i-1,j+1)) + &
1507  (fluxes%taux(i-1,j) + fluxes%taux(i,j+1)))
1508 
1509  if (cs%omega_frac >= 1.0) then ; absf = 2.0*cs%omega ; else
1510  absf = 0.5*(abs(g%CoriolisBu(i-1,j)) + abs(g%CoriolisBu(i,j)))
1511  if (cs%omega_frac > 0.0) &
1512  absf = sqrt(cs%omega_frac*4.0*cs%omega**2 + (1.0-cs%omega_frac)*absf**2)
1513  endif
1514 
1515  u_star = max(cs%ustar_min, 0.5 * (fluxes%ustar(i,j) + fluxes%ustar(i,j+1)))
1516  idecay_len_tke(i) = ((absf / u_star) * cs%TKE_decay) * h_to_m
1517 
1518  endif
1519  enddo
1520 
1521  if (do_any) then ; do k=1,nz
1522  if (k > nkml) then
1523  do_any = .false.
1524  if (use_eos .and. (k==nkml+1)) then
1525  ! Find dRho/dT and dRho_dS.
1526  do i=is,ie
1527  press(i) = gv%H_to_Pa * htot(i)
1528  k2 = max(1,nkml)
1529  i_2hlay = 1.0 / (h(i,j,k2) + h(i,j+1,k2) + h_neglect)
1530  t_eos(i) = (h(i,j,k2)*tv%T(i,j,k2) + h(i,j+1,k2)*tv%T(i,j+1,k2)) * i_2hlay
1531  s_eos(i) = (h(i,j,k2)*tv%S(i,j,k2) + h(i,j+1,k2)*tv%S(i,j+1,k2)) * i_2hlay
1532  enddo
1533  call calculate_density_derivs(t_eos, s_eos, press, dr_dt, dr_ds, &
1534  is-g%IsdB+1, ie-is+1, tv%eqn_of_state)
1535  endif
1536 
1537  do i=is,ie ; if (do_i(i)) then
1538 
1539  hlay = 0.5*(h(i,j,k) + h(i,j+1,k))
1540  if (hlay > h_tiny) then ! Only consider non-vanished layers.
1541  i_2hlay = 1.0 / (h(i,j,k) + h(i,j+1,k))
1542  u_at_v = 0.5 * (h(i,j,k) * (u(i-1,j,k) + u(i,j,k)) + &
1543  h(i,j+1,k) * (u(i-1,j+1,k) + u(i,j+1,k))) * i_2hlay
1544  uh2 = (uhtot(i) - htot(i)*u_at_v)**2 + (vhtot(i) - htot(i)*v(i,j,k))**2
1545 
1546  if (use_eos) then
1547  t_lay = (h(i,j,k)*tv%T(i,j,k) + h(i,j+1,k)*tv%T(i,j+1,k)) * i_2hlay
1548  s_lay = (h(i,j,k)*tv%S(i,j,k) + h(i,j+1,k)*tv%S(i,j+1,k)) * i_2hlay
1549  ghprime = g_h_rho0 * (dr_dt(i) * (t_lay*htot(i) - thtot(i)) + &
1550  dr_ds(i) * (s_lay*htot(i) - shtot(i)))
1551  else
1552  ghprime = g_h_rho0 * (gv%Rlay(k)*htot(i) - rhtot(i))
1553  endif
1554 
1555  if (ghprime > 0.0) then
1556  ribulk = cs%bulk_Ri_ML * exp(-htot(i) * idecay_len_tke(i))
1557  if (ribulk * uh2 <= htot(i)**2 * ghprime) then
1558  visc%nkml_visc_v(i,j) = real(k_massive(i))
1559  do_i(i) = .false.
1560  elseif (ribulk * uh2 <= (htot(i) + hlay)**2 * ghprime) then
1561  visc%nkml_visc_v(i,j) = real(k-1) + &
1562  ( sqrt(ribulk * uh2 / ghprime) - htot(i) ) / hlay
1563  do_i(i) = .false.
1564  endif
1565  endif
1566  k_massive(i) = k
1567  endif ! hlay > h_tiny
1568 
1569  if (do_i(i)) do_any = .true.
1570  endif ; enddo
1571 
1572  if (.not.do_any) exit ! All columns are done.
1573  endif
1574 
1575  do i=is,ie ; if (do_i(i)) then
1576  htot(i) = htot(i) + 0.5 * (h(i,j,k) + h(i,j+1,k))
1577  vhtot(i) = vhtot(i) + 0.5 * (h(i,j,k) + h(i,j+1,k)) * v(i,j,k)
1578  uhtot(i) = uhtot(i) + 0.25 * (h(i,j,k) * (u(i-1,j,k) + u(i,j,k)) + &
1579  h(i,j+1,k) * (u(i-1,j+1,k) + u(i,j+1,k)))
1580  if (use_eos) then
1581  thtot(i) = thtot(i) + 0.5 * (h(i,j,k)*tv%T(i,j,k) + h(i,j+1,k)*tv%T(i,j+1,k))
1582  shtot(i) = shtot(i) + 0.5 * (h(i,j,k)*tv%S(i,j,k) + h(i,j+1,k)*tv%S(i,j+1,k))
1583  else
1584  rhtot(i) = rhtot(i) + 0.5 * (h(i,j,k) + h(i,j+1,k)) * gv%Rlay(k)
1585  endif
1586  endif ; enddo
1587  enddo ; endif
1588 
1589  if (do_any) then ; do i=is,ie ; if (do_i(i)) then
1590  visc%nkml_visc_v(i,j) = k_massive(i)
1591  endif ; enddo ; endif
1592  endif ! dynamic_viscous_ML
1593 
1594  do_any_shelf = .false.
1595  if (associated(fluxes%frac_shelf_h)) then
1596  do i=is,ie
1597  if (fluxes%frac_shelf_v(i,j)*g%mask2dCv(i,j) == 0.0) then
1598  do_i(i) = .false.
1599  visc%tbl_thick_shelf_v(i,j) = 0.0 ; visc%kv_tbl_shelf_v(i,j) = 0.0
1600  else
1601  do_i(i) = .true. ; do_any_shelf = .true.
1602  endif
1603  enddo
1604  endif
1605 
1606  if (do_any_shelf) then
1607  do k=1,nz ; do i=is,ie ; if (do_i(i)) then
1608  if (v(i,j,k) * (h(i,j+1,k) - h(i,j,k)) >= 0) then
1609  h_at_vel(i,k) = 2.0*h(i,j,k)*h(i,j+1,k) / &
1610  (h(i,j,k) + h(i,j+1,k) + h_neglect)
1611  else
1612  h_at_vel(i,k) = 0.5 * (h(i,j,k) + h(i,j+1,k))
1613  endif
1614  else
1615  h_at_vel(i,k) = 0.0 ; ustar(i) = 0.0
1616  endif ; enddo ; enddo
1617 
1618  do i=is,ie ; if (do_i(i)) then
1619  htot_vel = 0.0 ; hwtot = 0.0 ; hutot = 0.0
1620  thtot(i) = 0.0 ; shtot(i) = 0.0
1621  if (use_eos .or. .not.cs%linear_drag) then ; do k=1,nz
1622  if (htot_vel>=cs%Htbl_shelf) exit ! terminate the k loop
1623  hweight = min(cs%Htbl_shelf - htot_vel, h_at_vel(i,k))
1624  if (hweight <= 1.5*gv%Angstrom + h_neglect) cycle
1625 
1626  htot_vel = htot_vel + h_at_vel(i,k)
1627  hwtot = hwtot + hweight
1628 
1629  if (.not.cs%linear_drag) then
1630  u_at_v = set_u_at_v(u, h, g, i, j, k, mask_u)
1631  hutot = hutot + hweight * sqrt(v(i,j,k)**2 + &
1632  u_at_v**2 + u_bg_sq)
1633  endif
1634  if (use_eos) then
1635  thtot(i) = thtot(i) + hweight * 0.5 * (tv%T(i,j,k) + tv%T(i,j+1,k))
1636  shtot(i) = shtot(i) + hweight * 0.5 * (tv%S(i,j,k) + tv%S(i,j+1,k))
1637  endif
1638  enddo ; endif
1639 
1640  if (.not.cs%linear_drag) then ; if (hwtot > 0.0) then
1641  ustar(i) = cdrag_sqrt*hutot/hwtot
1642  else
1643  ustar(i) = cdrag_sqrt*cs%drag_bg_vel
1644  endif ; endif
1645 
1646  if (use_eos) then ; if (hwtot > 0.0) then
1647  t_eos(i) = thtot(i)/hwtot ; s_eos(i) = shtot(i)/hwtot
1648  else
1649  t_eos(i) = 0.0 ; s_eos(i) = 0.0
1650  endif ; endif
1651  endif ; enddo ! I-loop
1652 
1653  if (use_eos) then
1654  call calculate_density_derivs(t_eos, s_eos, fluxes%p_surf(:,j), &
1655  dr_dt, dr_ds, is-g%IsdB+1, ie-is+1, tv%eqn_of_state)
1656  endif
1657 
1658  do i=is,ie ; if (do_i(i)) then
1659  ! The 400.0 in this expression is the square of a constant proposed
1660  ! by Killworth and Edwards, 1999, in equation (2.20).
1661  ustarsq = rho0x400_g * ustar(i)**2
1662  htot(i) = 0.0
1663  if (use_eos) then
1664  thtot(i) = 0.0 ; shtot(i) = 0.0
1665  do k=1,nz-1
1666  if (h_at_vel(i,k) <= 0.0) cycle
1667  t_lay = 0.5 * (tv%T(i,j,k) + tv%T(i,j+1,k))
1668  s_lay = 0.5 * (tv%S(i,j,k) + tv%S(i,j+1,k))
1669  oldfn = dr_dt(i)*(t_lay*htot(i) - thtot(i)) + dr_ds(i)*(s_lay*htot(i) - shtot(i))
1670  if (oldfn >= ustarsq) exit
1671 
1672  dfn = (dr_dt(i)*(0.5*(tv%T(i,j,k+1)+tv%T(i,j+1,k+1)) - t_lay) + &
1673  dr_ds(i)*(0.5*(tv%S(i,j,k+1)+tv%S(i,j+1,k+1)) - s_lay)) * &
1674  (h_at_vel(i,k)+htot(i))
1675  if ((oldfn + dfn) <= ustarsq) then
1676  dh = h_at_vel(i,k)
1677  else
1678  dh = h_at_vel(i,k) * sqrt((ustarsq-oldfn)/dfn)
1679  endif
1680 
1681  htot(i) = htot(i) + dh
1682  thtot(i) = thtot(i) + t_lay*dh ; shtot(i) = shtot(i) + s_lay*dh
1683  enddo
1684  if ((oldfn < ustarsq) .and. (h_at_vel(i,nz) > 0.0)) then
1685  t_lay = 0.5*(tv%T(i,j,nz) + tv%T(i,j+1,nz))
1686  s_lay = 0.5*(tv%S(i,j,nz) + tv%S(i,j+1,nz))
1687  if (dr_dt(i)*(t_lay*htot(i) - thtot(i)) + &
1688  dr_ds(i)*(s_lay*htot(i) - shtot(i)) < ustarsq) &
1689  htot(i) = htot(i) + h_at_vel(i,nz)
1690  endif ! Examination of layer nz.
1691  else ! Use Rlay as the density variable.
1692  rhtot = 0.0
1693  do k=1,nz-1
1694  rlay = gv%Rlay(k) ; rlb = gv%Rlay(k+1)
1695 
1696  oldfn = rlay*htot(i) - rhtot(i)
1697  if (oldfn >= ustarsq) exit
1698 
1699  dfn = (rlb - rlay)*(h_at_vel(i,k)+htot(i))
1700  if ((oldfn + dfn) <= ustarsq) then
1701  dh = h_at_vel(i,k)
1702  else
1703  dh = h_at_vel(i,k) * sqrt((ustarsq-oldfn)/dfn)
1704  endif
1705 
1706  htot(i) = htot(i) + dh
1707  rhtot = rhtot + rlay*dh
1708  enddo
1709  if (gv%Rlay(nz)*htot(i) - rhtot(i) < ustarsq) &
1710  htot(i) = htot(i) + h_at_vel(i,nz)
1711  endif ! use_EOS
1712 
1713  !visc%tbl_thick_shelf_v(i,J) = max(CS%Htbl_shelf_min, &
1714  ! htot(i) / (0.5 + sqrt(0.25 + &
1715  ! (htot(i)*(G%CoriolisBu(I-1,J)+G%CoriolisBu(I,J)))**2 / &
1716  ! (ustar(i)*m_to_H)**2 )) )
1717  ustar1 = ustar(i)*m_to_h
1718  h2f2 = (htot(i)*(g%CoriolisBu(i-1,j)+g%CoriolisBu(i,j)) + h_neglect*cs%Omega)**2
1719  visc%tbl_thick_shelf_v(i,j) = max(cs%Htbl_shelf_min, &
1720  ( htot(i)*ustar1 ) / ( 0.5*ustar1 + sqrt((0.5*ustar1)**2 + h2f2 ) ) )
1721  visc%kv_tbl_shelf_v(i,j) = max(cs%KV_TBL_min, &
1722  cdrag_sqrt*ustar(i)*visc%tbl_thick_shelf_v(i,j))
1723  endif ; enddo ! i-loop
1724  endif ! do_any_shelf
1725 
1726  enddo ! J-loop at v-points
1727 
1728  if (cs%debug) then
1729  if (associated(visc%nkml_visc_u) .and. associated(visc%nkml_visc_v)) &
1730  call uvchksum("nkml_visc_[uv]", visc%nkml_visc_u, &
1731  visc%nkml_visc_v, g%HI,haloshift=0)
1732  endif
1733  if (cs%id_nkml_visc_u > 0) &
1734  call post_data(cs%id_nkml_visc_u, visc%nkml_visc_u, cs%diag)
1735  if (cs%id_nkml_visc_v > 0) &
1736  call post_data(cs%id_nkml_visc_v, visc%nkml_visc_v, cs%diag)
1737 
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Here is the call graph for this function:
Here is the caller graph for this function: