24 implicit none ;
private 26 #include <MOM_memory.h> 44 logical :: cfl_based_trunc
56 logical :: cflrampingisactivated = .false.
57 type(time_type) :: rampstarttime
59 real allocable_,
dimension(NIMEMB_PTR_,NJMEM_,NK_INTERFACE_) :: &
61 real allocable_,
dimension(NIMEMB_PTR_,NJMEM_,NKMEM_) :: &
63 real allocable_,
dimension(NIMEM_,NJMEMB_PTR_,NK_INTERFACE_) :: &
65 real allocable_,
dimension(NIMEM_,NJMEMB_PTR_,NKMEM_) :: &
70 real,
pointer,
dimension(:,:) :: &
71 a1_shelf_u => null(), &
76 logical :: bottomdraglaw
81 logical :: channel_drag
84 logical :: harmonic_visc
92 logical :: direct_stress
94 logical :: dynamic_viscous_ml
100 integer,
pointer :: ntrunc
105 character(len=200) :: u_trunc_file
106 character(len=200) :: v_trunc_file
114 integer :: id_du_dt_visc = -1, id_dv_dt_visc = -1, id_au_vv = -1, id_av_vv = -1
115 integer :: id_h_u = -1, id_h_v = -1, id_hml_u = -1 , id_hml_v = -1
116 integer :: id_ray_u = -1, id_ray_v = -1, id_taux_bot = -1, id_tauy_bot = -1
138 subroutine vertvisc(u, v, h, fluxes, visc, dt, OBC, ADp, CDp, G, GV, CS, &
142 real,
intent(inout), &
143 dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: u
144 real,
intent(inout), &
145 dimension(SZI_(G),SZJB_(G),SZK_(GV)) :: v
147 dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h
148 type(
forcing),
intent(in) :: fluxes
150 real,
intent(in) :: dt
157 real,
optional,
intent(out),
dimension(SZIB_(G),SZJ_(G)) :: taux_bot
159 real,
optional,
intent(out),
dimension(SZI_(G),SZJB_(G)) :: tauy_bot
168 real :: c1(szib_(g),szk_(g))
171 real :: Ray(szib_(g),szk_(g))
190 real :: zDS, hfr, h_a
191 real :: surface_stress(szib_(g))
195 logical :: do_i(szib_(g))
197 integer :: i, j, k, is, ie, Isq, Ieq, Jsq, Jeq, nz, n
198 is = g%isc ; ie = g%iec
199 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB ; nz = g%ke
201 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_vert_friction(visc): "// &
202 "Module must be initialized before it is used.")
204 if (cs%direct_stress)
then 205 hmix = cs%Hmix_stress*gv%m_to_H
208 dt_rho0 = dt/gv%H_to_kg_m2
209 dt_m_to_h = dt*gv%m_to_H
211 h_neglect = gv%H_subroundoff
214 do k=1,nz ;
do i=isq,ieq ; ray(i,k) = 0.0 ;
enddo ;
enddo 225 do i=isq,ieq ; do_i(i) = (g%mask2dCu(i,j) > 0) ;
enddo 227 if (
ASSOCIATED(adp%du_dt_visc))
then ;
do k=1,nz ;
do i=isq,ieq
228 adp%du_dt_visc(i,j,k) = u(i,j,k)
229 enddo ;
enddo ;
endif 234 if (cs%direct_stress)
then 235 do i=isq,ieq ;
if (do_i(i))
then 236 surface_stress(i) = 0.0
238 stress = dt_rho0 * fluxes%taux(i,j)
240 h_a = 0.5 * (h(i,j,k) + h(i+1,j,k)) + h_neglect
241 hfr = 1.0 ;
if ((zds+h_a) > hmix) hfr = (hmix - zds) / h_a
242 u(i,j,k) = u(i,j,k) + i_hmix * hfr * stress
243 zds = zds + h_a ;
if (zds >= hmix)
exit 247 surface_stress(i) = dt_rho0 * (g%mask2dCu(i,j)*fluxes%taux(i,j))
250 if (cs%Channel_drag)
then ;
do k=1,nz ;
do i=isq,ieq
251 ray(i,k) = visc%Ray_u(i,j,k)
252 enddo ;
enddo ;
endif 277 do i=isq,ieq ;
if (do_i(i))
then 278 b_denom_1 = cs%h_u(i,j,1) + dt_m_to_h * (ray(i,1) + cs%a_u(i,j,1))
279 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h*cs%a_u(i,j,2))
280 d1(i) = b_denom_1 * b1(i)
281 u(i,j,1) = b1(i) * (cs%h_u(i,j,1) * u(i,j,1) + surface_stress(i))
283 do k=2,nz ;
do i=isq,ieq ;
if (do_i(i))
then 284 c1(i,k) = dt_m_to_h * cs%a_u(i,j,k) * b1(i)
285 b_denom_1 = cs%h_u(i,j,k) + dt_m_to_h * (ray(i,k) + cs%a_u(i,j,k)*d1(i))
286 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h * cs%a_u(i,j,k+1))
287 d1(i) = b_denom_1 * b1(i)
288 u(i,j,k) = (cs%h_u(i,j,k) * u(i,j,k) + &
289 dt_m_to_h * cs%a_u(i,j,k) * u(i,j,k-1)) * b1(i)
290 endif ;
enddo ;
enddo 294 do k=nz-1,1,-1 ;
do i=isq,ieq ;
if (do_i(i))
then 295 u(i,j,k) = u(i,j,k) + c1(i,k+1) * u(i,j,k+1)
296 endif ;
enddo ;
enddo 298 if (
ASSOCIATED(adp%du_dt_visc))
then ;
do k=1,nz ;
do i=isq,ieq
299 adp%du_dt_visc(i,j,k) = (u(i,j,k) - adp%du_dt_visc(i,j,k))*idt
300 enddo ;
enddo ;
endif 302 if (
ASSOCIATED(visc%taux_shelf))
then ;
do i=isq,ieq
303 visc%taux_shelf(i,j) = -rho0*cs%a1_shelf_u(i,j)*u(i,j,1)
306 if (
PRESENT(taux_bot))
then 308 taux_bot(i,j) = rho0 * (u(i,j,nz)*cs%a_u(i,j,nz+1))
310 if (cs%Channel_drag)
then ;
do k=1,nz ;
do i=isq,ieq
311 taux_bot(i,j) = taux_bot(i,j) + rho0 * (ray(i,k)*u(i,j,k))
312 enddo ;
enddo ;
endif 324 do i=is,ie ; do_i(i) = (g%mask2dCv(i,j) > 0) ;
enddo 326 if (
ASSOCIATED(adp%dv_dt_visc))
then ;
do k=1,nz ;
do i=is,ie
327 adp%dv_dt_visc(i,j,k) = v(i,j,k)
328 enddo ;
enddo ;
endif 333 if (cs%direct_stress)
then 334 do i=is,ie ;
if (do_i(i))
then 335 surface_stress(i) = 0.0
337 stress = dt_rho0 * fluxes%tauy(i,j)
339 h_a = 0.5 * (h(i,j,k) + h(i,j+1,k))
340 hfr = 1.0 ;
if ((zds+h_a) > hmix) hfr = (hmix - zds) / h_a
341 v(i,j,k) = v(i,j,k) + i_hmix * hfr * stress
342 zds = zds + h_a ;
if (zds >= hmix)
exit 346 surface_stress(i) = dt_rho0 * (g%mask2dCv(i,j)*fluxes%tauy(i,j))
349 if (cs%Channel_drag)
then ;
do k=1,nz ;
do i=is,ie
350 ray(i,k) = visc%Ray_v(i,j,k)
351 enddo ;
enddo ;
endif 353 do i=is,ie ;
if (do_i(i))
then 354 b_denom_1 = cs%h_v(i,j,1) + dt_m_to_h * (ray(i,1) + cs%a_v(i,j,1))
355 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h*cs%a_v(i,j,2))
356 d1(i) = b_denom_1 * b1(i)
357 v(i,j,1) = b1(i) * (cs%h_v(i,j,1) * v(i,j,1) + surface_stress(i))
359 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 360 c1(i,k) = dt_m_to_h * cs%a_v(i,j,k) * b1(i)
361 b_denom_1 = cs%h_v(i,j,k) + dt_m_to_h * (ray(i,k) + cs%a_v(i,j,k)*d1(i))
362 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h * cs%a_v(i,j,k+1))
363 d1(i) = b_denom_1 * b1(i)
364 v(i,j,k) = (cs%h_v(i,j,k) * v(i,j,k) + dt_m_to_h * &
365 cs%a_v(i,j,k) * v(i,j,k-1)) * b1(i)
366 endif ;
enddo ;
enddo 367 do k=nz-1,1,-1 ;
do i=is,ie ;
if (do_i(i))
then 368 v(i,j,k) = v(i,j,k) + c1(i,k+1) * v(i,j,k+1)
369 endif ;
enddo ;
enddo 371 if (
ASSOCIATED(adp%dv_dt_visc))
then ;
do k=1,nz ;
do i=is,ie
372 adp%dv_dt_visc(i,j,k) = (v(i,j,k) - adp%dv_dt_visc(i,j,k))*idt
373 enddo ;
enddo ;
endif 375 if (
ASSOCIATED(visc%tauy_shelf))
then ;
do i=is,ie
376 visc%tauy_shelf(i,j) = -rho0*cs%a1_shelf_v(i,j)*v(i,j,1)
379 if (
present(tauy_bot))
then 381 tauy_bot(i,j) = rho0 * (v(i,j,nz)*cs%a_v(i,j,nz+1))
383 if (cs%Channel_drag)
then ;
do k=1,nz ;
do i=is,ie
384 tauy_bot(i,j) = tauy_bot(i,j) + rho0 * (ray(i,k)*v(i,j,k))
385 enddo ;
enddo ;
endif 389 call vertvisc_limit_vel(u, v, h, adp, cdp, fluxes, visc, dt, g, gv, cs)
392 if (
associated(obc))
then 393 do n=1,obc%number_of_segments
394 if (obc%segment(n)%specified)
then 395 if (obc%segment(n)%is_N_or_S)
then 396 j = obc%segment(n)%HI%JsdB
397 do k=1,nz ;
do i=obc%segment(n)%HI%isd,obc%segment(n)%HI%ied
398 v(i,j,k) = obc%segment(n)%normal_vel(i,j,k)
400 elseif (obc%segment(n)%is_E_or_W)
then 401 i = obc%segment(n)%HI%IsdB
402 do k=1,nz ;
do j=obc%segment(n)%HI%jsd,obc%segment(n)%HI%jed
403 u(i,j,k) = obc%segment(n)%normal_vel(i,j,k)
411 if (cs%id_du_dt_visc > 0) &
412 call post_data(cs%id_du_dt_visc, adp%du_dt_visc, cs%diag)
413 if (cs%id_dv_dt_visc > 0) &
414 call post_data(cs%id_dv_dt_visc, adp%dv_dt_visc, cs%diag)
415 if (
present(taux_bot) .and. (cs%id_taux_bot > 0)) &
416 call post_data(cs%id_taux_bot, taux_bot, cs%diag)
417 if (
present(tauy_bot) .and. (cs%id_tauy_bot > 0)) &
418 call post_data(cs%id_tauy_bot, tauy_bot, cs%diag)
432 real,
dimension(SZIB_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: visc_rem_u
435 real,
dimension(SZI_(G),SZJB_(G),SZK_(GV)),
intent(inout) :: visc_rem_v
436 real,
intent(in) :: dt
442 real :: c1(szib_(g),szk_(g))
445 real :: Ray(szib_(g),szk_(g))
450 logical :: do_i(szib_(g))
452 integer :: i, j, k, is, ie, Isq, Ieq, Jsq, Jeq, nz
453 is = g%isc ; ie = g%iec
454 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB ; nz = g%ke
456 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_vert_friction(visc): "// &
457 "Module must be initialized before it is used.")
459 dt_m_to_h = dt*gv%m_to_H
461 do k=1,nz ;
do i=isq,ieq ; ray(i,k) = 0.0 ;
enddo ;
enddo 468 do i=isq,ieq ; do_i(i) = (g%mask2dCu(i,j) > 0) ;
enddo 470 if (cs%Channel_drag)
then ;
do k=1,nz ;
do i=isq,ieq
471 ray(i,k) = visc%Ray_u(i,j,k)
472 enddo ;
enddo ;
endif 474 do i=isq,ieq ;
if (do_i(i))
then 475 b_denom_1 = cs%h_u(i,j,1) + dt_m_to_h * (ray(i,1) + cs%a_u(i,j,1))
476 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h*cs%a_u(i,j,2))
477 d1(i) = b_denom_1 * b1(i)
478 visc_rem_u(i,j,1) = b1(i) * cs%h_u(i,j,1)
480 do k=2,nz ;
do i=isq,ieq ;
if (do_i(i))
then 481 c1(i,k) = dt_m_to_h * cs%a_u(i,j,k)*b1(i)
482 b_denom_1 = cs%h_u(i,j,k) + dt_m_to_h * (ray(i,k) + cs%a_u(i,j,k)*d1(i))
483 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h * cs%a_u(i,j,k+1))
484 d1(i) = b_denom_1 * b1(i)
485 visc_rem_u(i,j,k) = (cs%h_u(i,j,k) + dt_m_to_h * cs%a_u(i,j,k) * visc_rem_u(i,j,k-1)) * b1(i)
486 endif ;
enddo ;
enddo 487 do k=nz-1,1,-1 ;
do i=isq,ieq ;
if (do_i(i))
then 488 visc_rem_u(i,j,k) = visc_rem_u(i,j,k) + c1(i,k+1)*visc_rem_u(i,j,k+1)
490 endif ;
enddo ;
enddo 499 do i=is,ie ; do_i(i) = (g%mask2dCv(i,j) > 0) ;
enddo 501 if (cs%Channel_drag)
then ;
do k=1,nz ;
do i=is,ie
502 ray(i,k) = visc%Ray_v(i,j,k)
503 enddo ;
enddo ;
endif 505 do i=is,ie ;
if (do_i(i))
then 506 b_denom_1 = cs%h_v(i,j,1) + dt_m_to_h * (ray(i,1) + cs%a_v(i,j,1))
507 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h*cs%a_v(i,j,2))
508 d1(i) = b_denom_1 * b1(i)
509 visc_rem_v(i,j,1) = b1(i) * cs%h_v(i,j,1)
511 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 512 c1(i,k) = dt_m_to_h * cs%a_v(i,j,k)*b1(i)
513 b_denom_1 = cs%h_v(i,j,k) + dt_m_to_h * (ray(i,k) + cs%a_v(i,j,k)*d1(i))
514 b1(i) = 1.0 / (b_denom_1 + dt_m_to_h * cs%a_v(i,j,k+1))
515 d1(i) = b_denom_1 * b1(i)
516 visc_rem_v(i,j,k) = (cs%h_v(i,j,k) + dt_m_to_h * cs%a_v(i,j,k) * visc_rem_v(i,j,k-1)) * b1(i)
517 endif ;
enddo ;
enddo 518 do k=nz-1,1,-1 ;
do i=is,ie ;
if (do_i(i))
then 519 visc_rem_v(i,j,k) = visc_rem_v(i,j,k) + c1(i,k+1)*visc_rem_v(i,j,k+1)
520 endif ;
enddo ;
enddo 524 call uvchksum(
"visc_rem_[uv]", visc_rem_u, visc_rem_v, g%HI,haloshift=0)
533 subroutine vertvisc_coef(u, v, h, fluxes, visc, dt, G, GV, CS, OBC)
537 dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: u
539 dimension(SZI_(G),SZJB_(G),SZK_(GV)) :: v
541 dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h
542 type(
forcing),
intent(in) :: fluxes
544 real,
intent(in) :: dt
554 real,
dimension(SZIB_(G),SZK_(G)) :: &
560 real,
dimension(SZIB_(G),SZK_(G)+1) :: &
567 real,
dimension(SZIB_(G)) :: &
582 real,
allocatable,
dimension(:,:) :: hML_u, hML_v
583 real :: zcol(szi_(g))
593 real :: H_to_m, m_to_H
598 logical,
dimension(SZIB_(G)) :: do_i, do_i_shelf
599 logical :: do_any_shelf
600 integer,
dimension(SZIB_(G)) :: &
603 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
604 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
605 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB ; nz = g%ke
607 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_vert_friction(coef): "// &
608 "Module must be initialized before it is used.")
610 h_neglect = gv%H_subroundoff
611 h_to_m = gv%H_to_m ; m_to_h = gv%m_to_H
612 i_hbbl(:) = 1.0 / (cs%Hbbl * gv%m_to_H + h_neglect)
613 i_valbl = 0.0 ;
if (cs%harm_BL_val > 0.0) i_valbl = 1.0 / cs%harm_BL_val
615 if (cs%debug .or. (cs%id_hML_u > 0))
then 616 allocate(hml_u(g%IsdB:g%IedB,g%jsd:g%jed)) ; hml_u(:,:) = 0.0
618 if (cs%debug .or. (cs%id_hML_v > 0))
then 619 allocate(hml_v(g%isd:g%ied,g%JsdB:g%JedB)) ; hml_v(:,:) = 0.0
622 if ((
associated(visc%taux_shelf) .or.
associated(fluxes%frac_shelf_u)) .and. &
623 .not.
associated(cs%a1_shelf_u))
then 624 allocate(cs%a1_shelf_u(g%IsdB:g%IedB,g%jsd:g%jed)) ; cs%a1_shelf_u(:,:)=0.0
626 if ((
associated(visc%tauy_shelf) .or.
associated(fluxes%frac_shelf_u)) .and. &
627 .not.
associated(cs%a1_shelf_v))
then 628 allocate(cs%a1_shelf_v(g%isd:g%ied,g%JsdB:g%JedB)) ; cs%a1_shelf_v(:,:)=0.0
638 do i=isq,ieq ; do_i(i) = (g%mask2dCu(i,j) > 0) ;
enddo 640 if (cs%bottomdraglaw)
then ;
do i=isq,ieq
641 kv_bbl(i) = visc%kv_bbl_u(i,j)
642 bbl_thick(i) = visc%bbl_thick_u(i,j) * m_to_h
643 if (do_i(i)) i_hbbl(i) = 1.0 / (bbl_thick(i) + h_neglect)
646 do k=1,nz ;
do i=isq,ieq ;
if (do_i(i))
then 647 h_harm(i,k) = 2.0*h(i,j,k)*h(i+1,j,k) / (h(i,j,k)+h(i+1,j,k)+h_neglect)
648 h_arith(i,k) = 0.5*(h(i+1,j,k)+h(i,j,k))
649 endif ;
enddo ;
enddo 651 dmin(i) = min(g%bathyT(i,j), g%bathyT(i+1,j)) * m_to_h
656 if (
associated(obc))
then ;
if (obc%number_of_segments > 0)
then 657 do i=isq,ieq ;
if (do_i(i) .and. (obc%segnum_u(i,j) /= obc_none))
then 658 if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_e)
then 659 do k=1,nz ; h_harm(i,k) = h(i,j,k) ; h_arith(i,k) = h(i,j,k) ;
enddo 660 dmin(i) = g%bathyT(i,j) * m_to_h
662 elseif (obc%segment(obc%segnum_u(i,j))%direction ==
obc_direction_w)
then 663 do k=1,nz ; h_harm(i,k) = h(i+1,j,k) ; h_arith(i,k) = h(i+1,j,k) ;
enddo 664 dmin(i) = g%bathyT(i+1,j) * m_to_h
675 if (cs%harmonic_visc)
then 676 do i=isq,ieq ; z_i(i,nz+1) = 0.0 ;
enddo 677 do k=nz,1,-1 ;
do i=isq,ieq ;
if (do_i(i))
then 678 hvel(i,k) = h_harm(i,k)
679 if (u(i,j,k) * (h(i+1,j,k)-h(i,j,k)) < 0)
then 680 z2 = z_i(i,k+1) ; botfn = 1.0 / (1.0 + 0.09*z2*z2*z2*z2*z2*z2)
681 hvel(i,k) = (1.0-botfn)*h_harm(i,k) + botfn*h_arith(i,k)
683 z_i(i,k) = z_i(i,k+1) + h_harm(i,k)*i_hbbl(i)
684 endif ;
enddo ;
enddo 686 do i=isq,ieq ; zh(i) = 0.0 ; z_i(i,nz+1) = 0.0 ;
enddo 687 do i=isq,ieq+1 ; zcol(i) = -g%bathyT(i,j) * m_to_h ;
enddo 689 do i=isq,ieq+1 ; zcol(i) = zcol(i) + h(i,j,k) ;
enddo 690 do i=isq,ieq ;
if (do_i(i))
then 691 zh(i) = zh(i) + h_harm(i,k)
693 z_clear = max(zcol(i),zcol(i+1)) + dmin(i)
694 if (zi_dir(i) < 0) z_clear = zcol(i) + dmin(i)
695 if (zi_dir(i) > 0) z_clear = zcol(i+1) + dmin(i)
697 z_i(i,k) = max(zh(i), z_clear) * i_hbbl(i)
699 hvel(i,k) = h_arith(i,k)
700 if (u(i,j,k) * (h(i+1,j,k)-h(i,j,k)) > 0)
then 701 if (zh(i) * i_hbbl(i) < cs%harm_BL_val)
then 702 hvel(i,k) = h_harm(i,k)
704 z2_wt = 1.0 ;
if (zh(i) * i_hbbl(i) < 2.0*cs%harm_BL_val) &
705 z2_wt = max(0.0, min(1.0, zh(i) * i_hbbl(i) * i_valbl - 1.0))
706 z2 = z2_wt * (max(zh(i), z_clear) * i_hbbl(i))
707 botfn = 1.0 / (1.0 + 0.09*z2*z2*z2*z2*z2*z2)
708 hvel(i,k) = (1.0-botfn)*h_arith(i,k) + botfn*h_harm(i,k)
717 dt, j, g, gv, cs, visc, fluxes, work_on_u=.true., obc=obc)
718 if (
allocated(hml_u))
then 719 do i=isq,ieq ;
if (do_i(i))
then ; hml_u(i,j) = h_ml(i) ;
endif ;
enddo 722 do_any_shelf = .false.
723 if (
associated(fluxes%frac_shelf_u))
then 725 cs%a1_shelf_u(i,j) = 0.0
726 do_i_shelf(i) = (do_i(i) .and. fluxes%frac_shelf_u(i,j) > 0.0)
727 if (do_i_shelf(i)) do_any_shelf = .true.
729 if (do_any_shelf)
then 730 if (cs%harmonic_visc)
then 732 kv_bbl, z_i, h_ml, dt, j, g, gv, cs, &
733 visc, fluxes, work_on_u=.true., obc=obc, shelf=.true.)
736 do i=isq,ieq ;
if (do_i_shelf(i))
then 737 zh(i) = 0.0 ; ztop_min(i) = min(zcol(i), zcol(i+1))
738 i_htbl(i) = 1.0 / (visc%tbl_thick_shelf_u(i,j)*m_to_h + h_neglect)
741 do i=isq,ieq+1 ; zcol(i) = zcol(i) - h(i,j,k) ;
enddo 742 do i=isq,ieq ;
if (do_i_shelf(i))
then 743 zh(i) = zh(i) + h_harm(i,k)
745 hvel_shelf(i,k) = hvel(i,k)
746 if (u(i,j,k) * (h(i+1,j,k)-h(i,j,k)) > 0)
then 747 if (zh(i) * i_htbl(i) < cs%harm_BL_val)
then 748 hvel_shelf(i,k) = min(hvel(i,k), h_harm(i,k))
750 z2_wt = 1.0 ;
if (zh(i) * i_htbl(i) < 2.0*cs%harm_BL_val) &
751 z2_wt = max(0.0, min(1.0, zh(i) * i_htbl(i) * i_valbl - 1.0))
752 z2 = z2_wt * (max(zh(i), ztop_min(i) - min(zcol(i),zcol(i+1))) * i_htbl(i))
753 topfn = 1.0 / (1.0 + 0.09*z2**6)
754 hvel_shelf(i,k) = min(hvel(i,k), (1.0-topfn)*h_arith(i,k) + topfn*h_harm(i,k))
760 bbl_thick, kv_bbl, z_i, h_ml, dt, j, g, gv, cs, &
761 visc, fluxes, work_on_u=.true., obc=obc, shelf=.true.)
763 do i=isq,ieq ;
if (do_i_shelf(i)) cs%a1_shelf_u(i,j) = a_shelf(i,1) ;
enddo 767 if (do_any_shelf)
then 768 do k=1,nz+1 ;
do i=isq,ieq ;
if (do_i_shelf(i))
then 769 cs%a_u(i,j,k) = fluxes%frac_shelf_u(i,j) * a_shelf(i,k) + &
770 (1.0-fluxes%frac_shelf_u(i,j)) * a(i,k)
774 elseif (do_i(i))
then 775 cs%a_u(i,j,k) = a(i,k)
776 endif ;
enddo ;
enddo 777 do k=1,nz ;
do i=isq,ieq ;
if (do_i_shelf(i))
then 779 cs%h_u(i,j,k) = fluxes%frac_shelf_u(i,j) * hvel_shelf(i,k) + &
780 (1.0-fluxes%frac_shelf_u(i,j)) * hvel(i,k)
781 elseif (do_i(i))
then 782 cs%h_u(i,j,k) = hvel(i,k)
783 endif ;
enddo ;
enddo 785 do k=1,nz+1 ;
do i=isq,ieq ;
if (do_i(i)) cs%a_u(i,j,k) = a(i,k) ;
enddo ;
enddo 786 do k=1,nz ;
do i=isq,ieq ;
if (do_i(i)) cs%h_u(i,j,k) = hvel(i,k) ;
enddo ;
enddo 800 do i=is,ie ; do_i(i) = (g%mask2dCv(i,j) > 0) ;
enddo 802 if (cs%bottomdraglaw)
then ;
do i=is,ie
803 kv_bbl(i) = visc%kv_bbl_v(i,j)
804 bbl_thick(i) = visc%bbl_thick_v(i,j) * m_to_h
805 if (do_i(i)) i_hbbl(i) = 1.0 / bbl_thick(i)
808 do k=1,nz ;
do i=is,ie ;
if (do_i(i))
then 809 h_harm(i,k) = 2.0*h(i,j,k)*h(i,j+1,k) / (h(i,j,k)+h(i,j+1,k)+h_neglect)
810 h_arith(i,k) = 0.5*(h(i,j+1,k)+h(i,j,k))
811 endif ;
enddo ;
enddo 813 dmin(i) = min(g%bathyT(i,j), g%bathyT(i,j+1)) * m_to_h
818 if (
associated(obc))
then ;
if (obc%number_of_segments > 0)
then 819 do i=is,ie ;
if (do_i(i) .and. (obc%segnum_v(i,j) /= obc_none))
then 821 do k=1,nz ; h_harm(i,k) = h(i,j,k) ; h_arith(i,k) = h(i,j,k) ;
enddo 822 dmin(i) = g%bathyT(i,j) * m_to_h
824 elseif (obc%segment(obc%segnum_v(i,j))%direction ==
obc_direction_s)
then 825 do k=1,nz ; h_harm(i,k) = h(i,j+1,k) ; h_arith(i,k) = h(i,j+1,k) ;
enddo 826 dmin(i) = g%bathyT(i,j+1) * m_to_h
837 if (cs%harmonic_visc)
then 838 do i=is,ie ; z_i(i,nz+1) = 0.0 ;
enddo 840 do k=nz,1,-1 ;
do i=is,ie ;
if (do_i(i))
then 841 hvel(i,k) = h_harm(i,k)
842 if (v(i,j,k) * (h(i,j+1,k)-h(i,j,k)) < 0)
then 843 z2 = z_i(i,k+1) ; botfn = 1.0 / (1.0 + 0.09*z2*z2*z2*z2*z2*z2)
844 hvel(i,k) = (1.0-botfn)*h_harm(i,k) + botfn*h_arith(i,k)
846 z_i(i,k) = z_i(i,k+1) + h_harm(i,k)*i_hbbl(i)
847 endif ;
enddo ;
enddo 850 zh(i) = 0.0 ; z_i(i,nz+1) = 0.0
851 zcol1(i) = -g%bathyT(i,j) * m_to_h
852 zcol2(i) = -g%bathyT(i,j+1) * m_to_h
854 do k=nz,1,-1 ;
do i=is,ie ;
if (do_i(i))
then 855 zh(i) = zh(i) + h_harm(i,k)
856 zcol1(i) = zcol1(i) + h(i,j,k) ; zcol2(i) = zcol2(i) + h(i,j+1,k)
858 z_clear = max(zcol1(i),zcol2(i)) + dmin(i)
859 if (zi_dir(i) < 0) z_clear = zcol1(i) + dmin(i)
860 if (zi_dir(i) > 0) z_clear = zcol2(i) + dmin(i)
862 z_i(i,k) = max(zh(i), z_clear) * i_hbbl(i)
864 hvel(i,k) = h_arith(i,k)
865 if (v(i,j,k) * (h(i,j+1,k)-h(i,j,k)) > 0)
then 866 if (zh(i) * i_hbbl(i) < cs%harm_BL_val)
then 867 hvel(i,k) = h_harm(i,k)
869 z2_wt = 1.0 ;
if (zh(i) * i_hbbl(i) < 2.0*cs%harm_BL_val) &
870 z2_wt = max(0.0, min(1.0, zh(i) * i_hbbl(i) * i_valbl - 1.0))
871 z2 = z2_wt * (max(zh(i), max(zcol1(i),zcol2(i)) + dmin(i)) * i_hbbl(i))
872 botfn = 1.0 / (1.0 + 0.09*z2*z2*z2*z2*z2*z2)
873 hvel(i,k) = (1.0-botfn)*h_arith(i,k) + botfn*h_harm(i,k)
877 endif ;
enddo ;
enddo 881 dt, j, g, gv, cs, visc, fluxes, work_on_u=.false., obc=obc)
882 if (
allocated(hml_v))
then 883 do i=is,ie ;
if (do_i(i))
then ; hml_v(i,j) = h_ml(i) ;
endif ;
enddo 885 do_any_shelf = .false.
886 if (
associated(fluxes%frac_shelf_v))
then 888 cs%a1_shelf_v(i,j) = 0.0
889 do_i_shelf(i) = (do_i(i) .and. fluxes%frac_shelf_v(i,j) > 0.0)
890 if (do_i_shelf(i)) do_any_shelf = .true.
892 if (do_any_shelf)
then 893 if (cs%harmonic_visc)
then 895 kv_bbl, z_i, h_ml, dt, j, g, gv, cs, visc, &
896 fluxes, work_on_u=.false., obc=obc, shelf=.true.)
899 do i=is,ie ;
if (do_i_shelf(i))
then 900 zh(i) = 0.0 ; ztop_min(i) = min(zcol1(i), zcol2(i))
901 i_htbl(i) = 1.0 / (visc%tbl_thick_shelf_v(i,j)*m_to_h + h_neglect)
904 do i=is,ie ;
if (do_i_shelf(i))
then 905 zcol1(i) = zcol1(i) - h(i,j,k) ; zcol2(i) = zcol2(i) - h(i,j+1,k)
906 zh(i) = zh(i) + h_harm(i,k)
908 hvel_shelf(i,k) = hvel(i,k)
909 if (v(i,j,k) * (h(i,j+1,k)-h(i,j,k)) > 0)
then 910 if (zh(i) * i_htbl(i) < cs%harm_BL_val)
then 911 hvel_shelf(i,k) = min(hvel(i,k), h_harm(i,k))
913 z2_wt = 1.0 ;
if (zh(i) * i_htbl(i) < 2.0*cs%harm_BL_val) &
914 z2_wt = max(0.0, min(1.0, zh(i) * i_htbl(i) * i_valbl - 1.0))
915 z2 = z2_wt * (max(zh(i), ztop_min(i) - min(zcol1(i),zcol2(i))) * i_htbl(i))
916 topfn = 1.0 / (1.0 + 0.09*z2**6)
917 hvel_shelf(i,k) = min(hvel(i,k), (1.0-topfn)*h_arith(i,k) + topfn*h_harm(i,k))
923 bbl_thick, kv_bbl, z_i, h_ml, dt, j, g, gv, cs, &
924 visc, fluxes, work_on_u=.false., obc=obc, shelf=.true.)
926 do i=is,ie ;
if (do_i_shelf(i)) cs%a1_shelf_v(i,j) = a_shelf(i,1) ;
enddo 930 if (do_any_shelf)
then 931 do k=1,nz+1 ;
do i=is,ie ;
if (do_i_shelf(i))
then 932 cs%a_v(i,j,k) = fluxes%frac_shelf_v(i,j) * a_shelf(i,k) + &
933 (1.0-fluxes%frac_shelf_v(i,j)) * a(i,k)
937 elseif (do_i(i))
then 938 cs%a_v(i,j,k) = a(i,k)
939 endif ;
enddo ;
enddo 940 do k=1,nz ;
do i=is,ie ;
if (do_i_shelf(i))
then 942 cs%h_v(i,j,k) = fluxes%frac_shelf_v(i,j) * hvel_shelf(i,k) + &
943 (1.0-fluxes%frac_shelf_v(i,j)) * hvel(i,k)
944 elseif (do_i(i))
then 945 cs%h_v(i,j,k) = hvel(i,k)
946 endif ;
enddo ;
enddo 948 do k=1,nz+1 ;
do i=is,ie ;
if (do_i(i)) cs%a_v(i,j,k) = a(i,k) ;
enddo ;
enddo 949 do k=1,nz ;
do i=is,ie ;
if (do_i(i)) cs%h_v(i,j,k) = hvel(i,k) ;
enddo ;
enddo 954 call uvchksum(
"vertvisc_coef h_[uv]", cs%h_u, &
955 cs%h_v, g%HI,haloshift=0, scale=gv%H_to_m)
956 call uvchksum(
"vertvisc_coef a_[uv]", cs%a_u, &
957 cs%a_v, g%HI, haloshift=0)
958 if (
allocated(hml_u) .and.
allocated(hml_v)) &
959 call uvchksum(
"vertvisc_coef hML_[uv]", hml_u, hml_v, &
960 g%HI, haloshift=0, scale=gv%H_to_m)
964 if (cs%id_au_vv > 0)
call post_data(cs%id_au_vv, cs%a_u, cs%diag)
965 if (cs%id_av_vv > 0)
call post_data(cs%id_av_vv, cs%a_v, cs%diag)
966 if (cs%id_h_u > 0)
call post_data(cs%id_h_u, cs%h_u, cs%diag)
967 if (cs%id_h_v > 0)
call post_data(cs%id_h_v, cs%h_v, cs%diag)
968 if (cs%id_hML_u > 0)
call post_data(cs%id_hML_u, hml_u, cs%diag)
969 if (cs%id_hML_v > 0)
call post_data(cs%id_hML_v, hml_v, cs%diag)
971 if (
allocated(hml_u))
deallocate(hml_u)
972 if (
allocated(hml_v))
deallocate(hml_v)
980 dt, j, G, GV, CS, visc, fluxes, work_on_u, OBC, shelf)
984 real,
dimension(SZIB_(G),SZK_(GV)+1),
intent(out) :: a
986 real,
dimension(SZIB_(G),SZK_(GV)),
intent(in) :: hvel
988 logical,
dimension(SZIB_(G)),
intent(in) :: do_i
990 real,
dimension(SZIB_(G),SZK_(GV)),
intent(in) :: h_harm
992 real,
dimension(SZIB_(G)),
intent(in) :: bbl_thick
994 real,
dimension(SZIB_(G)),
intent(in) :: kv_bbl
997 real,
dimension(SZIB_(G),SZK_(GV)+1),
intent(in) :: z_i
999 real,
dimension(SZIB_(G)),
intent(out) :: h_ml
1001 integer,
intent(in) :: j
1003 real,
intent(in) :: dt
1009 type(
forcing),
intent(in) :: fluxes
1011 logical,
intent(in) :: work_on_u
1016 logical,
optional,
intent(in) :: shelf
1020 real,
dimension(SZIB_(G)) :: &
1029 real,
dimension(SZIB_(G),SZK_(GV)) :: &
1043 real :: H_to_m, m_to_H
1046 logical :: do_shelf, do_OBCs
1047 integer :: i, k, is, ie, max_nk
1053 if (work_on_u)
then ; is = g%IscB ; ie = g%IecB
1054 else ; is = g%isc ; ie = g%iec ;
endif 1056 h_neglect = gv%H_subroundoff
1057 h_to_m = gv%H_to_m ; m_to_h = gv%m_to_H
1058 dz_neglect = gv%H_subroundoff*gv%H_to_m
1060 do_shelf = .false. ;
if (
present(shelf)) do_shelf = shelf
1062 if (
associated(obc))
then ; do_obcs = (obc%number_of_segments > 0) ;
endif 1067 do i=is,ie ; a(i,1) = 0.0 ;
enddo 1068 if ((gv%nkml>0) .or. do_shelf)
then ;
do k=2,nz ;
do i=is,ie
1069 if (do_i(i)) a(i,k) = 2.0*cs%Kv
1070 enddo ;
enddo ;
else 1071 i_hmix = 1.0 / (cs%Hmix * m_to_h + h_neglect)
1072 do i=is,ie ; z_t(i) = h_neglect*i_hmix ;
enddo 1073 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 1074 z_t(i) = z_t(i) + h_harm(i,k-1)*i_hmix
1075 a(i,k) = 2.0*cs%Kv + 2.0*cs%Kvml / ((z_t(i)*z_t(i)) * &
1076 (1.0 + 0.09*z_t(i)*z_t(i)*z_t(i)*z_t(i)*z_t(i)*z_t(i)))
1077 endif ;
enddo ;
enddo 1080 do i=is,ie ;
if (do_i(i))
then 1081 if (cs%bottomdraglaw)
then 1083 if (r < bbl_thick(i))
then 1084 a(i,nz+1) = 1.0*kv_bbl(i) / (1e-10*dt*kv_bbl(i) + r*h_to_m)
1086 a(i,nz+1) = 1.0*kv_bbl(i) / (1e-10*dt*kv_bbl(i) + bbl_thick(i)*h_to_m)
1089 a(i,nz+1) = 2.0*cs%Kvbbl / (hvel(i,nz)*h_to_m + 2.0e-10*dt*cs%Kvbbl)
1093 if (
associated(visc%Kv_turb))
then 1099 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 1100 kv_add(i,k) = (2.*0.5)*(visc%Kv_turb(i,j,k) + visc%Kv_turb(i+1,j,k))
1101 endif ;
enddo ;
enddo 1103 do i=is,ie ;
if (do_i(i) .and. (obc%segnum_u(i,j) /= obc_none))
then 1104 if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_e)
then 1105 do k=2,nz ; kv_add(i,k) = 2.*visc%Kv_turb(i,j,k) ;
enddo 1106 elseif (obc%segment(obc%segnum_u(i,j))%direction ==
obc_direction_w)
then 1107 do k=2,nz ; kv_add(i,k) = 2.*visc%Kv_turb(i+1,j,k) ;
enddo 1111 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 1112 a(i,k) = a(i,k) + kv_add(i,k)
1113 endif ;
enddo ;
enddo 1115 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 1116 kv_add(i,k) = (2.*0.5)*(visc%Kv_turb(i,j,k) + visc%Kv_turb(i,j+1,k))
1117 endif ;
enddo ;
enddo 1119 do i=is,ie ;
if (do_i(i) .and. (obc%segnum_v(i,j) /= obc_none))
then 1121 do k=2,nz ; kv_add(i,k) = 2.*visc%Kv_turb(i,j,k) ;
enddo 1122 elseif (obc%segment(obc%segnum_v(i,j))%direction ==
obc_direction_s)
then 1123 do k=2,nz ; kv_add(i,k) = 2.*visc%Kv_turb(i,j+1,k) ;
enddo 1127 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 1128 a(i,k) = a(i,k) + kv_add(i,k)
1129 endif ;
enddo ;
enddo 1133 do k=nz,2,-1 ;
do i=is,ie ;
if (do_i(i))
then 1137 botfn = 1.0 / (1.0 + 0.09*z2*z2*z2*z2*z2*z2)
1139 if (cs%bottomdraglaw)
then 1140 a(i,k) = a(i,k) + 2.0*(kv_bbl(i)-cs%Kv)*botfn
1141 r = (hvel(i,k)+hvel(i,k-1))
1142 if (r > 2.0*bbl_thick(i))
then 1143 h_shear = ((1.0 - botfn) * r + botfn*2.0*bbl_thick(i))
1148 a(i,k) = a(i,k) + 2.0*(cs%Kvbbl-cs%Kv)*botfn
1149 h_shear = hvel(i,k) + hvel(i,k-1) + h_neglect
1156 a(i,k) = a(i,k) / (h_shear*h_to_m + 1.0e-10*dt*a(i,k))
1157 endif ;
enddo ;
enddo 1161 do i=is,ie ;
if (do_i(i))
then 1163 kv_tbl(i) = visc%kv_tbl_shelf_u(i,j)
1164 tbl_thick(i) = visc%tbl_thick_shelf_u(i,j) * m_to_h
1166 kv_tbl(i) = visc%kv_tbl_shelf_v(i,j)
1167 tbl_thick(i) = visc%tbl_thick_shelf_v(i,j) * m_to_h
1172 if (0.5*hvel(i,1) > tbl_thick(i))
then 1173 a(i,1) = kv_tbl(i) / (tbl_thick(i) *h_to_m + (1.0e-10*dt)*kv_tbl(i))
1175 a(i,1) = kv_tbl(i) / (0.5*hvel(i,1)*h_to_m + (1.0e-10*dt)*kv_tbl(i))
1179 do k=2,nz ;
do i=is,ie ;
if (do_i(i))
then 1180 z_t(i) = z_t(i) + hvel(i,k-1) / tbl_thick(i)
1181 topfn = 1.0 / (1.0 + 0.09 * z_t(i)**6)
1183 r = (hvel(i,k)+hvel(i,k-1))
1184 if (r > 2.0*tbl_thick(i))
then 1185 h_shear = ((1.0 - topfn) * r + topfn*2.0*tbl_thick(i))
1192 a_top = 2.0 * topfn * kv_tbl(i)
1193 a(i,k) = a(i,k) + a_top / (h_shear*h_to_m + 1.0e-10*dt*a_top)
1194 endif ;
enddo ;
enddo 1195 elseif (cs%dynamic_viscous_ML .or. (gv%nkml>0))
then 1197 do i=is,ie ;
if (do_i(i))
then 1198 if (gv%nkml>0) nk_visc(i) =
real(gv%nkml+1)
1200 u_star(i) = 0.5*(fluxes%ustar(i,j) + fluxes%ustar(i+1,j))
1201 absf(i) = 0.5*(abs(g%CoriolisBu(i,j-1)) + abs(g%CoriolisBu(i,j)))
1202 if (cs%dynamic_viscous_ML) nk_visc(i) = visc%nkml_visc_u(i,j) + 1
1204 u_star(i) = 0.5*(fluxes%ustar(i,j) + fluxes%ustar(i,j+1))
1205 absf(i) = 0.5*(abs(g%CoriolisBu(i-1,j)) + abs(g%CoriolisBu(i,j)))
1206 if (cs%dynamic_viscous_ML) nk_visc(i) = visc%nkml_visc_v(i,j) + 1
1208 h_ml(i) = h_neglect ; z_t(i) = 0.0
1209 max_nk = max(max_nk,ceiling(nk_visc(i) - 1.0))
1212 if (do_obcs)
then ;
if (work_on_u)
then 1213 do i=is,ie ;
if (do_i(i) .and. (obc%segnum_u(i,j) /= obc_none))
then 1214 if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_e) &
1215 u_star(i) = fluxes%ustar(i,j)
1217 u_star(i) = fluxes%ustar(i+1,j)
1220 do i=is,ie ;
if (do_i(i) .and. (obc%segnum_v(i,j) /= obc_none))
then 1222 u_star(i) = fluxes%ustar(i,j)
1224 u_star(i) = fluxes%ustar(i,j+1)
1228 do k=1,max_nk ;
do i=is,ie ;
if (do_i(i))
then 1229 if (k+1 <= nk_visc(i))
then 1230 h_ml(i) = h_ml(i) + hvel(i,k)
1231 elseif (k < nk_visc(i))
then 1232 h_ml(i) = h_ml(i) + (nk_visc(i) - k) * hvel(i,k)
1234 endif ;
enddo ;
enddo 1236 do k=2,max_nk ;
do i=is,ie ;
if (do_i(i))
then ;
if (k < nk_visc(i))
then 1238 z_t(i) = z_t(i) + hvel(i,k-1)
1239 temp1 = (z_t(i)*h_ml(i) - z_t(i)*z_t(i)) * h_to_m
1243 visc_ml = u_star(i) * 0.41 * (temp1*u_star(i)) / &
1244 (absf(i)*temp1 + h_ml(i)*u_star(i))
1245 a_ml = 4.0*visc_ml / ((hvel(i,k)+hvel(i,k-1) + h_neglect) * h_to_m + &
1248 if (a_ml > a(i,k)) a(i,k) = a_ml
1249 endif ;
endif ;
enddo ;
enddo 1257 subroutine vertvisc_limit_vel(u, v, h, ADp, CDp, fluxes, visc, dt, G, GV, CS)
1260 real,
intent(inout), &
1261 dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: u
1262 real,
intent(inout), &
1263 dimension(SZI_(G),SZJB_(G),SZK_(GV)) :: v
1265 dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h
1268 type(
forcing),
intent(in) :: fluxes
1270 real,
intent(in) :: dt
1280 real :: vel_report(szib_(g),szjb_(g))
1281 real :: u_old(szib_(g),szj_(g),szk_(g))
1282 real :: v_old(szi_(g),szjb_(g),szk_(g))
1283 logical :: trunc_any, dowrite(szib_(g),szjb_(g))
1284 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
1285 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1286 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
1289 truncvel = 0.9*maxvel
1290 h_report = 6.0 * gv%Angstrom
1291 dt_rho0 = dt / gv%Rho0
1293 if (len_trim(cs%u_trunc_file) > 0)
then 1299 do i=isq,ieq ; dowrite(i,j) = .false. ;
enddo 1300 if (cs%CFL_based_trunc)
then 1301 do i=isq,ieq ; vel_report(i,j) = 3.0e8 ;
enddo 1302 do k=1,nz ;
do i=isq,ieq
1303 if (u(i,j,k) < 0.0)
then 1304 cfl = (-u(i,j,k) * dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
1306 cfl = (u(i,j,k) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
1308 if (cfl > cs%CFL_trunc) trunc_any = .true.
1309 if (cfl > cs%CFL_report)
then 1310 dowrite(i,j) = .true.
1311 vel_report(i,j) = min(vel_report(i,j), abs(u(i,j,k)))
1315 do i=isq,ieq; vel_report(i,j) = maxvel;
enddo 1316 do k=1,nz ;
do i=isq,ieq ;
if (abs(u(i,j,k)) > maxvel)
then 1317 dowrite(i,j) = .true. ; trunc_any = .true.
1318 endif ;
enddo ;
enddo 1321 do i=isq,ieq ;
if (dowrite(i,j))
then 1322 u_old(i,j,:) = u(i,j,:)
1325 if (trunc_any)
then ;
if (cs%CFL_based_trunc)
then 1326 do k=1,nz ;
do i=isq,ieq
1327 if ((u(i,j,k) * (dt * g%dy_Cu(i,j))) * g%IareaT(i+1,j) < -cs%CFL_trunc)
then 1328 u(i,j,k) = (-0.9*cs%CFL_trunc) * (g%areaT(i+1,j) / (dt * g%dy_Cu(i,j)))
1329 if (h(i,j,k) + h(i+1,j,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1330 elseif ((u(i,j,k) * (dt * g%dy_Cu(i,j))) * g%IareaT(i,j) > cs%CFL_trunc)
then 1331 u(i,j,k) = (0.9*cs%CFL_trunc) * (g%areaT(i,j) / (dt * g%dy_Cu(i,j)))
1332 if (h(i,j,k) + h(i+1,j,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1336 do k=1,nz ;
do i=isq,ieq ;
if (abs(u(i,j,k)) > maxvel)
then 1337 u(i,j,k) = sign(truncvel,u(i,j,k))
1338 if (h(i,j,k) + h(i+1,j,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1339 endif ;
enddo ;
enddo 1343 if (cs%CFL_based_trunc)
then 1345 do k=1,nz ;
do j=js,je ;
do i=isq,ieq
1346 if ((u(i,j,k) * (dt * g%dy_Cu(i,j))) * g%IareaT(i+1,j) < -cs%CFL_trunc)
then 1347 u(i,j,k) = (-0.9*cs%CFL_trunc) * (g%areaT(i+1,j) / (dt * g%dy_Cu(i,j)))
1348 if (h(i,j,k) + h(i+1,j,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1349 elseif ((u(i,j,k) * (dt * g%dy_Cu(i,j))) * g%IareaT(i,j) > cs%CFL_trunc)
then 1350 u(i,j,k) = (0.9*cs%CFL_trunc) * (g%areaT(i,j) / (dt * g%dy_Cu(i,j)))
1351 if (h(i,j,k) + h(i+1,j,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1353 enddo ;
enddo ;
enddo 1356 do k=1,nz ;
do j=js,je ;
do i=isq,ieq ;
if (abs(u(i,j,k)) > maxvel)
then 1357 u(i,j,k) = sign(truncvel,u(i,j,k))
1358 if (h(i,j,k) + h(i+1,j,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1359 endif ;
enddo ;
enddo ;
enddo 1363 if (len_trim(cs%u_trunc_file) > 0)
then 1364 do j=js,je;
do i=isq,ieq ;
if (dowrite(i,j))
then 1367 call write_u_accel(i, j, u_old, h, adp, cdp, dt, g, gv, cs%PointAccel_CSp, &
1368 vel_report(i,j), -vel_report(i,j), fluxes%taux(i,j)*dt_rho0, &
1369 a=cs%a_u(:,j,:), hv=cs%h_u(:,j,:))
1370 endif ; enddo;
enddo 1373 if (len_trim(cs%v_trunc_file) > 0)
then 1379 do i=is,ie ; dowrite(i,j) = .false. ;
enddo 1380 if (cs%CFL_based_trunc)
then 1381 do i=is,ie ; vel_report(i,j) = 3.0e8 ;
enddo 1382 do k=1,nz ;
do i=is,ie
1383 if (v(i,j,k) < 0.0)
then 1384 cfl = (-v(i,j,k) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1386 cfl = (v(i,j,k) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1388 if (cfl > cs%CFL_trunc) trunc_any = .true.
1389 if (cfl > cs%CFL_report)
then 1390 dowrite(i,j) = .true.
1391 vel_report(i,j) = min(vel_report(i,j), abs(v(i,j,k)))
1395 do i=is,ie ; vel_report(i,j) = maxvel ;
enddo 1396 do k=1,nz ;
do i=is,ie ;
if (abs(v(i,j,k)) > maxvel)
then 1397 dowrite(i,j) = .true. ; trunc_any = .true.
1398 endif ;
enddo ;
enddo 1401 do i=is,ie ;
if (dowrite(i,j))
then 1402 v_old(i,j,:) = v(i,j,:)
1405 if (trunc_any)
then ;
if (cs%CFL_based_trunc)
then 1406 do k=1,nz;
do i=is,ie
1407 if ((v(i,j,k) * (dt * g%dx_Cv(i,j))) * g%IareaT(i,j+1) < -cs%CFL_trunc)
then 1408 v(i,j,k) = (-0.9*cs%CFL_trunc) * (g%areaT(i,j+1) / (dt * g%dx_Cv(i,j)))
1409 if (h(i,j,k) + h(i,j+1,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1410 elseif ((v(i,j,k) * (dt * g%dx_Cv(i,j))) * g%IareaT(i,j) > cs%CFL_trunc)
then 1411 v(i,j,k) = (0.9*cs%CFL_trunc) * (g%areaT(i,j) / (dt * g%dx_Cv(i,j)))
1412 if (h(i,j,k) + h(i,j+1,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1416 do k=1,nz ;
do i=is,ie ;
if (abs(v(i,j,k)) > maxvel)
then 1417 v(i,j,k) = sign(truncvel,v(i,j,k))
1418 if (h(i,j,k) + h(i,j+1,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1419 endif ;
enddo ;
enddo 1423 if (cs%CFL_based_trunc)
then 1425 do k=1,nz ;
do j=jsq,jeq ;
do i=is,ie
1426 if ((v(i,j,k) * (dt * g%dx_Cv(i,j))) * g%IareaT(i,j+1) < -cs%CFL_trunc)
then 1427 v(i,j,k) = (-0.9*cs%CFL_trunc) * (g%areaT(i,j+1) / (dt * g%dx_Cv(i,j)))
1428 if (h(i,j,k) + h(i,j+1,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1429 elseif ((v(i,j,k) * (dt * g%dx_Cv(i,j))) * g%IareaT(i,j) > cs%CFL_trunc)
then 1430 v(i,j,k) = (0.9*cs%CFL_trunc) * (g%areaT(i,j) / (dt * g%dx_Cv(i,j)))
1431 if (h(i,j,k) + h(i,j+1,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1433 enddo ;
enddo ;
enddo 1436 do k=1,nz ;
do j=jsq,jeq ;
do i=is,ie ;
if (abs(v(i,j,k)) > maxvel)
then 1437 v(i,j,k) = sign(truncvel,v(i,j,k))
1438 if (h(i,j,k) + h(i,j+1,k) > h_report) cs%ntrunc = cs%ntrunc + 1
1439 endif ;
enddo ;
enddo ;
enddo 1443 if (len_trim(cs%v_trunc_file) > 0)
then 1444 do j=jsq,jeq;
do i=is,ie ;
if (dowrite(i,j))
then 1447 call write_v_accel(i, j, v_old, h, adp, cdp, dt, g, gv, cs%PointAccel_CSp, &
1448 vel_report(i,j), -vel_report(i,j), fluxes%tauy(i,j)*dt_rho0, &
1449 a=cs%a_v(:,j,:),hv=cs%h_v(:,j,:))
1450 endif ; enddo;
enddo 1456 subroutine vertvisc_init(MIS, Time, G, GV, param_file, diag, ADp, dirs, &
1461 type(time_type),
target,
intent(in) :: Time
1465 type(
diag_ctrl),
target,
intent(inout) :: diag
1468 integer,
target,
intent(inout) :: ntrunc
1473 real :: hmix_str_dflt
1474 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz
1476 #include "version_variable.h" 1477 character(len=40) :: mdl =
"MOM_vert_friction" 1478 character(len=40) :: thickness_units =
"meters or kg m-2" 1480 if (
associated(cs))
then 1481 call mom_error(warning,
"vertvisc_init called with an associated "// &
1482 "control structure.")
1487 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
1488 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1490 cs%diag => diag ; cs%ntrunc => ntrunc ; ntrunc = 0
1494 call get_param(param_file, mdl,
"BOTTOMDRAGLAW", cs%bottomdraglaw, &
1495 "If true, the bottom stress is calculated with a drag \n"//&
1496 "law of the form c_drag*|u|*u. The velocity magnitude \n"//&
1497 "may be an assumed value or it may be based on the \n"//&
1498 "actual velocity in the bottommost HBBL, depending on \n"//&
1499 "LINEAR_DRAG.", default=.true.)
1500 call get_param(param_file, mdl,
"CHANNEL_DRAG", cs%Channel_drag, &
1501 "If true, the bottom drag is exerted directly on each \n"//&
1502 "layer proportional to the fraction of the bottom it \n"//&
1503 "overlies.", default=.false.)
1504 call get_param(param_file, mdl,
"DIRECT_STRESS", cs%direct_stress, &
1505 "If true, the wind stress is distributed over the \n"//&
1506 "topmost HMIX_STRESS of fluid (like in HYCOM), and KVML \n"//&
1507 "may be set to a very small value.", default=.false.)
1508 call get_param(param_file, mdl,
"DYNAMIC_VISCOUS_ML", cs%dynamic_viscous_ML, &
1509 "If true, use a bulk Richardson number criterion to \n"//&
1510 "determine the mixed layer thickness for viscosity.", &
1512 call get_param(param_file, mdl,
"U_TRUNC_FILE", cs%u_trunc_file, &
1513 "The absolute path to a file into which the accelerations \n"//&
1514 "leading to zonal velocity truncations are written. \n"//&
1515 "Undefine this for efficiency if this diagnostic is not \n"//&
1516 "needed.", default=
" ")
1517 call get_param(param_file, mdl,
"V_TRUNC_FILE", cs%v_trunc_file, &
1518 "The absolute path to a file into which the accelerations \n"//&
1519 "leading to meridional velocity truncations are written. \n"//&
1520 "Undefine this for efficiency if this diagnostic is not \n"//&
1521 "needed.", default=
" ")
1522 call get_param(param_file, mdl,
"HARMONIC_VISC", cs%harmonic_visc, &
1523 "If true, use the harmonic mean thicknesses for \n"//&
1524 "calculating the vertical viscosity.", default=.false.)
1525 call get_param(param_file, mdl,
"HARMONIC_BL_SCALE", cs%harm_BL_val, &
1526 "A scale to determine when water is in the boundary \n"//&
1527 "layers based solely on harmonic mean thicknesses for \n"//&
1528 "the purpose of determining the extent to which the \n"//&
1529 "thicknesses used in the viscosities are upwinded.", &
1530 default=0.0, units=
"nondim")
1531 call get_param(param_file, mdl,
"DEBUG", cs%debug, default=.false.)
1534 call get_param(param_file, mdl,
"HMIX_FIXED", cs%Hmix, &
1535 "The prescribed depth over which the near-surface \n"//&
1536 "viscosity and diffusivity are elevated when the bulk \n"//&
1537 "mixed layer is not used.", units=
"m", fail_if_missing=.true.)
1538 if (cs%direct_stress)
then 1539 if (gv%nkml < 1)
then 1540 call get_param(param_file, mdl,
"HMIX_STRESS", cs%Hmix_stress, &
1541 "The depth over which the wind stress is applied if \n"//&
1542 "DIRECT_STRESS is true.", units=
"m", default=cs%Hmix)
1544 call get_param(param_file, mdl,
"HMIX_STRESS", cs%Hmix_stress, &
1545 "The depth over which the wind stress is applied if \n"//&
1546 "DIRECT_STRESS is true.", units=
"m", fail_if_missing=.true.)
1548 if (cs%Hmix_stress <= 0.0)
call mom_error(fatal,
"vertvisc_init: " // &
1549 "HMIX_STRESS must be set to a positive value if DIRECT_STRESS is true.")
1551 call get_param(param_file, mdl,
"KV", cs%Kv, &
1552 "The background kinematic viscosity in the interior. \n"//&
1553 "The molecular value, ~1e-6 m2 s-1, may be used.", &
1554 units=
"m2 s-1", fail_if_missing=.true.)
1557 if (gv%nkml < 1)
call get_param(param_file, mdl,
"KVML", cs%Kvml, &
1558 "The kinematic viscosity in the mixed layer. A typical \n"//&
1559 "value is ~1e-2 m2 s-1. KVML is not used if \n"//&
1560 "BULKMIXEDLAYER is true. The default is set by KV.", &
1561 units=
"m2 s-1", default=cs%Kv)
1562 if (.not.cs%bottomdraglaw)
call get_param(param_file, mdl,
"KVBBL", cs%Kvbbl, &
1563 "The kinematic viscosity in the benthic boundary layer. \n"//&
1564 "A typical value is ~1e-2 m2 s-1. KVBBL is not used if \n"//&
1565 "BOTTOMDRAGLAW is true. The default is set by KV.", &
1566 units=
"m2 s-1", default=cs%Kv)
1567 call get_param(param_file, mdl,
"HBBL", cs%Hbbl, &
1568 "The thickness of a bottom boundary layer with a \n"//&
1569 "viscosity of KVBBL if BOTTOMDRAGLAW is not defined, or \n"//&
1570 "the thickness over which near-bottom velocities are \n"//&
1571 "averaged for the drag law if BOTTOMDRAGLAW is defined \n"//&
1572 "but LINEAR_DRAG is not.", units=
"m", fail_if_missing=.true.)
1573 call get_param(param_file, mdl,
"MAXVEL", cs%maxvel, &
1574 "The maximum velocity allowed before the velocity \n"//&
1575 "components are truncated.", units=
"m s-1", default=3.0e8)
1576 call get_param(param_file, mdl,
"CFL_BASED_TRUNCATIONS", cs%CFL_based_trunc, &
1577 "If true, base truncations on the CFL number, and not an \n"//&
1578 "absolute speed.", default=.true.)
1579 call get_param(param_file, mdl,
"CFL_TRUNCATE", cs%CFL_trunc, &
1580 "The value of the CFL number that will cause velocity \n"//&
1581 "components to be truncated; instability can occur past 0.5.", &
1582 units=
"nondim", default=0.5)
1583 call get_param(param_file, mdl,
"CFL_REPORT", cs%CFL_report, &
1584 "The value of the CFL number that causes accelerations \n"//&
1585 "to be reported; the default is CFL_TRUNCATE.", &
1586 units=
"nondim", default=cs%CFL_trunc)
1587 call get_param(param_file, mdl,
"CFL_TRUNCATE_RAMP_TIME", cs%truncRampTime, &
1588 "The time over which the CFL trunction value is ramped\n"//&
1589 "up at the beginning of the run.", &
1590 units=
"s", default=0.)
1591 cs%CFL_truncE = cs%CFL_trunc
1592 call get_param(param_file, mdl,
"CFL_TRUNCATE_START", cs%CFL_truncS, &
1593 "The start value of the truncation CFL number used when\n"//&
1594 "ramping up CFL_TRUNC.", &
1595 units=
"nondim", default=0.)
1597 alloc_(cs%a_u(isdb:iedb,jsd:jed,nz+1)) ; cs%a_u(:,:,:) = 0.0
1598 alloc_(cs%h_u(isdb:iedb,jsd:jed,nz)) ; cs%h_u(:,:,:) = 0.0
1599 alloc_(cs%a_v(isd:ied,jsdb:jedb,nz+1)) ; cs%a_v(:,:,:) = 0.0
1600 alloc_(cs%h_v(isd:ied,jsdb:jedb,nz)) ; cs%h_v(:,:,:) = 0.0
1602 cs%id_au_vv = register_diag_field(
'ocean_model',
'au_visc', diag%axesCui, time, &
1603 'Zonal Viscous Vertical Coupling Coefficient',
'meter second-1')
1604 cs%id_av_vv = register_diag_field(
'ocean_model',
'av_visc', diag%axesCvi, time, &
1605 'Meridional Viscous Vertical Coupling Coefficient',
'meter second-1')
1607 cs%id_h_u = register_diag_field(
'ocean_model',
'Hu_visc', diag%axesCuL, time, &
1608 'Thickness at Zonal Velocity Points for Viscosity', thickness_units)
1609 cs%id_h_v = register_diag_field(
'ocean_model',
'Hv_visc', diag%axesCvL, time, &
1610 'Thickness at Meridional Velocity Points for Viscosity', thickness_units)
1611 cs%id_hML_u = register_diag_field(
'ocean_model',
'HMLu_visc', diag%axesCu1, time, &
1612 'Mixed Layer Thickness at Zonal Velocity Points for Viscosity', thickness_units)
1613 cs%id_hML_v = register_diag_field(
'ocean_model',
'HMLv_visc', diag%axesCv1, time, &
1614 'Mixed Layer Thickness at Meridional Velocity Points for Viscosity', thickness_units)
1616 cs%id_du_dt_visc = register_diag_field(
'ocean_model',
'du_dt_visc', diag%axesCuL, &
1617 time,
'Zonal Acceleration from Vertical Viscosity',
'meter second-2')
1618 if (cs%id_du_dt_visc > 0)
call safe_alloc_ptr(adp%du_dt_visc,isdb,iedb,jsd,jed,nz)
1619 cs%id_dv_dt_visc = register_diag_field(
'ocean_model',
'dv_dt_visc', diag%axesCvL, &
1620 time,
'Meridional Acceleration from Vertical Viscosity',
'meter second-2')
1621 if (cs%id_dv_dt_visc > 0)
call safe_alloc_ptr(adp%dv_dt_visc,isd,ied,jsdb,jedb,nz)
1623 cs%id_taux_bot = register_diag_field(
'ocean_model',
'taux_bot', diag%axesCu1, &
1624 time,
'Zonal Bottom Stress from Ocean to Earth',
'Pa')
1625 cs%id_tauy_bot = register_diag_field(
'ocean_model',
'tauy_bot', diag%axesCv1, &
1626 time,
'Meridional Bottom Stress from Ocean to Earth',
'Pa')
1628 if ((len_trim(cs%u_trunc_file) > 0) .or. (len_trim(cs%v_trunc_file) > 0)) &
1629 call pointaccel_init(mis, time, g, param_file, diag, dirs, cs%PointAccel_CSp)
1637 type(time_type),
target,
intent(in) :: Time
1640 logical,
optional,
intent(in) :: activate
1643 real :: deltaTime, wghtA
1644 character(len=12) :: msg
1646 if (cs%truncRampTime==0.)
return 1650 if (
present(activate))
then 1652 cs%rampStartTime = time
1653 cs%CFLrampingIsActivated = .true.
1656 if (.not.cs%CFLrampingIsActivated)
return 1657 deltatime = max( 0., time_type_to_real( time - cs%rampStartTime ) )
1658 if (deltatime >= cs%truncRampTime)
then 1659 cs%CFL_trunc = cs%CFL_truncE
1660 cs%truncRampTime = 0.
1662 wghta = min( 1., deltatime / cs%truncRampTime )
1665 wghta = 1. - ( (1. - wghta)**2 )
1666 cs%CFL_trunc = cs%CFL_truncS + wghta * ( cs%CFL_truncE - cs%CFL_truncS )
1668 write(msg(1:12),
'(es12.3)') cs%CFL_trunc
1669 call mom_error(note,
"MOM_vert_friction: updateCFLtruncationValue set CFL"// &
1670 " limit to "//trim(msg))
1676 dealloc_(cs%a_u) ; dealloc_(cs%h_u)
1677 dealloc_(cs%a_v) ; dealloc_(cs%h_v)
1678 if (
associated(cs%a1_shelf_u))
deallocate(cs%a1_shelf_u)
1679 if (
associated(cs%a1_shelf_v))
deallocate(cs%a1_shelf_v)
integer, parameter, public obc_direction_s
Indicates the boundary is an effective southern boundary.
integer, parameter, public obc_direction_w
Indicates the boundary is an effective western boundary.
integer, parameter, public obc_direction_n
Indicates the boundary is an effective northern boundary.
This module implements boundary forcing for MOM6.
subroutine, public pointaccel_init(MIS, Time, G, param_file, diag, dirs, CS)
subroutine, public vertvisc_end(CS)
Clean up and deallocate the vertical friction module.
Ocean grid type. See mom_grid for details.
subroutine, public vertvisc_remnant(visc, visc_rem_u, visc_rem_v, dt, G, GV, CS)
Calculate the fraction of momentum originally in a layer that remains after a time-step of viscosity...
Implements vertical viscosity (vertvisc)
Provides the ocean grid type.
subroutine, public updatecfltruncationvalue(Time, CS, activate)
Update the CFL truncation value as a function of time. If called with the optional argument activate=...
The vertvisc_type structure contains vertical viscosities, drag coefficients, and related fields...
The accel_diag_ptrs structure contains pointers to arrays with accelerations, which can later be used...
integer, parameter, public obc_simple
The cont_diag_ptrs structure contains pointers to arrays with transports, which can later be used for...
The ocean_internal_state structure contains pointers to all of the prognostic variables allocated in ...
subroutine, public vertvisc_coef(u, v, h, fluxes, visc, dt, G, GV, CS, OBC)
Calculate the coupling coefficients (CSa_u and CSa_v) and effective layer thicknesses (CSh_u and CSh_...
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
subroutine, public vertvisc_init(MIS, Time, G, GV, param_file, diag, ADp, dirs, ntrunc, CS)
Initialise the vertical friction module.
integer, parameter, public obc_direction_e
Indicates the boundary is an effective eastern boundary.
subroutine, public write_v_accel(i, J, vm, hin, ADp, CDp, dt, G, GV, CS, maxvel, minvel, str, a, hv)
This subroutine writes to an output file all of the accelerations that have been applied to a column ...
subroutine, public vertvisc_limit_vel(u, v, h, ADp, CDp, fluxes, visc, dt, G, GV, CS)
Velocity components which exceed a threshold for physically reasonable values are truncated...
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
integer, parameter, public obc_none
Controls where open boundary conditions are applied.
subroutine, public write_u_accel(I, j, um, hin, ADp, CDp, dt, G, GV, CS, maxvel, minvel, str, a, hv)
This subroutine writes to an output file all of the accelerations that have been applied to a column ...
subroutine, public vertvisc(u, v, h, fluxes, visc, dt, OBC, ADp, CDp, G, GV, CS, taux_bot, tauy_bot)
Perform a fully implicit vertical diffusion of momentum. Stress top and bottom boundary conditions ar...
subroutine, public mom_error(level, message, all_print)
subroutine find_coupling_coef(a, hvel, do_i, h_harm, bbl_thick, kv_bbl, z_i, h_ml, dt, j, G, GV, CS, visc, fluxes, work_on_u, OBC, shelf)
Calculate the 'coupling coefficient' (a[k]) at the interfaces. If BOTTOMDRAGLAW is defined...