6 use mom_cpu_clock,
only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, clock_routine
12 use mom_open_boundary,
only : obc_direction_e, obc_direction_w, obc_direction_n, obc_direction_s
17 implicit none ;
private
19 #include <MOM_memory.h>
21 public continuity_ppm, continuity_ppm_init, continuity_ppm_end, continuity_ppm_stencil
24 integer :: id_clock_update, id_clock_correct
47 real :: cfl_limit_adjust
48 logical :: aggress_adjust
54 logical :: better_iter
57 logical :: use_visc_rem_max
59 logical :: marginal_faces
68 integer :: ish, ieh, jsh, jeh
76 subroutine continuity_ppm(u, v, hin, h, uh, vh, dt, G, GV, US, CS, uhbt, vhbt, OBC, &
77 visc_rem_u, visc_rem_v, u_cor, v_cor, BT_cont)
80 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
82 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
84 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
86 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
88 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
90 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
92 real,
intent(in) :: dt
95 real,
dimension(SZIB_(G),SZJ_(G)), &
96 optional,
intent(in) :: uhbt
98 real,
dimension(SZI_(G),SZJB_(G)), &
99 optional,
intent(in) :: vhbt
102 optional,
pointer :: obc
103 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
104 optional,
intent(in) :: visc_rem_u
110 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
111 optional,
intent(in) :: visc_rem_v
117 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
118 optional,
intent(out) :: u_cor
120 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
121 optional,
intent(out) :: v_cor
130 integer :: is, ie, js, je, nz, stencil
134 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
136 h_min = gv%Angstrom_H
138 if (.not.
associated(cs))
call mom_error(fatal, &
139 "MOM_continuity_PPM: Module must be initialized before it is used.")
140 x_first = (mod(g%first_direction,2) == 0)
142 if (
present(visc_rem_u) .neqv.
present(visc_rem_v))
call mom_error(fatal, &
143 "MOM_continuity_PPM: Either both visc_rem_u and visc_rem_v or neither"// &
144 " one must be present in call to continuity_PPM.")
146 stencil = 3 ;
if (cs%simple_2nd) stencil = 2 ;
if (cs%upwind_1st) stencil = 1
150 lb%ish = g%isc ; lb%ieh = g%iec
151 lb%jsh = g%jsc-stencil ; lb%jeh = g%jec+stencil
152 call zonal_mass_flux(u, hin, uh, dt, g, gv, us, cs, lb, uhbt, obc, visc_rem_u, u_cor, bt_cont)
154 call cpu_clock_begin(id_clock_update)
156 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
157 h(i,j,k) = hin(i,j,k) - dt * g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
160 enddo ;
enddo ;
enddo
161 call cpu_clock_end(id_clock_update)
163 lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
167 call meridional_mass_flux(v, h, vh, dt, g, gv, us, cs, lb, vhbt, obc, visc_rem_v, v_cor, bt_cont)
169 call cpu_clock_begin(id_clock_update)
171 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
172 h(i,j,k) = h(i,j,k) - dt * g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
174 if (h(i,j,k) < h_min) h(i,j,k) = h_min
175 enddo ;
enddo ;
enddo
176 call cpu_clock_end(id_clock_update)
180 lb%ish = g%isc-stencil ; lb%ieh = g%iec+stencil
181 lb%jsh = g%jsc ; lb%jeh = g%jec
183 call meridional_mass_flux(v, hin, vh, dt, g, gv, us, cs, lb, vhbt, obc, visc_rem_v, v_cor, bt_cont)
185 call cpu_clock_begin(id_clock_update)
187 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
188 h(i,j,k) = hin(i,j,k) - dt * g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
189 enddo ;
enddo ;
enddo
190 call cpu_clock_end(id_clock_update)
194 lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
195 call zonal_mass_flux(u, h, uh, dt, g, gv, us, cs, lb, uhbt, obc, visc_rem_u, u_cor, bt_cont)
197 call cpu_clock_begin(id_clock_update)
199 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
200 h(i,j,k) = h(i,j,k) - dt * g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
202 if (h(i,j,k) < h_min) h(i,j,k) = h_min
203 enddo ;
enddo ;
enddo
204 call cpu_clock_end(id_clock_update)
208 end subroutine continuity_ppm
211 subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, US, CS, LB, uhbt, OBC, &
212 visc_rem_u, u_cor, BT_cont)
215 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
217 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
219 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
222 real,
intent(in) :: dt
227 optional,
pointer :: OBC
228 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
229 optional,
intent(in) :: visc_rem_u
234 real,
dimension(SZIB_(G),SZJ_(G)), &
235 optional,
intent(in) :: uhbt
237 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
238 optional,
intent(out) :: u_cor
245 real,
dimension(SZIB_(G),SZK_(G)) :: duhdu
246 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_L, h_R
247 real,
dimension(SZIB_(G)) :: &
254 logical,
dimension(SZIB_(G)) :: do_I
255 real,
dimension(SZIB_(G),SZK_(G)) :: &
257 real,
dimension(SZIB_(G)) :: FAuI
265 integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
267 logical :: local_specified_BC, use_visc_rem, set_BT_cont, any_simple_OBC
268 logical :: local_Flather_OBC, local_open_BC, is_simple
271 use_visc_rem =
present(visc_rem_u)
272 local_specified_bc = .false. ; set_bt_cont = .false. ; local_flather_obc = .false.
273 local_open_bc = .false.
274 if (
present(bt_cont)) set_bt_cont = (
associated(bt_cont))
275 if (
present(obc))
then ;
if (
associated(obc))
then
276 local_specified_bc = obc%specified_u_BCs_exist_globally
277 local_flather_obc = obc%Flather_u_BCs_exist_globally
278 local_open_bc = obc%open_u_BCs_exist_globally
280 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
282 cfl_dt = cs%CFL_limit_adjust / dt
284 if (cs%aggress_adjust) cfl_dt = i_dt
286 call cpu_clock_begin(id_clock_update)
290 if (cs%upwind_1st)
then
291 do j=jsh,jeh ;
do i=ish-1,ieh+1
292 h_l(i,j,k) = h_in(i,j,k) ; h_r(i,j,k) = h_in(i,j,k)
295 call ppm_reconstruction_x(h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), g, lb, &
296 2.0*gv%Angstrom_H, cs%monotonic, simple_2nd=cs%simple_2nd, obc=obc)
298 do i=ish-1,ieh ; visc_rem(i,k) = 1.0 ;
enddo
300 call cpu_clock_end(id_clock_update)
302 call cpu_clock_begin(id_clock_correct)
311 do i=ish-1,ieh ; do_i(i) = .true. ; visc_rem_max(i) = 0.0 ;
enddo
314 if (use_visc_rem)
then ;
do i=ish-1,ieh
315 visc_rem(i,k) = visc_rem_u(i,j,k)
316 visc_rem_max(i) = max(visc_rem_max(i), visc_rem(i,k))
318 call zonal_flux_layer(u(:,j,k), h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), &
319 uh(:,j,k), duhdu(:,k), visc_rem(:,k), &
320 dt, g, us, j, ish, ieh, do_i, cs%vol_CFL, obc)
321 if (local_specified_bc)
then
323 l_seg = obc%segnum_u(i,j)
325 if (l_seg /= obc_none)
then
326 if (obc%segment(l_seg)%specified) &
327 uh(i,j,k) = obc%segment(l_seg)%normal_trans(i,j,k)
333 if ((.not.use_visc_rem).or.(.not.cs%use_visc_rem_max))
then ;
do i=ish-1,ieh
334 visc_rem_max(i) = 1.0
337 if (
present(uhbt) .or. set_bt_cont)
then
342 if (visc_rem_max(i) > 0.0) i_vrm = 1.0 / visc_rem_max(i)
344 dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
345 dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
346 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif
347 du_max_cfl(i) = 2.0* (cfl_dt * dx_w) * i_vrm
348 du_min_cfl(i) = -2.0 * (cfl_dt * dx_e) * i_vrm
349 uh_tot_0(i) = 0.0 ; duhdu_tot_0(i) = 0.0
351 do k=1,nz ;
do i=ish-1,ieh
352 duhdu_tot_0(i) = duhdu_tot_0(i) + duhdu(i,k)
353 uh_tot_0(i) = uh_tot_0(i) + uh(i,j,k)
355 if (use_visc_rem)
then
356 if (cs%aggress_adjust)
then
357 do k=1,nz ;
do i=ish-1,ieh
359 dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
360 dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
361 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif
363 du_lim = 0.499*((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k)))
364 if (du_max_cfl(i) * visc_rem(i,k) > du_lim) &
365 du_max_cfl(i) = du_lim / visc_rem(i,k)
367 du_lim = 0.499*((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k)))
368 if (du_min_cfl(i) * visc_rem(i,k) < du_lim) &
369 du_min_cfl(i) = du_lim / visc_rem(i,k)
372 do k=1,nz ;
do i=ish-1,ieh
374 dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
375 dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
376 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif
378 if (du_max_cfl(i) * visc_rem(i,k) > dx_w*cfl_dt - u(i,j,k)) &
379 du_max_cfl(i) = (dx_w*cfl_dt - u(i,j,k)) / visc_rem(i,k)
380 if (du_min_cfl(i) * visc_rem(i,k) < -dx_e*cfl_dt - u(i,j,k)) &
381 du_min_cfl(i) = -(dx_e*cfl_dt + u(i,j,k)) / visc_rem(i,k)
385 if (cs%aggress_adjust)
then
386 do k=1,nz ;
do i=ish-1,ieh
388 dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
389 dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
390 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif
392 du_max_cfl(i) = min(du_max_cfl(i), 0.499 * &
393 ((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k))) )
394 du_min_cfl(i) = max(du_min_cfl(i), 0.499 * &
395 ((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k))) )
398 do k=1,nz ;
do i=ish-1,ieh
400 dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
401 dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
402 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif
404 du_max_cfl(i) = min(du_max_cfl(i), dx_w*cfl_dt - u(i,j,k))
405 du_min_cfl(i) = max(du_min_cfl(i), -(dx_e*cfl_dt + u(i,j,k)))
410 du_max_cfl(i) = max(du_max_cfl(i),0.0)
411 du_min_cfl(i) = min(du_min_cfl(i),0.0)
414 any_simple_obc = .false.
415 if (
present(uhbt) .or. set_bt_cont)
then
416 if (local_specified_bc .or. local_flather_obc)
then ;
do i=ish-1,ieh
417 l_seg = obc%segnum_u(i,j)
421 if (l_seg /= obc_none) &
422 is_simple = obc%segment(l_seg)%specified
423 do_i(i) = .not. (l_seg /= obc_none .and. is_simple)
424 any_simple_obc = any_simple_obc .or. is_simple
425 enddo ;
else ;
do i=ish-1,ieh
430 if (
present(uhbt))
then
431 call zonal_flux_adjust(u, h_in, h_l, h_r, uhbt(:,j), uh_tot_0, duhdu_tot_0, du, &
432 du_max_cfl, du_min_cfl, dt, g, us, cs, visc_rem, &
433 j, ish, ieh, do_i, .true., uh, obc=obc)
435 if (
present(u_cor))
then ;
do k=1,nz
436 do i=ish-1,ieh ; u_cor(i,j,k) = u(i,j,k) + du(i) * visc_rem(i,k) ;
enddo
437 if (local_specified_bc)
then ;
do i=ish-1,ieh
438 l_seg = obc%segnum_u(i,j)
440 if (l_seg /= obc_none)
then
441 if (obc%segment(l_seg)%specified) &
442 u_cor(i,j,k) = obc%segment(l_seg)%normal_vel(i,j,k)
449 if (set_bt_cont)
then
450 call set_zonal_bt_cont(u, h_in, h_l, h_r, bt_cont, uh_tot_0, duhdu_tot_0,&
451 du_max_cfl, du_min_cfl, dt, g, us, cs, visc_rem, &
452 visc_rem_max, j, ish, ieh, do_i)
453 if (any_simple_obc)
then
455 l_seg = obc%segnum_u(i,j)
458 if (l_seg /= obc_none) &
459 do_i(i) = obc%segment(l_seg)%specified
461 if (do_i(i)) faui(i) = gv%H_subroundoff*g%dy_Cu(i,j)
464 do k=1,nz ;
do i=ish-1,ieh ;
if (do_i(i))
then
465 if ((abs(obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)) > 0.0) .and. &
466 (obc%segment(obc%segnum_u(i,j))%specified)) &
467 faui(i) = faui(i) + obc%segment(obc%segnum_u(i,j))%normal_trans(i,j,k) / &
468 obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
469 endif ;
enddo ;
enddo
470 do i=ish-1,ieh ;
if (do_i(i))
then
471 bt_cont%FA_u_W0(i,j) = faui(i) ; bt_cont%FA_u_E0(i,j) = faui(i)
472 bt_cont%FA_u_WW(i,j) = faui(i) ; bt_cont%FA_u_EE(i,j) = faui(i)
473 bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
482 if (local_open_bc .and. set_bt_cont)
then
483 do n = 1, obc%number_of_segments
484 if (obc%segment(n)%open .and. obc%segment(n)%is_E_or_W)
then
485 i = obc%segment(n)%HI%IsdB
486 if (obc%segment(n)%direction == obc_direction_e)
then
487 do j = obc%segment(n)%HI%Jsd, obc%segment(n)%HI%Jed
489 do k=1,nz ; fa_u = fa_u + h_in(i,j,k)*g%dy_Cu(i,j) ;
enddo
490 bt_cont%FA_u_W0(i,j) = fa_u ; bt_cont%FA_u_E0(i,j) = fa_u
491 bt_cont%FA_u_WW(i,j) = fa_u ; bt_cont%FA_u_EE(i,j) = fa_u
492 bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
495 do j = obc%segment(n)%HI%Jsd, obc%segment(n)%HI%Jed
497 do k=1,nz ; fa_u = fa_u + h_in(i+1,j,k)*g%dy_Cu(i,j) ;
enddo
498 bt_cont%FA_u_W0(i,j) = fa_u ; bt_cont%FA_u_E0(i,j) = fa_u
499 bt_cont%FA_u_WW(i,j) = fa_u ; bt_cont%FA_u_EE(i,j) = fa_u
500 bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
506 call cpu_clock_end(id_clock_correct)
508 if (set_bt_cont)
then ;
if (
allocated(bt_cont%h_u))
then
509 if (
present(u_cor))
then
510 call zonal_face_thickness(u_cor, h_in, h_l, h_r, bt_cont%h_u, dt, g, us, lb, &
511 cs%vol_CFL, cs%marginal_faces, visc_rem_u, obc)
513 call zonal_face_thickness(u, h_in, h_l, h_r, bt_cont%h_u, dt, g, us, lb, &
514 cs%vol_CFL, cs%marginal_faces, visc_rem_u, obc)
518 end subroutine zonal_mass_flux
521 subroutine zonal_flux_layer(u, h, h_L, h_R, uh, duhdu, visc_rem, dt, G, US, j, &
522 ish, ieh, do_I, vol_CFL, OBC)
524 real,
dimension(SZIB_(G)),
intent(in) :: u
525 real,
dimension(SZIB_(G)),
intent(in) :: visc_rem
530 real,
dimension(SZI_(G)),
intent(in) :: h
531 real,
dimension(SZI_(G)),
intent(in) :: h_L
532 real,
dimension(SZI_(G)),
intent(in) :: h_R
533 real,
dimension(SZIB_(G)),
intent(inout) :: uh
535 real,
dimension(SZIB_(G)),
intent(inout) :: duhdu
537 real,
intent(in) :: dt
539 integer,
intent(in) :: j
540 integer,
intent(in) :: ish
541 integer,
intent(in) :: ieh
542 logical,
dimension(SZIB_(G)),
intent(in) :: do_I
543 logical,
intent(in) :: vol_CFL
553 logical :: local_open_BC
555 local_open_bc = .false.
556 if (
present(obc))
then ;
if (
associated(obc))
then
557 local_open_bc = obc%open_u_BCs_exist_globally
560 do i=ish-1,ieh ;
if (do_i(i))
then
563 if (vol_cfl)
then ; cfl = (u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
564 else ; cfl = u(i) * dt * g%IdxT(i,j) ;
endif
565 curv_3 = h_l(i) + h_r(i) - 2.0*h(i)
566 uh(i) = g%dy_Cu(i,j) * u(i) * &
567 (h_r(i) + cfl * (0.5*(h_l(i) - h_r(i)) + curv_3*(cfl - 1.5)))
568 h_marg = h_r(i) + cfl * ((h_l(i) - h_r(i)) + 3.0*curv_3*(cfl - 1.0))
569 elseif (u(i) < 0.0)
then
570 if (vol_cfl)
then ; cfl = (-u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
571 else ; cfl = -u(i) * dt * g%IdxT(i+1,j) ;
endif
572 curv_3 = h_l(i+1) + h_r(i+1) - 2.0*h(i+1)
573 uh(i) = g%dy_Cu(i,j) * u(i) * &
574 (h_l(i+1) + cfl * (0.5*(h_r(i+1)-h_l(i+1)) + curv_3*(cfl - 1.5)))
575 h_marg = h_l(i+1) + cfl * ((h_r(i+1)-h_l(i+1)) + 3.0*curv_3*(cfl - 1.0))
578 h_marg = 0.5 * (h_l(i+1) + h_r(i))
580 duhdu(i) = g%dy_Cu(i,j) * h_marg * visc_rem(i)
583 if (local_open_bc)
then
584 do i=ish-1,ieh ;
if (do_i(i))
then
585 l_seg = obc%segnum_u(i,j)
587 if (l_seg /= obc_none)
then
588 if (obc%segment(l_seg)%open)
then
589 if (obc%segment(l_seg)%direction == obc_direction_e)
then
590 uh(i) = g%dy_Cu(i,j) * u(i) * h(i)
591 duhdu(i) = g%dy_Cu(i,j) * h(i) * visc_rem(i)
593 uh(i) = g%dy_Cu(i,j) * u(i) * h(i+1)
594 duhdu(i) = g%dy_Cu(i,j) * h(i+1) * visc_rem(i)
600 end subroutine zonal_flux_layer
603 subroutine zonal_face_thickness(u, h, h_L, h_R, h_u, dt, G, US, LB, vol_CFL, &
604 marginal, visc_rem_u, OBC)
606 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
607 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
609 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
611 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
613 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h_u
614 real,
intent(in) :: dt
617 logical,
intent(in) :: vol_CFL
619 logical,
intent(in) :: marginal
621 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
622 optional,
intent(in) :: visc_rem_u
635 logical :: local_open_BC
636 integer :: i, j, k, ish, ieh, jsh, jeh, nz, n
637 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
640 do k=1,nz ;
do j=jsh,jeh ;
do i=ish-1,ieh
641 if (u(i,j,k) > 0.0)
then
642 if (vol_cfl)
then ; cfl = (u(i,j,k) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
643 else ; cfl = u(i,j,k) * dt * g%IdxT(i,j) ;
endif
644 curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
645 h_avg = h_r(i,j,k) + cfl * (0.5*(h_l(i,j,k) - h_r(i,j,k)) + curv_3*(cfl - 1.5))
646 h_marg = h_r(i,j,k) + cfl * ((h_l(i,j,k) - h_r(i,j,k)) + 3.0*curv_3*(cfl - 1.0))
647 elseif (u(i,j,k) < 0.0)
then
648 if (vol_cfl)
then ; cfl = (-u(i,j,k)*dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
649 else ; cfl = -u(i,j,k) * dt * g%IdxT(i+1,j) ;
endif
650 curv_3 = h_l(i+1,j,k) + h_r(i+1,j,k) - 2.0*h(i+1,j,k)
651 h_avg = h_l(i+1,j,k) + cfl * (0.5*(h_r(i+1,j,k)-h_l(i+1,j,k)) + curv_3*(cfl - 1.5))
652 h_marg = h_l(i+1,j,k) + cfl * ((h_r(i+1,j,k)-h_l(i+1,j,k)) + &
653 3.0*curv_3*(cfl - 1.0))
655 h_avg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
658 h_marg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
663 if (marginal)
then ; h_u(i,j,k) = h_marg
664 else ; h_u(i,j,k) = h_avg ;
endif
665 enddo ;
enddo ;
enddo
666 if (
present(visc_rem_u))
then
668 do k=1,nz ;
do j=jsh,jeh ;
do i=ish-1,ieh
669 h_u(i,j,k) = h_u(i,j,k) * visc_rem_u(i,j,k)
670 enddo ;
enddo ;
enddo
673 local_open_bc = .false.
674 if (
present(obc))
then ;
if (
associated(obc))
then
675 local_open_bc = obc%open_u_BCs_exist_globally
677 if (local_open_bc)
then
678 do n = 1, obc%number_of_segments
679 if (obc%segment(n)%open .and. obc%segment(n)%is_E_or_W)
then
680 i = obc%segment(n)%HI%IsdB
681 if (obc%segment(n)%direction == obc_direction_e)
then
682 if (
present(visc_rem_u))
then ;
do k=1,nz
683 do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
684 h_u(i,j,k) = h(i,j,k) * visc_rem_u(i,j,k)
686 enddo ;
else ;
do k=1,nz
687 do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
688 h_u(i,j,k) = h(i,j,k)
692 if (
present(visc_rem_u))
then ;
do k=1,nz
693 do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
694 h_u(i,j,k) = h(i+1,j,k) * visc_rem_u(i,j,k)
696 enddo ;
else ;
do k=1,nz
697 do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
698 h_u(i,j,k) = h(i+1,j,k)
706 end subroutine zonal_face_thickness
710 subroutine zonal_flux_adjust(u, h_in, h_L, h_R, uhbt, uh_tot_0, duhdu_tot_0, &
711 du, du_max_CFL, du_min_CFL, dt, G, US, CS, visc_rem, &
712 j, ish, ieh, do_I_in, full_precision, uh_3d, OBC)
714 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
715 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
717 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
719 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
721 real,
dimension(SZIB_(G),SZK_(G)),
intent(in) :: visc_rem
726 real,
dimension(SZIB_(G)),
optional,
intent(in) :: uhbt
729 real,
dimension(SZIB_(G)),
intent(in) :: du_max_CFL
731 real,
dimension(SZIB_(G)),
intent(in) :: du_min_CFL
733 real,
dimension(SZIB_(G)),
intent(in) :: uh_tot_0
735 real,
dimension(SZIB_(G)),
intent(in) :: duhdu_tot_0
737 real,
dimension(SZIB_(G)),
intent(out) :: du
739 real,
intent(in) :: dt
742 integer,
intent(in) :: j
743 integer,
intent(in) :: ish
744 integer,
intent(in) :: ieh
745 logical,
dimension(SZIB_(G)),
intent(in) :: do_I_in
747 logical,
optional,
intent(in) :: full_precision
750 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
optional,
intent(inout) :: uh_3d
754 real,
dimension(SZIB_(G),SZK_(G)) :: &
757 real,
dimension(SZIB_(G)) :: &
768 integer :: i, k, nz, itt, max_itts = 20
769 logical :: full_prec, domore, do_I(SZIB_(G))
772 full_prec = .true. ;
if (
present(full_precision)) full_prec = full_precision
774 uh_aux(:,:) = 0.0 ; duhdu(:,:) = 0.0
776 if (
present(uh_3d))
then ;
do k=1,nz ;
do i=ish-1,ieh
777 uh_aux(i,k) = uh_3d(i,j,k)
778 enddo ;
enddo ;
endif
781 du(i) = 0.0 ; do_i(i) = do_i_in(i)
782 du_max(i) = du_max_cfl(i) ; du_min(i) = du_min_cfl(i)
783 uh_err(i) = uh_tot_0(i) - uhbt(i) ; duhdu_tot(i) = duhdu_tot_0(i)
784 uh_err_best(i) = abs(uh_err(i))
790 case (:1) ; tol_eta = 1e-6 * cs%tol_eta
791 case (2) ; tol_eta = 1e-4 * cs%tol_eta
792 case (3) ; tol_eta = 1e-2 * cs%tol_eta
793 case default ; tol_eta = cs%tol_eta
796 tol_eta = cs%tol_eta_aux ;
if (itt<=1) tol_eta = 1e-6 * cs%tol_eta_aux
801 if (uh_err(i) > 0.0)
then ; du_max(i) = du(i)
802 elseif (uh_err(i) < 0.0)
then ; du_min(i) = du(i)
803 else ; do_i(i) = .false. ;
endif
806 do i=ish-1,ieh ;
if (do_i(i))
then
807 if ((dt * min(g%IareaT(i,j),g%IareaT(i+1,j))*abs(uh_err(i)) > tol_eta) .or. &
808 (cs%better_iter .and. ((abs(uh_err(i)) > tol_vel * duhdu_tot(i)) .or. &
809 (abs(uh_err(i)) > uh_err_best(i))) ))
then
813 ddu = -uh_err(i) / duhdu_tot(i)
816 if (abs(ddu) < 1.0e-15*abs(du(i)))
then
818 elseif (ddu > 0.0)
then
819 if (du(i) >= du_max(i))
then
820 du(i) = 0.5*(du_prev + du_max(i))
821 if (du_max(i) - du_prev < 1.0e-15*abs(du(i))) do_i(i) = .false.
824 if (du(i) <= du_min(i))
then
825 du(i) = 0.5*(du_prev + du_min(i))
826 if (du_prev - du_min(i) < 1.0e-15*abs(du(i))) do_i(i) = .false.
831 du(i) = du(i) - uh_err(i) / duhdu_tot(i)
832 if ((du(i) >= du_max(i)) .or. (du(i) <= du_min(i))) &
833 du(i) = 0.5*(du_max(i) + du_min(i))
835 if (do_i(i)) domore = .true.
840 if (.not.domore)
exit
842 if ((itt < max_itts) .or.
present(uh_3d))
then ;
do k=1,nz
843 do i=ish-1,ieh ; u_new(i) = u(i,j,k) + du(i) * visc_rem(i,k) ;
enddo
844 call zonal_flux_layer(u_new, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), &
845 uh_aux(:,k), duhdu(:,k), visc_rem(:,k), &
846 dt, g, us, j, ish, ieh, do_i, cs%vol_CFL, obc)
849 if (itt < max_itts)
then
851 uh_err(i) = -uhbt(i) ; duhdu_tot(i) = 0.0
853 do k=1,nz ;
do i=ish-1,ieh
854 uh_err(i) = uh_err(i) + uh_aux(i,k)
855 duhdu_tot(i) = duhdu_tot(i) + duhdu(i,k)
858 uh_err_best(i) = min(uh_err_best(i), abs(uh_err(i)))
866 if (
present(uh_3d))
then ;
do k=1,nz ;
do i=ish-1,ieh
867 uh_3d(i,j,k) = uh_aux(i,k)
868 enddo ;
enddo ;
endif
870 end subroutine zonal_flux_adjust
874 subroutine set_zonal_bt_cont(u, h_in, h_L, h_R, BT_cont, uh_tot_0, duhdu_tot_0, &
875 du_max_CFL, du_min_CFL, dt, G, US, CS, visc_rem, &
876 visc_rem_max, j, ish, ieh, do_I)
878 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
879 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
881 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
883 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
887 real,
dimension(SZIB_(G)),
intent(in) :: uh_tot_0
889 real,
dimension(SZIB_(G)),
intent(in) :: duhdu_tot_0
891 real,
dimension(SZIB_(G)),
intent(in) :: du_max_CFL
893 real,
dimension(SZIB_(G)),
intent(in) :: du_min_CFL
895 real,
intent(in) :: dt
898 real,
dimension(SZIB_(G),SZK_(G)),
intent(in) :: visc_rem
903 real,
dimension(SZIB_(G)),
intent(in) :: visc_rem_max
904 integer,
intent(in) :: j
905 integer,
intent(in) :: ish
906 integer,
intent(in) :: ieh
907 logical,
dimension(SZIB_(G)),
intent(in) :: do_I
910 real,
dimension(SZIB_(G)) :: &
943 nz = g%ke ; idt = 1.0 / dt
944 min_visc_rem = 0.1 ; cfl_min = 1e-6
947 do i=ish-1,ieh ; zeros(i) = 0.0 ;
enddo
948 call zonal_flux_adjust(u, h_in, h_l, h_r, zeros, uh_tot_0, duhdu_tot_0, du0, &
949 du_max_cfl, du_min_cfl, dt, g, us, cs, visc_rem, &
950 j, ish, ieh, do_i, .true.)
957 if (do_i(i)) domore = .true.
958 du_cfl(i) = (cfl_min * idt) * g%dxCu(i,j)
959 dur(i) = min(0.0,du0(i) - du_cfl(i))
960 dul(i) = max(0.0,du0(i) + du_cfl(i))
961 famt_l(i) = 0.0 ; famt_r(i) = 0.0 ; famt_0(i) = 0.0
962 uhtot_l(i) = 0.0 ; uhtot_r(i) = 0.0
965 if (.not.domore)
then
966 do k=1,nz ;
do i=ish-1,ieh
967 bt_cont%FA_u_W0(i,j) = 0.0 ; bt_cont%FA_u_WW(i,j) = 0.0
968 bt_cont%FA_u_E0(i,j) = 0.0 ; bt_cont%FA_u_EE(i,j) = 0.0
969 bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
974 do k=1,nz ;
do i=ish-1,ieh ;
if (do_i(i))
then
975 visc_rem_lim = max(visc_rem(i,k), min_visc_rem*visc_rem_max(i))
976 if (visc_rem_lim > 0.0)
then
977 if (u(i,j,k) + dur(i)*visc_rem_lim > -du_cfl(i)*visc_rem(i,k)) &
978 dur(i) = -(u(i,j,k) + du_cfl(i)*visc_rem(i,k)) / visc_rem_lim
979 if (u(i,j,k) + dul(i)*visc_rem_lim < du_cfl(i)*visc_rem(i,k)) &
980 dul(i) = -(u(i,j,k) - du_cfl(i)*visc_rem(i,k)) / visc_rem_lim
982 endif ;
enddo ;
enddo
985 do i=ish-1,ieh ;
if (do_i(i))
then
986 u_l(i) = u(i,j,k) + dul(i) * visc_rem(i,k)
987 u_r(i) = u(i,j,k) + dur(i) * visc_rem(i,k)
988 u_0(i) = u(i,j,k) + du0(i) * visc_rem(i,k)
990 call zonal_flux_layer(u_0, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_0, duhdu_0, &
991 visc_rem(:,k), dt, g, us, j, ish, ieh, do_i, cs%vol_CFL)
992 call zonal_flux_layer(u_l, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_l, duhdu_l, &
993 visc_rem(:,k), dt, g, us, j, ish, ieh, do_i, cs%vol_CFL)
994 call zonal_flux_layer(u_r, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_r, duhdu_r, &
995 visc_rem(:,k), dt, g, us, j, ish, ieh, do_i, cs%vol_CFL)
996 do i=ish-1,ieh ;
if (do_i(i))
then
997 famt_0(i) = famt_0(i) + duhdu_0(i)
998 famt_l(i) = famt_l(i) + duhdu_l(i)
999 famt_r(i) = famt_r(i) + duhdu_r(i)
1000 uhtot_l(i) = uhtot_l(i) + uh_l(i)
1001 uhtot_r(i) = uhtot_r(i) + uh_r(i)
1004 do i=ish-1,ieh ;
if (do_i(i))
then
1005 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1006 if ((dul(i) - du0(i)) /= 0.0) &
1007 fa_avg = uhtot_l(i) / (dul(i) - du0(i))
1008 if (fa_avg > max(fa_0, famt_l(i)))
then ; fa_avg = max(fa_0, famt_l(i))
1009 elseif (fa_avg < min(fa_0, famt_l(i)))
then ; fa_0 = fa_avg ;
endif
1011 bt_cont%FA_u_W0(i,j) = fa_0 ; bt_cont%FA_u_WW(i,j) = famt_l(i)
1012 if (abs(fa_0-famt_l(i)) <= 1e-12*fa_0)
then ; bt_cont%uBT_WW(i,j) = 0.0 ;
else
1013 bt_cont%uBT_WW(i,j) = (1.5 * (dul(i) - du0(i))) * &
1014 ((famt_l(i) - fa_avg) / (famt_l(i) - fa_0))
1017 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1018 if ((dur(i) - du0(i)) /= 0.0) &
1019 fa_avg = uhtot_r(i) / (dur(i) - du0(i))
1020 if (fa_avg > max(fa_0, famt_r(i)))
then ; fa_avg = max(fa_0, famt_r(i))
1021 elseif (fa_avg < min(fa_0, famt_r(i)))
then ; fa_0 = fa_avg ;
endif
1023 bt_cont%FA_u_E0(i,j) = fa_0 ; bt_cont%FA_u_EE(i,j) = famt_r(i)
1024 if (abs(famt_r(i) - fa_0) <= 1e-12*fa_0)
then ; bt_cont%uBT_EE(i,j) = 0.0 ;
else
1025 bt_cont%uBT_EE(i,j) = (1.5 * (dur(i) - du0(i))) * &
1026 ((famt_r(i) - fa_avg) / (famt_r(i) - fa_0))
1029 bt_cont%FA_u_W0(i,j) = 0.0 ; bt_cont%FA_u_WW(i,j) = 0.0
1030 bt_cont%FA_u_E0(i,j) = 0.0 ; bt_cont%FA_u_EE(i,j) = 0.0
1031 bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
1034 end subroutine set_zonal_bt_cont
1037 subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, US, CS, LB, vhbt, OBC, &
1038 visc_rem_v, v_cor, BT_cont)
1041 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
1042 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
1044 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out) :: vh
1046 real,
intent(in) :: dt
1052 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
1053 optional,
intent(in) :: visc_rem_v
1058 real,
dimension(SZI_(G),SZJB_(G)),
optional,
intent(in) :: vhbt
1060 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
1061 optional,
intent(out) :: v_cor
1067 real,
dimension(SZI_(G),SZK_(G)) :: &
1069 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
1071 real,
dimension(SZI_(G)) :: &
1078 logical,
dimension(SZI_(G)) :: do_I
1079 real,
dimension(SZI_(G)) :: FAvi
1081 real,
dimension(SZI_(G),SZK_(G)) :: &
1089 integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
1091 logical :: local_specified_BC, use_visc_rem, set_BT_cont, any_simple_OBC
1092 logical :: local_Flather_OBC, is_simple, local_open_BC
1095 use_visc_rem =
present(visc_rem_v)
1096 local_specified_bc = .false. ; set_bt_cont = .false. ; local_flather_obc = .false.
1097 local_open_bc = .false.
1098 if (
present(bt_cont)) set_bt_cont = (
associated(bt_cont))
1099 if (
present(obc))
then ;
if (
associated(obc))
then ;
if (obc%OBC_pe)
then
1100 local_specified_bc = obc%specified_v_BCs_exist_globally
1101 local_flather_obc = obc%Flather_v_BCs_exist_globally
1102 local_open_bc = obc%open_v_BCs_exist_globally
1103 endif ;
endif ;
endif
1104 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
1106 cfl_dt = cs%CFL_limit_adjust / dt
1108 if (cs%aggress_adjust) cfl_dt = i_dt
1110 call cpu_clock_begin(id_clock_update)
1114 if (cs%upwind_1st)
then
1115 do j=jsh-1,jeh+1 ;
do i=ish,ieh
1116 h_l(i,j,k) = h_in(i,j,k) ; h_r(i,j,k) = h_in(i,j,k)
1119 call ppm_reconstruction_y(h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), g, lb, &
1120 2.0*gv%Angstrom_H, cs%monotonic, simple_2nd=cs%simple_2nd, obc=obc)
1122 do i=ish,ieh ; visc_rem(i,k) = 1.0 ;
enddo
1124 call cpu_clock_end(id_clock_update)
1126 call cpu_clock_begin(id_clock_correct)
1135 do i=ish,ieh ; do_i(i) = .true. ; visc_rem_max(i) = 0.0 ;
enddo
1138 if (use_visc_rem)
then ;
do i=ish,ieh
1139 visc_rem(i,k) = visc_rem_v(i,j,k)
1140 visc_rem_max(i) = max(visc_rem_max(i), visc_rem(i,k))
1142 call merid_flux_layer(v(:,j,k), h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), &
1143 vh(:,j,k), dvhdv(:,k), visc_rem(:,k), &
1144 dt, g, us, j, ish, ieh, do_i, cs%vol_CFL, obc)
1145 if (local_specified_bc)
then
1147 l_seg = obc%segnum_v(i,j)
1149 if (l_seg /= obc_none)
then
1150 if (obc%segment(l_seg)%specified) &
1151 vh(i,j,k) = obc%segment(l_seg)%normal_trans(i,j,k)
1156 if ((.not.use_visc_rem) .or. (.not.cs%use_visc_rem_max))
then ;
do i=ish,ieh
1157 visc_rem_max(i) = 1.0
1160 if (
present(vhbt) .or. set_bt_cont)
then
1165 if (visc_rem_max(i) > 0.0) i_vrm = 1.0 / visc_rem_max(i)
1166 if (cs%vol_CFL)
then
1167 dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1168 dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1169 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif
1170 dv_max_cfl(i) = 2.0 * (cfl_dt * dy_s) * i_vrm
1171 dv_min_cfl(i) = -2.0 * (cfl_dt * dy_n) * i_vrm
1172 vh_tot_0(i) = 0.0 ; dvhdv_tot_0(i) = 0.0
1174 do k=1,nz ;
do i=ish,ieh
1175 dvhdv_tot_0(i) = dvhdv_tot_0(i) + dvhdv(i,k)
1176 vh_tot_0(i) = vh_tot_0(i) + vh(i,j,k)
1179 if (use_visc_rem)
then
1180 if (cs%aggress_adjust)
then
1181 do k=1,nz ;
do i=ish,ieh
1182 if (cs%vol_CFL)
then
1183 dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1184 dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1185 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif
1186 dv_lim = 0.499*((dy_s*i_dt - v(i,j,k)) + min(0.0,v(i,j-1,k)))
1187 if (dv_max_cfl(i) * visc_rem(i,k) > dv_lim) &
1188 dv_max_cfl(i) = dv_lim / visc_rem(i,k)
1190 dv_lim = 0.499*((-dy_n*cfl_dt - v(i,j,k)) + max(0.0,v(i,j+1,k)))
1191 if (dv_min_cfl(i) * visc_rem(i,k) < dv_lim) &
1192 dv_min_cfl(i) = dv_lim / visc_rem(i,k)
1195 do k=1,nz ;
do i=ish,ieh
1196 if (cs%vol_CFL)
then
1197 dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1198 dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1199 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif
1200 if (dv_max_cfl(i) * visc_rem(i,k) > dy_s*cfl_dt - v(i,j,k)) &
1201 dv_max_cfl(i) = (dy_s*cfl_dt - v(i,j,k)) / visc_rem(i,k)
1202 if (dv_min_cfl(i) * visc_rem(i,k) < -dy_n*cfl_dt - v(i,j,k)) &
1203 dv_min_cfl(i) = -(dy_n*cfl_dt + v(i,j,k)) / visc_rem(i,k)
1207 if (cs%aggress_adjust)
then
1208 do k=1,nz ;
do i=ish,ieh
1209 if (cs%vol_CFL)
then
1210 dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1211 dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1212 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif
1213 dv_max_cfl(i) = min(dv_max_cfl(i), 0.499 * &
1214 ((dy_s*i_dt - v(i,j,k)) + min(0.0,v(i,j-1,k))) )
1215 dv_min_cfl(i) = max(dv_min_cfl(i), 0.499 * &
1216 ((-dy_n*i_dt - v(i,j,k)) + max(0.0,v(i,j+1,k))) )
1219 do k=1,nz ;
do i=ish,ieh
1220 if (cs%vol_CFL)
then
1221 dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1222 dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1223 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif
1224 dv_max_cfl(i) = min(dv_max_cfl(i), dy_s*cfl_dt - v(i,j,k))
1225 dv_min_cfl(i) = max(dv_min_cfl(i), -(dy_n*cfl_dt + v(i,j,k)))
1230 dv_max_cfl(i) = max(dv_max_cfl(i),0.0)
1231 dv_min_cfl(i) = min(dv_min_cfl(i),0.0)
1234 any_simple_obc = .false.
1235 if (
present(vhbt) .or. set_bt_cont)
then
1236 if (local_specified_bc .or. local_flather_obc)
then ;
do i=ish,ieh
1237 l_seg = obc%segnum_v(i,j)
1241 if (l_seg /= obc_none) &
1242 is_simple = obc%segment(l_seg)%specified
1243 do_i(i) = .not.(l_seg /= obc_none .and. is_simple)
1244 any_simple_obc = any_simple_obc .or. is_simple
1245 enddo ;
else ;
do i=ish,ieh
1250 if (
present(vhbt))
then
1251 call meridional_flux_adjust(v, h_in, h_l, h_r, vhbt(:,j), vh_tot_0, dvhdv_tot_0, dv, &
1252 dv_max_cfl, dv_min_cfl, dt, g, us, cs, visc_rem, &
1253 j, ish, ieh, do_i, .true., vh, obc=obc)
1255 if (
present(v_cor))
then ;
do k=1,nz
1256 do i=ish,ieh ; v_cor(i,j,k) = v(i,j,k) + dv(i) * visc_rem(i,k) ;
enddo
1257 if (local_specified_bc)
then ;
do i=ish,ieh
1258 l_seg = obc%segnum_v(i,j)
1260 if (l_seg /= obc_none)
then
1261 if (obc%segment(obc%segnum_v(i,j))%specified) &
1262 v_cor(i,j,k) = obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1268 if (set_bt_cont)
then
1269 call set_merid_bt_cont(v, h_in, h_l, h_r, bt_cont, vh_tot_0, dvhdv_tot_0,&
1270 dv_max_cfl, dv_min_cfl, dt, g, us, cs, visc_rem, &
1271 visc_rem_max, j, ish, ieh, do_i)
1272 if (any_simple_obc)
then
1274 l_seg = obc%segnum_v(i,j)
1277 if(l_seg /= obc_none) &
1278 do_i(i) = (obc%segment(l_seg)%specified)
1280 if (do_i(i)) favi(i) = gv%H_subroundoff*g%dx_Cv(i,j)
1283 do k=1,nz ;
do i=ish,ieh ;
if (do_i(i))
then
1284 if ((abs(obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)) > 0.0) .and. &
1285 (obc%segment(obc%segnum_v(i,j))%specified)) &
1286 favi(i) = favi(i) + obc%segment(obc%segnum_v(i,j))%normal_trans(i,j,k) / &
1287 obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1288 endif ;
enddo ;
enddo
1289 do i=ish,ieh ;
if (do_i(i))
then
1290 bt_cont%FA_v_S0(i,j) = favi(i) ; bt_cont%FA_v_N0(i,j) = favi(i)
1291 bt_cont%FA_v_SS(i,j) = favi(i) ; bt_cont%FA_v_NN(i,j) = favi(i)
1292 bt_cont%vBT_SS(i,j) = 0.0 ; bt_cont%vBT_NN(i,j) = 0.0
1301 if (local_open_bc .and. set_bt_cont)
then
1302 do n = 1, obc%number_of_segments
1303 if (obc%segment(n)%open .and. obc%segment(n)%is_N_or_S)
then
1304 j = obc%segment(n)%HI%JsdB
1305 if (obc%segment(n)%direction == obc_direction_n)
then
1306 do i = obc%segment(n)%HI%Isd, obc%segment(n)%HI%Ied
1308 do k=1,nz ; fa_v = fa_v + h_in(i,j,k)*g%dx_Cv(i,j) ;
enddo
1309 bt_cont%FA_v_S0(i,j) = fa_v ; bt_cont%FA_v_N0(i,j) = fa_v
1310 bt_cont%FA_v_SS(i,j) = fa_v ; bt_cont%FA_v_NN(i,j) = fa_v
1311 bt_cont%vBT_SS(i,j) = 0.0 ; bt_cont%vBT_NN(i,j) = 0.0
1314 do i = obc%segment(n)%HI%Isd, obc%segment(n)%HI%Ied
1316 do k=1,nz ; fa_v = fa_v + h_in(i,j+1,k)*g%dx_Cv(i,j) ;
enddo
1317 bt_cont%FA_v_S0(i,j) = fa_v ; bt_cont%FA_v_N0(i,j) = fa_v
1318 bt_cont%FA_v_SS(i,j) = fa_v ; bt_cont%FA_v_NN(i,j) = fa_v
1319 bt_cont%vBT_SS(i,j) = 0.0 ; bt_cont%vBT_NN(i,j) = 0.0
1325 call cpu_clock_end(id_clock_correct)
1327 if (set_bt_cont)
then ;
if (
allocated(bt_cont%h_v))
then
1328 if (
present(v_cor))
then
1329 call merid_face_thickness(v_cor, h_in, h_l, h_r, bt_cont%h_v, dt, g, us, lb, &
1330 cs%vol_CFL, cs%marginal_faces, visc_rem_v, obc)
1332 call merid_face_thickness(v, h_in, h_l, h_r, bt_cont%h_v, dt, g, us, lb, &
1333 cs%vol_CFL, cs%marginal_faces, visc_rem_v, obc)
1337 end subroutine meridional_mass_flux
1340 subroutine merid_flux_layer(v, h, h_L, h_R, vh, dvhdv, visc_rem, dt, G, US, J, &
1341 ish, ieh, do_I, vol_CFL, OBC)
1343 real,
dimension(SZI_(G)),
intent(in) :: v
1344 real,
dimension(SZI_(G)),
intent(in) :: visc_rem
1349 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h
1351 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_L
1353 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_R
1355 real,
dimension(SZI_(G)),
intent(inout) :: vh
1357 real,
dimension(SZI_(G)),
intent(inout) :: dvhdv
1359 real,
intent(in) :: dt
1361 integer,
intent(in) :: j
1362 integer,
intent(in) :: ish
1363 integer,
intent(in) :: ieh
1364 logical,
dimension(SZI_(G)),
intent(in) :: do_I
1365 logical,
intent(in) :: vol_CFL
1375 logical :: local_open_BC
1377 local_open_bc = .false.
1378 if (
present(obc))
then ;
if (
associated(obc))
then
1379 local_open_bc = obc%open_v_BCs_exist_globally
1382 do i=ish,ieh ;
if (do_i(i))
then
1383 if (v(i) > 0.0)
then
1384 if (vol_cfl)
then ; cfl = (v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1385 else ; cfl = v(i) * dt * g%IdyT(i,j) ;
endif
1386 curv_3 = h_l(i,j) + h_r(i,j) - 2.0*h(i,j)
1387 vh(i) = g%dx_Cv(i,j) * v(i) * ( h_r(i,j) + cfl * &
1388 (0.5*(h_l(i,j) - h_r(i,j)) + curv_3*(cfl - 1.5)) )
1389 h_marg = h_r(i,j) + cfl * ((h_l(i,j) - h_r(i,j)) + &
1390 3.0*curv_3*(cfl - 1.0))
1391 elseif (v(i) < 0.0)
then
1392 if (vol_cfl)
then ; cfl = (-v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1393 else ; cfl = -v(i) * dt * g%IdyT(i,j+1) ;
endif
1394 curv_3 = h_l(i,j+1) + h_r(i,j+1) - 2.0*h(i,j+1)
1395 vh(i) = g%dx_Cv(i,j) * v(i) * ( h_l(i,j+1) + cfl * &
1396 (0.5*(h_r(i,j+1)-h_l(i,j+1)) + curv_3*(cfl - 1.5)) )
1397 h_marg = h_l(i,j+1) + cfl * ((h_r(i,j+1)-h_l(i,j+1)) + &
1398 3.0*curv_3*(cfl - 1.0))
1401 h_marg = 0.5 * (h_l(i,j+1) + h_r(i,j))
1403 dvhdv(i) = g%dx_Cv(i,j) * h_marg * visc_rem(i)
1406 if (local_open_bc)
then
1407 do i=ish,ieh ;
if (do_i(i))
then
1408 l_seg = obc%segnum_v(i,j)
1410 if (l_seg /= obc_none)
then
1411 if (obc%segment(l_seg)%open)
then
1412 if (obc%segment(l_seg)%direction == obc_direction_n)
then
1413 vh(i) = g%dx_Cv(i,j) * v(i) * h(i,j)
1414 dvhdv(i) = g%dx_Cv(i,j) * h(i,j) * visc_rem(i)
1416 vh(i) = g%dx_Cv(i,j) * v(i) * h(i,j+1)
1417 dvhdv(i) = g%dx_Cv(i,j) * h(i,j+1) * visc_rem(i)
1423 end subroutine merid_flux_layer
1426 subroutine merid_face_thickness(v, h, h_L, h_R, h_v, dt, G, US, LB, vol_CFL, &
1427 marginal, visc_rem_v, OBC)
1429 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
1430 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1432 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
1434 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
1436 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: h_v
1438 real,
intent(in) :: dt
1441 logical,
intent(in) :: vol_CFL
1443 logical,
intent(in) :: marginal
1445 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
optional,
intent(in) :: visc_rem_v
1458 logical :: local_open_BC
1459 integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
1460 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
1463 do k=1,nz ;
do j=jsh-1,jeh ;
do i=ish,ieh
1464 if (v(i,j,k) > 0.0)
then
1465 if (vol_cfl)
then ; cfl = (v(i,j,k) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1466 else ; cfl = v(i,j,k) * dt * g%IdyT(i,j) ;
endif
1467 curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
1468 h_avg = h_r(i,j,k) + cfl * (0.5*(h_l(i,j,k) - h_r(i,j,k)) + curv_3*(cfl - 1.5))
1469 h_marg = h_r(i,j,k) + cfl * ((h_l(i,j,k) - h_r(i,j,k)) + &
1470 3.0*curv_3*(cfl - 1.0))
1471 elseif (v(i,j,k) < 0.0)
then
1472 if (vol_cfl)
then ; cfl = (-v(i,j,k)*dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1473 else ; cfl = -v(i,j,k) * dt * g%IdyT(i,j+1) ;
endif
1474 curv_3 = h_l(i,j+1,k) + h_r(i,j+1,k) - 2.0*h(i,j+1,k)
1475 h_avg = h_l(i,j+1,k) + cfl * (0.5*(h_r(i,j+1,k)-h_l(i,j+1,k)) + curv_3*(cfl - 1.5))
1476 h_marg = h_l(i,j+1,k) + cfl * ((h_r(i,j+1,k)-h_l(i,j+1,k)) + &
1477 3.0*curv_3*(cfl - 1.0))
1479 h_avg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1482 h_marg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1487 if (marginal)
then ; h_v(i,j,k) = h_marg
1488 else ; h_v(i,j,k) = h_avg ;
endif
1489 enddo ;
enddo ;
enddo
1491 if (
present(visc_rem_v))
then
1493 do k=1,nz ;
do j=jsh-1,jeh ;
do i=ish,ieh
1494 h_v(i,j,k) = h_v(i,j,k) * visc_rem_v(i,j,k)
1495 enddo ;
enddo ;
enddo
1498 local_open_bc = .false.
1499 if (
present(obc))
then ;
if (
associated(obc))
then
1500 local_open_bc = obc%open_v_BCs_exist_globally
1502 if (local_open_bc)
then
1503 do n = 1, obc%number_of_segments
1504 if (obc%segment(n)%open .and. obc%segment(n)%is_N_or_S)
then
1505 j = obc%segment(n)%HI%JsdB
1506 if (obc%segment(n)%direction == obc_direction_n)
then
1507 if (
present(visc_rem_v))
then ;
do k=1,nz
1508 do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1509 h_v(i,j,k) = h(i,j,k) * visc_rem_v(i,j,k)
1511 enddo ;
else ;
do k=1,nz
1512 do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1513 h_v(i,j,k) = h(i,j,k)
1517 if (
present(visc_rem_v))
then ;
do k=1,nz
1518 do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1519 h_v(i,j,k) = h(i,j+1,k) * visc_rem_v(i,j,k)
1521 enddo ;
else ;
do k=1,nz
1522 do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1523 h_v(i,j,k) = h(i,j+1,k)
1531 end subroutine merid_face_thickness
1534 subroutine meridional_flux_adjust(v, h_in, h_L, h_R, vhbt, vh_tot_0, dvhdv_tot_0, &
1535 dv, dv_max_CFL, dv_min_CFL, dt, G, US, CS, visc_rem, &
1536 j, ish, ieh, do_I_in, full_precision, vh_3d, OBC)
1538 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
1540 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1542 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),&
1544 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1546 real,
dimension(SZI_(G),SZK_(G)),
intent(in) :: visc_rem
1552 real,
dimension(SZI_(G)), &
1553 optional,
intent(in) :: vhbt
1555 real,
dimension(SZI_(G)),
intent(in) :: dv_max_CFL
1556 real,
dimension(SZI_(G)),
intent(in) :: dv_min_CFL
1557 real,
dimension(SZI_(G)),
intent(in) :: vh_tot_0
1559 real,
dimension(SZI_(G)),
intent(in) :: dvhdv_tot_0
1561 real,
dimension(SZI_(G)),
intent(out) :: dv
1562 real,
intent(in) :: dt
1565 integer,
intent(in) :: j
1566 integer,
intent(in) :: ish
1567 integer,
intent(in) :: ieh
1568 logical,
dimension(SZI_(G)), &
1569 intent(in) :: do_I_in
1570 logical,
optional,
intent(in) :: full_precision
1572 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)), &
1573 optional,
intent(inout) :: vh_3d
1577 real,
dimension(SZI_(G),SZK_(G)) :: &
1580 real,
dimension(SZI_(G)) :: &
1591 integer :: i, k, nz, itt, max_itts = 20
1592 logical :: full_prec, domore, do_I(SZI_(G))
1595 full_prec = .true. ;
if (
present(full_precision)) full_prec = full_precision
1597 vh_aux(:,:) = 0.0 ; dvhdv(:,:) = 0.0
1599 if (
present(vh_3d))
then ;
do k=1,nz ;
do i=ish,ieh
1600 vh_aux(i,k) = vh_3d(i,j,k)
1601 enddo ;
enddo ;
endif
1604 dv(i) = 0.0 ; do_i(i) = do_i_in(i)
1605 dv_max(i) = dv_max_cfl(i) ; dv_min(i) = dv_min_cfl(i)
1606 vh_err(i) = vh_tot_0(i) - vhbt(i) ; dvhdv_tot(i) = dvhdv_tot_0(i)
1607 vh_err_best(i) = abs(vh_err(i))
1613 case (:1) ; tol_eta = 1e-6 * cs%tol_eta
1614 case (2) ; tol_eta = 1e-4 * cs%tol_eta
1615 case (3) ; tol_eta = 1e-2 * cs%tol_eta
1616 case default ; tol_eta = cs%tol_eta
1619 tol_eta = cs%tol_eta_aux ;
if (itt<=1) tol_eta = 1e-6 * cs%tol_eta_aux
1621 tol_vel = cs%tol_vel
1624 if (vh_err(i) > 0.0)
then ; dv_max(i) = dv(i)
1625 elseif (vh_err(i) < 0.0)
then ; dv_min(i) = dv(i)
1626 else ; do_i(i) = .false. ;
endif
1629 do i=ish,ieh ;
if (do_i(i))
then
1630 if ((dt * min(g%IareaT(i,j),g%IareaT(i,j+1))*abs(vh_err(i)) > tol_eta) .or. &
1631 (cs%better_iter .and. ((abs(vh_err(i)) > tol_vel * dvhdv_tot(i)) .or. &
1632 (abs(vh_err(i)) > vh_err_best(i))) ))
then
1636 ddv = -vh_err(i) / dvhdv_tot(i)
1639 if (abs(ddv) < 1.0e-15*abs(dv(i)))
then
1641 elseif (ddv > 0.0)
then
1642 if (dv(i) >= dv_max(i))
then
1643 dv(i) = 0.5*(dv_prev + dv_max(i))
1644 if (dv_max(i) - dv_prev < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1647 if (dv(i) <= dv_min(i))
then
1648 dv(i) = 0.5*(dv_prev + dv_min(i))
1649 if (dv_prev - dv_min(i) < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1654 dv(i) = dv(i) - vh_err(i) / dvhdv_tot(i)
1655 if ((dv(i) >= dv_max(i)) .or. (dv(i) <= dv_min(i))) &
1656 dv(i) = 0.5*(dv_max(i) + dv_min(i))
1658 if (do_i(i)) domore = .true.
1663 if (.not.domore)
exit
1665 if ((itt < max_itts) .or.
present(vh_3d))
then ;
do k=1,nz
1666 do i=ish,ieh ; v_new(i) = v(i,j,k) + dv(i) * visc_rem(i,k) ;
enddo
1667 call merid_flux_layer(v_new, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), &
1668 vh_aux(:,k), dvhdv(:,k), visc_rem(:,k), &
1669 dt, g, us, j, ish, ieh, do_i, cs%vol_CFL, obc)
1672 if (itt < max_itts)
then
1674 vh_err(i) = -vhbt(i) ; dvhdv_tot(i) = 0.0
1676 do k=1,nz ;
do i=ish,ieh
1677 vh_err(i) = vh_err(i) + vh_aux(i,k)
1678 dvhdv_tot(i) = dvhdv_tot(i) + dvhdv(i,k)
1681 vh_err_best(i) = min(vh_err_best(i), abs(vh_err(i)))
1689 if (
present(vh_3d))
then ;
do k=1,nz ;
do i=ish,ieh
1690 vh_3d(i,j,k) = vh_aux(i,k)
1691 enddo ;
enddo ;
endif
1693 end subroutine meridional_flux_adjust
1697 subroutine set_merid_bt_cont(v, h_in, h_L, h_R, BT_cont, vh_tot_0, dvhdv_tot_0, &
1698 dv_max_CFL, dv_min_CFL, dt, G, US, CS, visc_rem, &
1699 visc_rem_max, j, ish, ieh, do_I)
1701 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
1702 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
1704 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
1706 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
1710 real,
dimension(SZI_(G)),
intent(in) :: vh_tot_0
1712 real,
dimension(SZI_(G)),
intent(in) :: dvhdv_tot_0
1714 real,
dimension(SZI_(G)),
intent(in) :: dv_max_CFL
1716 real,
dimension(SZI_(G)),
intent(in) :: dv_min_CFL
1718 real,
intent(in) :: dt
1721 real,
dimension(SZI_(G),SZK_(G)),
intent(in) :: visc_rem
1726 real,
dimension(SZI_(G)),
intent(in) :: visc_rem_max
1727 integer,
intent(in) :: j
1728 integer,
intent(in) :: ish
1729 integer,
intent(in) :: ieh
1730 logical,
dimension(SZI_(G)),
intent(in) :: do_I
1733 real,
dimension(SZI_(G)) :: &
1753 real :: visc_rem_lim
1756 real :: min_visc_rem
1766 nz = g%ke ; idt = 1.0 / dt
1767 min_visc_rem = 0.1 ; cfl_min = 1e-6
1770 do i=ish,ieh ; zeros(i) = 0.0 ;
enddo
1771 call meridional_flux_adjust(v, h_in, h_l, h_r, zeros, vh_tot_0, dvhdv_tot_0, dv0, &
1772 dv_max_cfl, dv_min_cfl, dt, g, us, cs, visc_rem, &
1773 j, ish, ieh, do_i, .true.)
1779 do i=ish,ieh ;
if (do_i(i))
then
1781 dv_cfl(i) = (cfl_min * idt) * g%dyCv(i,j)
1782 dvr(i) = min(0.0,dv0(i) - dv_cfl(i))
1783 dvl(i) = max(0.0,dv0(i) + dv_cfl(i))
1784 famt_l(i) = 0.0 ; famt_r(i) = 0.0 ; famt_0(i) = 0.0
1785 vhtot_l(i) = 0.0 ; vhtot_r(i) = 0.0
1788 if (.not.domore)
then
1789 do k=1,nz ;
do i=ish,ieh
1790 bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1791 bt_cont%vBT_SS(i,j) = 0.0
1792 bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1793 bt_cont%vBT_NN(i,j) = 0.0
1798 do k=1,nz ;
do i=ish,ieh ;
if (do_i(i))
then
1799 visc_rem_lim = max(visc_rem(i,k), min_visc_rem*visc_rem_max(i))
1800 if (visc_rem_lim > 0.0)
then
1801 if (v(i,j,k) + dvr(i)*visc_rem_lim > -dv_cfl(i)*visc_rem(i,k)) &
1802 dvr(i) = -(v(i,j,k) + dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1803 if (v(i,j,k) + dvl(i)*visc_rem_lim < dv_cfl(i)*visc_rem(i,k)) &
1804 dvl(i) = -(v(i,j,k) - dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1806 endif ;
enddo ;
enddo
1808 do i=ish,ieh ;
if (do_i(i))
then
1809 v_l(i) = v(i,j,k) + dvl(i) * visc_rem(i,k)
1810 v_r(i) = v(i,j,k) + dvr(i) * visc_rem(i,k)
1811 v_0(i) = v(i,j,k) + dv0(i) * visc_rem(i,k)
1813 call merid_flux_layer(v_0, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_0, dvhdv_0, &
1814 visc_rem(:,k), dt, g, us, j, ish, ieh, do_i, cs%vol_CFL)
1815 call merid_flux_layer(v_l, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_l, dvhdv_l, &
1816 visc_rem(:,k), dt, g, us, j, ish, ieh, do_i, cs%vol_CFL)
1817 call merid_flux_layer(v_r, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_r, dvhdv_r, &
1818 visc_rem(:,k), dt, g, us, j, ish, ieh, do_i, cs%vol_CFL)
1819 do i=ish,ieh ;
if (do_i(i))
then
1820 famt_0(i) = famt_0(i) + dvhdv_0(i)
1821 famt_l(i) = famt_l(i) + dvhdv_l(i)
1822 famt_r(i) = famt_r(i) + dvhdv_r(i)
1823 vhtot_l(i) = vhtot_l(i) + vh_l(i)
1824 vhtot_r(i) = vhtot_r(i) + vh_r(i)
1827 do i=ish,ieh ;
if (do_i(i))
then
1828 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1829 if ((dvl(i) - dv0(i)) /= 0.0) &
1830 fa_avg = vhtot_l(i) / (dvl(i) - dv0(i))
1831 if (fa_avg > max(fa_0, famt_l(i)))
then ; fa_avg = max(fa_0, famt_l(i))
1832 elseif (fa_avg < min(fa_0, famt_l(i)))
then ; fa_0 = fa_avg ;
endif
1833 bt_cont%FA_v_S0(i,j) = fa_0 ; bt_cont%FA_v_SS(i,j) = famt_l(i)
1834 if (abs(fa_0-famt_l(i)) <= 1e-12*fa_0)
then ; bt_cont%vBT_SS(i,j) = 0.0 ;
else
1835 bt_cont%vBT_SS(i,j) = (1.5 * (dvl(i) - dv0(i))) * &
1836 ((famt_l(i) - fa_avg) / (famt_l(i) - fa_0))
1839 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1840 if ((dvr(i) - dv0(i)) /= 0.0) &
1841 fa_avg = vhtot_r(i) / (dvr(i) - dv0(i))
1842 if (fa_avg > max(fa_0, famt_r(i)))
then ; fa_avg = max(fa_0, famt_r(i))
1843 elseif (fa_avg < min(fa_0, famt_r(i)))
then ; fa_0 = fa_avg ;
endif
1844 bt_cont%FA_v_N0(i,j) = fa_0 ; bt_cont%FA_v_NN(i,j) = famt_r(i)
1845 if (abs(famt_r(i) - fa_0) <= 1e-12*fa_0)
then ; bt_cont%vBT_NN(i,j) = 0.0 ;
else
1846 bt_cont%vBT_NN(i,j) = (1.5 * (dvr(i) - dv0(i))) * &
1847 ((famt_r(i) - fa_avg) / (famt_r(i) - fa_0))
1850 bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1851 bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1852 bt_cont%vBT_SS(i,j) = 0.0 ; bt_cont%vBT_NN(i,j) = 0.0
1855 end subroutine set_merid_bt_cont
1858 subroutine ppm_reconstruction_x(h_in, h_L, h_R, G, LB, h_min, monotonic, simple_2nd, OBC)
1860 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
1861 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_L
1863 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_R
1866 real,
intent(in) :: h_min
1868 logical,
optional,
intent(in) :: monotonic
1871 logical,
optional,
intent(in) :: simple_2nd
1877 real,
dimension(SZI_(G),SZJ_(G)) :: slp
1878 real,
parameter :: oneSixth = 1./6.
1879 real :: h_ip1, h_im1
1881 logical :: use_CW84, use_2nd
1882 character(len=256) :: mesg
1883 integer :: i, j, isl, iel, jsl, jel, n, stencil
1884 logical :: local_open_BC
1887 use_cw84 = .false. ;
if (
present(monotonic)) use_cw84 = monotonic
1888 use_2nd = .false. ;
if (
present(simple_2nd)) use_2nd = simple_2nd
1890 local_open_bc = .false.
1891 if (
present(obc))
then ;
if (
associated(obc))
then
1892 local_open_bc = obc%open_u_BCs_exist_globally
1895 isl = lb%ish-1 ; iel = lb%ieh+1 ; jsl = lb%jsh ; jel = lb%jeh
1898 stencil = 2 ;
if (use_2nd) stencil = 1
1900 if ((isl-stencil < g%isd) .or. (iel+stencil > g%ied))
then
1901 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", &
1902 & "x-halo that needs to be increased by ",i2,".")') &
1903 stencil + max(g%isd-isl,iel-g%ied)
1904 call mom_error(fatal,mesg)
1906 if ((jsl < g%jsd) .or. (jel > g%jed))
then
1907 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", &
1908 & "y-halo that needs to be increased by ",i2,".")') &
1909 max(g%jsd-jsl,jel-g%jed)
1910 call mom_error(fatal,mesg)
1914 do j=jsl,jel ;
do i=isl,iel
1915 h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1916 h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1917 h_l(i,j) = 0.5*( h_im1 + h_in(i,j) )
1918 h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) )
1921 do j=jsl,jel ;
do i=isl-1,iel+1
1922 if ((g%mask2dT(i-1,j) * g%mask2dT(i,j) * g%mask2dT(i+1,j)) == 0.0)
then
1926 slp(i,j) = 0.5 * (h_in(i+1,j) - h_in(i-1,j))
1928 dmx = max(h_in(i+1,j), h_in(i-1,j), h_in(i,j)) - h_in(i,j)
1929 dmn = h_in(i,j) - min(h_in(i+1,j), h_in(i-1,j), h_in(i,j))
1930 slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1935 if (local_open_bc)
then
1936 do n=1, obc%number_of_segments
1937 segment => obc%segment(n)
1938 if (.not. segment%on_pe) cycle
1939 if (segment%direction == obc_direction_e .or. &
1940 segment%direction == obc_direction_w)
then
1942 do j=segment%HI%jsd,segment%HI%jed
1950 do j=jsl,jel ;
do i=isl,iel
1955 h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1956 h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1958 h_l(i,j) = 0.5*( h_im1 + h_in(i,j) ) + onesixth*( slp(i-1,j) - slp(i,j) )
1959 h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i+1,j) )
1963 if (local_open_bc)
then
1964 do n=1, obc%number_of_segments
1965 segment => obc%segment(n)
1966 if (.not. segment%on_pe) cycle
1967 if (segment%direction == obc_direction_e)
then
1969 do j=segment%HI%jsd,segment%HI%jed
1970 h_l(i+1,j) = h_in(i,j)
1971 h_r(i+1,j) = h_in(i,j)
1972 h_l(i,j) = h_in(i,j)
1973 h_r(i,j) = h_in(i,j)
1975 elseif (segment%direction == obc_direction_w)
then
1977 do j=segment%HI%jsd,segment%HI%jed
1978 h_l(i,j) = h_in(i+1,j)
1979 h_r(i,j) = h_in(i+1,j)
1980 h_l(i+1,j) = h_in(i+1,j)
1981 h_r(i+1,j) = h_in(i+1,j)
1988 call ppm_limit_cw84(h_in, h_l, h_r, g, isl, iel, jsl, jel)
1990 call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
1994 end subroutine ppm_reconstruction_x
1997 subroutine ppm_reconstruction_y(h_in, h_L, h_R, G, LB, h_min, monotonic, simple_2nd, OBC)
1999 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
2000 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_L
2002 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_R
2005 real,
intent(in) :: h_min
2007 logical,
optional,
intent(in) :: monotonic
2010 logical,
optional,
intent(in) :: simple_2nd
2016 real,
dimension(SZI_(G),SZJ_(G)) :: slp
2017 real,
parameter :: oneSixth = 1./6.
2018 real :: h_jp1, h_jm1
2020 logical :: use_CW84, use_2nd
2021 character(len=256) :: mesg
2022 integer :: i, j, isl, iel, jsl, jel, n, stencil
2023 logical :: local_open_BC
2026 use_cw84 = .false. ;
if (
present(monotonic)) use_cw84 = monotonic
2027 use_2nd = .false. ;
if (
present(simple_2nd)) use_2nd = simple_2nd
2029 local_open_bc = .false.
2030 if (
present(obc))
then ;
if (
associated(obc))
then
2031 local_open_bc = obc%open_v_BCs_exist_globally
2034 isl = lb%ish ; iel = lb%ieh ; jsl = lb%jsh-1 ; jel = lb%jeh+1
2037 stencil = 2 ;
if (use_2nd) stencil = 1
2039 if ((isl < g%isd) .or. (iel > g%ied))
then
2040 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", &
2041 & "x-halo that needs to be increased by ",i2,".")') &
2042 max(g%isd-isl,iel-g%ied)
2043 call mom_error(fatal,mesg)
2045 if ((jsl-stencil < g%jsd) .or. (jel+stencil > g%jed))
then
2046 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", &
2047 & "y-halo that needs to be increased by ",i2,".")') &
2048 stencil + max(g%jsd-jsl,jel-g%jed)
2049 call mom_error(fatal,mesg)
2053 do j=jsl,jel ;
do i=isl,iel
2054 h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
2055 h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
2056 h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) )
2057 h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) )
2060 do j=jsl-1,jel+1 ;
do i=isl,iel
2061 if ((g%mask2dT(i,j-1) * g%mask2dT(i,j) * g%mask2dT(i,j+1)) == 0.0)
then
2065 slp(i,j) = 0.5 * (h_in(i,j+1) - h_in(i,j-1))
2067 dmx = max(h_in(i,j+1), h_in(i,j-1), h_in(i,j)) - h_in(i,j)
2068 dmn = h_in(i,j) - min(h_in(i,j+1), h_in(i,j-1), h_in(i,j))
2069 slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
2074 if (local_open_bc)
then
2075 do n=1, obc%number_of_segments
2076 segment => obc%segment(n)
2077 if (.not. segment%on_pe) cycle
2078 if (segment%direction == obc_direction_s .or. &
2079 segment%direction == obc_direction_n)
then
2081 do i=segment%HI%isd,segment%HI%ied
2089 do j=jsl,jel ;
do i=isl,iel
2092 h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
2093 h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
2095 h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) ) + onesixth*( slp(i,j-1) - slp(i,j) )
2096 h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i,j+1) )
2100 if (local_open_bc)
then
2101 do n=1, obc%number_of_segments
2102 segment => obc%segment(n)
2103 if (.not. segment%on_pe) cycle
2104 if (segment%direction == obc_direction_n)
then
2106 do i=segment%HI%isd,segment%HI%ied
2107 h_l(i,j+1) = h_in(i,j)
2108 h_r(i,j+1) = h_in(i,j)
2109 h_l(i,j) = h_in(i,j)
2110 h_r(i,j) = h_in(i,j)
2112 elseif (segment%direction == obc_direction_s)
then
2114 do i=segment%HI%isd,segment%HI%ied
2115 h_l(i,j) = h_in(i,j+1)
2116 h_r(i,j) = h_in(i,j+1)
2117 h_l(i,j+1) = h_in(i,j+1)
2118 h_r(i,j+1) = h_in(i,j+1)
2125 call ppm_limit_cw84(h_in, h_l, h_r, g, isl, iel, jsl, jel)
2127 call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
2131 end subroutine ppm_reconstruction_y
2137 subroutine ppm_limit_pos(h_in, h_L, h_R, h_min, G, iis, iie, jis, jie)
2139 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
2140 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_L
2141 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_R
2142 real,
intent(in) :: h_min
2144 integer,
intent(in) :: iis
2145 integer,
intent(in) :: iie
2146 integer,
intent(in) :: jis
2147 integer,
intent(in) :: jie
2150 real :: curv, dh, scale
2151 character(len=256) :: mesg
2154 do j=jis,jie ;
do i=iis,iie
2157 curv = 3.0*(h_l(i,j) + h_r(i,j) - 2.0*h_in(i,j))
2158 if (curv > 0.0)
then
2159 dh = h_r(i,j) - h_l(i,j)
2160 if (abs(dh) < curv)
then
2161 if (h_in(i,j) <= h_min)
then
2162 h_l(i,j) = h_in(i,j) ; h_r(i,j) = h_in(i,j)
2163 elseif (12.0*curv*(h_in(i,j) - h_min) < (curv**2 + 3.0*dh**2))
then
2166 scale = 12.0*curv*(h_in(i,j) - h_min) / (curv**2 + 3.0*dh**2)
2167 h_l(i,j) = h_in(i,j) + scale*(h_l(i,j) - h_in(i,j))
2168 h_r(i,j) = h_in(i,j) + scale*(h_r(i,j) - h_in(i,j))
2174 end subroutine ppm_limit_pos
2178 subroutine ppm_limit_cw84(h_in, h_L, h_R, G, iis, iie, jis, jie)
2180 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
2181 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_L
2183 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_R
2185 integer,
intent(in) :: iis
2186 integer,
intent(in) :: iie
2187 integer,
intent(in) :: jis
2188 integer,
intent(in) :: jie
2191 real :: h_i, RLdiff, RLdiff2, RLmean, FunFac
2192 character(len=256) :: mesg
2195 do j=jis,jie ;
do i=iis,iie
2199 if ( ( h_r(i,j) - h_i ) * ( h_i - h_l(i,j) ) <= 0. )
then
2200 h_l(i,j) = h_i ; h_r(i,j) = h_i
2202 rldiff = h_r(i,j) - h_l(i,j)
2203 rlmean = 0.5 * ( h_r(i,j) + h_l(i,j) )
2204 funfac = 6. * rldiff * ( h_i - rlmean )
2205 rldiff2 = rldiff * rldiff
2206 if ( funfac > rldiff2 ) h_l(i,j) = 3. * h_i - 2. * h_r(i,j)
2207 if ( funfac < -rldiff2 ) h_r(i,j) = 3. * h_i - 2. * h_l(i,j)
2212 end subroutine ppm_limit_cw84
2215 function ratio_max(a, b, maxrat)
result(ratio)
2216 real,
intent(in) :: a
2217 real,
intent(in) :: b
2218 real,
intent(in) :: maxrat
2221 if (abs(a) > abs(maxrat*b))
then
2226 end function ratio_max
2229 subroutine continuity_ppm_init(Time, G, GV, US, param_file, diag, CS)
2230 type(time_type),
target,
intent(in) :: time
2236 type(
diag_ctrl),
target,
intent(inout) :: diag
2240 #include "version_variable.h"
2242 character(len=40) :: mdl =
"MOM_continuity_PPM"
2244 if (
associated(cs))
then
2245 call mom_error(warning,
"continuity_PPM_init called with associated control structure.")
2252 call get_param(param_file, mdl,
"MONOTONIC_CONTINUITY", cs%monotonic, &
2253 "If true, CONTINUITY_PPM uses the Colella and Woodward "//&
2254 "monotonic limiter. The default (false) is to use a "//&
2255 "simple positive definite limiter.", default=.false.)
2256 call get_param(param_file, mdl,
"SIMPLE_2ND_PPM_CONTINUITY", cs%simple_2nd, &
2257 "If true, CONTINUITY_PPM uses a simple 2nd order "//&
2258 "(arithmetic mean) interpolation of the edge values. "//&
2259 "This may give better PV conservation properties. While "//&
2260 "it formally reduces the accuracy of the continuity "//&
2261 "solver itself in the strongly advective limit, it does "//&
2262 "not reduce the overall order of accuracy of the dynamic "//&
2263 "core.", default=.false.)
2264 call get_param(param_file, mdl,
"UPWIND_1ST_CONTINUITY", cs%upwind_1st, &
2265 "If true, CONTINUITY_PPM becomes a 1st-order upwind "//&
2266 "continuity solver. This scheme is highly diffusive "//&
2267 "but may be useful for debugging or in single-column "//&
2268 "mode where its minimal stencil is useful.", default=.false.)
2269 call get_param(param_file, mdl,
"ETA_TOLERANCE", cs%tol_eta, &
2270 "The tolerance for the differences between the "//&
2271 "barotropic and baroclinic estimates of the sea surface "//&
2272 "height due to the fluxes through each face. The total "//&
2273 "tolerance for SSH is 4 times this value. The default "//&
2274 "is 0.5*NK*ANGSTROM, and this should not be set less "//&
2275 "than about 10^-15*MAXIMUM_DEPTH.", units=
"m", scale=gv%m_to_H, &
2276 default=0.5*g%ke*gv%Angstrom_m, unscaled=tol_eta_m)
2279 call get_param(param_file, mdl,
"ETA_TOLERANCE_AUX", cs%tol_eta_aux, &
2280 "The tolerance for free-surface height discrepancies "//&
2281 "between the barotropic solution and the sum of the "//&
2282 "layer thicknesses when calculating the auxiliary "//&
2283 "corrected velocities. By default, this is the same as "//&
2284 "ETA_TOLERANCE, but can be made larger for efficiency.", &
2285 units=
"m", default=tol_eta_m, scale=gv%m_to_H)
2286 call get_param(param_file, mdl,
"VELOCITY_TOLERANCE", cs%tol_vel, &
2287 "The tolerance for barotropic velocity discrepancies "//&
2288 "between the barotropic solution and the sum of the "//&
2289 "layer thicknesses.", units=
"m s-1", default=3.0e8, scale=us%m_s_to_L_T)
2292 call get_param(param_file, mdl,
"CONT_PPM_AGGRESS_ADJUST", cs%aggress_adjust,&
2293 "If true, allow the adjusted velocities to have a "//&
2294 "relative CFL change up to 0.5.", default=.false.)
2295 cs%vol_CFL = cs%aggress_adjust
2296 call get_param(param_file, mdl,
"CONT_PPM_VOLUME_BASED_CFL", cs%vol_CFL, &
2297 "If true, use the ratio of the open face lengths to the "//&
2298 "tracer cell areas when estimating CFL numbers. The "//&
2299 "default is set by CONT_PPM_AGGRESS_ADJUST.", &
2300 default=cs%aggress_adjust, do_not_read=cs%aggress_adjust)
2301 call get_param(param_file, mdl,
"CONTINUITY_CFL_LIMIT", cs%CFL_limit_adjust, &
2302 "The maximum CFL of the adjusted velocities.", units=
"nondim", &
2304 call get_param(param_file, mdl,
"CONT_PPM_BETTER_ITER", cs%better_iter, &
2305 "If true, stop corrective iterations using a velocity "//&
2306 "based criterion and only stop if the iteration is "//&
2307 "better than all predecessors.", default=.true.)
2308 call get_param(param_file, mdl,
"CONT_PPM_USE_VISC_REM_MAX", &
2309 cs%use_visc_rem_max, &
2310 "If true, use more appropriate limiting bounds for "//&
2311 "corrections in strongly viscous columns.", default=.true.)
2312 call get_param(param_file, mdl,
"CONT_PPM_MARGINAL_FACE_AREAS", cs%marginal_faces, &
2313 "If true, use the marginal face areas from the continuity "//&
2314 "solver for use as the weights in the barotropic solver. "//&
2315 "Otherwise use the transport averaged areas.", default=.true.)
2319 id_clock_update = cpu_clock_id(
'(Ocean continuity update)', grain=clock_routine)
2320 id_clock_correct = cpu_clock_id(
'(Ocean continuity correction)', grain=clock_routine)
2322 end subroutine continuity_ppm_init
2325 function continuity_ppm_stencil(CS)
result(stencil)
2329 stencil = 3 ;
if (cs%simple_2nd) stencil = 2 ;
if (cs%upwind_1st) stencil = 1
2331 end function continuity_ppm_stencil
2334 subroutine continuity_ppm_end(CS)
2337 end subroutine continuity_ppm_end