MOM6
MOM_CVMix_shear.F90
1 !> Interface to CVMix interior shear schemes
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 !> \author Brandon Reichl
7 
8 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
9 use mom_diag_mediator, only : diag_ctrl, time_type
10 use mom_error_handler, only : mom_error, is_root_pe, fatal, warning, note
12 use mom_grid, only : ocean_grid_type
16 use mom_eos, only : calculate_density
17 use cvmix_shear, only : cvmix_init_shear, cvmix_coeffs_shear
18 use mom_kappa_shear, only : kappa_shear_is_used
19 implicit none ; private
20 
21 #include <MOM_memory.h>
22 
23 public calculate_cvmix_shear, cvmix_shear_init, cvmix_shear_is_used, cvmix_shear_end
24 
25 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
26 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
27 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
28 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
29 
30 !> Control structure including parameters for CVMix interior shear schemes.
31 type, public :: cvmix_shear_cs ! TODO: private
32  logical :: use_lmd94 !< Flags to use the LMD94 scheme
33  logical :: use_pp81 !< Flags to use Pacanowski and Philander (JPO 1981)
34  logical :: smooth_ri !< If true, smooth Ri using a 1-2-1 filter
35  real :: ri_zero !< LMD94 critical Richardson number
36  real :: nu_zero !< LMD94 maximum interior diffusivity
37  real :: kpp_exp !< Exponent of unitless factor of diff.
38  !! for KPP internal shear mixing scheme.
39  real, allocatable, dimension(:,:,:) :: n2 !< Squared Brunt-Vaisala frequency [T-2 ~> s-2]
40  real, allocatable, dimension(:,:,:) :: s2 !< Squared shear frequency [T-2 ~> s-2]
41  real, allocatable, dimension(:,:,:) :: ri_grad !< Gradient Richardson number
42  real, allocatable, dimension(:,:,:) :: ri_grad_smooth !< Gradient Richardson number
43  !! after smoothing
44  character(10) :: mix_scheme !< Mixing scheme name (string)
45 
46  type(diag_ctrl), pointer :: diag => null() !< Pointer to the diagnostics control structure
47  !>@{ Diagnostic handles
48  integer :: id_n2 = -1, id_s2 = -1, id_ri_grad = -1, id_kv = -1, id_kd = -1
49  integer :: id_ri_grad_smooth = -1
50  !>@}
51 
52 end type cvmix_shear_cs
53 
54 character(len=40) :: mdl = "MOM_CVMix_shear" !< This module's name.
55 
56 contains
57 
58 !> Subroutine for calculating (internal) vertical diffusivities/viscosities
59 subroutine calculate_cvmix_shear(u_H, v_H, h, tv, kd, kv, G, GV, US, CS )
60  type(ocean_grid_type), intent(in) :: G !< Grid structure.
61  type(verticalgrid_type), intent(in) :: GV !< Vertical grid structure.
62  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
63  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: u_H !< Initial zonal velocity on T points [L T-1 ~> m s-1]
64  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: v_H !< Initial meridional velocity on T
65  !! points [L T-1 ~> m s-1]
66  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thickness [H ~> m or kg m-2].
67  type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamics structure.
68  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(out) :: kd !< The vertical diffusivity at each interface
69  !! (not layer!) [Z2 T-1 ~> m2 s-1].
70  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(out) :: kv !< The vertical viscosity at each interface
71  !! (not layer!) [Z2 T-1 ~> m2 s-1].
72  type(cvmix_shear_cs), pointer :: CS !< The control structure returned by a previous
73  !! call to CVMix_shear_init.
74  ! Local variables
75  integer :: i, j, k, kk, km1
76  real :: GoRho ! Gravitational acceleration divided by density [Z T-2 R-1 ~> m4 s-2 kg-2]
77  real :: pref ! Interface pressures [R L2 T-2 ~> Pa]
78  real :: DU, DV ! Velocity differences [L T-1 ~> m s-1]
79  real :: DZ ! Grid spacing around an interface [Z ~> m]
80  real :: N2 ! Buoyancy frequency at an interface [T-2 ~> s-2]
81  real :: S2 ! Shear squared at an interface [T-2 ~> s-2]
82  real :: dummy ! A dummy variable [nondim]
83  real :: dRho ! Buoyancy differences [Z T-2 ~> m s-2]
84  real, dimension(2*(G%ke)) :: pres_1d ! A column of interface pressures [R L2 T-2 ~> Pa]
85  real, dimension(2*(G%ke)) :: temp_1d ! A column of temperatures [degC]
86  real, dimension(2*(G%ke)) :: salt_1d ! A column of salinities [ppt]
87  real, dimension(2*(G%ke)) :: rho_1d ! A column of densities at interface pressures [R ~> kg m-3]
88  real, dimension(G%ke+1) :: Ri_Grad !< Gradient Richardson number [nondim]
89  real, dimension(G%ke+1) :: Kvisc !< Vertical viscosity at interfaces [m2 s-1]
90  real, dimension(G%ke+1) :: Kdiff !< Diapycnal diffusivity at interfaces [m2 s-1]
91  real :: epsln !< Threshold to identify vanished layers [H ~> m or kg m-2]
92 
93  ! some constants
94  gorho = us%L_to_Z**2 * gv%g_Earth / gv%Rho0
95  epsln = 1.e-10 * gv%m_to_H
96 
97  do j = g%jsc, g%jec
98  do i = g%isc, g%iec
99 
100  ! skip calling for land points
101  if (g%mask2dT(i,j)==0.) cycle
102 
103  ! Richardson number computed for each cell in a column.
104  pref = 0. ; if (associated(tv%p_surf)) pref = tv%p_surf(i,j)
105  ri_grad(:)=1.e8 !Initialize w/ large Richardson value
106  do k=1,g%ke
107  ! pressure, temp, and saln for EOS
108  ! kk+1 = k fields
109  ! kk+2 = km1 fields
110  km1 = max(1, k-1)
111  kk = 2*(k-1)
112  pres_1d(kk+1) = pref
113  pres_1d(kk+2) = pref
114  temp_1d(kk+1) = tv%T(i,j,k)
115  temp_1d(kk+2) = tv%T(i,j,km1)
116  salt_1d(kk+1) = tv%S(i,j,k)
117  salt_1d(kk+2) = tv%S(i,j,km1)
118 
119  ! pRef is pressure at interface between k and km1.
120  ! iterate pRef for next pass through k-loop.
121  pref = pref + (gv%g_Earth * gv%H_to_RZ) * h(i,j,k)
122 
123  enddo ! k-loop finishes
124 
125  ! compute in-situ density [R ~> kg m-3]
126  call calculate_density(temp_1d, salt_1d, pres_1d, rho_1d, tv%eqn_of_state)
127 
128  ! N2 (can be negative) on interface
129  do k = 1, g%ke
130  km1 = max(1, k-1)
131  kk = 2*(k-1)
132  du = u_h(i,j,k) - u_h(i,j,km1)
133  dv = v_h(i,j,k) - v_h(i,j,km1)
134  drho = gorho * (rho_1d(kk+1) - rho_1d(kk+2))
135  dz = (0.5*(h(i,j,km1) + h(i,j,k))+gv%H_subroundoff)*gv%H_to_Z
136  n2 = drho / dz
137  s2 = us%L_to_Z**2*(du*du+dv*dv)/(dz*dz)
138  ri_grad(k) = max(0., n2) / max(s2, 1.e-10*us%T_to_s**2)
139 
140  ! fill 3d arrays, if user asks for diagsnostics
141  if (cs%id_N2 > 0) cs%N2(i,j,k) = n2
142  if (cs%id_S2 > 0) cs%S2(i,j,k) = s2
143 
144  enddo
145 
146  ri_grad(g%ke+1) = ri_grad(g%ke)
147 
148  if (cs%id_ri_grad > 0) cs%ri_grad(i,j,:) = ri_grad(:)
149 
150  if (cs%smooth_ri) then
151  ! 1) fill Ri_grad in vanished layers with adjacent value
152  do k = 2, g%ke
153  if (h(i,j,k) <= epsln) ri_grad(k) = ri_grad(k-1)
154  enddo
155 
156  ri_grad(g%ke+1) = ri_grad(g%ke)
157 
158  ! 2) vertically smooth Ri with 1-2-1 filter
159  dummy = 0.25 * ri_grad(2)
160  ri_grad(g%ke+1) = ri_grad(g%ke)
161  do k = 3, g%ke
162  ri_grad(k) = dummy + 0.5 * ri_grad(k) + 0.25 * ri_grad(k+1)
163  dummy = 0.25 * ri_grad(k)
164  enddo
165 
166  if (cs%id_ri_grad_smooth > 0) cs%ri_grad_smooth(i,j,:) = ri_grad(:)
167  endif
168 
169  do k=1,g%ke+1
170  kvisc(k) = us%Z2_T_to_m2_s * kv(i,j,k)
171  kdiff(k) = us%Z2_T_to_m2_s * kd(i,j,k)
172  enddo
173 
174  ! Call to CVMix wrapper for computing interior mixing coefficients.
175  call cvmix_coeffs_shear(mdiff_out=kvisc(:), &
176  tdiff_out=kdiff(:), &
177  rich=ri_grad(:), &
178  nlev=g%ke, &
179  max_nlev=g%ke)
180  do k=1,g%ke+1
181  kv(i,j,k) = us%m2_s_to_Z2_T * kvisc(k)
182  kd(i,j,k) = us%m2_s_to_Z2_T * kdiff(k)
183  enddo
184  enddo
185  enddo
186 
187  ! write diagnostics
188  if (cs%id_kd > 0) call post_data(cs%id_kd, kd, cs%diag)
189  if (cs%id_kv > 0) call post_data(cs%id_kv, kv, cs%diag)
190  if (cs%id_N2 > 0) call post_data(cs%id_N2, cs%N2, cs%diag)
191  if (cs%id_S2 > 0) call post_data(cs%id_S2, cs%S2, cs%diag)
192  if (cs%id_ri_grad > 0) call post_data(cs%id_ri_grad, cs%ri_grad, cs%diag)
193  if (cs%id_ri_grad_smooth > 0) call post_data(cs%id_ri_grad_smooth ,cs%ri_grad_smooth, cs%diag)
194 
195 end subroutine calculate_cvmix_shear
196 
197 
198 !> Initialized the CVMix internal shear mixing routine.
199 !! \todo Does this note require emphasis?
200 !! \note *This is where we test to make sure multiple internal shear
201 !! mixing routines (including JHL) are not enabled at the same time.*
202 !! (returns) CVMix_shear_init - True if module is to be used, False otherwise
203 logical function cvmix_shear_init(Time, G, GV, US, param_file, diag, CS)
204  type(time_type), intent(in) :: Time !< The current time.
205  type(ocean_grid_type), intent(in) :: G !< Grid structure.
206  type(verticalgrid_type), intent(in) :: GV !< Vertical grid structure.
207  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
208  type(param_file_type), intent(in) :: param_file !< Run-time parameter file handle
209  type(diag_ctrl), target, intent(inout) :: diag !< Diagnostics control structure.
210  type(cvmix_shear_cs), pointer :: CS !< This module's control structure.
211  ! Local variables
212  integer :: NumberTrue=0
213  logical :: use_JHL
214 ! This include declares and sets the variable "version".
215 #include "version_variable.h"
216 
217  if (associated(cs)) then
218  call mom_error(warning, "CVMix_shear_init called with an associated "// &
219  "control structure.")
220  return
221  endif
222  allocate(cs)
223 
224 ! Set default, read and log parameters
225  call get_param(param_file, mdl, "USE_LMD94", cs%use_LMD94, default=.false., do_not_log=.true.)
226  call get_param(param_file, mdl, "USE_PP81", cs%use_PP81, default=.false., do_not_log=.true.)
227  call log_version(param_file, mdl, version, &
228  "Parameterization of shear-driven turbulence via CVMix (various options)", &
229  all_default=.not.(cs%use_PP81.or.cs%use_LMD94))
230  call get_param(param_file, mdl, "USE_LMD94", cs%use_LMD94, &
231  "If true, use the Large-McWilliams-Doney (JGR 1994) "//&
232  "shear mixing parameterization.", default=.false.)
233  if (cs%use_LMD94) then
234  numbertrue=numbertrue + 1
235  cs%Mix_Scheme='KPP'
236  endif
237  call get_param(param_file, mdl, "USE_PP81", cs%use_PP81, &
238  "If true, use the Pacanowski and Philander (JPO 1981) "//&
239  "shear mixing parameterization.", default=.false.)
240  if (cs%use_PP81) then
241  numbertrue = numbertrue + 1
242  cs%Mix_Scheme='PP'
243  endif
244  use_jhl=kappa_shear_is_used(param_file)
245  if (use_jhl) numbertrue = numbertrue + 1
246  ! After testing for interior schemes, make sure only 0 or 1 are enabled.
247  ! Otherwise, warn user and kill job.
248  if ((numbertrue) > 1) then
249  call mom_error(fatal, 'MOM_CVMix_shear_init: '// &
250  'Multiple shear driven internal mixing schemes selected,'//&
251  ' please disable all but one scheme to proceed.')
252  endif
253  cvmix_shear_init=(cs%use_PP81.or.cs%use_LMD94)
254 
255 ! Forego remainder of initialization if not using this scheme
256  if (.not. cvmix_shear_init) return
257  call get_param(param_file, mdl, "NU_ZERO", cs%Nu_Zero, &
258  "Leading coefficient in KPP shear mixing.", &
259  units="nondim", default=5.e-3)
260  call get_param(param_file, mdl, "RI_ZERO", cs%Ri_Zero, &
261  "Critical Richardson for KPP shear mixing, "// &
262  "NOTE this the internal mixing and this is "// &
263  "not for setting the boundary layer depth." &
264  ,units="nondim", default=0.8)
265  call get_param(param_file, mdl, "KPP_EXP", cs%KPP_exp, &
266  "Exponent of unitless factor of diffusivities, "// &
267  "for KPP internal shear mixing scheme." &
268  ,units="nondim", default=3.0)
269  call get_param(param_file, mdl, "SMOOTH_RI", cs%smooth_ri, &
270  "If true, vertically smooth the Richardson "// &
271  "number by applying a 1-2-1 filter once.", &
272  default = .false.)
273  call cvmix_init_shear(mix_scheme=cs%Mix_Scheme, &
274  kpp_nu_zero=cs%Nu_Zero, &
275  kpp_ri_zero=cs%Ri_zero, &
276  kpp_exp=cs%KPP_exp)
277 
278  ! Register diagnostics; allocation and initialization
279  cs%diag => diag
280 
281  cs%id_N2 = register_diag_field('ocean_model', 'N2_shear', diag%axesTi, time, &
282  'Square of Brunt-Vaisala frequency used by MOM_CVMix_shear module', '1/s2', conversion=us%s_to_T**2)
283  if (cs%id_N2 > 0) then
284  allocate( cs%N2( szi_(g), szj_(g), szk_(g)+1 ) ) ; cs%N2(:,:,:) = 0.
285  endif
286 
287  cs%id_S2 = register_diag_field('ocean_model', 'S2_shear', diag%axesTi, time, &
288  'Square of vertical shear used by MOM_CVMix_shear module','1/s2', conversion=us%s_to_T**2)
289  if (cs%id_S2 > 0) then
290  allocate( cs%S2( szi_(g), szj_(g), szk_(g)+1 ) ) ; cs%S2(:,:,:) = 0.
291  endif
292 
293  cs%id_ri_grad = register_diag_field('ocean_model', 'ri_grad_shear', diag%axesTi, time, &
294  'Gradient Richarson number used by MOM_CVMix_shear module','nondim')
295  if (cs%id_ri_grad > 0) then !Initialize w/ large Richardson value
296  allocate( cs%ri_grad( szi_(g), szj_(g), szk_(g)+1 )) ; cs%ri_grad(:,:,:) = 1.e8
297  endif
298 
299  cs%id_ri_grad_smooth = register_diag_field('ocean_model', 'ri_grad_shear_smooth', &
300  diag%axesTi, time, &
301  'Smoothed gradient Richarson number used by MOM_CVMix_shear module','nondim')
302  if (cs%id_ri_grad_smooth > 0) then !Initialize w/ large Richardson value
303  allocate( cs%ri_grad_smooth( szi_(g), szj_(g), szk_(g)+1 )) ; cs%ri_grad_smooth(:,:,:) = 1.e8
304  endif
305 
306  cs%id_kd = register_diag_field('ocean_model', 'kd_shear_CVMix', diag%axesTi, time, &
307  'Vertical diffusivity added by MOM_CVMix_shear module', 'm2/s', conversion=us%Z2_T_to_m2_s)
308  cs%id_kv = register_diag_field('ocean_model', 'kv_shear_CVMix', diag%axesTi, time, &
309  'Vertical viscosity added by MOM_CVMix_shear module', 'm2/s', conversion=us%Z2_T_to_m2_s)
310 
311 end function cvmix_shear_init
312 
313 !> Reads the parameters "LMD94" and "PP81" and returns state.
314 !! This function allows other modules to know whether this parameterization will
315 !! be used without needing to duplicate the log entry.
316 logical function cvmix_shear_is_used(param_file)
317  type(param_file_type), intent(in) :: param_file !< Run-time parameter files handle.
318  ! Local variables
319  logical :: LMD94, PP81
320  call get_param(param_file, mdl, "USE_LMD94", lmd94, &
321  default=.false., do_not_log = .true.)
322  call get_param(param_file, mdl, "Use_PP81", pp81, &
323  default=.false., do_not_log = .true.)
324  cvmix_shear_is_used = (lmd94 .or. pp81)
325 end function cvmix_shear_is_used
326 
327 !> Clear pointers and dealocate memory
328 subroutine cvmix_shear_end(CS)
329  type(cvmix_shear_cs), pointer :: CS !< Control structure for this module that
330  !! will be deallocated in this subroutine
331 
332  if (.not. associated(cs)) return
333 
334  if (cs%id_N2 > 0) deallocate(cs%N2)
335  if (cs%id_S2 > 0) deallocate(cs%S2)
336  if (cs%id_ri_grad > 0) deallocate(cs%ri_grad)
337  deallocate(cs)
338 
339 end subroutine cvmix_shear_end
340 
341 end module mom_cvmix_shear
Control structure including parameters for CVMix interior shear schemes.
Interface to CVMix interior shear schemes.
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Shear-dependent mixing following Jackson et al. 2008.
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:68
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Definition: MOM_grid.F90:2
The MOM6 facility to parse input files for runtime parameters.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Routines for error handling and I/O management.
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Provides a transparent vertical ocean grid type and supporting routines.
Provides transparent structures with groups of MOM6 variables and supporting routines.
An overloaded interface to read and log the values of various types of parameters.