7 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, clock_routine
22 implicit none ;
private 24 #include <MOM_memory.h> 38 real :: meke_min_gamma
41 logical :: rd_as_max_scale
43 logical :: use_old_lscale
53 real :: viscosity_coeff
62 real :: meke_advection_factor
67 real,
dimension(:,:),
allocatable :: del2meke
71 integer :: id_meke = -1, id_ue = -1, id_kh = -1, id_src = -1
72 integer :: id_ub = -1, id_ut = -1
73 integer :: id_gm_src = -1, id_mom_src = -1, id_decay = -1
74 integer :: id_khmeke_u = -1, id_khmeke_v = -1, id_ku = -1
75 integer :: id_le = -1, id_gamma_b = -1, id_gamma_t = -1
76 integer :: id_lrhines = -1, id_leady = -1
79 integer :: id_clock_pass
80 type(group_pass_type) :: pass_meke, pass_kh, pass_ku, pass_del2meke
87 subroutine step_forward_meke(MEKE, h, SN_u, SN_v, visc, dt, G, GV, CS, hu, hv)
91 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
92 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: SN_u
93 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: SN_v
95 real,
intent(in) :: dt
97 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: hu
98 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: hv
100 real,
dimension(SZI_(G),SZJ_(G)) :: &
112 real,
dimension(SZIB_(G),SZJ_(G)) :: &
118 real,
dimension(SZI_(G),SZJB_(G)) :: &
124 real :: Kh_here, Inv_Kh_max, K4_here
132 logical :: use_drag_rate
133 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
135 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
136 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
138 if (.not.
associated(cs))
call mom_error(fatal, &
139 "MOM_MEKE: Module must be initialized before it is used.")
140 if (.not.
associated(meke))
call mom_error(fatal, &
141 "MOM_MEKE: MEKE must be initialized before it is used.")
143 rho0 = gv%H_to_kg_m2 * gv%m_to_H
144 mass_neglect = gv%H_to_kg_m2 * gv%H_subroundoff
145 sdt = dt*cs%MEKE_dtScale
146 if (cs%MEKE_damping + cs%MEKE_Cd_scale > 0.0 .or. cs%MEKE_Cb>0. &
147 .or. cs%visc_drag)
then 148 use_drag_rate = .true.
150 use_drag_rate = .false.
154 if (
associated(meke%MEKE))
then 157 if (
associated(meke%mom_src))
call hchksum(meke%mom_src,
'MEKE mom_src',g%HI)
158 if (
associated(meke%GM_src))
call hchksum(meke%GM_src,
'MEKE GM_src',g%HI)
159 if (
associated(meke%MEKE))
call hchksum(meke%MEKE,
'MEKE MEKE',g%HI)
160 call uvchksum(
"MEKE SN_[uv]", sn_u, sn_v, g%HI)
161 call uvchksum(
"MEKE h[uv]", hu, hv, g%HI, haloshift=1)
165 sdt = dt*cs%MEKE_dtScale
166 rho0 = gv%H_to_kg_m2 * gv%m_to_H
167 mass_neglect = gv%H_to_kg_m2 * gv%H_subroundoff
172 sdt_damp = sdt ;
if (cs%MEKE_KH >= 0.0 .or. cs%MEKE_K4 >= 0.) sdt_damp = 0.5*sdt
175 if (cs%MEKE_advection_factor>0.)
then 176 do j=js,je ;
do i=is-1,ie
180 do j=js,je ;
do i=is-1,ie
181 barohu(i,j) = hu(i,j,k)
184 do j=js-1,je ;
do i=is,ie
188 do j=js-1,je ;
do i=is,ie
189 barohv(i,j) = hv(i,j,k)
200 if (cs%MEKE_Cd_scale == 0.0 .and. .not. cs%visc_drag)
then 202 do j=js,je ;
do i=is,ie
208 if (cs%visc_drag)
then 210 do j=js,je ;
do i=is-1,ie
211 drag_vel_u(i,j) = 0.0
212 if ((g%mask2dCu(i,j) > 0.0) .and. (visc%bbl_thick_u(i,j) > 0.0)) &
213 drag_vel_u(i,j) = visc%kv_bbl_u(i,j) / visc%bbl_thick_u(i,j)
216 do j=js-1,je ;
do i=is,ie
217 drag_vel_v(i,j) = 0.0
218 if ((g%mask2dCv(i,j) > 0.0) .and. (visc%bbl_thick_v(i,j) > 0.0)) &
219 drag_vel_v(i,j) = visc%kv_bbl_v(i,j) / visc%bbl_thick_v(i,j)
223 do j=js,je ;
do i=is,ie
224 drag_rate_visc(i,j) = (0.25*g%IareaT(i,j) * &
225 ((g%areaCu(i-1,j)*drag_vel_u(i-1,j) + &
226 g%areaCu(i,j)*drag_vel_u(i,j)) + &
227 (g%areaCv(i,j-1)*drag_vel_v(i,j-1) + &
228 g%areaCv(i,j)*drag_vel_v(i,j)) ) )
232 do j=js,je ;
do i=is,ie
233 drag_rate_visc(i,j) = 0.
239 do i=is-1,ie+1 ; mass(i,j) = 0.0 ;
enddo 240 do k=1,nz ;
do i=is-1,ie+1
241 mass(i,j) = mass(i,j) + g%mask2dT(i,j) * (gv%H_to_kg_m2 * h(i,j,k))
245 if (mass(i,j) > 0.0) i_mass(i,j) = 1.0 / mass(i,j)
250 if (cs%initialize)
then 252 cs%initialize = .false.
256 call meke_lengthscales(cs, meke, g, sn_u, sn_v, meke%MEKE, bottomfac2, barotrfac2, lmixscale)
258 call uvchksum(
"MEKE drag_vel_[uv]", drag_vel_u, drag_vel_v, g%HI)
259 call hchksum(mass,
'MEKE mass',g%HI,haloshift=1)
260 call hchksum(drag_rate_visc,
'MEKE drag_rate_visc',g%HI)
261 call hchksum(bottomfac2,
'MEKE bottomFac2',g%HI)
262 call hchksum(barotrfac2,
'MEKE barotrFac2',g%HI)
263 call hchksum(lmixscale,
'MEKE LmixScale',g%HI)
274 do j=js,je ;
do i=is,ie
275 src(i,j) = cs%MEKE_BGsrc
278 if (
associated(meke%mom_src))
then 280 do j=js,je ;
do i=is,ie
281 src(i,j) = src(i,j) - cs%MEKE_FrCoeff*i_mass(i,j)*meke%mom_src(i,j)
285 if (
associated(meke%GM_src))
then 287 do j=js,je ;
do i=is,ie
288 src(i,j) = src(i,j) - cs%MEKE_GMcoeff*i_mass(i,j)*meke%GM_src(i,j)
294 do j=js,je ;
do i=is,ie
295 meke%MEKE(i,j) = (meke%MEKE(i,j) + sdt*src(i,j) )*g%mask2dT(i,j)
298 if (use_drag_rate)
then 301 do j=js,je ;
do i=is,ie
302 drag_rate(i,j) = (rho0 * i_mass(i,j)) * sqrt( drag_rate_visc(i,j)**2 &
303 + cdrag2 * ( max(0.0, 2.0*bottomfac2(i,j)*meke%MEKE(i,j)) + cs%MEKE_Uscale**2 ) )
309 do j=js,je ;
do i=is,ie
310 ldamping = cs%MEKE_damping + drag_rate(i,j) * bottomfac2(i,j)
311 if (meke%MEKE(i,j)<0.) ldamping = 0.
314 meke%MEKE(i,j) = meke%MEKE(i,j) / (1.0 + sdt_damp*ldamping)
315 meke_decay(i,j) = ldamping*g%mask2dT(i,j)
319 if (cs%MEKE_KH >= 0.0 .or. cs%KhMEKE_FAC > 0.0 .or. cs%MEKE_K4 >= 0.0)
then 321 call cpu_clock_begin(cs%id_clock_pass)
322 call do_group_pass(cs%pass_MEKE, g%Domain)
323 call cpu_clock_end(cs%id_clock_pass)
326 if (cs%MEKE_K4 >= 0.0)
then 330 do j=js,je ;
do i=is-1,ie
331 meke_uflux(i,j) = ((g%dy_Cu(i,j)*g%IdxCu(i,j)) * g%mask2dCu(i,j)) * &
332 (meke%MEKE(i+1,j) - meke%MEKE(i,j))
338 do j=js-1,je ;
do i=is,ie
339 meke_vflux(i,j) = ((g%dx_Cv(i,j)*g%IdyCv(i,j)) * g%mask2dCv(i,j)) * &
340 (meke%MEKE(i,j+1) - meke%MEKE(i,j))
346 do j=js,je ;
do i=is,ie
347 cs%del2MEKE(i,j) = g%IareaT(i,j) * &
348 ((meke_uflux(i,j) - meke_uflux(i-1,j)) + (meke_vflux(i,j) - meke_vflux(i,j-1)))
353 call cpu_clock_begin(cs%id_clock_pass)
354 call do_group_pass(cs%pass_del2MEKE, g%Domain)
355 call cpu_clock_end(cs%id_clock_pass)
362 do j=js,je ;
do i=is-1,ie
365 inv_kh_max = 64.0*sdt * (((g%dy_Cu(i,j)*g%IdxCu(i,j)) * &
366 max(g%IareaT(i,j),g%IareaT(i+1,j))))**2.0
367 if (k4_here*inv_kh_max > 0.3) k4_here = 0.3 / inv_kh_max
369 meke_uflux(i,j) = ((k4_here * (g%dy_Cu(i,j)*g%IdxCu(i,j))) * &
370 ((2.0*mass(i,j)*mass(i+1,j)) / ((mass(i,j)+mass(i+1,j)) + mass_neglect)) ) * &
371 (cs%del2MEKE(i+1,j) - cs%del2MEKE(i,j))
374 do j=js-1,je ;
do i=is,ie
376 inv_kh_max = 64.0*sdt * (((g%dx_Cv(i,j)*g%IdyCv(i,j)) * &
377 max(g%IareaT(i,j),g%IareaT(i,j+1))))**2.0
378 if (k4_here*inv_kh_max > 0.3) k4_here = 0.3 / inv_kh_max
380 meke_vflux(i,j) = ((k4_here * (g%dx_Cv(i,j)*g%IdyCv(i,j))) * &
381 ((2.0*mass(i,j)*mass(i,j+1)) / ((mass(i,j)+mass(i,j+1)) + mass_neglect)) ) * &
382 (cs%del2MEKE(i,j+1) - cs%del2MEKE(i,j))
386 do j=js,je ;
do i=is,ie
387 cs%del2MEKE(i,j) = (sdt*(g%IareaT(i,j)*i_mass(i,j))) * &
388 ((meke_uflux(i-1,j) - meke_uflux(i,j)) + &
389 (meke_vflux(i,j-1) - meke_vflux(i,j)))
400 if (cs%MEKE_KH >= 0.0 .or. cs%KhMEKE_FAC > 0.0 .or. cs%MEKE_advection_factor >0.0)
then 402 kh_here = max(0.,cs%MEKE_Kh)
404 do j=js,je ;
do i=is-1,ie
406 if (
associated(meke%Kh)) &
407 kh_here = max(0.,cs%MEKE_Kh) + cs%KhMEKE_Fac*0.5*(meke%Kh(i,j)+meke%Kh(i+1,j))
408 inv_kh_max = 2.0*sdt * ((g%dy_Cu(i,j)*g%IdxCu(i,j)) * &
409 max(g%IareaT(i,j),g%IareaT(i+1,j)))
410 if (kh_here*inv_kh_max > 0.25) kh_here = 0.25 / inv_kh_max
413 meke_uflux(i,j) = ((kh_here * (g%dy_Cu(i,j)*g%IdxCu(i,j))) * &
414 ((2.0*mass(i,j)*mass(i+1,j)) / ((mass(i,j)+mass(i+1,j)) + mass_neglect)) ) * &
415 (meke%MEKE(i,j) - meke%MEKE(i+1,j))
418 do j=js-1,je ;
do i=is,ie
419 if (
associated(meke%Kh)) &
420 kh_here = max(0.,cs%MEKE_Kh) + cs%KhMEKE_Fac*0.5*(meke%Kh(i,j)+meke%Kh(i,j+1))
421 inv_kh_max = 2.0*sdt * ((g%dx_Cv(i,j)*g%IdyCv(i,j)) * &
422 max(g%IareaT(i,j),g%IareaT(i,j+1)))
423 if (kh_here*inv_kh_max > 0.25) kh_here = 0.25 / inv_kh_max
426 meke_vflux(i,j) = ((kh_here * (g%dx_Cv(i,j)*g%IdyCv(i,j))) * &
427 ((2.0*mass(i,j)*mass(i,j+1)) / ((mass(i,j)+mass(i,j+1)) + mass_neglect)) ) * &
428 (meke%MEKE(i,j) - meke%MEKE(i,j+1))
430 if (cs%MEKE_advection_factor>0.)
then 431 advfac = cs%MEKE_advection_factor / dt
433 do j=js,je ;
do i=is-1,ie
434 if (barohu(i,j)>0.)
then 435 meke_uflux(i,j) = meke_uflux(i,j) + barohu(i,j)*meke%MEKE(i,j)*advfac
436 elseif (barohu(i,j)<0.)
then 437 meke_uflux(i,j) = meke_uflux(i,j) + barohu(i,j)*meke%MEKE(i+1,j)*advfac
441 do j=js-1,je ;
do i=is,ie
442 if (barohv(i,j)>0.)
then 443 meke_vflux(i,j) = meke_vflux(i,j) + barohv(i,j)*meke%MEKE(i,j)*advfac
444 elseif (barohv(i,j)<0.)
then 445 meke_vflux(i,j) = meke_vflux(i,j) + barohv(i,j)*meke%MEKE(i,j+1)*advfac
450 do j=js,je ;
do i=is,ie
451 meke%MEKE(i,j) = meke%MEKE(i,j) + (sdt*(g%IareaT(i,j)*i_mass(i,j))) * &
452 ((meke_uflux(i-1,j) - meke_uflux(i,j)) + &
453 (meke_vflux(i,j-1) - meke_vflux(i,j)))
458 if (cs%MEKE_K4 >= 0.0)
then 460 do j=js,je ;
do i=is,ie
461 meke%MEKE(i,j) = meke%MEKE(i,j) + cs%del2MEKE(i,j)
466 if (cs%MEKE_KH >= 0.0 .or. cs%MEKE_K4 >= 0.0)
then 467 if (sdt>sdt_damp)
then 469 if (use_drag_rate)
then 471 do j=js,je ;
do i=is,ie
472 drag_rate(i,j) = (rho0 * i_mass(i,j)) * sqrt( drag_rate_visc(i,j)**2 &
473 + cdrag2 * ( max(0.0, 2.0*bottomfac2(i,j)*meke%MEKE(i,j)) + cs%MEKE_Uscale**2 ) )
477 do j=js,je ;
do i=is,ie
478 ldamping = cs%MEKE_damping + drag_rate(i,j) * bottomfac2(i,j)
479 if (meke%MEKE(i,j)<0.) ldamping = 0.
482 meke%MEKE(i,j) = meke%MEKE(i,j) / (1.0 + sdt_damp*ldamping)
483 meke_decay(i,j) = 0.5 * g%mask2dT(i,j) * (meke_decay(i,j) + ldamping)
489 call cpu_clock_begin(cs%id_clock_pass)
490 call do_group_pass(cs%pass_MEKE, g%Domain)
491 call cpu_clock_end(cs%id_clock_pass)
494 if (cs%MEKE_KhCoeff>0.)
then 495 if (cs%use_old_lscale)
then 496 if (cs%Rd_as_max_scale)
then 498 do j=js,je ;
do i=is,ie
499 meke%Kh(i,j) = (cs%MEKE_KhCoeff &
500 * sqrt(2.*max(0.,barotrfac2(i,j)*meke%MEKE(i,j))*g%areaT(i,j))) &
501 * min(meke%Rd_dx_h(i,j), 1.0)
505 do j=js,je ;
do i=is,ie
506 meke%Kh(i,j) = cs%MEKE_KhCoeff*sqrt(2.*max(0.,barotrfac2(i,j)*meke%MEKE(i,j))*g%areaT(i,j))
511 do j=js,je ;
do i=is,ie
512 meke%Kh(i,j) = (cs%MEKE_KhCoeff*sqrt(2.*max(0.,barotrfac2(i,j)*meke%MEKE(i,j)))*lmixscale(i,j))
515 call cpu_clock_begin(cs%id_clock_pass)
516 call do_group_pass(cs%pass_Kh, g%Domain)
517 call cpu_clock_end(cs%id_clock_pass)
521 if (cs%viscosity_coeff/=0.)
then 523 do j=js-1,je+1 ;
do i=is-1,ie+1
524 meke%Ku(i,j) = cs%viscosity_coeff*sqrt(2.*max(0.,meke%MEKE(i,j)))*lmixscale(i,j)
526 call cpu_clock_begin(cs%id_clock_pass)
527 call do_group_pass(cs%pass_Ku, g%Domain)
528 call cpu_clock_end(cs%id_clock_pass)
532 if (cs%id_MEKE>0)
call post_data(cs%id_MEKE, meke%MEKE, cs%diag)
533 if (cs%id_Ue>0)
call post_data(cs%id_Ue, sqrt(max(0.,2.0*meke%MEKE)), cs%diag)
534 if (cs%id_Ub>0)
call post_data(cs%id_Ub, sqrt(max(0.,2.0*meke%MEKE*bottomfac2)), cs%diag)
535 if (cs%id_Ut>0)
call post_data(cs%id_Ut, sqrt(max(0.,2.0*meke%MEKE*barotrfac2)), cs%diag)
536 if (cs%id_Kh>0)
call post_data(cs%id_Kh, meke%Kh, cs%diag)
537 if (cs%id_Ku>0)
call post_data(cs%id_Ku, meke%Ku, cs%diag)
538 if (cs%id_KhMEKE_u>0)
call post_data(cs%id_KhMEKE_u, kh_u, cs%diag)
539 if (cs%id_KhMEKE_v>0)
call post_data(cs%id_KhMEKE_v, kh_v, cs%diag)
540 if (cs%id_src>0)
call post_data(cs%id_src, src, cs%diag)
541 if (cs%id_decay>0)
call post_data(cs%id_decay, meke_decay, cs%diag)
542 if (cs%id_GM_src>0)
call post_data(cs%id_GM_src, meke%GM_src, cs%diag)
543 if (cs%id_mom_src>0)
call post_data(cs%id_mom_src, meke%mom_src, cs%diag)
544 if (cs%id_Le>0)
call post_data(cs%id_Le, lmixscale, cs%diag)
545 if (cs%id_gamma_b>0)
then 546 do j=js,je ;
do i=is,ie
547 bottomfac2(i,j) = sqrt(bottomfac2(i,j))
549 call post_data(cs%id_gamma_b, bottomfac2, cs%diag)
551 if (cs%id_gamma_t>0)
then 552 do j=js,je ;
do i=is,ie
553 barotrfac2(i,j) = sqrt(barotrfac2(i,j))
555 call post_data(cs%id_gamma_t, barotrfac2, cs%diag)
567 subroutine meke_equilibrium(CS, MEKE, G, GV, SN_u, SN_v, drag_rate_visc, I_mass)
572 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: SN_u
573 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: SN_v
574 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: drag_rate_visc
575 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: I_mass
577 real :: beta, SN, bottomFac2, barotrFac2, LmixScale, Lrhines, Leady
578 real :: I_H, KhCoeff, Kh, Ubg2, cd2, drag_rate, ldamping, src
579 real :: EKE, EKEmin, EKEmax, resid, ResMin, ResMax, EKEerr
580 integer :: i, j, is, ie, js, je, n1, n2
581 real,
parameter :: tolerance = 1.e-12
582 logical :: useSecant, debugIteration
584 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
586 debugiteration = .false.
587 khcoeff = cs%MEKE_KhCoeff
588 ubg2 = cs%MEKE_Uscale**2
592 do j=js,je ;
do i=is,ie
595 sn = min( min(sn_u(i,j) , sn_u(i-1,j)) , min(sn_v(i,j), sn_v(i,j-1)) )
596 beta = sqrt( g%dF_dx(i,j)**2 + g%dF_dy(i,j)**2 )
597 i_h = gv%Rho0 * i_mass(i,j)
599 if (khcoeff*sn*i_h>0.)
then 612 meke%Rd_dx_h(i,j), sn, eke, &
613 bottomfac2, barotrfac2, lmixscale, &
616 kh = (khcoeff * sqrt(2.*barotrfac2*eke) * lmixscale)
618 drag_rate = i_h * sqrt( drag_rate_visc(i,j)**2 + cd2 * ( 2.0*bottomfac2*eke + ubg2 ) )
619 ldamping = cs%MEKE_damping + drag_rate * bottomfac2
620 resid = src - ldamping * eke
621 if (debugiteration)
then 622 write(0,*) n1,
'EKE=',eke,
'resid=',resid
623 write(0,*)
'EKEmin=',ekemin,
'ResMin=',resmin
624 write(0,*)
'src=',src,
'ldamping=',ldamping
625 write(0,*)
'gamma-b=',bottomfac2,
'gamma-t=',barotrfac2
626 write(0,*)
'drag_visc=',drag_rate_visc(i,j),
'Ubg2=',ubg2
631 if (resid<resmin) usesecant = .true.
633 if (ekemax > 2.e17)
then 634 if (debugiteration) stop
'Something has gone very wrong' 635 debugiteration = .true.
637 ekemin = 0. ; resmin = 0.
646 n2 = 0 ; ekeerr = ekemax - ekemin
647 do while (ekeerr>tolerance)
650 eke = ekemin + (ekemax - ekemin) * (resmin / (resmin - resmax))
652 eke = 0.5 * (ekemin + ekemax)
654 ekeerr = min( eke-ekemin, ekemax-eke )
656 kh = (khcoeff * sqrt(2.*barotrfac2*eke) * lmixscale)
658 drag_rate = i_h * sqrt( drag_rate_visc(i,j)**2 + cd2 * ( 2.0*bottomfac2*eke + ubg2 ) )
659 ldamping = cs%MEKE_damping + drag_rate * bottomfac2
660 resid = src - ldamping * eke
661 if (usesecant.and.resid>resmin) usesecant = .false.
664 if (resid<resmin) usesecant = .true.
666 elseif (resid<0.)
then 672 if (n2>200) stop
'Failing to converge?' 688 EKE, bottomFac2, barotrFac2, LmixScale)
692 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: SN_u
693 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: SN_v
694 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: EKE
695 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: bottomFac2
696 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: barotrFac2
697 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: LmixScale
699 real,
dimension(SZI_(G),SZJ_(G)) :: Lrhines, Leady
701 integer :: i, j, is, ie, js, je
703 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
706 do j=js,je ;
do i=is,ie
707 if (.not.cs%use_old_lscale)
then 708 if (cs%aEady > 0.)
then 709 sn = 0.25*( (sn_u(i,j) + sn_u(i-1,j)) + (sn_v(i,j) + sn_v(i,j-1)) )
713 beta = sqrt( g%dF_dx(i,j)**2 + g%dF_dy(i,j)**2 )
717 meke%Rd_dx_h(i,j), sn, meke%MEKE(i,j), &
718 bottomfac2(i,j), barotrfac2(i,j), lmixscale(i,j), &
719 lrhines(i,j), leady(i,j))
721 if (cs%id_Lrhines>0)
call post_data(cs%id_Lrhines, lrhines, cs%diag)
722 if (cs%id_Leady>0)
call post_data(cs%id_Leady, leady, cs%diag)
730 EKE, bottomFac2, barotrFac2, LmixScale, Lrhines, Leady)
732 real,
intent(in) :: area
733 real,
intent(in) :: beta
734 real,
intent(in) :: depth
735 real,
intent(in) :: Rd_dx
736 real,
intent(in) :: SN
737 real,
intent(in) :: EKE
738 real,
intent(out) :: bottomFac2
739 real,
intent(out) :: barotrFac2
740 real,
intent(out) :: LmixScale
741 real,
intent(out) :: Lrhines
742 real,
intent(out) :: Leady
744 real :: Lgrid, Ldeform, LdeformLim, Ue, Lfrict
748 ldeform = lgrid * rd_dx
749 lfrict = depth / cs%cdrag
752 bottomfac2 = cs%MEKE_CD_SCALE**2
753 if (lfrict*cs%MEKE_Cb>0.) bottomfac2 = bottomfac2 + 1./( 1. + cs%MEKE_Cb*(ldeform/lfrict) )**0.8
754 bottomfac2 = max(bottomfac2, cs%MEKE_min_gamma)
758 if (lfrict*cs%MEKE_Ct>0.) barotrfac2 = 1./( 1. + cs%MEKE_Ct*(ldeform/lfrict) )**0.25
759 barotrfac2 = max(barotrfac2, cs%MEKE_min_gamma)
760 if (cs%use_old_lscale)
then 761 if (cs%Rd_as_max_scale)
then 762 lmixscale = min(ldeform, lgrid)
767 ue = sqrt( 2.0 * max( 0., barotrfac2*eke ) )
768 lrhines = sqrt( ue / max( beta, 1.e-30 ) )
769 if (cs%aEady > 0.)
then 770 leady = ue / max( sn, 1.e-15 )
775 if (cs%aDeform*ldeform > 0.) lmixscale = lmixscale + 1./(cs%aDeform*ldeform)
776 if (cs%aFrict *lfrict > 0.) lmixscale = lmixscale + 1./(cs%aFrict *lfrict)
777 if (cs%aRhines*lrhines > 0.) lmixscale = lmixscale + 1./(cs%aRhines*lrhines)
778 if (cs%aEady *leady > 0.) lmixscale = lmixscale + 1./(cs%aEady *leady)
779 if (cs%aGrid *lgrid > 0.) lmixscale = lmixscale + 1./(cs%aGrid *lgrid)
780 if (cs%Lfixed > 0.) lmixscale = lmixscale + 1./cs%Lfixed
781 if (lmixscale > 0.) lmixscale = 1. / lmixscale
788 logical function meke_init(Time, G, param_file, diag, CS, MEKE, restart_CS)
789 type(time_type),
intent(in) :: Time
792 type(
diag_ctrl),
target,
intent(inout) :: diag
797 integer :: is, ie, js, je, isd, ied, jsd, jed, nz
798 logical :: laplacian, useVarMix, coldStart
800 #include "version_variable.h" 801 character(len=40) :: mdl =
"MOM_MEKE" 803 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
804 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
809 "If true, turns on the MEKE scheme which calculates\n"// &
810 "a sub-grid mesoscale eddy kinetic energy budget.", &
814 if (.not.
associated(meke))
then 816 call mom_error(warning,
"MEKE_init called with NO associated "// &
817 "MEKE-type structure.")
820 if (
associated(cs))
then 822 "MEKE_init called with an associated control structure.")
824 else ;
allocate(cs) ;
endif 826 call mom_mesg(
"MEKE_init: reading parameters ", 5)
829 call get_param(param_file, mdl,
"MEKE_DAMPING", cs%MEKE_damping, &
830 "The local depth-indepented MEKE dissipation rate.", &
831 units=
"s-1", default=0.0)
832 call get_param(param_file, mdl,
"MEKE_CD_SCALE", cs%MEKE_Cd_scale, &
833 "The ratio of the bottom eddy velocity to the column mean\n"//&
834 "eddy velocity, i.e. sqrt(2*MEKE). This should be less than 1\n"//&
835 "to account for the surface intensification of MEKE.", &
836 units=
"nondim", default=0.)
837 call get_param(param_file, mdl,
"MEKE_CB", cs%MEKE_Cb, &
838 "A coefficient in the expression for the ratio of bottom projected\n"//&
839 "eddy energy and mean column energy (see Jansen et al. 2015).",&
840 units=
"nondim", default=25.)
841 call get_param(param_file, mdl,
"MEKE_MIN_GAMMA2", cs%MEKE_min_gamma, &
842 "The minimum allowed value of gamma_b^2.",&
843 units=
"nondim", default=0.0001)
844 call get_param(param_file, mdl,
"MEKE_CT", cs%MEKE_Ct, &
845 "A coefficient in the expression for the ratio of barotropic\n"//&
846 "eddy energy and mean column energy (see Jansen et al. 2015).",&
847 units=
"nondim", default=50.)
848 call get_param(param_file, mdl,
"MEKE_GMCOEFF", cs%MEKE_GMcoeff, &
849 "The efficiency of the conversion of potential energy \n"//&
850 "into MEKE by the thickness mixing parameterization. \n"//&
851 "If MEKE_GMCOEFF is negative, this conversion is not \n"//&
852 "used or calculated.", units=
"nondim", default=-1.0)
853 call get_param(param_file, mdl,
"MEKE_FRCOEFF", cs%MEKE_FrCoeff, &
854 "The efficiency of the conversion of mean energy into \n"//&
855 "MEKE. If MEKE_FRCOEFF is negative, this conversion \n"//&
856 "is not used or calculated.", units=
"nondim", default=-1.0)
857 call get_param(param_file, mdl,
"MEKE_BGSRC", cs%MEKE_BGsrc, &
858 "A background energy source for MEKE.", units=
"W kg-1", &
860 call get_param(param_file, mdl,
"MEKE_KH", cs%MEKE_Kh, &
861 "A background lateral diffusivity of MEKE.\n"//&
862 "Use a negative value to not apply lateral diffusion to MEKE.", &
863 units=
"m2 s-1", default=-1.0)
864 call get_param(param_file, mdl,
"MEKE_K4", cs%MEKE_K4, &
865 "A lateral bi-harmonic diffusivity of MEKE.\n"//&
866 "Use a negative value to not apply bi-harmonic diffusion to MEKE.", &
867 units=
"m4 s-1", default=-1.0)
868 call get_param(param_file, mdl,
"MEKE_DTSCALE", cs%MEKE_dtScale, &
869 "A scaling factor to accelerate the time evolution of MEKE.", &
870 units=
"nondim", default=1.0)
871 call get_param(param_file, mdl,
"MEKE_KHCOEFF", cs%MEKE_KhCoeff, &
872 "A scaling factor in the expression for eddy diffusivity\n"//&
873 "which is otherwise proportional to the MEKE velocity-\n"//&
874 "scale times an eddy mixing-length. This factor\n"//&
875 "must be >0 for MEKE to contribute to the thickness/\n"//&
876 "and tracer diffusivity in the rest of the model.", &
877 units=
"nondim", default=1.0)
878 call get_param(param_file, mdl,
"MEKE_USCALE", cs%MEKE_Uscale, &
879 "The background velocity that is combined with MEKE to \n"//&
880 "calculate the bottom drag.", units=
"m s-1", default=0.0)
881 call get_param(param_file, mdl,
"MEKE_VISC_DRAG", cs%visc_drag, &
882 "If true, use the vertvisc_type to calculate the bottom \n"//&
883 "drag acting on MEKE.", default=.true.)
884 call get_param(param_file, mdl,
"MEKE_KHTH_FAC", meke%KhTh_fac, &
885 "A factor that maps MEKE%Kh to KhTh.", units=
"nondim", &
887 call get_param(param_file, mdl,
"MEKE_KHTR_FAC", meke%KhTr_fac, &
888 "A factor that maps MEKE%Kh to KhTr.", units=
"nondim", &
890 call get_param(param_file, mdl,
"MEKE_KHMEKE_FAC", cs%KhMEKE_Fac, &
891 "A factor that maps MEKE%Kh to Kh for MEKE itself.", &
892 units=
"nondim", default=0.0)
893 call get_param(param_file, mdl,
"MEKE_OLD_LSCALE", cs%use_old_lscale, &
894 "If true, use the old formula for length scale which is\n"//&
895 "a function of grid spacing and deformation radius.", &
897 call get_param(param_file, mdl,
"MEKE_RD_MAX_SCALE", cs%Rd_as_max_scale, &
898 "If true, the length scale used by MEKE is the minimum of\n"//&
899 "the deformation radius or grid-spacing. Only used if\n"//&
900 "MEKE_OLD_LSCALE=True", units=
"nondim", default=.false.)
901 call get_param(param_file, mdl,
"MEKE_VISCOSITY_COEFF", cs%viscosity_coeff, &
902 "If non-zero, is the scaling coefficient in the expression for\n"//&
903 "viscosity used to parameterize lateral momentum mixing by\n"//&
904 "unresolved eddies represented by MEKE. Can be negative to\n"//&
905 "represent backscatter from the unresolved eddies.", &
906 units=
"nondim", default=0.0)
907 call get_param(param_file, mdl,
"MEKE_FIXED_MIXING_LENGTH", cs%Lfixed, &
908 "If positive, is a fixed length contribution to the expression\n"//&
909 "for mixing length used in MEKE-derived diffusiviity.", &
910 units=
"m", default=0.0)
911 call get_param(param_file, mdl,
"MEKE_ALPHA_DEFORM", cs%aDeform, &
912 "If positive, is a coefficient weighting the deformation scale\n"//&
913 "in the expression for mixing length used in MEKE-derived diffusiviity.", &
914 units=
"nondim", default=0.0)
915 call get_param(param_file, mdl,
"MEKE_ALPHA_RHINES", cs%aRhines, &
916 "If positive, is a coefficient weighting the Rhines scale\n"//&
917 "in the expression for mixing length used in MEKE-derived diffusiviity.", &
918 units=
"nondim", default=0.05)
919 call get_param(param_file, mdl,
"MEKE_ALPHA_EADY", cs%aEady, &
920 "If positive, is a coefficient weighting the Eady length scale\n"//&
921 "in the expression for mixing length used in MEKE-derived diffusiviity.", &
922 units=
"nondim", default=0.05)
923 call get_param(param_file, mdl,
"MEKE_ALPHA_FRICT", cs%aFrict, &
924 "If positive, is a coefficient weighting the frictional arrest scale\n"//&
925 "in the expression for mixing length used in MEKE-derived diffusiviity.", &
926 units=
"nondim", default=0.0)
927 call get_param(param_file, mdl,
"MEKE_ALPHA_GRID", cs%aGrid, &
928 "If positive, is a coefficient weighting the grid-spacing as a scale\n"//&
929 "in the expression for mixing length used in MEKE-derived diffusiviity.", &
930 units=
"nondim", default=0.0)
931 call get_param(param_file, mdl,
"MEKE_COLD_START", coldstart, &
932 "If true, initialize EKE to zero. Otherwise a local equilibrium solution\n"//&
933 "is used as an initial condition for EKE.", default=.false.)
934 call get_param(param_file, mdl,
"MEKE_BACKSCAT_RO_C", meke%backscatter_Ro_c, &
935 "The coefficient in the Rossby number function for scaling the buharmonic\n"//&
936 "frictional energy source. Setting to non-zero enables the Rossby number function.", &
937 units=
"nondim", default=0.0)
938 call get_param(param_file, mdl,
"MEKE_BACKSCAT_RO_POW", meke%backscatter_Ro_pow, &
939 "The power in the Rossby number function for scaling the biharmomnic\n"//&
940 "frictional energy source.", units=
"nondim", default=0.0)
941 call get_param(param_file, mdl,
"MEKE_ADVECTION_FACTOR", cs%MEKE_advection_factor, &
942 "A scale factor in front of advection of eddy energy. Zero turns advection off.\n"//&
943 "Using unity would be normal but other values could accomodate a mismatch\n"//&
944 "between the advecting barotropic flow and the vertical structure of MEKE.", &
945 units=
"nondim", default=0.0)
948 call get_param(param_file, mdl,
"CDRAG", cs%cdrag, &
949 "CDRAG is the drag coefficient relating the magnitude of \n"//&
950 "the velocity field to the bottom stress.", units=
"nondim", &
952 call get_param(param_file, mdl,
"LAPLACIAN", laplacian, default=.false., do_not_log=.true.)
953 if (cs%viscosity_coeff/=0. .and. .not. laplacian)
call mom_error(fatal, &
954 "LAPLACIAN must be true if MEKE_VISCOSITY_COEFF is true.")
956 call get_param(param_file, mdl,
"USE_VARIABLE_MIXING", usevarmix, default=.false., do_not_log=.true.)
957 if (.not. usevarmix .and. cs%aEady>0.)
call mom_error(fatal, &
958 "USE_VARIABLE_MIXING must be true if USE_MEKE is true and MEKE_ALPHA_EADY>0.")
959 call get_param(param_file, mdl,
"DEBUG", cs%debug, default=.false., do_not_log=.true.)
962 if (cs%MEKE_K4>=0.)
then 963 allocate(cs%del2MEKE(isd:ied,jsd:jed)) ; cs%del2MEKE(:,:) = 0.0
967 if (
associated(meke%MEKE))
then 969 call do_group_pass(cs%pass_MEKE, g%Domain)
971 if (
associated(meke%Kh))
then 973 call do_group_pass(cs%pass_Kh, g%Domain)
975 if (
associated(meke%Ku))
then 977 call do_group_pass(cs%pass_Ku, g%Domain)
979 if (
allocated(cs%del2MEKE))
then 981 call do_group_pass(cs%pass_del2MEKE, g%Domain)
986 cs%id_MEKE = register_diag_field(
'ocean_model',
'MEKE', diag%axesT1, time, &
987 'Mesoscale Eddy Kinetic Energy',
'meter2 second-2')
988 if (.not.
associated(meke%MEKE)) cs%id_MEKE = -1
989 cs%id_Kh = register_diag_field(
'ocean_model',
'MEKE_KH', diag%axesT1, time, &
990 'MEKE derived diffusivity',
'meter2 second-1')
991 if (.not.
associated(meke%Kh)) cs%id_Kh = -1
992 cs%id_Ku = register_diag_field(
'ocean_model',
'MEKE_KU', diag%axesT1, time, &
993 'MEKE derived lateral viscosity',
'meter2 second-1')
994 if (.not.
associated(meke%Ku)) cs%id_Ku = -1
995 cs%id_Ue = register_diag_field(
'ocean_model',
'MEKE_Ue', diag%axesT1, time, &
996 'MEKE derived eddy-velocity scale',
'meter second-1')
997 if (.not.
associated(meke%MEKE)) cs%id_Ue = -1
998 cs%id_Ub = register_diag_field(
'ocean_model',
'MEKE_Ub', diag%axesT1, time, &
999 'MEKE derived bottom eddy-velocity scale',
'meter second-1')
1000 if (.not.
associated(meke%MEKE)) cs%id_Ub = -1
1001 cs%id_Ut = register_diag_field(
'ocean_model',
'MEKE_Ut', diag%axesT1, time, &
1002 'MEKE derived barotropic eddy-velocity scale',
'meter second-1')
1003 if (.not.
associated(meke%MEKE)) cs%id_Ut = -1
1004 cs%id_src = register_diag_field(
'ocean_model',
'MEKE_src', diag%axesT1, time, &
1005 'MEKE energy source',
'meter2 second-3')
1006 cs%id_decay = register_diag_field(
'ocean_model',
'MEKE_decay', diag%axesT1, time, &
1007 'MEKE decay rate',
'second-1')
1008 cs%id_KhMEKE_u = register_diag_field(
'ocean_model',
'KHMEKE_u', diag%axesCu1, time, &
1009 'Zonal diffusivity of MEKE',
'meter2 second-1')
1010 cs%id_KhMEKE_v = register_diag_field(
'ocean_model',
'KHMEKE_v', diag%axesCv1, time, &
1011 'Meridional diffusivity of MEKE',
'meter2 second-1')
1012 cs%id_GM_src = register_diag_field(
'ocean_model',
'MEKE_GM_src', diag%axesT1, time, &
1013 'MEKE energy available from thickness mixing',
'Watt meter-2')
1014 if (.not.
associated(meke%GM_src)) cs%id_GM_src = -1
1015 cs%id_mom_src = register_diag_field(
'ocean_model',
'MEKE_mom_src',diag%axesT1, time, &
1016 'MEKE energy available from momentum',
'Watt meter-2')
1017 if (.not.
associated(meke%mom_src)) cs%id_mom_src = -1
1018 cs%id_Le = register_diag_field(
'ocean_model',
'MEKE_Le', diag%axesT1, time, &
1019 'Eddy mixing length used in the MEKE derived eddy diffusivity',
'meter')
1020 cs%id_Lrhines = register_diag_field(
'ocean_model',
'MEKE_Lrhines', diag%axesT1, time, &
1021 'Rhines length scale used in the MEKE derived eddy diffusivity',
'meter')
1022 cs%id_Leady = register_diag_field(
'ocean_model',
'MEKE_Leady', diag%axesT1, time, &
1023 'Eady length scale used in the MEKE derived eddy diffusivity',
'meter')
1024 cs%id_gamma_b = register_diag_field(
'ocean_model',
'MEKE_gamma_b', diag%axesT1, time, &
1025 'Ratio of bottom-projected eddy velocity to column-mean eddy velocity',
'nondim')
1026 cs%id_gamma_t = register_diag_field(
'ocean_model',
'MEKE_gamma_t', diag%axesT1, time, &
1027 'Ratio of barotropic eddy velocity to column-mean eddy velocity',
'nondim')
1029 cs%id_clock_pass = cpu_clock_id(
'(Ocean continuity halo updates)', grain=clock_routine)
1035 if (coldstart) cs%initialize = .false.
1036 if (cs%initialize)
call mom_error(warning, &
1037 "MEKE_init: Initializing MEKE with a local equilibrium balance.")
1050 real :: MEKE_GMcoeff, MEKE_FrCoeff, MEKE_KHCoeff, MEKE_viscCoeff
1052 integer :: isd, ied, jsd, jed
1055 usemeke = .false.;
call read_param(param_file,
"USE_MEKE",usemeke)
1058 meke_gmcoeff =-1.;
call read_param(param_file,
"MEKE_GMCOEFF",meke_gmcoeff)
1059 meke_frcoeff =-1.;
call read_param(param_file,
"MEKE_FRCOEFF",meke_frcoeff)
1060 meke_khcoeff =1.;
call read_param(param_file,
"MEKE_KHCOEFF",meke_khcoeff)
1061 meke_visccoeff =0.;
call read_param(param_file,
"MEKE_VISCOSITY_COEFF",meke_visccoeff)
1064 if (
associated(meke))
then 1065 call mom_error(warning,
"MEKE_alloc_register_restart called with an associated "// &
1068 else;
allocate(meke);
endif 1070 if (.not. usemeke)
return 1073 call mom_mesg(
"MEKE_alloc_register_restart: allocating and registering", 5)
1074 isd = hi%isd ; ied = hi%ied ; jsd = hi%jsd ; jed = hi%jed
1075 allocate(meke%MEKE(isd:ied,jsd:jed)) ; meke%MEKE(:,:) = 0.0
1076 vd =
var_desc(
"MEKE",
"m2 s-2", hor_grid=
'h', z_grid=
'1', &
1077 longname=
"Mesoscale Eddy Kinetic Energy")
1079 if (meke_gmcoeff>=0.)
then 1080 allocate(meke%GM_src(isd:ied,jsd:jed)) ; meke%GM_src(:,:) = 0.0
1082 if (meke_frcoeff>=0.)
then 1083 allocate(meke%mom_src(isd:ied,jsd:jed)) ; meke%mom_src(:,:) = 0.0
1085 if (meke_khcoeff>=0.)
then 1086 allocate(meke%Kh(isd:ied,jsd:jed)) ; meke%Kh(:,:) = 0.0
1087 vd =
var_desc(
"MEKE_Kh",
"m2 s-1",hor_grid=
'h',z_grid=
'1', &
1088 longname=
"Lateral diffusivity from Mesoscale Eddy Kinetic Energy")
1091 allocate(meke%Rd_dx_h(isd:ied,jsd:jed)) ; meke%Rd_dx_h(:,:) = 0.0
1092 if (meke_visccoeff/=0.)
then 1093 allocate(meke%Ku(isd:ied,jsd:jed)) ; meke%Ku(:,:) = 0.0
1094 vd =
var_desc(
"MEKE_Ah",
"m2 s-1", hor_grid=
'h', z_grid=
'1', &
1095 longname=
"Lateral viscosity from Mesoscale Eddy Kinetic Energy")
1107 if (
associated(cs))
deallocate(cs)
1109 if (.not.
associated(meke))
return 1111 if (
associated(meke%MEKE))
deallocate(meke%MEKE)
1112 if (
associated(meke%GM_src))
deallocate(meke%GM_src)
1113 if (
associated(meke%mom_src))
deallocate(meke%mom_src)
1114 if (
associated(meke%Kh))
deallocate(meke%Kh)
1115 if (
associated(meke%Ku))
deallocate(meke%Ku)
1116 if (
allocated(cs%del2MEKE))
deallocate(cs%del2MEKE)
subroutine meke_lengthscales(CS, MEKE, G, SN_u, SN_v, EKE, bottomFac2, barotrFac2, LmixScale)
Calculates the eddy mixing length scale and and functions that are ratios of either bottom or barot...
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...
Ocean grid type. See mom_grid for details.
Provides the ocean grid type.
subroutine, public do_group_pass(group, MOM_dom)
The vertvisc_type structure contains vertical viscosities, drag coefficients, and related fields...
This module contains I/O framework code.
Defines the horizontal index type (hor_index_type) used for providing index ranges.
subroutine meke_equilibrium(CS, MEKE, G, GV, SN_u, SN_v, drag_rate_visc, I_mass)
Calculates the equilibrium solutino where the source depends only on MEKE diffusivity and there is no...
subroutine, public meke_end(MEKE, CS)
Deallocates any variables allocated in MEKE_init or MEKE_alloc_register_restart.
Container for horizontal index ranges for data, computational and global domains. ...
Control structure that contains MEKE parameters and diagnostics handles.
logical function, public meke_init(Time, G, param_file, diag, CS, MEKE, restart_CS)
Initializes the MOM_MEKE module and reads parameters. Returns True if module is to be used...
subroutine, public step_forward_meke(MEKE, h, SN_u, SN_v, visc, dt, G, GV, CS, hu, hv)
Integrates forward-in-time the MEKE eddy energy equation. See MEKE equations.
subroutine meke_lengthscales_0d(CS, area, beta, depth, Rd_dx, SN, EKE, bottomFac2, barotrFac2, LmixScale, Lrhines, Leady)
Calculates the eddy mixing length scale and and functions that are ratios of either bottom or barot...
Implements the Mesoscale Eddy Kinetic Energy framework.
subroutine, public mom_mesg(message, verb, all_print)
Type for describing a variable, typically a tracer.
subroutine, public meke_alloc_register_restart(HI, param_file, MEKE, restart_CS)
Allocates memory and register restart fields for the MOM_MEKE module.
subroutine, public mom_error(level, message, all_print)