22 implicit none ;
private 24 #include <MOM_memory.h> 28 logical :: use_variable_mixing
29 logical :: resoln_scaled_kh
31 logical :: resoln_scaled_khth
33 logical :: depth_scaled_khth
35 logical :: resoln_scaled_khtr
37 logical :: interpolate_res_fn
42 logical :: use_stored_slopes
43 logical :: resoln_use_ebt
45 logical :: khth_use_ebt_struct
47 logical :: calculate_cg1
50 logical :: calculate_rd_dx
52 logical :: calculate_res_fns
54 logical :: calculate_depth_fns
56 logical :: calculate_eady_growth_rate
58 real,
dimension(:,:),
pointer :: &
72 depth_fn_u => null(), &
74 depth_fn_v => null(), &
76 beta_dx2_h => null(), &
78 beta_dx2_q => null(), &
80 beta_dx2_u => null(), &
82 beta_dx2_v => null(), &
94 real,
dimension(:,:,:),
pointer :: &
98 real allocable_,
dimension(NIMEMB_PTR_,NJMEM_) :: &
101 real allocable_,
dimension(NIMEM_,NJMEMB_PTR_) :: &
104 real allocable_,
dimension(NIMEMB_PTR_,NJMEM_,NKMEM_) :: &
107 real allocable_,
dimension(NIMEM_,NJMEMB_PTR_,NKMEM_) :: &
111 logical :: use_visbeck
112 integer :: varmix_ktop
113 real :: visbeck_l_scale
114 real :: res_coef_khth
117 real :: res_coef_visc
120 real :: depth_scaled_khth_h0
121 real :: depth_scaled_khth_exp
123 integer :: res_fn_power_khth
126 integer :: res_fn_power_visc
129 real :: visbeck_s_max
132 logical :: use_qg_leith_gm
133 logical :: use_beta_in_qg_leith
138 integer :: id_sn_u=-1, id_sn_v=-1, id_l2u=-1, id_l2v=-1, id_res_fn = -1
139 integer :: id_n2_u=-1, id_n2_v=-1, id_s2_u=-1, id_s2_v=-1
140 integer :: id_rd_dx=-1, id_kh_u_qg = -1, id_kh_v_qg = -1
146 type(group_pass_type) :: pass_cg1
150 public varmix_init, calc_slope_functions, calc_resoln_function
151 public calc_qg_leith_viscosity, calc_depth_function
156 subroutine calc_depth_function(G, CS)
161 integer :: is, ie, js, je, isq, ieq, jsq, jeq
165 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
166 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
168 if (.not.
associated(cs))
call mom_error(fatal,
"calc_depth_function:"// &
169 "Module must be initialized before it is used.")
170 if (.not. cs%calculate_depth_fns)
return 171 if (.not.
associated(cs%Depth_fn_u))
call mom_error(fatal, &
172 "calc_depth_function: %Depth_fn_u is not associated with Depth_scaled_KhTh.")
173 if (.not.
associated(cs%Depth_fn_v))
call mom_error(fatal, &
174 "calc_depth_function: %Depth_fn_v is not associated with Depth_scaled_KhTh.")
176 h0 = cs%depth_scaled_khth_h0
177 expo = cs%depth_scaled_khth_exp
179 do j=js,je ;
do i=is-1,ieq
180 cs%Depth_fn_u(i,j) = (min(1.0, 0.5*(g%bathyT(i,j) + g%bathyT(i+1,j))/h0))**expo
183 do j=js-1,jeq ;
do i=is,ie
184 cs%Depth_fn_v(i,j) = (min(1.0, 0.5*(g%bathyT(i,j) + g%bathyT(i,j+1))/h0))**expo
187 end subroutine calc_depth_function
190 subroutine calc_resoln_function(h, tv, G, GV, US, CS)
192 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
206 integer :: is, ie, js, je, isq, ieq, jsq, jeq, nz
208 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
209 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
211 if (.not.
associated(cs))
call mom_error(fatal,
"calc_resoln_function:"// &
212 "Module must be initialized before it is used.")
213 if (cs%calculate_cg1)
then 214 if (.not.
associated(cs%cg1))
call mom_error(fatal, &
215 "calc_resoln_function: %cg1 is not associated with Resoln_scaled_Kh.")
216 if (cs%khth_use_ebt_struct)
then 217 if (.not.
associated(cs%ebt_struct))
call mom_error(fatal, &
218 "calc_resoln_function: %ebt_struct is not associated with RESOLN_USE_EBT.")
219 if (cs%Resoln_use_ebt)
then 221 call wave_speed(h, tv, g, gv, us, cs%cg1, cs%wave_speed_CSp, modal_structure=cs%ebt_struct)
224 call wave_speed(h, tv, g, gv, us, cs%cg1, cs%wave_speed_CSp, modal_structure=cs%ebt_struct, &
226 call wave_speed(h, tv, g, gv, us, cs%cg1, cs%wave_speed_CSp)
228 call pass_var(cs%ebt_struct, g%Domain)
230 call wave_speed(h, tv, g, gv, us, cs%cg1, cs%wave_speed_CSp)
234 call do_group_pass(cs%pass_cg1, g%Domain)
239 if (cs%calculate_rd_dx)
then 240 if (.not.
associated(cs%Rd_dx_h))
call mom_error(fatal, &
241 "calc_resoln_function: %Rd_dx_h is not associated with calculate_rd_dx.")
243 do j=js-1,je+1 ;
do i=is-1,ie+1
244 cs%Rd_dx_h(i,j) = cs%cg1(i,j) / &
245 (sqrt(cs%f2_dx2_h(i,j) + cs%cg1(i,j)*cs%beta_dx2_h(i,j)))
247 if (query_averaging_enabled(cs%diag))
then 248 if (cs%id_Rd_dx > 0)
call post_data(cs%id_Rd_dx, cs%Rd_dx_h, cs%diag)
252 if (.not. cs%calculate_res_fns)
return 254 if (.not.
associated(cs%Res_fn_h))
call mom_error(fatal, &
255 "calc_resoln_function: %Res_fn_h is not associated with Resoln_scaled_Kh.")
256 if (.not.
associated(cs%Res_fn_q))
call mom_error(fatal, &
257 "calc_resoln_function: %Res_fn_q is not associated with Resoln_scaled_Kh.")
258 if (.not.
associated(cs%Res_fn_u))
call mom_error(fatal, &
259 "calc_resoln_function: %Res_fn_u is not associated with Resoln_scaled_Kh.")
260 if (.not.
associated(cs%Res_fn_v))
call mom_error(fatal, &
261 "calc_resoln_function: %Res_fn_v is not associated with Resoln_scaled_Kh.")
262 if (.not.
associated(cs%f2_dx2_h))
call mom_error(fatal, &
263 "calc_resoln_function: %f2_dx2_h is not associated with Resoln_scaled_Kh.")
264 if (.not.
associated(cs%f2_dx2_q))
call mom_error(fatal, &
265 "calc_resoln_function: %f2_dx2_q is not associated with Resoln_scaled_Kh.")
266 if (.not.
associated(cs%f2_dx2_u))
call mom_error(fatal, &
267 "calc_resoln_function: %f2_dx2_u is not associated with Resoln_scaled_Kh.")
268 if (.not.
associated(cs%f2_dx2_v))
call mom_error(fatal, &
269 "calc_resoln_function: %f2_dx2_v is not associated with Resoln_scaled_Kh.")
270 if (.not.
associated(cs%beta_dx2_h))
call mom_error(fatal, &
271 "calc_resoln_function: %beta_dx2_h is not associated with Resoln_scaled_Kh.")
272 if (.not.
associated(cs%beta_dx2_q))
call mom_error(fatal, &
273 "calc_resoln_function: %beta_dx2_q is not associated with Resoln_scaled_Kh.")
274 if (.not.
associated(cs%beta_dx2_u))
call mom_error(fatal, &
275 "calc_resoln_function: %beta_dx2_u is not associated with Resoln_scaled_Kh.")
276 if (.not.
associated(cs%beta_dx2_v))
call mom_error(fatal, &
277 "calc_resoln_function: %beta_dx2_v is not associated with Resoln_scaled_Kh.")
284 if (cs%Res_fn_power_visc >= 100)
then 286 do j=js-1,je+1 ;
do i=is-1,ie+1
287 dx_term = cs%f2_dx2_h(i,j) + cs%cg1(i,j)*cs%beta_dx2_h(i,j)
288 if ((cs%Res_coef_visc * cs%cg1(i,j))**2 > dx_term)
then 289 cs%Res_fn_h(i,j) = 0.0
291 cs%Res_fn_h(i,j) = 1.0
295 do j=js-1,jeq ;
do i=is-1,ieq
296 cg1_q = 0.25 * ((cs%cg1(i,j) + cs%cg1(i+1,j+1)) + (cs%cg1(i+1,j) + cs%cg1(i,j+1)))
297 dx_term = cs%f2_dx2_q(i,j) + cg1_q * cs%beta_dx2_q(i,j)
298 if ((cs%Res_coef_visc * cg1_q)**2 > dx_term)
then 299 cs%Res_fn_q(i,j) = 0.0
301 cs%Res_fn_q(i,j) = 1.0
304 elseif (cs%Res_fn_power_visc == 2)
then 306 do j=js-1,je+1 ;
do i=is-1,ie+1
307 dx_term = cs%f2_dx2_h(i,j) + cs%cg1(i,j)*cs%beta_dx2_h(i,j)
308 cs%Res_fn_h(i,j) = dx_term / (dx_term + (cs%Res_coef_visc * cs%cg1(i,j))**2)
311 do j=js-1,jeq ;
do i=is-1,ieq
312 cg1_q = 0.25 * ((cs%cg1(i,j) + cs%cg1(i+1,j+1)) + (cs%cg1(i+1,j) + cs%cg1(i,j+1)))
313 dx_term = cs%f2_dx2_q(i,j) + cg1_q * cs%beta_dx2_q(i,j)
314 cs%Res_fn_q(i,j) = dx_term / (dx_term + (cs%Res_coef_visc * cg1_q)**2)
316 elseif (mod(cs%Res_fn_power_visc, 2) == 0)
then 317 power_2 = cs%Res_fn_power_visc / 2
319 do j=js-1,je+1 ;
do i=is-1,ie+1
320 dx_term = (us%L_T_to_m_s**2*(cs%f2_dx2_h(i,j) + cs%cg1(i,j)*cs%beta_dx2_h(i,j)))**power_2
321 cs%Res_fn_h(i,j) = dx_term / &
322 (dx_term + (cs%Res_coef_visc * us%L_T_to_m_s*cs%cg1(i,j))**cs%Res_fn_power_visc)
325 do j=js-1,jeq ;
do i=is-1,ieq
326 cg1_q = 0.25 * ((cs%cg1(i,j) + cs%cg1(i+1,j+1)) + (cs%cg1(i+1,j) + cs%cg1(i,j+1)))
327 dx_term = (us%L_T_to_m_s**2*(cs%f2_dx2_q(i,j) + cg1_q * cs%beta_dx2_q(i,j)))**power_2
328 cs%Res_fn_q(i,j) = dx_term / &
329 (dx_term + (cs%Res_coef_visc * us%L_T_to_m_s*cg1_q)**cs%Res_fn_power_visc)
333 do j=js-1,je+1 ;
do i=is-1,ie+1
334 dx_term = (us%L_T_to_m_s*sqrt(cs%f2_dx2_h(i,j) + &
335 cs%cg1(i,j)*cs%beta_dx2_h(i,j)))**cs%Res_fn_power_visc
336 cs%Res_fn_h(i,j) = dx_term / &
337 (dx_term + (cs%Res_coef_visc * us%L_T_to_m_s*cs%cg1(i,j))**cs%Res_fn_power_visc)
340 do j=js-1,jeq ;
do i=is-1,ieq
341 cg1_q = 0.25 * ((cs%cg1(i,j) + cs%cg1(i+1,j+1)) + (cs%cg1(i+1,j) + cs%cg1(i,j+1)))
342 dx_term = (us%L_T_to_m_s*sqrt(cs%f2_dx2_q(i,j) + &
343 cg1_q * cs%beta_dx2_q(i,j)))**cs%Res_fn_power_visc
344 cs%Res_fn_q(i,j) = dx_term / &
345 (dx_term + (cs%Res_coef_visc * us%L_T_to_m_s*cg1_q)**cs%Res_fn_power_visc)
349 if (cs%interpolate_Res_fn)
then 350 do j=js,je ;
do i=is-1,ieq
351 cs%Res_fn_u(i,j) = 0.5*(cs%Res_fn_h(i,j) + cs%Res_fn_h(i+1,j))
353 do j=js-1,jeq ;
do i=is,ie
354 cs%Res_fn_v(i,j) = 0.5*(cs%Res_fn_h(i,j) + cs%Res_fn_h(i,j+1))
357 if (cs%Res_fn_power_khth >= 100)
then 359 do j=js,je ;
do i=is-1,ieq
360 cg1_u = 0.5 * (cs%cg1(i,j) + cs%cg1(i+1,j))
361 dx_term = cs%f2_dx2_u(i,j) + cg1_u * cs%beta_dx2_u(i,j)
362 if ((cs%Res_coef_khth * cg1_u)**2 > dx_term)
then 363 cs%Res_fn_u(i,j) = 0.0
365 cs%Res_fn_u(i,j) = 1.0
369 do j=js-1,jeq ;
do i=is,ie
370 cg1_v = 0.5 * (cs%cg1(i,j) + cs%cg1(i,j+1))
371 dx_term = cs%f2_dx2_v(i,j) + cg1_v * cs%beta_dx2_v(i,j)
372 if ((cs%Res_coef_khth * cg1_v)**2 > dx_term)
then 373 cs%Res_fn_v(i,j) = 0.0
375 cs%Res_fn_v(i,j) = 1.0
378 elseif (cs%Res_fn_power_khth == 2)
then 380 do j=js,je ;
do i=is-1,ieq
381 cg1_u = 0.5 * (cs%cg1(i,j) + cs%cg1(i+1,j))
382 dx_term = cs%f2_dx2_u(i,j) + cg1_u * cs%beta_dx2_u(i,j)
383 cs%Res_fn_u(i,j) = dx_term / (dx_term + (cs%Res_coef_khth * cg1_u)**2)
386 do j=js-1,jeq ;
do i=is,ie
387 cg1_v = 0.5 * (cs%cg1(i,j) + cs%cg1(i,j+1))
388 dx_term = cs%f2_dx2_v(i,j) + cg1_v * cs%beta_dx2_v(i,j)
389 cs%Res_fn_v(i,j) = dx_term / (dx_term + (cs%Res_coef_khth * cg1_v)**2)
391 elseif (mod(cs%Res_fn_power_khth, 2) == 0)
then 392 power_2 = cs%Res_fn_power_khth / 2
394 do j=js,je ;
do i=is-1,ieq
395 cg1_u = 0.5 * (cs%cg1(i,j) + cs%cg1(i+1,j))
396 dx_term = (us%L_T_to_m_s**2 * (cs%f2_dx2_u(i,j) + cg1_u * cs%beta_dx2_u(i,j)))**power_2
397 cs%Res_fn_u(i,j) = dx_term / &
398 (dx_term + (cs%Res_coef_khth * us%L_T_to_m_s*cg1_u)**cs%Res_fn_power_khth)
401 do j=js-1,jeq ;
do i=is,ie
402 cg1_v = 0.5 * (cs%cg1(i,j) + cs%cg1(i,j+1))
403 dx_term = (us%L_T_to_m_s**2 * (cs%f2_dx2_v(i,j) + cg1_v * cs%beta_dx2_v(i,j)))**power_2
404 cs%Res_fn_v(i,j) = dx_term / &
405 (dx_term + (cs%Res_coef_khth * us%L_T_to_m_s*cg1_v)**cs%Res_fn_power_khth)
409 do j=js,je ;
do i=is-1,ieq
410 cg1_u = 0.5 * (cs%cg1(i,j) + cs%cg1(i+1,j))
411 dx_term = (us%L_T_to_m_s*sqrt(cs%f2_dx2_u(i,j) + &
412 cg1_u * cs%beta_dx2_u(i,j)))**cs%Res_fn_power_khth
413 cs%Res_fn_u(i,j) = dx_term / &
414 (dx_term + (cs%Res_coef_khth * us%L_T_to_m_s*cg1_u)**cs%Res_fn_power_khth)
417 do j=js-1,jeq ;
do i=is,ie
418 cg1_v = 0.5 * (cs%cg1(i,j) + cs%cg1(i,j+1))
419 dx_term = (us%L_T_to_m_s*sqrt(cs%f2_dx2_v(i,j) + &
420 cg1_v * cs%beta_dx2_v(i,j)))**cs%Res_fn_power_khth
421 cs%Res_fn_v(i,j) = dx_term / &
422 (dx_term + (cs%Res_coef_khth * us%L_T_to_m_s*cg1_v)**cs%Res_fn_power_khth)
428 if (query_averaging_enabled(cs%diag))
then 429 if (cs%id_Res_fn > 0)
call post_data(cs%id_Res_fn, cs%Res_fn_h, cs%diag)
432 end subroutine calc_resoln_function
436 subroutine calc_slope_functions(h, tv, dt, G, GV, US, CS, OBC)
440 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
442 real,
intent(in) :: dt
446 real,
dimension(SZI_(G), SZJ_(G), SZK_(G)+1) :: &
448 real,
dimension(SZIB_(G), SZJ_(G), SZK_(G)+1) :: n2_u
449 real,
dimension(SZI_(G), SZJB_(G), SZK_(G)+1) :: n2_v
451 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_lateral_mixing_coeffs.F90, calc_slope_functions:"//&
452 "Module must be initialized before it is used.")
454 if (cs%calculate_Eady_growth_rate)
then 455 call find_eta(h, tv, g, gv, us, e, halo_size=2)
456 if (cs%use_stored_slopes)
then 457 call calc_isoneutral_slopes(g, gv, us, h, e, tv, dt*cs%kappa_smooth, &
458 cs%slope_x, cs%slope_y, n2_u, n2_v, 1, obc=obc)
459 call calc_visbeck_coeffs(h, cs%slope_x, cs%slope_y, n2_u, n2_v, g, gv, us, cs, obc=obc)
463 call calc_slope_functions_using_just_e(h, g, gv, us, cs, e, .true., obc=obc)
467 if (query_averaging_enabled(cs%diag))
then 468 if (cs%id_SN_u > 0)
call post_data(cs%id_SN_u, cs%SN_u, cs%diag)
469 if (cs%id_SN_v > 0)
call post_data(cs%id_SN_v, cs%SN_v, cs%diag)
470 if (cs%id_L2u > 0)
call post_data(cs%id_L2u, cs%L2u, cs%diag)
471 if (cs%id_L2v > 0)
call post_data(cs%id_L2v, cs%L2v, cs%diag)
472 if (cs%calculate_Eady_growth_rate .and. cs%use_stored_slopes)
then 473 if (cs%id_N2_u > 0)
call post_data(cs%id_N2_u, n2_u, cs%diag)
474 if (cs%id_N2_v > 0)
call post_data(cs%id_N2_v, n2_v, cs%diag)
478 end subroutine calc_slope_functions
481 subroutine calc_visbeck_coeffs(h, slope_x, slope_y, N2_u, N2_v, G, GV, US, CS, OBC)
482 type(ocean_grid_type),
intent(inout) :: G
483 type(verticalGrid_type),
intent(in) :: GV
484 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
485 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: slope_x
486 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: N2_u
488 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)+1),
intent(in) :: slope_y
489 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)+1),
intent(in) :: N2_v
491 type(unit_scale_type),
intent(in) :: US
492 type(VarMix_CS),
pointer :: CS
493 type(ocean_OBC_type),
optional,
pointer :: OBC
500 integer :: is, ie, js, je, nz
501 integer :: i, j, k, kb_max
503 real :: S2max, wNE, wSE, wSW, wNW
504 real :: H_u(SZIB_(G)), H_v(SZI_(G))
505 real :: S2_u(SZIB_(G), SZJ_(G))
506 real :: S2_v(SZI_(G), SZJB_(G))
507 logical :: local_open_u_BC, local_open_v_BC
509 if (.not.
associated(cs))
call mom_error(fatal,
"calc_slope_function:"// &
510 "Module must be initialized before it is used.")
511 if (.not. cs%calculate_Eady_growth_rate)
return 512 if (.not.
associated(cs%SN_u))
call mom_error(fatal,
"calc_slope_function:"// &
513 "%SN_u is not associated with use_variable_mixing.")
514 if (.not.
associated(cs%SN_v))
call mom_error(fatal,
"calc_slope_function:"// &
515 "%SN_v is not associated with use_variable_mixing.")
517 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
519 local_open_u_bc = .false.
520 local_open_v_bc = .false.
521 if (
present(obc))
then ;
if (
associated(obc))
then 522 local_open_u_bc = obc%open_u_BCs_exist_globally
523 local_open_v_bc = obc%open_v_BCs_exist_globally
526 s2max = cs%Visbeck_S_max**2
529 do j=js-1,je+1 ;
do i=is-1,ie+1
541 cs%SN_u(i,j) = 0. ; h_u(i) = 0. ; s2_u(i,j) = 0.
543 do k=2,nz ;
do i=is-1,ie
544 hdn = sqrt( h(i,j,k) * h(i+1,j,k) )
545 hup = sqrt( h(i,j,k-1) * h(i+1,j,k-1) )
546 h_geom = sqrt( hdn * hup )
549 wse = g%mask2dCv(i+1,j-1) * ( (h(i+1,j,k)*h(i+1,j-1,k)) * (h(i+1,j,k-1)*h(i+1,j-1,k-1)) )
550 wnw = g%mask2dCv(i ,j ) * ( (h(i ,j,k)*h(i ,j+1,k)) * (h(i ,j,k-1)*h(i ,j+1,k-1)) )
551 wne = g%mask2dCv(i+1,j ) * ( (h(i+1,j,k)*h(i+1,j+1,k)) * (h(i+1,j,k-1)*h(i+1,j+1,k-1)) )
552 wsw = g%mask2dCv(i ,j-1) * ( (h(i ,j,k)*h(i ,j-1,k)) * (h(i ,j,k-1)*h(i ,j-1,k-1)) )
553 s2 = slope_x(i,j,k)**2 + &
554 ((wnw*slope_y(i,j,k)**2 + wse*slope_y(i+1,j-1,k)**2) + &
555 (wne*slope_y(i+1,j,k)**2 + wsw*slope_y(i,j-1,k)**2) ) / &
556 ( ((wse+wnw) + (wne+wsw)) + gv%H_subroundoff**4 )
557 if (s2max>0.) s2 = s2 * s2max / (s2 + s2max)
559 n2 = max(0., n2_u(i,j,k))
560 cs%SN_u(i,j) = cs%SN_u(i,j) + sqrt( s2*n2 )*h_geom
561 s2_u(i,j) = s2_u(i,j) + s2*h_geom
562 h_u(i) = h_u(i) + h_geom
566 cs%SN_u(i,j) = g%mask2dCu(i,j) * cs%SN_u(i,j) / h_u(i)
567 s2_u(i,j) = g%mask2dCu(i,j) * s2_u(i,j) / h_u(i)
571 if (local_open_u_bc)
then 572 l_seg = obc%segnum_u(i,j)
574 if (l_seg /= obc_none)
then 575 if (obc%segment(l_seg)%open)
then 586 cs%SN_v(i,j) = 0. ; h_v(i) = 0. ; s2_v(i,j) = 0.
588 do k=2,nz ;
do i=is,ie
589 hdn = sqrt( h(i,j,k) * h(i,j+1,k) )
590 hup = sqrt( h(i,j,k-1) * h(i,j+1,k-1) )
591 h_geom = sqrt( hdn * hup )
594 wse = g%mask2dCu(i,j) * ( (h(i,j ,k)*h(i+1,j ,k)) * (h(i,j ,k-1)*h(i+1,j ,k-1)) )
595 wnw = g%mask2dCu(i-1,j+1) * ( (h(i,j+1,k)*h(i-1,j+1,k)) * (h(i,j+1,k-1)*h(i-1,j+1,k-1)) )
596 wne = g%mask2dCu(i,j+1) * ( (h(i,j+1,k)*h(i+1,j+1,k)) * (h(i,j+1,k-1)*h(i+1,j+1,k-1)) )
597 wsw = g%mask2dCu(i-1,j) * ( (h(i,j ,k)*h(i-1,j ,k)) * (h(i,j ,k-1)*h(i-1,j ,k-1)) )
598 s2 = slope_y(i,j,k)**2 + &
599 ((wse*slope_x(i,j,k)**2 + wnw*slope_x(i-1,j+1,k)**2) + &
600 (wne*slope_x(i,j+1,k)**2 + wsw*slope_x(i-1,j,k)**2) ) / &
601 ( ((wse+wnw) + (wne+wsw)) + gv%H_subroundoff**4 )
602 if (s2max>0.) s2 = s2 * s2max / (s2 + s2max)
604 n2 = max(0., n2_v(i,j,k))
605 cs%SN_v(i,j) = cs%SN_v(i,j) + sqrt( s2*n2 )*h_geom
606 s2_v(i,j) = s2_v(i,j) + s2*h_geom
607 h_v(i) = h_v(i) + h_geom
611 cs%SN_v(i,j) = g%mask2dCv(i,j) * cs%SN_v(i,j) / h_v(i)
612 s2_v(i,j) = g%mask2dCv(i,j) * s2_v(i,j) / h_v(i)
616 if (local_open_v_bc)
then 617 l_seg = obc%segnum_v(i,j)
619 if (l_seg /= obc_none)
then 620 if (obc%segment(obc%segnum_v(i,j))%open)
then 629 if (query_averaging_enabled(cs%diag))
then 630 if (cs%id_S2_u > 0)
call post_data(cs%id_S2_u, s2_u, cs%diag)
631 if (cs%id_S2_v > 0)
call post_data(cs%id_S2_v, s2_v, cs%diag)
635 call uvchksum(
"calc_Visbeck_coeffs slope_[xy]", slope_x, slope_y, g%HI, haloshift=1)
636 call uvchksum(
"calc_Visbeck_coeffs N2_u, N2_v", n2_u, n2_v, g%HI, &
637 scale=us%s_to_T**2, scalar_pair=.true.)
638 call uvchksum(
"calc_Visbeck_coeffs SN_[uv]", cs%SN_u, cs%SN_v, g%HI, &
639 scale=us%s_to_T, scalar_pair=.true.)
642 end subroutine calc_visbeck_coeffs
646 subroutine calc_slope_functions_using_just_e(h, G, GV, US, CS, e, calculate_slopes, OBC)
647 type(ocean_grid_type),
intent(inout) :: G
648 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
649 type(verticalGrid_type),
intent(in) :: GV
650 type(unit_scale_type),
intent(in) :: US
651 type(VarMix_CS),
pointer :: CS
652 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: e
653 logical,
intent(in) :: calculate_slopes
655 type(ocean_OBC_type),
optional,
pointer :: OBC
657 real :: E_x(SZIB_(G), SZJ_(G))
658 real :: E_y(SZI_(G), SZJB_(G))
667 integer :: is, ie, js, je, nz
668 integer :: i, j, k, kb_max
670 real :: S2N2_u_local(SZIB_(G), SZJ_(G),SZK_(G))
671 real :: S2N2_v_local(SZI_(G), SZJB_(G),SZK_(G))
672 logical :: local_open_u_BC, local_open_v_BC
674 if (.not.
associated(cs))
call mom_error(fatal,
"calc_slope_function:"// &
675 "Module must be initialized before it is used.")
676 if (.not. cs%calculate_Eady_growth_rate)
return 677 if (.not.
associated(cs%SN_u))
call mom_error(fatal,
"calc_slope_function:"// &
678 "%SN_u is not associated with use_variable_mixing.")
679 if (.not.
associated(cs%SN_v))
call mom_error(fatal,
"calc_slope_function:"// &
680 "%SN_v is not associated with use_variable_mixing.")
682 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
684 local_open_u_bc = .false.
685 local_open_v_bc = .false.
686 if (
present(obc))
then ;
if (
associated(obc))
then 687 local_open_u_bc = obc%open_u_BCs_exist_globally
688 local_open_v_bc = obc%open_v_BCs_exist_globally
691 one_meter = 1.0 * gv%m_to_H
692 h_neglect = gv%H_subroundoff
693 h_cutoff =
real(2*nz) * (GV%Angstrom_H + h_neglect)
700 do k=nz,cs%VarMix_Ktop,-1
702 if (calculate_slopes)
then 704 do j=js-1,je+1 ;
do i=is-1,ie
705 e_x(i,j) = us%Z_to_L*(e(i+1,j,k)-e(i,j,k))*g%IdxCu(i,j)
707 if (min(h(i,j,k),h(i+1,j,k)) < h_cutoff) e_x(i,j) = 0.
709 do j=js-1,je ;
do i=is-1,ie+1
710 e_y(i,j) = us%Z_to_L*(e(i,j+1,k)-e(i,j,k))*g%IdyCv(i,j)
712 if (min(h(i,j,k),h(i,j+1,k)) < h_cutoff) e_y(i,j) = 0.
715 do j=js-1,je+1 ;
do i=is-1,ie
716 e_x(i,j) = cs%slope_x(i,j,k)
717 if (min(h(i,j,k),h(i+1,j,k)) < h_cutoff) e_x(i,j) = 0.
719 do j=js-1,je ;
do i=is-1,ie+1
720 e_y(i,j) = cs%slope_y(i,j,k)
721 if (min(h(i,j,k),h(i,j+1,k)) < h_cutoff) e_y(i,j) = 0.
726 do j=js,je ;
do i=is-1,ie
727 s2 = ( e_x(i,j)**2 + 0.25*( &
728 (e_y(i,j)**2+e_y(i+1,j-1)**2)+(e_y(i+1,j)**2+e_y(i,j-1)**2) ) )
729 hdn = 2.*h(i,j,k)*h(i,j,k-1) / (h(i,j,k) + h(i,j,k-1) + h_neglect)
730 hup = 2.*h(i+1,j,k)*h(i+1,j,k-1) / (h(i+1,j,k) + h(i+1,j,k-1) + h_neglect)
731 h_geom = sqrt(hdn*hup)
732 n2 = gv%g_prime(k)*us%L_to_Z**2 / (gv%H_to_Z * max(hdn,hup,one_meter))
733 if (min(h(i,j,k-1), h(i+1,j,k-1), h(i,j,k), h(i+1,j,k)) < h_cutoff) &
735 s2n2_u_local(i,j,k) = (h_geom * gv%H_to_Z) * s2 * n2
737 do j=js-1,je ;
do i=is,ie
738 s2 = ( e_y(i,j)**2 + 0.25*( &
739 (e_x(i,j)**2+e_x(i-1,j+1)**2)+(e_x(i,j+1)**2+e_x(i-1,j)**2) ) )
740 hdn = 2.*h(i,j,k)*h(i,j,k-1) / (h(i,j,k) + h(i,j,k-1) + h_neglect)
741 hup = 2.*h(i,j+1,k)*h(i,j+1,k-1) / (h(i,j+1,k) + h(i,j+1,k-1) + h_neglect)
742 h_geom = sqrt(hdn*hup)
743 n2 = gv%g_prime(k)*us%L_to_Z**2 / (gv%H_to_Z * max(hdn,hup,one_meter))
744 if (min(h(i,j,k-1), h(i,j+1,k-1), h(i,j,k), h(i,j+1,k)) < h_cutoff) &
746 s2n2_v_local(i,j,k) = (h_geom * gv%H_to_Z) * s2 * n2
752 do i=is-1,ie ; cs%SN_u(i,j) = 0.0 ;
enddo 753 do k=nz,cs%VarMix_Ktop,-1 ;
do i=is-1,ie
754 cs%SN_u(i,j) = cs%SN_u(i,j) + s2n2_u_local(i,j,k)
760 if ( min(g%bathyT(i,j), g%bathyT(i+1,j)) > h_cutoff*gv%H_to_Z )
then 761 cs%SN_u(i,j) = g%mask2dCu(i,j) * sqrt( cs%SN_u(i,j) / &
762 (max(g%bathyT(i,j), g%bathyT(i+1,j))) )
766 if (local_open_u_bc)
then 767 l_seg = obc%segnum_u(i,j)
769 if (l_seg /= obc_none)
then 770 if (obc%segment(l_seg)%open)
then 779 do i=is,ie ; cs%SN_v(i,j) = 0.0 ;
enddo 780 do k=nz,cs%VarMix_Ktop,-1 ;
do i=is,ie
781 cs%SN_v(i,j) = cs%SN_v(i,j) + s2n2_v_local(i,j,k)
786 if ( min(g%bathyT(i,j), g%bathyT(i+1,j)) > h_cutoff*gv%H_to_Z )
then 787 cs%SN_v(i,j) = g%mask2dCv(i,j) * sqrt( cs%SN_v(i,j) / &
788 (max(g%bathyT(i,j), g%bathyT(i,j+1))) )
792 if (local_open_v_bc)
then 793 l_seg = obc%segnum_v(i,j)
795 if (l_seg /= obc_none)
then 796 if (obc%segment(obc%segnum_v(i,j))%open)
then 804 end subroutine calc_slope_functions_using_just_e
807 subroutine calc_qg_leith_viscosity(CS, G, GV, US, h, k, div_xx_dx, div_xx_dy, vort_xy_dx, vort_xy_dy)
812 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
813 integer,
intent(in) :: k
814 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: div_xx_dx
816 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: div_xx_dy
818 real,
dimension(SZI_(G),SZJB_(G)),
intent(inout) :: vort_xy_dx
820 real,
dimension(SZIB_(G),SZJ_(G)),
intent(inout) :: vort_xy_dy
823 real,
dimension(SZI_(G),SZJB_(G)) :: &
830 real,
dimension(SZIB_(G),SZJ_(G)) :: &
836 real :: h_at_slope_above
837 real :: h_at_slope_below
840 integer :: i, j, is, ie, js, je, isq, ieq, jsq, jeq,nz
843 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
844 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
847 inv_pi3 = 1.0/((4.0*atan(1.0))**3)
849 if ((k > 1) .and. (k < nz))
then 851 do j=js-1,je+1 ;
do i=is-2,ieq+1
852 h_at_slope_above = 2. * ( h(i,j,k-1) * h(i+1,j,k-1) ) * ( h(i,j,k) * h(i+1,j,k) ) / &
853 ( ( h(i,j,k-1) * h(i+1,j,k-1) ) * ( h(i,j,k) + h(i+1,j,k) ) &
854 + ( h(i,j,k) * h(i+1,j,k) ) * ( h(i,j,k-1) + h(i+1,j,k-1) ) + gv%H_subroundoff )
855 h_at_slope_below = 2. * ( h(i,j,k) * h(i+1,j,k) ) * ( h(i,j,k+1) * h(i+1,j,k+1) ) / &
856 ( ( h(i,j,k) * h(i+1,j,k) ) * ( h(i,j,k+1) + h(i+1,j,k+1) ) &
857 + ( h(i,j,k+1) * h(i+1,j,k+1) ) * ( h(i,j,k) + h(i+1,j,k) ) + gv%H_subroundoff )
858 ih = 1./ ( ( h_at_slope_above + h_at_slope_below + gv%H_subroundoff ) * gv%H_to_Z )
859 dslopex_dz(i,j) = 2. * ( cs%slope_x(i,j,k) - cs%slope_x(i,j,k+1) ) * ih
860 h_at_u(i,j) = 2. * ( h_at_slope_above * h_at_slope_below ) * ih
863 do j=js-2,jeq+1 ;
do i=is-1,ie+1
864 h_at_slope_above = 2. * ( h(i,j,k-1) * h(i,j+1,k-1) ) * ( h(i,j,k) * h(i,j+1,k) ) / &
865 ( ( h(i,j,k-1) * h(i,j+1,k-1) ) * ( h(i,j,k) + h(i,j+1,k) ) &
866 + ( h(i,j,k) * h(i,j+1,k) ) * ( h(i,j,k-1) + h(i,j+1,k-1) ) + gv%H_subroundoff )
867 h_at_slope_below = 2. * ( h(i,j,k) * h(i,j+1,k) ) * ( h(i,j,k+1) * h(i,j+1,k+1) ) / &
868 ( ( h(i,j,k) * h(i,j+1,k) ) * ( h(i,j,k+1) + h(i,j+1,k+1) ) &
869 + ( h(i,j,k+1) * h(i,j+1,k+1) ) * ( h(i,j,k) + h(i,j+1,k) ) + gv%H_subroundoff )
870 ih = 1./ ( ( h_at_slope_above + h_at_slope_below + gv%H_subroundoff ) * gv%H_to_Z )
871 dslopey_dz(i,j) = 2. * ( cs%slope_y(i,j,k) - cs%slope_y(i,j,k+1) ) * ih
872 h_at_v(i,j) = 2. * ( h_at_slope_above * h_at_slope_below ) * ih
875 do j=js-1,je ;
do i=is-1,ieq+1
876 f = 0.5 * ( g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j) )
877 vort_xy_dx(i,j) = vort_xy_dx(i,j) - f * us%L_to_Z * &
878 ( ( h_at_u(i,j) * dslopex_dz(i,j) + h_at_u(i-1,j+1) * dslopex_dz(i-1,j+1) ) &
879 + ( h_at_u(i-1,j) * dslopex_dz(i-1,j) + h_at_u(i,j+1) * dslopex_dz(i,j+1) ) ) / &
880 ( ( h_at_u(i,j) + h_at_u(i-1,j+1) ) + ( h_at_u(i-1,j) + h_at_u(i,j+1) ) + gv%H_subroundoff)
883 do j=js-1,jeq+1 ;
do i=is-1,ie
884 f = 0.5 * ( g%CoriolisBu(i,j) + g%CoriolisBu(i,j-1) )
885 vort_xy_dy(i,j) = vort_xy_dy(i,j) - f * us%L_to_Z * &
886 ( ( h_at_v(i,j) * dslopey_dz(i,j) + h_at_v(i+1,j-1) * dslopey_dz(i+1,j-1) ) &
887 + ( h_at_v(i,j-1) * dslopey_dz(i,j-1) + h_at_v(i+1,j) * dslopey_dz(i+1,j) ) ) / &
888 ( ( h_at_v(i,j) + h_at_v(i+1,j-1) ) + ( h_at_v(i,j-1) + h_at_v(i+1,j) ) + gv%H_subroundoff)
892 if (cs%use_QG_Leith_GM)
then 894 do j=js,je ;
do i=is-1,ieq
895 grad_vort_mag_u(i,j) = sqrt(vort_xy_dy(i,j)**2 + (0.25*((vort_xy_dx(i,j) + vort_xy_dx(i+1,j-1)) &
896 + (vort_xy_dx(i+1,j) + vort_xy_dx(i,j-1))))**2)
897 grad_div_mag_u(i,j) = sqrt(div_xx_dx(i,j)**2 + (0.25*((div_xx_dy(i,j) + div_xx_dy(i+1,j-1)) &
898 + (div_xx_dy(i+1,j) + div_xx_dy(i,j-1))))**2)
899 if (cs%use_beta_in_QG_Leith)
then 900 beta_u(i,j) = sqrt((0.5*(g%dF_dx(i,j)+g%dF_dx(i+1,j))**2) + &
901 (0.5*(g%dF_dy(i,j)+g%dF_dy(i+1,j))**2))
902 cs%KH_u_QG(i,j,k) = min(grad_vort_mag_u(i,j) + grad_div_mag_u(i,j), 3.0*beta_u(i,j)) * &
903 cs%Laplac3_const_u(i,j) * inv_pi3
905 cs%KH_u_QG(i,j,k) = (grad_vort_mag_u(i,j) + grad_div_mag_u(i,j)) * &
906 cs%Laplac3_const_u(i,j) * inv_pi3
910 do j=js-1,jeq ;
do i=is,ie
911 grad_vort_mag_v(i,j) = sqrt(vort_xy_dx(i,j)**2 + (0.25*((vort_xy_dy(i,j) + vort_xy_dy(i-1,j+1)) &
912 + (vort_xy_dy(i,j+1) + vort_xy_dy(i-1,j))))**2)
913 grad_div_mag_v(i,j) = sqrt(div_xx_dy(i,j)**2 + (0.25*((div_xx_dx(i,j) + div_xx_dx(i-1,j+1)) &
914 + (div_xx_dx(i,j+1) + div_xx_dx(i-1,j))))**2)
915 if (cs%use_beta_in_QG_Leith)
then 916 beta_v(i,j) = sqrt((0.5*(g%dF_dx(i,j)+g%dF_dx(i,j+1))**2) + &
917 (0.5*(g%dF_dy(i,j)+g%dF_dy(i,j+1))**2))
918 cs%KH_v_QG(i,j,k) = min(grad_vort_mag_v(i,j) + grad_div_mag_v(i,j), 3.0*beta_v(i,j)) * &
919 cs%Laplac3_const_v(i,j) * inv_pi3
921 cs%KH_v_QG(i,j,k) = (grad_vort_mag_v(i,j) + grad_div_mag_v(i,j)) * &
922 cs%Laplac3_const_v(i,j) * inv_pi3
928 if (cs%id_KH_v_QG > 0)
call post_data(cs%id_KH_v_QG, cs%KH_v_QG, cs%diag)
929 if (cs%id_KH_u_QG > 0)
call post_data(cs%id_KH_u_QG, cs%KH_u_QG, cs%diag)
933 end subroutine calc_qg_leith_viscosity
936 subroutine varmix_init(Time, G, GV, US, param_file, diag, CS)
937 type(time_type),
intent(in) :: time
942 type(
diag_ctrl),
target,
intent(inout) :: diag
945 real :: khtr_slope_cff, khth_slope_cff, oneortwo
946 real :: n2_filter_depth
948 real :: khtr_passivity_coeff
949 real :: absurdly_small_freq
951 logical :: gill_equatorial_ld, use_fgnv_streamfn, use_meke, in_use
952 logical :: default_2018_answers, remap_answers_2018
953 real :: mle_front_length
954 real :: leith_lap_const
955 real :: grid_sp_u2, grid_sp_v2
956 real :: grid_sp_u3, grid_sp_v3
957 real :: wave_speed_min
958 real :: wave_speed_tol
959 logical :: better_speed_est
962 # include "version_variable.h" 963 character(len=40) :: mdl =
"MOM_lateral_mixing_coeffs" 964 integer :: is, ie, js, je, isq, ieq, jsq, jeq, i, j
965 integer :: isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
966 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
967 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
968 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
969 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
971 if (
associated(cs))
then 972 call mom_error(warning,
"VarMix_init called with an associated "// &
973 "control structure.")
980 cs%calculate_cg1 = .false.
981 cs%calculate_Rd_dx = .false.
982 cs%calculate_res_fns = .false.
983 cs%calculate_Eady_growth_rate = .false.
984 cs%calculate_depth_fns = .false.
987 call get_param(param_file, mdl,
"USE_VARIABLE_MIXING", cs%use_variable_mixing,&
988 "If true, the variable mixing code will be called. This "//&
989 "allows diagnostics to be created even if the scheme is "//&
990 "not used. If KHTR_SLOPE_CFF>0 or KhTh_Slope_Cff>0, "//&
991 "this is set to true regardless of what is in the "//&
992 "parameter file.", default=.false.)
993 call get_param(param_file, mdl,
"USE_VISBECK", cs%use_Visbeck,&
994 "If true, use the Visbeck et al. (1997) formulation for \n"//&
995 "thickness diffusivity.", default=.false.)
996 call get_param(param_file, mdl,
"RESOLN_SCALED_KH", cs%Resoln_scaled_Kh, &
997 "If true, the Laplacian lateral viscosity is scaled away "//&
998 "when the first baroclinic deformation radius is well "//&
999 "resolved.", default=.false.)
1000 call get_param(param_file, mdl,
"DEPTH_SCALED_KHTH", cs%Depth_scaled_KhTh, &
1001 "If true, KHTH is scaled away when the depth is shallower"//&
1002 "than a reference depth: KHTH = MIN(1,H/H0)**N * KHTH, "//&
1003 "where H0 is a reference depth, controlled via DEPTH_SCALED_KHTH_H0, "//&
1004 "and the exponent (N) is controlled via DEPTH_SCALED_KHTH_EXP.",&
1006 call get_param(param_file, mdl,
"RESOLN_SCALED_KHTH", cs%Resoln_scaled_KhTh, &
1007 "If true, the interface depth diffusivity is scaled away "//&
1008 "when the first baroclinic deformation radius is well "//&
1009 "resolved.", default=.false.)
1010 call get_param(param_file, mdl,
"RESOLN_SCALED_KHTR", cs%Resoln_scaled_KhTr, &
1011 "If true, the epipycnal tracer diffusivity is scaled "//&
1012 "away when the first baroclinic deformation radius is "//&
1013 "well resolved.", default=.false.)
1014 call get_param(param_file, mdl,
"RESOLN_USE_EBT", cs%Resoln_use_ebt, &
1015 "If true, uses the equivalent barotropic wave speed instead "//&
1016 "of first baroclinic wave for calculating the resolution fn.",&
1018 call get_param(param_file, mdl,
"KHTH_USE_EBT_STRUCT", cs%khth_use_ebt_struct, &
1019 "If true, uses the equivalent barotropic structure "//&
1020 "as the vertical structure of thickness diffusivity.",&
1022 call get_param(param_file, mdl,
"KHTH_SLOPE_CFF", khth_slope_cff, &
1023 "The nondimensional coefficient in the Visbeck formula "//&
1024 "for the interface depth diffusivity", units=
"nondim", &
1026 call get_param(param_file, mdl,
"KHTR_SLOPE_CFF", khtr_slope_cff, &
1027 "The nondimensional coefficient in the Visbeck formula "//&
1028 "for the epipycnal tracer diffusivity", units=
"nondim", &
1030 call get_param(param_file, mdl,
"USE_STORED_SLOPES", cs%use_stored_slopes,&
1031 "If true, the isopycnal slopes are calculated once and "//&
1032 "stored for re-use. This uses more memory but avoids calling "//&
1033 "the equation of state more times than should be necessary.", &
1035 call get_param(param_file, mdl,
"VERY_SMALL_FREQUENCY", absurdly_small_freq, &
1036 "A miniscule frequency that is used to avoid division by 0. The default "//&
1037 "value is roughly (pi / (the age of the universe)).", &
1038 default=1.0e-17, units=
"s-1", scale=us%T_to_s)
1039 call get_param(param_file, mdl,
"KHTH_USE_FGNV_STREAMFUNCTION", use_fgnv_streamfn, &
1040 default=.false., do_not_log=.true.)
1041 cs%calculate_cg1 = cs%calculate_cg1 .or. use_fgnv_streamfn
1042 call get_param(param_file, mdl,
"USE_MEKE", use_meke, &
1043 default=.false., do_not_log=.true.)
1044 cs%calculate_Rd_dx = cs%calculate_Rd_dx .or. use_meke
1045 cs%calculate_Eady_growth_rate = cs%calculate_Eady_growth_rate .or. use_meke
1046 call get_param(param_file, mdl,
"KHTR_PASSIVITY_COEFF", khtr_passivity_coeff, &
1047 default=0., do_not_log=.true.)
1048 cs%calculate_Rd_dx = cs%calculate_Rd_dx .or. (khtr_passivity_coeff>0.)
1049 call get_param(param_file, mdl,
"MLE_FRONT_LENGTH", mle_front_length, &
1050 default=0., do_not_log=.true.)
1051 cs%calculate_Rd_dx = cs%calculate_Rd_dx .or. (mle_front_length>0.)
1053 call get_param(param_file, mdl,
"DEBUG", cs%debug, default=.false., do_not_log=.true.)
1056 if (cs%Resoln_use_ebt .or. cs%khth_use_ebt_struct)
then 1058 call get_param(param_file, mdl,
"RESOLN_N2_FILTER_DEPTH", n2_filter_depth, &
1059 "The depth below which N2 is monotonized to avoid stratification "//&
1060 "artifacts from altering the equivalent barotropic mode structure.",&
1061 units=
"m", default=2000., scale=us%m_to_Z)
1062 allocate(cs%ebt_struct(isd:ied,jsd:jed,g%ke)) ; cs%ebt_struct(:,:,:) = 0.0
1065 if (khtr_slope_cff>0. .or. khth_slope_cff>0.)
then 1066 cs%calculate_Eady_growth_rate = .true.
1067 call get_param(param_file, mdl,
"VISBECK_MAX_SLOPE", cs%Visbeck_S_max, &
1068 "If non-zero, is an upper bound on slopes used in the "//&
1069 "Visbeck formula for diffusivity. This does not affect the "//&
1070 "isopycnal slope calculation used within thickness diffusion.", &
1071 units=
"nondim", default=0.0)
1074 if (cs%use_stored_slopes)
then 1076 allocate(cs%slope_x(isdb:iedb,jsd:jed,g%ke+1)) ; cs%slope_x(:,:,:) = 0.0
1077 allocate(cs%slope_y(isd:ied,jsdb:jedb,g%ke+1)) ; cs%slope_y(:,:,:) = 0.0
1078 call get_param(param_file, mdl,
"KD_SMOOTH", cs%kappa_smooth, &
1079 "A diapycnal diffusivity that is used to interpolate "//&
1080 "more sensible values of T & S into thin layers.", &
1081 units=
"m2 s-1", default=1.0e-6, scale=us%m_to_Z**2*us%T_to_s)
1084 if (cs%calculate_Eady_growth_rate)
then 1086 allocate(cs%SN_u(isdb:iedb,jsd:jed)) ; cs%SN_u(:,:) = 0.0
1087 allocate(cs%SN_v(isd:ied,jsdb:jedb)) ; cs%SN_v(:,:) = 0.0
1088 cs%id_SN_u = register_diag_field(
'ocean_model',
'SN_u', diag%axesCu1, time, &
1089 'Inverse eddy time-scale, S*N, at u-points',
's-1', conversion=us%s_to_T)
1090 cs%id_SN_v = register_diag_field(
'ocean_model',
'SN_v', diag%axesCv1, time, &
1091 'Inverse eddy time-scale, S*N, at v-points',
's-1', conversion=us%s_to_T)
1092 call get_param(param_file, mdl,
"VARMIX_KTOP", cs%VarMix_Ktop, &
1093 "The layer number at which to start vertical integration "//&
1094 "of S*N for purposes of finding the Eady growth rate.", &
1095 units=
"nondim", default=2)
1098 if (khtr_slope_cff>0. .or. khth_slope_cff>0.)
then 1100 call get_param(param_file, mdl,
"VISBECK_L_SCALE", cs%Visbeck_L_scale, &
1101 "The fixed length scale in the Visbeck formula.", units=
"m", &
1103 allocate(cs%L2u(isdb:iedb,jsd:jed)) ; cs%L2u(:,:) = 0.0
1104 allocate(cs%L2v(isd:ied,jsdb:jedb)) ; cs%L2v(:,:) = 0.0
1105 if (cs%Visbeck_L_scale<0)
then 1106 do j=js,je ;
do i=is-1,ieq
1107 cs%L2u(i,j) = cs%Visbeck_L_scale**2 * g%areaCu(i,j)
1109 do j=js-1,jeq ;
do i=is,ie
1110 cs%L2v(i,j) = cs%Visbeck_L_scale**2 * g%areaCv(i,j)
1113 cs%L2u(:,:) = us%m_to_L**2*cs%Visbeck_L_scale**2
1114 cs%L2v(:,:) = us%m_to_L**2*cs%Visbeck_L_scale**2
1117 cs%id_L2u = register_diag_field(
'ocean_model',
'L2u', diag%axesCu1, time, &
1118 'Length scale squared for mixing coefficient, at u-points', &
1119 'm2', conversion=us%L_to_m**2)
1120 cs%id_L2v = register_diag_field(
'ocean_model',
'L2v', diag%axesCv1, time, &
1121 'Length scale squared for mixing coefficient, at v-points', &
1122 'm2', conversion=us%L_to_m**2)
1125 if (cs%calculate_Eady_growth_rate .and. cs%use_stored_slopes)
then 1126 cs%id_N2_u = register_diag_field(
'ocean_model',
'N2_u', diag%axesCui, time, &
1127 'Square of Brunt-Vaisala frequency, N^2, at u-points, as used in Visbeck et al.', &
1128 's-2', conversion=us%s_to_T**2)
1129 cs%id_N2_v = register_diag_field(
'ocean_model',
'N2_v', diag%axesCvi, time, &
1130 'Square of Brunt-Vaisala frequency, N^2, at v-points, as used in Visbeck et al.', &
1131 's-2', conversion=us%s_to_T**2)
1133 if (cs%use_stored_slopes)
then 1134 cs%id_S2_u = register_diag_field(
'ocean_model',
'S2_u', diag%axesCu1, time, &
1135 'Depth average square of slope magnitude, S^2, at u-points, as used in Visbeck et al.',
'nondim')
1136 cs%id_S2_v = register_diag_field(
'ocean_model',
'S2_v', diag%axesCv1, time, &
1137 'Depth average square of slope magnitude, S^2, at v-points, as used in Visbeck et al.',
'nondim')
1141 if (cs%Resoln_scaled_Kh .or. cs%Resoln_scaled_KhTh .or. cs%Resoln_scaled_KhTr)
then 1142 cs%calculate_Rd_dx = .true.
1143 cs%calculate_res_fns = .true.
1144 allocate(cs%Res_fn_h(isd:ied,jsd:jed)) ; cs%Res_fn_h(:,:) = 0.0
1145 allocate(cs%Res_fn_q(isdb:iedb,jsdb:jedb)) ; cs%Res_fn_q(:,:) = 0.0
1146 allocate(cs%Res_fn_u(isdb:iedb,jsd:jed)) ; cs%Res_fn_u(:,:) = 0.0
1147 allocate(cs%Res_fn_v(isd:ied,jsdb:jedb)) ; cs%Res_fn_v(:,:) = 0.0
1148 allocate(cs%beta_dx2_q(isdb:iedb,jsdb:jedb)) ; cs%beta_dx2_q(:,:) = 0.0
1149 allocate(cs%beta_dx2_u(isdb:iedb,jsd:jed)) ; cs%beta_dx2_u(:,:) = 0.0
1150 allocate(cs%beta_dx2_v(isd:ied,jsdb:jedb)) ; cs%beta_dx2_v(:,:) = 0.0
1151 allocate(cs%f2_dx2_q(isdb:iedb,jsdb:jedb)) ; cs%f2_dx2_q(:,:) = 0.0
1152 allocate(cs%f2_dx2_u(isdb:iedb,jsd:jed)) ; cs%f2_dx2_u(:,:) = 0.0
1153 allocate(cs%f2_dx2_v(isd:ied,jsdb:jedb)) ; cs%f2_dx2_v(:,:) = 0.0
1155 cs%id_Res_fn = register_diag_field(
'ocean_model',
'Res_fn', diag%axesT1, time, &
1156 'Resolution function for scaling diffusivities',
'nondim')
1158 call get_param(param_file, mdl,
"KH_RES_SCALE_COEF", cs%Res_coef_khth, &
1159 "A coefficient that determines how KhTh is scaled away if "//&
1160 "RESOLN_SCALED_... is true, as "//&
1161 "F = 1 / (1 + (KH_RES_SCALE_COEF*Rd/dx)^KH_RES_FN_POWER).", &
1162 units=
"nondim", default=1.0)
1163 call get_param(param_file, mdl,
"KH_RES_FN_POWER", cs%Res_fn_power_khth, &
1164 "The power of dx/Ld in the Kh resolution function. Any "//&
1165 "positive integer may be used, although even integers "//&
1166 "are more efficient to calculate. Setting this greater "//&
1167 "than 100 results in a step-function being used.", &
1168 units=
"nondim", default=2)
1169 call get_param(param_file, mdl,
"VISC_RES_SCALE_COEF", cs%Res_coef_visc, &
1170 "A coefficient that determines how Kh is scaled away if "//&
1171 "RESOLN_SCALED_... is true, as "//&
1172 "F = 1 / (1 + (KH_RES_SCALE_COEF*Rd/dx)^KH_RES_FN_POWER). "//&
1173 "This function affects lateral viscosity, Kh, and not KhTh.", &
1174 units=
"nondim", default=cs%Res_coef_khth)
1175 call get_param(param_file, mdl,
"VISC_RES_FN_POWER", cs%Res_fn_power_visc, &
1176 "The power of dx/Ld in the Kh resolution function. Any "//&
1177 "positive integer may be used, although even integers "//&
1178 "are more efficient to calculate. Setting this greater "//&
1179 "than 100 results in a step-function being used. "//&
1180 "This function affects lateral viscosity, Kh, and not KhTh.", &
1181 units=
"nondim", default=cs%Res_fn_power_khth)
1182 call get_param(param_file, mdl,
"INTERPOLATE_RES_FN", cs%interpolate_Res_fn, &
1183 "If true, interpolate the resolution function to the "//&
1184 "velocity points from the thickness points; otherwise "//&
1185 "interpolate the wave speed and calculate the resolution "//&
1186 "function independently at each point.", default=.false.)
1187 if (cs%interpolate_Res_fn)
then 1188 if (cs%Res_coef_visc /= cs%Res_coef_khth)
call mom_error(fatal, &
1189 "MOM_lateral_mixing_coeffs.F90, VarMix_init:"//&
1190 "When INTERPOLATE_RES_FN=True, VISC_RES_FN_POWER must equal KH_RES_SCALE_COEF.")
1191 if (cs%Res_fn_power_visc /= cs%Res_fn_power_khth)
call mom_error(fatal, &
1192 "MOM_lateral_mixing_coeffs.F90, VarMix_init:"//&
1193 "When INTERPOLATE_RES_FN=True, VISC_RES_FN_POWER must equal KH_RES_FN_POWER.")
1195 call get_param(param_file, mdl,
"GILL_EQUATORIAL_LD", gill_equatorial_ld, &
1196 "If true, uses Gill's definition of the baroclinic "//&
1197 "equatorial deformation radius, otherwise, if false, use "//&
1198 "Pedlosky's definition. These definitions differ by a factor "//&
1199 "of 2 in front of the beta term in the denominator. Gill's "//&
1200 "is the more appropriate definition.", default=.true.)
1201 if (gill_equatorial_ld)
then 1205 do j=js-1,jeq ;
do i=is-1,ieq
1206 cs%f2_dx2_q(i,j) = (g%dxBu(i,j)**2 + g%dyBu(i,j)**2) * &
1207 max(g%CoriolisBu(i,j)**2, absurdly_small_freq**2)
1208 cs%beta_dx2_q(i,j) = oneortwo * ((g%dxBu(i,j))**2 + (g%dyBu(i,j))**2) * (sqrt(0.5 * &
1209 ( (((g%CoriolisBu(i,j)-g%CoriolisBu(i-1,j)) * g%IdxCv(i,j))**2 + &
1210 ((g%CoriolisBu(i+1,j)-g%CoriolisBu(i,j)) * g%IdxCv(i+1,j))**2) + &
1211 (((g%CoriolisBu(i,j)-g%CoriolisBu(i,j-1)) * g%IdyCu(i,j))**2 + &
1212 ((g%CoriolisBu(i,j+1)-g%CoriolisBu(i,j)) * g%IdyCu(i,j+1))**2) ) ))
1215 do j=js,je ;
do i=is-1,ieq
1216 cs%f2_dx2_u(i,j) = (g%dxCu(i,j)**2 + g%dyCu(i,j)**2) * &
1217 max(0.5* (g%CoriolisBu(i,j)**2+g%CoriolisBu(i,j-1)**2), absurdly_small_freq**2)
1218 cs%beta_dx2_u(i,j) = oneortwo * ((g%dxCu(i,j))**2 + (g%dyCu(i,j))**2) * (sqrt( &
1219 0.25*( (((g%CoriolisBu(i,j-1)-g%CoriolisBu(i-1,j-1)) * g%IdxCv(i,j-1))**2 + &
1220 ((g%CoriolisBu(i+1,j)-g%CoriolisBu(i,j)) * g%IdxCv(i+1,j))**2) + &
1221 (((g%CoriolisBu(i+1,j-1)-g%CoriolisBu(i,j-1)) * g%IdxCv(i+1,j-1))**2 + &
1222 ((g%CoriolisBu(i,j)-g%CoriolisBu(i-1,j)) * g%IdxCv(i,j))**2) ) + &
1223 ((g%CoriolisBu(i,j)-g%CoriolisBu(i,j-1)) * g%IdyCu(i,j))**2 ))
1226 do j=js-1,jeq ;
do i=is,ie
1227 cs%f2_dx2_v(i,j) = ((g%dxCv(i,j))**2 + (g%dyCv(i,j))**2) * &
1228 max(0.5*(g%CoriolisBu(i,j)**2+g%CoriolisBu(i-1,j)**2), absurdly_small_freq**2)
1229 cs%beta_dx2_v(i,j) = oneortwo * ((g%dxCv(i,j))**2 + (g%dyCv(i,j))**2) * (sqrt( &
1230 ((g%CoriolisBu(i,j)-g%CoriolisBu(i-1,j)) * g%IdxCv(i,j))**2 + &
1231 0.25*( (((g%CoriolisBu(i,j)-g%CoriolisBu(i,j-1)) * g%IdyCu(i,j))**2 + &
1232 ((g%CoriolisBu(i-1,j+1)-g%CoriolisBu(i-1,j)) * g%IdyCu(i-1,j+1))**2) + &
1233 (((g%CoriolisBu(i,j+1)-g%CoriolisBu(i,j)) * g%IdyCu(i,j+1))**2 + &
1234 ((g%CoriolisBu(i-1,j)-g%CoriolisBu(i-1,j-1)) * g%IdyCu(i-1,j))**2) ) ))
1239 if (cs%Depth_scaled_KhTh)
then 1240 cs%calculate_depth_fns = .true.
1241 allocate(cs%Depth_fn_u(isdb:iedb,jsd:jed)) ; cs%Depth_fn_u(:,:) = 0.0
1242 allocate(cs%Depth_fn_v(isd:ied,jsdb:jedb)) ; cs%Depth_fn_v(:,:) = 0.0
1243 call get_param(param_file, mdl,
"DEPTH_SCALED_KHTH_H0", cs%depth_scaled_khth_h0, &
1244 "The depth above which KHTH is scaled away.",&
1245 units=
"m", default=1000.)
1246 call get_param(param_file, mdl,
"DEPTH_SCALED_KHTH_EXP", cs%depth_scaled_khth_exp, &
1247 "The exponent used in the depth dependent scaling function for KHTH.",&
1248 units=
"nondim", default=3.0)
1252 cs%id_Rd_dx = register_diag_field(
'ocean_model',
'Rd_dx', diag%axesT1, time, &
1253 'Ratio between deformation radius and grid spacing',
'm m-1')
1254 cs%calculate_Rd_dx = cs%calculate_Rd_dx .or. (cs%id_Rd_dx>0)
1256 if (cs%calculate_Rd_dx)
then 1257 cs%calculate_cg1 = .true.
1258 allocate(cs%Rd_dx_h(isd:ied,jsd:jed)) ; cs%Rd_dx_h(:,:) = 0.0
1259 allocate(cs%beta_dx2_h(isd:ied,jsd:jed)); cs%beta_dx2_h(:,:) = 0.0
1260 allocate(cs%f2_dx2_h(isd:ied,jsd:jed)) ; cs%f2_dx2_h(:,:) = 0.0
1261 do j=js-1,je+1 ;
do i=is-1,ie+1
1262 cs%f2_dx2_h(i,j) = (g%dxT(i,j)**2 + g%dyT(i,j)**2) * &
1263 max(0.25 * ((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
1264 (g%CoriolisBu(i-1,j)**2 + g%CoriolisBu(i,j-1)**2)), &
1265 absurdly_small_freq**2)
1266 cs%beta_dx2_h(i,j) = oneortwo * ((g%dxT(i,j))**2 + (g%dyT(i,j))**2) * (sqrt(0.5 * &
1267 ( (((g%CoriolisBu(i,j)-g%CoriolisBu(i-1,j)) * g%IdxCv(i,j))**2 + &
1268 ((g%CoriolisBu(i,j-1)-g%CoriolisBu(i-1,j-1)) * g%IdxCv(i,j-1))**2) + &
1269 (((g%CoriolisBu(i,j)-g%CoriolisBu(i,j-1)) * g%IdyCu(i,j))**2 + &
1270 ((g%CoriolisBu(i-1,j)-g%CoriolisBu(i-1,j-1)) * g%IdyCu(i-1,j))**2) ) ))
1274 if (cs%calculate_cg1)
then 1276 allocate(cs%cg1(isd:ied,jsd:jed)) ; cs%cg1(:,:) = 0.0
1277 call get_param(param_file, mdl,
"DEFAULT_2018_ANSWERS", default_2018_answers, &
1278 "This sets the default value for the various _2018_ANSWERS parameters.", &
1280 call get_param(param_file, mdl,
"REMAPPING_2018_ANSWERS", remap_answers_2018, &
1281 "If true, use the order of arithmetic and expressions that recover the "//&
1282 "answers from the end of 2018. Otherwise, use updated and more robust "//&
1283 "forms of the same expressions.", default=default_2018_answers)
1284 call get_param(param_file, mdl,
"INTERNAL_WAVE_SPEED_TOL", wave_speed_tol, &
1285 "The fractional tolerance for finding the wave speeds.", &
1286 units=
"nondim", default=0.001)
1288 call get_param(param_file, mdl,
"INTERNAL_WAVE_SPEED_MIN", wave_speed_min, &
1289 "A floor in the first mode speed below which 0 used instead.", &
1290 units=
"m s-1", default=0.0, scale=us%m_s_to_L_T)
1291 call get_param(param_file, mdl,
"INTERNAL_WAVE_SPEED_BETTER_EST", better_speed_est, &
1292 "If true, use a more robust estimate of the first mode wave speed as the "//&
1293 "starting point for iterations.", default=.false.)
1294 call wave_speed_init(cs%wave_speed_CSp, use_ebt_mode=cs%Resoln_use_ebt, &
1295 mono_n2_depth=n2_filter_depth, remap_answers_2018=remap_answers_2018, &
1296 better_speed_est=better_speed_est, min_speed=wave_speed_min, &
1297 wave_speed_tol=wave_speed_tol)
1301 call get_param(param_file, mdl,
"USE_QG_LEITH_GM", cs%use_QG_Leith_GM, &
1302 "If true, use the QG Leith viscosity as the GM coefficient.", &
1305 if (cs%Use_QG_Leith_GM)
then 1306 call get_param(param_file, mdl,
"LEITH_LAP_CONST", leith_lap_const, &
1307 "The nondimensional Laplacian Leith constant, \n"//&
1308 "often set to 1.0", units=
"nondim", default=0.0)
1310 call get_param(param_file, mdl,
"USE_BETA_IN_LEITH", cs%use_beta_in_QG_Leith, &
1311 "If true, include the beta term in the Leith nonlinear eddy viscosity.", &
1314 alloc_(cs%Laplac3_const_u(isdb:iedb,jsd:jed)) ; cs%Laplac3_const_u(:,:) = 0.0
1315 alloc_(cs%Laplac3_const_v(isd:ied,jsdb:jedb)) ; cs%Laplac3_const_v(:,:) = 0.0
1316 alloc_(cs%KH_u_QG(isdb:iedb,jsd:jed,g%ke)) ; cs%KH_u_QG(:,:,:) = 0.0
1317 alloc_(cs%KH_v_QG(isd:ied,jsdb:jedb,g%ke)) ; cs%KH_v_QG(:,:,:) = 0.0
1320 cs%id_KH_u_QG = register_diag_field(
'ocean_model',
'KH_u_QG', diag%axesCuL, time, &
1321 'Horizontal viscosity from Leith QG, at u-points',
'm2 s-1', conversion=us%L_to_m**2*us%s_to_T)
1322 cs%id_KH_v_QG = register_diag_field(
'ocean_model',
'KH_v_QG', diag%axesCvL, time, &
1323 'Horizontal viscosity from Leith QG, at v-points',
'm2 s-1', conversion=us%L_to_m**2*us%s_to_T)
1325 do j=jsq,jeq+1 ;
do i=is-1,ieq
1327 grid_sp_u2 = g%dyCu(i,j)*g%dxCu(i,j)
1328 grid_sp_u3 = grid_sp_u2*sqrt(grid_sp_u2)
1329 cs%Laplac3_const_u(i,j) = leith_lap_const * grid_sp_u3
1331 do j=js-1,jeq ;
do i=isq,ieq+1
1333 grid_sp_v2 = g%dyCv(i,j)*g%dxCv(i,j)
1334 grid_sp_v3 = grid_sp_v2*sqrt(grid_sp_v2)
1335 cs%Laplac3_const_v(i,j) = leith_lap_const * grid_sp_v3
1338 if (.not. cs%use_stored_slopes)
call mom_error(fatal, &
1339 "MOM_lateral_mixing_coeffs.F90, VarMix_init:"//&
1340 "USE_STORED_SLOPES must be True when using QG Leith.")
1345 cs%use_variable_mixing = .true.
1351 end subroutine varmix_init
Calculates the heights of sruface or all interfaces from layer thicknesses.
Control structure for MOM_wave_speed.
Functions for calculating interface heights, including free surface height.
Ocean grid type. See mom_grid for details.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Routines for calculating baroclinic wave speeds.
The MOM6 facility to parse input files for runtime parameters.
Variable mixing coefficients.
Do a halo update on a pair of arrays representing the two components of a vector. ...
Variable mixing coefficients.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Describes the decomposed MOM domain and has routines for communications across PEs.
Routines for error handling and I/O management.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Set up a group of halo updates.
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Controls where open boundary conditions are applied.
Provides a transparent vertical ocean grid type and supporting routines.
Provides transparent structures with groups of MOM6 variables and supporting routines.
Do a halo update on an array.
Calculations of isoneutral slopes and stratification.
An overloaded interface to read and log the values of various types of parameters.
Provides checksumming functions for debugging.