21 use cvmix_background
, only : cvmix_init_bkgnd, cvmix_coeffs_bkgnd
23 implicit none ;
private 25 #include <MOM_memory.h> 27 public bkgnd_mixing_init
28 public bkgnd_mixing_end
29 public calculate_bkgnd_mixing
40 real :: bryan_lewis_c1
42 real :: bryan_lewis_c2
44 real :: bryan_lewis_c3
46 real :: bryan_lewis_c4
50 real :: bckgrnd_vdc_eq
52 real :: bckgrnd_vdc_psim
54 real :: bckgrnd_vdc_banda
64 real :: kd_tanh_lat_scale
70 logical :: kd_tanh_lat_fn
74 logical :: bryan_lewis_diffusivity
76 logical :: horiz_varying_background
78 logical :: henyey_igw_background
82 logical :: henyey_igw_background_new
96 logical :: bulkmixedlayer
97 logical :: kd_via_kdml_bug
104 character(len=40) :: bkgnd_scheme_str =
"none" 108 character(len=40) :: mdl =
"MOM_bkgnd_mixing" 113 subroutine bkgnd_mixing_init(Time, G, GV, US, param_file, diag, CS)
115 type(time_type),
intent(in) :: Time
120 type(
diag_ctrl),
target,
intent(inout) :: diag
126 real :: prandtl_bkgnd_comp
129 #include "version_variable.h" 131 if (
associated(cs))
then 132 call mom_error(warning,
"bkgnd_mixing_init called with an associated "// &
133 "control structure.")
140 "Adding static vertical background mixing coefficients")
142 call get_param(param_file, mdl,
"KD", cs%Kd, &
143 "The background diapycnal diffusivity of density in the "//&
144 "interior. Zero or the molecular value, ~1e-7 m2 s-1, "//&
145 "may be used.", default=0.0, units=
"m2 s-1", scale=us%m2_s_to_Z2_T)
147 call get_param(param_file, mdl,
"KV", kv, &
148 "The background kinematic viscosity in the interior. "//&
149 "The molecular value, ~1e-6 m2 s-1, may be used.", &
150 units=
"m2 s-1", scale=us%m2_s_to_Z2_T, fail_if_missing=.true.)
152 call get_param(param_file, mdl,
"KD_MIN", cs%Kd_min, &
153 "The minimum diapycnal diffusivity.", &
154 units=
"m2 s-1", default=0.01*cs%Kd*us%Z2_T_to_m2_s, scale=us%m2_s_to_Z2_T)
160 cs%bulkmixedlayer = (gv%nkml > 0)
161 if (cs%bulkmixedlayer)
then 163 call get_param(param_file, mdl,
"KDML", cs%Kdml, default=-1.)
164 if (cs%Kdml>0.)
call mom_error(fatal, &
165 "bkgnd_mixing_init: KDML cannot be set when using bulk mixed layer.")
168 call get_param(param_file, mdl,
"KDML", cs%Kdml, &
169 "If BULKMIXEDLAYER is false, KDML is the elevated "//&
170 "diapycnal diffusivity in the topmost HMIX of fluid. "//&
171 "KDML is only used if BULKMIXEDLAYER is false.", &
172 units=
"m2 s-1", default=cs%Kd*us%Z2_T_to_m2_s, scale=us%m2_s_to_Z2_T)
173 call get_param(param_file, mdl,
"HMIX_FIXED", cs%Hmix, &
174 "The prescribed depth over which the near-surface "//&
175 "viscosity and diffusivity are elevated when the bulk "//&
176 "mixed layer is not used.", units=
"m", scale=us%m_to_Z, fail_if_missing=.true.)
179 call get_param(param_file, mdl,
'DEBUG', cs%debug, default=.false., do_not_log=.true.)
183 call get_param(param_file, mdl,
"BRYAN_LEWIS_DIFFUSIVITY", cs%Bryan_Lewis_diffusivity, &
184 "If true, use a Bryan & Lewis (JGR 1979) like tanh "//&
185 "profile of background diapycnal diffusivity with depth. "//&
186 "This is done via CVMix.", default=.false.)
188 if (cs%Bryan_Lewis_diffusivity)
then 189 call check_bkgnd_scheme(cs,
"BRYAN_LEWIS_DIFFUSIVITY")
191 call get_param(param_file, mdl,
"BRYAN_LEWIS_C1", cs%Bryan_Lewis_c1, &
192 "The vertical diffusivity values for Bryan-Lewis profile at |z|=D.", &
193 units=
"m2 s-1", fail_if_missing=.true.)
195 call get_param(param_file, mdl,
"BRYAN_LEWIS_C2", cs%Bryan_Lewis_c2, &
196 "The amplitude of variation in diffusivity for the Bryan-Lewis profile", &
197 units=
"m2 s-1", fail_if_missing=.true.)
199 call get_param(param_file, mdl,
"BRYAN_LEWIS_C3", cs%Bryan_Lewis_c3, &
200 "The inverse length scale for transition region in the Bryan-Lewis profile", &
201 units=
"m-1", fail_if_missing=.true.)
203 call get_param(param_file, mdl,
"BRYAN_LEWIS_C4", cs%Bryan_Lewis_c4, &
204 "The depth where diffusivity is BRYAN_LEWIS_C1 in the Bryan-Lewis profile",&
205 units=
"m", fail_if_missing=.true.)
209 call get_param(param_file, mdl,
"HORIZ_VARYING_BACKGROUND", cs%horiz_varying_background, &
210 "If true, apply vertically uniform, latitude-dependent background "//&
211 "diffusivity, as described in Danabasoglu et al., 2012", &
214 if (cs%horiz_varying_background)
then 215 call check_bkgnd_scheme(cs,
"HORIZ_VARYING_BACKGROUND")
217 call get_param(param_file, mdl,
"BCKGRND_VDC1", cs%bckgrnd_vdc1, &
218 "Background diffusivity (Ledwell) when HORIZ_VARYING_BACKGROUND=True", &
219 units=
"m2 s-1",default = 0.16e-04, scale=us%m2_s_to_Z2_T)
221 call get_param(param_file, mdl,
"BCKGRND_VDC_EQ", cs%bckgrnd_vdc_eq, &
222 "Equatorial diffusivity (Gregg) when HORIZ_VARYING_BACKGROUND=True", &
223 units=
"m2 s-1",default = 0.01e-04, scale=us%m2_s_to_Z2_T)
225 call get_param(param_file, mdl,
"BCKGRND_VDC_PSIM", cs%bckgrnd_vdc_psim, &
226 "Max. PSI induced diffusivity (MacKinnon) when HORIZ_VARYING_BACKGROUND=True", &
227 units=
"m2 s-1",default = 0.13e-4, scale=us%m2_s_to_Z2_T)
229 call get_param(param_file, mdl,
"BCKGRND_VDC_BAN", cs%bckgrnd_vdc_Banda, &
230 "Banda Sea diffusivity (Gordon) when HORIZ_VARYING_BACKGROUND=True", &
231 units=
"m2 s-1",default = 1.0e-4, scale=us%m2_s_to_Z2_T)
234 call get_param(param_file, mdl,
"PRANDTL_BKGND", cs%prandtl_bkgnd, &
235 "Turbulent Prandtl number used to convert vertical "//&
236 "background diffusivities into viscosities.", &
237 units=
"nondim", default=1.0)
239 if (cs%Bryan_Lewis_diffusivity .or. cs%horiz_varying_background)
then 241 prandtl_bkgnd_comp = cs%prandtl_bkgnd
242 if (cs%Kd /= 0.0) prandtl_bkgnd_comp = kv/cs%Kd
244 if ( abs(cs%prandtl_bkgnd - prandtl_bkgnd_comp)>1.e-14)
then 245 call mom_error(fatal,
"set_diffusivity_init: The provided KD, KV,"//&
246 "and PRANDTL_BKGND values are incompatible. The following "//&
247 "must hold: KD*PRANDTL_BKGND==KV")
252 call get_param(param_file, mdl,
"HENYEY_IGW_BACKGROUND", cs%Henyey_IGW_background, &
253 "If true, use a latitude-dependent scaling for the near "//&
254 "surface background diffusivity, as described in "//&
255 "Harrison & Hallberg, JPO 2008.", default=.false.)
256 if (cs%Henyey_IGW_background)
call check_bkgnd_scheme(cs,
"HENYEY_IGW_BACKGROUND")
259 call get_param(param_file, mdl,
"HENYEY_IGW_BACKGROUND_NEW", cs%Henyey_IGW_background_new, &
260 "If true, use a better latitude-dependent scaling for the "//&
261 "background diffusivity, as described in "//&
262 "Harrison & Hallberg, JPO 2008.", default=.false.)
263 if (cs%Henyey_IGW_background_new)
call check_bkgnd_scheme(cs,
"HENYEY_IGW_BACKGROUND_NEW")
265 if (cs%Kd>0.0 .and. (trim(cs%bkgnd_scheme_str)==
"BRYAN_LEWIS_DIFFUSIVITY" .or.&
266 trim(cs%bkgnd_scheme_str)==
"HORIZ_VARYING_BACKGROUND" ))
then 267 call mom_error(warning,
"set_diffusivity_init: a nonzero constant background "//&
268 "diffusivity (KD) is specified along with "//trim(cs%bkgnd_scheme_str))
271 if (cs%Henyey_IGW_background)
then 272 call get_param(param_file, mdl,
"HENYEY_N0_2OMEGA", cs%N0_2Omega, &
273 "The ratio of the typical Buoyancy frequency to twice "//&
274 "the Earth's rotation period, used with the Henyey "//&
275 "scaling from the mixing.", units=
"nondim", default=20.0)
276 call get_param(param_file, mdl,
"OMEGA", cs%omega, &
277 "The rotation rate of the earth.", units=
"s-1", &
278 default=7.2921e-5, scale=us%T_to_s)
281 call get_param(param_file, mdl,
"KD_TANH_LAT_FN", cs%Kd_tanh_lat_fn, &
282 "If true, use a tanh dependence of Kd_sfc on latitude, "//&
283 "like CM2.1/CM2M. There is no physical justification "//&
284 "for this form, and it can not be used with "//&
285 "HENYEY_IGW_BACKGROUND.", default=.false.)
287 if (cs%Kd_tanh_lat_fn) &
288 call get_param(param_file, mdl,
"KD_TANH_LAT_SCALE", cs%Kd_tanh_lat_scale, &
289 "A nondimensional scaling for the range ofdiffusivities "//&
290 "with KD_TANH_LAT_FN. Valid values are in the range of "//&
291 "-2 to 2; 0.4 reproduces CM2M.", units=
"nondim", default=0.0)
293 if (cs%Henyey_IGW_background .and. cs%Kd_tanh_lat_fn)
call mom_error(fatal, &
294 "MOM_bkgnd_mixing: KD_TANH_LAT_FN can not be used with HENYEY_IGW_BACKGROUND.")
296 cs%Kd_via_Kdml_bug = .false.
297 if ((cs%Kd /= cs%Kdml) .and. .not.(cs%Kd_tanh_lat_fn .or. cs%bulkmixedlayer .or. &
298 cs%Henyey_IGW_background .or. cs%Henyey_IGW_background_new .or. &
299 cs%horiz_varying_background .or. cs%Bryan_Lewis_diffusivity))
then 300 call get_param(param_file, mdl,
"KD_BACKGROUND_VIA_KDML_BUG", cs%Kd_via_Kdml_bug, &
301 "If true and KDML /= KD and several other conditions apply, the background "//&
302 "diffusivity is set incorrectly using a bug that was introduced in March, 2018.", &
308 end subroutine bkgnd_mixing_init
311 subroutine calculate_bkgnd_mixing(h, tv, N2_lay, Kd_lay, Kd_int, Kv_bkgnd, j, G, GV, US, CS)
315 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: h
317 real,
dimension(SZI_(G),SZK_(GV)),
intent(in) :: N2_lay
319 real,
dimension(SZI_(G),SZK_(GV)),
intent(out) :: Kd_lay
321 real,
dimension(SZI_(G),SZK_(GV)+1),
intent(out) :: Kd_int
323 real,
dimension(SZI_(G),SZK_(GV)+1),
intent(out) :: Kv_bkgnd
325 integer,
intent(in) :: j
331 real,
dimension(SZK_(GV)+1) :: depth_int
332 real,
dimension(SZK_(GV)+1) :: Kd_col
333 real,
dimension(SZK_(GV)+1) :: Kv_col
334 real,
dimension(SZI_(G)) :: Kd_sfc
335 real,
dimension(SZI_(G)) :: depth
345 real :: bckgrnd_vdc_psin
346 real :: bckgrnd_vdc_psis
347 integer :: i, k, is, ie, js, je, nz
349 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
352 deg_to_rad = atan(1.0)/45.0
360 if (cs%Bryan_Lewis_diffusivity)
then 365 depth_int(k) = depth_int(k-1) + gv%H_to_m*h(i,j,k-1)
368 call cvmix_init_bkgnd(max_nlev=nz, &
370 bl1 = cs%Bryan_Lewis_c1, &
371 bl2 = cs%Bryan_Lewis_c2, &
372 bl3 = cs%Bryan_Lewis_c3, &
373 bl4 = cs%Bryan_Lewis_c4, &
374 prandtl = cs%prandtl_bkgnd)
376 kd_col(:) = 0.0 ; kv_col(:) = 0.0
377 call cvmix_coeffs_bkgnd(mdiff_out=kv_col, tdiff_out=kd_col, nlev=nz, max_nlev=nz)
381 kv_bkgnd(i,k) = us%m2_s_to_Z2_T*kv_col(k)
382 kd_int(i,k) = us%m2_s_to_Z2_T*kd_col(k)
385 kd_lay(i,k) = kd_lay(i,k) + 0.5 * us%m2_s_to_Z2_T * (kd_col(k) + kd_col(k+1))
389 elseif (cs%horiz_varying_background)
then 392 bckgrnd_vdc_psis = cs%bckgrnd_vdc_psim * exp(-(0.4*(g%geoLatT(i,j)+28.9))**2)
393 bckgrnd_vdc_psin = cs%bckgrnd_vdc_psim * exp(-(0.4*(g%geoLatT(i,j)-28.9))**2)
394 kd_int(i,1) = (cs%bckgrnd_vdc_eq + bckgrnd_vdc_psin) + bckgrnd_vdc_psis
396 if (g%geoLatT(i,j) < -10.0)
then 397 kd_int(i,1) = kd_int(i,1) + cs%bckgrnd_vdc1
398 elseif (g%geoLatT(i,j) <= 10.0)
then 399 kd_int(i,1) = kd_int(i,1) + cs%bckgrnd_vdc1 * (g%geoLatT(i,j)/10.0)**2
401 kd_int(i,1) = kd_int(i,1) + cs%bckgrnd_vdc1
405 if ( (g%geoLatT(i,j) < -1.0) .and. (g%geoLatT(i,j) > -4.0) .and. &
406 ( mod(g%geoLonT(i,j)+360.0,360.0) > 103.0) .and. &
407 ( mod(g%geoLonT(i,j)+360.0,360.0) < 134.0) )
then 408 kd_int(i,1) = cs%bckgrnd_vdc_Banda
412 if ( (g%geoLatT(i,j) <= -4.0) .and. (g%geoLatT(i,j) > -7.0) .and. &
413 ( mod(g%geoLonT(i,j)+360.0,360.0) > 106.0) .and. &
414 ( mod(g%geoLonT(i,j)+360.0,360.0) < 140.0) )
then 415 kd_int(i,1) = cs%bckgrnd_vdc_Banda
419 if ( (g%geoLatT(i,j) <= -7.0) .and. (g%geoLatT(i,j) > -8.3) .and. &
420 ( mod(g%geoLonT(i,j)+360.0,360.0) > 111.0) .and. &
421 ( mod(g%geoLonT(i,j)+360.0,360.0) < 142.0) )
then 422 kd_int(i,1) = cs%bckgrnd_vdc_Banda
427 do k=1,nz+1 ;
do i=is,ie
428 kd_int(i,k) = kd_int(i,1)
429 kv_bkgnd(i,k) = kd_int(i,1) * cs%prandtl_bkgnd
431 do k=1,nz ;
do i=is,ie
432 kd_lay(i,k) = kd_int(i,1)
435 elseif (cs%Henyey_IGW_background_new)
then 436 i_x30 = 2.0 / invcosh(cs%N0_2Omega*2.0)
437 i_2omega = 0.5 / cs%omega
438 do k=1,nz ;
do i=is,ie
439 abs_sinlat = max(min_sinlat, abs(sin(g%geoLatT(i,j)*deg_to_rad)))
440 n_2omega = max(abs_sinlat, sqrt(n2_lay(i,k))*i_2omega)
441 n02_n2 = (cs%N0_2Omega/n_2omega)**2
442 kd_lay(i,k) = max(cs%Kd_min, cs%Kd * &
443 ((abs_sinlat * invcosh(n_2omega/abs_sinlat)) * i_x30)*n02_n2)
447 kd_int(i,1) = 0.0; kv_bkgnd(i,1) = 0.0
448 kd_int(i,nz+1) = 0.0; kv_bkgnd(i,nz+1) = 0.0
450 do k=2,nz ;
do i=is,ie
451 kd_int(i,k) = 0.5*(kd_lay(i,k-1) + kd_lay(i,k))
452 kv_bkgnd(i,k) = kd_int(i,k) * cs%prandtl_bkgnd
456 if (cs%Henyey_IGW_background)
then 457 i_x30 = 2.0 / invcosh(cs%N0_2Omega*2.0)
459 abs_sinlat = abs(sin(g%geoLatT(i,j)*deg_to_rad))
460 kd_sfc(i) = max(cs%Kd_min, cs%Kd * &
461 ((abs_sinlat * invcosh(cs%N0_2Omega / max(min_sinlat, abs_sinlat))) * i_x30) )
463 elseif (cs%Kd_tanh_lat_fn)
then 468 kd_sfc(i) = max(cs%Kd_min, cs%Kd * (1.0 + &
469 cs%Kd_tanh_lat_scale * 0.5*tanh((abs(g%geoLatT(i,j)) - 35.0)/5.0) ))
478 if ((.not.cs%bulkmixedlayer) .and. (cs%Kd /= cs%Kdml))
then 481 i_hmix = 1.0 / (cs%Hmix + gv%H_subroundoff*gv%H_to_Z)
482 do i=is,ie ; depth(i) = 0.0 ;
enddo 483 do k=1,nz ;
do i=is,ie
484 depth_c = depth(i) + 0.5*gv%H_to_Z*h(i,j,k)
485 if (cs%Kd_via_Kdml_bug)
then 488 if (depth_c <= cs%Hmix)
then ; kd_int(i,k) = cs%Kdml
489 elseif (depth_c >= 2.0*cs%Hmix)
then ; kd_int(i,k) = kd_sfc(i)
491 kd_lay(i,k) = ((kd_sfc(i) - cs%Kdml) * i_hmix) * depth_c + (2.0*cs%Kdml - kd_sfc(i))
494 if (depth_c <= cs%Hmix)
then ; kd_lay(i,k) = cs%Kdml
495 elseif (depth_c >= 2.0*cs%Hmix)
then ; kd_lay(i,k) = kd_sfc(i)
497 kd_lay(i,k) = ((kd_sfc(i) - cs%Kdml) * i_hmix) * depth_c + (2.0*cs%Kdml - kd_sfc(i))
501 depth(i) = depth(i) + gv%H_to_Z*h(i,j,k)
505 do k=1,nz ;
do i=is,ie
506 kd_lay(i,k) = kd_sfc(i)
512 kd_int(i,1) = 0.0; kv_bkgnd(i,1) = 0.0
513 kd_int(i,nz+1) = 0.0; kv_bkgnd(i,nz+1) = 0.0
515 do k=2,nz ;
do i=is,ie
516 kd_int(i,k) = 0.5*(kd_lay(i,k-1) + kd_lay(i,k))
517 kv_bkgnd(i,k) = kd_int(i,k) * cs%prandtl_bkgnd
521 end subroutine calculate_bkgnd_mixing
526 logical function cvmix_bkgnd_is_used(param_file)
528 call get_param(param_file, mdl,
"USE_CVMix_BACKGROUND", cvmix_bkgnd_is_used, &
529 default=.false., do_not_log = .true.)
531 end function cvmix_bkgnd_is_used
535 subroutine check_bkgnd_scheme(CS, str)
537 character(len=*),
intent(in) :: str
540 if (trim(cs%bkgnd_scheme_str)==
"none")
then 541 cs%bkgnd_scheme_str = str
543 call mom_error(fatal,
"set_diffusivity_init: Cannot activate both "//trim(str)//
" and "//&
544 trim(cs%bkgnd_scheme_str)//
".")
550 subroutine bkgnd_mixing_end(CS)
554 if (.not.
associated(cs))
return 557 end subroutine bkgnd_mixing_end
This module implements boundary forcing for MOM6.
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Vertical viscosities, drag coefficients, and related fields.
Interface to background mixing schemes, including the Bryan and Lewis (1979) which is applied via CVM...
The MOM6 facility to parse input files for runtime parameters.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
A module with intrinsic functions that are used by MOM but are not supported by some compilers...
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Routines for error handling and I/O management.
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Calculate the derivatives of density with temperature and salinity from T, S, and P...
Provides subroutines for quantities specific to the equation of state.
An overloaded interface to log version information about modules.
Control structure including parameters for this module.
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.
Provides checksumming functions for debugging.