MOM6
MOM_set_diffusivity.F90
Go to the documentation of this file.
2 !***********************************************************************
3 !* GNU General Public License *
4 !* This file is a part of MOM. *
5 !* *
6 !* MOM is free software; you can redistribute it and/or modify it and *
7 !* are expected to follow the terms of the GNU General Public License *
8 !* as published by the Free Software Foundation; either version 2 of *
9 !* the License, or (at your option) any later version. *
10 !* *
11 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
13 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
14 !* License for more details. *
15 !* *
16 !* For the full text of the GNU General Public License, *
17 !* write to: Free Software Foundation, Inc., *
18 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
19 !* or see: http://www.gnu.org/licenses/gpl.html *
20 !***********************************************************************
21 
22 !********+*********+*********+*********+*********+*********+*********+**
23 !* *
24 !* By Robert Hallberg, September 1997 - June 2007 *
25 !* *
26 !* This file contains the subroutines that sets the diapycnal *
27 !* diffusivity, perhaps adding up pieces that are calculated in other *
28 !* files and passed in via the vertvisc type argument. *
29 !* *
30 !* A small fragment of the grid is shown below: *
31 !* *
32 !* j+1 x ^ x ^ x At x: q *
33 !* j+1 > o > o > At ^: v *
34 !* j x ^ x ^ x At >: u *
35 !* j > o > o > At o: h, buoy, ustar, T, S, Kd, ea, eb, etc. *
36 !* j-1 x ^ x ^ x *
37 !* i-1 i i+1 At x & ^: *
38 !* i i+1 At > & o: *
39 !* *
40 !* The boundaries always run through q grid points (x). *
41 !* *
42 !********+*********+*********+*********+*********+*********+*********+**
43 
44 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
45 use mom_cpu_clock, only : clock_module_driver, clock_module, clock_routine
46 use mom_diag_mediator, only : diag_ctrl, time_type
47 use mom_diag_mediator, only : safe_alloc_ptr, post_data, register_diag_field
49 use mom_debugging, only : hchksum, uvchksum
51 use mom_error_handler, only : mom_error, is_root_pe, fatal, warning, note
55 use mom_forcing_type, only : forcing, optics_type
56 use mom_grid, only : ocean_grid_type
59 use mom_io, only : slasher, vardesc, var_desc
66 
69 
70 use fms_mod, only : read_data
71 
72 implicit none ; private
73 
74 #include <MOM_memory.h>
75 
76 public set_diffusivity
77 public set_bbl_tke
80 
81 type, public :: set_diffusivity_cs ; private
82  logical :: debug ! If true, write verbose checksums for debugging.
83 
84  logical :: bulkmixedlayer ! If true, a refined bulk mixed layer is used with
85  ! GV%nk_rho_varies variable density mixed & buffer
86  ! layers.
87  real :: fluxri_max ! The flux Richardson number where the stratification is
88  ! large enough that N2 > omega2. The full expression for
89  ! the Flux Richardson number is usually
90  ! FLUX_RI_MAX*N2/(N2+OMEGA2). The default is 0.2.
91  logical :: henyey_igw_background ! If true, use a simplified variant of the
92  ! Henyey et al, JGR (1986) latitudinal scaling for
93  ! the background diapycnal diffusivity, which gives
94  ! a marked decrease in the diffusivity near the
95  ! equator. The simplification here is to assume
96  ! that the in-situ stratification is the same as
97  ! the reference stratificaiton.
98  logical :: henyey_igw_background_new ! same as Henyey_IGW_background
99  ! but incorporate the effect of
100  ! stratification on TKE dissipation,
101  !
102  ! e = f/f_0 * acosh(N/f) / acosh(N_0/f_0) * e_0
103  !
104  ! where e is the TKE dissipation, and N_0 and f_0 are the
105  ! reference buoyancy frequency and inertial frequencies respectively.
106  ! e_0 is the reference dissipation at (N_0,f_0). In the
107  ! previous version, N=N_0.
108  !
109  ! Additionally, the squared inverse relationship between
110  ! diapycnal diffusivities and stratification is included
111  !
112  ! kd = e/N^2
113  !
114  ! where kd is the diapycnal diffusivity.
115  ! This approach assumes that work done
116  ! against gravity is uniformly distributed
117  ! throughout the column. Whereas, kd=kd_0*e,
118  ! as in the original version, concentrates buoyancy
119  ! work in regions of strong stratification.
120 
121  logical :: kd_tanh_lat_fn ! If true, use the tanh dependence of Kd_sfc on
122  ! latitude, like GFDL CM2.1/CM2M. There is no physical
123  ! justification for this form, and it can not be
124  ! used with Henyey_IGW_background.
125  real :: kd_tanh_lat_scale ! A nondimensional scaling for the range of
126  ! diffusivities with Kd_tanh_lat_fn. Valid values
127  ! are in the range of -2 to 2; 0.4 reproduces CM2M.
128 
129  logical :: bottomdraglaw ! If true, the bottom stress is calculated with a
130  ! drag law c_drag*|u|*u.
131  logical :: bbl_mixing_as_max ! If true, take the maximum of the diffusivity
132  ! from the BBL mixing and the other diffusivities.
133  ! Otherwise, diffusivities from the BBL_mixing is
134  ! added.
135  logical :: use_lotw_bbl_diffusivity ! If true, use simpler/less precise, BBL diffusivity.
136  logical :: lotw_bbl_use_omega ! If true, use simpler/less precise, BBL diffusivity.
137  real :: bbl_effic ! efficiency with which the energy extracted
138  ! by bottom drag drives BBL diffusion (nondim)
139  real :: cdrag ! quadratic drag coefficient (nondim)
140  real :: imax_decay ! inverse of a maximum decay scale for
141  ! bottom-drag driven turbulence, (1/m)
142 
143  real :: kd ! interior diapycnal diffusivity (m2/s)
144  real :: kd_min ! minimum diapycnal diffusivity (m2/s)
145  real :: kd_max ! maximum increment for diapycnal diffusivity (m2/s)
146  ! Set to a negative value to have no limit.
147  real :: kd_add ! uniform diffusivity added everywhere without
148  ! filtering or scaling (m2/s)
149  real :: kv ! interior vertical viscosity (m2/s)
150  real :: kdml ! mixed layer diapycnal diffusivity (m2/s)
151  ! when bulkmixedlayer==.false.
152  real :: hmix ! mixed layer thickness (meter) when
153  ! bulkmixedlayer==.false.
154 
155  logical :: bryan_lewis_diffusivity ! If true, background vertical diffusivity
156  ! uses Bryan-Lewis (1979) like tanh profile.
157  real :: kd_bryan_lewis_deep ! abyssal value of Bryan-Lewis profile (m2/s)
158  real :: kd_bryan_lewis_surface ! surface value of Bryan-Lewis profile (m2/s)
159  real :: bryan_lewis_depth_cent ! center of transition depth in Bryan-Lewis (meter)
160  real :: bryan_lewis_width_trans ! width of transition for Bryan-Lewis (meter)
161 
162  real :: n0_2omega ! ratio of the typical Buoyancy frequency to
163  ! twice the Earth's rotation period, used with the
164  ! Henyey scaling from the mixing
165  real :: n2_floor_iomega2 ! floor applied to N2(k) scaled by Omega^2
166  ! If =0., N2(k) is positive definite
167  ! If =1., N2(k) > Omega^2 everywhere
168 
169  type(diag_ctrl), pointer :: diag ! structure to regulate diagn output timing
170 
171  real :: int_tide_decay_scale ! decay scale for internal wave TKE (meter)
172  real :: mu_itides ! efficiency for conversion of dissipation
173  ! to potential energy (nondimensional)
174  real :: gamma_itides ! fraction of local dissipation (nondimensional)
175  real :: gamma_lee ! fraction of local dissipation for lee waves
176  ! (Nikurashin's energy input) (nondimensional)
177  real :: decay_scale_factor_lee ! Scaling factor for the decay scale of lee
178  ! wave energy dissipation (nondimensional)
179  real :: min_zbot_itides ! minimum depth for internal tide conversion (meter)
180  logical :: int_tide_dissipation ! Internal tide conversion (from barotropic) with
181  ! the schemes of St Laurent et al (2002)/
182  ! Simmons et al (2004)
183  logical :: lowmode_itidal_dissipation ! Internal tide conversion (from low modes) with
184  ! the schemes of St Laurent et al (2002)/
185  ! Simmons et al (2004) !BDM
186  integer :: int_tide_profile ! A coded integer indicating the vertical profile
187  ! for dissipation of the internal waves. Schemes that
188  ! are currently encoded are St Laurent et al (2002) and
189  ! Polzin (2009).
190  real :: nu_polzin ! The non-dimensional constant used in Polzin form of
191  ! the vertical scale of decay of tidal dissipation
192  real :: nbotref_polzin ! Reference value for the buoyancy frequency at the
193  ! ocean bottom used in Polzin formulation of the
194  ! vertical scale of decay of tidal dissipation (1/s)
195  real :: polzin_decay_scale_factor ! Scaling factor for the decay length scale
196  ! of the tidal dissipation profile in Polzin
197  ! (nondimensional)
198  real :: polzin_decay_scale_max_factor ! The decay length scale of tidal
199  ! dissipation profile in Polzin formulation should not
200  ! exceed Polzin_decay_scale_max_factor * depth of the
201  ! ocean (nondimensional).
202  real :: polzin_min_decay_scale ! minimum decay scale of the tidal dissipation
203  ! profile in Polzin formulation (meter)
204  logical :: lee_wave_dissipation ! Enable lee-wave driven mixing, following
205  ! Nikurashin (2010), with a vertical energy
206  ! deposition profile specified by Lee_wave_profile.
207  ! St Laurent et al (2002) or
208  ! Simmons et al (2004) scheme
209  integer :: lee_wave_profile ! A coded integer indicating the vertical profile
210  ! for dissipation of the lee waves. Schemes that are
211  ! currently encoded are St Laurent et al (2002) and
212  ! Polzin (2009).
213  logical :: limit_dissipation ! If enabled, dissipation is limited to be larger
214  ! than the following:
215  real :: dissip_min ! Minimum dissipation (W/m3)
216  real :: dissip_n0 ! Coefficient a in minimum dissipation = a+b*N (W/m3)
217  real :: dissip_n1 ! Coefficient b in minimum dissipation = a+b*N (J/m3)
218  real :: dissip_n2 ! Coefficient c in minimum dissipation = c*N2 (W m-3 s2)
219  real :: dissip_kd_min ! Minimum Kd (m2/s) with dissipatio Rho0*Kd_min*N^2
220 
221  real :: tke_itide_max ! maximum internal tide conversion (W m-2)
222  ! available to mix above the BBL
223  real :: omega ! Earth's rotation frequency (s-1)
224  real :: utide ! constant tidal amplitude (m s-1) used if
225  ! tidal amplitude file is not present
226  real :: kappa_itides ! topographic wavenumber and non-dimensional scaling
227  real :: kappa_h2_factor ! factor for the product of wavenumber * rms sgs height
228  logical :: ml_radiation ! allow a fraction of TKE available from wind work
229  ! to penetrate below mixed layer base with a vertical
230  ! decay scale determined by the minimum of
231  ! (1) The depth of the mixed layer, or
232  ! (2) An Ekman length scale.
233  ! Energy availble to drive mixing below the mixed layer is
234  ! given by E = ML_RAD_COEFF*MSTAR*USTAR**3. Optionally, if
235  ! ML_rad_TKE_decay is true, this is further reduced by a factor
236  ! of exp(-h_ML*Idecay_len_TkE), where Idecay_len_TKE is
237  ! calculated the same way as in the mixed layer code.
238  ! The diapycnal diffusivity is KD(k) = E/(N2(k)+OMEGA2),
239  ! where N2 is the squared buoyancy frequency (s-2) and OMEGA2
240  ! is the rotation rate of the earth squared.
241  real :: ml_rad_kd_max ! Maximum diapycnal diffusivity due to turbulence
242  ! radiated from the base of the mixed layer (m2/s)
243  real :: ml_rad_efold_coeff ! non-dim coefficient to scale penetration depth
244  real :: ml_rad_coeff ! coefficient, which scales MSTAR*USTAR^3 to
245  ! obtain energy available for mixing below
246  ! mixed layer base (nondimensional)
247  logical :: ml_rad_tke_decay ! If true, apply same exponential decay
248  ! to ML_rad as applied to the other surface
249  ! sources of TKE in the mixed layer code.
250  real :: ustar_min ! A minimum value of ustar to avoid numerical
251  ! problems (m/s). If the value is small enough,
252  ! this parameter should not affect the solution.
253  real :: tke_decay ! ratio of natural Ekman depth to TKE decay scale (nondim)
254  real :: mstar ! ratio of friction velocity cubed to
255  ! TKE input to the mixed layer (nondim)
256  logical :: ml_use_omega ! If true, use absolute rotation rate instead
257  ! of the vertical component of rotation when
258  ! setting the decay scale for mixed layer turbulence.
259  real :: ml_omega_frac ! When setting the decay scale for turbulence, use
260  ! this fraction of the absolute rotation rate blended
261  ! with the local value of f, as f^2 ~= (1-of)*f^2 + of*4*omega^2.
262  logical :: user_change_diff ! If true, call user-defined code to change diffusivity.
263  logical :: usekappashear ! If true, use the kappa_shear module to find the
264  ! shear-driven diapycnal diffusivity.
265 
266  logical :: usecvmix ! If true, use one of the CVMix modules to find
267  ! shear-driven diapycnal diffusivity.
268 
269  logical :: double_diffusion ! If true, enable double-diffusive mixing.
270  logical :: simple_tke_to_kd ! If true, uses a simple estimate of Kd/TKE that
271  ! does not rely on a layer-formulation.
272  real :: max_rrho_salt_fingers ! max density ratio for salt fingering
273  real :: max_salt_diff_salt_fingers ! max salt diffusivity for salt fingers (m2/s)
274  real :: kv_molecular ! molecular visc for double diff convect (m2/s)
275 
276  real, pointer, dimension(:,:) :: tke_niku => null()
277  real, pointer, dimension(:,:) :: tke_itidal => null()
278  real, pointer, dimension(:,:) :: nb => null()
279  real, pointer, dimension(:,:) :: mask_itidal => null()
280  real, pointer, dimension(:,:) :: h2 => null()
281  real, pointer, dimension(:,:) :: tideamp => null() ! RMS tidal amplitude (m/s)
282 
283  character(len=200) :: inputdir
284  type(user_change_diff_cs), pointer :: user_change_diff_csp => null()
285  type(diag_to_z_cs), pointer :: diag_to_z_csp => null()
286  type(kappa_shear_cs), pointer :: kappashear_csp => null()
287  type(cvmix_shear_cs), pointer :: cvmix_shear_csp => null()
288  type(int_tide_cs), pointer :: int_tide_csp => null()
289 
290  integer :: id_tke_itidal = -1
291  integer :: id_tke_leewave = -1
292  integer :: id_maxtke = -1
293  integer :: id_tke_to_kd = -1
294 
295  integer :: id_kd_itidal = -1
296  integer :: id_kd_niku = -1
297  integer :: id_kd_lowmode = -1
298  integer :: id_kd_user = -1
299  integer :: id_kd_layer = -1
300  integer :: id_kd_bbl = -1
301  integer :: id_kd_bbl_z = -1
302  integer :: id_kd_itidal_z = -1
303  integer :: id_kd_niku_z = -1
304  integer :: id_kd_lowmode_z = -1
305  integer :: id_kd_user_z = -1
306  integer :: id_kd_work = -1
307  integer :: id_kd_itidal_work = -1
308  integer :: id_kd_niku_work = -1
309  integer :: id_kd_lowmode_work= -1
310 
311  integer :: id_fl_itidal = -1
312  integer :: id_fl_lowmode = -1
313  integer :: id_polzin_decay_scale = -1
314  integer :: id_polzin_decay_scale_scaled = -1
315 
316  integer :: id_nb = -1
317  integer :: id_n2 = -1
318  integer :: id_n2_z = -1
319  integer :: id_n2_bot = -1
320  integer :: id_n2_meanz = -1
321 
322  integer :: id_kt_extra = -1
323  integer :: id_ks_extra = -1
324  integer :: id_kt_extra_z = -1
325  integer :: id_ks_extra_z = -1
326 
327 end type set_diffusivity_cs
328 
330  real, pointer, dimension(:,:,:) :: &
331  n2_3d => null(),& ! squared buoyancy frequency at interfaces (1/s2)
332  kd_itidal => null(),& ! internal tide diffusivity at interfaces (m2/s)
333  fl_itidal => null(),& ! vertical flux of tidal turbulent dissipation (m3/s3)
334  kd_lowmode => null(),& ! internal tide diffusivity at interfaces
335  ! due to propagating low modes (m2/s) (BDM)
336  fl_lowmode => null(),& ! vertical flux of tidal turbulent dissipation
337  ! due to propagating low modes (m3/s3) (BDM)
338  kd_niku => null(),& ! lee-wave diffusivity at interfaces (m2/s)
339  kd_user => null(),& ! user-added diffusivity at interfaces (m2/s)
340  kd_bbl => null(),& ! BBL diffusivity at interfaces (m2/s)
341  kd_work => null(),& ! layer integrated work by diapycnal mixing (W/m2)
342  kd_niku_work => null(),& ! layer integrated work by lee-wave driven mixing (W/m2)
343  kd_itidal_work => null(),& ! layer integrated work by int tide driven mixing (W/m2)
344  kd_lowmode_work=> null(),& ! layer integrated work by low mode driven mixing (W/m2) BDM
345  maxtke => null(),& ! energy required to entrain to h_max (m3/s3)
346  tke_to_kd => null(),& ! conversion rate (~1.0 / (G_Earth + dRho_lay))
347  ! between TKE dissipated within a layer and Kd
348  ! in that layer, in m2 s-1 / m3 s-3 = s2 m-1
349  kt_extra => null(),& ! double diffusion diffusivity for temp (m2/s)
350  ks_extra => null() ! double diffusion diffusivity for saln (m2/s)
351 
352  real, pointer, dimension(:,:) :: &
353  tke_itidal_used => null(),& ! internal tide TKE input at ocean bottom (W/m2)
354  n2_bot => null(),& ! bottom squared buoyancy frequency (1/s2)
355  n2_meanz => null(),& ! vertically averaged buoyancy frequency (1/s2)
356  polzin_decay_scale_scaled => null(),& ! vertical scale of decay for tidal dissipation
357  polzin_decay_scale => null() ! vertical decay scale for tidal diss with Polzin (meter)
358 
359 end type diffusivity_diags
360 
361 character*(20), parameter :: stlaurent_profile_string = "STLAURENT_02"
362 character*(20), parameter :: polzin_profile_string = "POLZIN_09"
363 integer, parameter :: stlaurent_02 = 1
364 integer, parameter :: polzin_09 = 2
365 
366 ! Clocks
368 
369 contains
370 
371 subroutine set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, optics, visc, dt, &
372  G, GV, CS, Kd, Kd_int)
373  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
374  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
375  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
376  intent(in) :: u !< The zonal velocity, in m s-1.
377  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
378  intent(in) :: v !< The meridional velocity, in m s-1.
379  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
380  intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2).
381  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
382  intent(in) :: u_h
383  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
384  intent(in) :: v_h
385  type(thermo_var_ptrs), intent(inout) :: tv !< Structure with pointers to thermodynamic
386  !! fields. Out is for tv%TempxPmE.
387  type(forcing), intent(in) :: fluxes !< Structure of surface fluxes that may be
388  !! used.
389  type(optics_type), pointer :: optics
390  type(vertvisc_type), intent(inout) :: visc !< Structure containing vertical viscosities,
391  !! bottom boundary layer properies, and related
392  !! fields.
393  real, intent(in) :: dt !< Time increment (sec).
394  type(set_diffusivity_cs), pointer :: CS !< Module control structure.
395  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
396  intent(out) :: Kd !< Diapycnal diffusivity of each layer (m2/sec).
397  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), &
398  optional, intent(out) :: Kd_int !< Diapycnal diffusivity at each interface
399  !! (m2/sec).
400 
401 ! Arguments:
402 ! (in) u - zonal velocity (m/s)
403 ! (in) v - meridional velocity (m/s)
404 ! (in) h - Layer thickness (m or kg/m2)
405 ! (in) tv - structure with pointers to thermodynamic fields
406 ! (in) fluxes - structure of surface fluxes that may be used
407 ! (in) visc - structure containing vertical viscosities, bottom boundary
408 ! layer properies, and related fields
409 ! (in) dt - time increment (sec)
410 ! (in) G - ocean grid structure
411 ! (in) GV - The ocean's vertical grid structure.
412 ! (in) CS - module control structure
413 ! (in) j - meridional index upon which to work
414 ! (out) Kd - diapycnal diffusivity of each layer (m2/sec)
415 ! (out,opt) Kd_int - diapycnal diffusivity at each interface (m2/sec)
416 
417  real, dimension(SZI_(G)) :: &
418  depth, & ! distance from surface of an interface (meter)
419  N2_bot ! bottom squared buoyancy frequency (1/s2)
420  real, dimension(SZI_(G), SZJ_(G)) :: &
421  Kd_sfc ! surface value of the diffusivity (m2/s)
422 
423  type(diffusivity_diags) :: dd ! structure w/ arrays of pointers to avail diags
424 
425  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
426  T_f, S_f ! temperature and salinity (deg C and ppt);
427  ! massless layers filled vertically by diffusion.
428 
429  real, dimension(SZI_(G),SZK_(G)) :: &
430  N2_lay, & ! squared buoyancy frequency associated with layers (1/s2)
431  maxTKE, & ! energy required to entrain to h_max (m3/s3)
432  TKE_to_Kd ! conversion rate (~1.0 / (G_Earth + dRho_lay)) between
433  ! TKE dissipated within a layer and Kd in that layer, in
434  ! m2 s-1 / m3 s-3 = s2 m-1.
435 
436  real, dimension(SZI_(G),SZK_(G)+1) :: &
437  N2_int, & ! squared buoyancy frequency associated at interfaces (1/s2)
438  dRho_int, & ! locally ref potential density difference across interfaces (in s-2) smg: or kg/m3?
439  KT_extra, & ! double difusion diffusivity on temperature (m2/sec)
440  KS_extra ! double difusion diffusivity on salinity (m2/sec)
441 
442  real :: I_trans ! inverse of the transitional for Bryan-Lewis (1/m)
443  real :: depth_c ! depth of the center of a layer (meter)
444  real :: I_Hmix ! inverse of fixed mixed layer thickness (1/m)
445  real :: I_Rho0 ! inverse of Boussinesq density (m3/kg)
446  real :: I_x30 ! 2/acos(2) = 1/(sin(30 deg) * acosh(1/sin(30 deg)))
447  real :: abs_sin ! absolute value of sine of latitude (nondim)
448  real :: atan_fn_sfc ! surface value of Bryan-Lewis profile (nondim)
449  real :: atan_fn_lay ! value of Bryan-Lewis profile in layer middle (nondim)
450  real :: I_atan_fn ! inverse of change in Bryan-Lewis profile from surface to infinite depth (nondim)
451  real :: deg_to_rad ! factor converting degrees to radians, pi/180.
452  real :: dissip ! local variable for dissipation calculations (W/m3)
453  real :: Omega2 ! squared absolute rotation rate (1/s2)
454  real :: I_2Omega ! 1/(2 Omega) (sec)
455  real :: N_2Omega
456  real :: N02_N2
457  real :: epsilon
458 
459  logical :: use_EOS ! If true, compute density from T/S using equation of state.
460  type(p3d) :: z_ptrs(6) ! pointers to diagns to be interpolated into depth space
461  integer :: kb(szi_(g)) ! The index of the lightest layer denser than the
462  ! buffer layer.
463  integer :: num_z_diags ! number of diagns to be interpolated to depth space
464  integer :: z_ids(6) ! id numbers of diagns to be interpolated to depth space
465  logical :: showCallTree ! If true, show the call tree.
466 
467  integer :: i, j, k, is, ie, js, je, nz
468  integer :: isd, ied, jsd, jed
469 
470  real :: kappa_fill ! diffusivity used to fill massless layers
471  real :: dt_fill ! timestep used to fill massless layers
472 
473  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
474  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
475  showcalltree = calltree_showquery()
476  if (showcalltree) call calltree_enter("set_diffusivity(), MOM_set_diffusivity.F90")
477 
478  if (.not.associated(cs)) call mom_error(fatal,"set_diffusivity: "//&
479  "Module must be initialized before it is used.")
480 
481  i_rho0 = 1.0/gv%Rho0
482  kappa_fill = 1.e-3 ! m2 s-1
483  dt_fill = 7200.
484  deg_to_rad = atan(1.0)/45.0 ! = PI/180
485  omega2 = cs%Omega*cs%Omega
486  i_2omega = 0.5/cs%Omega
487  epsilon = 1.e-10
488 
489  use_eos = associated(tv%eqn_of_state)
490 
491  if ((cs%double_diffusion) .and. &
492  .not.(associated(visc%Kd_extra_T) .and. associated(visc%Kd_extra_S)) ) &
493  call mom_error(fatal, "set_diffusivity: visc%Kd_extra_T and "//&
494  "visc%Kd_extra_S must be associated when DOUBLE_DIFFUSION is true.")
495 
496  ! Set up arrays for diagnostics.
497 
498  if ((cs%id_N2 > 0) .or. (cs%id_N2_z > 0)) then
499  allocate(dd%N2_3d(isd:ied,jsd:jed,nz+1)) ; dd%N2_3d(:,:,:) = 0.0
500  endif
501  if ((cs%id_Kd_itidal > 0) .or. (cs%id_Kd_itidal_z > 0) .or. &
502  (cs%id_Kd_Itidal_work > 0)) then
503  allocate(dd%Kd_itidal(isd:ied,jsd:jed,nz+1)) ; dd%Kd_itidal(:,:,:) = 0.0
504  endif
505  if ((cs%id_Kd_lowmode > 0) .or. (cs%id_Kd_lowmode_z > 0) .or. &
506  (cs%id_Kd_lowmode_work > 0)) then
507  allocate(dd%Kd_lowmode(isd:ied,jsd:jed,nz+1)) ; dd%Kd_lowmode(:,:,:) = 0.0
508  endif
509  if ( (cs%id_Fl_itidal > 0) ) then
510  allocate(dd%Fl_itidal(isd:ied,jsd:jed,nz+1)) ; dd%Fl_itidal(:,:,:) = 0.0
511  endif
512  if ( (cs%id_Fl_lowmode > 0) ) then
513  allocate(dd%Fl_lowmode(isd:ied,jsd:jed,nz+1)) ; dd%Fl_lowmode(:,:,:) = 0.0
514  endif
515  if ( (cs%id_Polzin_decay_scale > 0) ) then
516  allocate(dd%Polzin_decay_scale(isd:ied,jsd:jed))
517  dd%Polzin_decay_scale(:,:) = 0.0
518  endif
519  if ( (cs%id_Polzin_decay_scale_scaled > 0) ) then
520  allocate(dd%Polzin_decay_scale_scaled(isd:ied,jsd:jed))
521  dd%Polzin_decay_scale_scaled(:,:) = 0.0
522  endif
523  if ( (cs%id_N2_bot > 0) ) then
524  allocate(dd%N2_bot(isd:ied,jsd:jed)) ; dd%N2_bot(:,:) = 0.0
525  endif
526  if ( (cs%id_N2_meanz > 0) ) then
527  allocate(dd%N2_meanz(isd:ied,jsd:jed)) ; dd%N2_meanz(:,:) = 0.0
528  endif
529  if ((cs%id_Kd_Niku > 0) .or. (cs%id_Kd_Niku_z > 0) .or. &
530  (cs%id_Kd_Niku_work > 0)) then
531  allocate(dd%Kd_Niku(isd:ied,jsd:jed,nz+1)) ; dd%Kd_Niku(:,:,:) = 0.0
532  endif
533  if ((cs%id_Kd_user > 0) .or. (cs%id_Kd_user_z > 0)) then
534  allocate(dd%Kd_user(isd:ied,jsd:jed,nz+1)) ; dd%Kd_user(:,:,:) = 0.0
535  endif
536  if (cs%id_Kd_work > 0) then
537  allocate(dd%Kd_work(isd:ied,jsd:jed,nz)) ; dd%Kd_work(:,:,:) = 0.0
538  endif
539  if (cs%id_Kd_Niku_work > 0) then
540  allocate(dd%Kd_Niku_work(isd:ied,jsd:jed,nz)) ; dd%Kd_Niku_work(:,:,:) = 0.0
541  endif
542  if (cs%id_Kd_Itidal_work > 0) then
543  allocate(dd%Kd_Itidal_work(isd:ied,jsd:jed,nz))
544  dd%Kd_Itidal_work(:,:,:) = 0.0
545  endif
546  if (cs%id_Kd_Lowmode_Work > 0) then
547  allocate(dd%Kd_Lowmode_Work(isd:ied,jsd:jed,nz))
548  dd%Kd_Lowmode_Work(:,:,:) = 0.0
549  endif
550  if (cs%id_TKE_itidal > 0) then
551  allocate(dd%TKE_Itidal_used(isd:ied,jsd:jed)) ; dd%TKE_Itidal_used(:,:) = 0.
552  endif
553  if (cs%id_maxTKE > 0) then
554  allocate(dd%maxTKE(isd:ied,jsd:jed,nz)) ; dd%maxTKE(:,:,:) = 0.0
555  endif
556  if (cs%id_TKE_to_Kd > 0) then
557  allocate(dd%TKE_to_Kd(isd:ied,jsd:jed,nz)) ; dd%TKE_to_Kd(:,:,:) = 0.0
558  endif
559  if ((cs%id_KT_extra > 0) .or. (cs%id_KT_extra_z > 0)) then
560  allocate(dd%KT_extra(isd:ied,jsd:jed,nz+1)) ; dd%KT_extra(:,:,:) = 0.0
561  endif
562  if ((cs%id_KS_extra > 0) .or. (cs%id_KS_extra_z > 0)) then
563  allocate(dd%KS_extra(isd:ied,jsd:jed,nz+1)) ; dd%KS_extra(:,:,:) = 0.0
564  endif
565  if ((cs%id_Kd_BBL > 0) .or. (cs%id_Kd_BBL_z > 0)) then
566  allocate(dd%Kd_BBL(isd:ied,jsd:jed,nz+1)) ; dd%Kd_BBL(:,:,:) = 0.0
567  endif
568 
569  ! Smooth the properties through massless layers.
570  if (use_eos) then
571  if (cs%debug) then
572  call hchksum(tv%T, "before vert_fill_TS tv%T",g%HI)
573  call hchksum(tv%S, "before vert_fill_TS tv%S",g%HI)
574  call hchksum(h, "before vert_fill_TS h",g%HI, scale=gv%H_to_m)
575  endif
576  call vert_fill_ts(h, tv%T, tv%S, kappa_fill, dt_fill, t_f, s_f, g, gv)
577  if (cs%debug) then
578  call hchksum(tv%T, "after vert_fill_TS tv%T",g%HI)
579  call hchksum(tv%S, "after vert_fill_TS tv%S",g%HI)
580  call hchksum(h, "after vert_fill_TS h",g%HI, scale=gv%H_to_m)
581  endif
582  endif
583 
584  if (cs%useKappaShear) then
585  if (cs%debug) then
586  call hchksum(u_h, "before calc_KS u_h",g%HI)
587  call hchksum(v_h, "before calc_KS v_h",g%HI)
588  endif
589  call cpu_clock_begin(id_clock_kappashear)
590  ! Changes: visc%Kd_turb, visc%TKE_turb (not clear that TKE_turb is used as input ????)
591  ! Sets visc%Kv_turb
592  call calculate_kappa_shear(u_h, v_h, h, tv, fluxes%p_surf, visc%Kd_turb, visc%TKE_turb, &
593  visc%Kv_turb, dt, g, gv, cs%kappaShear_CSp)
594  call cpu_clock_end(id_clock_kappashear)
595  if (cs%debug) then
596  call hchksum(visc%Kd_turb, "after calc_KS visc%Kd_turb",g%HI)
597  call hchksum(visc%Kv_turb, "after calc_KS visc%Kv_turb",g%HI)
598  call hchksum(visc%TKE_turb, "after calc_KS visc%TKE_turb",g%HI)
599  endif
600  if (showcalltree) call calltree_waypoint("done with calculate_kappa_shear (set_diffusivity)")
601  elseif (cs%useCVMix) then
602  !NOTE{BGR}: this needs cleaned up. Works in 1D case, not tested outside.
603  call calculate_cvmix_shear(u_h, v_h, h, tv, visc%Kd_turb, visc%Kv_turb,g,gv,cs%CVMix_shear_CSp)
604  elseif (associated(visc%Kv_turb)) then
605  visc%Kv_turb(:,:,:) = 0. ! needed if calculate_kappa_shear is not enabled
606  endif
607 
608 ! Calculate the diffusivity, Kd, for each layer. This would be
609 ! the appropriate place to add a depth-dependent parameterization or
610 ! another explicit parameterization of Kd.
611 
612  if (cs%Bryan_Lewis_diffusivity) then
613 !$OMP parallel do default(none) shared(is,ie,js,je,CS,Kd_sfc)
614  do j=js,je ; do i=is,ie
615  kd_sfc(i,j) = cs%Kd_Bryan_Lewis_surface
616  enddo ; enddo
617  else
618 !$OMP parallel do default(none) shared(is,ie,js,je,CS,Kd_sfc)
619  do j=js,je ; do i=is,ie
620  kd_sfc(i,j) = cs%Kd
621  enddo ; enddo
622  endif
623  if (cs%Henyey_IGW_background) then
624  i_x30 = 2.0 / invcosh(cs%N0_2Omega*2.0) ! This is evaluated at 30 deg.
625 !$OMP parallel do default(none) shared(is,ie,js,je,Kd_sfc,CS,G,deg_to_rad,epsilon,I_x30) &
626 !$OMP private(abs_sin)
627  do j=js,je ; do i=is,ie
628  abs_sin = abs(sin(g%geoLatT(i,j)*deg_to_rad))
629  kd_sfc(i,j) = max(cs%Kd_min, kd_sfc(i,j) * &
630  ((abs_sin * invcosh(cs%N0_2Omega/max(epsilon,abs_sin))) * i_x30) )
631  enddo ; enddo
632  elseif (cs%Kd_tanh_lat_fn) then
633 !$OMP parallel do default(none) shared(is,ie,js,je,Kd_sfc,CS,G)
634  do j=js,je ; do i=is,ie
635  ! The transition latitude and latitude range are hard-scaled here, since
636  ! this is not really intended for wide-spread use, but rather for
637  ! comparison with CM2M / CM2.1 settings.
638  kd_sfc(i,j) = max(cs%Kd_min, kd_sfc(i,j) * (1.0 + &
639  cs%Kd_tanh_lat_scale * 0.5*tanh((abs(g%geoLatT(i,j)) - 35.0)/5.0) ))
640  enddo ; enddo
641  endif
642 
643  if (cs%debug) call hchksum(kd_sfc,"Kd_sfc",g%HI,haloshift=0)
644 !$OMP parallel do default(none) shared(is,ie,js,je,nz,G,GV,CS,h,tv,T_f,S_f,fluxes,dd, &
645 !$OMP Kd,Kd_sfc,epsilon,deg_to_rad,I_2Omega,visc, &
646 !$OMP Kd_int,dt,u,v,Omega2) &
647 !$OMP private(dRho_int,I_trans,atan_fn_sfc,I_atan_fn,atan_fn_lay, &
648 !$OMP I_Hmix,depth_c,depth,N2_lay, N2_int, N2_bot, &
649 !$OMP I_x30,abs_sin,N_2Omega,N02_N2,KT_extra, KS_extra, &
650 !$OMP TKE_to_Kd,maxTKE,dissip,kb)
651  do j=js,je
652  ! Set up variables related to the stratification.
653  call find_n2(h, tv, t_f, s_f, fluxes, j, g, gv, cs, drho_int, n2_lay, n2_int, n2_bot)
654  if (associated(dd%N2_3d)) then
655  do k=1,nz+1 ; do i=is,ie ; dd%N2_3d(i,j,k) = n2_int(i,k) ; enddo ; enddo
656  endif
657 
658  ! Set up the background diffusivity.
659  if (cs%Bryan_Lewis_diffusivity) then
660  i_trans = 1.0 / cs%Bryan_Lewis_width_trans
661  atan_fn_sfc = atan(cs%Bryan_Lewis_depth_cent*i_trans)
662  i_atan_fn = 1.0 / (2.0*atan(1.0) + atan_fn_sfc)
663  do i=is,ie ; depth(i) = 0.0 ; enddo
664  do k=1,nz ; do i=is,ie
665  atan_fn_lay = atan((cs%Bryan_Lewis_depth_cent - &
666  (depth(i)+0.5*gv%H_to_m*h(i,j,k)))*i_trans)
667  kd(i,j,k) = kd_sfc(i,j) + (cs%Kd_Bryan_Lewis_deep - kd_sfc(i,j)) * &
668  (atan_fn_sfc - atan_fn_lay) * i_atan_fn
669  depth(i) = depth(i) + gv%H_to_m*h(i,j,k)
670  enddo ; enddo
671  elseif ((.not.cs%bulkmixedlayer) .and. (cs%Kd /= cs%Kdml)) then
672  i_hmix = 1.0 / cs%Hmix
673  do i=is,ie ; depth(i) = 0.0 ; enddo
674  do k=1,nz ; do i=is,ie
675  depth_c = depth(i) + 0.5*gv%H_to_m*h(i,j,k)
676 
677  if (depth_c <= cs%Hmix) then ; kd(i,j,k) = cs%Kdml
678  elseif (depth_c >= 2.0*cs%Hmix) then ; kd(i,j,k) = kd_sfc(i,j)
679  else
680  kd(i,j,k) = ((kd_sfc(i,j) - cs%Kdml) * i_hmix) * depth_c + &
681  (2.0*cs%Kdml - kd_sfc(i,j))
682  endif
683 
684  depth(i) = depth(i) + gv%H_to_m*h(i,j,k)
685  enddo ; enddo
686  elseif (cs%Henyey_IGW_background_new) then
687  i_x30 = 2.0 / invcosh(cs%N0_2Omega*2.0) ! This is evaluated at 30 deg.
688  do k=1,nz ; do i=is,ie
689  abs_sin = max(epsilon,abs(sin(g%geoLatT(i,j)*deg_to_rad)))
690  n_2omega = max(abs_sin,sqrt(n2_lay(i,k))*i_2omega)
691  n02_n2 = (cs%N0_2Omega/n_2omega)**2
692  kd(i,j,k) = max(cs%Kd_min, kd_sfc(i,j) * &
693  ((abs_sin * invcosh(n_2omega/abs_sin)) * i_x30)*n02_n2)
694  enddo ; enddo
695  else
696  do k=1,nz ; do i=is,ie
697  kd(i,j,k) = kd_sfc(i,j)
698  enddo ; enddo
699  endif
700 
701  if (cs%double_diffusion) then
702  call double_diffusion(tv, h, t_f, s_f, j, g, gv, cs, kt_extra, ks_extra)
703  do k=2,nz ; do i=is,ie
704  if (ks_extra(i,k) > kt_extra(i,k)) then ! salt fingering
705  kd(i,j,k-1) = kd(i,j,k-1) + 0.5*kt_extra(i,k)
706  kd(i,j,k) = kd(i,j,k) + 0.5*kt_extra(i,k)
707  visc%Kd_extra_S(i,j,k) = ks_extra(i,k)-kt_extra(i,k)
708  visc%Kd_extra_T(i,j,k) = 0.0
709  elseif (kt_extra(i,k) > 0.0) then ! double-diffusive convection
710  kd(i,j,k-1) = kd(i,j,k-1) + 0.5*ks_extra(i,k)
711  kd(i,j,k) = kd(i,j,k) + 0.5*ks_extra(i,k)
712  visc%Kd_extra_T(i,j,k) = kt_extra(i,k)-ks_extra(i,k)
713  visc%Kd_extra_S(i,j,k) = 0.0
714  else ! There is no double diffusion at this interface.
715  visc%Kd_extra_T(i,j,k) = 0.0
716  visc%Kd_extra_S(i,j,k) = 0.0
717  endif
718  enddo; enddo
719  if (associated(dd%KT_extra)) then ; do k=1,nz+1 ; do i=is,ie
720  dd%KT_extra(i,j,k) = kt_extra(i,k)
721  enddo ; enddo ; endif
722 
723  if (associated(dd%KS_extra)) then ; do k=1,nz+1 ; do i=is,ie
724  dd%KS_extra(i,j,k) = ks_extra(i,k)
725  enddo ; enddo ; endif
726  endif
727 
728  ! Add the input turbulent diffusivity.
729  if (cs%useKappaShear .or. cs%useCVMix) then
730  if (present(kd_int)) then
731  do k=2,nz ; do i=is,ie
732  kd_int(i,j,k) = visc%Kd_turb(i,j,k) + 0.5*(kd(i,j,k-1) + kd(i,j,k))
733  enddo ; enddo
734  do i=is,ie
735  kd_int(i,j,1) = visc%Kd_turb(i,j,1) ! This isn't actually used. It could be 0.
736  kd_int(i,j,nz+1) = 0.0
737  enddo
738  endif
739  do k=1,nz ; do i=is,ie
740  kd(i,j,k) = kd(i,j,k) + 0.5*(visc%Kd_turb(i,j,k) + visc%Kd_turb(i,j,k+1))
741  enddo ; enddo
742  else
743  if (present(kd_int)) then
744  do i=is,ie
745  kd_int(i,j,1) = kd(i,j,1) ; kd_int(i,j,nz+1) = 0.0
746  enddo
747  do k=2,nz ; do i=is,ie
748  kd_int(i,j,k) = 0.5*(kd(i,j,k-1) + kd(i,j,k))
749  enddo ; enddo
750  endif
751  endif
752 
753  call find_tke_to_kd(h, tv, drho_int, n2_lay, j, dt, g, gv, cs, tke_to_kd, &
754  maxtke, kb)
755  if (associated(dd%maxTKE)) then ; do k=1,nz ; do i=is,ie
756  dd%maxTKE(i,j,k) = maxtke(i,k)
757  enddo ; enddo ; endif
758  if (associated(dd%TKE_to_Kd)) then ; do k=1,nz ; do i=is,ie
759  dd%TKE_to_Kd(i,j,k) = tke_to_kd(i,k)
760  enddo ; enddo ; endif
761 
762  ! Add the ML_Rad diffusivity.
763  if (cs%ML_radiation) &
764  call add_mlrad_diffusivity(h, fluxes, j, g, gv, cs, kd, tke_to_kd, kd_int)
765 
766  ! Add the Nikurashin and / or tidal bottom-driven mixing
767  if (cs%Int_tide_dissipation .or. cs%Lee_wave_dissipation .or. cs%Lowmode_itidal_dissipation) &
768  call add_int_tide_diffusivity(h, n2_bot, j, tke_to_kd, maxtke, g, gv, cs, &
769  dd, n2_lay, kd, kd_int)
770 
771  ! This adds the diffusion sustained by the energy extracted from the flow
772  ! by the bottom drag.
773  if (cs%bottomdraglaw .and. (cs%BBL_effic>0.0)) then
774  if (cs%use_LOTW_BBL_diffusivity) then
775  call add_lotw_bbl_diffusivity(h, u, v, tv, fluxes, visc, j, n2_int, g, gv, cs, &
776  kd, kd_int, dd%Kd_BBL)
777  else
778  call add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, tke_to_kd, &
779  maxtke, kb, g, gv, cs, kd, kd_int, dd%Kd_BBL)
780  endif
781  endif
782 
783  if (cs%limit_dissipation) then
784  do k=2,nz-1 ; do i=is,ie
785  ! This calculates the dissipation ONLY from Kd calculated in this routine
786  ! dissip has units of W/m3 (kg/m3 * m2/s * 1/s2 = J/s/m3)
787  ! 1) a global constant,
788  ! 2) a dissipation proportional to N (aka Gargett) and
789  ! 3) dissipation corresponding to a (nearly) constant diffusivity.
790  dissip = max( cs%dissip_min, & ! Const. floor on dissip.
791  cs%dissip_N0 + cs%dissip_N1 * sqrt(n2_lay(i,k)), & ! Floor aka Gargett
792  cs%dissip_N2 * n2_lay(i,k) ) ! Floor of Kd_min*rho0/F_Ri
793  kd(i,j,k) = max( kd(i,j,k) , & ! Apply floor to Kd
794  dissip * (cs%FluxRi_max / (gv%Rho0 * (n2_lay(i,k) + omega2))) )
795  enddo ; enddo
796 
797  if (present(kd_int)) then ; do k=2,nz ; do i=is,ie
798  ! This calculates the dissipation ONLY from Kd calculated in this routine
799  ! dissip has units of W/m3 (kg/m3 * m2/s * 1/s2 = J/s/m3)
800  ! 1) a global constant,
801  ! 2) a dissipation proportional to N (aka Gargett) and
802  ! 3) dissipation corresponding to a (nearly) constant diffusivity.
803  dissip = max( cs%dissip_min, & ! Const. floor on dissip.
804  cs%dissip_N0 + cs%dissip_N1 * sqrt(n2_int(i,k)), & ! Floor aka Gargett
805  cs%dissip_N2 * n2_int(i,k) ) ! Floor of Kd_min*rho0/F_Ri
806  kd_int(i,j,k) = max( kd_int(i,j,k) , & ! Apply floor to Kd
807  dissip * (cs%FluxRi_max / (gv%Rho0 * (n2_int(i,k) + omega2))) )
808  enddo ; enddo ; endif
809  endif
810 
811  if (associated(dd%Kd_work)) then
812  do k=1,nz ; do i=is,ie
813  dd%Kd_Work(i,j,k) = gv%Rho0 * kd(i,j,k) * n2_lay(i,k) * &
814  gv%H_to_m*h(i,j,k) ! Watt m-2 s or kg s-3
815  enddo ; enddo
816  endif
817  enddo ! j-loop
818 
819  if (cs%debug) then
820  call hchksum(kd,"BBL Kd",g%HI,haloshift=0)
821  if (cs%useKappaShear) call hchksum(visc%Kd_turb,"Turbulent Kd",g%HI,haloshift=0)
822  if (associated(visc%kv_bbl_u) .and. associated(visc%kv_bbl_v)) then
823  call uvchksum("BBL Kv_bbl_[uv]", visc%kv_bbl_u, visc%kv_bbl_v, &
824  g%HI, 0, symmetric=.true.)
825  endif
826  if (associated(visc%bbl_thick_u) .and. associated(visc%bbl_thick_v)) then
827  call uvchksum("BBL bbl_thick_[uv]", visc%bbl_thick_u, &
828  visc%bbl_thick_v, g%HI, 0, symmetric=.true.)
829  endif
830  if (associated(visc%Ray_u) .and. associated(visc%Ray_v)) then
831  call uvchksum("Ray_[uv]", visc%Ray_u, visc%Ray_v, g%HI, 0, symmetric=.true.)
832  endif
833  endif
834 
835  if (cs%Kd_add > 0.0) then
836  if (present(kd_int)) then
837 !$OMP parallel do default(none) shared(is,ie,js,je,nz,Kd_int,CS,Kd)
838  do k=1,nz ; do j=js,je ; do i=is,ie
839  kd_int(i,j,k) = kd_int(i,j,k) + cs%Kd_add
840  kd(i,j,k) = kd(i,j,k) + cs%Kd_add
841  enddo ; enddo ; enddo
842  else
843 !$OMP parallel do default(none) shared(is,ie,js,je,nz,CS,Kd)
844  do k=1,nz ; do j=js,je ; do i=is,ie
845  kd(i,j,k) = kd(i,j,k) + cs%Kd_add
846  enddo ; enddo ; enddo
847  endif
848  endif
849 
850  if (cs%user_change_diff) then
851  call user_change_diff(h, tv, g, cs%user_change_diff_CSp, kd, kd_int, &
852  t_f, s_f, dd%Kd_user)
853  endif
854 
855  if (cs%id_Kd_layer > 0) call post_data(cs%id_Kd_layer, kd, cs%diag)
856 
857  num_z_diags = 0
858  if (cs%Int_tide_dissipation .or. cs%Lee_wave_dissipation .or. cs%Lowmode_itidal_dissipation) then
859  if (cs%id_TKE_itidal > 0) call post_data(cs%id_TKE_itidal, dd%TKE_itidal_used, cs%diag)
860  if (cs%id_TKE_leewave > 0) call post_data(cs%id_TKE_leewave, cs%TKE_Niku, cs%diag)
861  if (cs%id_Nb > 0) call post_data(cs%id_Nb, cs%Nb, cs%diag)
862  if (cs%id_N2 > 0) call post_data(cs%id_N2, dd%N2_3d, cs%diag)
863  if (cs%id_N2_bot > 0) call post_data(cs%id_N2_bot, dd%N2_bot, cs%diag)
864  if (cs%id_N2_meanz > 0) call post_data(cs%id_N2_meanz,dd%N2_meanz,cs%diag)
865 
866  if (cs%id_Fl_itidal > 0) call post_data(cs%id_Fl_itidal, dd%Fl_itidal, cs%diag)
867  if (cs%id_Kd_itidal > 0) call post_data(cs%id_Kd_itidal, dd%Kd_itidal, cs%diag)
868  if (cs%id_Kd_Niku > 0) call post_data(cs%id_Kd_Niku, dd%Kd_Niku, cs%diag)
869  if (cs%id_Kd_lowmode> 0) call post_data(cs%id_Kd_lowmode, dd%Kd_lowmode, cs%diag)
870  if (cs%id_Fl_lowmode> 0) call post_data(cs%id_Fl_lowmode, dd%Fl_lowmode, cs%diag)
871  if (cs%id_Kd_user > 0) call post_data(cs%id_Kd_user, dd%Kd_user, cs%diag)
872  if (cs%id_Kd_Work > 0) call post_data(cs%id_Kd_Work, dd%Kd_Work, cs%diag)
873  if (cs%id_Kd_Itidal_Work > 0) &
874  call post_data(cs%id_Kd_Itidal_Work, dd%Kd_Itidal_Work, cs%diag)
875  if (cs%id_Kd_Niku_Work > 0) call post_data(cs%id_Kd_Niku_Work, dd%Kd_Niku_Work, cs%diag)
876  if (cs%id_Kd_Lowmode_Work > 0) &
877  call post_data(cs%id_Kd_Lowmode_Work, dd%Kd_Lowmode_Work, cs%diag)
878  if (cs%id_maxTKE > 0) call post_data(cs%id_maxTKE, dd%maxTKE, cs%diag)
879  if (cs%id_TKE_to_Kd > 0) call post_data(cs%id_TKE_to_Kd, dd%TKE_to_Kd, cs%diag)
880 
881  if (cs%id_Polzin_decay_scale > 0 ) &
882  call post_data(cs%id_Polzin_decay_scale, dd%Polzin_decay_scale, cs%diag)
883  if (cs%id_Polzin_decay_scale_scaled > 0 ) &
884  call post_data(cs%id_Polzin_decay_scale_scaled, dd%Polzin_decay_scale_scaled, cs%diag)
885 
886  if (cs%id_Kd_itidal_z > 0) then
887  num_z_diags = num_z_diags + 1
888  z_ids(num_z_diags) = cs%id_Kd_itidal_z
889  z_ptrs(num_z_diags)%p => dd%Kd_itidal
890  endif
891 
892  if (cs%id_Kd_Niku_z > 0) then
893  num_z_diags = num_z_diags + 1
894  z_ids(num_z_diags) = cs%id_Kd_Niku_z
895  z_ptrs(num_z_diags)%p => dd%Kd_Niku
896  endif
897 
898  if (cs%id_Kd_lowmode_z > 0) then
899  num_z_diags = num_z_diags + 1
900  z_ids(num_z_diags) = cs%id_Kd_lowmode_z
901  z_ptrs(num_z_diags)%p => dd%Kd_lowmode
902  endif
903 
904  if (cs%id_N2_z > 0) then
905  num_z_diags = num_z_diags + 1
906  z_ids(num_z_diags) = cs%id_N2_z
907  z_ptrs(num_z_diags)%p => dd%N2_3d
908  endif
909 
910  if (cs%id_Kd_user_z > 0) then
911  num_z_diags = num_z_diags + 1
912  z_ids(num_z_diags) = cs%id_Kd_user_z
913  z_ptrs(num_z_diags)%p => dd%Kd_user
914  endif
915 
916  endif
917 
918  if (cs%id_KT_extra > 0) call post_data(cs%id_KT_extra, dd%KT_extra, cs%diag)
919  if (cs%id_KS_extra > 0) call post_data(cs%id_KS_extra, dd%KS_extra, cs%diag)
920  if (cs%id_Kd_BBL > 0) call post_data(cs%id_Kd_BBL, dd%Kd_BBL, cs%diag)
921 
922  if (cs%id_KT_extra_z > 0) then
923  num_z_diags = num_z_diags + 1
924  z_ids(num_z_diags) = cs%id_KT_extra_z
925  z_ptrs(num_z_diags)%p => dd%KT_extra
926  endif
927 
928  if (cs%id_KS_extra_z > 0) then
929  num_z_diags = num_z_diags + 1
930  z_ids(num_z_diags) = cs%id_KS_extra_z
931  z_ptrs(num_z_diags)%p => dd%KS_extra
932  endif
933 
934  if (cs%id_Kd_BBL_z > 0) then
935  num_z_diags = num_z_diags + 1
936  z_ids(num_z_diags) = cs%id_Kd_BBL_z
937  z_ptrs(num_z_diags)%p => dd%KS_extra
938  endif
939 
940  if (num_z_diags > 0) &
941  call calc_zint_diags(h, z_ptrs, z_ids, num_z_diags, g, gv, cs%diag_to_Z_CSp)
942 
943  if (associated(dd%N2_3d)) deallocate(dd%N2_3d)
944  if (associated(dd%Kd_itidal)) deallocate(dd%Kd_itidal)
945  if (associated(dd%Kd_lowmode)) deallocate(dd%Kd_lowmode)
946  if (associated(dd%Fl_itidal)) deallocate(dd%Fl_itidal)
947  if (associated(dd%Fl_lowmode)) deallocate(dd%Fl_lowmode)
948  if (associated(dd%Polzin_decay_scale)) deallocate(dd%Polzin_decay_scale)
949  if (associated(dd%Polzin_decay_scale_scaled)) deallocate(dd%Polzin_decay_scale_scaled)
950  if (associated(dd%N2_bot)) deallocate(dd%N2_bot)
951  if (associated(dd%N2_meanz)) deallocate(dd%N2_meanz)
952  if (associated(dd%Kd_work)) deallocate(dd%Kd_work)
953  if (associated(dd%Kd_user)) deallocate(dd%Kd_user)
954  if (associated(dd%Kd_Niku)) deallocate(dd%Kd_Niku)
955  if (associated(dd%Kd_Niku_work)) deallocate(dd%Kd_Niku_work)
956  if (associated(dd%Kd_Itidal_Work)) deallocate(dd%Kd_Itidal_Work)
957  if (associated(dd%Kd_Lowmode_Work)) deallocate(dd%Kd_Lowmode_Work)
958  if (associated(dd%TKE_itidal_used)) deallocate(dd%TKE_itidal_used)
959  if (associated(dd%maxTKE)) deallocate(dd%maxTKE)
960  if (associated(dd%TKE_to_Kd)) deallocate(dd%TKE_to_Kd)
961  if (associated(dd%KT_extra)) deallocate(dd%KT_extra)
962  if (associated(dd%KS_extra)) deallocate(dd%KS_extra)
963  if (associated(dd%Kd_BBL)) deallocate(dd%Kd_BBL)
964 
965  if (showcalltree) call calltree_leave("set_diffusivity()")
966 
967 end subroutine set_diffusivity
968 
969 subroutine find_tke_to_kd(h, tv, dRho_int, N2_lay, j, dt, G, GV, CS, &
970  TKE_to_Kd, maxTKE, kb)
971  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
972  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
973  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
974  type(thermo_var_ptrs), intent(in) :: tv
975  real, dimension(SZI_(G),SZK_(G)+1), intent(in) :: dRho_int
976  real, dimension(SZI_(G),SZK_(G)), intent(in) :: N2_lay
977  integer, intent(in) :: j
978  real, intent(in) :: dt
979  type(set_diffusivity_cs), pointer :: CS
980  real, dimension(SZI_(G),SZK_(G)), intent(out) :: TKE_to_Kd, maxTKE
981  integer, dimension(SZI_(G)), intent(out) :: kb
982 
983  real, dimension(SZI_(G),SZK_(G)) :: &
984  ds_dsp1, & ! coordinate variable (sigma-2) difference across an
985  ! interface divided by the difference across the interface
986  ! below it (nondimensional)
987  dsp1_ds, & ! inverse coordinate variable (sigma-2) difference
988  ! across an interface times the difference across the
989  ! interface above it (nondimensional)
990  rho_0, & ! Layer potential densities relative to surface pressure (kg/m3)
991  maxent ! maxEnt is the maximum value of entrainment from below (with
992  ! compensating entrainment from above to keep the layer
993  ! density from changing) that will not deplete all of the
994  ! layers above or below a layer within a timestep (meter)
995  real, dimension(SZI_(G)) :: &
996  htot, & ! total thickness above or below a layer, or the
997  ! integrated thickness in the BBL (meter)
998  mfkb, & ! total thickness in the mixed and buffer layers
999  ! times ds_dsp1 (meter)
1000  p_ref, & ! array of tv%P_Ref pressures
1001  rcv_kmb, & ! coordinate density in the lowest buffer layer
1002  p_0 ! An array of 0 pressures
1003 
1004  real :: dh_max ! maximum amount of entrainment a layer could
1005  ! undergo before entraining all fluid in the layers
1006  ! above or below (meter)
1007  real :: dRho_lay ! density change across a layer (kg/m3)
1008  real :: Omega2 ! rotation rate squared (1/s2)
1009  real :: G_Rho0 ! gravitation accel divided by Bouss ref density (m4 s-2 kg-1)
1010  real :: I_Rho0 ! inverse of Boussinesq reference density (m3/kg)
1011  real :: I_dt ! 1/dt (1/sec)
1012  real :: H_neglect ! negligibly small thickness (units as h)
1013  real :: hN2pO2 ! h * (N^2 + Omega^2), in m s-2.
1014  logical :: do_i(szi_(g))
1015 
1016  integer :: i, k, is, ie, nz, i_rem, kmb, kb_min
1017  is = g%isc ; ie = g%iec ; nz = g%ke
1018 
1019  i_dt = 1.0/dt
1020  omega2 = cs%Omega**2
1021  g_rho0 = gv%g_Earth / gv%Rho0
1022  h_neglect = gv%H_subroundoff
1023  i_rho0 = 1.0/gv%Rho0
1024 
1025  ! Simple but coordinate-independent estimate of Kd/TKE
1026  if (cs%simple_TKE_to_Kd) then
1027  do k=1,nz ; do i=is,ie
1028  hn2po2 = ( gv%H_to_m * h(i,j,k) ) * ( n2_lay(i,k) + omega2 ) ! Units of m s-2.
1029  if (hn2po2>0.) then
1030  tke_to_kd(i,k) = 1./ hn2po2 ! Units of s2 m-1.
1031  else; tke_to_kd(i,k) = 0.; endif
1032  ! The maximum TKE conversion we allow is really a statement
1033  ! about the upper diffusivity we allow. Kd_max must be set.
1034  maxtke(i,k) = hn2po2 * cs%Kd_max ! Units of m3 s-3.
1035  enddo ; enddo
1036  kb(is:ie) = -1 ! kb should not be used by any code in non-layered mode -AJA
1037  return
1038  endif
1039 
1040  ! Determine kb - the index of the shallowest active interior layer.
1041  if (cs%bulkmixedlayer) then
1042  kmb = gv%nk_rho_varies
1043  do i=is,ie ; p_0(i) = 0.0 ; p_ref(i) = tv%P_Ref ; enddo
1044  do k=1,nz
1045  call calculate_density(tv%T(:,j,k),tv%S(:,j,k),p_0,rho_0(:,k),&
1046  is,ie-is+1,tv%eqn_of_state)
1047  enddo
1048  call calculate_density(tv%T(:,j,kmb),tv%S(:,j,kmb),p_ref,rcv_kmb,&
1049  is,ie-is+1,tv%eqn_of_state)
1050 
1051  kb_min = kmb+1
1052  do i=is,ie
1053  ! Determine the next denser layer than the buffer layer in the
1054  ! coordinate density (sigma-2).
1055  do k=kmb+1,nz-1 ; if (rcv_kmb(i) <= gv%Rlay(k)) exit ; enddo
1056  kb(i) = k
1057 
1058  ! Backtrack, in case there are massive layers above that are stable
1059  ! in sigma-0.
1060  do k=kb(i)-1,kmb+1,-1
1061  if (rho_0(i,kmb) > rho_0(i,k)) exit
1062  if (h(i,j,k)>2.0*gv%Angstrom) kb(i) = k
1063  enddo
1064  enddo
1065 
1066  call set_density_ratios(h, tv, kb, g, gv, cs, j, ds_dsp1, rho_0)
1067  else ! not bulkmixedlayer
1068  kb_min = 2 ; kmb = 0
1069  do i=is,ie ; kb(i) = 1 ; enddo
1070  call set_density_ratios(h, tv, kb, g, gv, cs, j, ds_dsp1)
1071  endif
1072 
1073  ! Determine maxEnt - the maximum permitted entrainment from below by each
1074  ! interior layer.
1075  do k=2,nz-1 ; do i=is,ie
1076  dsp1_ds(i,k) = 1.0 / ds_dsp1(i,k)
1077  enddo ; enddo
1078  do i=is,ie ; dsp1_ds(i,nz) = 0.0 ; enddo
1079 
1080  if (cs%bulkmixedlayer) then
1081  kmb = gv%nk_rho_varies
1082  do i=is,ie
1083  htot(i) = gv%H_to_m*h(i,j,kmb)
1084  mfkb(i) = 0.0
1085  if (kb(i) < nz) &
1086  mfkb(i) = ds_dsp1(i,kb(i)) * (gv%H_to_m*(h(i,j,kmb) - gv%Angstrom))
1087  enddo
1088  do k=1,kmb-1 ; do i=is,ie
1089  htot(i) = htot(i) + gv%H_to_m*h(i,j,k)
1090  mfkb(i) = mfkb(i) + ds_dsp1(i,k+1)*(gv%H_to_m*(h(i,j,k) - gv%Angstrom))
1091  enddo ; enddo
1092  else
1093  do i=is,i
1094  maxent(i,1) = 0.0 ; htot(i) = gv%H_to_m*(h(i,j,1) - gv%Angstrom)
1095  enddo
1096  endif
1097  do k=kb_min,nz-1 ; do i=is,ie
1098  if (k == kb(i)) then
1099  maxent(i,kb(i))= mfkb(i)
1100  elseif (k > kb(i)) then
1101  maxent(i,k) = (1.0/dsp1_ds(i,k))*(maxent(i,k-1) + htot(i))
1102 ! maxEnt(i,k) = ds_dsp1(i,k)*(maxEnt(i,k-1) + htot(i)) ! BITWISE CHG
1103  htot(i) = htot(i) + gv%H_to_m*(h(i,j,k) - gv%Angstrom)
1104  endif
1105  enddo ; enddo
1106 
1107  do i=is,ie
1108  htot(i) = gv%H_to_m*(h(i,j,nz) - gv%Angstrom) ; maxent(i,nz) = 0.0
1109  do_i(i) = (g%mask2dT(i,j) > 0.5)
1110  enddo
1111  do k=nz-1,kb_min,-1
1112  i_rem = 0
1113  do i=is,ie ; if (do_i(i)) then
1114  if (k<kb(i)) then ; do_i(i) = .false. ; cycle ; endif
1115  i_rem = i_rem + 1 ! Count the i-rows that are still being worked on.
1116  maxent(i,k) = min(maxent(i,k),dsp1_ds(i,k+1)*maxent(i,k+1) + htot(i))
1117  htot(i) = htot(i) + gv%H_to_m*(h(i,j,k) - gv%Angstrom)
1118  endif ; enddo
1119  if (i_rem == 0) exit
1120  enddo ! k-loop
1121 
1122  ! Now set maxTKE and TKE_to_Kd.
1123  do i=is,ie
1124  maxtke(i,1) = 0.0 ; tke_to_kd(i,1) = 0.0
1125  maxtke(i,nz) = 0.0 ; tke_to_kd(i,nz) = 0.0
1126  enddo
1127  do k=2,kmb ; do i=is,ie
1128  maxtke(i,k) = 0.0
1129  tke_to_kd(i,k) = 1.0 / ((n2_lay(i,k) + omega2) * &
1130  (gv%H_to_m*(h(i,j,k) + h_neglect)))
1131  enddo ; enddo
1132  do k=kmb+1,kb_min-1 ; do i=is,ie
1133  ! These are the properties in the deeper mixed and buffer layers, and
1134  ! should perhaps be revisited.
1135  maxtke(i,k) = 0.0 ; tke_to_kd(i,k) = 0.0
1136  enddo ; enddo
1137  do k=kb_min,nz-1 ; do i=is,ie
1138  if (k<kb(i)) then
1139  maxtke(i,k) = 0.0
1140  tke_to_kd(i,k) = 0.0
1141  else
1142  ! maxTKE is found by determining the kappa that gives maxEnt.
1143  ! ### This should be 1 / G_Earth * (delta rho_InSitu)
1144  ! kappa_max = I_dt * dRho_int(i,K+1) * maxEnt(i,k) * &
1145  ! (GV%H_to_m*h(i,j,k) + dh_max) / dRho_lay
1146  ! maxTKE(i,k) = GV%g_Earth * dRho_lay * kappa_max
1147  ! dRho_int should already be non-negative, so the max is redundant?
1148  dh_max = maxent(i,k) * (1.0 + dsp1_ds(i,k))
1149  drho_lay = 0.5 * max(drho_int(i,k) + drho_int(i,k+1), 0.0)
1150  maxtke(i,k) = i_dt * ((gv%g_Earth * i_rho0) * &
1151  (0.5*max(drho_int(i,k+1) + dsp1_ds(i,k)*drho_int(i,k),0.0))) * &
1152  ((gv%H_to_m*h(i,j,k) + dh_max) * maxent(i,k))
1153  tke_to_kd(i,k) = 1.0 / (g_rho0 * drho_lay + &
1154  cs%Omega**2 * gv%H_to_m*(h(i,j,k) + h_neglect))
1155  endif
1156  enddo ; enddo
1157 
1158 end subroutine find_tke_to_kd
1159 
1160 subroutine find_n2(h, tv, T_f, S_f, fluxes, j, G, GV, CS, dRho_int, &
1161  N2_lay, N2_int, N2_bot)
1162  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1163  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
1164  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
1165  type(thermo_var_ptrs), intent(in) :: tv
1166  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: T_f, S_f
1167  type(forcing), intent(in) :: fluxes
1168  integer, intent(in) :: j
1169  type(set_diffusivity_cs), pointer :: CS
1170  real, dimension(SZI_(G),SZK_(G)+1), intent(out) :: dRho_int, N2_int
1171  real, dimension(SZI_(G),SZK_(G)), intent(out) :: N2_lay
1172  real, dimension(SZI_(G)), intent(out) :: N2_bot
1173 
1174  real, dimension(SZI_(G),SZK_(G)+1) :: &
1175  dRho_int_unfilt, & ! unfiltered density differences across interfaces
1176  dRho_dT, & ! partial derivative of density wrt temp (kg m-3 degC-1)
1177  dRho_dS ! partial derivative of density wrt saln (kg m-3 PPT-1)
1178 
1179  real, dimension(SZI_(G)) :: &
1180  pres, & ! pressure at each interface (Pa)
1181  Temp_int, & ! temperature at each interface (degC)
1182  Salin_int, & ! salinity at each interface (PPT)
1183  drho_bot, &
1184  h_amp, &
1185  hb, &
1186  z_from_bot
1187 
1188  real :: Rml_base ! density of the deepest variable density layer
1189  real :: dz_int ! thickness associated with an interface (meter)
1190  real :: G_Rho0 ! gravitation acceleration divided by Bouss reference density (m4 s-2 kg-1)
1191  real :: H_neglect ! negligibly small thickness, in the same units as h.
1192 
1193  logical :: do_i(szi_(g)), do_any
1194  integer :: i, k, is, ie, nz
1195 
1196  is = g%isc ; ie = g%iec ; nz = g%ke
1197  g_rho0 = gv%g_Earth / gv%Rho0
1198  h_neglect = gv%H_subroundoff
1199 
1200  ! Find the (limited) density jump across each interface.
1201  do i=is,ie
1202  drho_int(i,1) = 0.0 ; drho_int(i,nz+1) = 0.0
1203  drho_int_unfilt(i,1) = 0.0 ; drho_int_unfilt(i,nz+1) = 0.0
1204  enddo
1205  if (associated(tv%eqn_of_state)) then
1206  if (associated(fluxes%p_surf)) then
1207  do i=is,ie ; pres(i) = fluxes%p_surf(i,j) ; enddo
1208  else
1209  do i=is,ie ; pres(i) = 0.0 ; enddo
1210  endif
1211  do k=2,nz
1212  do i=is,ie
1213  pres(i) = pres(i) + gv%H_to_Pa*h(i,j,k-1)
1214  temp_int(i) = 0.5 * (t_f(i,j,k) + t_f(i,j,k-1))
1215  salin_int(i) = 0.5 * (s_f(i,j,k) + s_f(i,j,k-1))
1216  enddo
1217  call calculate_density_derivs(temp_int, salin_int, pres, &
1218  drho_dt(:,k), drho_ds(:,k), is, ie-is+1, tv%eqn_of_state)
1219  do i=is,ie
1220  drho_int(i,k) = max(drho_dt(i,k)*(t_f(i,j,k) - t_f(i,j,k-1)) + &
1221  drho_ds(i,k)*(s_f(i,j,k) - s_f(i,j,k-1)), 0.0)
1222  drho_int_unfilt(i,k) = max(drho_dt(i,k)*(tv%T(i,j,k) - tv%T(i,j,k-1)) + &
1223  drho_ds(i,k)*(tv%S(i,j,k) - tv%S(i,j,k-1)), 0.0)
1224  enddo
1225  enddo
1226  else
1227  do k=2,nz ; do i=is,ie
1228  drho_int(i,k) = gv%Rlay(k) - gv%Rlay(k-1)
1229  enddo ; enddo
1230  endif
1231 
1232  ! Set the buoyancy frequencies.
1233  do k=1,nz ; do i=is,ie
1234  n2_lay(i,k) = g_rho0 * 0.5*(drho_int(i,k) + drho_int(i,k+1)) / &
1235  (gv%H_to_m*(h(i,j,k) + h_neglect))
1236  enddo ; enddo
1237  do i=is,ie ; n2_int(i,1) = 0.0 ; n2_int(i,nz+1) = 0.0 ; enddo
1238  do k=2,nz ; do i=is,ie
1239  n2_int(i,k) = g_rho0 * drho_int(i,k) / &
1240  (0.5*gv%H_to_m*(h(i,j,k-1) + h(i,j,k) + h_neglect))
1241  enddo ; enddo
1242 
1243  ! Find the bottom boundary layer stratification, and use this in the deepest layers.
1244  do i=is,ie
1245  hb(i) = 0.0 ; drho_bot(i) = 0.0
1246  z_from_bot(i) = 0.5*gv%H_to_m*h(i,j,nz)
1247  do_i(i) = (g%mask2dT(i,j) > 0.5)
1248 
1249  if (cs%Int_tide_dissipation .or. cs%Lee_wave_dissipation) then
1250  h_amp(i) = sqrt(cs%h2(i,j)) ! for computing Nb
1251  else
1252  h_amp(i) = 0.0
1253  endif
1254  enddo
1255 
1256  do k=nz,2,-1
1257  do_any = .false.
1258  do i=is,ie ; if (do_i(i)) then
1259  dz_int = 0.5*gv%H_to_m*(h(i,j,k) + h(i,j,k-1))
1260  z_from_bot(i) = z_from_bot(i) + dz_int ! middle of the layer above
1261 
1262  hb(i) = hb(i) + dz_int
1263  drho_bot(i) = drho_bot(i) + drho_int(i,k)
1264 
1265  if (z_from_bot(i) > h_amp(i)) then
1266  if (k>2) then
1267  ! Always include at least one full layer.
1268  hb(i) = hb(i) + 0.5*gv%H_to_m*(h(i,j,k-1) + h(i,j,k-2))
1269  drho_bot(i) = drho_bot(i) + drho_int(i,k-1)
1270  endif
1271  do_i(i) = .false.
1272  else
1273  do_any = .true.
1274  endif
1275  endif ; enddo
1276  if (.not.do_any) exit
1277  enddo
1278 
1279  do i=is,ie
1280  if (hb(i) > 0.0) then
1281  n2_bot(i) = (g_rho0 * drho_bot(i)) / hb(i)
1282  else ; n2_bot(i) = 0.0 ; endif
1283  z_from_bot(i) = 0.5*gv%H_to_m*h(i,j,nz)
1284  do_i(i) = (g%mask2dT(i,j) > 0.5)
1285  enddo
1286 
1287  do k=nz,2,-1
1288  do_any = .false.
1289  do i=is,ie ; if (do_i(i)) then
1290  dz_int = 0.5*gv%H_to_m*(h(i,j,k) + h(i,j,k-1))
1291  z_from_bot(i) = z_from_bot(i) + dz_int ! middle of the layer above
1292 
1293  n2_int(i,k) = n2_bot(i)
1294  if (k>2) n2_lay(i,k-1) = n2_bot(i)
1295 
1296  if (z_from_bot(i) > h_amp(i)) then
1297  if (k>2) n2_int(i,k-1) = n2_bot(i)
1298  do_i(i) = .false.
1299  else
1300  do_any = .true.
1301  endif
1302  endif ; enddo
1303  if (.not.do_any) exit
1304  enddo
1305 
1306  if (associated(tv%eqn_of_state)) then
1307  do k=1,nz+1 ; do i=is,ie
1308  drho_int(i,k) = drho_int_unfilt(i,k)
1309  enddo ; enddo
1310  endif
1311 
1312 end subroutine find_n2
1313 
1314 !> This subroutine sets the additional diffusivities of temperature and
1315 !! salinity due to double diffusion, using the same functional form as is
1316 !! used in MOM4.1, and taken from an NCAR technical note (REF?) that updates
1317 !! what was in Large et al. (1994). All the coefficients here should probably
1318 !! be made run-time variables rather than hard-coded constants.
1319 !!
1320 !! \todo Find reference for NCAR tech note above.
1321 subroutine double_diffusion(tv, h, T_f, S_f, j, G, GV, CS, Kd_T_dd, Kd_S_dd)
1322  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1323  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1324  type(thermo_var_ptrs), intent(in) :: tv !< Structure containing pointers to any available
1325  !! thermodynamic fields; absent fields have NULL
1326  !! ptrs.
1327  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1328  intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2).
1329  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1330  intent(in) :: T_f !< layer temp in C with the values in massless layers
1331  !! filled vertically by diffusion.
1332  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1333  intent(in) :: S_f !< Layer salinities in PPT with values in massless
1334  !! layers filled vertically by diffusion.
1335  integer, intent(in) :: j !< Meridional index upon which to work.
1336  type(set_diffusivity_cs), pointer :: CS !< Module control structure.
1337  real, dimension(SZI_(G),SZK_(G)+1), &
1338  intent(out) :: Kd_T_dd !< Interface double diffusion diapycnal
1339  !! diffusivity for temp (m2/sec).
1340  real, dimension(SZI_(G),SZK_(G)+1), &
1341  intent(out) :: Kd_S_dd !< Interface double diffusion diapycnal
1342  !! diffusivity for saln (m2/sec).
1343 
1344 ! Arguments:
1345 ! (in) tv - structure containing pointers to any available
1346 ! thermodynamic fields; absent fields have NULL ptrs
1347 ! (in) h - layer thickness (m or kg m-2)
1348 ! (in) T_f - layer temp in C with the values in massless layers
1349 ! filled vertically by diffusion
1350 ! (in) S_f - layer salinities in PPT with values in massless layers
1351 ! filled vertically by diffusion
1352 ! (in) G - ocean grid structure
1353 ! (in) GV - The ocean's vertical grid structure.
1354 ! (in) CS - module control structure
1355 ! (in) j - meridional index upon which to work
1356 ! (out) Kd_T_dd - interface double diffusion diapycnal diffusivity for temp (m2/sec)
1357 ! (out) Kd_S_dd - interface double diffusion diapycnal diffusivity for saln (m2/sec)
1358 
1359 ! This subroutine sets the additional diffusivities of temperature and
1360 ! salinity due to double diffusion, using the same functional form as is
1361 ! used in MOM4.1, and taken from an NCAR technical note (###REF?) that updates
1362 ! what was in Large et al. (1994). All the coefficients here should probably
1363 ! be made run-time variables rather than hard-coded constants.
1364 
1365  real, dimension(SZI_(G)) :: &
1366  dRho_dT, & ! partial derivatives of density wrt temp (kg m-3 degC-1)
1367  dRho_dS, & ! partial derivatives of density wrt saln (kg m-3 PPT-1)
1368  pres, & ! pressure at each interface (Pa)
1369  Temp_int, & ! temp and saln at interfaces
1370  Salin_int
1371 
1372  real :: alpha_dT ! density difference between layers due to temp diffs (kg/m3)
1373  real :: beta_dS ! density difference between layers due to saln diffs (kg/m3)
1374 
1375  real :: Rrho ! vertical density ratio
1376  real :: diff_dd ! factor for double-diffusion
1377  real :: prandtl ! flux ratio for diffusive convection regime
1378 
1379  real, parameter :: Rrho0 = 1.9 ! limit for double-diffusive density ratio
1380  real, parameter :: dsfmax = 1.e-4 ! max diffusivity in case of salt fingering
1381  real, parameter :: Kv_molecular = 1.5e-6 ! molecular viscosity (m2/sec)
1382 
1383  integer :: i, k, is, ie, nz
1384  is = g%isc ; ie = g%iec ; nz = g%ke
1385 
1386  if (associated(tv%eqn_of_state)) then
1387  do i=is,ie
1388  pres(i) = 0.0 ; kd_t_dd(i,1) = 0.0 ; kd_s_dd(i,1) = 0.0
1389  kd_t_dd(i,nz+1) = 0.0 ; kd_s_dd(i,nz+1) = 0.0
1390  enddo
1391  do k=2,nz
1392  do i=is,ie
1393  pres(i) = pres(i) + gv%H_to_Pa*h(i,j,k-1)
1394  temp_int(i) = 0.5 * (t_f(i,j,k-1) + t_f(i,j,k))
1395  salin_int(i) = 0.5 * (s_f(i,j,k-1) + s_f(i,j,k))
1396  enddo
1397  call calculate_density_derivs(temp_int, salin_int, pres, &
1398  drho_dt(:), drho_ds(:), is, ie-is+1, tv%eqn_of_state)
1399 
1400  do i=is,ie
1401  alpha_dt = -1.0*drho_dt(i) * (t_f(i,j,k-1) - t_f(i,j,k))
1402  beta_ds = drho_ds(i) * (s_f(i,j,k-1) - s_f(i,j,k))
1403 
1404  if ((alpha_dt > beta_ds) .and. (beta_ds > 0.0)) then ! salt finger case
1405  rrho = min(alpha_dt/beta_ds,rrho0)
1406  diff_dd = 1.0 - ((rrho-1.0)/(rrho0-1.0))
1407  diff_dd = dsfmax*diff_dd*diff_dd*diff_dd
1408  kd_t_dd(i,k) = 0.7*diff_dd
1409  kd_s_dd(i,k) = diff_dd
1410  elseif ((alpha_dt < 0.) .and. (beta_ds < 0.) .and. (alpha_dt > beta_ds)) then ! diffusive convection
1411  rrho = alpha_dt/beta_ds
1412  diff_dd = kv_molecular*0.909*exp(4.6*exp(-0.54*(1/rrho-1)))
1413  prandtl = 0.15*rrho
1414  if (rrho > 0.5) prandtl = (1.85-0.85/rrho)*rrho
1415  kd_t_dd(i,k) = diff_dd
1416  kd_s_dd(i,k) = prandtl*diff_dd
1417  else
1418  kd_t_dd(i,k) = 0.0 ; kd_s_dd(i,k) = 0.0
1419  endif
1420  enddo
1421  enddo
1422  endif
1423 
1424 end subroutine double_diffusion
1425 !> This routine adds diffusion sustained by flow energy extracted by bottom drag.
1426 subroutine add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, &
1427  maxTKE, kb, G, GV, CS, Kd, Kd_int, Kd_BBL)
1428  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1429  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
1430  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1
1431  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity, in m s-1
1432  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
1433  type(thermo_var_ptrs), intent(in) :: tv
1434  type(forcing), intent(in) :: fluxes
1435  type(vertvisc_type), intent(in) :: visc
1436  integer, intent(in) :: j
1437  real, dimension(SZI_(G),SZK_(G)), intent(in) :: TKE_to_Kd, maxTKE
1438  integer, dimension(SZI_(G)), intent(in) :: kb
1439  type(set_diffusivity_cs), pointer :: CS
1440  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: Kd
1441  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(inout) :: Kd_int
1442  real, dimension(:,:,:), pointer :: Kd_BBL
1443 
1444 ! This routine adds diffusion sustained by flow energy extracted by bottom drag.
1445 
1446  real, dimension(SZK_(G)+1) :: &
1447  Rint ! coordinate density of an interface (kg/m3)
1448  real, dimension(SZI_(G)) :: &
1449  htot, & ! total thickness above or below a layer, or the
1450  ! integrated thickness in the BBL (meter)
1451  rho_htot, & ! running integral with depth of density (kg/m2)
1452  gh_sum_top, & ! BBL value of g'h that can be supported by
1453  ! the local ustar, times R0_g (kg/m2)
1454  rho_top, & ! density at top of the BBL (kg/m3)
1455  tke, & ! turbulent kinetic energy available to drive
1456  ! bottom-boundary layer mixing in a layer (m3/s3)
1457  i2decay ! inverse of twice the TKE decay scale (1/m)
1458 
1459  real :: TKE_to_layer ! TKE used to drive mixing in a layer (m3/s3)
1460  real :: TKE_Ray ! TKE from layer Rayleigh drag used to drive mixing in layer (m3/s3)
1461  real :: TKE_here ! TKE that goes into mixing in this layer (m3/s3)
1462  real :: dRl, dRbot ! temporaries holding density differences (kg/m3)
1463  real :: cdrag_sqrt ! square root of the drag coefficient (nondimensional)
1464  real :: ustar_h ! value of ustar at a thickness point (m/s)
1465  real :: absf ! average absolute Coriolis parameter around a thickness point (1/s)
1466  real :: R0_g ! Rho0 / G_Earth (kg s2 m-2)
1467  real :: I_rho0 ! 1 / RHO0
1468  real :: delta_Kd ! increment to Kd from the bottom boundary layer mixing (m2/s)
1469  logical :: Rayleigh_drag ! Set to true if Rayleigh drag velocities
1470  ! defined in visc, on the assumption that this
1471  ! extracted energy also drives diapycnal mixing.
1472 
1473  logical :: domore, do_i(szi_(g))
1474  logical :: do_diag_Kd_BBL
1475 
1476  integer :: i, k, is, ie, nz, i_rem, kb_min
1477  is = g%isc ; ie = g%iec ; nz = g%ke
1478 
1479  do_diag_kd_bbl = associated(kd_bbl)
1480 
1481  if (.not.(cs%bottomdraglaw .and. (cs%BBL_effic>0.0))) return
1482 
1483  cdrag_sqrt = sqrt(cs%cdrag)
1484  tke_ray = 0.0 ; rayleigh_drag = .false.
1485  if (associated(visc%Ray_u) .and. associated(visc%Ray_v)) rayleigh_drag = .true.
1486 
1487  i_rho0 = 1.0/gv%Rho0
1488  r0_g = gv%Rho0/gv%g_Earth
1489 
1490  do k=2,nz ; rint(k) = 0.5*(gv%Rlay(k-1)+gv%Rlay(k)) ; enddo
1491 
1492  kb_min = max(gv%nk_rho_varies+1,2)
1493 
1494  ! The turbulence decay scale is 0.5*ustar/f from K&E & MOM_vertvisc.F90
1495  ! Any turbulence that makes it into the mixed layers is assumed
1496  ! to be relatively small and is discarded.
1497  do i=is,ie
1498  ustar_h = visc%ustar_BBL(i,j)
1499  if (ASSOCIATED(fluxes%ustar_tidal)) &
1500  ustar_h = ustar_h + fluxes%ustar_tidal(i,j)
1501  absf = 0.25*((abs(g%CoriolisBu(i-1,j-1)) + abs(g%CoriolisBu(i,j))) + &
1502  (abs(g%CoriolisBu(i-1,j)) + abs(g%CoriolisBu(i,j-1))))
1503  if ((ustar_h > 0.0) .and. (absf > 0.5*cs%IMax_decay*ustar_h)) then
1504  i2decay(i) = absf / ustar_h
1505  else
1506  ! The maximum decay scale should be something of order 200 m.
1507  ! If ustar_h = 0, this is land so this value doesn't matter.
1508  i2decay(i) = 0.5*cs%IMax_decay
1509  endif
1510  tke(i) = ((cs%BBL_effic * cdrag_sqrt) * &
1511  exp(-i2decay(i)*(gv%H_to_m*h(i,j,nz))) ) * &
1512  visc%TKE_BBL(i,j)
1513 
1514  if (ASSOCIATED(fluxes%TKE_tidal)) &
1515  tke(i) = tke(i) + fluxes%TKE_tidal(i,j) * i_rho0 * &
1516  (cs%BBL_effic * exp(-i2decay(i)*(gv%H_to_m*h(i,j,nz))))
1517 
1518  ! Distribute the work over a BBL of depth 20^2 ustar^2 / g' following
1519  ! Killworth & Edwards (1999) and Zilitikevich & Mironov (1996).
1520  ! Rho_top is determined by finding the density where
1521  ! integral(bottom, Z) (rho(z') - rho(Z)) dz' = rho_0 400 ustar^2 / g
1522 
1523  gh_sum_top(i) = r0_g * 400.0 * ustar_h**2
1524 
1525  do_i(i) = (g%mask2dT(i,j) > 0.5)
1526  htot(i) = gv%H_to_m*h(i,j,nz)
1527  rho_htot(i) = gv%Rlay(nz)*(gv%H_to_m*h(i,j,nz))
1528  rho_top(i) = gv%Rlay(1)
1529  if (cs%bulkmixedlayer .and. do_i(i)) rho_top(i) = gv%Rlay(kb(i)-1)
1530  enddo
1531 
1532  do k=nz-1,2,-1 ; domore = .false.
1533  do i=is,ie ; if (do_i(i)) then
1534  htot(i) = htot(i) + gv%H_to_m*h(i,j,k)
1535  rho_htot(i) = rho_htot(i) + gv%Rlay(k)*(gv%H_to_m*h(i,j,k))
1536  if (htot(i)*gv%Rlay(k-1) <= (rho_htot(i) - gh_sum_top(i))) then
1537  ! The top of the mixing is in the interface atop the current layer.
1538  rho_top(i) = (rho_htot(i) - gh_sum_top(i)) / htot(i)
1539  do_i(i) = .false.
1540  elseif (k <= kb(i)) then ; do_i(i) = .false.
1541  else ; domore = .true. ; endif
1542  endif ; enddo
1543  if (.not.domore) exit
1544  enddo ! k-loop
1545 
1546  do i=is,ie ; do_i(i) = (g%mask2dT(i,j) > 0.5) ; enddo
1547  do k=nz-1,kb_min,-1
1548  i_rem = 0
1549  do i=is,ie ; if (do_i(i)) then
1550  if (k<kb(i)) then ; do_i(i) = .false. ; cycle ; endif
1551  i_rem = i_rem + 1 ! Count the i-rows that are still being worked on.
1552  ! Apply vertical decay of the turbulent energy. This energy is
1553  ! simply lost.
1554  tke(i) = tke(i) * exp(-i2decay(i) * (gv%H_to_m*(h(i,j,k) + h(i,j,k+1))))
1555 
1556 ! if (maxEnt(i,k) <= 0.0) cycle
1557  if (maxtke(i,k) <= 0.0) cycle
1558 
1559  ! This is an analytic integral where diffusity is a quadratic function of
1560  ! rho that goes asymptotically to 0 at Rho_top (vaguely following KPP?).
1561  if (tke(i) > 0.0) then
1562  if (rint(k) <= rho_top(i)) then
1563  tke_to_layer = tke(i)
1564  else
1565  drl = rint(k+1) - rint(k) ; drbot = rint(k+1) - rho_top(i)
1566  tke_to_layer = tke(i) * drl * (3.0*drbot*(rint(k) - rho_top(i)) +&
1567  drl**2) / drbot**3
1568  endif
1569  else ; tke_to_layer = 0.0 ; endif
1570 
1571  ! TKE_Ray has been initialized to 0 above.
1572  if (rayleigh_drag) tke_ray = 0.5*cs%BBL_effic * g%IareaT(i,j) * &
1573  ((g%areaCu(i-1,j) * visc%Ray_u(i-1,j,k) * u(i-1,j,k)**2 + &
1574  g%areaCu(i,j) * visc%Ray_u(i,j,k) * u(i,j,k)**2) + &
1575  (g%areaCv(i,j-1) * visc%Ray_v(i,j-1,k) * v(i,j-1,k)**2 + &
1576  g%areaCv(i,j) * visc%Ray_v(i,j,k) * v(i,j,k)**2))
1577 
1578  if (tke_to_layer + tke_ray > 0.0) then
1579  if (cs%BBL_mixing_as_max) then
1580  if (tke_to_layer + tke_ray > maxtke(i,k)) &
1581  tke_to_layer = maxtke(i,k) - tke_ray
1582 
1583  tke(i) = tke(i) - tke_to_layer
1584 
1585  if (kd(i,j,k) < (tke_to_layer+tke_ray)*tke_to_kd(i,k)) then
1586  delta_kd = (tke_to_layer+tke_ray)*tke_to_kd(i,k) - kd(i,j,k)
1587  if ((cs%Kd_max >= 0.0) .and. (delta_kd > cs%Kd_max)) then
1588  delta_kd = cs%Kd_Max
1589  kd(i,j,k) = kd(i,j,k) + delta_kd
1590  else
1591  kd(i,j,k) = (tke_to_layer+tke_ray)*tke_to_kd(i,k)
1592  endif
1593  kd_int(i,j,k) = kd_int(i,j,k) + 0.5*delta_kd
1594  kd_int(i,j,k+1) = kd_int(i,j,k+1) + 0.5*delta_kd
1595  if (do_diag_kd_bbl) then
1596  kd_bbl(i,j,k) = kd_bbl(i,j,k) + 0.5*delta_kd
1597  kd_bbl(i,j,k+1) = kd_bbl(i,j,k+1) + 0.5*delta_kd
1598  endif
1599  endif
1600  else
1601  if (kd(i,j,k) >= maxtke(i,k)*tke_to_kd(i,k)) then
1602  tke_here = 0.0
1603  tke(i) = tke(i) + tke_ray
1604  elseif (kd(i,j,k) + (tke_to_layer+tke_ray)*tke_to_kd(i,k) > &
1605  maxtke(i,k)*tke_to_kd(i,k)) then
1606  tke_here = ((tke_to_layer+tke_ray) + kd(i,j,k)/tke_to_kd(i,k)) - &
1607  maxtke(i,k)
1608  tke(i) = tke(i) - tke_here + tke_ray
1609  else
1610  tke_here = tke_to_layer + tke_ray
1611  tke(i) = tke(i) - tke_to_layer
1612  endif
1613  if (tke(i) < 0.0) tke(i) = 0.0 ! This should be unnecessary?
1614 
1615  if (tke_here > 0.0) then
1616  delta_kd = tke_here*tke_to_kd(i,k)
1617  if (cs%Kd_max >= 0.0) delta_kd = min(delta_kd, cs%Kd_max)
1618  kd(i,j,k) = kd(i,j,k) + delta_kd
1619  kd_int(i,j,k) = kd_int(i,j,k) + 0.5*delta_kd
1620  kd_int(i,j,k+1) = kd_int(i,j,k+1) + 0.5*delta_kd
1621  if (do_diag_kd_bbl) then
1622  kd_bbl(i,j,k) = kd_bbl(i,j,k) + 0.5*delta_kd
1623  kd_bbl(i,j,k+1) = kd_bbl(i,j,k+1) + 0.5*delta_kd
1624  endif
1625  endif
1626  endif
1627  endif
1628 
1629  ! This may be risky - in the case that there are exactly zero
1630  ! velocities at 4 neighboring points, but nonzero velocities
1631  ! above the iterations would stop too soon. I don't see how this
1632  ! could happen in practice. RWH
1633  if ((tke(i)<= 0.0) .and. (tke_ray == 0.0)) then
1634  do_i(i) = .false. ; i_rem = i_rem - 1
1635  endif
1636 
1637  endif ; enddo
1638  if (i_rem == 0) exit
1639  enddo ! k-loop
1640 
1641 end subroutine add_drag_diffusivity
1642 
1643 !> Calculates a BBL diffusivity use a Prandtl number 1 diffusivitiy with a law of the
1644 !! wall turbulent viscosity, up to a BBL height where the energy used for mixing has
1645 !! consumed the mechanical TKE input.
1646 subroutine add_lotw_bbl_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, &
1647  G, GV, CS, Kd, Kd_int, Kd_BBL)
1648  type(ocean_grid_type), intent(in) :: G !< Grid structure
1649  type(verticalgrid_type), intent(in) :: GV !< Vertical grid structure
1650  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< u component of flow (m s-1)
1651  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< v component of flow (m s-1)
1652  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thickness (m or kg m-2)
1653  type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables structure
1654  type(forcing), intent(in) :: fluxes !< Surface fluxes structure
1655  type(vertvisc_type), intent(in) :: visc !< Vertical viscosity structure
1656  integer, intent(in) :: j !< j-index of row to work on
1657  real, dimension(SZI_(G),SZK_(G)+1), intent(in) :: N2_int !< Square of Brunt-Vaisala at interfaces (s-2)
1658  type(set_diffusivity_cs), pointer :: CS !< Diffusivity control structure
1659  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: Kd !< Layer net diffusivity (m2 s-1)
1660  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(inout) :: Kd_int !< Interface net diffusivity (m2 s-1)
1661  real, dimension(:,:,:), pointer :: Kd_BBL !< Interface BBL diffusivity (m2 s-1)
1662 
1663  ! Local variables
1664  real :: TKE_column ! net TKE input into the column (m3 s-3)
1665  real :: TKE_to_layer ! TKE used to drive mixing in a layer (m3 s-3)
1666  real :: TKE_Ray ! TKE from a layer Rayleigh drag used to drive mixing in that layer (m3 s-3)
1667  real :: TKE_remaining ! remaining TKE available for mixing in this layer and above (m3 s-3)
1668  real :: TKE_consumed ! TKE used for mixing in this layer (m3 s-3)
1669  real :: TKE_Kd_wall ! TKE associated with unlimited law of the wall mixing (m3 s-3)
1670  real :: cdrag_sqrt ! square root of the drag coefficient (nondimensional)
1671  real :: ustar ! value of ustar at a thickness point (m/s)
1672  real :: ustar2 ! square of ustar, for convenience (m2/s2)
1673  real :: absf ! average absolute value of Coriolis parameter around a thickness point (1/sec)
1674  real :: dh, dhm1 ! thickness of layers k and k-1, respecitvely (meter)
1675  real :: z ! distance to interface k from bottom (meter)
1676  real :: D_minus_z ! distance to interface k from surface (meter)
1677  real :: total_thickness ! total thickness of water column (meter)
1678  real :: Idecay ! inverse of decay scale used for "Joule heating" loss of TKE with height (1/m)
1679  real :: Kd_wall ! Law of the wall diffusivity (m2/s)
1680  real :: Kd_lower ! diffusivity for lower interface (m2/sec)
1681  real :: ustar_D ! u* x D (m2/s)
1682  real :: I_Rho0 ! 1 / rho0
1683  real :: N2_min ! Minimum value of N2 to use in calculation of TKE_Kd_wall (1/s2)
1684  logical :: Rayleigh_drag ! Set to true if there are Rayleigh drag velocities defined in visc, on
1685  ! the assumption that this extracted energy also drives diapycnal mixing.
1686  integer :: i, k, km1
1687  real, parameter :: von_karm = 0.41 ! Von Karman constant (http://en.wikipedia.org/wiki/Von_Karman_constant)
1688  logical :: do_diag_Kd_BBL
1689 
1690  if (.not.(cs%bottomdraglaw .and. (cs%BBL_effic>0.0))) return
1691  do_diag_kd_bbl = associated(kd_bbl)
1692 
1693  n2_min = 0.
1694  if (cs%LOTW_BBL_use_omega) n2_min = (cs%omega**2)
1695 
1696  ! Determine whether to add Rayleigh drag contribution to TKE
1697  rayleigh_drag = .false.
1698  if (associated(visc%Ray_u) .and. associated(visc%Ray_v)) rayleigh_drag = .true.
1699  i_rho0 = 1.0/gv%Rho0
1700  cdrag_sqrt = sqrt(cs%cdrag)
1701 
1702  tke_ray = 0. ! In case Rayleigh_drag is not used.
1703  do i=g%isc,g%iec ! Developed in single-column mode
1704 
1705  ! Column-wise parameters.
1706  absf = 0.25*((abs(g%CoriolisBu(i-1,j-1)) + abs(g%CoriolisBu(i,j))) + &
1707  (abs(g%CoriolisBu(i-1,j)) + abs(g%CoriolisBu(i,j-1)))) ! Non-zero on equator!
1708 
1709  ! u* at the bottom, in m s-1.
1710  ustar = visc%ustar_BBL(i,j)
1711  ustar2 = ustar**2
1712  ! In add_drag_diffusivity(), fluxes%ustar_tidal is added in. This might be double counting
1713  ! since ustar_BBL should already include all contributions to u*? -AJA
1714  if (ASSOCIATED(fluxes%ustar_tidal)) ustar = ustar + fluxes%ustar_tidal(i,j)
1715 
1716  ! The maximum decay scale should be something of order 200 m. We use the smaller of u*/f and
1717  ! (IMax_decay)^-1 as the decay scale. If ustar = 0, this is land so this value doesn't matter.
1718  idecay = cs%IMax_decay
1719  if ((ustar > 0.0) .and. (absf > cs%IMax_decay*ustar)) idecay = absf / ustar
1720 
1721  ! Energy input at the bottom, in m3 s-3.
1722  ! (Note that visc%TKE_BBL is in m3 s-3, set in set_BBL_TKE().)
1723  ! I am still unsure about sqrt(cdrag) in this expressions - AJA
1724  tke_column = cdrag_sqrt * visc%TKE_BBL(i,j)
1725  ! Add in tidal dissipation energy at the bottom, in m3 s-3.
1726  ! Note that TKE_tidal is in W m-2.
1727  if (ASSOCIATED(fluxes%TKE_tidal)) tke_column = tke_column + fluxes%TKE_tidal(i,j) * i_rho0
1728  tke_column = cs%BBL_effic * tke_column ! Only use a fraction of the mechanical dissipation for mixing.
1729 
1730  tke_remaining = tke_column
1731  total_thickness = ( sum(h(i,j,:)) + gv%H_subroundoff )* gv%H_to_m ! Total column thickness, in m.
1732  ustar_d = ustar * total_thickness
1733  z = 0.
1734  kd_lower = 0. ! Diffusivity on bottom boundary.
1735 
1736  ! Work upwards from the bottom, accumulating work used until it exceeds the available TKE input
1737  ! at the bottom.
1738  do k=g%ke,2,-1
1739  dh = gv%H_to_m * h(i,j,k) ! Thickness of this level in m.
1740  km1 = max(k-1, 1)
1741  dhm1 = gv%H_to_m * h(i,j,km1) ! Thickness of level above in m.
1742 
1743  ! Add in additional energy input from bottom-drag against slopes (sides)
1744  if (rayleigh_drag) tke_remaining = tke_remaining + 0.5*cs%BBL_effic * g%IareaT(i,j) * &
1745  ((g%areaCu(i-1,j) * visc%Ray_u(i-1,j,k) * u(i-1,j,k)**2 + &
1746  g%areaCu(i,j) * visc%Ray_u(i,j,k) * u(i,j,k)**2) + &
1747  (g%areaCv(i,j-1) * visc%Ray_v(i,j-1,k) * v(i,j-1,k)**2 + &
1748  g%areaCv(i,j) * visc%Ray_v(i,j,k) * v(i,j,k)**2))
1749 
1750  ! Exponentially decay TKE across the thickness of the layer.
1751  ! This is energy loss in addition to work done as mixing, apparently to Joule heating.
1752  tke_remaining = exp(-idecay*dh) * tke_remaining
1753 
1754  z = z + h(i,j,k)*gv%H_to_m ! Distance between upper interface of layer and the bottom, in m.
1755  d_minus_z = max(total_thickness - z, 0.) ! Thickness above layer, m.
1756 
1757  ! Diffusivity using law of the wall, limited by rotation, at height z, in m2/s.
1758  ! This calculation is at the upper interface of the layer
1759  if ( ustar_d + absf * ( z * d_minus_z ) == 0.) then
1760  kd_wall = 0.
1761  else
1762  kd_wall = ( ( von_karm * ustar2 ) * ( z * d_minus_z ) )/( ustar_d + absf * ( z * d_minus_z ) )
1763  endif
1764 
1765  ! TKE associated with Kd_wall, in m3 s-2.
1766  ! This calculation if for the volume spanning the interface.
1767  tke_kd_wall = kd_wall * 0.5 * (dh + dhm1) * max(n2_int(i,k), n2_min)
1768 
1769  ! Now bound Kd such that the associated TKE is no greater than available TKE for mixing.
1770  if (tke_kd_wall>0.) then
1771  tke_consumed = min(tke_kd_wall, tke_remaining)
1772  kd_wall = (tke_consumed/tke_kd_wall) * kd_wall ! Scale Kd so that only TKE_consumed is used.
1773  else
1774  ! Either N2=0 or dh = 0.
1775  if (tke_remaining>0.) then
1776  kd_wall = cs%Kd_max
1777  else
1778  kd_wall = 0.
1779  endif
1780  tke_consumed = 0.
1781  endif
1782 
1783  ! Now use up the appropriate about of TKE associated with the diffusivity chosen
1784  tke_remaining = tke_remaining - tke_consumed ! Note this will be non-negative
1785 
1786  ! Add this BBL diffusivity to the model net diffusivity.
1787  kd_int(i,j,k) = kd_int(i,j,k) + kd_wall
1788  kd(i,j,k) = kd(i,j,k) + 0.5*(kd_wall + kd_lower)
1789  kd_lower = kd_wall ! Store for next level up.
1790  if (do_diag_kd_bbl) kd_bbl(i,j,k) = kd_wall
1791  enddo ! k
1792  enddo ! i
1793 
1794 end subroutine add_lotw_bbl_diffusivity
1795 !> This routine adds effects of mixed layer radiation to the layer diffusivities.
1796 subroutine add_mlrad_diffusivity(h, fluxes, j, G, GV, CS, Kd, TKE_to_Kd, Kd_int)
1797  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1798  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
1799  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
1800  type(forcing), intent(in) :: fluxes
1801  integer, intent(in) :: j
1802  type(set_diffusivity_cs), pointer :: CS
1803  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: Kd
1804  real, dimension(SZI_(G),SZK_(G)), intent(in) :: TKE_to_Kd
1805  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), optional, intent(inout) :: Kd_int
1806 
1807 ! This routine adds effects of mixed layer radiation to the layer diffusivities.
1808 
1809  real, dimension(SZI_(G)) :: &
1810  h_ml, &
1811  TKE_ml_flux, &
1812  I_decay, &
1813  Kd_mlr_ml
1814 
1815  real :: f_sq, h_ml_sq, ustar_sq, Kd_mlr, C1_6
1816  real :: Omega2 ! rotation rate squared (1/s2)
1817  real :: z1 ! layer thickness times I_decay (nondim)
1818  real :: dzL ! thickness converted to meter
1819  real :: I_decay_len2_TKE ! squared inverse decay lengthscale for
1820  ! TKE, as used in the mixed layer code (1/m2)
1821  real :: h_neglect ! negligibly small thickness (meter)
1822 
1823  logical :: do_any, do_i(szi_(g))
1824  integer :: i, k, is, ie, nz, kml
1825  is = g%isc ; ie = g%iec ; nz = g%ke
1826 
1827  omega2 = cs%Omega**2
1828  c1_6 = 1.0 / 6.0
1829  kml = gv%nkml
1830  h_neglect = gv%H_subroundoff*gv%H_to_m
1831 
1832  if (.not.cs%ML_radiation) return
1833 
1834  do i=is,ie ; h_ml(i) = 0.0 ; do_i(i) = (g%mask2dT(i,j) > 0.5) ; enddo
1835  do k=1,kml ; do i=is,ie ; h_ml(i) = h_ml(i) + gv%H_to_m*h(i,j,k) ; enddo ; enddo
1836 
1837  do i=is,ie ; if (do_i(i)) then
1838  if (cs%ML_omega_frac >= 1.0) then
1839  f_sq = 4.0*omega2
1840  else
1841  f_sq = 0.25*((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
1842  (g%CoriolisBu(i,j-1)**2 + g%CoriolisBu(i-1,j)**2))
1843  if (cs%ML_omega_frac > 0.0) &
1844  f_sq = cs%ML_omega_frac*4.0*omega2 + (1.0-cs%ML_omega_frac)*f_sq
1845  endif
1846 
1847  ustar_sq = max(fluxes%ustar(i,j), cs%ustar_min)**2
1848 
1849  tke_ml_flux(i) = (cs%mstar*cs%ML_rad_coeff)*(ustar_sq*fluxes%ustar(i,j))
1850  i_decay_len2_tke = cs%TKE_decay**2 * (f_sq / ustar_sq)
1851 
1852  if (cs%ML_rad_TKE_decay) &
1853  tke_ml_flux(i) = tke_ml_flux(i) * exp(-h_ml(i) * sqrt(i_decay_len2_tke))
1854 
1855  ! Calculate the inverse decay scale
1856  h_ml_sq = (cs%ML_rad_efold_coeff * (h_ml(i)+h_neglect))**2
1857  i_decay(i) = sqrt((i_decay_len2_tke * h_ml_sq + 1.0) / h_ml_sq)
1858 
1859  ! Average the dissipation layer kml+1, using
1860  ! a more accurate Taylor series approximations for very thin layers.
1861  z1 = (gv%H_to_m*h(i,j,kml+1)) * i_decay(i)
1862  if (z1 > 1e-5) then
1863  kd_mlr = (tke_ml_flux(i) * tke_to_kd(i,kml+1)) * &
1864  (1.0 - exp(-z1))
1865  else
1866  kd_mlr = (tke_ml_flux(i) * tke_to_kd(i,kml+1)) * &
1867  (z1 * (1.0 - z1 * (0.5 - c1_6*z1)))
1868  endif
1869  kd_mlr_ml(i) = min(kd_mlr,cs%ML_rad_kd_max)
1870  tke_ml_flux(i) = tke_ml_flux(i) * exp(-z1)
1871  endif ; enddo
1872 
1873  do k=1,kml+1 ; do i=is,ie ; if (do_i(i)) then
1874  kd(i,j,k) = kd(i,j,k) + kd_mlr_ml(i)
1875  endif ; enddo ; enddo
1876  if (present(kd_int)) then
1877  do k=2,kml+1 ; do i=is,ie ; if (do_i(i)) then
1878  kd_int(i,j,k) = kd_int(i,j,k) + kd_mlr_ml(i)
1879  endif ; enddo ; enddo
1880  if (kml<=nz-1) then ; do i=is,ie ; if (do_i(i)) then
1881  kd_int(i,j,kml+2) = kd_int(i,j,kml+2) + 0.5*kd_mlr_ml(i)
1882  endif ; enddo ; endif
1883  endif
1884 
1885  do k=kml+2,nz-1
1886  do_any = .false.
1887  do i=is,ie ; if (do_i(i)) then
1888  dzl = gv%H_to_m*h(i,j,k) ; z1 = dzl*i_decay(i)
1889  if (z1 > 1e-5) then
1890  kd_mlr = (tke_ml_flux(i) * tke_to_kd(i,k)) * &
1891  ((1.0 - exp(-z1)) / dzl)
1892  else
1893  kd_mlr = (tke_ml_flux(i) * tke_to_kd(i,k)) * &
1894  (i_decay(i) * (1.0 - z1 * (0.5 - c1_6*z1)))
1895  endif
1896  kd_mlr = min(kd_mlr,cs%ML_rad_kd_max)
1897  kd(i,j,k) = kd(i,j,k) + kd_mlr
1898  if (present(kd_int)) then
1899  kd_int(i,j,k) = kd_int(i,j,k) + 0.5*kd_mlr
1900  kd_int(i,j,k+1) = kd_int(i,j,k+1) + 0.5*kd_mlr
1901  endif
1902 
1903  tke_ml_flux(i) = tke_ml_flux(i) * exp(-z1)
1904  if (tke_ml_flux(i) * i_decay(i) < 0.1*cs%Kd_min*omega2) then
1905  do_i(i) = .false.
1906  else ; do_any = .true. ; endif
1907  endif ; enddo
1908  if (.not.do_any) exit
1909  enddo
1910 
1911 end subroutine add_mlrad_diffusivity
1912 
1913  !> This subroutine adds the effect of internal-tide-driven mixing to the layer diffusivities.
1914  !! The mechanisms considered are (1) local dissipation of internal waves generated by the
1915  !! barotropic flow ("itidal"), (2) local dissipation of internal waves generated by the propagating
1916  !! low modes (rays) of the internal tide ("lowmode"), and (3) local dissipation of internal lee waves.
1917  !! Will eventually need to add diffusivity due to other wave-breaking processes (e.g. Bottom friction,
1918  !! Froude-number-depending breaking, PSI, etc.).
1919 subroutine add_int_tide_diffusivity(h, N2_bot, j, TKE_to_Kd, max_TKE, G, GV, CS, &
1920  dd, N2_lay, Kd, Kd_int )
1921  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1922  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
1923  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
1924  real, dimension(SZI_(G)), intent(in) :: N2_bot
1925  real, dimension(SZI_(G),SZK_(G)), intent(in) :: N2_lay
1926  integer, intent(in) :: j
1927  real, dimension(SZI_(G),SZK_(G)), intent(in) :: TKE_to_Kd, max_TKE
1928  type(set_diffusivity_cs), pointer :: CS
1929  type(diffusivity_diags), intent(inout) :: dd
1930  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: Kd
1931  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), optional, intent(inout) :: Kd_int
1932 
1933  ! This subroutine adds the effect of internal-tide-driven mixing to the layer diffusivities.
1934  ! The mechanisms considered are (1) local dissipation of internal waves generated by the
1935  ! barotropic flow ("itidal"), (2) local dissipation of internal waves generated by the propagating
1936  ! low modes (rays) of the internal tide ("lowmode"), and (3) local dissipation of internal lee waves.
1937  ! Will eventually need to add diffusivity due to other wave-breaking processes (e.g. Bottom friction,
1938  ! Froude-number-depending breaking, PSI, etc.).
1939 
1940  real, dimension(SZI_(G)) :: &
1941  htot, & ! total thickness above or below a layer, or the
1942  ! integrated thickness in the BBL (meter)
1943  htot_wkb, & ! distance from top to bottom (meter) WKB scaled
1944  tke_itidal_bot, & ! internal tide TKE at ocean bottom (m3/s3)
1945  tke_niku_bot, & ! lee-wave TKE at ocean bottom (m3/s3)
1946  tke_lowmode_bot, & ! internal tide TKE at ocean bottom lost from all remote low modes (m3/s3) (BDM)
1947  inv_int, & ! inverse of TKE decay for int tide over the depth of the ocean (nondim)
1948  inv_int_lee, & ! inverse of TKE decay for lee waves over the depth of the ocean (nondim)
1949  inv_int_low, & ! inverse of TKE decay for low modes over the depth of the ocean (nondim) (BDM)
1950  z0_polzin, & ! TKE decay scale in Polzin formulation (meter)
1951  z0_polzin_scaled, & ! TKE decay scale in Polzin formulation (meter)
1952  ! multiplied by N2_bot/N2_meanz to be coherent with the WKB scaled z
1953  ! z*=int(N2/N2_bot) * N2_bot/N2_meanz = int(N2/N2_meanz)
1954  ! z0_Polzin_scaled = z0_Polzin * N2_bot/N2_meanz
1955  n2_meanz, & ! vertically averaged squared buoyancy frequency (1/s2) for WKB scaling
1956  tke_itidal_rem, & ! remaining internal tide TKE (from barotropic source)
1957  tke_niku_rem, & ! remaining lee-wave TKE
1958  tke_lowmode_rem, & ! remaining internal tide TKE (from propagating low mode source) (BDM)
1959  tke_frac_top, & ! fraction of bottom TKE that should appear at top of a layer (nondim)
1960  tke_frac_top_lee, & ! fraction of bottom TKE that should appear at top of a layer (nondim)
1961  tke_frac_top_lowmode, &
1962  ! fraction of bottom TKE that should appear at top of a layer (nondim) (BDM)
1963  z_from_bot, & ! distance from bottom (meter)
1964  z_from_bot_wkb ! distance from bottom (meter), WKB scaled
1965 
1966  real :: I_rho0 ! 1 / RHO0, (m3/kg)
1967  real :: Kd_add ! diffusivity to add in a layer (m2/sec)
1968  real :: TKE_itide_lay ! internal tide TKE imparted to a layer (from barotropic) (m3/s3)
1969  real :: TKE_Niku_lay ! lee-wave TKE imparted to a layer (m3/s3)
1970  real :: TKE_lowmode_lay ! internal tide TKE imparted to a layer (from low mode) (m3/s3) (BDM)
1971  real :: frac_used ! fraction of TKE that can be used in a layer (nondim)
1972  real :: Izeta ! inverse of TKE decay scale (1/meter)
1973  real :: Izeta_lee ! inverse of TKE decay scale for lee waves (1/meter)
1974  real :: z0_psl ! temporary variable with units of meter
1975  real :: TKE_lowmode_tot ! TKE from all low modes (W/m2) (BDM)
1976 
1977 
1978  logical :: use_Polzin, use_Simmons
1979  integer :: i, k, is, ie, nz
1980  integer :: a, fr, m
1981  is = g%isc ; ie = g%iec ; nz = g%ke
1982 
1983  if (.not.(cs%Int_tide_dissipation .or. cs%Lee_wave_dissipation)) return
1984 
1985  do i=is,ie ; htot(i) = 0.0 ; inv_int(i) = 0.0 ; inv_int_lee(i) = 0.0 ; inv_int_low(i) = 0.0 ;enddo
1986  do k=1,nz ; do i=is,ie
1987  htot(i) = htot(i) + gv%H_to_m*h(i,j,k)
1988  enddo ; enddo
1989 
1990  i_rho0 = 1.0/gv%Rho0
1991 
1992  use_polzin = ((cs%Int_tide_dissipation .and. (cs%int_tide_profile == polzin_09)) .or. &
1993  (cs%lee_wave_dissipation .and. (cs%lee_wave_profile == polzin_09)) .or. &
1994  (cs%Lowmode_itidal_dissipation .and. (cs%int_tide_profile == polzin_09)))
1995  use_simmons = ((cs%Int_tide_dissipation .and. (cs%int_tide_profile == stlaurent_02)) .or. &
1996  (cs%lee_wave_dissipation .and. (cs%lee_wave_profile == stlaurent_02)) .or. &
1997  (cs%Lowmode_itidal_dissipation .and. (cs%int_tide_profile == stlaurent_02)))
1998 
1999  ! Calculate parameters for vertical structure of dissipation
2000  ! Simmons:
2001  if ( use_simmons ) then
2002  izeta = 1.0 / max(cs%Int_tide_decay_scale, gv%H_subroundoff*gv%H_to_m)
2003  izeta_lee = 1.0 / max(cs%Int_tide_decay_scale*cs%Decay_scale_factor_lee, &
2004  gv%H_subroundoff*gv%H_to_m)
2005  do i=is,ie
2006  cs%Nb(i,j) = sqrt(n2_bot(i))
2007  if (associated(dd%N2_bot)) dd%N2_bot(i,j) = n2_bot(i)
2008  if ( cs%Int_tide_dissipation ) then
2009  if (izeta*htot(i) > 1.0e-14) then ! L'Hospital's version of Adcroft's reciprocal rule.
2010  inv_int(i) = 1.0 / (1.0 - exp(-izeta*htot(i)))
2011  endif
2012  endif
2013  if ( cs%Lee_wave_dissipation ) then
2014  if (izeta_lee*htot(i) > 1.0e-14) then ! L'Hospital's version of Adcroft's reciprocal rule.
2015  inv_int_lee(i) = 1.0 / (1.0 - exp(-izeta_lee*htot(i)))
2016  endif
2017  endif
2018  if ( cs%Lowmode_itidal_dissipation) then
2019  if (izeta*htot(i) > 1.0e-14) then ! L'Hospital's version of Adcroft's reciprocal rule.
2020  inv_int_low(i) = 1.0 / (1.0 - exp(-izeta*htot(i)))
2021  endif
2022  endif
2023  z_from_bot(i) = gv%H_to_m*h(i,j,nz)
2024  enddo
2025  endif ! Simmons
2026 
2027  ! Polzin:
2028  if ( use_polzin ) then
2029  ! WKB scaling of the vertical coordinate
2030  do i=is,ie ; n2_meanz(i)=0.0 ; enddo
2031  do k=1,nz ; do i=is,ie
2032  n2_meanz(i) = n2_meanz(i) + n2_lay(i,k)*gv%H_to_m*h(i,j,k)
2033  enddo ; enddo
2034  do i=is,ie
2035  n2_meanz(i) = n2_meanz(i) / (htot(i) + gv%H_subroundoff*gv%H_to_m)
2036  if (associated(dd%N2_meanz)) dd%N2_meanz(i,j) = n2_meanz(i)
2037  enddo
2038 
2039  ! WKB scaled z*(z=H) z* at the surface using the modified Polzin WKB scaling
2040  do i=is,ie ; htot_wkb(i) = htot(i) ; enddo
2041 ! do i=is,ie ; htot_WKB(i) = 0.0 ; enddo
2042 ! do k=1,nz ; do i=is,ie
2043 ! htot_WKB(i) = htot_WKB(i) + GV%H_to_m*h(i,j,k)*N2_lay(i,k) / N2_meanz(i)
2044 ! enddo ; enddo
2045  ! htot_WKB(i) = htot(i) ! Nearly equivalent and simpler
2046 
2047  do i=is,ie
2048  cs%Nb(i,j) = sqrt(n2_bot(i))
2049  if ((cs%tideamp(i,j) > 0.0) .and. &
2050  (cs%kappa_itides**2 * cs%h2(i,j) * cs%Nb(i,j)**3 > 1.0e-14) ) then
2051  z0_polzin(i) = cs%Polzin_decay_scale_factor * cs%Nu_Polzin * &
2052  cs%Nbotref_Polzin**2 * cs%tideamp(i,j) / &
2053  ( cs%kappa_itides**2 * cs%h2(i,j) * cs%Nb(i,j)**3 )
2054  if (z0_polzin(i) < cs%Polzin_min_decay_scale) &
2055  z0_polzin(i) = cs%Polzin_min_decay_scale
2056  if (n2_meanz(i) > 1.0e-14 ) then
2057  z0_polzin_scaled(i) = z0_polzin(i)*cs%Nb(i,j)**2 / n2_meanz(i)
2058  else
2059  z0_polzin_scaled(i) = cs%Polzin_decay_scale_max_factor * htot(i)
2060  endif
2061  if (z0_polzin_scaled(i) > (cs%Polzin_decay_scale_max_factor * htot(i)) ) &
2062  z0_polzin_scaled(i) = cs%Polzin_decay_scale_max_factor * htot(i)
2063  else
2064  z0_polzin(i) = cs%Polzin_decay_scale_max_factor * htot(i)
2065  z0_polzin_scaled(i) = cs%Polzin_decay_scale_max_factor * htot(i)
2066  endif
2067 
2068  if (associated(dd%Polzin_decay_scale)) &
2069  dd%Polzin_decay_scale(i,j) = z0_polzin(i)
2070  if (associated(dd%Polzin_decay_scale_scaled)) &
2071  dd%Polzin_decay_scale_scaled(i,j) = z0_polzin_scaled(i)
2072  if (associated(dd%N2_bot)) dd%N2_bot(i,j) = cs%Nb(i,j)*cs%Nb(i,j)
2073 
2074  if ( cs%Int_tide_dissipation .and. (cs%int_tide_profile == polzin_09) ) then
2075  ! For the Polzin formulation, this if loop prevents the vertical
2076  ! flux of energy dissipation from having NaN values
2077  if (htot_wkb(i) > 1.0e-14) then
2078  inv_int(i) = ( z0_polzin_scaled(i) / htot_wkb(i) ) + 1
2079  endif
2080  endif
2081  if ( cs%lee_wave_dissipation .and. (cs%lee_wave_profile == polzin_09) ) then
2082  ! For the Polzin formulation, this if loop prevents the vertical
2083  ! flux of energy dissipation from having NaN values
2084  if (htot_wkb(i) > 1.0e-14) then
2085  inv_int_lee(i) = ( z0_polzin_scaled(i)*cs%Decay_scale_factor_lee / htot_wkb(i) ) + 1
2086  endif
2087  endif
2088  if ( cs%Lowmode_itidal_dissipation .and. (cs%int_tide_profile == polzin_09) ) then
2089  ! For the Polzin formulation, this if loop prevents the vertical
2090  ! flux of energy dissipation from having NaN values
2091  if (htot_wkb(i) > 1.0e-14) then
2092  inv_int_low(i) = ( z0_polzin_scaled(i) / htot_wkb(i) ) + 1
2093  endif
2094  endif
2095 
2096  z_from_bot(i) = gv%H_to_m*h(i,j,nz)
2097  ! Use the new formulation for WKB scaling. N2 is referenced to its
2098  ! vertical mean.
2099  if (n2_meanz(i) > 1.0e-14 ) then
2100  z_from_bot_wkb(i) = gv%H_to_m*h(i,j,nz)*n2_lay(i,nz) / n2_meanz(i)
2101  else ; z_from_bot_wkb(i) = 0 ; endif
2102  enddo
2103  endif ! Polzin
2104 
2105  ! Calculate/get dissipation values at bottom
2106  ! Both Polzin and Simmons:
2107  do i=is,ie
2108  ! Dissipation of locally trapped internal tide (non-propagating high modes)
2109  tke_itidal_bot(i) = min(cs%TKE_itidal(i,j)*cs%Nb(i,j),cs%TKE_itide_max)
2110  if (associated(dd%TKE_itidal_used)) &
2111  dd%TKE_itidal_used(i,j) = tke_itidal_bot(i)
2112  tke_itidal_bot(i) = (i_rho0 * cs%Mu_itides * cs%Gamma_itides) * tke_itidal_bot(i)
2113  ! Dissipation of locally trapped lee waves
2114  tke_niku_bot(i) = 0.0
2115  if (cs%Lee_wave_dissipation) then
2116  tke_niku_bot(i) = (i_rho0 * cs%Mu_itides * cs%Gamma_lee) * cs%TKE_Niku(i,j)
2117  endif
2118  ! Dissipation of propagating internal tide (baroclinic low modes; rays) (BDM)
2119  tke_lowmode_tot = 0.0
2120  tke_lowmode_bot(i) = 0.0
2121  if (cs%Lowmode_itidal_dissipation) then
2122  ! get loss rate due to wave drag on low modes (already multiplied by q)
2123  call get_lowmode_loss(i,j,g,cs%int_tide_CSp,"WaveDrag",tke_lowmode_tot)
2124  tke_lowmode_bot(i) = cs%Mu_itides * i_rho0 * tke_lowmode_tot
2125  endif
2126  ! Vertical energy flux at bottom
2127  tke_itidal_rem(i) = inv_int(i) * tke_itidal_bot(i)
2128  tke_niku_rem(i) = inv_int_lee(i) * tke_niku_bot(i)
2129  tke_lowmode_rem(i) = inv_int_low(i) * tke_lowmode_bot(i)
2130 
2131  if (associated(dd%Fl_itidal)) dd%Fl_itidal(i,j,nz) = tke_itidal_rem(i) !why is this here? BDM
2132  enddo
2133 
2134  ! Estimate the work that would be done by mixing in each layer.
2135  ! Simmons:
2136  if ( use_simmons ) then
2137  do k=nz-1,2,-1 ; do i=is,ie
2138  if (max_tke(i,k) <= 0.0) cycle
2139  z_from_bot(i) = z_from_bot(i) + gv%H_to_m*h(i,j,k)
2140 
2141  ! Fraction of bottom flux predicted to reach top of this layer
2142  tke_frac_top(i) = inv_int(i) * exp(-izeta * z_from_bot(i))
2143  tke_frac_top_lee(i) = inv_int_lee(i) * exp(-izeta_lee * z_from_bot(i))
2144  tke_frac_top_lowmode(i) = inv_int_low(i) * exp(-izeta * z_from_bot(i))
2145 
2146  ! Actual influx at bottom of layer minus predicted outflux at top of layer to give
2147  ! predicted power expended
2148  tke_itide_lay = tke_itidal_rem(i) - tke_itidal_bot(i) * tke_frac_top(i)
2149  tke_niku_lay = tke_niku_rem(i) - tke_niku_bot(i) * tke_frac_top_lee(i)
2150  tke_lowmode_lay = tke_lowmode_rem(i) - tke_lowmode_bot(i)* tke_frac_top_lowmode(i)
2151 
2152  ! Actual power expended may be less than predicted if stratification is weak; adjust
2153  if (tke_itide_lay + tke_niku_lay + tke_lowmode_lay > max_tke(i,k)) then
2154  frac_used = max_tke(i,k) / (tke_itide_lay + tke_niku_lay + tke_lowmode_lay)
2155  tke_itide_lay = frac_used * tke_itide_lay
2156  tke_niku_lay = frac_used * tke_niku_lay
2157  tke_lowmode_lay = frac_used * tke_lowmode_lay
2158  endif
2159 
2160  ! Calculate vertical flux available to bottom of layer above
2161  tke_itidal_rem(i) = tke_itidal_rem(i) - tke_itide_lay
2162  tke_niku_rem(i) = tke_niku_rem(i) - tke_niku_lay
2163  tke_lowmode_rem(i) = tke_lowmode_rem(i) - tke_lowmode_lay
2164 
2165  ! Convert power to diffusivity
2166  kd_add = tke_to_kd(i,k) * (tke_itide_lay + tke_niku_lay + tke_lowmode_lay)
2167 
2168  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2169  kd(i,j,k) = kd(i,j,k) + kd_add
2170 
2171  if (present(kd_int)) then
2172  kd_int(i,j,k) = kd_int(i,j,k) + 0.5*kd_add
2173  kd_int(i,j,k+1) = kd_int(i,j,k+1) + 0.5*kd_add
2174  endif
2175 
2176  ! diagnostics
2177  if (associated(dd%Kd_itidal)) then
2178  ! If at layers, dd%Kd_itidal is just TKE_to_Kd(i,k) * TKE_itide_lay
2179  ! The following sets the interface diagnostics.
2180  kd_add = tke_to_kd(i,k) * tke_itide_lay
2181  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2182  if (k>1) dd%Kd_itidal(i,j,k) = dd%Kd_itidal(i,j,k) + 0.5*kd_add
2183  if (k<nz) dd%Kd_itidal(i,j,k+1) = dd%Kd_itidal(i,j,k+1) + 0.5*kd_add
2184  endif
2185  if (associated(dd%Kd_Itidal_work)) &
2186  dd%Kd_itidal_work(i,j,k) = gv%Rho0 * tke_itide_lay
2187  if (associated(dd%Fl_itidal)) dd%Fl_itidal(i,j,k) = tke_itidal_rem(i)
2188 
2189  if (associated(dd%Kd_Niku)) then
2190  ! If at layers, dd%Kd_Niku(i,j,K) is just TKE_to_Kd(i,k) * TKE_Niku_lay
2191  ! The following sets the interface diagnostics.
2192  kd_add = tke_to_kd(i,k) * tke_niku_lay
2193  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2194  if (k>1) dd%Kd_Niku(i,j,k) = dd%Kd_Niku(i,j,k) + 0.5*kd_add
2195  if (k<nz) dd%Kd_Niku(i,j,k+1) = dd%Kd_Niku(i,j,k+1) + 0.5*kd_add
2196  endif
2197 ! if (associated(dd%Kd_Niku)) dd%Kd_Niku(i,j,K) = TKE_to_Kd(i,k) * TKE_Niku_lay
2198  if (associated(dd%Kd_Niku_work)) &
2199  dd%Kd_Niku_work(i,j,k) = gv%Rho0 * tke_niku_lay
2200 
2201  if (associated(dd%Kd_lowmode)) then
2202  ! If at layers, dd%Kd_lowmode is just TKE_to_Kd(i,k) * TKE_lowmode_lay
2203  ! The following sets the interface diagnostics.
2204  kd_add = tke_to_kd(i,k) * tke_lowmode_lay
2205  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2206  if (k>1) dd%Kd_lowmode(i,j,k) = dd%Kd_lowmode(i,j,k) + 0.5*kd_add
2207  if (k<nz) dd%Kd_lowmode(i,j,k+1) = dd%Kd_lowmode(i,j,k+1) + 0.5*kd_add
2208  endif
2209  if (associated(dd%Kd_lowmode_work)) &
2210  dd%Kd_lowmode_work(i,j,k) = gv%Rho0 * tke_lowmode_lay
2211  if (associated(dd%Fl_lowmode)) dd%Fl_lowmode(i,j,k) = tke_lowmode_rem(i)
2212 
2213  enddo ; enddo ;
2214  endif ! Simmons
2215 
2216  ! Polzin:
2217  if ( use_polzin ) then
2218  do k=nz-1,2,-1 ; do i=is,ie
2219  if (max_tke(i,k) <= 0.0) cycle
2220  z_from_bot(i) = z_from_bot(i) + gv%H_to_m*h(i,j,k)
2221  if (n2_meanz(i) > 1.0e-14 ) then
2222  z_from_bot_wkb(i) = z_from_bot_wkb(i) + gv%H_to_m*h(i,j,k)*n2_lay(i,k)/n2_meanz(i)
2223  else ; z_from_bot_wkb(i) = 0 ; endif
2224 
2225  ! Fraction of bottom flux predicted to reach top of this layer
2226  tke_frac_top(i) = ( inv_int(i) * z0_polzin_scaled(i) ) / &
2227  ( z0_polzin_scaled(i) + z_from_bot_wkb(i) )
2228  z0_psl = z0_polzin_scaled(i)*cs%Decay_scale_factor_lee
2229  tke_frac_top_lee(i) = (inv_int_lee(i) * z0_psl) / (z0_psl + z_from_bot_wkb(i))
2230  tke_frac_top_lowmode(i) = ( inv_int_low(i) * z0_polzin_scaled(i) ) / &
2231  ( z0_polzin_scaled(i) + z_from_bot_wkb(i) )
2232 
2233  ! Actual influx at bottom of layer minus predicted outflux at top of layer to give
2234  ! predicted power expended
2235  tke_itide_lay = tke_itidal_rem(i) - tke_itidal_bot(i) *tke_frac_top(i)
2236  tke_niku_lay = tke_niku_rem(i) - tke_niku_bot(i) * tke_frac_top_lee(i)
2237  tke_lowmode_lay = tke_lowmode_rem(i) - tke_lowmode_bot(i)*tke_frac_top_lowmode(i)
2238 
2239  ! Actual power expended may be less than predicted if stratification is weak; adjust
2240  if (tke_itide_lay + tke_niku_lay + tke_lowmode_lay > max_tke(i,k)) then
2241  frac_used = max_tke(i,k) / (tke_itide_lay + tke_niku_lay + tke_lowmode_lay)
2242  tke_itide_lay = frac_used * tke_itide_lay
2243  tke_niku_lay = frac_used * tke_niku_lay
2244  tke_lowmode_lay = frac_used * tke_lowmode_lay
2245  endif
2246 
2247  ! Calculate vertical flux available to bottom of layer above
2248  tke_itidal_rem(i) = tke_itidal_rem(i) - tke_itide_lay
2249  tke_niku_rem(i) = tke_niku_rem(i) - tke_niku_lay
2250  tke_lowmode_rem(i) = tke_lowmode_rem(i) - tke_lowmode_lay
2251 
2252  ! Convert power to diffusivity
2253  kd_add = tke_to_kd(i,k) * (tke_itide_lay + tke_niku_lay + tke_lowmode_lay)
2254 
2255  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2256  kd(i,j,k) = kd(i,j,k) + kd_add
2257 
2258  if (present(kd_int)) then
2259  kd_int(i,j,k) = kd_int(i,j,k) + 0.5*kd_add
2260  kd_int(i,j,k+1) = kd_int(i,j,k+1) + 0.5*kd_add
2261  endif
2262 
2263  ! diagnostics
2264  if (associated(dd%Kd_itidal)) then
2265  ! If at layers, this is just dd%Kd_itidal(i,j,K) = TKE_to_Kd(i,k) * TKE_itide_lay
2266  ! The following sets the interface diagnostics.
2267  kd_add = tke_to_kd(i,k) * tke_itide_lay
2268  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2269  if (k>1) dd%Kd_itidal(i,j,k) = dd%Kd_itidal(i,j,k) + 0.5*kd_add
2270  if (k<nz) dd%Kd_itidal(i,j,k+1) = dd%Kd_itidal(i,j,k+1) + 0.5*kd_add
2271  endif
2272  if (associated(dd%Kd_Itidal_work)) &
2273  dd%Kd_itidal_work(i,j,k) = gv%Rho0 * tke_itide_lay
2274  if (associated(dd%Fl_itidal)) dd%Fl_itidal(i,j,k) = tke_itidal_rem(i)
2275 
2276  if (associated(dd%Kd_Niku)) then
2277  ! If at layers, this is just dd%Kd_Niku(i,j,K) = TKE_to_Kd(i,k) * TKE_Niku_lay
2278  ! The following sets the interface diagnostics.
2279  kd_add = tke_to_kd(i,k) * tke_niku_lay
2280  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2281  if (k>1) dd%Kd_Niku(i,j,k) = dd%Kd_Niku(i,j,k) + 0.5*kd_add
2282  if (k<nz) dd%Kd_Niku(i,j,k+1) = dd%Kd_Niku(i,j,k+1) + 0.5*kd_add
2283  endif
2284  ! if (associated(dd%Kd_Niku)) dd%Kd_Niku(i,j,K) = TKE_to_Kd(i,k) * TKE_Niku_lay
2285  if (associated(dd%Kd_Niku_work)) dd%Kd_Niku_work(i,j,k) = gv%Rho0 * tke_niku_lay
2286 
2287  if (associated(dd%Kd_lowmode)) then
2288  ! If at layers, dd%Kd_lowmode is just TKE_to_Kd(i,k) * TKE_lowmode_lay
2289  ! The following sets the interface diagnostics.
2290  kd_add = tke_to_kd(i,k) * tke_lowmode_lay
2291  if (cs%Kd_max >= 0.0) kd_add = min(kd_add, cs%Kd_max)
2292  if (k>1) dd%Kd_lowmode(i,j,k) = dd%Kd_lowmode(i,j,k) + 0.5*kd_add
2293  if (k<nz) dd%Kd_lowmode(i,j,k+1) = dd%Kd_lowmode(i,j,k+1) + 0.5*kd_add
2294  endif
2295  if (associated(dd%Kd_lowmode_work)) &
2296  dd%Kd_lowmode_work(i,j,k) = gv%Rho0 * tke_lowmode_lay
2297  if (associated(dd%Fl_lowmode)) dd%Fl_lowmode(i,j,k) = tke_lowmode_rem(i)
2298 
2299  enddo ; enddo;
2300  endif ! Polzin
2301 
2302 end subroutine add_int_tide_diffusivity
2303 !> This subroutine calculates several properties related to bottom
2304 !! boundary layer turbulence.
2305 subroutine set_bbl_tke(u, v, h, fluxes, visc, G, GV, CS)
2306  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
2307  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
2308  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1
2309  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity, in m s-1
2310  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
2311  type(forcing), intent(in) :: fluxes
2312  type(vertvisc_type), intent(inout) :: visc
2313  type(set_diffusivity_cs), pointer :: CS
2314 
2315  ! This subroutine calculates several properties related to bottom
2316  ! boundary layer turbulence.
2317 
2318  real, dimension(SZI_(G)) :: &
2319  htot ! total thickness above or below a layer, or the
2320  ! integrated thickness in the BBL (meter)
2321 
2322  real, dimension(SZIB_(G)) :: &
2323  uhtot, & ! running integral of u in the BBL (m2/s)
2324  ustar, & ! bottom boundary layer turbulence speed (m/s)
2325  u2_bbl ! square of the mean zonal velocity in the BBL (m2/s2)
2326 
2327  real :: vhtot(szi_(g)) ! running integral of v in the BBL (m2/sec)
2328 
2329  real, dimension(SZI_(G),SZJB_(G)) :: &
2330  vstar, & ! ustar at at v-points in 2 j-rows (m/s)
2331  v2_bbl ! square of average meridional velocity in BBL (m2/s2)
2332 
2333  real :: cdrag_sqrt ! square root of the drag coefficient (nondim)
2334  real :: hvel ! thickness at velocity points (meter)
2335 
2336  logical :: domore, do_i(szi_(g))
2337  integer :: i, j, k, is, ie, js, je, nz
2338  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
2339 
2340  if (.not.associated(cs)) call mom_error(fatal,"set_BBL_TKE: "//&
2341  "Module must be initialized before it is used.")
2342 
2343  if (.not.cs%bottomdraglaw .or. (cs%BBL_effic<=0.0)) then
2344  if (associated(visc%ustar_BBL)) then
2345  do j=js,je ; do i=is,ie ; visc%ustar_BBL(i,j) = 0.0 ; enddo ; enddo
2346  endif
2347  if (associated(visc%TKE_BBL)) then
2348  do j=js,je ; do i=is,ie ; visc%TKE_BBL(i,j) = 0.0 ; enddo ; enddo
2349  endif
2350  return
2351  endif
2352 
2353  cdrag_sqrt = sqrt(cs%cdrag)
2354 
2355 !$OMP parallel default(none) shared(cdrag_sqrt,is,ie,js,je,nz,visc,CS,G,GV,vstar,h,v, &
2356 !$OMP v2_bbl,u) &
2357 !$OMP private(do_i,vhtot,htot,domore,hvel,uhtot,ustar,u2_bbl)
2358 !$OMP do
2359  do j=js-1,je
2360  ! Determine ustar and the square magnitude of the velocity in the
2361  ! bottom boundary layer. Together these give the TKE source and
2362  ! vertical decay scale.
2363  do i=is,ie ; if ((g%mask2dCv(i,j) > 0.5) .and. (cdrag_sqrt*visc%bbl_thick_v(i,j) > 0.0)) then
2364  do_i(i) = .true. ; vhtot(i) = 0.0 ; htot(i) = 0.0
2365  vstar(i,j) = visc%kv_bbl_v(i,j)/(cdrag_sqrt*visc%bbl_thick_v(i,j))
2366  else
2367  do_i(i) = .false. ; vstar(i,j) = 0.0 ; htot(i) = 0.0
2368  endif ; enddo
2369  do k=nz,1,-1
2370  domore = .false.
2371  do i=is,ie ; if (do_i(i)) then
2372  hvel = 0.5*gv%H_to_m*(h(i,j,k) + h(i,j+1,k))
2373  if ((htot(i) + hvel) >= visc%bbl_thick_v(i,j)) then
2374  vhtot(i) = vhtot(i) + (visc%bbl_thick_v(i,j) - htot(i))*v(i,j,k)
2375  htot(i) = visc%bbl_thick_v(i,j)
2376  do_i(i) = .false.
2377  else
2378  vhtot(i) = vhtot(i) + hvel*v(i,j,k)
2379  htot(i) = htot(i) + hvel
2380  domore = .true.
2381  endif
2382  endif ; enddo
2383  if (.not.domore) exit
2384  enddo
2385  do i=is,ie ; if ((g%mask2dCv(i,j) > 0.5) .and. (htot(i) > 0.0)) then
2386  v2_bbl(i,j) = (vhtot(i)*vhtot(i))/(htot(i)*htot(i))
2387  else
2388  v2_bbl(i,j) = 0.0
2389  endif ; enddo
2390  enddo
2391 !$OMP do
2392  do j=js,je
2393  do i=is-1,ie ; if ((g%mask2dCu(i,j) > 0.5) .and. (cdrag_sqrt*visc%bbl_thick_u(i,j) > 0.0)) then
2394  do_i(i) = .true. ; uhtot(i) = 0.0 ; htot(i) = 0.0
2395  ustar(i) = visc%kv_bbl_u(i,j)/(cdrag_sqrt*visc%bbl_thick_u(i,j))
2396  else
2397  do_i(i) = .false. ; ustar(i) = 0.0 ; htot(i) = 0.0
2398  endif ; enddo
2399  do k=nz,1,-1 ; domore = .false.
2400  do i=is-1,ie ; if (do_i(i)) then
2401  hvel = 0.5*gv%H_to_m*(h(i,j,k) + h(i+1,j,k))
2402  if ((htot(i) + hvel) >= visc%bbl_thick_u(i,j)) then
2403  uhtot(i) = uhtot(i) + (visc%bbl_thick_u(i,j) - htot(i))*u(i,j,k)
2404  htot(i) = visc%bbl_thick_u(i,j)
2405  do_i(i) = .false.
2406  else
2407  uhtot(i) = uhtot(i) + hvel*u(i,j,k)
2408  htot(i) = htot(i) + hvel
2409  domore = .true.
2410  endif
2411  endif ; enddo
2412  if (.not.domore) exit
2413  enddo
2414  do i=is-1,ie ; if ((g%mask2dCu(i,j) > 0.5) .and. (htot(i) > 0.0)) then
2415  u2_bbl(i) = (uhtot(i)*uhtot(i))/(htot(i)*htot(i))
2416  else
2417  u2_bbl(i) = 0.0
2418  endif ; enddo
2419 
2420  do i=is,ie
2421  visc%ustar_BBL(i,j) = sqrt(0.5*g%IareaT(i,j) * &
2422  ((g%areaCu(i-1,j)*(ustar(i-1)*ustar(i-1)) + &
2423  g%areaCu(i,j)*(ustar(i)*ustar(i))) + &
2424  (g%areaCv(i,j-1)*(vstar(i,j-1)*vstar(i,j-1)) + &
2425  g%areaCv(i,j)*(vstar(i,j)*vstar(i,j))) ) )
2426  visc%TKE_BBL(i,j) = (((g%areaCu(i-1,j)*(ustar(i-1)*u2_bbl(i-1)) + &
2427  g%areaCu(i,j) * (ustar(i)*u2_bbl(i))) + &
2428  (g%areaCv(i,j-1)*(vstar(i,j-1)*v2_bbl(i,j-1)) + &
2429  g%areaCv(i,j) * (vstar(i,j)*v2_bbl(i,j))))*g%IareaT(i,j))
2430  enddo
2431  enddo
2432 !$OMP end parallel
2433 
2434 end subroutine set_bbl_tke
2435 
2436 subroutine set_density_ratios(h, tv, kb, G, GV, CS, j, ds_dsp1, rho_0)
2437  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2438  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2439  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
2440  intent(in) :: h !< Layer thicknesses, in H (usually m
2441  !! or kg m-2).
2442  type(thermo_var_ptrs), intent(in) :: tv !< Structure containing pointers to any
2443  !! available thermodynamic fields; absent
2444  !! fields have NULL ptrs.
2445  integer, dimension(SZI_(G)), intent(in) :: kb !< Index of lightest layer denser than the
2446  !! buffer layer.
2447  type(set_diffusivity_cs), pointer :: CS !< Control structure returned by previous
2448  !! call to diabatic_entrain_init.
2449  integer, intent(in) :: j !< Meridional index upon which to work.
2450  real, dimension(SZI_(G),SZK_(G)), intent(out) :: ds_dsp1 !< Coordinate variable (sigma-2)
2451  !! difference across an interface divided by
2452  !! the difference across the interface below
2453  !! it (nondimensional)
2454  real, dimension(SZI_(G),SZK_(G)), &
2455  optional, intent(in) :: rho_0 !< Layer potential densities relative to
2456  !! surface press (kg/m3).
2457 
2458 ! Arguments:
2459 ! (in) h - layer thickness (meter)
2460 ! (in) tv - structure containing pointers to any available
2461 ! thermodynamic fields; absent fields have NULL ptrs
2462 ! (in) kb - index of lightest layer denser than the buffer layer
2463 ! (in) G - ocean grid structure
2464 ! (in) GV - The ocean's vertical grid structure.
2465 ! (in) CS - control structure returned by previous call to diabatic_entrain_init
2466 ! (in) j - meridional index upon which to work
2467 ! (in) ds_dsp1 - coordinate variable (sigma-2) difference across an
2468 ! interface divided by the difference across the interface
2469 ! below it (nondimensional)
2470 ! (in) rho_0 - layer potential densities relative to surface press (kg/m3)
2471 
2472  real :: g_R0 ! g_R0 is g/Rho (m4 kg-1 s-2)
2473  real :: eps, tmp ! nondimensional temproray variables
2474  real :: a(szk_(g)), a_0(szk_(g)) ! nondimensional temporary variables
2475  real :: p_ref(szi_(g)) ! an array of tv%P_Ref pressures
2476  real :: Rcv(szi_(g),szk_(g)) ! coordinate density in the mixed and buffer layers (kg/m3)
2477  real :: I_Drho ! temporary variable (m3/kg)
2478 
2479  integer :: i, k, k3, is, ie, nz, kmb
2480  is = g%isc ; ie = g%iec ; nz = g%ke
2481 
2482  do k=2,nz-1
2483  if (gv%g_prime(k+1)/=0.) then
2484  do i=is,ie
2485  ds_dsp1(i,k) = gv%g_prime(k) / gv%g_prime(k+1)
2486  enddo
2487  else
2488  do i=is,ie
2489  ds_dsp1(i,k) = 1.
2490  enddo
2491  endif
2492  enddo
2493 
2494  if (cs%bulkmixedlayer) then
2495  g_r0 = gv%g_Earth/gv%Rho0
2496  kmb = gv%nk_rho_varies
2497  eps = 0.1
2498  do i=is,ie ; p_ref(i) = tv%P_Ref ; enddo
2499  do k=1,kmb
2500  call calculate_density(tv%T(:,j,k),tv%S(:,j,k),p_ref,rcv(:,k),&
2501  is,ie-is+1,tv%eqn_of_state)
2502  enddo
2503  do i=is,ie
2504  if (kb(i) <= nz-1) then
2505 ! Set up appropriately limited ratios of the reduced gravities of the
2506 ! interfaces above and below the buffer layer and the next denser layer.
2507  k = kb(i)
2508 
2509  i_drho = g_r0 / gv%g_prime(k+1)
2510  ! The indexing convention for a is appropriate for the interfaces.
2511  do k3=1,kmb
2512  a(k3+1) = (gv%Rlay(k) - rcv(i,k3)) * i_drho
2513  enddo
2514  if ((present(rho_0)) .and. (a(kmb+1) < 2.0*eps*ds_dsp1(i,k))) then
2515 ! If the buffer layer nearly matches the density of the layer below in the
2516 ! coordinate variable (sigma-2), use the sigma-0-based density ratio if it is
2517 ! greater (and stable).
2518  if ((rho_0(i,k) > rho_0(i,kmb)) .and. &
2519  (rho_0(i,k+1) > rho_0(i,k))) then
2520  i_drho = 1.0 / (rho_0(i,k+1)-rho_0(i,k))
2521  a_0(kmb+1) = min((rho_0(i,k)-rho_0(i,kmb)) * i_drho, ds_dsp1(i,k))
2522  if (a_0(kmb+1) > a(kmb+1)) then
2523  do k3=2,kmb
2524  a_0(k3) = a_0(kmb+1) + (rho_0(i,kmb)-rho_0(i,k3-1)) * i_drho
2525  enddo
2526  if (a(kmb+1) <= eps*ds_dsp1(i,k)) then
2527  do k3=2,kmb+1 ; a(k3) = a_0(k3) ; enddo
2528  else
2529 ! Alternative... tmp = 0.5*(1.0 - cos(PI*(a(K2+1)/(eps*ds_dsp1(i,k)) - 1.0)) )
2530  tmp = a(kmb+1)/(eps*ds_dsp1(i,k)) - 1.0
2531  do k3=2,kmb+1 ; a(k3) = tmp*a(k3) + (1.0-tmp)*a_0(k3) ; enddo
2532  endif
2533  endif
2534  endif
2535  endif
2536 
2537  ds_dsp1(i,k) = max(a(kmb+1),1e-5)
2538 
2539  do k3=2,kmb
2540 ! ds_dsp1(i,k3) = MAX(a(k3),1e-5)
2541  ! Deliberately treat convective instabilies of the upper mixed
2542  ! and buffer layers with respect to the deepest buffer layer as
2543  ! though they don't exist. They will be eliminated by the upcoming
2544  ! call to the mixedlayer code anyway.
2545  ! The indexing convention is appropriate for the interfaces.
2546  ds_dsp1(i,k3) = max(a(k3),ds_dsp1(i,k))
2547  enddo
2548  endif ! (kb(i) <= nz-1)
2549  enddo ! I-loop.
2550  endif ! bulkmixedlayer
2551 
2552 end subroutine set_density_ratios
2553 
2554 subroutine set_diffusivity_init(Time, G, GV, param_file, diag, CS, diag_to_Z_CSp, int_tide_CSp)
2555  type(time_type), intent(in) :: Time
2556  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
2557  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2558  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
2559  !! parameters.
2560  type(diag_ctrl), target, intent(inout) :: diag !< structure used to regulate diagnostic output.
2561  type(set_diffusivity_cs), pointer :: CS !< pointer set to point to the module control
2562  !! structure.
2563  type(diag_to_z_cs), pointer :: diag_to_Z_CSp !< pointer to the Z-diagnostics control
2564  !! structure.
2565  type(int_tide_cs), pointer :: int_tide_CSp !< pointer to the internal tides control
2566  !! structure (BDM)
2567 
2568 ! Arguments:
2569 ! (in) Time - current model time
2570 ! (in) G - ocean grid structure
2571 ! (in) GV - The ocean's vertical grid structure.
2572 ! (in) param_file - structure indicating open file to parse for params
2573 ! (in) diag - structure used to regulate diagnostic output
2574 ! (in/out) CS - pointer set to point to the module control structure
2575 ! (in) diag_to_Z_CSp - pointer to the Z-diagnostics control structure
2576 ! (in) int_tide_CSp - pointer to the internal tides control structure (BDM)
2577 
2578  real :: decay_length, utide, zbot, hamp
2579  type(vardesc) :: vd
2580  logical :: read_tideamp, ML_use_omega
2581 ! This include declares and sets the variable "version".
2582 #include "version_variable.h"
2583  character(len=40) :: mdl = "MOM_set_diffusivity" ! This module's name.
2584  character(len=20) :: tmpstr
2585  character(len=200) :: filename, tideamp_file, h2_file, Niku_TKE_input_file
2586  real :: Niku_scale ! local variable for scaling the Nikurashin TKE flux data
2587  real :: omega_frac_dflt
2588  integer :: i, j, is, ie, js, je
2589  integer :: isd, ied, jsd, jed
2590 
2591  if (associated(cs)) then
2592  call mom_error(warning, "diabatic_entrain_init called with an associated "// &
2593  "control structure.")
2594  return
2595  endif
2596  allocate(cs)
2597 
2598  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
2599  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
2600 
2601  cs%diag => diag
2602  if (associated(int_tide_csp)) cs%int_tide_CSp => int_tide_csp
2603  if (associated(diag_to_z_csp)) cs%diag_to_Z_CSp => diag_to_z_csp
2604 
2605  ! These default values always need to be set.
2606  cs%BBL_mixing_as_max = .true.
2607  cs%Kdml = 0.0 ; cs%cdrag = 0.003 ; cs%BBL_effic = 0.0 ;
2608  cs%bulkmixedlayer = (gv%nkml > 0)
2609 
2610 
2611  ! Read all relevant parameters and write them to the model log.
2612  call log_version(param_file, mdl, version, "")
2613 
2614  call get_param(param_file, mdl, "INPUTDIR", cs%inputdir, default=".")
2615  cs%inputdir = slasher(cs%inputdir)
2616  call get_param(param_file, mdl, "FLUX_RI_MAX", cs%FluxRi_max, &
2617  "The flux Richardson number where the stratification is \n"//&
2618  "large enough that N2 > omega2. The full expression for \n"//&
2619  "the Flux Richardson number is usually \n"//&
2620  "FLUX_RI_MAX*N2/(N2+OMEGA2).", default=0.2)
2621  call get_param(param_file, mdl, "OMEGA", cs%omega, &
2622  "The rotation rate of the earth.", units="s-1", &
2623  default=7.2921e-5)
2624 
2625  call get_param(param_file, mdl, "ML_RADIATION", cs%ML_radiation, &
2626  "If true, allow a fraction of TKE available from wind \n"//&
2627  "work to penetrate below the base of the mixed layer \n"//&
2628  "with a vertical decay scale determined by the minimum \n"//&
2629  "of: (1) The depth of the mixed layer, (2) an Ekman \n"//&
2630  "length scale.", default=.false.)
2631  if (cs%ML_radiation) then
2632  ! This give a minimum decay scale that is typically much less than Angstrom.
2633  cs%ustar_min = 2e-4*cs%omega*(gv%Angstrom + gv%H_subroundoff)
2634 
2635  call get_param(param_file, mdl, "ML_RAD_EFOLD_COEFF", cs%ML_rad_efold_coeff, &
2636  "A coefficient that is used to scale the penetration \n"//&
2637  "depth for turbulence below the base of the mixed layer. \n"//&
2638  "This is only used if ML_RADIATION is true.", units="nondim", &
2639  default=0.2)
2640  call get_param(param_file, mdl, "ML_RAD_KD_MAX", cs%ML_rad_kd_max, &
2641  "The maximum diapycnal diffusivity due to turbulence \n"//&
2642  "radiated from the base of the mixed layer. \n"//&
2643  "This is only used if ML_RADIATION is true.", units="m2 s-1", &
2644  default=1.0e-3)
2645  call get_param(param_file, mdl, "ML_RAD_COEFF", cs%ML_rad_coeff, &
2646  "The coefficient which scales MSTAR*USTAR^3 to obtain \n"//&
2647  "the energy available for mixing below the base of the \n"//&
2648  "mixed layer. This is only used if ML_RADIATION is true.", &
2649  units="nondim", default=0.2)
2650  call get_param(param_file, mdl, "ML_RAD_APPLY_TKE_DECAY", cs%ML_rad_TKE_decay, &
2651  "If true, apply the same exponential decay to ML_rad as \n"//&
2652  "is applied to the other surface sources of TKE in the \n"//&
2653  "mixed layer code. This is only used if ML_RADIATION is true.",&
2654  default=.true.)
2655  call get_param(param_file, mdl, "MSTAR", cs%mstar, &
2656  "The ratio of the friction velocity cubed to the TKE \n"//&
2657  "input to the mixed layer.", "units=nondim", default=1.2)
2658  call get_param(param_file, mdl, "TKE_DECAY", cs%TKE_decay, &
2659  "The ratio of the natural Ekman depth to the TKE decay scale.", &
2660  units="nondim", default=2.5)
2661  call get_param(param_file, mdl, "ML_USE_OMEGA", ml_use_omega, &
2662  "If true, use the absolute rotation rate instead of the \n"//&
2663  "vertical component of rotation when setting the decay \n"//&
2664  "scale for turbulence.", default=.false., do_not_log=.true.)
2665  omega_frac_dflt = 0.0
2666  if (ml_use_omega) then
2667  call mom_error(warning, "ML_USE_OMEGA is depricated; use ML_OMEGA_FRAC=1.0 instead.")
2668  omega_frac_dflt = 1.0
2669  endif
2670  call get_param(param_file, mdl, "ML_OMEGA_FRAC", cs%ML_omega_frac, &
2671  "When setting the decay scale for turbulence, use this \n"//&
2672  "fraction of the absolute rotation rate blended with the \n"//&
2673  "local value of f, as sqrt((1-of)*f^2 + of*4*omega^2).", &
2674  units="nondim", default=omega_frac_dflt)
2675  endif
2676 
2677  call get_param(param_file, mdl, "BOTTOMDRAGLAW", cs%bottomdraglaw, &
2678  "If true, the bottom stress is calculated with a drag \n"//&
2679  "law of the form c_drag*|u|*u. The velocity magnitude \n"//&
2680  "may be an assumed value or it may be based on the \n"//&
2681  "actual velocity in the bottommost HBBL, depending on \n"//&
2682  "LINEAR_DRAG.", default=.true.)
2683  if (cs%bottomdraglaw) then
2684  call get_param(param_file, mdl, "CDRAG", cs%cdrag, &
2685  "The drag coefficient relating the magnitude of the \n"//&
2686  "velocity field to the bottom stress. CDRAG is only used \n"//&
2687  "if BOTTOMDRAGLAW is true.", units="nondim", default=0.003)
2688  call get_param(param_file, mdl, "BBL_EFFIC", cs%BBL_effic, &
2689  "The efficiency with which the energy extracted by \n"//&
2690  "bottom drag drives BBL diffusion. This is only \n"//&
2691  "used if BOTTOMDRAGLAW is true.", units="nondim", default=0.20)
2692  call get_param(param_file, mdl, "BBL_MIXING_MAX_DECAY", decay_length, &
2693  "The maximum decay scale for the BBL diffusion, or 0 \n"//&
2694  "to allow the mixing to penetrate as far as \n"//&
2695  "stratification and rotation permit. The default is 0. \n"//&
2696  "This is only used if BOTTOMDRAGLAW is true.", units="m", &
2697  default=0.0)
2698 
2699  cs%IMax_decay = 1.0/200.0
2700  if (decay_length > 0.0) cs%IMax_decay = 1.0/decay_length
2701  call get_param(param_file, mdl, "BBL_MIXING_AS_MAX", cs%BBL_mixing_as_max, &
2702  "If true, take the maximum of the diffusivity from the \n"//&
2703  "BBL mixing and the other diffusivities. Otherwise, \n"//&
2704  "diffusiviy from the BBL_mixing is simply added.", &
2705  default=.true.)
2706  call get_param(param_file, mdl, "USE_LOTW_BBL_DIFFUSIVITY", cs%use_LOTW_BBL_diffusivity, &
2707  "If true, uses a simple, imprecise but non-coordinate dependent, model\n"//&
2708  "of BBL mixing diffusivity based on Law of the Wall. Otherwise, uses\n"//&
2709  "the original BBL scheme.", default=.false.)
2710  if (cs%use_LOTW_BBL_diffusivity) then
2711  call get_param(param_file, mdl, "LOTW_BBL_USE_OMEGA", cs%LOTW_BBL_use_omega, &
2712  "If true, use the maximum of Omega and N for the TKE to diffusion\n"//&
2713  "calculation. Otherwise, N is N.", default=.true.)
2714  endif
2715  else
2716  cs%use_LOTW_BBL_diffusivity = .false. ! This parameterization depends on a u* from viscous BBL
2717  endif
2718  cs%id_Kd_BBL = register_diag_field('ocean_model','Kd_BBL',diag%axesTi,time, &
2719  'Bottom Boundary Layer Diffusivity', 'meter2 sec-1')
2720  call get_param(param_file, mdl, "SIMPLE_TKE_TO_KD", cs%simple_TKE_to_Kd, &
2721  "If true, uses a simple estimate of Kd/TKE that will\n"//&
2722  "work for arbitrary vertical coordinates. If false,\n"//&
2723  "calculates Kd/TKE and bounds based on exact energetics/n"//&
2724  "for an isopycnal layer-formulation.", &
2725  default=.false.)
2726 
2727  call get_param(param_file, mdl, "BRYAN_LEWIS_DIFFUSIVITY", &
2728  cs%Bryan_Lewis_diffusivity, &
2729  "If true, use a Bryan & Lewis (JGR 1979) like tanh \n"//&
2730  "profile of background diapycnal diffusivity with depth.", &
2731  default=.false.)
2732  if (cs%Bryan_Lewis_diffusivity) then
2733  call get_param(param_file, mdl, "KD_BRYAN_LEWIS_DEEP", &
2734  cs%Kd_Bryan_Lewis_deep, &
2735  "The abyssal value of a Bryan-Lewis diffusivity profile. \n"//&
2736  "KD_BRYAN_LEWIS_DEEP is only used if \n"//&
2737  "BRYAN_LEWIS_DIFFUSIVITY is true.", units="m2 s-1", &
2738  fail_if_missing=.true.)
2739  call get_param(param_file, mdl, "KD_BRYAN_LEWIS_SURFACE", &
2740  cs%Kd_Bryan_Lewis_surface, &
2741  "The surface value of a Bryan-Lewis diffusivity profile. \n"//&
2742  "KD_BRYAN_LEWIS_SURFACE is only used if \n"//&
2743  "BRYAN_LEWIS_DIFFUSIVITY is true.", units="m2 s-1", &
2744  fail_if_missing=.true.)
2745  call get_param(param_file, mdl, "BRYAN_LEWIS_DEPTH_CENT", &
2746  cs%Bryan_Lewis_depth_cent, &
2747  "The depth about which the transition in the Bryan-Lewis \n"//&
2748  "profile is centered. BRYAN_LEWIS_DEPTH_CENT is only \n"//&
2749  "used if BRYAN_LEWIS_DIFFUSIVITY is true.", units="m", &
2750  fail_if_missing=.true.)
2751  call get_param(param_file, mdl, "BRYAN_LEWIS_WIDTH_TRANS", &
2752  cs%Bryan_Lewis_width_trans, &
2753  "The width of the transition in the Bryan-Lewis \n"//&
2754  "profile. BRYAN_LEWIS_WIDTH_TRANS is only \n"//&
2755  "used if BRYAN_LEWIS_DIFFUSIVITY is true.", units="m", &
2756  fail_if_missing=.true.)
2757  endif
2758 
2759  call get_param(param_file, mdl, "HENYEY_IGW_BACKGROUND", &
2760  cs%Henyey_IGW_background, &
2761  "If true, use a latitude-dependent scaling for the near \n"//&
2762  "surface background diffusivity, as described in \n"//&
2763  "Harrison & Hallberg, JPO 2008.", default=.false.)
2764  call get_param(param_file, mdl, "HENYEY_IGW_BACKGROUND_NEW", &
2765  cs%Henyey_IGW_background_new, &
2766  "If true, use a better latitude-dependent scaling for the\n"//&
2767  "background diffusivity, as described in \n"//&
2768  "Harrison & Hallberg, JPO 2008.", default=.false.)
2769  if (cs%Henyey_IGW_background .and. cs%Henyey_IGW_background_new) call mom_error(fatal, &
2770  "set_diffusivity_init: HENYEY_IGW_BACKGROUND and HENYEY_IGW_BACKGROUND_NEW "// &
2771  "are mutually exclusive. Set only one or none.")
2772  if (cs%Henyey_IGW_background) &
2773  call get_param(param_file, mdl, "HENYEY_N0_2OMEGA", cs%N0_2Omega, &
2774  "The ratio of the typical Buoyancy frequency to twice \n"//&
2775  "the Earth's rotation period, used with the Henyey \n"//&
2776  "scaling from the mixing.", units="nondim", default=20.0)
2777  call get_param(param_file, mdl, "N2_FLOOR_IOMEGA2", cs%N2_FLOOR_IOMEGA2, &
2778  "The floor applied to N2(k) scaled by Omega^2:\n"//&
2779  "\tIf =0., N2(k) is simply positive definite.\n"//&
2780  "\tIf =1., N2(k) > Omega^2 everywhere.", units="nondim", &
2781  default=1.0)
2782 
2783  call get_param(param_file, mdl, "KD_TANH_LAT_FN", &
2784  cs%Kd_tanh_lat_fn, &
2785  "If true, use a tanh dependence of Kd_sfc on latitude, \n"//&
2786  "like CM2.1/CM2M. There is no physical justification \n"//&
2787  "for this form, and it can not be used with \n"//&
2788  "HENYEY_IGW_BACKGROUND.", default=.false.)
2789  if (cs%Kd_tanh_lat_fn) &
2790  call get_param(param_file, mdl, "KD_TANH_LAT_SCALE", &
2791  cs%Kd_tanh_lat_scale, &
2792  "A nondimensional scaling for the range ofdiffusivities \n"//&
2793  "with KD_TANH_LAT_FN. Valid values are in the range of \n"//&
2794  "-2 to 2; 0.4 reproduces CM2M.", units="nondim", default=0.0)
2795 
2796  call get_param(param_file, mdl, "KV", cs%Kv, &
2797  "The background kinematic viscosity in the interior. \n"//&
2798  "The molecular value, ~1e-6 m2 s-1, may be used.", &
2799  units="m2 s-1", fail_if_missing=.true.)
2800 
2801  call get_param(param_file, mdl, "KD", cs%Kd, &
2802  "The background diapycnal diffusivity of density in the \n"//&
2803  "interior. Zero or the molecular value, ~1e-7 m2 s-1, \n"//&
2804  "may be used.", units="m2 s-1", fail_if_missing=.true.)
2805  call get_param(param_file, mdl, "KD_MIN", cs%Kd_min, &
2806  "The minimum diapycnal diffusivity.", &
2807  units="m2 s-1", default=0.01*cs%Kd)
2808  call get_param(param_file, mdl, "KD_MAX", cs%Kd_max, &
2809  "The maximum permitted increment for the diapycnal \n"//&
2810  "diffusivity from TKE-based parameterizations, or a \n"//&
2811  "negative value for no limit.", units="m2 s-1", default=-1.0)
2812  if (cs%simple_TKE_to_Kd .and. cs%Kd_max<=0.) call mom_error(fatal, &
2813  "set_diffusivity_init: To use SIMPLE_TKE_TO_KD, KD_MAX must be set to >0.")
2814  call get_param(param_file, mdl, "KD_ADD", cs%Kd_add, &
2815  "A uniform diapycnal diffusivity that is added \n"//&
2816  "everywhere without any filtering or scaling.", &
2817  units="m2 s-1", default=0.0)
2818  if (cs%use_LOTW_BBL_diffusivity .and. cs%Kd_max<=0.) call mom_error(fatal, &
2819  "set_diffusivity_init: KD_MAX must be set (positive) when "// &
2820  "USE_LOTW_BBL_DIFFUSIVITY=True.")
2821 
2822  if (cs%bulkmixedlayer) then
2823  ! Check that Kdml is not set when using bulk mixed layer
2824  call get_param(param_file, mdl, "KDML", cs%Kdml, default=-1.)
2825  if (cs%Kdml>0.) call mom_error(fatal, &
2826  "set_diffusivity_init: KDML cannot be set when using"// &
2827  "bulk mixed layer.")
2828  cs%Kdml = cs%Kd ! This is not used with a bulk mixed layer, but also
2829  ! cannot be a NaN.
2830  else
2831  call get_param(param_file, mdl, "KDML", cs%Kdml, &
2832  "If BULKMIXEDLAYER is false, KDML is the elevated \n"//&
2833  "diapycnal diffusivity in the topmost HMIX of fluid. \n"//&
2834  "KDML is only used if BULKMIXEDLAYER is false.", &
2835  units="m2 s-1", default=cs%Kd)
2836  call get_param(param_file, mdl, "HMIX_FIXED", cs%Hmix, &
2837  "The prescribed depth over which the near-surface \n"//&
2838  "viscosity and diffusivity are elevated when the bulk \n"//&
2839  "mixed layer is not used.", units="m", fail_if_missing=.true.)
2840  endif
2841  call get_param(param_file, mdl, "DEBUG", cs%debug, &
2842  "If true, write out verbose debugging data.", default=.false.)
2843 
2844  call get_param(param_file, mdl, "INT_TIDE_DISSIPATION", cs%Int_tide_dissipation, &
2845  "If true, use an internal tidal dissipation scheme to \n"//&
2846  "drive diapycnal mixing, along the lines of St. Laurent \n"//&
2847  "et al. (2002) and Simmons et al. (2004).", default=.false.)
2848  if (cs%Int_tide_dissipation) then
2849  call get_param(param_file, mdl, "INT_TIDE_PROFILE", tmpstr, &
2850  "INT_TIDE_PROFILE selects the vertical profile of energy \n"//&
2851  "dissipation with INT_TIDE_DISSIPATION. Valid values are:\n"//&
2852  "\t STLAURENT_02 - Use the St. Laurent et al exponential \n"//&
2853  "\t decay profile.\n"//&
2854  "\t POLZIN_09 - Use the Polzin WKB-streched algebraic \n"//&
2855  "\t decay profile.", &
2856  default=stlaurent_profile_string)
2857  tmpstr = uppercase(tmpstr)
2858  select case (tmpstr)
2859  case (stlaurent_profile_string) ; cs%int_tide_profile = stlaurent_02
2860  case (polzin_profile_string) ; cs%int_tide_profile = polzin_09
2861  case default
2862  call mom_error(fatal, "set_diffusivity_init: Unrecognized setting "// &
2863  "#define INT_TIDE_PROFILE "//trim(tmpstr)//" found in input file.")
2864  end select
2865  endif
2866 
2867  call get_param(param_file, mdl, "LEE_WAVE_DISSIPATION", cs%Lee_wave_dissipation, &
2868  "If true, use an lee wave driven dissipation scheme to \n"//&
2869  "drive diapycnal mixing, along the lines of Nikurashin \n"//&
2870  "(2010) and using the St. Laurent et al. (2002) \n"//&
2871  "and Simmons et al. (2004) vertical profile", default=.false.)
2872  if (cs%lee_wave_dissipation) then
2873  call get_param(param_file, mdl, "LEE_WAVE_PROFILE", tmpstr, &
2874  "LEE_WAVE_PROFILE selects the vertical profile of energy \n"//&
2875  "dissipation with LEE_WAVE_DISSIPATION. Valid values are:\n"//&
2876  "\t STLAURENT_02 - Use the St. Laurent et al exponential \n"//&
2877  "\t decay profile.\n"//&
2878  "\t POLZIN_09 - Use the Polzin WKB-streched algebraic \n"//&
2879  "\t decay profile.", &
2880  default=stlaurent_profile_string)
2881  tmpstr = uppercase(tmpstr)
2882  select case (tmpstr)
2883  case (stlaurent_profile_string) ; cs%lee_wave_profile = stlaurent_02
2884  case (polzin_profile_string) ; cs%lee_wave_profile = polzin_09
2885  case default
2886  call mom_error(fatal, "set_diffusivity_init: Unrecognized setting "// &
2887  "#define LEE_WAVE_PROFILE "//trim(tmpstr)//" found in input file.")
2888  end select
2889  endif
2890 
2891  call get_param(param_file, mdl, "INT_TIDE_LOWMODE_DISSIPATION", cs%Lowmode_itidal_dissipation, &
2892  "If true, consider mixing due to breaking low modes that \n"//&
2893  "have been remotely generated; as with itidal drag on the \n"//&
2894  "barotropic tide, use an internal tidal dissipation scheme to \n"//&
2895  "drive diapycnal mixing, along the lines of St. Laurent \n"//&
2896  "et al. (2002) and Simmons et al. (2004).", default=.false.)
2897 
2898  if ((cs%Int_tide_dissipation .and. (cs%int_tide_profile == polzin_09)) .or. &
2899  (cs%lee_wave_dissipation .and. (cs%lee_wave_profile == polzin_09))) then
2900  call get_param(param_file, mdl, "NU_POLZIN", cs%Nu_Polzin, &
2901  "When the Polzin decay profile is used, this is a \n"//&
2902  "non-dimensional constant in the expression for the \n"//&
2903  "vertical scale of decay for the tidal energy dissipation.", &
2904  units="nondim", default=0.0697)
2905  call get_param(param_file, mdl, "NBOTREF_POLZIN", cs%Nbotref_Polzin, &
2906  "When the Polzin decay profile is used, this is the \n"//&
2907  "Rreference value of the buoyancy frequency at the ocean \n"//&
2908  "bottom in the Polzin formulation for the vertical \n"//&
2909  "scale of decay for the tidal energy dissipation.", &
2910  units="s-1", default=9.61e-4)
2911  call get_param(param_file, mdl, "POLZIN_DECAY_SCALE_FACTOR", &
2912  cs%Polzin_decay_scale_factor, &
2913  "When the Polzin decay profile is used, this is a \n"//&
2914  "scale factor for the vertical scale of decay of the tidal \n"//&
2915  "energy dissipation.", default=1.0, units="nondim")
2916  call get_param(param_file, mdl, "POLZIN_SCALE_MAX_FACTOR", &
2917  cs%Polzin_decay_scale_max_factor, &
2918  "When the Polzin decay profile is used, this is a factor \n"//&
2919  "to limit the vertical scale of decay of the tidal \n"//&
2920  "energy dissipation to POLZIN_DECAY_SCALE_MAX_FACTOR \n"//&
2921  "times the depth of the ocean.", units="nondim", default=1.0)
2922  call get_param(param_file, mdl, "POLZIN_MIN_DECAY_SCALE", cs%Polzin_min_decay_scale, &
2923  "When the Polzin decay profile is used, this is the \n"//&
2924  "minimum vertical decay scale for the vertical profile\n"//&
2925  "of internal tide dissipation with the Polzin (2009) formulation", &
2926  units="m", default=0.0)
2927  endif
2928  call get_param(param_file, mdl, "USER_CHANGE_DIFFUSIVITY", cs%user_change_diff, &
2929  "If true, call user-defined code to change the diffusivity.", &
2930  default=.false.)
2931 
2932  call get_param(param_file, mdl, "DISSIPATION_MIN", cs%dissip_min, &
2933  "The minimum dissipation by which to determine a lower \n"//&
2934  "bound of Kd (a floor).", units="W m-3", default=0.0)
2935  call get_param(param_file, mdl, "DISSIPATION_N0", cs%dissip_N0, &
2936  "The intercept when N=0 of the N-dependent expression \n"//&
2937  "used to set a minimum dissipation by which to determine \n"//&
2938  "a lower bound of Kd (a floor): A in eps_min = A + B*N.", &
2939  units="W m-3", default=0.0)
2940  call get_param(param_file, mdl, "DISSIPATION_N1", cs%dissip_N1, &
2941  "The coefficient multiplying N, following Gargett, used to \n"//&
2942  "set a minimum dissipation by which to determine a lower \n"//&
2943  "bound of Kd (a floor): B in eps_min = A + B*N", &
2944  units="J m-3", default=0.0)
2945  call get_param(param_file, mdl, "DISSIPATION_KD_MIN", cs%dissip_Kd_min, &
2946  "The minimum vertical diffusivity applied as a floor.", &
2947  units="m2 s-1", default=0.0)
2948 
2949  cs%limit_dissipation = (cs%dissip_min>0.) .or. (cs%dissip_N1>0.) .or. &
2950  (cs%dissip_N0>0.) .or. (cs%dissip_Kd_min>0.)
2951  cs%dissip_N2 = 0.0
2952  if (cs%FluxRi_max > 0.0) &
2953  cs%dissip_N2 = cs%dissip_Kd_min * gv%Rho0 / cs%FluxRi_max
2954 
2955  if (cs%Int_tide_dissipation .or. cs%Lee_wave_dissipation) then
2956  call get_param(param_file, mdl, "INT_TIDE_DECAY_SCALE", cs%Int_tide_decay_scale, &
2957  "The decay scale away from the bottom for tidal TKE with \n"//&
2958  "the new coding when INT_TIDE_DISSIPATION is used.", &
2959  units="m", default=0.0)
2960  call get_param(param_file, mdl, "MU_ITIDES", cs%Mu_itides, &
2961  "A dimensionless turbulent mixing efficiency used with \n"//&
2962  "INT_TIDE_DISSIPATION, often 0.2.", units="nondim", default=0.2)
2963  call get_param(param_file, mdl, "GAMMA_ITIDES", cs%Gamma_itides, &
2964  "The fraction of the internal tidal energy that is \n"//&
2965  "dissipated locally with INT_TIDE_DISSIPATION. \n"//&
2966  "THIS NAME COULD BE BETTER.", &
2967  units="nondim", default=0.3333)
2968  call get_param(param_file, mdl, "MIN_ZBOT_ITIDES", cs%min_zbot_itides, &
2969  "Turn off internal tidal dissipation when the total \n"//&
2970  "ocean depth is less than this value.", units="m", default=0.0)
2971 
2972  call safe_alloc_ptr(cs%Nb,isd,ied,jsd,jed)
2973  call safe_alloc_ptr(cs%h2,isd,ied,jsd,jed)
2974  call safe_alloc_ptr(cs%TKE_itidal,isd,ied,jsd,jed)
2975  call safe_alloc_ptr(cs%mask_itidal,isd,ied,jsd,jed) ; cs%mask_itidal(:,:) = 1.0
2976 
2977  call get_param(param_file, mdl, "KAPPA_ITIDES", cs%kappa_itides, &
2978  "A topographic wavenumber used with INT_TIDE_DISSIPATION. \n"//&
2979  "The default is 2pi/10 km, as in St.Laurent et al. 2002.", &
2980  units="m-1", default=8.e-4*atan(1.0))
2981 
2982  call get_param(param_file, mdl, "UTIDE", cs%utide, &
2983  "The constant tidal amplitude used with INT_TIDE_DISSIPATION.", &
2984  units="m s-1", default=0.0)
2985  call safe_alloc_ptr(cs%tideamp,is,ie,js,je) ; cs%tideamp(:,:) = cs%utide
2986 
2987  call get_param(param_file, mdl, "KAPPA_H2_FACTOR", cs%kappa_h2_factor, &
2988  "A scaling factor for the roughness amplitude with n"//&
2989  "INT_TIDE_DISSIPATION.", units="nondim", default=1.0)
2990  call get_param(param_file, mdl, "TKE_ITIDE_MAX", cs%TKE_itide_max, &
2991  "The maximum internal tide energy source availble to mix \n"//&
2992  "above the bottom boundary layer with INT_TIDE_DISSIPATION.", &
2993  units="W m-2", default=1.0e3)
2994 
2995  call get_param(param_file, mdl, "READ_TIDEAMP", read_tideamp, &
2996  "If true, read a file (given by TIDEAMP_FILE) containing \n"//&
2997  "the tidal amplitude with INT_TIDE_DISSIPATION.", default=.false.)
2998  if (read_tideamp) then
2999  call get_param(param_file, mdl, "TIDEAMP_FILE", tideamp_file, &
3000  "The path to the file containing the spatially varying \n"//&
3001  "tidal amplitudes with INT_TIDE_DISSIPATION.", default="tideamp.nc")
3002  filename = trim(cs%inputdir) // trim(tideamp_file)
3003  call log_param(param_file, mdl, "INPUTDIR/TIDEAMP_FILE", filename)
3004  call read_data(filename, 'tideamp', cs%tideamp, &
3005  domain=g%domain%mpp_domain, timelevel=1)
3006  endif
3007 
3008  call get_param(param_file, mdl, "H2_FILE", h2_file, &
3009  "The path to the file containing the sub-grid-scale \n"//&
3010  "topographic roughness amplitude with INT_TIDE_DISSIPATION.", &
3011  fail_if_missing=.true.)
3012  filename = trim(cs%inputdir) // trim(h2_file)
3013  call log_param(param_file, mdl, "INPUTDIR/H2_FILE", filename)
3014  call read_data(filename, 'h2', cs%h2, domain=g%domain%mpp_domain, &
3015  timelevel=1)
3016 
3017  do j=js,je ; do i=is,ie
3018  if (g%bathyT(i,j) < cs%min_zbot_itides) cs%mask_itidal(i,j) = 0.0
3019  cs%tideamp(i,j) = cs%tideamp(i,j) * cs%mask_itidal(i,j) * g%mask2dT(i,j)
3020 
3021  ! Restrict rms topo to 10 percent of column depth.
3022  zbot = g%bathyT(i,j)
3023  hamp = sqrt(cs%h2(i,j))
3024  hamp = min(0.1*zbot,hamp)
3025  cs%h2(i,j) = hamp*hamp
3026 
3027  utide = cs%tideamp(i,j)
3028  ! Compute the fixed part of internal tidal forcing; units are [kg s-2] here.
3029  cs%TKE_itidal(i,j) = 0.5*cs%kappa_h2_factor*gv%Rho0*&
3030  cs%kappa_itides*cs%h2(i,j)*utide*utide
3031  enddo; enddo
3032 
3033  endif
3034 
3035  cs%id_Kd_layer = register_diag_field('ocean_model', 'Kd_layer', diag%axesTL, time, &
3036  'Diapycnal diffusivity of layers (as set)', 'meter2 second-1')
3037 
3038  if (cs%Lee_wave_dissipation) then
3039 
3040  call get_param(param_file, mdl, "NIKURASHIN_TKE_INPUT_FILE",niku_tke_input_file, &
3041  "The path to the file containing the TKE input from lee \n"//&
3042  "wave driven mixing. Used with LEE_WAVE_DISSIPATION.", &
3043  fail_if_missing=.true.)
3044  call get_param(param_file, mdl, "NIKURASHIN_SCALE",niku_scale, &
3045  "A non-dimensional factor by which to scale the lee-wave \n"//&
3046  "driven TKE input. Used with LEE_WAVE_DISSIPATION.", &
3047  units="nondim", default=1.0)
3048 
3049  filename = trim(cs%inputdir) // trim(niku_tke_input_file)
3050  call log_param(param_file, mdl, "INPUTDIR/NIKURASHIN_TKE_INPUT_FILE", &
3051  filename)
3052  call safe_alloc_ptr(cs%TKE_Niku,is,ie,js,je); cs%TKE_Niku(:,:) = 0.0
3053  call read_data(filename, 'TKE_input', cs%TKE_Niku, &
3054  domain=g%domain%mpp_domain, timelevel=1 ) ! ??? timelevel -aja
3055  cs%TKE_Niku(:,:) = niku_scale * cs%TKE_Niku(:,:)
3056 
3057  call get_param(param_file, mdl, "GAMMA_NIKURASHIN",cs%Gamma_lee, &
3058  "The fraction of the lee wave energy that is dissipated \n"//&
3059  "locally with LEE_WAVE_DISSIPATION.", units="nondim", &
3060  default=0.3333)
3061  call get_param(param_file, mdl, "DECAY_SCALE_FACTOR_LEE",cs%Decay_scale_factor_lee, &
3062  "Scaling for the vertical decay scaleof the local \n"//&
3063  "dissipation of lee waves dissipation.", units="nondim", &
3064  default=1.0)
3065 
3066  cs%id_TKE_leewave = register_diag_field('ocean_model','TKE_leewave',diag%axesT1,time, &
3067  'Lee wave Driven Turbulent Kinetic Energy', 'Watt meter-2')
3068  cs%id_Kd_Niku = register_diag_field('ocean_model','Kd_Nikurashin',diag%axesTi,time, &
3069  'Lee Wave Driven Diffusivity', 'meter2 sec-1')
3070  else
3071  cs%Decay_scale_factor_lee = -9.e99 ! This should never be used if CS%Lee_wave_dissipation = False
3072  endif
3073 
3074  if (cs%Int_tide_dissipation .or. cs%Lee_wave_dissipation .or. &
3075  cs%Lowmode_itidal_dissipation) then
3076 
3077  cs%id_TKE_itidal = register_diag_field('ocean_model','TKE_itidal',diag%axesT1,time, &
3078  'Internal Tide Driven Turbulent Kinetic Energy', 'Watt meter-2')
3079  cs%id_maxTKE = register_diag_field('ocean_model','maxTKE',diag%axesTL,time, &
3080  'Maximum layer TKE', 'meter3 second-3')
3081  cs%id_TKE_to_Kd = register_diag_field('ocean_model','TKE_to_Kd',diag%axesTL,time, &
3082  'Convert TKE to Kd', 'second2 meter')
3083 
3084  cs%id_Nb = register_diag_field('ocean_model','Nb',diag%axesT1,time, &
3085  'Bottom Buoyancy Frequency', 'sec-1')
3086 
3087  cs%id_Kd_itidal = register_diag_field('ocean_model','Kd_itides',diag%axesTi,time, &
3088  'Internal Tide Driven Diffusivity', 'meter2 sec-1')
3089 
3090  cs%id_Kd_lowmode = register_diag_field('ocean_model','Kd_lowmode',diag%axesTi,time, &
3091  'Internal Tide Driven Diffusivity (from propagating low modes)', 'meter2 sec-1')
3092 
3093  cs%id_Fl_itidal = register_diag_field('ocean_model','Fl_itides',diag%axesTi,time, &
3094  'Vertical flux of tidal turbulent dissipation', 'meter3 sec-3')
3095 
3096  cs%id_Fl_lowmode = register_diag_field('ocean_model','Fl_lowmode',diag%axesTi,time, &
3097  'Vertical flux of tidal turbulent dissipation (from propagating low modes)', 'meter3 sec-3')
3098 
3099  cs%id_Polzin_decay_scale = register_diag_field('ocean_model','Polzin_decay_scale',diag%axesT1,time, &
3100  'Vertical decay scale for the tidal turbulent dissipation with Polzin scheme', 'meter')
3101 
3102  cs%id_Polzin_decay_scale_scaled = register_diag_field('ocean_model','Polzin_decay_scale_scaled',diag%axesT1,time, &
3103  'Vertical decay scale for the tidal turbulent dissipation with Polzin scheme, scaled by N2_bot/N2_meanz', 'meter')
3104 
3105  cs%id_N2_bot = register_diag_field('ocean_model','N2_b',diag%axesT1,time, &
3106  'Bottom Buoyancy frequency squared', 's-2')
3107 
3108  cs%id_N2_meanz = register_diag_field('ocean_model','N2_meanz',diag%axesT1,time, &
3109  'Buoyancy frequency squared averaged over the water column', 's-2')
3110 
3111  cs%id_Kd_Work = register_diag_field('ocean_model','Kd_Work',diag%axesTL,time, &
3112  'Work done by Diapycnal Mixing', 'Watts m-2')
3113 
3114  cs%id_Kd_Itidal_Work = register_diag_field('ocean_model','Kd_Itidal_Work',diag%axesTL,time, &
3115  'Work done by Internal Tide Diapycnal Mixing', 'Watts m-2')
3116 
3117  cs%id_Kd_Niku_Work = register_diag_field('ocean_model','Kd_Nikurashin_Work',diag%axesTL,time, &
3118  'Work done by Nikurashin Lee Wave Drag Scheme', 'Watts m-2')
3119 
3120  cs%id_Kd_Lowmode_Work = register_diag_field('ocean_model','Kd_Lowmode_Work',diag%axesTL,time, &
3121  'Work done by Internal Tide Diapycnal Mixing (low modes)', 'Watts m-2')
3122 
3123  cs%id_N2 = register_diag_field('ocean_model','N2',diag%axesTi,time, &
3124  'Buoyancy frequency squared', 'sec-2', cmor_field_name='obvfsq', &
3125  cmor_units='s-2', cmor_long_name='Square of seawater buoyancy frequency',&
3126  cmor_standard_name='square_of_brunt_vaisala_frequency_in_sea_water')
3127 
3128  if (cs%user_change_diff) &
3129  cs%id_Kd_user = register_diag_field('ocean_model','Kd_user',diag%axesTi,time, &
3130  'User-specified Extra Diffusivity', 'meter2 sec-1')
3131 
3132  if (associated(diag_to_z_csp)) then
3133  vd = var_desc("N2", "second-2",&
3134  "Buoyancy frequency, interpolated to z", z_grid='z')
3135  cs%id_N2_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3136  vd = var_desc("Kd_itides","meter2 second-1", &
3137  "Internal Tide Driven Diffusivity, interpolated to z", z_grid='z')
3138  cs%id_Kd_itidal_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3139  if (cs%Lee_wave_dissipation) then
3140  vd = var_desc("Kd_Nikurashin", "meter2 second-1", &
3141  "Lee Wave Driven Diffusivity, interpolated to z", z_grid='z')
3142  cs%id_Kd_Niku_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3143  endif
3144  if (cs%Lowmode_itidal_dissipation) then
3145  vd = var_desc("Kd_lowmode","meter2 second-1", &
3146  "Internal Tide Driven Diffusivity (from low modes), interpolated to z",&
3147  z_grid='z')
3148  cs%id_Kd_lowmode_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3149  endif
3150  if (cs%user_change_diff) &
3151  cs%id_Kd_user_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3152  endif
3153  endif
3154 
3155  call get_param(param_file, mdl, "DOUBLE_DIFFUSION", cs%double_diffusion, &
3156  "If true, increase diffusivitives for temperature or salt \n"//&
3157  "based on double-diffusive paramaterization from MOM4/KPP.", &
3158  default=.false.)
3159  if (cs%double_diffusion) then
3160  call get_param(param_file, mdl, "MAX_RRHO_SALT_FINGERS", cs%Max_Rrho_salt_fingers, &
3161  "Maximum density ratio for salt fingering regime.", &
3162  default=2.55, units="nondim")
3163  call get_param(param_file, mdl, "MAX_SALT_DIFF_SALT_FINGERS", cs%Max_salt_diff_salt_fingers, &
3164  "Maximum salt diffusivity for salt fingering regime.", &
3165  default=1.e-4, units="m2 s-1")
3166  call get_param(param_file, mdl, "KV_MOLECULAR", cs%Kv_molecular, &
3167  "Molecular viscosity for calculation of fluxes under \n"//&
3168  "double-diffusive convection.", default=1.5e-6, units="m2 s-1")
3169  ! The default molecular viscosity follows the CCSM4.0 and MOM4p1 defaults.
3170 
3171  cs%id_KT_extra = register_diag_field('ocean_model','KT_extra',diag%axesTi,time, &
3172  'Double-diffusive diffusivity for temperature', 'meter2 sec-1')
3173 
3174  cs%id_KS_extra = register_diag_field('ocean_model','KS_extra',diag%axesTi,time, &
3175  'Double-diffusive diffusivity for salinity', 'meter2 sec-1')
3176 
3177  if (associated(diag_to_z_csp)) then
3178  vd = var_desc("KT_extra", "meter2 second-1", &
3179  "Double-Diffusive Temperature Diffusivity, interpolated to z", &
3180  z_grid='z')
3181  cs%id_KT_extra_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3182  vd = var_desc("KS_extra", "meter2 second-1", &
3183  "Double-Diffusive Salinity Diffusivity, interpolated to z",&
3184  z_grid='z')
3185  cs%id_KS_extra_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3186  vd = var_desc("Kd_BBL", "meter2 second-1", &
3187  "Bottom Boundary Layer Diffusivity", z_grid='z')
3188  cs%id_Kd_BBL_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
3189  endif
3190  endif
3191 
3192  if (cs%Int_tide_dissipation .and. cs%Bryan_Lewis_diffusivity) &
3193  call mom_error(fatal,"MOM_Set_Diffusivity: "// &
3194  "Bryan-Lewis and internal tidal dissipation are both enabled. Choose one.")
3195  if (cs%Henyey_IGW_background .and. cs%Kd_tanh_lat_fn) call mom_error(fatal, &
3196  "Set_diffusivity: KD_TANH_LAT_FN can not be used with HENYEY_IGW_BACKGROUND.")
3197 
3198  if (cs%user_change_diff) then
3199  call user_change_diff_init(time, g, param_file, diag, cs%user_change_diff_CSp)
3200  endif
3201 
3202  cs%useKappaShear = kappa_shear_init(time, g, gv, param_file, cs%diag, cs%kappaShear_CSp)
3203  if (cs%useKappaShear) &
3204  id_clock_kappashear = cpu_clock_id('(Ocean kappa_shear)', grain=clock_module)
3205  cs%useCVMix = cvmix_shear_init(time, g, gv, param_file, cs%diag, cs%CVMix_shear_CSp)
3206 
3207 
3208 
3209 end subroutine set_diffusivity_init
3210 
3211 subroutine set_diffusivity_end(CS)
3212  type(set_diffusivity_cs), pointer :: CS
3213 
3214  if (cs%user_change_diff) &
3215  call user_change_diff_end(cs%user_change_diff_CSp)
3216 
3217  if (associated(cs)) deallocate(cs)
3218 
3219 end subroutine set_diffusivity_end
3220 
3221 end module mom_set_diffusivity
subroutine add_int_tide_diffusivity(h, N2_bot, j, TKE_to_Kd, max_TKE, G, GV, CS, dd, N2_lay, Kd, Kd_int)
This subroutine adds the effect of internal-tide-driven mixing to the layer diffusivities. The mechanisms considered are (1) local dissipation of internal waves generated by the barotropic flow ("itidal"), (2) local dissipation of internal waves generated by the propagating low modes (rays) of the internal tide ("lowmode"), and (3) local dissipation of internal lee waves. Will eventually need to add diffusivity due to other wave-breaking processes (e.g. Bottom friction, Froude-number-depending breaking, PSI, etc.).
character *(20), parameter polzin_profile_string
subroutine, public set_diffusivity_end(CS)
subroutine add_drag_diffusivity(h, u, v, tv, fluxes, visc, j, TKE_to_Kd, maxTKE, kb, G, GV, CS, Kd, Kd_int, Kd_BBL)
This routine adds diffusion sustained by flow energy extracted by bottom drag.
subroutine, public user_change_diff_end(CS)
Clean up the module control structure.
type(vardesc) function, public var_desc(name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, conversion, caller)
Returns a vardesc type whose elements have been filled with the provided fields. The argument name is...
Definition: MOM_io.F90:585
subroutine set_density_ratios(h, tv, kb, G, GV, CS, j, ds_dsp1, rho_0)
This module implements boundary forcing for MOM6.
Control structure including parameters for CVMix interior shear schemes.
Interface to CVMix interior shear schemes.
subroutine, public vert_fill_ts(h, T_in, S_in, kappa, dt, T_f, S_f, G, GV, halo_here)
Fills tracer values in massless layers with sensible values by diffusing vertically with a (small) co...
integer, parameter stlaurent_02
subroutine double_diffusion(tv, h, T_f, S_f, j, G, GV, CS, Kd_T_dd, Kd_S_dd)
This subroutine sets the additional diffusivities of temperature and salinity due to double diffusion...
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
subroutine, public calculate_cvmix_shear(u_H, v_H, h, tv, KH, KM, G, GV, CS)
Subroutine for calculating (internal) diffusivity.
Provides the ocean grid type.
Definition: MOM_grid.F90:2
The vertvisc_type structure contains vertical viscosities, drag coefficients, and related fields...
subroutine, public get_lowmode_loss(i, j, G, CS, mechanism, TKE_loss_sum)
This subroutine extracts the energy lost from the propagating internal which has been summed across a...
logical function, public cvmix_shear_init(Time, G, GV, param_file, diag, CS)
Initialized the cvmix internal shear mixing routine.
subroutine, public user_change_diff_init(Time, G, param_file, diag, CS)
Set up the module control structure.
subroutine, public calltree_leave(mesg)
Writes a message about leaving a subroutine if call tree reporting is active.
This module contains I/O framework code.
Definition: MOM_io.F90:2
subroutine, public set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, optics, visc, dt, G, GV, CS, Kd, Kd_int)
logical function, public kappa_shear_init(Time, G, GV, param_file, diag, CS)
character *(20), parameter stlaurent_profile_string
real function, public invcosh(x)
subroutine, public set_diffusivity_init(Time, G, GV, param_file, diag, CS, diag_to_Z_CSp, int_tide_CSp)
integer, parameter polzin_09
subroutine, public calltree_waypoint(mesg, n)
Writes a message about reaching a milestone if call tree reporting is active.
subroutine, public calculate_density_derivs(T, S, pressure, drho_dT, drho_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate density derivatives for 1-D array inputs.
Definition: MOM_EOS.F90:214
character(len=len(input_string)) function, public uppercase(input_string)
subroutine add_mlrad_diffusivity(h, fluxes, j, G, GV, CS, Kd, TKE_to_Kd, Kd_int)
This routine adds effects of mixed layer radiation to the layer diffusivities.
Thickness diffusion (or Gent McWilliams)
logical function, public is_root_pe()
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
logical function, public calltree_showquery()
Returns True, if the verbosity>=6 indicating to show the call tree.
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:51
subroutine, public user_change_diff(h, tv, G, CS, Kd, Kd_int, T_f, S_f, Kd_int_add)
This subroutine provides an interface for a user to use to modify the main code to alter the diffusiv...
subroutine, public set_bbl_tke(u, v, h, fluxes, visc, G, GV, CS)
This subroutine calculates several properties related to bottom boundary layer turbulence.
subroutine find_tke_to_kd(h, tv, dRho_int, N2_lay, j, dt, G, GV, CS, TKE_to_Kd, maxTKE, kb)
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine add_lotw_bbl_diffusivity(h, u, v, tv, fluxes, visc, j, N2_int, G, GV, CS, Kd, Kd_int, Kd_BBL)
Calculates a BBL diffusivity use a Prandtl number 1 diffusivitiy with a law of the wall turbulent vis...
integer function, public register_zint_diag(var_desc, CS, day)
By Robert Hallberg, May 2012.
subroutine find_n2(h, tv, T_f, S_f, fluxes, j, G, GV, CS, dRho_int, N2_lay, N2_int, N2_bot)
integer function, public register_diag_field(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name, cell_methods, x_cell_method, y_cell_method, v_cell_method, conversion, v_extensive)
Returns the "diag_mediator" handle for a group (native, CMOR, z-coord, ...) of diagnostics derived fr...
subroutine, public mom_error(level, message, all_print)
subroutine, public calc_zint_diags(h, in_ptrs, ids, num_diags, G, GV, CS)
subroutine, public calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, kv_io, dt, G, GV, CS, initialize_all)
Subroutine for calculating diffusivity and TKE.
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.