6 use mom_cpu_clock,
only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
10 use mom_domains,
only : sum_across_pes, max_across_pes
21 implicit none ;
private 23 #include <MOM_memory.h> 26 public tracer_advect_init
27 public tracer_advect_end
37 type(group_pass_type) :: pass_uhr_vhr_t_hprev
41 integer :: id_clock_advect
42 integer :: id_clock_pass
43 integer :: id_clock_sync
50 subroutine advect_tracer(h_end, uhtr, vhtr, OBC, dt, G, GV, US, CS, Reg, &
51 h_prev_opt, max_iter_in, x_first_in, uhr_out, vhr_out, h_out)
54 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
56 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
58 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
61 real,
intent(in) :: dt
65 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
66 optional,
intent(in) :: h_prev_opt
67 integer,
optional,
intent(in) :: max_iter_in
68 logical,
optional,
intent(in) :: x_first_in
70 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
71 optional,
intent(out) :: uhr_out
73 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
74 optional,
intent(out) :: vhr_out
76 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
77 optional,
intent(out) :: h_out
80 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
82 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)) :: &
84 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)) :: &
86 real :: uh_neglect(szib_(g),szj_(g))
87 real :: vh_neglect(szi_(g),szjb_(g))
92 logical :: domore_u(szj_(g),szk_(g))
93 logical :: domore_v(szjb_(g),szk_(g))
97 integer :: domore_k(szk_(g))
100 integer :: i, j, k, m, is, ie, js, je, isd, ied, jsd, jed, nz, itt, ntr, do_any
101 integer :: isv, iev, jsv, jev
102 integer :: isdb, iedb, jsdb, jedb
104 domore_u(:,:) = .false.
105 domore_v(:,:) = .false.
106 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
107 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
108 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
109 landvolfill = 1.0e-20
112 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_tracer_advect: "// &
113 "tracer_advect_init must be called before advect_tracer.")
114 if (.not.
associated(reg))
call mom_error(fatal,
"MOM_tracer_advect: "// &
115 "register_tracer must be called before advect_tracer.")
116 if (reg%ntr==0)
return 117 call cpu_clock_begin(id_clock_advect)
118 x_first = (mod(g%first_direction,2) == 0)
121 if (cs%usePPM .and. .not. cs%useHuynh) stencil = 3
124 do m=1,ntr ; tr(m) = reg%Tr(m) ;
enddo 127 max_iter = 2*int(ceiling(dt/cs%dt)) + 1
129 if (
present(max_iter_in)) max_iter = max_iter_in
130 if (
present(x_first_in)) x_first = x_first_in
131 call cpu_clock_begin(id_clock_pass)
137 call cpu_clock_end(id_clock_pass)
147 do j=jsd,jed ;
do i=isdb,iedb ; uhr(i,j,k) = 0.0 ;
enddo ;
enddo 148 do j=jsdb,jedb ;
do i=isd,ied ; vhr(i,j,k) = 0.0 ;
enddo ;
enddo 149 do j=jsd,jed ;
do i=isd,ied ; hprev(i,j,k) = 0.0 ;
enddo ;
enddo 152 do j=js,je ;
do i=is-1,ie ; uhr(i,j,k) = uhtr(i,j,k) ;
enddo ;
enddo 153 do j=js-1,je ;
do i=is,ie ; vhr(i,j,k) = vhtr(i,j,k) ;
enddo ;
enddo 154 if (.not.
present(h_prev_opt))
then 158 do i=is,ie ;
do j=js,je
159 hprev(i,j,k) = max(0.0, g%areaT(i,j)*h_end(i,j,k) + &
160 ((uhr(i,j,k) - uhr(i-1,j,k)) + (vhr(i,j,k) - vhr(i,j-1,k))))
164 hprev(i,j,k) = hprev(i,j,k) + &
165 max(0.0, 1.0e-13*hprev(i,j,k) - g%areaT(i,j)*h_end(i,j,k))
168 do i=is,ie ;
do j=js,je
169 hprev(i,j,k) = h_prev_opt(i,j,k)
176 do j=jsd,jed ;
do i=isd,ied-1
177 uh_neglect(i,j) = gv%H_subroundoff * min(g%areaT(i,j), g%areaT(i+1,j))
180 do j=jsd,jed-1 ;
do i=isd,ied
181 vh_neglect(i,j) = gv%H_subroundoff * min(g%areaT(i,j), g%areaT(i,j+1))
187 if (
associated(tr(m)%ad_x))
then 188 do k=1,nz ;
do j=jsd,jed ;
do i=isd,ied
189 tr(m)%ad_x(i,j,k) = 0.0
190 enddo ;
enddo ;
enddo 192 if (
associated(tr(m)%ad_y))
then 193 do k=1,nz ;
do j=jsd,jed ;
do i=isd,ied
194 tr(m)%ad_y(i,j,k) = 0.0
195 enddo ;
enddo ;
enddo 197 if (
associated(tr(m)%advection_xy))
then 198 do k=1,nz ;
do j=jsd,jed ;
do i=isd,ied
199 tr(m)%advection_xy(i,j,k) = 0.0
200 enddo ;
enddo ;
enddo 202 if (
associated(tr(m)%ad2d_x))
then 203 do j=jsd,jed ;
do i=isd,ied ; tr(m)%ad2d_x(i,j) = 0.0 ;
enddo ;
enddo 205 if (
associated(tr(m)%ad2d_y))
then 206 do j=jsd,jed ;
do i=isd,ied ; tr(m)%ad2d_y(i,j) = 0.0 ;
enddo ;
enddo 211 isv = is ; iev = ie ; jsv = js ; jev = je
215 if (isv > is-stencil)
then 216 call do_group_pass(cs%pass_uhr_vhr_t_hprev, g%Domain, clock=id_clock_pass)
218 nsten_halo = min(is-isd,ied-ie,js-jsd,jed-je)/stencil
219 isv = is-nsten_halo*stencil ; jsv = js-nsten_halo*stencil
220 iev = ie+nsten_halo*stencil ; jev = je+nsten_halo*stencil
223 if ((nsten_halo > 1) .or. (itt==1))
then 225 do k=1,nz ;
if (domore_k(k) > 0)
then 226 do j=jsv,jev ;
if (.not.domore_u(j,k))
then 227 do i=isv+stencil-1,iev-stencil;
if (uhr(i,j,k) /= 0.0)
then 228 domore_u(j,k) = .true. ;
exit 231 do j=jsv+stencil-1,jev-stencil ;
if (.not.domore_v(j,k))
then 232 do i=isv+stencil,iev-stencil;
if (vhr(i,j,k) /= 0.0)
then 233 domore_v(j,k) = .true. ;
exit 240 do j=jsv,jev ;
if (domore_u(j,k)) domore_k(k) = 1 ;
enddo 241 do j=jsv+stencil-1,jev-stencil ;
if (domore_v(j,k)) domore_k(k) = 1 ;
enddo 248 isv = isv + stencil ; iev = iev - stencil
249 jsv = jsv + stencil ; jev = jev - stencil
262 do k=1,nz ;
if (domore_k(k) > 0)
then 264 call advect_x(tr, hprev, uhr, uh_neglect, obc, domore_u, ntr, idt, &
265 isv, iev, jsv-stencil, jev+stencil, k, g, gv, us, cs%usePPM, cs%useHuynh)
269 do k=1,nz ;
if (domore_k(k) > 0)
then 271 call advect_y(tr, hprev, vhr, vh_neglect, obc, domore_v, ntr, idt, &
272 isv, iev, jsv, jev, k, g, gv, us, cs%usePPM, cs%useHuynh)
276 do j=jsv-stencil,jev+stencil ;
if (domore_u(j,k)) domore_k(k) = 1 ;
enddo 277 do j=jsv-1,jev ;
if (domore_v(j,k)) domore_k(k) = 1 ;
enddo 284 do k=1,nz ;
if (domore_k(k) > 0)
then 286 call advect_y(tr, hprev, vhr, vh_neglect, obc, domore_v, ntr, idt, &
287 isv-stencil, iev+stencil, jsv, jev, k, g, gv, us, cs%usePPM, cs%useHuynh)
291 do k=1,nz ;
if (domore_k(k) > 0)
then 293 call advect_x(tr, hprev, uhr, uh_neglect, obc, domore_u, ntr, idt, &
294 isv, iev, jsv, jev, k, g, gv, us, cs%usePPM, cs%useHuynh)
298 do j=jsv,jev ;
if (domore_u(j,k)) domore_k(k) = 1 ;
enddo 299 do j=jsv-1,jev ;
if (domore_v(j,k)) domore_k(k) = 1 ;
enddo 307 if (itt >= max_iter)
then 312 if (isv > is-stencil)
then 314 call cpu_clock_begin(id_clock_sync)
315 call sum_across_pes(domore_k(:), nz)
316 call cpu_clock_end(id_clock_sync)
317 do k=1,nz ; do_any = do_any + domore_k(k) ;
enddo 318 if (do_any == 0)
then 326 if (
present(uhr_out)) uhr_out(:,:,:) = uhr(:,:,:)
327 if (
present(vhr_out)) vhr_out(:,:,:) = vhr(:,:,:)
328 if (
present(h_out)) h_out(:,:,:) = hprev(:,:,:)
330 call cpu_clock_end(id_clock_advect)
332 end subroutine advect_tracer
337 subroutine advect_x(Tr, hprev, uhr, uh_neglect, OBC, domore_u, ntr, Idt, &
338 is, ie, js, je, k, G, GV, US, usePPM, useHuynh)
339 type(ocean_grid_type),
intent(inout) :: G
340 type(verticalGrid_type),
intent(in) :: GV
341 type(tracer_type),
dimension(ntr),
intent(inout) :: Tr
342 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: hprev
344 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: uhr
346 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: uh_neglect
348 type(ocean_OBC_type),
pointer :: OBC
349 logical,
dimension(SZJ_(G),SZK_(G)),
intent(inout) :: domore_u
351 real,
intent(in) :: Idt
352 integer,
intent(in) :: ntr
353 integer,
intent(in) :: is
354 integer,
intent(in) :: ie
355 integer,
intent(in) :: js
356 integer,
intent(in) :: je
357 integer,
intent(in) :: k
358 type(unit_scale_type),
intent(in) :: US
359 logical,
intent(in) :: usePPM
360 logical,
intent(in) :: useHuynh
363 real,
dimension(SZI_(G),ntr) :: &
365 real,
dimension(SZIB_(G),SZJ_(G),ntr) :: &
367 real,
dimension(SZI_(G),ntr) :: &
376 real :: uhh(SZIB_(G))
378 real,
dimension(SZIB_(G)) :: &
387 logical :: do_i(SZIB_(G),SZJ_(G))
389 integer :: i, j, m, n, i_up, stencil
390 real :: aR, aL, dMx, dMn, Tp, Tc, Tm, dA, mA, a6
391 real :: fac1,u_L_in,u_L_out
392 type(OBC_segment_type),
pointer :: segment=>null()
393 logical :: usePLMslope
394 logical,
dimension(SZJ_(G),SZK_(G)) :: domore_u_initial
398 domore_u_initial = domore_u
400 useplmslope = .not. (useppm .and. usehuynh)
403 if (useppm .and. .not. usehuynh) stencil = 2
405 min_h = 0.1*gv%Angstrom_H
407 h_neglect = gv%H_subroundoff
409 do i=is-1,ie ; cfl(i) = 0.0 ;
enddo 411 do j=js,je ;
if (domore_u(j,k))
then 412 domore_u(j,k) = .false.
415 if (useplmslope)
then 416 do m=1,ntr ;
do i=is-stencil,ie+stencil
431 tp = tr(m)%t(i+1,j,k) ; tc = tr(m)%t(i,j,k) ; tm = tr(m)%t(i-1,j,k)
432 dmx = max( tp, tc, tm ) - tc
433 dmn= tc - min( tp, tc, tm )
434 slope_x(i,m) = g%mask2dCu(i,j)*g%mask2dCu(i-1,j) * &
435 sign( min(0.5*abs(tp-tm), 2.0*dmx, 2.0*dmn), tp-tm )
442 t_tmp(i,m) = tr(m)%t(i,j,k)
446 if (
associated(obc))
then ;
if (obc%OBC_pe)
then 447 do n=1,obc%number_of_segments
448 segment=>obc%segment(n)
449 if (.not.
associated(segment%tr_Reg)) cycle
450 if (segment%is_E_or_W)
then 451 if (j>=segment%HI%jsd .and. j<=segment%HI%jed)
then 454 if (
associated(segment%tr_Reg%Tr(m)%tres))
then 455 if (segment%direction == obc_direction_w)
then 456 t_tmp(i,m) = segment%tr_Reg%Tr(m)%tres(i,j,k)
458 t_tmp(i+1,m) = segment%tr_Reg%Tr(m)%tres(i,j,k)
461 if (segment%direction == obc_direction_w)
then 462 t_tmp(i,m) = segment%tr_Reg%Tr(m)%OBC_inflow_conc
464 t_tmp(i+1,m) = segment%tr_Reg%Tr(m)%OBC_inflow_conc
469 do i=segment%HI%IsdB-1,segment%HI%IsdB+1
470 tp = t_tmp(i+1,m) ; tc = t_tmp(i,m) ; tm = t_tmp(i-1,m)
471 dmx = max( tp, tc, tm ) - tc
472 dmn= tc - min( tp, tc, tm )
473 slope_x(i,m) = g%mask2dCu(i,j)*g%mask2dCu(i-1,j) * &
474 sign( min(0.5*abs(tp-tm), 2.0*dmx, 2.0*dmn), tp-tm )
489 if ((uhr(i,j,k) == 0.0) .or. &
490 ((uhr(i,j,k) < 0.0) .and. (hprev(i+1,j,k) <= tiny_h)) .or. &
491 ((uhr(i,j,k) > 0.0) .and. (hprev(i,j,k) <= tiny_h)) )
then 494 elseif (uhr(i,j,k) < 0.0)
then 495 hup = hprev(i+1,j,k) - g%areaT(i+1,j)*min_h
496 hlos = max(0.0, uhr(i+1,j,k))
497 if ((((hup - hlos) + uhr(i,j,k)) < 0.0) .and. &
498 ((0.5*hup + uhr(i,j,k)) < 0.0))
then 499 uhh(i) = min(-0.5*hup, -hup+hlos, 0.0)
500 domore_u(j,k) = .true.
504 cfl(i) = - uhh(i) / (hprev(i+1,j,k))
506 hup = hprev(i,j,k) - g%areaT(i,j)*min_h
507 hlos = max(0.0, -uhr(i-1,j,k))
508 if ((((hup - hlos) - uhr(i,j,k)) < 0.0) .and. &
509 ((0.5*hup - uhr(i,j,k)) < 0.0))
then 510 uhh(i) = max(0.5*hup, hup-hlos, 0.0)
511 domore_u(j,k) = .true.
515 cfl(i) = uhh(i) / (hprev(i,j,k))
521 do m=1,ntr ;
do i=is-1,ie
523 if (uhh(i) >= 0.0)
then 530 tp = t_tmp(i_up+1,m) ; tc = t_tmp(i_up,m) ; tm = t_tmp(i_up-1,m)
533 al = ( 5.*tc + ( 2.*tm - tp ) )/6.
534 al = max( min(tc,tm), al) ; al = min( max(tc,tm), al)
535 ar = ( 5.*tc + ( 2.*tp - tm ) )/6.
536 ar = max( min(tc,tp), ar) ; ar = min( max(tc,tp), ar)
538 al = 0.5 * ((tm + tc) + (slope_x(i_up-1,m) - slope_x(i_up,m)) / 3.)
539 ar = 0.5 * ((tc + tp) + (slope_x(i_up,m) - slope_x(i_up+1,m)) / 3.)
542 da = ar - al ; ma = 0.5*( ar + al )
543 if (g%mask2dCu(i_up,j)*g%mask2dCu(i_up-1,j)*(tp-tc)*(tc-tm) <= 0.)
then 545 elseif ( da*(tc-ma) > (da*da)/6. )
then 547 elseif ( da*(tc-ma) < - (da*da)/6. )
then 551 a6 = 6.*tc - 3. * (ar + al)
553 if (uhh(i) >= 0.0)
then 554 flux_x(i,j,m) = uhh(i)*( ar - 0.5 * cfl(i) * ( &
555 ( ar - al ) - a6 * ( 1. - 2./3. * cfl(i) ) ) )
557 flux_x(i,j,m) = uhh(i)*( al + 0.5 * cfl(i) * ( &
558 ( ar - al ) + a6 * ( 1. - 2./3. * cfl(i) ) ) )
562 do m=1,ntr ;
do i=is-1,ie
563 if (uhh(i) >= 0.0)
then 570 flux_x(i,j,m) = uhh(i)*( tc + 0.5 * slope_x(i,m) * ( 1. - cfl(i) ) )
578 flux_x(i,j,m) = uhh(i)*( tc - 0.5 * slope_x(i+1,m) * ( 1. - cfl(i) ) )
583 if (
associated(obc))
then ;
if (obc%OBC_pe)
then 584 if (obc%specified_u_BCs_exist_globally .or. obc%open_u_BCs_exist_globally)
then 585 do n=1,obc%number_of_segments
586 segment=>obc%segment(n)
587 if (.not.
associated(segment%tr_Reg)) cycle
588 if (segment%is_E_or_W)
then 589 if (j>=segment%HI%jsd .and. j<=segment%HI%jed)
then 593 if ((uhr(i,j,k) > 0.0) .and. (segment%direction == obc_direction_w) .or. &
594 (uhr(i,j,k) < 0.0) .and. (segment%direction == obc_direction_e))
then 598 if (
associated(segment%tr_Reg%Tr(m)%tres))
then 599 flux_x(i,j,m) = uhh(i)*segment%tr_Reg%Tr(m)%tres(i,j,k)
600 else ; flux_x(i,j,m) = uhh(i)*segment%tr_Reg%Tr(m)%OBC_inflow_conc ;
endif 608 if (obc%open_u_BCs_exist_globally)
then 609 do n=1,obc%number_of_segments
610 segment=>obc%segment(n)
612 if (segment%is_E_or_W .and. (j >= segment%HI%jsd .and. j<= segment%HI%jed))
then 613 if (segment%specified) cycle
614 if (.not.
associated(segment%tr_Reg)) cycle
617 if ((uhr(i,j,k) > 0.0) .and. (g%mask2dT(i,j) < 0.5) .or. &
618 (uhr(i,j,k) < 0.0) .and. (g%mask2dT(i+1,j) < 0.5))
then 621 if (
associated(segment%tr_Reg%Tr(m)%tres))
then 622 flux_x(i,j,m) = uhh(i)*segment%tr_Reg%Tr(m)%tres(i,j,k)
623 else; flux_x(i,j,m) = uhh(i)*segment%tr_Reg%Tr(m)%OBC_inflow_conc;
endif 634 uhr(i,j,k) = uhr(i,j,k) - uhh(i)
635 if (abs(uhr(i,j,k)) < uh_neglect(i,j)) uhr(i,j,k) = 0.0
638 if ((uhh(i) /= 0.0) .or. (uhh(i-1) /= 0.0))
then 640 hlst(i) = hprev(i,j,k)
641 hprev(i,j,k) = hprev(i,j,k) - (uhh(i) - uhh(i-1))
642 if (hprev(i,j,k) <= 0.0)
then ; do_i(i,j) = .false.
643 elseif (hprev(i,j,k) < h_neglect*g%areaT(i,j))
then 644 hlst(i) = hlst(i) + (h_neglect*g%areaT(i,j) - hprev(i,j,k))
645 ihnew(i) = 1.0 / (h_neglect*g%areaT(i,j))
646 else ; ihnew(i) = 1.0 / hprev(i,j,k) ;
endif 658 if (ihnew(i) > 0.0)
then 659 tr(m)%t(i,j,k) = (tr(m)%t(i,j,k) * hlst(i) - &
660 (flux_x(i,j,m) - flux_x(i-1,j,m))) * ihnew(i)
666 if (
associated(tr(m)%ad_x))
then ;
do i=is,ie ;
if (do_i(i,j))
then 667 tr(m)%ad_x(i,j,k) = tr(m)%ad_x(i,j,k) + flux_x(i,j,m)*idt
668 endif ;
enddo ;
endif 672 if (
associated(tr(m)%advection_xy))
then 673 do i=is,ie ;
if (do_i(i,j))
then 674 tr(m)%advection_xy(i,j,k) = tr(m)%advection_xy(i,j,k) - (flux_x(i,j,m) - flux_x(i-1,j,m)) * &
689 do j=js,je ;
if (domore_u_initial(j,k))
then 691 if (
associated(tr(m)%ad2d_x))
then ;
do i=is,ie ;
if (do_i(i,j))
then 692 tr(m)%ad2d_x(i,j) = tr(m)%ad2d_x(i,j) + flux_x(i,j,m)*idt
693 endif ;
enddo ;
endif 698 end subroutine advect_x
702 subroutine advect_y(Tr, hprev, vhr, vh_neglect, OBC, domore_v, ntr, Idt, &
703 is, ie, js, je, k, G, GV, US, usePPM, useHuynh)
704 type(ocean_grid_type),
intent(inout) :: G
705 type(verticalGrid_type),
intent(in) :: GV
706 type(tracer_type),
dimension(ntr),
intent(inout) :: Tr
707 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: hprev
709 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: vhr
711 real,
dimension(SZI_(G),SZJB_(G)),
intent(inout) :: vh_neglect
713 type(ocean_OBC_type),
pointer :: OBC
714 logical,
dimension(SZJB_(G),SZK_(G)),
intent(inout) :: domore_v
716 real,
intent(in) :: Idt
717 integer,
intent(in) :: ntr
718 integer,
intent(in) :: is
719 integer,
intent(in) :: ie
720 integer,
intent(in) :: js
721 integer,
intent(in) :: je
722 integer,
intent(in) :: k
723 type(unit_scale_type),
intent(in) :: US
724 logical,
intent(in) :: usePPM
725 logical,
intent(in) :: useHuynh
728 real,
dimension(SZI_(G),ntr,SZJ_(G)) :: &
730 real,
dimension(SZI_(G),ntr,SZJB_(G)) :: &
732 real,
dimension(SZI_(G),ntr,SZJB_(G)) :: &
736 real :: vhh(SZI_(G),SZJB_(G))
742 real,
dimension(SZIB_(G)) :: &
751 logical :: do_j_tr(SZJ_(G))
752 logical :: do_i(SZIB_(G), SZJ_(G))
754 integer :: i, j, j2, m, n, j_up, stencil
755 real :: aR, aL, dMx, dMn, Tp, Tc, Tm, dA, mA, a6
756 real :: fac1,v_L_in,v_L_out
757 type(OBC_segment_type),
pointer :: segment=>null()
758 logical :: usePLMslope
760 useplmslope = .not. (useppm .and. usehuynh)
763 if (useppm .and. .not. usehuynh) stencil = 2
765 min_h = 0.1*gv%Angstrom_H
767 h_neglect = gv%H_subroundoff
780 do j=js-1,je ;
if (domore_v(j,k))
then ;
do j2=1-stencil,stencil ; do_j_tr(j+j2) = .true. ;
enddo ;
endif ;
enddo 784 if (useplmslope)
then 785 do j=js-stencil,je+stencil ;
if (do_j_tr(j))
then ;
do m=1,ntr ;
do i=is,ie
800 tp = tr(m)%t(i,j+1,k) ; tc = tr(m)%t(i,j,k) ; tm = tr(m)%t(i,j-1,k)
801 dmx = max( tp, tc, tm ) - tc
802 dmn= tc - min( tp, tc, tm )
803 slope_y(i,m,j) = g%mask2dCv(i,j)*g%mask2dCv(i,j-1) * &
804 sign( min(0.5*abs(tp-tm), 2.0*dmx, 2.0*dmn), tp-tm )
805 enddo ;
enddo ;
endif ;
enddo 811 do j=g%jsd,g%jed ;
do m=1,ntr ;
do i=g%isd,g%ied
812 t_tmp(i,m,j) = tr(m)%t(i,j,k)
813 enddo ;
enddo ;
enddo 816 if (
associated(obc))
then ;
if (obc%OBC_pe)
then 817 do n=1,obc%number_of_segments
818 segment=>obc%segment(n)
819 if (.not.
associated(segment%tr_Reg)) cycle
821 if (segment%is_N_or_S)
then 822 if (i>=segment%HI%isd .and. i<=segment%HI%ied)
then 825 if (
associated(segment%tr_Reg%Tr(m)%tres))
then 826 if (segment%direction == obc_direction_s)
then 827 t_tmp(i,m,j) = segment%tr_Reg%Tr(m)%tres(i,j,k)
829 t_tmp(i,m,j+1) = segment%tr_Reg%Tr(m)%tres(i,j,k)
832 if (segment%direction == obc_direction_s)
then 833 t_tmp(i,m,j) = segment%tr_Reg%Tr(m)%OBC_inflow_conc
835 t_tmp(i,m,j+1) = segment%tr_Reg%Tr(m)%OBC_inflow_conc
840 do j=segment%HI%JsdB-1,segment%HI%JsdB+1
841 tp = t_tmp(i,m,j+1) ; tc = t_tmp(i,m,j) ; tm = t_tmp(i,m,j-1)
842 dmx = max( tp, tc, tm ) - tc
843 dmn= tc - min( tp, tc, tm )
844 slope_y(i,m,j) = g%mask2dCv(i,j)*g%mask2dCv(i,j-1) * &
845 sign( min(0.5*abs(tp-tm), 2.0*dmx, 2.0*dmn), tp-tm )
858 do j=js-1,je ;
if (domore_v(j,k))
then 859 domore_v(j,k) = .false.
862 if ((vhr(i,j,k) == 0.0) .or. &
863 ((vhr(i,j,k) < 0.0) .and. (hprev(i,j+1,k) <= tiny_h)) .or. &
864 ((vhr(i,j,k) > 0.0) .and. (hprev(i,j,k) <= tiny_h)) )
then 867 elseif (vhr(i,j,k) < 0.0)
then 868 hup = hprev(i,j+1,k) - g%areaT(i,j+1)*min_h
869 hlos = max(0.0, vhr(i,j+1,k))
870 if ((((hup - hlos) + vhr(i,j,k)) < 0.0) .and. &
871 ((0.5*hup + vhr(i,j,k)) < 0.0))
then 872 vhh(i,j) = min(-0.5*hup, -hup+hlos, 0.0)
873 domore_v(j,k) = .true.
875 vhh(i,j) = vhr(i,j,k)
877 cfl(i) = - vhh(i,j) / hprev(i,j+1,k)
879 hup = hprev(i,j,k) - g%areaT(i,j)*min_h
880 hlos = max(0.0, -vhr(i,j-1,k))
881 if ((((hup - hlos) - vhr(i,j,k)) < 0.0) .and. &
882 ((0.5*hup - vhr(i,j,k)) < 0.0))
then 883 vhh(i,j) = max(0.5*hup, hup-hlos, 0.0)
884 domore_v(j,k) = .true.
886 vhh(i,j) = vhr(i,j,k)
888 cfl(i) = vhh(i,j) / hprev(i,j,k)
893 do m=1,ntr ;
do i=is,ie
895 if (vhh(i,j) >= 0.0)
then 902 tp = t_tmp(i,m,j_up+1) ; tc = t_tmp(i,m,j_up) ; tm = t_tmp(i,m,j_up-1)
905 al = ( 5.*tc + ( 2.*tm - tp ) )/6.
906 al = max( min(tc,tm), al) ; al = min( max(tc,tm), al)
907 ar = ( 5.*tc + ( 2.*tp - tm ) )/6.
908 ar = max( min(tc,tp), ar) ; ar = min( max(tc,tp), ar)
910 al = 0.5 * ((tm + tc) + (slope_y(i,m,j_up-1) - slope_y(i,m,j_up)) / 3.)
911 ar = 0.5 * ((tc + tp) + (slope_y(i,m,j_up) - slope_y(i,m,j_up+1)) / 3.)
914 da = ar - al ; ma = 0.5*( ar + al )
915 if (g%mask2dCv(i,j_up)*g%mask2dCv(i,j_up-1)*(tp-tc)*(tc-tm) <= 0.)
then 917 elseif ( da*(tc-ma) > (da*da)/6. )
then 919 elseif ( da*(tc-ma) < - (da*da)/6. )
then 923 a6 = 6.*tc - 3. * (ar + al)
925 if (vhh(i,j) >= 0.0)
then 926 flux_y(i,m,j) = vhh(i,j)*( ar - 0.5 * cfl(i) * ( &
927 ( ar - al ) - a6 * ( 1. - 2./3. * cfl(i) ) ) )
929 flux_y(i,m,j) = vhh(i,j)*( al + 0.5 * cfl(i) * ( &
930 ( ar - al ) + a6 * ( 1. - 2./3. * cfl(i) ) ) )
934 do m=1,ntr ;
do i=is,ie
935 if (vhh(i,j) >= 0.0)
then 942 flux_y(i,m,j) = vhh(i,j)*( tc + 0.5 * slope_y(i,m,j) * ( 1. - cfl(i) ) )
950 flux_y(i,m,j) = vhh(i,j)*( tc - 0.5 * slope_y(i,m,j+1) * ( 1. - cfl(i) ) )
955 if (
associated(obc))
then ;
if (obc%OBC_pe)
then 956 if (obc%specified_v_BCs_exist_globally .or. obc%open_v_BCs_exist_globally)
then 957 do n=1,obc%number_of_segments
958 segment=>obc%segment(n)
959 if (.not. segment%specified) cycle
960 if (.not.
associated(segment%tr_Reg)) cycle
961 if (obc%segment(n)%is_N_or_S)
then 962 if (j >= segment%HI%JsdB .and. j<= segment%HI%JedB)
then 963 do i=segment%HI%isd,segment%HI%ied
966 if ((vhr(i,j,k) > 0.0) .and. (segment%direction == obc_direction_s) .or. &
967 (vhr(i,j,k) < 0.0) .and. (segment%direction == obc_direction_n))
then 968 vhh(i,j) = vhr(i,j,k)
970 if (
associated(segment%tr_Reg%Tr(m)%t))
then 971 flux_y(i,m,j) = vhh(i,j)*obc%segment(n)%tr_Reg%Tr(m)%tres(i,j,k)
972 else ; flux_y(i,m,j) = vhh(i,j)*obc%segment(n)%tr_Reg%Tr(m)%OBC_inflow_conc ;
endif 981 if (obc%open_v_BCs_exist_globally)
then 982 do n=1,obc%number_of_segments
983 segment=>obc%segment(n)
984 if (segment%specified) cycle
985 if (.not.
associated(segment%tr_Reg)) cycle
986 if (segment%is_N_or_S .and. (j >= segment%HI%JsdB .and. j<= segment%HI%JedB))
then 987 do i=segment%HI%isd,segment%HI%ied
989 if ((vhr(i,j,k) > 0.0) .and. (g%mask2dT(i,j) < 0.5) .or. &
990 (vhr(i,j,k) < 0.0) .and. (g%mask2dT(i,j+1) < 0.5))
then 991 vhh(i,j) = vhr(i,j,k)
993 if (
associated(segment%tr_Reg%Tr(m)%t))
then 994 flux_y(i,m,j) = vhh(i,j)*segment%tr_Reg%Tr(m)%tres(i,j,k)
995 else ; flux_y(i,m,j) = vhh(i,j)*segment%tr_Reg%Tr(m)%OBC_inflow_conc ;
endif 1005 do i=is,ie ; vhh(i,j) = 0.0 ;
enddo 1006 do m=1,ntr ;
do i=is,ie ; flux_y(i,m,j) = 0.0 ;
enddo ;
enddo 1009 do j=js-1,je ;
do i=is,ie
1010 vhr(i,j,k) = vhr(i,j,k) - vhh(i,j)
1011 if (abs(vhr(i,j,k)) < vh_neglect(i,j)) vhr(i,j,k) = 0.0
1016 do j=js,je ;
if (do_j_tr(j))
then 1018 if ((vhh(i,j) /= 0.0) .or. (vhh(i,j-1) /= 0.0))
then 1020 hlst(i) = hprev(i,j,k)
1021 hprev(i,j,k) = max(hprev(i,j,k) - (vhh(i,j) - vhh(i,j-1)), 0.0)
1022 if (hprev(i,j,k) <= 0.0)
then ; do_i(i,j) = .false.
1023 elseif (hprev(i,j,k) < h_neglect*g%areaT(i,j))
then 1024 hlst(i) = hlst(i) + (h_neglect*g%areaT(i,j) - hprev(i,j,k))
1025 ihnew(i) = 1.0 / (h_neglect*g%areaT(i,j))
1026 else ; ihnew(i) = 1.0 / hprev(i,j,k) ;
endif 1027 else ; do_i(i,j) = .false. ;
endif 1032 do i=is,ie ;
if (do_i(i,j))
then 1033 tr(m)%t(i,j,k) = (tr(m)%t(i,j,k) * hlst(i) - &
1034 (flux_y(i,m,j) - flux_y(i,m,j-1))) * ihnew(i)
1038 if (
associated(tr(m)%ad_y))
then ;
do i=is,ie ;
if (do_i(i,j))
then 1039 tr(m)%ad_y(i,j,k) = tr(m)%ad_y(i,j,k) + flux_y(i,m,j)*idt
1040 endif ;
enddo ;
endif 1044 if (
associated(tr(m)%advection_xy))
then 1045 do i=is,ie ;
if (do_i(i,j))
then 1046 tr(m)%advection_xy(i,j,k) = tr(m)%advection_xy(i,j,k) - (flux_y(i,m,j) - flux_y(i,m,j-1))* idt * &
1057 do j=js,je ;
if (do_j_tr(j))
then 1059 if (
associated(tr(m)%ad2d_y))
then ;
do i=is,ie ;
if (do_i(i,j))
then 1060 tr(m)%ad2d_y(i,j) = tr(m)%ad2d_y(i,j) + flux_y(i,m,j)*idt
1061 endif ;
enddo ;
endif 1066 end subroutine advect_y
1069 subroutine tracer_advect_init(Time, G, US, param_file, diag, CS)
1070 type(time_type),
target,
intent(in) :: time
1071 type(ocean_grid_type),
intent(in) :: g
1072 type(unit_scale_type),
intent(in) :: us
1073 type(param_file_type),
intent(in) :: param_file
1074 type(diag_ctrl),
target,
intent(inout) :: diag
1077 integer,
save :: init_calls = 0
1080 # include "version_variable.h" 1081 character(len=40) :: mdl =
"MOM_tracer_advect" 1082 character(len=256) :: mesg
1084 if (
associated(cs))
then 1085 call mom_error(warning,
"tracer_advect_init called with associated control structure.")
1093 call log_version(param_file, mdl, version,
"")
1094 call get_param(param_file, mdl,
"DT", cs%dt, fail_if_missing=.true., &
1095 desc=
"The (baroclinic) dynamics time step.", units=
"s", scale=us%s_to_T)
1096 call get_param(param_file, mdl,
"DEBUG", cs%debug, default=.false.)
1097 call get_param(param_file, mdl,
"TRACER_ADVECTION_SCHEME", mesg, &
1098 desc=
"The horizontal transport scheme for tracers:\n"//&
1099 " PLM - Piecewise Linear Method\n"//&
1100 " PPM:H3 - Piecewise Parabolic Method (Huyhn 3rd order)\n"// &
1101 " PPM - Piecewise Parabolic Method (Colella-Woodward)" &
1103 select case (trim(mesg))
1108 cs%useHuynh = .true.
1111 cs%useHuynh = .false.
1113 call mom_error(fatal,
"MOM_tracer_advect, tracer_advect_init: "//&
1114 "Unknown TRACER_ADVECTION_SCHEME = "//trim(mesg))
1117 id_clock_advect = cpu_clock_id(
'(Ocean advect tracer)', grain=clock_module)
1118 id_clock_pass = cpu_clock_id(
'(Ocean tracer halo updates)', grain=clock_routine)
1119 id_clock_sync = cpu_clock_id(
'(Ocean tracer global synch)', grain=clock_routine)
1121 end subroutine tracer_advect_init
1124 subroutine tracer_advect_end(CS)
1127 if (
associated(cs))
deallocate(cs)
1129 end subroutine tracer_advect_end
Control structure for this module.
Ocean grid type. See mom_grid for details.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Open boundary segment data structure.
Wraps the MPP cpu clock functions.
The MOM6 facility to parse input files for runtime parameters.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Describes the decomposed MOM domain and has routines for communications across PEs.
Type to carry basic tracer information.
Routines for error handling and I/O management.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Set up a group of halo updates.
This module contains the subroutines that advect tracers along coordinate surfaces.
Controls where open boundary conditions are applied.
Provides a transparent vertical ocean grid type and supporting routines.
Do a halo update on an array.
An overloaded interface to read and log the values of various types of parameters.