20 implicit none ;
private 25 #include <MOM_memory.h> 30 real :: khth_slope_cff
38 logical :: use_fgnv_streamfn
47 logical :: detangle_interfaces
56 real,
pointer :: gmwork(:,:) => null()
57 real,
pointer :: diagslopex(:,:,:) => null()
58 real,
pointer :: diagslopey(:,:,:) => null()
62 integer :: id_uhgm = -1, id_vhgm = -1, id_gmwork = -1
63 integer :: id_kh_u = -1, id_kh_v = -1, id_kh_t = -1
64 integer :: id_kh_u1 = -1, id_kh_v1 = -1, id_kh_t1 = -1
65 integer :: id_slope_x = -1, id_slope_y = -1
66 integer :: id_sfn_unlim_x = -1, id_sfn_unlim_y = -1, id_sfn_x = -1, id_sfn_y = -1
75 subroutine thickness_diffuse(h, uhtr, vhtr, tv, dt, G, GV, MEKE, VarMix, CDp, CS)
78 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
79 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: uhtr
80 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: vhtr
82 real,
intent(in) :: dt
88 real :: e(szi_(g), szj_(g), szk_(g)+1)
90 real :: uhD(szib_(g), szj_(g), szk_(g))
91 real :: vhD(szi_(g), szjb_(g), szk_(g))
93 real,
dimension(SZIB_(G), SZJ_(G), SZK_(G)+1) :: &
99 real,
dimension(SZI_(G), SZJB_(G), SZK_(G)+1) :: &
105 real,
dimension(SZI_(G), SZJ_(G), SZK_(G)) :: &
108 real,
dimension(SZIB_(G), SZJ_(G)) :: &
110 real,
dimension(SZI_(G), SZJB_(G)) :: &
112 real :: Khth_Loc_u(szib_(g), szj_(g))
113 real :: Khth_Loc(szib_(g), szjb_(g))
114 real :: H_to_m, m_to_H
117 real,
dimension(:,:),
pointer :: cg1 => null()
118 logical :: use_VarMix, Resoln_scaled, use_stored_slopes, khth_use_ebt_struct
119 integer :: i, j, k, is, ie, js, je, nz
120 real :: hu(szi_(g), szj_(g))
121 real :: hv(szi_(g), szj_(g))
122 real :: KH_u_lay(szi_(g), szj_(g))
123 real :: KH_v_lay(szi_(g), szj_(g))
125 if (.not.
ASSOCIATED(cs))
call mom_error(fatal,
"MOM_thickness_diffuse:"// &
126 "Module must be initialized before it is used.")
128 if ((.not.cs%thickness_diffuse) .or. &
129 .not.( cs%Khth > 0.0 .or.
associated(varmix) .or.
associated(meke) ) )
return 131 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
132 h_neglect = gv%H_subroundoff
133 h_to_m = gv%H_to_m ; m_to_h = gv%m_to_H
135 if (
associated(meke))
then 136 if (
ASSOCIATED(meke%GM_src))
then 137 do j=js,je ;
do i=is,ie ; meke%GM_src(i,j) = 0. ;
enddo ;
enddo 141 use_varmix = .false. ; resoln_scaled = .false. ; use_stored_slopes = .false.
142 khth_use_ebt_struct = .false.
143 if (
Associated(varmix))
then 144 use_varmix = varmix%use_variable_mixing .and. (cs%KHTH_Slope_Cff > 0.)
145 resoln_scaled = varmix%Resoln_scaled_KhTh
146 use_stored_slopes = varmix%use_stored_slopes
147 khth_use_ebt_struct = varmix%khth_use_ebt_struct
148 if (
associated(varmix%cg1)) cg1 => varmix%cg1
154 do j=js,je ;
do i=is-1,ie
155 kh_u_cfl(i,j) = (0.25*cs%max_Khth_CFL) / &
156 (dt*(g%IdxCu(i,j)*g%IdxCu(i,j) + g%IdyCu(i,j)*g%IdyCu(i,j)))
159 do j=js-1,je ;
do i=is,ie
160 kh_v_cfl(i,j) = (0.25*cs%max_Khth_CFL) / &
161 (dt*(g%IdxCv(i,j)*g%IdxCv(i,j) + g%IdyCv(i,j)*g%IdyCv(i,j)))
164 call find_eta(h, tv, gv%g_Earth, g, gv, e, halo_size=1)
172 do j=js,je;
do i=is-1,ie
173 khth_loc_u(i,j) = cs%Khth
178 do j=js,je ;
do i=is-1,ie
179 khth_loc_u(i,j) = khth_loc_u(i,j) + cs%KHTH_Slope_Cff*varmix%L2u(i,j)*varmix%SN_u(i,j)
183 if (
associated(meke))
then ;
if (
associated(meke%Kh))
then 185 do j=js,je ;
do i=is-1,ie
186 khth_loc_u(i,j) = khth_loc_u(i,j) + meke%KhTh_fac*sqrt(meke%Kh(i,j)*meke%Kh(i+1,j))
190 if (resoln_scaled)
then 192 do j=js,je;
do i=is-1,ie
193 khth_loc_u(i,j) = khth_loc_u(i,j) * varmix%Res_fn_u(i,j)
197 if (cs%Khth_Max > 0)
then 199 do j=js,je;
do i=is-1,ie
200 khth_loc_u(i,j) = max(cs%Khth_min, min(khth_loc_u(i,j),cs%Khth_Max))
204 do j=js,je;
do i=is-1,ie
205 khth_loc_u(i,j) = max(cs%Khth_min, khth_loc_u(i,j))
209 do j=js,je;
do i=is-1,ie
210 kh_u(i,j,1) = min(kh_u_cfl(i,j), khth_loc_u(i,j))
213 if (khth_use_ebt_struct)
then 215 do k=2,nz+1 ;
do j=js,je ;
do i=is-1,ie
216 kh_u(i,j,k) = kh_u(i,j,1) * 0.5 * ( varmix%ebt_struct(i,j,k-1) + varmix%ebt_struct(i+1,j,k-1) )
217 enddo ;
enddo ;
enddo 220 do k=2,nz+1 ;
do j=js,je ;
do i=is-1,ie
221 kh_u(i,j,k) = kh_u(i,j,1)
222 enddo ;
enddo ;
enddo 226 do j=js-1,je ;
do i=is,ie
227 khth_loc(i,j) = cs%Khth
232 do j=js-1,je ;
do i=is,ie
233 khth_loc(i,j) = khth_loc(i,j) + cs%KHTH_Slope_Cff*varmix%L2v(i,j)*varmix%SN_v(i,j)
236 if (
associated(meke))
then ;
if (
associated(meke%Kh))
then 238 do j=js-1,je ;
do i=is,ie
239 khth_loc(i,j) = khth_loc(i,j) + meke%KhTh_fac*sqrt(meke%Kh(i,j)*meke%Kh(i,j+1))
243 if (resoln_scaled)
then 245 do j=js-1,je ;
do i=is,ie
246 khth_loc(i,j) = khth_loc(i,j) * varmix%Res_fn_v(i,j)
250 if (cs%Khth_Max > 0)
then 252 do j=js-1,je ;
do i=is,ie
253 khth_loc(i,j) = max(cs%Khth_min, min(khth_loc(i,j),cs%Khth_Max))
257 do j=js-1,je ;
do i=is,ie
258 khth_loc(i,j) = max(cs%Khth_min, khth_loc(i,j))
262 if (cs%max_Khth_CFL > 0.0)
then 264 do j=js-1,je ;
do i=is,ie
265 kh_v(i,j,1) = min(kh_v_cfl(i,j), khth_loc(i,j))
268 if (khth_use_ebt_struct)
then 270 do k=2,nz+1 ;
do j=js-1,je ;
do i=is,ie
271 kh_v(i,j,k) = kh_v(i,j,1) * 0.5 * ( varmix%ebt_struct(i,j,k-1) + varmix%ebt_struct(i,j+1,k-1) )
272 enddo ;
enddo ;
enddo 275 do k=2,nz+1 ;
do j=js-1,je ;
do i=is,ie
276 kh_v(i,j,k) = kh_v(i,j,1)
277 enddo ;
enddo ;
enddo 280 do k=1,nz+1 ;
do j=js,je ;
do i=is-1,ie ; int_slope_u(i,j,k) = 0.0 ;
enddo ;
enddo ;
enddo 282 do k=1,nz+1 ;
do j=js-1,je ;
do i=is,ie ; int_slope_v(i,j,k) = 0.0 ;
enddo ;
enddo ;
enddo 285 if (cs%detangle_interfaces)
then 286 call add_detangling_kh(h, e, kh_u, kh_v, kh_u_cfl, kh_v_cfl, tv, dt, g, gv, &
287 cs, int_slope_u, int_slope_v)
291 call uvchksum(
"Kh_[uv]", kh_u, kh_v, g%HI,haloshift=0)
292 call uvchksum(
"int_slope_[uv]", int_slope_u, int_slope_v, g%HI, haloshift=0)
293 call hchksum(h,
"thickness_diffuse_1 h", g%HI, haloshift=1, scale=gv%H_to_m)
294 call hchksum(e,
"thickness_diffuse_1 e", g%HI, haloshift=1)
295 if (use_stored_slopes)
then 296 call uvchksum(
"VarMix%slope_[xy]", varmix%slope_x, varmix%slope_y, &
299 if (
associated(tv%eqn_of_state))
then 300 call hchksum(tv%T,
"thickness_diffuse T", g%HI, haloshift=1)
301 call hchksum(tv%S,
"thickness_diffuse S", g%HI, haloshift=1)
306 if (use_stored_slopes)
then 307 call thickness_diffuse_full(h, e, kh_u, kh_v, tv, uhd, vhd, cg1, dt, g, gv, meke, cs, &
308 int_slope_u, int_slope_v, varmix%slope_x, varmix%slope_y)
310 call thickness_diffuse_full(h, e, kh_u, kh_v, tv, uhd, vhd, cg1, dt, g, gv, meke, cs, &
311 int_slope_u, int_slope_v)
314 if (
associated(meke) .AND.
ASSOCIATED(varmix))
then 315 if (
ASSOCIATED(meke%Rd_dx_h) .and.
ASSOCIATED(varmix%Rd_dx_h))
then 317 do j=js,je ;
do i=is,ie
318 meke%Rd_dx_h(i,j) = varmix%Rd_dx_h(i,j)
324 if (query_averaging_enabled(cs%diag))
then 325 if (cs%id_uhGM > 0)
call post_data(cs%id_uhGM, uhd, cs%diag)
326 if (cs%id_vhGM > 0)
call post_data(cs%id_vhGM, vhd, cs%diag)
327 if (cs%id_GMwork > 0)
call post_data(cs%id_GMwork, cs%GMwork, cs%diag)
328 if (cs%id_KH_u > 0)
call post_data(cs%id_KH_u, kh_u, cs%diag)
329 if (cs%id_KH_v > 0)
call post_data(cs%id_KH_v, kh_v, cs%diag)
330 if (cs%id_KH_u1 > 0)
call post_data(cs%id_KH_u1, kh_u(:,:,1), cs%diag)
331 if (cs%id_KH_v1 > 0)
call post_data(cs%id_KH_v1, kh_v(:,:,1), cs%diag)
338 if (cs%id_KH_t > 0 .or. cs%id_KH_t1 > 0)
then 342 do j=js,je ;
do i=is-1,ie
343 hu(i,j) = 2.0*h(i,j,k)*h(i+1,j,k)/(h(i,j,k)+h(i+1,j,k)+h_neglect)
344 if(hu(i,j) /= 0.0) hu(i,j) = 1.0
345 kh_u_lay(i,j) = 0.5*(kh_u(i,j,k)+kh_u(i,j,k+1))
347 do j=js-1,je ;
do i=is,ie
348 hv(i,j) = 2.0*h(i,j,k)*h(i,j+1,k)/(h(i,j,k)+h(i,j+1,k)+h_neglect)
349 if(hv(i,j) /= 0.0) hv(i,j) = 1.0
350 kh_v_lay(i,j) = 0.5*(kh_v(i,j,k)+kh_v(i,j,k+1))
353 do j=js,je ;
do i=is,ie
354 kh_t(i,j,k) = ((hu(i-1,j)*kh_u_lay(i-1,j)+hu(i,j)*kh_u_lay(i,j)) &
355 +(hv(i,j-1)*kh_v_lay(i,j-1)+hv(i,j)*kh_v_lay(i,j))) &
356 / (hu(i-1,j)+hu(i,j)+hv(i,j-1)+hv(i,j)+h_neglect)
359 if(cs%id_KH_t > 0)
call post_data(cs%id_KH_t, kh_t, cs%diag)
360 if(cs%id_KH_t1 > 0)
call post_data(cs%id_KH_t1, kh_t(:,:,1), cs%diag)
367 do j=js,je ;
do i=is-1,ie
368 uhtr(i,j,k) = uhtr(i,j,k) + uhd(i,j,k)*dt
369 if (
ASSOCIATED(cdp%uhGM)) cdp%uhGM(i,j,k) = uhd(i,j,k)
371 do j=js-1,je ;
do i=is,ie
372 vhtr(i,j,k) = vhtr(i,j,k) + vhd(i,j,k)*dt
373 if (
ASSOCIATED(cdp%vhGM)) cdp%vhGM(i,j,k) = vhd(i,j,k)
375 do j=js,je ;
do i=is,ie
376 h(i,j,k) = h(i,j,k) - dt * g%IareaT(i,j) * &
377 ((uhd(i,j,k) - uhd(i-1,j,k)) + (vhd(i,j,k) - vhd(i,j-1,k)))
378 if (h(i,j,k) < gv%Angstrom) h(i,j,k) = gv%Angstrom
388 call uvchksum(
"thickness_diffuse [uv]hD", uhd, vhd, &
389 g%HI, haloshift=0, scale=gv%H_to_m)
390 call uvchksum(
"thickness_diffuse [uv]htr", uhtr, vhtr, &
391 g%HI, haloshift=0, scale=gv%H_to_m)
392 call hchksum(h,
"thickness_diffuse h", g%HI, haloshift=0, scale=gv%H_to_m)
400 subroutine thickness_diffuse_full(h, e, Kh_u, Kh_v, tv, uhD, vhD, cg1, dt, G, GV, MEKE, &
401 CS, int_slope_u, int_slope_v, slope_x, slope_y)
404 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
405 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: e
406 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: Kh_u
407 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)+1),
intent(in) :: Kh_v
409 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out) :: uhD
410 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out) :: vhD
411 real,
dimension(:,:),
pointer :: cg1
412 real,
intent(in) :: dt
415 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)+1),
optional,
intent(in) :: int_slope_u
418 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)+1),
optional,
intent(in) :: int_slope_v
421 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)+1),
optional,
intent(in) :: slope_x
422 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)+1),
optional,
intent(in) :: slope_y
424 real,
dimension(SZI_(G), SZJ_(G), SZK_(G)) :: &
435 real,
dimension(SZI_(G), SZJ_(G), SZK_(G)+1) :: &
438 real,
dimension(SZIB_(G)) :: &
441 real,
dimension(SZI_(G)) :: &
444 real :: uhtot(szib_(g), szj_(g))
445 real :: vhtot(szi_(g), szjb_(g))
446 real,
dimension(SZIB_(G)) :: &
449 real,
dimension(SZI_(G)) :: &
452 real :: Work_u(szib_(g), szj_(g))
453 real :: Work_v(szi_(g), szjb_(g))
461 real :: drdi_u(szib_(g), szk_(g)+1)
462 real :: drdj_v(szi_(g), szk_(g)+1)
463 real :: drdkDe_u(szib_(g), szk_(g)+1)
464 real :: drdkDe_v(szi_(g), szk_(g)+1)
465 real :: hg2A, hg2B, hg2L, hg2R
466 real :: haA, haB, haL, haR
468 real :: wtA, wtB, wtL, wtR
469 real :: drdx, drdy, drdz
472 real :: c2_h_u(szib_(g), szk_(g)+1)
473 real :: c2_h_v(szi_(g), szk_(g)+1)
474 real :: hN2_u(szib_(g), szk_(g)+1)
475 real :: hN2_v(szi_(g), szk_(g)+1)
478 real :: Sfn_unlim_u(szib_(g), szk_(g)+1)
479 real :: Sfn_unlim_v(szi_(g), szk_(g)+1)
480 real :: slope2_Ratio_u(szib_(g), szk_(g)+1)
481 real :: slope2_Ratio_v(szi_(g), szk_(g)+1)
502 real :: H_to_m, m_to_H
505 real,
dimension(SZIB_(G), SZJ_(G), SZK_(G)+1) :: diag_sfn_x, diag_sfn_unlim_x
506 real,
dimension(SZI_(G), SZJB_(G), SZK_(G)+1) :: diag_sfn_y, diag_sfn_unlim_y
507 logical :: present_int_slope_u, present_int_slope_v
508 logical :: present_slope_x, present_slope_y, calc_derivatives
509 integer :: is, ie, js, je, nz, IsdB
511 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke ; isdb = g%IsdB
513 h_to_m = gv%H_to_m ; m_to_h = gv%m_to_H
515 i_slope_max2 = 1.0 / (cs%slope_max**2)
516 g_scale = gv%g_Earth * h_to_m
517 h_neglect = gv%H_subroundoff ; h_neglect2 = h_neglect**2
518 dz_neglect = gv%H_subroundoff*h_to_m
519 g_rho0 = gv%g_Earth / gv%Rho0
520 n2_floor = cs%N2_floor
522 use_eos =
associated(tv%eqn_of_state)
523 present_int_slope_u =
PRESENT(int_slope_u)
524 present_int_slope_v =
PRESENT(int_slope_v)
525 present_slope_x =
PRESENT(slope_x)
526 present_slope_y =
PRESENT(slope_y)
528 nk_linear = max(gv%nkml, 1)
531 if (
associated(meke)) find_work =
ASSOCIATED(meke%GM_src)
532 find_work = (
ASSOCIATED(cs%GMwork) .or. find_work)
535 call vert_fill_ts(h, tv%T, tv%S, cs%kappa_smooth, dt, t, s, g, gv, 1)
538 if (cs%use_FGNV_streamfn .and. .not.
associated(cg1))
call mom_error(fatal, &
539 "cg1 must be associated when using FGNV streamfunction.")
546 do j=js-1,je+1 ;
do i=is-1,ie+1
547 h_avail_rsum(i,j,1) = 0.0
550 h_avail(i,j,1) = max(i4dt*g%areaT(i,j)*(h(i,j,1)-gv%Angstrom),0.0)
551 h_avail_rsum(i,j,2) = h_avail(i,j,1)
553 pres(i,j,2) = pres(i,j,1) + gv%H_to_Pa*h(i,j,1)
557 do k=2,nz ;
do i=is-1,ie+1
558 h_avail(i,j,k) = max(i4dt*g%areaT(i,j)*(h(i,j,k)-gv%Angstrom),0.0)
559 h_avail_rsum(i,j,k+1) = h_avail_rsum(i,j,k) + h_avail(i,j,k)
560 h_frac(i,j,k) = 0.0 ;
if (h_avail(i,j,k) > 0.0) &
561 h_frac(i,j,k) = h_avail(i,j,k) / h_avail_rsum(i,j,k+1)
562 pres(i,j,k+1) = pres(i,j,k) + gv%H_to_Pa*h(i,j,k)
566 do j=js,je ;
do i=is-1,ie
567 uhtot(i,j) = 0.0 ; work_u(i,j) = 0.0
568 diag_sfn_x(i,j,1) = 0.0 ; diag_sfn_unlim_x(i,j,1) = 0.0
569 diag_sfn_x(i,j,nz+1) = 0.0 ; diag_sfn_unlim_x(i,j,nz+1) = 0.0
572 do j=js-1,je ;
do i=is,ie
573 vhtot(i,j) = 0.0 ; work_v(i,j) = 0.0
574 diag_sfn_y(i,j,1) = 0.0 ; diag_sfn_unlim_y(i,j,1) = 0.0
575 diag_sfn_y(i,j,nz+1) = 0.0 ; diag_sfn_unlim_y(i,j,nz+1) = 0.0
593 do i=is-1,ie ; hn2_u(i,1) = 0. ; hn2_u(i,nz+1) = 0. ;
enddo 595 if (find_work .and. .not.(use_eos))
then 596 drdia = 0.0 ; drdib = 0.0
598 drdkl = gv%Rlay(k)-gv%Rlay(k-1) ; drdkr = gv%Rlay(k)-gv%Rlay(k-1)
601 calc_derivatives = use_eos .and. (k >= nk_linear) .and. &
602 (find_work .or. .not. present_slope_x .or. cs%use_FGNV_streamfn)
605 if (calc_derivatives)
then 607 pres_u(i) = 0.5*(pres(i,j,k) + pres(i+1,j,k))
608 t_u(i) = 0.25*((t(i,j,k) + t(i+1,j,k)) + (t(i,j,k-1) + t(i+1,j,k-1)))
609 s_u(i) = 0.25*((s(i,j,k) + s(i+1,j,k)) + (s(i,j,k-1) + s(i+1,j,k-1)))
612 drho_ds_u, (is-isdb+1)-1, ie-is+2, tv%eqn_of_state)
616 if (calc_derivatives)
then 618 drdia = drho_dt_u(i) * (t(i+1,j,k-1)-t(i,j,k-1)) + &
619 drho_ds_u(i) * (s(i+1,j,k-1)-s(i,j,k-1))
620 drdib = drho_dt_u(i) * (t(i+1,j,k)-t(i,j,k)) + &
621 drho_ds_u(i) * (s(i+1,j,k)-s(i,j,k))
624 drdkl = (drho_dt_u(i) * (t(i,j,k)-t(i,j,k-1)) + &
625 drho_ds_u(i) * (s(i,j,k)-s(i,j,k-1)))
626 drdkr = (drho_dt_u(i) * (t(i+1,j,k)-t(i+1,j,k-1)) + &
627 drho_ds_u(i) * (s(i+1,j,k)-s(i+1,j,k-1)))
628 drdkde_u(i,k) = drdkr * e(i+1,j,k) - drdkl * e(i,j,k)
631 if (find_work) drdi_u(i,k) = drdib
633 if (k > nk_linear)
then 635 if (cs%use_FGNV_streamfn .or. .not.present_slope_x)
then 636 hg2l = h(i,j,k-1)*h(i,j,k) + h_neglect2
637 hg2r = h(i+1,j,k-1)*h(i+1,j,k) + h_neglect2
638 hal = 0.5*(h(i,j,k-1) + h(i,j,k)) + h_neglect
639 har = 0.5*(h(i+1,j,k-1) + h(i+1,j,k)) + h_neglect
640 if (gv%Boussinesq)
then 641 dzal = hal * h_to_m ; dzar = har * h_to_m
643 dzal = 0.5*(e(i,j,k-1) - e(i,j,k+1)) + dz_neglect
644 dzar = 0.5*(e(i+1,j,k-1) - e(i+1,j,k+1)) + dz_neglect
648 wtl = hg2l*(har*dzar) ; wtr = hg2r*(hal*dzal)
650 drdz = (wtl * drdkl + wtr * drdkr) / (dzal*wtl + dzar*wtr)
654 hg2a = h(i,j,k-1)*h(i+1,j,k-1) + h_neglect2
655 hg2b = h(i,j,k)*h(i+1,j,k) + h_neglect2
656 haa = 0.5*(h(i,j,k-1) + h(i+1,j,k-1)) + h_neglect
657 hab = 0.5*(h(i,j,k) + h(i+1,j,k)) + h_neglect
660 hn2_u(i,k) = 0.5*( hg2a / haa + hg2b / hab ) * max(drdz*g_rho0 , n2_floor)
662 if (present_slope_x)
then 663 slope = slope_x(i,j,k)
664 slope2_ratio_u(i,k) = slope**2 * i_slope_max2
668 wta = hg2a*hab ; wtb = hg2b*haa
670 drdx = ((wta * drdia + wtb * drdib) / (wta + wtb) - &
671 drdz * (e(i,j,k)-e(i+1,j,k))) * g%IdxCu(i,j)
675 mag_grad2 = drdx**2 + drdz**2
676 if (mag_grad2 > 0.0)
then 677 slope = drdx / sqrt(mag_grad2)
678 slope2_ratio_u(i,k) = slope**2 * i_slope_max2
681 slope2_ratio_u(i,k) = 1.0e20
687 if (present_int_slope_u)
then 688 slope = (1.0 - int_slope_u(i,j,k)) * slope + &
689 int_slope_u(i,j,k) * ((e(i+1,j,k)-e(i,j,k)) * g%IdxCu(i,j))
690 slope2_ratio_u(i,k) = (1.0 - int_slope_u(i,j,k)) * slope2_ratio_u(i,k)
692 if (cs%id_slope_x > 0) cs%diagSlopeX(i,j,k) = slope
695 sfn_unlim_u(i,k) = -((kh_u(i,j,k)*g%dy_Cu(i,j))*slope) * m_to_h
699 if (sfn_unlim_u(i,k) > 0.0)
then 700 if (e(i,j,k) < e(i+1,j,nz+1))
then 701 sfn_unlim_u(i,k) = 0.0
703 elseif (e(i+1,j,nz+1) > e(i,j,k+1))
then 706 sfn_unlim_u(i,k) = sfn_unlim_u(i,k) * ((e(i,j,k) - e(i+1,j,nz+1)) / &
707 ((e(i,j,k) - e(i,j,k+1)) + dz_neglect))
710 if (e(i+1,j,k) < e(i,j,nz+1))
then ; sfn_unlim_u(i,k) = 0.0
711 elseif (e(i,j,nz+1) > e(i+1,j,k+1))
then 712 sfn_unlim_u(i,k) = sfn_unlim_u(i,k) * ((e(i+1,j,k) - e(i,j,nz+1)) / &
713 ((e(i+1,j,k) - e(i+1,j,k+1)) + dz_neglect))
719 hn2_u(i,k) = n2_floor * h_neglect
720 sfn_unlim_u(i,k) = 0.
722 if (cs%id_sfn_unlim_x>0) diag_sfn_unlim_x(i,j,k) = sfn_unlim_u(i,k)
726 if (cs%use_FGNV_streamfn)
then 727 do k=1,nz ;
do i=is-1,ie ;
if (g%mask2dCu(i,j)>0.)
then 728 h_harm = gv%H_to_m * max( h_neglect, &
729 2. * h(i,j,k) * h(i+1,j,k) / ( ( h(i,j,k) + h(i+1,j,k) ) + h_neglect ) )
730 c2_h_u(i,k) = cs%FGNV_scale * ( 0.5*( cg1(i,j) + cg1(i+1,j) ) )**2 / h_harm
731 endif ;
enddo ;
enddo 735 if (g%mask2dCu(i,j)>0.)
then 736 sfn_unlim_u(i,:) = ( 1. + cs%FGNV_scale ) * sfn_unlim_u(i,:)
739 sfn_unlim_u(i,:) = 0.
746 if (k > nk_linear)
then 749 if (uhtot(i,j) <= 0.0)
then 751 sfn_safe = uhtot(i,j) * (1.0 - h_frac(i,j,k))
753 sfn_safe = uhtot(i,j) * (1.0 - h_frac(i+1,j,k))
757 sfn_est = (sfn_unlim_u(i,k) + slope2_ratio_u(i,k)*sfn_safe) / (1.0 + slope2_ratio_u(i,k))
759 if (present_slope_x)
then 760 slope = slope_x(i,j,k)
762 slope = ((e(i,j,k)-e(i+1,j,k))*g%IdxCu(i,j)) * m_to_h
764 sfn_est = (kh_u(i,j,k)*g%dy_Cu(i,j)) * slope
766 if (cs%id_slope_x > 0) cs%diagSlopeX(i,j,k) = slope
771 sfn = min(max(sfn_est, -h_avail_rsum(i,j,k)), h_avail_rsum(i+1,j,k))
775 uhd(i,j,k) = max(min((sfn - uhtot(i,j)), h_avail(i,j,k)), &
778 if (cs%id_sfn_x>0) diag_sfn_x(i,j,k) = diag_sfn_x(i,j,k+1) + uhd(i,j,k)
790 if (uhtot(i,j) <= 0.0)
then 791 uhd(i,j,k) = -uhtot(i,j) * h_frac(i,j,k)
793 uhd(i,j,k) = -uhtot(i,j) * h_frac(i+1,j,k)
796 if (cs%id_sfn_x>0) diag_sfn_x(i,j,k) = diag_sfn_x(i,j,k+1) + uhd(i,j,k)
804 uhtot(i,j) = uhtot(i,j) + uhd(i,j,k)
813 work_u(i,j) = work_u(i,j) + g_scale * &
814 ( uhtot(i,j) * drdkde_u(i,k) - &
815 (uhd(i,j,k) * drdi_u(i,k)) * 0.25 * &
816 ((e(i,j,k) + e(i,j,k+1)) + (e(i+1,j,k) + e(i+1,j,k+1))) )
839 if (find_work .and. .not.(use_eos))
then 840 drdja = 0.0 ; drdjb = 0.0
842 drdkl = gv%Rlay(k)-gv%Rlay(k-1) ; drdkr = gv%Rlay(k)-gv%Rlay(k-1)
845 calc_derivatives = use_eos .and. (k >= nk_linear) .and. &
846 (find_work .or. .not. present_slope_y)
848 if (calc_derivatives)
then 850 pres_v(i) = 0.5*(pres(i,j,k) + pres(i,j+1,k))
851 t_v(i) = 0.25*((t(i,j,k) + t(i,j+1,k)) + (t(i,j,k-1) + t(i,j+1,k-1)))
852 s_v(i) = 0.25*((s(i,j,k) + s(i,j+1,k)) + (s(i,j,k-1) + s(i,j+1,k-1)))
855 drho_ds_v, is, ie-is+1, tv%eqn_of_state)
858 if (calc_derivatives)
then 860 drdja = drho_dt_v(i) * (t(i,j+1,k-1)-t(i,j,k-1)) + &
861 drho_ds_v(i) * (s(i,j+1,k-1)-s(i,j,k-1))
862 drdjb = drho_dt_v(i) * (t(i,j+1,k)-t(i,j,k)) + &
863 drho_ds_v(i) * (s(i,j+1,k)-s(i,j,k))
866 drdkl = (drho_dt_v(i) * (t(i,j,k)-t(i,j,k-1)) + &
867 drho_ds_v(i) * (s(i,j,k)-s(i,j,k-1)))
868 drdkr = (drho_dt_v(i) * (t(i,j+1,k)-t(i,j+1,k-1)) + &
869 drho_ds_v(i) * (s(i,j+1,k)-s(i,j+1,k-1)))
870 drdkde_v(i,k) = drdkr * e(i,j+1,k) - drdkl * e(i,j,k)
873 if (find_work) drdj_v(i,k) = drdjb
875 if (k > nk_linear)
then 877 if (cs%use_FGNV_streamfn .or. .not.present_slope_y)
then 878 hg2l = h(i,j,k-1)*h(i,j,k) + h_neglect2
879 hg2r = h(i,j+1,k-1)*h(i,j+1,k) + h_neglect2
880 hal = 0.5*(h(i,j,k-1) + h(i,j,k)) + h_neglect
881 har = 0.5*(h(i,j+1,k-1) + h(i,j+1,k)) + h_neglect
882 if (gv%Boussinesq)
then 883 dzal = hal * h_to_m ; dzar = har * h_to_m
885 dzal = 0.5*(e(i,j,k-1) - e(i,j,k+1)) + dz_neglect
886 dzar = 0.5*(e(i,j+1,k-1) - e(i,j+1,k+1)) + dz_neglect
890 wtl = hg2l*(har*dzar) ; wtr = hg2r*(hal*dzal)
892 drdz = (wtl * drdkl + wtr * drdkr) / (dzal*wtl + dzar*wtr)
896 hg2a = h(i,j,k-1)*h(i,j+1,k-1) + h_neglect2
897 hg2b = h(i,j,k)*h(i,j+1,k) + h_neglect2
898 haa = 0.5*(h(i,j,k-1) + h(i,j+1,k-1)) + h_neglect
899 hab = 0.5*(h(i,j,k) + h(i,j+1,k)) + h_neglect
902 hn2_v(i,k) = 0.5*( hg2a / haa + hg2b / hab ) * max(drdz*g_rho0 , n2_floor)
904 if (present_slope_y)
then 905 slope = slope_y(i,j,k)
906 slope2_ratio_v(i,k) = slope**2 * i_slope_max2
910 wta = hg2a*hab ; wtb = hg2b*haa
912 drdy = ((wta * drdja + wtb * drdjb) / (wta + wtb) - &
913 drdz * (e(i,j,k)-e(i,j+1,k))) * g%IdyCv(i,j)
917 mag_grad2 = drdy**2 + drdz**2
918 if (mag_grad2 > 0.0)
then 919 slope = drdy / sqrt(mag_grad2)
920 slope2_ratio_v(i,k) = slope**2 * i_slope_max2
923 slope2_ratio_v(i,k) = 1.0e20
929 if (present_int_slope_v)
then 930 slope = (1.0 - int_slope_v(i,j,k)) * slope + &
931 int_slope_v(i,j,k) * ((e(i,j+1,k)-e(i,j,k)) * g%IdyCv(i,j))
932 slope2_ratio_v(i,k) = (1.0 - int_slope_v(i,j,k)) * slope2_ratio_v(i,k)
934 if (cs%id_slope_y > 0) cs%diagSlopeY(i,j,k) = slope
937 sfn_unlim_v(i,k) = -((kh_v(i,j,k)*g%dx_Cv(i,j))*slope) * m_to_h
941 if (sfn_unlim_v(i,k) > 0.0)
then 942 if (e(i,j,k) < e(i,j+1,nz+1))
then 943 sfn_unlim_v(i,k) = 0.0
945 elseif (e(i,j+1,nz+1) > e(i,j,k+1))
then 948 sfn_unlim_v(i,k) = sfn_unlim_v(i,k) * ((e(i,j,k) - e(i,j+1,nz+1)) / &
949 ((e(i,j,k) - e(i,j,k+1)) + dz_neglect))
952 if (e(i,j+1,k) < e(i,j,nz+1))
then ; sfn_unlim_v(i,k) = 0.0
953 elseif (e(i,j,nz+1) > e(i,j+1,k+1))
then 954 sfn_unlim_v(i,k) = sfn_unlim_v(i,k) * ((e(i,j+1,k) - e(i,j,nz+1)) / &
955 ((e(i,j+1,k) - e(i,j+1,k+1)) + dz_neglect))
961 hn2_v(i,k) = n2_floor * h_neglect
962 sfn_unlim_v(i,k) = 0.
964 if (cs%id_sfn_unlim_y>0) diag_sfn_unlim_y(i,j,k) = sfn_unlim_v(i,k)
968 if (cs%use_FGNV_streamfn)
then 969 do k=1,nz ;
do i=is,ie ;
if (g%mask2dCv(i,j)>0.)
then 970 h_harm = gv%H_to_m * max( h_neglect, &
971 2. * h(i,j,k) * h(i,j+1,k) / ( ( h(i,j,k) + h(i,j+1,k) ) + h_neglect ) )
972 c2_h_v(i,k) = cs%FGNV_scale * ( 0.5*( cg1(i,j) + cg1(i,j+1) ) )**2 / h_harm
973 endif ;
enddo ;
enddo 977 if (g%mask2dCv(i,j)>0.)
then 978 sfn_unlim_v(i,:) = ( 1. + cs%FGNV_scale ) * sfn_unlim_v(i,:)
981 sfn_unlim_v(i,:) = 0.
988 if (k > nk_linear)
then 991 if (vhtot(i,j) <= 0.0)
then 993 sfn_safe = vhtot(i,j) * (1.0 - h_frac(i,j,k))
995 sfn_safe = vhtot(i,j) * (1.0 - h_frac(i,j+1,k))
999 sfn_est = (sfn_unlim_v(i,k) + slope2_ratio_v(i,k)*sfn_safe) / (1.0 + slope2_ratio_v(i,k))
1001 if (present_slope_y)
then 1002 slope = slope_y(i,j,k)
1004 slope = ((e(i,j,k)-e(i,j+1,k))*g%IdyCv(i,j)) * m_to_h
1006 sfn_est = (kh_v(i,j,k)*g%dx_Cv(i,j)) * slope
1008 if (cs%id_slope_y > 0) cs%diagSlopeY(i,j,k) = slope
1013 sfn = min(max(sfn_est, -h_avail_rsum(i,j,k)), h_avail_rsum(i,j+1,k))
1017 vhd(i,j,k) = max(min((sfn - vhtot(i,j)), h_avail(i,j,k)), &
1020 if (cs%id_sfn_y>0) diag_sfn_y(i,j,k) = diag_sfn_y(i,j,k+1) + vhd(i,j,k)
1032 if (vhtot(i,j) <= 0.0)
then 1033 vhd(i,j,k) = -vhtot(i,j) * h_frac(i,j,k)
1035 vhd(i,j,k) = -vhtot(i,j) * h_frac(i,j+1,k)
1038 if (cs%id_sfn_y>0) diag_sfn_y(i,j,k) = diag_sfn_y(i,j,k+1) + vhd(i,j,k)
1046 vhtot(i,j) = vhtot(i,j) + vhd(i,j,k)
1055 work_v(i,j) = work_v(i,j) + g_scale * &
1056 ( vhtot(i,j) * drdkde_v(i,k) - &
1057 (vhd(i,j,k) * drdj_v(i,k)) * 0.25 * &
1058 ((e(i,j,k) + e(i,j,k+1)) + (e(i,j+1,k) + e(i,j+1,k+1))) )
1066 if (.not.find_work .or. .not.(use_eos))
then 1067 do j=js,je ;
do i=is-1,ie ; uhd(i,j,1) = -uhtot(i,j) ;
enddo ;
enddo 1068 do j=js-1,je ;
do i=is,ie ; vhd(i,j,1) = -vhtot(i,j) ;
enddo ;
enddo 1076 pres_u(i) = 0.5*(pres(i,j,1) + pres(i+1,j,1))
1077 t_u(i) = 0.5*(t(i,j,1) + t(i+1,j,1))
1078 s_u(i) = 0.5*(s(i,j,1) + s(i+1,j,1))
1081 drho_ds_u, (is-isdb+1)-1, ie-is+2, tv%eqn_of_state)
1084 uhd(i,j,1) = -uhtot(i,j)
1087 drdib = drho_dt_u(i) * (t(i+1,j,1)-t(i,j,1)) + &
1088 drho_ds_u(i) * (s(i+1,j,1)-s(i,j,1))
1090 work_u(i,j) = work_u(i,j) + g_scale * ( (uhd(i,j,1) * drdib) * 0.25 * &
1091 ((e(i,j,1) + e(i,j,2)) + (e(i+1,j,1) + e(i+1,j,2))) )
1099 pres_v(i) = 0.5*(pres(i,j,1) + pres(i,j+1,1))
1100 t_v(i) = 0.5*(t(i,j,1) + t(i,j+1,1))
1101 s_v(i) = 0.5*(s(i,j,1) + s(i,j+1,1))
1104 drho_ds_v, is, ie-is+1, tv%eqn_of_state)
1107 vhd(i,j,1) = -vhtot(i,j)
1110 drdjb = drho_dt_v(i) * (t(i,j+1,1)-t(i,j,1)) + &
1111 drho_ds_v(i) * (s(i,j+1,1)-s(i,j,1))
1113 work_v(i,j) = work_v(i,j) - g_scale * ( (vhd(i,j,1) * drdjb) * 0.25 * &
1114 ((e(i,j,1) + e(i,j,2)) + (e(i,j+1,1) + e(i,j+1,2))) )
1119 if (find_work)
then ;
do j=js,je ;
do i=is,ie
1121 work_h = 0.5 * g%IareaT(i,j) * &
1122 ((work_u(i-1,j) + work_u(i,j)) + (work_v(i,j-1) + work_v(i,j)))
1123 if (
ASSOCIATED(cs%GMwork)) cs%GMwork(i,j) = work_h
1124 if (
associated(meke))
then ;
if (
ASSOCIATED(meke%GM_src))
then 1125 meke%GM_src(i,j) = meke%GM_src(i,j) + work_h
1127 enddo ;
enddo ;
endif 1129 if (cs%id_slope_x > 0)
call post_data(cs%id_slope_x, cs%diagSlopeX, cs%diag)
1130 if (cs%id_slope_y > 0)
call post_data(cs%id_slope_y, cs%diagSlopeY, cs%diag)
1131 if (cs%id_sfn_x > 0)
call post_data(cs%id_sfn_x, diag_sfn_x, cs%diag)
1132 if (cs%id_sfn_y > 0)
call post_data(cs%id_sfn_y, diag_sfn_y, cs%diag)
1133 if (cs%id_sfn_unlim_x > 0)
call post_data(cs%id_sfn_unlim_x, diag_sfn_unlim_x, cs%diag)
1134 if (cs%id_sfn_unlim_y > 0)
call post_data(cs%id_sfn_unlim_y, diag_sfn_unlim_y, cs%diag)
1140 integer,
intent(in) :: nk
1141 real,
dimension(nk),
intent(in) :: c2_h
1142 real,
dimension(nk+1),
intent(in) :: hN2
1143 real,
dimension(nk+1),
intent(inout) :: sfn
1149 real :: b_denom, beta, d1, c1(nk)
1152 b_denom = hn2(2) + c2_h(1)
1153 beta = 1.0 / ( b_denom + c2_h(2) )
1155 sfn(2) = ( beta * hn2(2) )*sfn(2)
1157 c1(k-1) = beta * c2_h(k-1)
1158 b_denom = hn2(k) + d1*c2_h(k-1)
1159 beta = 1.0 / (b_denom + c2_h(k))
1161 sfn(k) = beta * (hn2(k)*sfn(k) + c2_h(k-1)*sfn(k-1))
1163 c1(nk) = beta * c2_h(nk)
1166 sfn(k) = sfn(k) + c1(k)*sfn(k+1)
1172 subroutine add_detangling_kh(h, e, Kh_u, Kh_v, KH_u_CFL, KH_v_CFL, tv, dt, G, GV, CS, &
1173 int_slope_u, int_slope_v)
1176 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1177 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: e
1178 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: Kh_u
1179 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)+1),
intent(inout) :: Kh_v
1180 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: Kh_u_CFL
1181 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: Kh_v_CFL
1183 real,
intent(in) :: dt
1185 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: int_slope_u
1188 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)+1),
intent(inout) :: int_slope_v
1192 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
1195 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)) :: &
1198 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)) :: &
1201 real,
dimension(SZI_(G),SZJ_(G)) :: &
1233 real :: denom, I_denom
1242 real,
dimension(SZIB_(G),SZK_(G)+1) :: &
1265 real,
dimension(SZIB_(G)) :: &
1267 logical,
dimension(SZIB_(G)) :: &
1269 integer :: i, j, k, n, ish, jsh, is, ie, js, je, nz, k_top
1270 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1272 k_top = gv%nk_rho_varies + 1
1273 h_neglect = gv%H_subroundoff
1278 if (cs%detangle_time > dt) kh_scale = 0.5 * dt / cs%detangle_time
1280 do j=js-1,je+1 ;
do i=is-1,ie+1
1281 de_top(i,j,k_top) = 0.0 ; de_bot(i,j) = 0.0
1283 do k=k_top+1,nz ;
do j=js-1,je+1 ;
do i=is-1,ie+1
1284 de_top(i,j,k) = de_top(i,j,k-1) + h(i,j,k-1)
1285 enddo ;
enddo ;
enddo 1287 do j=js,je ;
do i=is-1,ie
1288 kh_lay_u(i,j,nz) = 0.0 ; kh_lay_u(i,j,k_top) = 0.0
1290 do j=js-1,je ;
do i=is,ie
1291 kh_lay_v(i,j,nz) = 0.0 ; kh_lay_v(i,j,k_top) = 0.0
1294 do k=nz-1,k_top+1,-1
1296 do j=js-1,je+1 ;
do i=is-1,ie+1
1297 de_bot(i,j) = de_bot(i,j) + h(i,j,k+1)
1300 do j=js,je ;
do i=is-1,ie ;
if (g%mask2dCu(i,j) > 0.0)
then 1301 if (h(i,j,k) > h(i+1,j,k))
then 1303 h1 = max( h(i+1,j,k), h2 - min(de_bot(i+1,j), de_top(i+1,j,k)) )
1306 h1 = max( h(i,j,k), h2 - min(de_bot(i,j), de_top(i,j,k)) )
1308 jag_rat = (h2 - h1)**2 / (h2 + h1 + h_neglect)**2
1309 kh_lay_u(i,j,k) = (kh_scale * kh_u_cfl(i,j)) * jag_rat**2
1310 endif ;
enddo ;
enddo 1312 do j=js-1,je ;
do i=is,ie ;
if (g%mask2dCv(i,j) > 0.0)
then 1313 if (h(i,j,k) > h(i,j+1,k))
then 1315 h1 = max( h(i,j+1,k), h2 - min(de_bot(i,j+1), de_top(i,j+1,k)) )
1318 h1 = max( h(i,j,k), h2 - min(de_bot(i,j), de_top(i,j,k)) )
1320 jag_rat = (h2 - h1)**2 / (h2 + h1 + h_neglect)**2
1321 kh_lay_v(i,j,k) = (kh_scale * kh_v_cfl(i,j)) * jag_rat**2
1322 endif ;
enddo ;
enddo 1327 i_4t = kh_scale / (4.0*dt)
1330 if (n==1)
then ; jsh = js ; ish = is-1
1331 else ; jsh = js-1 ; ish = is ;
endif 1338 do_i(i) = (g%mask2dCu(i,j) > 0.0)
1339 kh_max_max(i) = kh_u_cfl(i,j)
1341 do k=1,nz+1 ;
do i=ish,ie
1342 kh_bg(i,k) = kh_u(i,j,k) ; kh(i,k) = kh_bg(i,k)
1343 kh_min_max_p(i,k) = kh_bg(i,k) ; kh_min_max_m(i,k) = kh_bg(i,k)
1344 kh_detangle(i,k) = 0.0
1348 do_i(i) = (g%mask2dCv(i,j) > 0.0) ; kh_max_max(i) = kh_v_cfl(i,j)
1350 do k=1,nz+1 ;
do i=ish,ie
1351 kh_bg(i,k) = kh_v(i,j,k) ; kh(i,k) = kh_bg(i,k)
1352 kh_min_max_p(i,k) = kh_bg(i,k) ; kh_min_max_m(i,k) = kh_bg(i,k)
1353 kh_detangle(i,k) = 0.0
1358 do k=k_top,nz ;
do i=ish,ie ;
if (do_i(i))
then 1361 denom = ((g%IareaT(i+1,j) + g%IareaT(i,j))*g%dy_Cu(i,j))
1365 dh = i_4t * ((e(i+1,j,k) - e(i+1,j,k+1)) - &
1366 (e(i,j,k) - e(i,j,k+1))) / denom
1370 sign = 1.0 ;
if (dh < 0) sign = -1.0
1371 sl_k = sign * (e(i+1,j,k)-e(i,j,k)) * g%IdxCu(i,j)
1372 sl_kp1 = sign * (e(i+1,j,k+1)-e(i,j,k+1)) * g%IdxCu(i,j)
1377 denom = (sl_k**2 + sl_kp1**2)
1378 wt1 = 0.5 ; wt2 = 0.5
1379 if (denom > 0.0)
then 1380 wt1 = sl_k**2 / denom ; wt2 = sl_kp1**2 / denom
1382 kh_detangle(i,k) = kh_detangle(i,k) + wt1*kh_lay_u(i,j,k)
1383 kh_detangle(i,k+1) = kh_detangle(i,k+1) + wt2*kh_lay_u(i,j,k)
1386 denom = ((g%IareaT(i,j+1) + g%IareaT(i,j))*g%dx_Cv(i,j))
1388 dh = i_4t * ((e(i,j+1,k) - e(i,j+1,k+1)) - &
1389 (e(i,j,k) - e(i,j,k+1))) / denom
1393 sign = 1.0 ;
if (dh < 0) sign = -1.0
1394 sl_k = sign * (e(i,j+1,k)-e(i,j,k)) * g%IdyCv(i,j)
1395 sl_kp1 = sign * (e(i,j+1,k+1)-e(i,j,k+1)) * g%IdyCv(i,j)
1400 denom = (sl_k**2 + sl_kp1**2)
1401 wt1 = 0.5 ; wt2 = 0.5
1402 if (denom > 0.0)
then 1403 wt1 = sl_k**2 / denom ; wt2 = sl_kp1**2 / denom
1405 kh_detangle(i,k) = kh_detangle(i,k) + wt1*kh_lay_v(i,j,k)
1406 kh_detangle(i,k+1) = kh_detangle(i,k+1) + wt2*kh_lay_v(i,j,k)
1409 if (adh == 0.0)
then 1410 kh_min_m(i,k+1) = 1.0 ; kh0_min_m(i,k+1) = 0.0
1411 kh_max_m(i,k+1) = 1.0 ; kh0_max_m(i,k+1) = 0.0
1412 kh_min_p(i,k) = 1.0 ; kh0_min_p(i,k) = 0.0
1413 kh_max_p(i,k) = 1.0 ; kh0_max_p(i,k) = 0.0
1414 elseif (adh > 0.0)
then 1415 if (sl_k <= sl_kp1)
then 1418 kh_min_m(i,k+1) = 1.0 ; kh0_min_m(i,k+1) = 0.0
1419 kh_max_m(i,k+1) = 1.0 ; kh0_max_m(i,k+1) = 0.0
1420 kh_min_p(i,k) = 1.0 ; kh0_min_p(i,k) = 0.0
1421 kh_max_p(i,k) = 1.0 ; kh0_max_p(i,k) = 0.0
1422 elseif (sl_k <= 0.0)
then 1423 i_sl = -1.0 / sl_kp1
1425 irsl = 1e9 ;
if (rsl > 1e-9) irsl = 1.0/rsl
1428 if (kh_max_max(i) > 0) &
1429 fn_r = min(sqrt(rsl), rsl + (adh * i_sl) / kh_max_max(i))
1431 kh_min_m(i,k+1) = fn_r ; kh0_min_m(i,k+1) = 0.0
1432 kh_max_m(i,k+1) = rsl ; kh0_max_m(i,k+1) = adh * i_sl
1433 kh_min_p(i,k) = irsl ; kh0_min_p(i,k) = -adh * (i_sl*irsl)
1434 kh_max_p(i,k) = 1.0/(fn_r + 1.0e-30) ; kh0_max_p(i,k) = 0.0
1435 elseif (sl_kp1 < 0.0)
then 1436 i_sl_k = 1e18 ;
if (sl_k > 1e-18) i_sl_k = 1.0 / sl_k
1437 i_sl_kp1 = 1e18 ;
if (-sl_kp1 > 1e-18) i_sl_kp1 = -1.0 / sl_kp1
1439 kh_min_m(i,k+1) = 0.0 ; kh0_min_m(i,k+1) = 0.0
1440 kh_max_m(i,k+1) = - sl_k*i_sl_kp1 ; kh0_max_m(i,k+1) = adh*i_sl_kp1
1441 kh_min_p(i,k) = 0.0 ; kh0_min_p(i,k) = 0.0
1442 kh_max_p(i,k) = sl_kp1*i_sl_k ; kh0_max_p(i,k) = adh*i_sl_k
1446 kh_max = adh / (sl_k - sl_kp1)
1447 kh_min_max_p(i,k) = max(kh_min_max_p(i,k), kh_max)
1448 kh_min_max_m(i,k+1) = max(kh_min_max_m(i,k+1), kh_max)
1452 irsl = 1e9 ;
if (rsl > 1e-9) irsl = 1.0/rsl
1456 if (kh_max_max(i) > 0) &
1457 fn_r = min(sqrt(rsl), rsl + (adh * i_sl) / kh_max_max(i))
1459 kh_min_m(i,k+1) = irsl ; kh0_min_m(i,k+1) = -adh * (i_sl*irsl)
1460 kh_max_m(i,k+1) = 1.0/(fn_r + 1.0e-30) ; kh0_max_m(i,k+1) = 0.0
1461 kh_min_p(i,k) = fn_r ; kh0_min_p(i,k) = 0.0
1462 kh_max_p(i,k) = rsl ; kh0_max_p(i,k) = adh * i_sl
1465 endif ;
enddo ;
enddo 1467 do k=k_top,nz+1,nz+1-k_top ;
do i=ish,ie ;
if (do_i(i))
then 1469 kh_min_m(i,k) = 0.0 ; kh0_min_m(i,k) = 0.0
1470 kh_max_m(i,k) = 0.0 ; kh0_max_m(i,k) = 0.0
1471 kh_min_p(i,k) = 0.0 ; kh0_min_p(i,k) = 0.0
1472 kh_max_p(i,k) = 0.0 ; kh0_max_p(i,k) = 0.0
1473 kh_min_max_p(i,k) = kh_bg(i,k)
1474 kh_min_max_m(i,k) = kh_bg(i,k)
1475 endif ;
enddo ;
enddo 1485 do k=k_top+1,nz ;
do i=ish,ie ;
if (do_i(i))
then 1486 kh(i,k) = max(kh_bg(i,k), kh_detangle(i,k), &
1487 min(kh_min_m(i,k)*kh(i,k-1) + kh0_min_m(i,k), kh(i,k-1)))
1489 if (kh0_max_m(i,k) > kh_bg(i,k)) kh(i,k) = min(kh(i,k), kh0_max_m(i,k))
1490 if (kh0_max_p(i,k) > kh_bg(i,k)) kh(i,k) = min(kh(i,k), kh0_max_p(i,k))
1491 endif ;
enddo ;
enddo 1493 do k=nz,k_top+1,-1 ;
do i=ish,ie ;
if (do_i(i))
then 1494 kh(i,k) = max(kh(i,k), min(kh_min_p(i,k)*kh(i,k+1) + kh0_min_p(i,k), kh(i,k+1)))
1496 kh_max = max(kh_min_max_p(i,k), kh_max_p(i,k)*kh(i,k+1) + kh0_max_p(i,k))
1497 kh(i,k) = min(kh(i,k), kh_max)
1498 endif ;
enddo ;
enddo 1503 do k=k_top+1,nz ;
do i=ish,ie ;
if (do_i(i))
then 1504 kh_max = max(kh_min_max_m(i,k), kh_max_m(i,k)*kh(i,k-1) + kh0_max_m(i,k))
1505 if (kh(i,k) > kh_max) kh(i,k) = kh_max
1506 endif ;
enddo ;
enddo 1560 do k=k_top+1,nz ;
do i=ish,ie
1561 if (kh(i,k) > kh_u(i,j,k))
then 1562 dkh = (kh(i,k) - kh_u(i,j,k))
1563 int_slope_u(i,j,k) = dkh / kh(i,k)
1564 kh_u(i,j,k) = kh(i,k)
1568 do k=k_top+1,nz ;
do i=ish,ie
1569 if (kh(i,k) > kh_v(i,j,k))
then 1570 dkh = kh(i,k) - kh_v(i,j,k)
1571 int_slope_v(i,j,k) = dkh / kh(i,k)
1572 kh_v(i,j,k) = kh(i,k)
1584 subroutine vert_fill_ts(h, T_in, S_in, kappa, dt, T_f, S_f, G, GV, halo_here)
1587 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1588 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: T_in
1589 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: S_in
1590 real,
intent(in) :: kappa
1591 real,
intent(in) :: dt
1592 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(out) :: T_f
1593 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(out) :: S_f
1594 integer,
optional,
intent(in) :: halo_here
1597 real :: ent(szi_(g),szk_(g)+1)
1599 real :: b1(szi_(g)), d1(szi_(g))
1600 real :: c1(szi_(g),szk_(g))
1612 integer :: i, j, k, is, ie, js, je, nz, halo
1614 halo=0 ;
if (
present(halo_here)) halo = max(halo_here,0)
1616 is = g%isc-halo ; ie = g%iec+halo ; js = g%jsc-halo ; je = g%jec+halo
1618 h_neglect = gv%H_subroundoff
1619 kap_dt_x2 = (2.0*kappa*dt)*gv%m_to_H**2
1620 h0 = 1.0e-16*sqrt(kappa*dt)*gv%m_to_H
1622 if (kap_dt_x2 <= 0.0)
then 1624 do k=1,nz ;
do j=js,je ;
do i=is,ie
1625 t_f(i,j,k) = t_in(i,j,k) ; s_f(i,j,k) = s_in(i,j,k)
1626 enddo ;
enddo ;
enddo 1632 ent(i,2) = kap_dt_x2 / ((h(i,j,1)+h(i,j,2)) + h0)
1633 h_tr = h(i,j,1) + h_neglect
1634 b1(i) = 1.0 / (h_tr + ent(i,2))
1635 d1(i) = b1(i) * h(i,j,1)
1636 t_f(i,j,1) = (b1(i)*h_tr)*t_in(i,j,1)
1637 s_f(i,j,1) = (b1(i)*h_tr)*s_in(i,j,1)
1639 do k=2,nz-1 ;
do i=is,ie
1640 ent(i,k+1) = kap_dt_x2 / ((h(i,j,k)+h(i,j,k+1)) + h0)
1641 h_tr = h(i,j,k) + h_neglect
1642 c1(i,k) = ent(i,k) * b1(i)
1643 b1(i) = 1.0 / ((h_tr + d1(i)*ent(i,k)) + ent(i,k+1))
1644 d1(i) = b1(i) * (h_tr + d1(i)*ent(i,k))
1645 t_f(i,j,k) = b1(i) * (h_tr*t_in(i,j,k) + ent(i,k)*t_f(i,j,k-1))
1646 s_f(i,j,k) = b1(i) * (h_tr*s_in(i,j,k) + ent(i,k)*s_f(i,j,k-1))
1649 c1(i,nz) = ent(i,nz) * b1(i)
1650 h_tr = h(i,j,nz) + h_neglect
1651 b1(i) = 1.0 / (h_tr + d1(i)*ent(i,nz))
1652 t_f(i,j,nz) = b1(i) * (h_tr*t_in(i,j,nz) + ent(i,nz)*t_f(i,j,nz-1))
1653 s_f(i,j,nz) = b1(i) * (h_tr*s_in(i,j,nz) + ent(i,nz)*s_f(i,j,nz-1))
1655 do k=nz-1,1,-1 ;
do i=is,ie
1656 t_f(i,j,k) = t_f(i,j,k) + c1(i,k+1)*t_f(i,j,k+1)
1657 s_f(i,j,k) = s_f(i,j,k) + c1(i,k+1)*s_f(i,j,k+1)
1666 type(time_type),
intent(in) :: Time
1670 type(
diag_ctrl),
target,
intent(inout) :: diag
1675 #include "version_variable.h" 1676 character(len=40) :: mdl =
"MOM_thickness_diffuse" 1677 character(len=48) :: flux_units
1678 real :: omega, strat_floor
1680 if (
associated(cs))
then 1682 "Thickness_diffuse_init called with an associated control structure.")
1684 else ;
allocate(cs) ;
endif 1690 call get_param(param_file, mdl,
"THICKNESSDIFFUSE", cs%thickness_diffuse, &
1691 "If true, interface heights are diffused with a \n"//&
1692 "coefficient of KHTH.", default=.false.)
1693 call get_param(param_file, mdl,
"KHTH", cs%Khth, &
1694 "The background horizontal thickness diffusivity.", &
1695 units =
"m2 s-1", default=0.0)
1696 call get_param(param_file, mdl,
"KHTH_SLOPE_CFF", cs%KHTH_Slope_Cff, &
1697 "The nondimensional coefficient in the Visbeck formula \n"//&
1698 "for the interface depth diffusivity", units=
"nondim", &
1700 call get_param(param_file, mdl,
"KHTH_MIN", cs%KHTH_Min, &
1701 "The minimum horizontal thickness diffusivity.", &
1702 units =
"m2 s-1", default=0.0)
1703 call get_param(param_file, mdl,
"KHTH_MAX", cs%KHTH_Max, &
1704 "The maximum horizontal thickness diffusivity.", &
1705 units =
"m2 s-1", default=0.0)
1706 call get_param(param_file, mdl,
"KHTH_MAX_CFL", cs%max_Khth_CFL, &
1707 "The maximum value of the local diffusive CFL ratio that \n"//&
1708 "is permitted for the thickness diffusivity. 1.0 is the \n"//&
1709 "marginally unstable value in a pure layered model, but \n"//&
1710 "much smaller numbers (e.g. 0.1) seem to work better for \n"//&
1711 "ALE-based models.", units =
"nondimensional", default=0.8)
1712 if (cs%max_Khth_CFL < 0.0) cs%max_Khth_CFL = 0.0
1713 call get_param(param_file, mdl,
"DETANGLE_INTERFACES", cs%detangle_interfaces, &
1714 "If defined add 3-d structured enhanced interface height \n"//&
1715 "diffusivities to horizonally smooth jagged layers.", &
1717 cs%detangle_time = 0.0
1718 if (cs%detangle_interfaces) &
1719 call get_param(param_file, mdl,
"DETANGLE_TIMESCALE", cs%detangle_time, &
1720 "A timescale over which maximally jagged grid-scale \n"//&
1721 "thickness variations are suppressed. This must be \n"//&
1722 "longer than DT, or 0 to use DT.", units =
"s", default=0.0)
1723 call get_param(param_file, mdl,
"KHTH_SLOPE_MAX", cs%slope_max, &
1724 "A slope beyond which the calculated isopycnal slope is \n"//&
1725 "not reliable and is scaled away.", units=
"nondim", default=0.01)
1726 call get_param(param_file, mdl,
"KD_SMOOTH", cs%kappa_smooth, &
1727 "A diapycnal diffusivity that is used to interpolate \n"//&
1728 "more sensible values of T & S into thin layers.", &
1730 call get_param(param_file, mdl,
"KHTH_USE_FGNV_STREAMFUNCTION", cs%use_FGNV_streamfn, &
1731 "If true, use the streamfunction formulation of\n"// &
1732 "Ferrari et al., 2010, which effectively emphasizes\n"//&
1733 "graver vertical modes by smoothing in the vertical.", &
1735 call get_param(param_file, mdl,
"FGNV_FILTER_SCALE", cs%FGNV_scale, &
1736 "A coefficient scaling the vertical smoothing term in the\n"//&
1737 "Ferrari et al., 2010, streamfunction formulation.", &
1738 default=1., do_not_log=.not.cs%use_FGNV_streamfn)
1739 call get_param(param_file, mdl,
"FGNV_C_MIN", cs%FGNV_c_min, &
1740 "A minium wave speed used in the Ferrari et al., 2010,\n"//&
1741 "streamfunction formulation.", &
1742 default=0., units=
"m s-1", do_not_log=.not.cs%use_FGNV_streamfn)
1743 call get_param(param_file, mdl,
"FGNV_STRAT_FLOOR", strat_floor, &
1744 "A floor for Brunt-Vasaila frequency in the Ferrari et al., 2010,\n"//&
1745 "streamfunction formulation, expressed as a fraction of planetary\n"//&
1746 "rotation, OMEGA. This should be tiny but non-zero to avoid degeneracy.", &
1747 default=1.e-15, units=
"nondim", do_not_log=.not.cs%use_FGNV_streamfn)
1748 call get_param(param_file, mdl,
"OMEGA",omega, &
1749 "The rotation rate of the earth.", units=
"s-1", &
1750 default=7.2921e-5, do_not_log=.not.cs%use_FGNV_streamfn)
1751 if (cs%use_FGNV_streamfn) cs%N2_floor = (strat_floor*omega)**2
1752 call get_param(param_file, mdl,
"DEBUG", cs%debug, &
1753 "If true, write out verbose debugging data.", default=.false.)
1756 if (gv%Boussinesq)
then ; flux_units =
"meter3 second-1" 1757 else ; flux_units =
"kilogram second-1" ;
endif 1759 cs%id_uhGM = register_diag_field(
'ocean_model',
'uhGM', diag%axesCuL, time, &
1760 'Time Mean Diffusive Zonal Thickness Flux', flux_units, &
1761 y_cell_method=
'sum', v_extensive=.true.)
1762 if (cs%id_uhGM > 0)
call safe_alloc_ptr(cdp%uhGM,g%IsdB,g%IedB,g%jsd,g%jed,g%ke)
1763 cs%id_vhGM = register_diag_field(
'ocean_model',
'vhGM', diag%axesCvL, time, &
1764 'Time Mean Diffusive Meridional Thickness Flux', flux_units, &
1765 x_cell_method=
'sum', v_extensive=.true.)
1766 if (cs%id_vhGM > 0)
call safe_alloc_ptr(cdp%vhGM,g%isd,g%ied,g%JsdB,g%JedB,g%ke)
1768 cs%id_GMwork = register_diag_field(
'ocean_model',
'GMwork', diag%axesT1, time, &
1769 'Integrated Tendency of Ocean Mesoscale Eddy KE from Parameterized Eddy Advection', &
1770 'Watt meter-2', cmor_field_name=
'tnkebto', &
1771 cmor_long_name=
'Integrated Tendency of Ocean Mesoscale Eddy KE from Parameterized Eddy Advection',&
1772 cmor_units=
'W m-2', &
1773 cmor_standard_name=
'tendency_of_ocean_eddy_kinetic_energy_content_due_to_parameterized_eddy_advection')
1774 if (cs%id_GMwork > 0)
call safe_alloc_ptr(cs%GMwork,g%isd,g%ied,g%jsd,g%jed)
1776 cs%id_KH_u = register_diag_field(
'ocean_model',
'KHTH_u', diag%axesCui, time, &
1777 'Parameterized mesoscale eddy advection diffusivity at U-point',
'meter second-2')
1778 cs%id_KH_v = register_diag_field(
'ocean_model',
'KHTH_v', diag%axesCvi, time, &
1779 'Parameterized mesoscale eddy advection diffusivity at V-point',
'meter second-2')
1780 cs%id_KH_t = register_diag_field(
'ocean_model',
'KHTH_t', diag%axesTL, time, &
1781 'Ocean Tracer Diffusivity due to Parameterized Mesoscale Advection',
'meter second-2',&
1782 cmor_field_name=
'diftrblo', &
1783 cmor_long_name=
'Ocean Tracer Diffusivity due to Parameterized Mesoscale Advection', &
1784 cmor_units=
'm2 s-1', &
1785 cmor_standard_name=
'ocean_tracer_diffusivity_due_to_parameterized_mesoscale_advection')
1787 cs%id_KH_u1 = register_diag_field(
'ocean_model',
'KHTH_u1', diag%axesCu1, time, &
1788 'Parameterized mesoscale eddy advection diffusivity at U-points (2-D)',
'meter second-2')
1789 cs%id_KH_v1 = register_diag_field(
'ocean_model',
'KHTH_v1', diag%axesCv1, time, &
1790 'Parameterized mesoscale eddy advection diffusivity at V-points (2-D)',
'meter second-2')
1791 cs%id_KH_t1 = register_diag_field(
'ocean_model',
'KHTH_t1', diag%axesT1, time,&
1792 'Parameterized mesoscale eddy advection diffusivity at T-points (2-D)',
'meter second-2')
1794 cs%id_slope_x = register_diag_field(
'ocean_model',
'neutral_slope_x', diag%axesCui, time, &
1795 'Zonal slope of neutral surface',
'nondim')
1796 if (cs%id_slope_x > 0)
call safe_alloc_ptr(cs%diagSlopeX,g%IsdB,g%IedB,g%jsd,g%jed,g%ke+1)
1797 cs%id_slope_y = register_diag_field(
'ocean_model',
'neutral_slope_y', diag%axesCvi, time, &
1798 'Meridional slope of neutral surface',
'nondim')
1799 if (cs%id_slope_y > 0)
call safe_alloc_ptr(cs%diagSlopeY,g%isd,g%ied,g%JsdB,g%JedB,g%ke+1)
1800 cs%id_sfn_x = register_diag_field(
'ocean_model',
'GM_sfn_x', diag%axesCui, time, &
1801 'Parameterized Zonal Overturning Streamfunction',
'meter3 second-1')
1802 cs%id_sfn_y = register_diag_field(
'ocean_model',
'GM_sfn_y', diag%axesCvi, time, &
1803 'Parameterized Meridional Overturning Streamfunction',
'meter3 second-1')
1804 cs%id_sfn_unlim_x = register_diag_field(
'ocean_model',
'GM_sfn_unlim_x', diag%axesCui, time, &
1805 'Parameterized Zonal Overturning Streamfunction before limiting/smoothing',
'meter3 second-1')
1806 cs%id_sfn_unlim_y = register_diag_field(
'ocean_model',
'GM_sfn_unlim_y', diag%axesCvi, time, &
1807 'Parameterized Meridional Overturning Streamfunction before limiting/smoothing',
'meter3 second-1')
1814 if(
associated(cs))
deallocate(cs)
subroutine, public thickness_diffuse_end(CS)
Deallocate the thickness diffusion control structure.
subroutine, public vert_fill_ts(h, T_in, S_in, kappa, dt, T_f, S_f, G, GV, halo_here)
Fills tracer values in massless layers with sensible values by diffusing vertically with a (small) co...
The module calculates interface heights, including free surface height.
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
Provides the ocean grid type.
Variable mixing coefficients.
Variable mixing coefficients.
subroutine, public calculate_density_derivs(T, S, pressure, drho_dT, drho_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate density derivatives for 1-D array inputs.
Thickness diffusion (or Gent McWilliams)
The cont_diag_ptrs structure contains pointers to arrays with transports, which can later be used for...
Provides subroutines for quantities specific to the equation of state.
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
Control structure for thickness diffusion.
subroutine, public thickness_diffuse(h, uhtr, vhtr, tv, dt, G, GV, MEKE, VarMix, CDp, CS)
Calculates thickness diffusion coefficients and applies thickness diffusion to layer thicknesses...
subroutine, public thickness_diffuse_init(Time, G, GV, param_file, diag, CDp, CS)
Initialize the thickness diffusion module/structure.
subroutine thickness_diffuse_full(h, e, Kh_u, Kh_v, tv, uhD, vhD, cg1, dt, G, GV, MEKE, CS, int_slope_u, int_slope_v, slope_x, slope_y)
Calculates parameterized layer transports for use in the continuity equation. Fluxes are limited to g...
subroutine, public mom_error(level, message, all_print)
subroutine add_detangling_kh(h, e, Kh_u, Kh_v, KH_u_CFL, KH_v_CFL, tv, dt, G, GV, CS, int_slope_u, int_slope_v)
Modifies thickness diffusivities to untangle layer structures.
subroutine streamfn_solver(nk, c2_h, hN2, sfn)
Tridiagonal solver for streamfunction at interfaces.