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
29 implicit none ;
private 31 #include <MOM_memory.h> 38 real :: khtr_slope_cff
41 real :: khtr_passivity_coeff
44 real :: khtr_passivity_min
48 logical :: diffuse_ml_interior
50 logical :: check_diffusive_cfl
53 logical :: use_neutral_diffusion
59 logical :: show_call_tree
60 logical :: first_call = .true.
61 integer :: id_khtr_u = -1
62 integer :: id_khtr_v = -1
63 integer :: id_khtr_h = -1
64 integer :: id_cfl = -1
65 integer :: id_khdt_x = -1
66 integer :: id_khdt_y = -1
68 type(group_pass_type) :: pass_t
73 real,
dimension(:,:),
pointer :: p => null()
76 integer,
dimension(:,:),
pointer :: p => null()
87 subroutine tracer_hordiff(h, dt, MEKE, VarMix, G, GV, CS, Reg, tv, do_online_flag, read_khdt_x, read_khdt_y)
89 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
90 real,
intent(in) :: dt
103 logical,
optional :: do_online_flag
104 real,
dimension(SZIB_(G),SZJ_(G)),
optional,
intent(in) :: read_khdt_x
105 real,
dimension(SZI_(G),SZJB_(G)),
optional,
intent(in) :: read_khdt_y
108 real,
dimension(SZI_(G),SZJ_(G)) :: &
116 real,
dimension(SZIB_(G),SZJ_(G)) :: &
122 real,
dimension(SZI_(G),SZJB_(G)) :: &
130 logical :: use_VarMix, Resoln_scaled, do_online, use_Eady
131 integer :: i, j, k, m, is, ie, js, je, nz, ntr, itt, num_itts
143 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
146 if (
present(do_online_flag)) do_online = do_online_flag
148 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_tracer_hor_diff: "// &
149 "register_tracer must be called before tracer_hordiff.")
150 if (loc(reg)==0)
call mom_error(fatal,
"MOM_tracer_hor_diff: "// &
151 "register_tracer must be called before tracer_hordiff.")
152 if ((reg%ntr==0) .or. ((cs%KhTr <= 0.0) .and. .not.
associated(varmix)) )
return 154 if (cs%show_call_tree)
call calltree_enter(
"tracer_hordiff(), MOM_tracer_hor_diff.F90")
160 h_neglect = gv%H_subroundoff
162 if (cs%Diffuse_ML_interior .and. cs%first_call)
then ;
if (is_root_pe())
then 163 do m=1,ntr ;
if (
associated(reg%Tr(m)%df_x) .or.
associated(reg%Tr(m)%df_y)) &
164 call mom_error(warning,
"tracer_hordiff: Tracer "//trim(reg%Tr(m)%name)// &
165 " has associated 3-d diffusive flux diagnostics. These are not "//&
166 "valid when DIFFUSE_ML_TO_INTERIOR is defined. Use 2-d tracer "//&
167 "diffusion diagnostics instead to get accurate total fluxes.")
170 cs%first_call = .false.
174 use_varmix = .false. ; resoln_scaled = .false. ; use_eady = .false.
175 if (
Associated(varmix))
then 176 use_varmix = varmix%use_variable_mixing
177 resoln_scaled = varmix%Resoln_scaled_KhTr
178 use_eady = cs%KhTr_Slope_Cff > 0.
187 if (cs%show_call_tree)
call calltree_waypoint(
"Calculating diffusivity (tracer_hordiff)")
195 do j=js,je ;
do i=is-1,ie
197 if (use_eady) kh_loc = kh_loc + cs%KhTr_Slope_Cff*varmix%L2u(i,j)*varmix%SN_u(i,j)
198 if (
associated(meke%Kh)) &
199 kh_loc = kh_loc + meke%KhTr_fac*sqrt(meke%Kh(i,j)*meke%Kh(i+1,j))
200 if (cs%KhTr_max > 0.) kh_loc = min(kh_loc, cs%KhTr_max)
202 kh_loc = kh_loc * 0.5*(varmix%Res_fn_h(i,j) + varmix%Res_fn_h(i+1,j))
203 kh_u(i,j) = max(kh_loc, cs%KhTr_min)
204 if (cs%KhTr_passivity_coeff>0.)
then 205 rd_dx=0.5*( varmix%Rd_dx_h(i,j)+varmix%Rd_dx_h(i+1,j) )
206 kh_loc=kh_u(i,j)*max( cs%KhTr_passivity_min, cs%KhTr_passivity_coeff*rd_dx )
207 if (cs%KhTr_max > 0.) kh_loc = min(kh_loc, cs%KhTr_max)
208 kh_u(i,j) = max(kh_loc, cs%KhTr_min)
212 do j=js-1,je ;
do i=is,ie
214 if (use_eady) kh_loc = kh_loc + cs%KhTr_Slope_Cff*varmix%L2v(i,j)*varmix%SN_v(i,j)
215 if (
associated(meke%Kh)) &
216 kh_loc = kh_loc + meke%KhTr_fac*sqrt(meke%Kh(i,j)*meke%Kh(i,j+1))
217 if (cs%KhTr_max > 0.) kh_loc = min(kh_loc, cs%KhTr_max)
219 kh_loc = kh_loc * 0.5*(varmix%Res_fn_h(i,j) + varmix%Res_fn_h(i,j+1))
220 kh_v(i,j) = max(kh_loc, cs%KhTr_min)
221 if (cs%KhTr_passivity_coeff>0.)
then 222 rd_dx=0.5*( varmix%Rd_dx_h(i,j)+varmix%Rd_dx_h(i,j+1) )
223 kh_loc=kh_v(i,j)*max( cs%KhTr_passivity_min, cs%KhTr_passivity_coeff*rd_dx )
224 if (cs%KhTr_max > 0.) kh_loc = min(kh_loc, cs%KhTr_max)
225 kh_v(i,j) = max(kh_loc, cs%KhTr_min)
230 do j=js,je ;
do i=is-1,ie
231 khdt_x(i,j) = dt*(kh_u(i,j)*(g%dy_Cu(i,j)*g%IdxCu(i,j)))
234 do j=js-1,je ;
do i=is,ie
235 khdt_y(i,j) = dt*(kh_v(i,j)*(g%dx_Cv(i,j)*g%IdyCv(i,j)))
238 elseif (resoln_scaled)
then 242 do j=js,je ;
do i=is-1,ie
243 res_fn = 0.5 * (varmix%Res_fn_h(i,j) + varmix%Res_fn_h(i+1,j))
244 kh_u(i,j) = max(cs%KhTr * res_fn, cs%KhTr_min)
245 khdt_x(i,j) = dt*(cs%KhTr*(g%dy_Cu(i,j)*g%IdxCu(i,j))) * res_fn
248 do j=js-1,je ;
do i=is,ie
249 res_fn = 0.5*(varmix%Res_fn_h(i,j) + varmix%Res_fn_h(i,j+1))
250 kh_v(i,j) = max(cs%KhTr * res_fn, cs%KhTr_min)
251 khdt_y(i,j) = dt*(cs%KhTr*(g%dx_Cv(i,j)*g%IdyCv(i,j))) * res_fn
256 if (cs%id_KhTr_u > 0)
then 258 do j=js,je ;
do i=is-1,ie
260 khdt_x(i,j) = dt*(cs%KhTr*(g%dy_Cu(i,j)*g%IdxCu(i,j)))
264 do j=js,je ;
do i=is-1,ie
265 khdt_x(i,j) = dt*(cs%KhTr*(g%dy_Cu(i,j)*g%IdxCu(i,j)))
268 if (cs%id_KhTr_v > 0)
then 270 do j=js-1,je ;
do i=is,ie
272 khdt_y(i,j) = dt*(cs%KhTr*(g%dx_Cv(i,j)*g%IdyCv(i,j)))
276 do j=js-1,je ;
do i=is,ie
277 khdt_y(i,j) = dt*(cs%KhTr*(g%dx_Cv(i,j)*g%IdyCv(i,j)))
290 if (cs%check_diffusive_CFL)
then 291 if (cs%show_call_tree)
call calltree_waypoint(
"Checking diffusive CFL (tracer_hordiff)")
293 do j=js,je ;
do i=is,ie
294 cfl(i,j) = 2.0*((khdt_x(i-1,j) + khdt_x(i,j)) + &
295 (khdt_y(i,j-1) + khdt_y(i,j))) * g%IareaT(i,j)
296 if (max_cfl < cfl(i,j)) max_cfl = cfl(i,j)
299 call max_across_pes(max_cfl)
301 num_itts = max(1,ceiling(max_cfl))
302 i_numitts = 1.0 ;
if (num_itts > 1) i_numitts = 1.0 / (
real(num_itts))
303 if(cs%id_CFL > 0)
call post_data(cs%id_CFL, cfl, cs%diag, mask=g%mask2dT)
305 num_itts = 1 ; i_numitts = 1.0
309 if (
associated(reg%Tr(m)%df_x))
then 310 do k=1,nz ;
do j=js,je ;
do i=is-1,ie
311 reg%Tr(m)%df_x(i,j,k) = 0.0
312 enddo ;
enddo ;
enddo 314 if (
associated(reg%Tr(m)%df_y))
then 315 do k=1,nz ;
do j=js-1,je ;
do i=is,ie
316 reg%Tr(m)%df_y(i,j,k) = 0.0
317 enddo ;
enddo ;
enddo 319 if (
associated(reg%Tr(m)%df2d_x))
then 320 do j=js,je ;
do i=is-1,ie ; reg%Tr(m)%df2d_x(i,j) = 0.0 ;
enddo ;
enddo 322 if (
associated(reg%Tr(m)%df2d_y))
then 323 do j=js-1,je ;
do i=is,ie ; reg%Tr(m)%df2d_y(i,j) = 0.0 ;
enddo ;
enddo 327 if (cs%use_neutral_diffusion)
then 329 if (cs%show_call_tree)
call calltree_waypoint(
"Calling neutral diffusion coeffs (tracer_hordiff)")
331 call do_group_pass(cs%pass_t, g%Domain)
338 cs%neutral_diffusion_CSp)
339 do j=js-1,je ;
do i=is,ie
340 coef_y(i,j) = i_numitts * khdt_y(i,j)
344 coef_x(i,j) = i_numitts * khdt_x(i,j)
349 if (cs%show_call_tree)
call calltree_waypoint(
"Calling neutral diffusion (tracer_hordiff)",itt)
352 call do_group_pass(cs%pass_t, g%Domain)
357 reg%Tr(m)%name, cs%neutral_diffusion_CSp)
363 if (cs%show_call_tree)
call calltree_waypoint(
"Calculating horizontal diffusion (tracer_hordiff)")
366 call do_group_pass(cs%pass_t, g%Domain)
373 if (cs%Diffuse_ML_interior)
then 375 if (cs%ML_KhTr_scale <= 0.0) cycle
376 scale = i_numitts * cs%ML_KhTr_scale
378 if ((k>gv%nkml) .and. (k<=gv%nk_rho_varies)) cycle
381 do j=js-1,je ;
do i=is,ie
382 coef_y(i,j) = ((scale * khdt_y(i,j))*2.0*(h(i,j,k)*h(i,j+1,k))) / &
383 (h(i,j,k)+h(i,j+1,k)+h_neglect)
388 coef_x(i,j) = ((scale * khdt_x(i,j))*2.0*(h(i,j,k)*h(i+1,j,k))) / &
389 (h(i,j,k)+h(i+1,j,k)+h_neglect)
393 ihdxdy(i,j) = g%IareaT(i,j) / (h(i,j,k)+h_neglect)
398 do j=js,je ;
do i=is,ie
399 dtr(i,j) = ihdxdy(i,j) * &
400 ((coef_x(i-1,j) * (reg%Tr(m)%t(i-1,j,k) - reg%Tr(m)%t(i,j,k)) - &
401 coef_x(i,j) * (reg%Tr(m)%t(i,j,k) - reg%Tr(m)%t(i+1,j,k))) + &
402 (coef_y(i,j-1) * (reg%Tr(m)%t(i,j-1,k) - reg%Tr(m)%t(i,j,k)) - &
403 coef_y(i,j) * (reg%Tr(m)%t(i,j,k) - reg%Tr(m)%t(i,j+1,k))))
405 if (
associated(reg%Tr(m)%df_x))
then ;
do j=js,je ;
do i=g%IscB,g%IecB
406 reg%Tr(m)%df_x(i,j,k) = reg%Tr(m)%df_x(i,j,k) + coef_x(i,j) * &
407 (reg%Tr(m)%t(i,j,k) - reg%Tr(m)%t(i+1,j,k))*idt
408 enddo ;
enddo ;
endif 409 if (
associated(reg%Tr(m)%df_y))
then ;
do j=g%JscB,g%JecB ;
do i=is,ie
410 reg%Tr(m)%df_y(i,j,k) = reg%Tr(m)%df_y(i,j,k) + coef_y(i,j) * &
411 (reg%Tr(m)%t(i,j,k) - reg%Tr(m)%t(i,j+1,k))*idt
412 enddo ;
enddo ;
endif 413 if (
associated(reg%Tr(m)%df2d_x))
then ;
do j=js,je ;
do i=g%IscB,g%IecB
414 reg%Tr(m)%df2d_x(i,j) = reg%Tr(m)%df2d_x(i,j) + coef_x(i,j) * &
415 (reg%Tr(m)%t(i,j,k) - reg%Tr(m)%t(i+1,j,k))*idt
416 enddo ;
enddo ;
endif 417 if (
associated(reg%Tr(m)%df2d_y))
then ;
do j=g%JscB,g%JecB ;
do i=is,ie
418 reg%Tr(m)%df2d_y(i,j) = reg%Tr(m)%df2d_y(i,j) + coef_y(i,j) * &
419 (reg%Tr(m)%t(i,j,k) - reg%Tr(m)%t(i,j+1,k))*idt
420 enddo ;
enddo ;
endif 421 do j=js,je ;
do i=is,ie
422 reg%Tr(m)%t(i,j,k) = reg%Tr(m)%t(i,j,k) + dtr(i,j)
434 if (cs%Diffuse_ML_interior)
then 435 if (cs%show_call_tree)
call calltree_waypoint(
"Calling epipycnal_ML_diff (tracer_hordiff)")
447 if (cs%id_KhTr_u > 0)
then 448 do j=js,je ;
do i=is-1,ie
449 kh_u(i,j) = g%mask2dCu(i,j)*kh_u(i,j)
451 call post_data(cs%id_KhTr_u, kh_u, cs%diag, mask=g%mask2dCu)
453 if (cs%id_KhTr_v > 0)
then 454 do j=js-1,je ;
do i=is,ie
455 kh_v(i,j) = g%mask2dCv(i,j)*kh_v(i,j)
457 call post_data(cs%id_KhTr_v, kh_v, cs%diag, mask=g%mask2dCv)
459 if (cs%id_KhTr_h > 0)
then 461 do j=js,je ;
do i=is-1,ie
462 kh_u(i,j) = g%mask2dCu(i,j)*kh_u(i,j)
464 do j=js-1,je ;
do i=is,ie
465 kh_v(i,j) = g%mask2dCv(i,j)*kh_v(i,j)
467 do j=js,je ;
do i=is,ie
468 normalize = 1.0 / ((g%mask2dCu(i-1,j)+g%mask2dCu(i,j)) + &
469 (g%mask2dCv(i,j-1)+g%mask2dCv(i,j)) + gv%H_subroundoff)
470 kh_h(i,j) = normalize*g%mask2dT(i,j)*((kh_u(i-1,j)+kh_u(i,j)) + &
471 (kh_v(i,j-1)+kh_v(i,j)))
473 call post_data(cs%id_KhTr_h, kh_h, cs%diag, mask=g%mask2dT)
478 call uvchksum(
"After tracer diffusion khdt_[xy]", &
479 khdt_x, khdt_y, g%HI, haloshift=0, symmetric=.true.)
480 call uvchksum(
"After tracer diffusion Coef_[xy]", &
481 coef_x, coef_y, g%HI, haloshift=0, symmetric=.true.)
484 if (cs%id_khdt_x > 0)
call post_data(cs%id_khdt_x, khdt_x, cs%diag)
485 if (cs%id_khdt_y > 0)
call post_data(cs%id_khdt_y, khdt_y, cs%diag)
496 GV, CS, tv, num_itts)
499 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
500 real,
intent(in) :: dt
502 integer,
intent(in) :: ntr
503 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in) :: khdt_epi_x
504 real,
dimension(SZI_(G),SZJB_(G)),
intent(in) :: khdt_epi_y
507 integer,
intent(in) :: num_itts
510 real,
dimension(SZI_(G), SZJ_(G)) :: &
512 real,
dimension(SZI_(G), SZJ_(G), max(1,GV%nk_rho_varies)) :: &
517 type(
p2d),
dimension(SZJ_(G)) :: &
518 deep_wt_Lu, deep_wt_Ru, &
521 type(
p2d),
dimension(SZJB_(G)) :: &
522 deep_wt_Lv, deep_wt_Rv, &
525 type(
p2di),
dimension(SZJ_(G)) :: &
528 type(
p2di),
dimension(SZJB_(G)) :: &
532 real,
dimension(SZI_(G), SZJ_(G), SZK_(G)) :: &
534 real,
dimension(SZI_(G), SZJ_(G), SZK_(G)) :: Tr_flux_3d, Tr_adj_vert_L, Tr_adj_vert_R
536 real,
dimension(SZI_(G), SZK_(G), SZJ_(G)) :: &
539 integer,
dimension(SZI_(G), SZK_(G), SZJ_(G)) :: &
543 real,
dimension(SZK_(G)) :: &
550 integer,
dimension(SZK_(G)) :: &
554 integer,
dimension(SZI_(G), SZJ_(G)) :: &
560 integer,
dimension(SZJ_(G)) :: &
562 integer,
dimension(SZIB_(G), SZJ_(G)) :: &
564 integer,
dimension(SZI_(G), SZJB_(G)) :: &
570 real :: rho_pair, rho_a, rho_b
583 logical,
dimension(SZK_(G)) :: &
587 real :: p_ref_cv(szi_(g))
589 integer :: k_max, k_min, k_test, itmp
590 integer :: i, j, k, k2, m, is, ie, js, je, nz, nkmb
591 integer :: isd, ied, jsd, jed, IsdB, IedB, k_size
592 integer :: kL, kR, kLa, kLb, kRa, kRb, nP, itt, ns, max_itt
593 integer :: PEmax_kRho
594 integer :: isv, iev, jsv, jev
596 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
597 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
598 isdb = g%IsdB ; iedb = g%IedB
600 nkmb = gv%nk_rho_varies
602 if (num_itts <= 1)
then 603 max_itt = 1 ; i_maxitt = 1.0
605 max_itt = num_itts ; i_maxitt = 1.0 / (
real(max_itt))
608 do i=is-2,ie+2 ; p_ref_cv(i) = tv%P_Ref ;
enddo 611 call do_group_pass(cs%pass_t, g%Domain)
618 rho_coord(:,j,k), is-2, ie-is+5, tv%eqn_of_state)
622 do j=js-2,je+2 ;
do i=is-2,ie+2
623 rml_max(i,j) = rho_coord(i,j,1)
624 num_srt(i,j) = 0 ; max_krho(i,j) = 0
626 do k=2,nkmb ;
do j=js-2,je+2 ;
do i=is-2,ie+2
627 if (rml_max(i,j) < rho_coord(i,j,k)) rml_max(i,j) = rho_coord(i,j,k)
628 enddo ;
enddo ;
enddo 634 do j=js-2,je+2 ;
do i=is-2,ie+2 ;
if (g%mask2dT(i,j) > 0.5)
then 635 if (rml_max(i,j) > gv%Rlay(nz))
then ; max_krho(i,j) = nz+1
636 elseif (rml_max(i,j) <= gv%Rlay(nkmb+1))
then ; max_krho(i,j) = nkmb+1
638 k_min = nkmb+2 ; k_max = nz
640 k_test = (k_min + k_max) / 2
641 if (rml_max(i,j) <= gv%Rlay(k_test-1))
then ; k_max = k_test-1
642 elseif (gv%Rlay(k_test) < rml_max(i,j))
then ; k_min = k_test+1
643 else ; max_krho(i,j) = k_test ;
exit ;
endif 645 if (k_min == k_max)
then ; max_krho(i,j) = k_max ;
exit ;
endif 648 endif ;
enddo ;
enddo 651 do j=js-1,je+1 ;
do i=is-1,ie+1
652 k_end_srt(i,j) = max(max_krho(i,j), max_krho(i-1,j), max_krho(i+1,j), &
653 max_krho(i,j-1), max_krho(i,j+1))
654 if (pemax_krho < k_end_srt(i,j)) pemax_krho = k_end_srt(i,j)
656 if (pemax_krho > nz) pemax_krho = nz
658 h_exclude = 10.0*(gv%Angstrom + gv%H_subroundoff)
664 do k=1,nkmb ;
do i=is-1,ie+1 ;
if (g%mask2dT(i,j) > 0.5)
then 665 if (h(i,j,k) > h_exclude)
then 666 num_srt(i,j) = num_srt(i,j) + 1 ; ns = num_srt(i,j)
668 rho_srt(i,ns,j) = rho_coord(i,j,k)
669 h_srt(i,ns,j) = h(i,j,k)
671 endif ;
enddo ;
enddo 672 do k=nkmb+1,pemax_krho ;
do i=is-1,ie+1 ;
if (g%mask2dT(i,j) > 0.5)
then 673 if ((k<=k_end_srt(i,j)) .and. (h(i,j,k) > h_exclude))
then 674 num_srt(i,j) = num_srt(i,j) + 1 ; ns = num_srt(i,j)
676 rho_srt(i,ns,j) = gv%Rlay(k)
677 h_srt(i,ns,j) = h(i,j,k)
679 endif ;
enddo ;
enddo 684 do j=js-1,je+1;
do i=is-1,ie+1
685 do k=2,num_srt(i,j) ;
if (rho_srt(i,k,j) < rho_srt(i,k-1,j))
then 687 do k2 = k,2,-1 ;
if (rho_srt(i,k2,j) >= rho_srt(i,k2-1,j))
exit 688 itmp = k0_srt(i,k2-1,j) ; k0_srt(i,k2-1,j) = k0_srt(i,k2,j) ; k0_srt(i,k2,j) = itmp
689 tmp = rho_srt(i,k2-1,j) ; rho_srt(i,k2-1,j) = rho_srt(i,k2,j) ; rho_srt(i,k2,j) = tmp
690 tmp = h_srt(i,k2-1,j) ; h_srt(i,k2-1,j) = h_srt(i,k2,j) ; h_srt(i,k2,j) = tmp
697 do i=is-1,ie+1 ; max_srt(j) = max(max_srt(j), num_srt(i,j)) ;
enddo 702 k_size = max(2*max_srt(j),1)
703 allocate(deep_wt_lu(j)%p(isdb:iedb,k_size))
704 allocate(deep_wt_ru(j)%p(isdb:iedb,k_size))
705 allocate(hp_lu(j)%p(isdb:iedb,k_size))
706 allocate(hp_ru(j)%p(isdb:iedb,k_size))
707 allocate(k0a_lu(j)%p(isdb:iedb,k_size))
708 allocate(k0a_ru(j)%p(isdb:iedb,k_size))
709 allocate(k0b_lu(j)%p(isdb:iedb,k_size))
710 allocate(k0b_ru(j)%p(isdb:iedb,k_size))
720 do j=js,je ;
do i=is-1,ie ;
if (g%mask2dCu(i,j) > 0.5)
then 723 do k=1,num_srt(i,j) ; h_demand_l(k) = 0.0 ; h_used_l(k) = 0.0 ;
enddo 724 do k=1,num_srt(i+1,j) ; h_demand_r(k) = 0.0 ; h_used_r(k) = 0.0 ;
enddo 731 if (rho_srt(i,1,j) < rho_srt(i+1,1,j))
then 733 do kl=2,num_srt(i,j) ;
if (rho_srt(i,kl,j) >= rho_srt(i+1,1,j))
exit ;
enddo 734 elseif (rho_srt(i+1,1,j) < rho_srt(i,1,j))
then 736 do kr=2,num_srt(i+1,j) ;
if (rho_srt(i+1,kr,j) >= rho_srt(i,1,j))
exit ;
enddo 742 if ((kl > num_srt(i,j)) .or. (kr > num_srt(i+1,j)))
exit 744 if (rho_srt(i,kl,j) > rho_srt(i+1,kr,j))
then 747 rho_pair = rho_srt(i+1,kr,j)
749 k0b_lu(j)%p(i,k) = k0_srt(i,kl,j) ; k0b_ru(j)%p(i,k) = k0_srt(i+1,kr,j)
750 k0a_lu(j)%p(i,k) = k0_srt(i,kl-1,j) ; k0a_ru(j)%p(i,k) = k0b_ru(j)%p(i,k)
751 kbs_lp(k) = kl ; kbs_rp(k) = kr
753 rho_a = rho_srt(i,kl-1,j) ; rho_b = rho_srt(i,kl,j)
754 wt_b = 1.0 ;
if (abs(rho_a - rho_b) > abs(rho_pair - rho_a)) &
755 wt_b = (rho_pair - rho_a) / (rho_b - rho_a)
756 deep_wt_lu(j)%p(i,k) = wt_b ; deep_wt_ru(j)%p(i,k) = 1.0
758 h_demand_l(kl) = h_demand_l(kl) + 0.5*h_srt(i+1,kr,j) * wt_b
759 h_demand_l(kl-1) = h_demand_l(kl-1) + 0.5*h_srt(i+1,kr,j) * (1.0-wt_b)
761 kr = kr+1 ; left_set(k) = .false. ; right_set(k) = .true.
762 elseif (rho_srt(i,kl,j) < rho_srt(i+1,kr,j))
then 765 rho_pair = rho_srt(i,kl,j)
766 k0b_lu(j)%p(i,k) = k0_srt(i,kl,j) ; k0b_ru(j)%p(i,k) = k0_srt(i+1,kr,j)
767 k0a_lu(j)%p(i,k) = k0b_lu(j)%p(i,k) ; k0a_ru(j)%p(i,k) = k0_srt(i+1,kr-1,j)
769 kbs_lp(k) = kl ; kbs_rp(k) = kr
771 rho_a = rho_srt(i+1,kr-1,j) ; rho_b = rho_srt(i+1,kr,j)
772 wt_b = 1.0 ;
if (abs(rho_a - rho_b) > abs(rho_pair - rho_a)) &
773 wt_b = (rho_pair - rho_a) / (rho_b - rho_a)
774 deep_wt_lu(j)%p(i,k) = 1.0 ; deep_wt_ru(j)%p(i,k) = wt_b
776 h_demand_r(kr) = h_demand_r(kr) + 0.5*h_srt(i,kl,j) * wt_b
777 h_demand_r(kr-1) = h_demand_r(kr-1) + 0.5*h_srt(i,kl,j) * (1.0-wt_b)
779 kl = kl+1 ; left_set(k) = .true. ; right_set(k) = .false.
780 elseif ((k0_srt(i,kl,j) <= nkmb) .or. (k0_srt(i+1,kr,j) <= nkmb))
then 783 k0b_lu(j)%p(i,k) = k0_srt(i,kl,j) ; k0b_ru(j)%p(i,k) = k0_srt(i+1,kr,j)
784 k0a_lu(j)%p(i,k) = k0b_lu(j)%p(i,k) ; k0a_ru(j)%p(i,k) = k0b_ru(j)%p(i,k)
785 kbs_lp(k) = kl ; kbs_rp(k) = kr
786 deep_wt_lu(j)%p(i,k) = 1.0 ; deep_wt_ru(j)%p(i,k) = 1.0
788 h_demand_l(kl) = h_demand_l(kl) + 0.5*h_srt(i+1,kr,j)
789 h_demand_r(kr) = h_demand_r(kr) + 0.5*h_srt(i,kl,j)
791 kl = kl+1 ; kr = kr+1 ; left_set(k) = .true. ; right_set(k) = .true.
795 h_demand_l(kl) = h_demand_l(kl) + 0.5*h_srt(i+1,kr,j)
796 h_demand_r(kr) = h_demand_r(kr) + 0.5*h_srt(i,kl,j)
798 kl = kl+1 ; kr = kr+1
804 do k=1,num_srt(i+1,j)
805 h_supply_frac_r(k) = 1.0
806 if (h_demand_r(k) > 0.5*h_srt(i+1,k,j)) &
807 h_supply_frac_r(k) = 0.5*h_srt(i+1,k,j) / h_demand_r(k)
810 h_supply_frac_l(k) = 1.0
811 if (h_demand_l(k) > 0.5*h_srt(i,k,j)) &
812 h_supply_frac_l(k) = 0.5*h_srt(i,k,j) / h_demand_l(k)
817 kl = kbs_lp(k) ; kr = kbs_rp(k)
818 hp_lu(j)%p(i,k) = 0.0 ; hp_ru(j)%p(i,k) = 0.0
819 if (left_set(k))
then 820 if (deep_wt_ru(j)%p(i,k) < 1.0)
then 821 hp_ru(j)%p(i,k) = 0.5*h_srt(i,kl,j) * min(h_supply_frac_r(kr), h_supply_frac_r(kr-1))
822 wt_b = deep_wt_ru(j)%p(i,k)
823 h_used_r(kr-1) = h_used_r(kr-1) + (1.0 - wt_b)*hp_ru(j)%p(i,k)
824 h_used_r(kr) = h_used_r(kr) + wt_b*hp_ru(j)%p(i,k)
826 hp_ru(j)%p(i,k) = 0.5*h_srt(i,kl,j) * h_supply_frac_r(kr)
827 h_used_r(kr) = h_used_r(kr) + hp_ru(j)%p(i,k)
830 if (right_set(k))
then 831 if (deep_wt_lu(j)%p(i,k) < 1.0)
then 832 hp_lu(j)%p(i,k) = 0.5*h_srt(i+1,kr,j) * min(h_supply_frac_l(kl), h_supply_frac_l(kl-1))
833 wt_b = deep_wt_lu(j)%p(i,k)
834 h_used_l(kl-1) = h_used_l(kl-1) + (1.0 - wt_b)*hp_lu(j)%p(i,k)
835 h_used_l(kl) = h_used_l(kl) + wt_b*hp_lu(j)%p(i,k)
837 hp_lu(j)%p(i,k) = 0.5*h_srt(i+1,kr,j) * h_supply_frac_l(kl)
838 h_used_l(kl) = h_used_l(kl) + hp_lu(j)%p(i,k)
846 if (left_set(k)) hp_lu(j)%p(i,k) = hp_lu(j)%p(i,k) + &
847 (h_srt(i,kbs_lp(k),j) - h_used_l(kbs_lp(k)))
848 if (right_set(k)) hp_ru(j)%p(i,k) = hp_ru(j)%p(i,k) + &
849 (h_srt(i+1,kbs_rp(k),j) - h_used_r(kbs_rp(k)))
852 endif ;
enddo ;
enddo 855 k_size = max(max_srt(j)+max_srt(j+1),1)
856 allocate(deep_wt_lv(j)%p(isd:ied,k_size))
857 allocate(deep_wt_rv(j)%p(isd:ied,k_size))
858 allocate(hp_lv(j)%p(isd:ied,k_size))
859 allocate(hp_rv(j)%p(isd:ied,k_size))
860 allocate(k0a_lv(j)%p(isd:ied,k_size))
861 allocate(k0a_rv(j)%p(isd:ied,k_size))
862 allocate(k0b_lv(j)%p(isd:ied,k_size))
863 allocate(k0b_rv(j)%p(isd:ied,k_size))
873 do j=js-1,je ;
do i=is,ie ;
if (g%mask2dCv(i,j) > 0.5)
then 876 do k=1,num_srt(i,j) ; h_demand_l(k) = 0.0 ; h_used_l(k) = 0.0 ;
enddo 877 do k=1,num_srt(i,j+1) ; h_demand_r(k) = 0.0 ; h_used_r(k) = 0.0 ;
enddo 884 if (rho_srt(i,1,j) < rho_srt(i,1,j+1))
then 886 do kl=2,num_srt(i,j) ;
if (rho_srt(i,kl,j) >= rho_srt(i,1,j+1))
exit ;
enddo 887 elseif (rho_srt(i,1,j+1) < rho_srt(i,1,j))
then 889 do kr=2,num_srt(i,j+1) ;
if (rho_srt(i,kr,j+1) >= rho_srt(i,1,j))
exit ;
enddo 895 if ((kl > num_srt(i,j)) .or. (kr > num_srt(i,j+1)))
exit 897 if (rho_srt(i,kl,j) > rho_srt(i,kr,j+1))
then 900 rho_pair = rho_srt(i,kr,j+1)
902 k0b_lv(j)%p(i,k) = k0_srt(i,kl,j) ; k0b_rv(j)%p(i,k) = k0_srt(i,kr,j+1)
903 k0a_lv(j)%p(i,k) = k0_srt(i,kl-1,j) ; k0a_rv(j)%p(i,k) = k0b_rv(j)%p(i,k)
904 kbs_lp(k) = kl ; kbs_rp(k) = kr
906 rho_a = rho_srt(i,kl-1,j) ; rho_b = rho_srt(i,kl,j)
907 wt_b = 1.0 ;
if (abs(rho_a - rho_b) > abs(rho_pair - rho_a)) &
908 wt_b = (rho_pair - rho_a) / (rho_b - rho_a)
909 deep_wt_lv(j)%p(i,k) = wt_b ; deep_wt_rv(j)%p(i,k) = 1.0
911 h_demand_l(kl) = h_demand_l(kl) + 0.5*h_srt(i,kr,j+1) * wt_b
912 h_demand_l(kl-1) = h_demand_l(kl-1) + 0.5*h_srt(i,kr,j+1) * (1.0-wt_b)
914 kr = kr+1 ; left_set(k) = .false. ; right_set(k) = .true.
915 elseif (rho_srt(i,kl,j) < rho_srt(i,kr,j+1))
then 918 rho_pair = rho_srt(i,kl,j)
919 k0b_lv(j)%p(i,k) = k0_srt(i,kl,j) ; k0b_rv(j)%p(i,k) = k0_srt(i,kr,j+1)
920 k0a_lv(j)%p(i,k) = k0b_lv(j)%p(i,k) ; k0a_rv(j)%p(i,k) = k0_srt(i,kr-1,j+1)
922 kbs_lp(k) = kl ; kbs_rp(k) = kr
924 rho_a = rho_srt(i,kr-1,j+1) ; rho_b = rho_srt(i,kr,j+1)
925 wt_b = 1.0 ;
if (abs(rho_a - rho_b) > abs(rho_pair - rho_a)) &
926 wt_b = (rho_pair - rho_a) / (rho_b - rho_a)
927 deep_wt_lv(j)%p(i,k) = 1.0 ; deep_wt_rv(j)%p(i,k) = wt_b
929 h_demand_r(kr) = h_demand_r(kr) + 0.5*h_srt(i,kl,j) * wt_b
930 h_demand_r(kr-1) = h_demand_r(kr-1) + 0.5*h_srt(i,kl,j) * (1.0-wt_b)
932 kl = kl+1 ; left_set(k) = .true. ; right_set(k) = .false.
933 elseif ((k0_srt(i,kl,j) <= nkmb) .or. (k0_srt(i,kr,j+1) <= nkmb))
then 936 k0b_lv(j)%p(i,k) = k0_srt(i,kl,j) ; k0b_rv(j)%p(i,k) = k0_srt(i,kr,j+1)
937 k0a_lv(j)%p(i,k) = k0b_lv(j)%p(i,k) ; k0a_rv(j)%p(i,k) = k0b_rv(j)%p(i,k)
938 kbs_lp(k) = kl ; kbs_rp(k) = kr
939 deep_wt_lv(j)%p(i,k) = 1.0 ; deep_wt_rv(j)%p(i,k) = 1.0
941 h_demand_l(kl) = h_demand_l(kl) + 0.5*h_srt(i,kr,j+1)
942 h_demand_r(kr) = h_demand_r(kr) + 0.5*h_srt(i,kl,j)
944 kl = kl+1 ; kr = kr+1 ; left_set(k) = .true. ; right_set(k) = .true.
948 h_demand_l(kl) = h_demand_l(kl) + 0.5*h_srt(i,kr,j+1)
949 h_demand_r(kr) = h_demand_r(kr) + 0.5*h_srt(i,kl,j)
951 kl = kl+1 ; kr = kr+1
957 do k=1,num_srt(i,j+1)
958 h_supply_frac_r(k) = 1.0
959 if (h_demand_r(k) > 0.5*h_srt(i,k,j+1)) &
960 h_supply_frac_r(k) = 0.5*h_srt(i,k,j+1) / h_demand_r(k)
963 h_supply_frac_l(k) = 1.0
964 if (h_demand_l(k) > 0.5*h_srt(i,k,j)) &
965 h_supply_frac_l(k) = 0.5*h_srt(i,k,j) / h_demand_l(k)
970 kl = kbs_lp(k) ; kr = kbs_rp(k)
971 hp_lv(j)%p(i,k) = 0.0 ; hp_rv(j)%p(i,k) = 0.0
972 if (left_set(k))
then 973 if (deep_wt_rv(j)%p(i,k) < 1.0)
then 974 hp_rv(j)%p(i,k) = 0.5*h_srt(i,kl,j) * min(h_supply_frac_r(kr), h_supply_frac_r(kr-1))
975 wt_b = deep_wt_rv(j)%p(i,k)
976 h_used_r(kr-1) = h_used_r(kr-1) + (1.0 - wt_b) * hp_rv(j)%p(i,k)
977 h_used_r(kr) = h_used_r(kr) + wt_b * hp_rv(j)%p(i,k)
979 hp_rv(j)%p(i,k) = 0.5*h_srt(i,kl,j) * h_supply_frac_r(kr)
980 h_used_r(kr) = h_used_r(kr) + hp_rv(j)%p(i,k)
983 if (right_set(k))
then 984 if (deep_wt_lv(j)%p(i,k) < 1.0)
then 985 hp_lv(j)%p(i,k) = 0.5*h_srt(i,kr,j+1) * min(h_supply_frac_l(kl), h_supply_frac_l(kl-1))
986 wt_b = deep_wt_lv(j)%p(i,k)
987 h_used_l(kl-1) = h_used_l(kl-1) + (1.0 - wt_b) * hp_lv(j)%p(i,k)
988 h_used_l(kl) = h_used_l(kl) + wt_b * hp_lv(j)%p(i,k)
990 hp_lv(j)%p(i,k) = 0.5*h_srt(i,kr,j+1) * h_supply_frac_l(kl)
991 h_used_l(kl) = h_used_l(kl) + hp_lv(j)%p(i,k)
999 if (left_set(k)) hp_lv(j)%p(i,k) = hp_lv(j)%p(i,k) + &
1000 (h_srt(i,kbs_lp(k),j) - h_used_l(kbs_lp(k)))
1001 if (right_set(k)) hp_rv(j)%p(i,k) = hp_rv(j)%p(i,k) + &
1002 (h_srt(i,kbs_rp(k),j+1) - h_used_r(kbs_rp(k)))
1006 endif ;
enddo ;
enddo 1011 do k=1,pemax_krho ;
do j=js-1,je+1 ;
do i=is-1,ie+1
1012 tr_flux_conv(i,j,k) = 0.0
1013 enddo ;
enddo ;
enddo 1019 call do_group_pass(cs%pass_t, g%Domain)
1030 do j=js,je ;
do i=is-1,ie ;
if (g%mask2dCu(i,j) > 0.5)
then 1034 if (npu(i,j) >= 1)
then 1035 tr_min_face = min(tr(m)%t(i,j,1), tr(m)%t(i+1,j,1))
1036 tr_max_face = max(tr(m)%t(i,j,1), tr(m)%t(i+1,j,1))
1038 tr_min_face = min(tr_min_face, tr(m)%t(i,j,k), tr(m)%t(i+1,j,k))
1039 tr_max_face = max(tr_max_face, tr(m)%t(i,j,k), tr(m)%t(i+1,j,k))
1043 kla = nkmb+1 ;
if (max_krho(i,j) < nz+1) kla = max_krho(i,j)
1044 klb = kla ;
if (max_krho(i,j) < nz) klb = max_krho(i,j)+1
1045 kra = nkmb+1 ;
if (max_krho(i+1,j) < nz+1) kra = max_krho(i+1,j)
1046 krb = kra ;
if (max_krho(i+1,j) < nz) krb = max_krho(i+1,j)+1
1047 tr_la = tr_min_face ; tr_lb = tr_la ; tr_ra = tr_la ; tr_rb = tr_la
1048 if (h(i,j,kla) > h_exclude) tr_la = tr(m)%t(i,j,kla)
1049 if (h(i,j,klb) > h_exclude) tr_la = tr(m)%t(i,j,klb)
1050 if (h(i+1,j,kra) > h_exclude) tr_ra = tr(m)%t(i+1,j,kra)
1051 if (h(i+1,j,krb) > h_exclude) tr_rb = tr(m)%t(i+1,j,krb)
1052 tr_min_face = min(tr_min_face, tr_la, tr_lb, tr_ra, tr_rb)
1053 tr_max_face = max(tr_max_face, tr_la, tr_lb, tr_ra, tr_rb)
1057 tr_lb = tr(m)%t(i,j,k0b_lu(j)%p(i,k))
1058 tr_rb = tr(m)%t(i+1,j,k0b_ru(j)%p(i,k))
1059 tr_la = tr_lb ; tr_ra = tr_rb
1060 if (deep_wt_lu(j)%p(i,k) < 1.0) tr_la = tr(m)%t(i,j,k0a_lu(j)%p(i,k))
1061 if (deep_wt_ru(j)%p(i,k) < 1.0) tr_ra = tr(m)%t(i+1,j,k0a_ru(j)%p(i,k))
1062 tr_min_face = min(tr_min_face, tr_la, tr_lb, tr_ra, tr_rb)
1063 tr_max_face = max(tr_max_face, tr_la, tr_lb, tr_ra, tr_rb)
1068 klb = k0b_lu(j)%p(i,k) ; tr_lb = tr(m)%t(i,j,klb) ; tr_av_l = tr_lb
1069 if (deep_wt_lu(j)%p(i,k) < 1.0)
then 1070 kla = k0a_lu(j)%p(i,k) ; tr_la = tr(m)%t(i,j,kla)
1071 wt_b = deep_wt_lu(j)%p(i,k)
1072 tr_av_l = wt_b*tr_lb + (1.0-wt_b)*tr_la
1075 krb = k0b_ru(j)%p(i,k) ; tr_rb = tr(m)%t(i+1,j,krb) ; tr_av_r = tr_rb
1076 if (deep_wt_ru(j)%p(i,k) < 1.0)
then 1077 kra = k0a_ru(j)%p(i,k) ; tr_ra = tr(m)%t(i+1,j,kra)
1078 wt_b = deep_wt_ru(j)%p(i,k)
1079 tr_av_r = wt_b*tr_rb + (1.0-wt_b)*tr_ra
1082 h_l = hp_lu(j)%p(i,k) ; h_r = hp_ru(j)%p(i,k)
1083 tr_flux = i_maxitt * khdt_epi_x(i,j) * (tr_av_l - tr_av_r) * &
1084 ((2.0 * h_l * h_r) / (h_l + h_r))
1087 if (deep_wt_lu(j)%p(i,k) >= 1.0)
then 1088 tr_flux_conv(i,j,klb) = tr_flux_conv(i,j,klb) - tr_flux
1091 wt_b = deep_wt_lu(j)%p(i,k) ; wt_a = 1.0 - wt_b
1092 vol = hp_lu(j)%p(i,k) * g%areaT(i,j)
1100 if (tr_flux > 0.0)
then 1101 if (tr_la < tr_lb)
then ;
if (vol*(tr_la-tr_min_face) < tr_flux) &
1102 tr_adj_vert = -wt_a * min(tr_flux - vol * (tr_la-tr_min_face), &
1103 (vol*wt_b) * (tr_lb - tr_la))
1104 else ;
if (vol*(tr_lb-tr_min_face) < tr_flux) &
1105 tr_adj_vert = wt_b * min(tr_flux - vol * (tr_lb-tr_min_face), &
1106 (vol*wt_a) * (tr_la - tr_lb))
1108 elseif (tr_flux < 0.0)
then 1109 if (tr_la > tr_lb)
then ;
if (vol * (tr_max_face-tr_la) < -tr_flux) &
1110 tr_adj_vert = wt_a * min(-tr_flux - vol * (tr_max_face-tr_la), &
1111 (vol*wt_b) * (tr_la - tr_lb))
1112 else ;
if (vol*(tr_max_face-tr_lb) < -tr_flux) &
1113 tr_adj_vert = -wt_b * min(-tr_flux - vol * (tr_max_face-tr_lb), &
1114 (vol*wt_a)*(tr_lb - tr_la))
1118 tr_flux_conv(i,j,kla) = tr_flux_conv(i,j,kla) - (wt_a*tr_flux + tr_adj_vert)
1119 tr_flux_conv(i,j,klb) = tr_flux_conv(i,j,klb) - (wt_b*tr_flux - tr_adj_vert)
1122 if (deep_wt_ru(j)%p(i,k) >= 1.0)
then 1123 tr_flux_conv(i+1,j,krb) = tr_flux_conv(i+1,j,krb) + tr_flux
1126 wt_b = deep_wt_ru(j)%p(i,k) ; wt_a = 1.0 - wt_b
1127 vol = hp_ru(j)%p(i,k) * g%areaT(i+1,j)
1135 if (tr_flux < 0.0)
then 1136 if (tr_ra < tr_rb)
then ;
if (vol * (tr_ra-tr_min_face) < -tr_flux) &
1137 tr_adj_vert = -wt_a * min(-tr_flux - vol * (tr_ra-tr_min_face), &
1138 (vol*wt_b) * (tr_rb - tr_ra))
1139 else ;
if (vol*(tr_rb-tr_min_face) < (-tr_flux)) &
1140 tr_adj_vert = wt_b * min(-tr_flux - vol * (tr_rb-tr_min_face), &
1141 (vol*wt_a) * (tr_ra - tr_rb))
1143 elseif (tr_flux > 0.0)
then 1144 if (tr_ra > tr_rb)
then ;
if (vol * (tr_max_face-tr_ra) < tr_flux) &
1145 tr_adj_vert = wt_a * min(tr_flux - vol * (tr_max_face-tr_ra), &
1146 (vol*wt_b) * (tr_ra - tr_rb))
1147 else ;
if (vol*(tr_max_face-tr_rb) < tr_flux) &
1148 tr_adj_vert = -wt_b * min(tr_flux - vol * (tr_max_face-tr_rb), &
1149 (vol*wt_a)*(tr_rb - tr_ra))
1153 tr_flux_conv(i+1,j,kra) = tr_flux_conv(i+1,j,kra) + &
1154 (wt_a*tr_flux - tr_adj_vert)
1155 tr_flux_conv(i+1,j,krb) = tr_flux_conv(i+1,j,krb) + &
1156 (wt_b*tr_flux + tr_adj_vert)
1158 if (
associated(tr(m)%df2d_x)) &
1159 tr(m)%df2d_x(i,j) = tr(m)%df2d_x(i,j) + tr_flux * idt
1161 endif ;
enddo ;
enddo 1170 do j=js-1,je ;
do i=is,ie ;
if (g%mask2dCv(i,j) > 0.5)
then 1174 if (npv(i,j) >= 1)
then 1175 tr_min_face = min(tr(m)%t(i,j,1), tr(m)%t(i,j+1,1))
1176 tr_max_face = max(tr(m)%t(i,j,1), tr(m)%t(i,j+1,1))
1178 tr_min_face = min(tr_min_face, tr(m)%t(i,j,k), tr(m)%t(i,j+1,k))
1179 tr_max_face = max(tr_max_face, tr(m)%t(i,j,k), tr(m)%t(i,j+1,k))
1183 kla = nkmb+1 ;
if (max_krho(i,j) < nz+1) kla = max_krho(i,j)
1184 klb = kla ;
if (max_krho(i,j) < nz) klb = max_krho(i,j)+1
1185 kra = nkmb+1 ;
if (max_krho(i,j+1) < nz+1) kra = max_krho(i,j+1)
1186 krb = kra ;
if (max_krho(i,j+1) < nz) krb = max_krho(i,j+1)+1
1187 tr_la = tr_min_face ; tr_lb = tr_la ; tr_ra = tr_la ; tr_rb = tr_la
1188 if (h(i,j,kla) > h_exclude) tr_la = tr(m)%t(i,j,kla)
1189 if (h(i,j,klb) > h_exclude) tr_la = tr(m)%t(i,j,klb)
1190 if (h(i,j+1,kra) > h_exclude) tr_ra = tr(m)%t(i,j+1,kra)
1191 if (h(i,j+1,krb) > h_exclude) tr_rb = tr(m)%t(i,j+1,krb)
1192 tr_min_face = min(tr_min_face, tr_la, tr_lb, tr_ra, tr_rb)
1193 tr_max_face = max(tr_max_face, tr_la, tr_lb, tr_ra, tr_rb)
1197 tr_lb = tr(m)%t(i,j,k0b_lv(j)%p(i,k)) ; tr_rb = tr(m)%t(i,j+1,k0b_rv(j)%p(i,k))
1198 tr_la = tr_lb ; tr_ra = tr_rb
1199 if (deep_wt_lv(j)%p(i,k) < 1.0) tr_la = tr(m)%t(i,j,k0a_lv(j)%p(i,k))
1200 if (deep_wt_rv(j)%p(i,k) < 1.0) tr_ra = tr(m)%t(i,j+1,k0a_rv(j)%p(i,k))
1201 tr_min_face = min(tr_min_face, tr_la, tr_lb, tr_ra, tr_rb)
1202 tr_max_face = max(tr_max_face, tr_la, tr_lb, tr_ra, tr_rb)
1207 klb = k0b_lv(j)%p(i,k) ; tr_lb = tr(m)%t(i,j,klb) ; tr_av_l = tr_lb
1208 if (deep_wt_lv(j)%p(i,k) < 1.0)
then 1209 kla = k0a_lv(j)%p(i,k) ; tr_la = tr(m)%t(i,j,kla)
1210 wt_b = deep_wt_lv(j)%p(i,k)
1211 tr_av_l = wt_b * tr_lb + (1.0-wt_b) * tr_la
1214 krb = k0b_rv(j)%p(i,k) ; tr_rb = tr(m)%t(i,j+1,krb) ; tr_av_r = tr_rb
1215 if (deep_wt_rv(j)%p(i,k) < 1.0)
then 1216 kra = k0a_rv(j)%p(i,k) ; tr_ra = tr(m)%t(i,j+1,kra)
1217 wt_b = deep_wt_rv(j)%p(i,k)
1218 tr_av_r = wt_b * tr_rb + (1.0-wt_b) * tr_ra
1221 h_l = hp_lv(j)%p(i,k) ; h_r = hp_rv(j)%p(i,k)
1222 tr_flux = i_maxitt * ((2.0 * h_l * h_r) / (h_l + h_r)) * &
1223 khdt_epi_y(i,j) * (tr_av_l - tr_av_r)
1224 tr_flux_3d(i,j,k) = tr_flux
1226 if (deep_wt_lv(j)%p(i,k) < 1.0)
then 1228 wt_b = deep_wt_lv(j)%p(i,k) ; wt_a = 1.0 - wt_b
1229 vol = hp_lv(j)%p(i,k) * g%areaT(i,j)
1233 if (tr_flux > 0.0)
then 1234 if (tr_la < tr_lb)
then ;
if (vol * (tr_la-tr_min_face) < tr_flux) &
1235 tr_adj_vert = -wt_a * min(tr_flux - vol * (tr_la-tr_min_face), &
1236 (vol*wt_b) * (tr_lb - tr_la))
1237 else ;
if (vol*(tr_lb-tr_min_face) < tr_flux) &
1238 tr_adj_vert = wt_b * min(tr_flux - vol * (tr_lb-tr_min_face), &
1239 (vol*wt_a) * (tr_la - tr_lb))
1241 elseif (tr_flux < 0.0)
then 1242 if (tr_la > tr_lb)
then ;
if (vol * (tr_max_face-tr_la) < -tr_flux) &
1243 tr_adj_vert = wt_a * min(-tr_flux - vol * (tr_max_face-tr_la), &
1244 (vol*wt_b) * (tr_la - tr_lb))
1245 else ;
if (vol*(tr_max_face-tr_lb) < -tr_flux) &
1246 tr_adj_vert = -wt_b * min(-tr_flux - vol * (tr_max_face-tr_lb), &
1247 (vol*wt_a)*(tr_lb - tr_la))
1250 tr_adj_vert_l(i,j,k) = tr_adj_vert
1253 if (deep_wt_rv(j)%p(i,k) < 1.0)
then 1255 wt_b = deep_wt_rv(j)%p(i,k) ; wt_a = 1.0 - wt_b
1256 vol = hp_rv(j)%p(i,k) * g%areaT(i,j+1)
1260 if (tr_flux < 0.0)
then 1261 if (tr_ra < tr_rb)
then ;
if (vol * (tr_ra-tr_min_face) < -tr_flux) &
1262 tr_adj_vert = -wt_a * min(-tr_flux - vol * (tr_ra-tr_min_face), &
1263 (vol*wt_b) * (tr_rb - tr_ra))
1264 else ;
if (vol*(tr_rb-tr_min_face) < (-tr_flux)) &
1265 tr_adj_vert = wt_b * min(-tr_flux - vol * (tr_rb-tr_min_face), &
1266 (vol*wt_a) * (tr_ra - tr_rb))
1268 elseif (tr_flux > 0.0)
then 1269 if (tr_ra > tr_rb)
then ;
if (vol * (tr_max_face-tr_ra) < tr_flux) &
1270 tr_adj_vert = wt_a * min(tr_flux - vol * (tr_max_face-tr_ra), &
1271 (vol*wt_b) * (tr_ra - tr_rb))
1272 else ;
if (vol*(tr_max_face-tr_rb) < tr_flux) &
1273 tr_adj_vert = -wt_b * min(tr_flux - vol * (tr_max_face-tr_rb), &
1274 (vol*wt_a)*(tr_rb - tr_ra))
1277 tr_adj_vert_r(i,j,k) = tr_adj_vert
1279 if (
associated(tr(m)%df2d_y)) &
1280 tr(m)%df2d_y(i,j) = tr(m)%df2d_y(i,j) + tr_flux * idt
1282 endif ;
enddo ;
enddo 1287 do i=is,ie ;
do j=js-1,je ;
if (g%mask2dCv(i,j) > 0.5)
then 1289 klb = k0b_lv(j)%p(i,k); krb = k0b_rv(j)%p(i,k)
1290 if (deep_wt_lv(j)%p(i,k) >= 1.0)
then 1291 tr_flux_conv(i,j,klb) = tr_flux_conv(i,j,klb) - tr_flux_3d(i,j,k)
1293 kla = k0a_lv(j)%p(i,k)
1294 wt_b = deep_wt_lv(j)%p(i,k) ; wt_a = 1.0 - wt_b
1295 tr_flux_conv(i,j,kla) = tr_flux_conv(i,j,kla) - (wt_a*tr_flux_3d(i,j,k) + tr_adj_vert_l(i,j,k))
1296 tr_flux_conv(i,j,klb) = tr_flux_conv(i,j,klb) - (wt_b*tr_flux_3d(i,j,k) - tr_adj_vert_l(i,j,k))
1298 if (deep_wt_rv(j)%p(i,k) >= 1.0)
then 1299 tr_flux_conv(i,j+1,krb) = tr_flux_conv(i,j+1,krb) + tr_flux_3d(i,j,k)
1301 kra = k0a_rv(j)%p(i,k)
1302 wt_b = deep_wt_rv(j)%p(i,k) ; wt_a = 1.0 - wt_b
1303 tr_flux_conv(i,j+1,kra) = tr_flux_conv(i,j+1,kra) + &
1304 (wt_a*tr_flux_3d(i,j,k) - tr_adj_vert_r(i,j,k))
1305 tr_flux_conv(i,j+1,krb) = tr_flux_conv(i,j+1,krb) + &
1306 (wt_b*tr_flux_3d(i,j,k) + tr_adj_vert_r(i,j,k))
1309 endif ;
enddo ;
enddo 1311 do k=1,pemax_krho ;
do j=js,je ;
do i=is,ie
1312 if ((g%mask2dT(i,j) > 0.5) .and. (h(i,j,k) > 0.0))
then 1313 tr(m)%t(i,j,k) = tr(m)%t(i,j,k) + tr_flux_conv(i,j,k) / &
1314 (h(i,j,k)*g%areaT(i,j))
1315 tr_flux_conv(i,j,k) = 0.0
1317 enddo ;
enddo ;
enddo 1323 deallocate(deep_wt_lu(j)%p) ;
deallocate(deep_wt_ru(j)%p)
1324 deallocate(hp_lu(j)%p) ;
deallocate(hp_ru(j)%p)
1325 deallocate(k0a_lu(j)%p) ;
deallocate(k0a_ru(j)%p)
1326 deallocate(k0b_lu(j)%p) ;
deallocate(k0b_ru(j)%p)
1330 deallocate(deep_wt_lv(j)%p) ;
deallocate(deep_wt_rv(j)%p)
1331 deallocate(hp_lv(j)%p) ;
deallocate(hp_rv(j)%p)
1332 deallocate(k0a_lv(j)%p) ;
deallocate(k0a_rv(j)%p)
1333 deallocate(k0b_lv(j)%p) ;
deallocate(k0b_rv(j)%p)
1341 type(time_type),
target,
intent(in) :: Time
1342 type(ocean_grid_type),
intent(in) :: G
1343 type(diag_ctrl),
target,
intent(inout) :: diag
1344 type(param_file_type),
intent(in) :: param_file
1346 type(neutral_diffusion_cs),
pointer :: CSnd
1349 #include "version_variable.h" 1350 character(len=40) :: mdl =
"MOM_tracer_hor_diff" 1351 character(len=256) :: mesg
1353 if (
associated(cs))
then 1354 call mom_error(warning,
"tracer_hor_diff_init called with associated control structure.")
1360 cs%show_call_tree = calltree_showquery()
1363 call log_version(param_file, mdl, version,
"")
1364 call get_param(param_file, mdl,
"KHTR", cs%KhTr, &
1365 "The background along-isopycnal tracer diffusivity.", &
1366 units=
"m2 s-1", default=0.0)
1367 call get_param(param_file, mdl,
"KHTR_SLOPE_CFF", cs%KhTr_Slope_Cff, &
1368 "The scaling coefficient for along-isopycnal tracer \n"//&
1369 "diffusivity using a shear-based (Visbeck-like) \n"//&
1370 "parameterization. A non-zero value enables this param.", &
1371 units=
"nondim", default=0.0)
1372 call get_param(param_file, mdl,
"KHTR_MIN", cs%KhTr_Min, &
1373 "The minimum along-isopycnal tracer diffusivity.", &
1374 units=
"m2 s-1", default=0.0)
1375 call get_param(param_file, mdl,
"KHTR_MAX", cs%KhTr_Max, &
1376 "The maximum along-isopycnal tracer diffusivity.", &
1377 units=
"m2 s-1", default=0.0)
1378 call get_param(param_file, mdl,
"KHTR_PASSIVITY_COEFF", cs%KhTr_passivity_coeff, &
1379 "The coefficient that scales deformation radius over \n"//&
1380 "grid-spacing in passivity, where passiviity is the ratio \n"//&
1381 "between along isopycnal mxiing of tracers to thickness mixing. \n"//&
1382 "A non-zero value enables this parameterization.", &
1383 units=
"nondim", default=0.0)
1384 call get_param(param_file, mdl,
"KHTR_PASSIVITY_MIN", cs%KhTr_passivity_min, &
1385 "The minimum passivity which is the ratio between \n"//&
1386 "along isopycnal mxiing of tracers to thickness mixing. \n", &
1387 units=
"nondim", default=0.5)
1388 call get_param(param_file, mdl,
"DT", cs%dt, fail_if_missing=.true., &
1389 desc=
"The (baroclinic) dynamics time step.", units=
"s")
1392 call get_param(param_file, mdl,
"DIFFUSE_ML_TO_INTERIOR", cs%Diffuse_ML_interior, &
1393 "If true, enable epipycnal mixing between the surface \n"//&
1394 "boundary layer and the interior.", default=.false.)
1395 call get_param(param_file, mdl,
"CHECK_DIFFUSIVE_CFL", cs%check_diffusive_CFL, &
1396 "If true, use enough iterations the diffusion to ensure \n"//&
1397 "that the diffusive equivalent of the CFL limit is not \n"//&
1398 "violated. If false, always use 1 iteration.", default=.false.)
1399 cs%ML_KhTR_scale = 1.0
1400 if (cs%Diffuse_ML_interior)
then 1401 call get_param(param_file, mdl,
"ML_KHTR_SCALE", cs%ML_KhTR_scale, &
1402 "With Diffuse_ML_interior, the ratio of the truly \n"//&
1403 "horizontal diffusivity in the mixed layer to the \n"//&
1404 "epipycnal diffusivity. The valid range is 0 to 1.", &
1405 units=
"nondim", default=1.0)
1408 cs%use_neutral_diffusion = neutral_diffusion_init(time, g, param_file, diag, cs%neutral_diffusion_CSp)
1409 csnd => cs%neutral_diffusion_CSp
1410 if (cs%use_neutral_diffusion .and. cs%Diffuse_ML_interior)
call mom_error(fatal,
"MOM_tracer_hor_diff: "// &
1411 "USE_NEUTRAL_DIFFUSION and DIFFUSE_ML_TO_INTERIOR are mutually exclusive!")
1413 call get_param(param_file, mdl,
"DEBUG", cs%debug, default=.false.)
1415 id_clock_diffuse = cpu_clock_id(
'(Ocean diffuse tracer)', grain=clock_module)
1416 id_clock_epimix = cpu_clock_id(
'(Ocean epipycnal diffuse tracer)',grain=clock_module)
1417 id_clock_pass = cpu_clock_id(
'(Ocean tracer halo updates)', grain=clock_routine)
1418 id_clock_sync = cpu_clock_id(
'(Ocean tracer global synch)', grain=clock_routine)
1425 cs%id_KhTr_u = register_diag_field(
'ocean_model',
'KHTR_u', diag%axesCu1, time, &
1426 'Epipycnal tracer diffusivity at zonal faces of tracer cell',
'meter2 second-1')
1427 cs%id_KhTr_v = register_diag_field(
'ocean_model',
'KHTR_v', diag%axesCv1, time, &
1428 'Epipycnal tracer diffusivity at meridional faces of tracer cell',
'meter2 second-1')
1429 cs%id_KhTr_h = register_diag_field(
'ocean_model',
'KHTR_h', diag%axesT1, time,&
1430 'Epipycnal tracer diffusivity at tracer cell center',
'meter2 second-1', &
1431 cmor_field_name=
'diftrelo', cmor_units=
'm2 sec-1', &
1432 cmor_standard_name=
'ocean_tracer_epineutral_laplacian_diffusivity', &
1433 cmor_long_name =
'Ocean Tracer Epineutral Laplacian Diffusivity')
1435 cs%id_khdt_x = register_diag_field(
'ocean_model',
'KHDT_x', diag%axesCu1, time, &
1436 'Epipycnal tracer diffusivity operator at zonal faces of tracer cell',
'meter2')
1437 cs%id_khdt_y = register_diag_field(
'ocean_model',
'KHDT_y', diag%axesCv1, time, &
1438 'Epipycnal tracer diffusivity operator at meridional faces of tracer cell',
'meter2')
1439 if (cs%check_diffusive_CFL)
then 1440 cs%id_CFL = register_diag_field(
'ocean_model',
'CFL_lateral_diff', diag%axesT1, time,&
1441 'Grid CFL number for lateral/neutral tracer diffusion',
'dimensionless')
1450 call neutral_diffusion_end(cs%neutral_diffusion_CSp)
1451 if (
associated(cs))
deallocate(cs)
subroutine tracer_epipycnal_ml_diff(h, dt, Tr, ntr, khdt_epi_x, khdt_epi_y, G, GV, CS, tv, num_itts)
This subroutine does epipycnal diffusion of all tracers between the mixed and buffer layers and the i...
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
Provides the ocean grid type.
subroutine, public do_group_pass(group, MOM_dom)
subroutine, public mom_tracer_chksum(mesg, Tr, ntr, G)
This subroutine writes out chksums for tracers.
Main routine for lateral (along surface or neutral) diffusion of tracers.
logical function, public neutral_diffusion_init(Time, G, param_file, diag, CS)
Read parameters and allocate control structure for neutral_diffusion module.
subroutine, public calltree_leave(mesg)
Writes a message about leaving a subroutine if call tree reporting is active.
Variable mixing coefficients.
subroutine, public neutral_diffusion(G, GV, h, Coef_x, Coef_y, Tracer, m, dt, name, CS)
Update tracer concentration due to neutral diffusion; layer thickness unchanged by this update...
subroutine, public tracer_hor_diff_end(CS)
Variable mixing coefficients.
subroutine, public calltree_waypoint(mesg, n)
Writes a message about reaching a milestone if call tree reporting is active.
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
subroutine, public neutral_diffusion_calc_coeffs(G, GV, h, T, S, EOS, CS)
Calculate remapping factors for u/v columns used to map adjoining columns to a shared coordinate spac...
Type to carry basic tracer information.
logical function, public is_root_pe()
subroutine, public mom_set_verbosity(verb)
subroutine, public mom_mesg(message, verb, all_print)
Provides subroutines for quantities specific to the equation of state.
logical function, public calltree_showquery()
Returns True, if the verbosity>=6 indicating to show the call tree.
subroutine, public tracer_hordiff(h, dt, MEKE, VarMix, G, GV, CS, Reg, tv, do_online_flag, read_khdt_x, read_khdt_y)
Compute along-coordinate diffusion of all tracers using the diffusivity in CSKhTr, or using space-dependent diffusivity. Multiple iterations are used (if necessary) so that there is no limit on the acceptable time increment.
subroutine, public tracer_hor_diff_init(Time, G, param_file, diag, CS, CSnd)
Initialize lateral tracer diffusion module.
subroutine, public neutral_diffusion_end(CS)
Deallocates neutral_diffusion control structure.
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
A column-wise toolbox for implementing neutral diffusion.
subroutine, public mom_error(level, message, all_print)
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.