6 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, clock_routine
16 implicit none ;
private 18 #include <MOM_memory.h> 44 real :: cfl_limit_adjust
45 logical :: aggress_adjust
51 logical :: better_iter
54 logical :: use_visc_rem_max
56 logical :: marginal_faces
66 integer :: ish, ieh, jsh, jeh
74 subroutine continuity_ppm(u, v, hin, h, uh, vh, dt, G, GV, CS, uhbt, vhbt, OBC, &
75 visc_rem_u, visc_rem_v, u_cor, v_cor, &
76 uhbt_aux, vhbt_aux, u_cor_aux, v_cor_aux, BT_cont)
80 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
81 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
82 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: hin
83 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
84 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out) :: uh
86 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out) :: vh
88 real,
intent(in) :: dt
90 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in),
optional :: uhbt
92 real,
dimension(SZI_(G),SZJB_(G)),
intent(in),
optional :: vhbt
95 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in),
optional :: visc_rem_u
100 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in),
optional :: visc_rem_v
105 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out),
optional :: u_cor
107 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out),
optional :: v_cor
109 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in),
optional :: uhbt_aux
111 real,
dimension(SZI_(G),SZJB_(G)),
intent(in),
optional :: vhbt_aux
113 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out),
optional :: u_cor_aux
115 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out),
optional :: v_cor_aux
120 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_input
123 integer :: is, ie, js, je, nz, stencil
127 logical :: local_Flather_EW, local_Flather_NS
128 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
132 if (.not.
associated(cs))
call mom_error(fatal, &
133 "MOM_continuity_PPM: Module must be initialized before it is used.")
134 x_first = (mod(g%first_direction,2) == 0)
136 local_flather_ew = .false. ; local_flather_ns = .false.
137 if (
present(obc))
then ;
if (
associated(obc))
then ;
if (obc%OBC_pe)
then 138 local_flather_ew = obc%Flather_u_BCs_exist_globally
139 local_flather_ns = obc%Flather_v_BCs_exist_globally
142 if (local_flather_ew .or. local_flather_ns) &
143 h_input(:,:,:) = hin(:,:,:)
144 endif ;
endif ;
endif 146 if (
present(visc_rem_u) .neqv.
present(visc_rem_v))
call mom_error(fatal, &
147 "MOM_continuity_PPM: Either both visc_rem_u and visc_rem_v or neither"// &
148 " one must be present in call to continuity_PPM.")
150 stencil = 3 ;
if (cs%simple_2nd) stencil = 2 ;
if (cs%upwind_1st) stencil = 1
154 lb%ish = g%isc ; lb%ieh = g%iec
155 lb%jsh = g%jsc-stencil ; lb%jeh = g%jec+stencil
156 call zonal_mass_flux(u, hin, uh, dt, g, gv, cs, lb, uhbt, obc, visc_rem_u, &
157 u_cor, uhbt_aux, u_cor_aux, bt_cont)
161 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
162 h(i,j,k) = hin(i,j,k) - dt* g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
165 enddo ;
enddo ;
enddo 168 if (local_flather_ew)
then 170 do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh+1
171 if (obc%segnum_u(i-1,j) /= obc_none)
then 173 h(i,j,k) = h_input(i-1,j,k)
177 if (obc%segnum_u(i,j) /= obc_none)
then 179 h(i,j,k) = h_input(i+1,j,k)
184 lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
188 call meridional_mass_flux(v, h, vh, dt, g, gv, cs, lb, vhbt, obc, visc_rem_v, &
189 v_cor, vhbt_aux, v_cor_aux, bt_cont)
193 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
194 h(i,j,k) = h(i,j,k) - dt*g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
196 if (h(i,j,k) < h_min) h(i,j,k) = h_min
197 enddo ;
enddo ;
enddo 200 if (local_flather_ns)
then 202 do j=lb%jsh,lb%jeh+1 ;
do i=lb%ish-1,lb%ieh+1
203 if (obc%segnum_v(i,j-1) /= obc_none)
then 205 h(i,j,k) = h_input(i,j-1,k)
208 do j=lb%jsh-1,lb%jeh ;
do i=lb%ish-1,lb%ieh+1
209 if (obc%segnum_v(i,j) /= obc_none)
then 211 h(i,j,k) = h_input(i,j+1,k)
218 lb%ish = g%isc-stencil ; lb%ieh = g%iec+stencil
219 lb%jsh = g%jsc ; lb%jeh = g%jec
221 call meridional_mass_flux(v, hin, vh, dt, g, gv, cs, lb, vhbt, obc, visc_rem_v, &
222 v_cor, vhbt_aux, v_cor_aux, bt_cont)
226 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
227 h(i,j,k) = hin(i,j,k) - dt*g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
228 enddo ;
enddo ;
enddo 231 if (local_flather_ns)
then 233 do j=lb%jsh,lb%jeh+1 ;
do i=lb%ish-1,lb%ieh+1
234 if (obc%segnum_v(i,j-1) /= obc_none)
then 236 h(i,j,k) = h_input(i,j-1,k)
239 do j=lb%jsh-1,lb%jeh ;
do i=lb%ish-1,lb%ieh+1
240 if (obc%segnum_v(i,j) /= obc_none)
then 242 h(i,j,k) = h_input(i,j+1,k)
250 lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
251 call zonal_mass_flux(u, h, uh, dt, g, gv, cs, lb, uhbt, obc, visc_rem_u, &
252 u_cor, uhbt_aux, u_cor_aux, bt_cont)
256 do k=1,nz ;
do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh
257 h(i,j,k) = h(i,j,k) - dt* g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
259 if (h(i,j,k) < h_min) h(i,j,k) = h_min
260 enddo ;
enddo ;
enddo 263 if (local_flather_ew)
then 265 do j=lb%jsh,lb%jeh ;
do i=lb%ish,lb%ieh+1
266 if (obc%segnum_u(i-1,j) /= obc_none)
then 268 h(i,j,k) = h_input(i-1,j,k)
272 if (obc%segnum_u(i,j) /= obc_none)
then 274 h(i,j,k) = h_input(i+1,j,k)
284 subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, CS, LB, uhbt, OBC, &
285 visc_rem_u, u_cor, uhbt_aux, u_cor_aux, BT_cont)
288 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
289 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h_in
291 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out) :: uh
293 real,
intent(in) :: dt
297 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in),
optional :: visc_rem_u
302 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in),
optional :: uhbt
304 real,
dimension(SZIB_(G),SZJ_(G)),
intent(in),
optional :: uhbt_aux
306 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out),
optional :: u_cor
309 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(out),
optional :: u_cor_aux
316 real,
dimension(SZIB_(G),SZK_(G)) :: duhdu
317 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_L, h_R
318 real,
dimension(SZIB_(G)) :: &
325 logical,
dimension(SZIB_(G)) :: do_I
326 real,
dimension(SZIB_(G),SZK_(G)) :: &
334 integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
335 logical :: do_aux, local_specified_BC, use_visc_rem, set_BT_cont, any_simple_OBC
336 logical :: local_Flather_OBC, local_open_BC, is_simple
339 do_aux = (
present(uhbt_aux) .and.
present(u_cor_aux))
340 use_visc_rem =
present(visc_rem_u)
341 local_specified_bc = .false. ; set_bt_cont = .false. ; local_flather_obc = .false.
342 local_open_bc = .false.
343 if (
present(bt_cont)) set_bt_cont = (
associated(bt_cont))
344 if (
present(obc))
then ;
if (
associated(obc))
then 345 local_specified_bc = obc%specified_u_BCs_exist_globally
346 local_flather_obc = obc%Flather_u_BCs_exist_globally .or. &
347 obc%Flather_v_BCs_exist_globally
348 local_open_bc = obc%open_u_BCs_exist_globally
350 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
352 cfl_dt = cs%CFL_limit_adjust / dt
354 if (cs%aggress_adjust) cfl_dt = i_dt
360 if (cs%upwind_1st)
then 361 do j=jsh,jeh ;
do i=ish-1,ieh+1
362 h_l(i,j,k) = h_in(i,j,k) ; h_r(i,j,k) = h_in(i,j,k)
365 call ppm_reconstruction_x(h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), g, lb, &
366 2.0*gv%Angstrom, cs%monotonic, simple_2nd=cs%simple_2nd)
368 do i=ish-1,ieh ; visc_rem(i,k) = 1.0 ;
enddo 370 if (local_open_bc)
then 371 do n=1, obc%number_of_segments
372 segment => obc%segment(n)
373 if (.not. segment%on_pe .or. segment%specified) cycle
376 do k=1,nz ;
do j=segment%HI%jsd,segment%HI%jed
377 h_in(i+1,j,k) = h_in(i,j,k)
378 h_l(i+1,j,k) = h_in(i,j,k)
379 h_r(i+1,j,k) = h_in(i,j,k)
380 h_r(i,j,k) = h_in(i,j,k)
384 do k=1,nz ;
do j=segment%HI%jsd,segment%HI%jed
385 h_in(i,j,k) = h_in(i+1,j,k)
386 h_l(i,j,k) = h_in(i+1,j,k)
387 h_r(i,j,k) = h_in(i+1,j,k)
388 h_l(i+1,j,k) = h_in(i+1,j,k)
404 do i=ish-1,ieh ; do_i(i) = .true. ; visc_rem_max(i) = 0.0 ;
enddo 407 if (use_visc_rem)
then ;
do i=ish-1,ieh
408 visc_rem(i,k) = visc_rem_u(i,j,k)
409 visc_rem_max(i) = max(visc_rem_max(i), visc_rem(i,k))
411 call zonal_flux_layer(u(:,j,k), h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), &
412 uh(:,j,k), duhdu(:,k), visc_rem(:,k), &
413 dt, g, j, ish, ieh, do_i, cs%vol_CFL)
414 if (local_specified_bc)
then 416 if (obc%segment(obc%segnum_u(i,j))%specified) &
417 uh(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_trans(i,j,k)
422 if ((.not.use_visc_rem).or.(.not.cs%use_visc_rem_max))
then ;
do i=ish-1,ieh
423 visc_rem_max(i) = 1.0
426 if (
present(uhbt) .or. do_aux .or. set_bt_cont)
then 431 if (visc_rem_max(i) > 0.0) i_vrm = 1.0 / visc_rem_max(i)
433 dx_w =
ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
434 dx_e =
ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
435 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif 436 du_max_cfl(i) = 2.0* (cfl_dt * dx_w) * i_vrm
437 du_min_cfl(i) = -2.0 * (cfl_dt * dx_e) * i_vrm
438 uh_tot_0(i) = 0.0 ; duhdu_tot_0(i) = 0.0
440 do k=1,nz ;
do i=ish-1,ieh
441 duhdu_tot_0(i) = duhdu_tot_0(i) + duhdu(i,k)
442 uh_tot_0(i) = uh_tot_0(i) + uh(i,j,k)
444 if (use_visc_rem)
then 445 if (cs%aggress_adjust)
then 446 do k=1,nz ;
do i=ish-1,ieh
448 dx_w =
ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
449 dx_e =
ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
450 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif 452 du_lim = 0.499*((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k)))
453 if (du_max_cfl(i) * visc_rem(i,k) > du_lim) &
454 du_max_cfl(i) = du_lim / visc_rem(i,k)
456 du_lim = 0.499*((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k)))
457 if (du_min_cfl(i) * visc_rem(i,k) < du_lim) &
458 du_min_cfl(i) = du_lim / visc_rem(i,k)
461 do k=1,nz ;
do i=ish-1,ieh
463 dx_w =
ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
464 dx_e =
ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
465 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif 467 if (du_max_cfl(i) * visc_rem(i,k) > dx_w*cfl_dt - u(i,j,k)) &
468 du_max_cfl(i) = (dx_w*cfl_dt - u(i,j,k)) / visc_rem(i,k)
469 if (du_min_cfl(i) * visc_rem(i,k) < -dx_e*cfl_dt - u(i,j,k)) &
470 du_min_cfl(i) = -(dx_e*cfl_dt + u(i,j,k)) / visc_rem(i,k)
474 if (cs%aggress_adjust)
then 475 do k=1,nz ;
do i=ish-1,ieh
477 dx_w =
ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
478 dx_e =
ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
479 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif 481 du_max_cfl(i) = min(du_max_cfl(i), 0.499 * &
482 ((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k))) )
483 du_min_cfl(i) = max(du_min_cfl(i), 0.499 * &
484 ((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k))) )
487 do k=1,nz ;
do i=ish-1,ieh
489 dx_w =
ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
490 dx_e =
ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
491 else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ;
endif 493 du_max_cfl(i) = min(du_max_cfl(i), dx_w*cfl_dt - u(i,j,k))
494 du_min_cfl(i) = max(du_min_cfl(i), -(dx_e*cfl_dt + u(i,j,k)))
499 du_max_cfl(i) = max(du_max_cfl(i),0.0)
500 du_min_cfl(i) = min(du_min_cfl(i),0.0)
505 any_simple_obc = .false.
506 if (
present(uhbt) .or. do_aux .or. set_bt_cont)
then 507 if (local_specified_bc .or. local_flather_obc)
then ;
do i=ish-1,ieh
509 is_simple = obc%segment(obc%segnum_u(i,j))%specified
510 do_i(i) = .not.(obc%segnum_u(i,j) /= obc_none .and. is_simple)
511 any_simple_obc = any_simple_obc .or. is_simple
512 enddo ;
else ;
do i=ish-1,ieh
517 if (
present(uhbt))
then 519 duhdu_tot_0, du, du_max_cfl, du_min_cfl, dt, g, &
520 cs, visc_rem, j, ish, ieh, do_i, .true., uh)
522 if (
present(u_cor))
then ;
do k=1,nz
523 do i=ish-1,ieh ; u_cor(i,j,k) = u(i,j,k) + du(i) * visc_rem(i,k) ;
enddo 524 if (local_specified_bc)
then ;
do i=ish-1,ieh
525 if (obc%segment(obc%segnum_u(i,j))%specified) &
526 u_cor(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
534 duhdu_tot_0, du, du_max_cfl, du_min_cfl, dt, g, &
535 cs, visc_rem, j, ish, ieh, do_i, .false.)
538 do i=ish-1,ieh ; u_cor_aux(i,j,k) = u(i,j,k) + du(i) * visc_rem(i,k) ;
enddo 539 if (local_specified_bc)
then ;
do i=ish-1,ieh
540 if (obc%segment(obc%segnum_u(i,j))%specified) &
541 u_cor_aux(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
546 if (set_bt_cont)
then 548 du_max_cfl, du_min_cfl, dt, g, cs, visc_rem, &
549 visc_rem_max, j, ish, ieh, do_i)
550 if (any_simple_obc)
then 552 do_i(i) = obc%segment(obc%segnum_u(i,j))%specified
553 if (do_i(i)) bt_cont%Fa_u_W0(i,j) = gv%H_subroundoff*g%dy_Cu(i,j)
555 do k=1,nz ;
do i=ish-1,ieh ;
if (do_i(i))
then 556 if (abs(obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)) > 0.0) &
557 bt_cont%Fa_u_W0(i,j) = bt_cont%Fa_u_W0(i,j) + &
558 obc%segment(obc%segnum_u(i,j))%normal_trans(i,j,k) / &
559 obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
560 endif ;
enddo ;
enddo 561 do i=ish-1,ieh ;
if (do_i(i))
then 562 bt_cont%Fa_u_E0(i,j) = bt_cont%Fa_u_W0(i,j)
563 bt_cont%Fa_u_WW(i,j) = bt_cont%Fa_u_W0(i,j)
564 bt_cont%Fa_u_EE(i,j) = bt_cont%Fa_u_W0(i,j)
573 if (set_bt_cont)
then ;
if (
associated(bt_cont%h_u))
then 574 if (
present(u_cor))
then 576 cs%vol_CFL, cs%marginal_faces, visc_rem_u)
579 cs%vol_CFL, cs%marginal_faces, visc_rem_u)
586 subroutine zonal_flux_layer(u, h, h_L, h_R, uh, duhdu, visc_rem, dt, G, j, &
587 ish, ieh, do_I, vol_CFL)
589 real,
dimension(SZIB_(G)),
intent(in) :: u
590 real,
dimension(SZIB_(G)),
intent(in) :: visc_rem
595 real,
dimension(SZI_(G)),
intent(in) :: h
596 real,
dimension(SZI_(G)),
intent(in) :: h_L
597 real,
dimension(SZI_(G)),
intent(in) :: h_R
598 real,
dimension(SZIB_(G)),
intent(inout) :: uh
600 real,
dimension(SZIB_(G)),
intent(inout) :: duhdu
602 real,
intent(in) :: dt
603 integer,
intent(in) :: j
604 integer,
intent(in) :: ish
605 integer,
intent(in) :: ieh
606 logical,
dimension(SZIB_(G)),
intent(in) :: do_I
607 logical,
intent(in) :: vol_CFL
616 do i=ish-1,ieh ;
if (do_i(i))
then 619 if (vol_cfl)
then ; cfl = (u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
620 else ; cfl = u(i) * dt * g%IdxT(i,j) ;
endif 621 curv_3 = h_l(i) + h_r(i) - 2.0*h(i)
622 uh(i) = g%dy_Cu(i,j) * u(i) * &
623 (h_r(i) + cfl * (0.5*(h_l(i) - h_r(i)) + curv_3*(cfl - 1.5)))
624 h_marg = h_r(i) + cfl * ((h_l(i) - h_r(i)) + 3.0*curv_3*(cfl - 1.0))
625 elseif (u(i) < 0.0)
then 626 if (vol_cfl)
then ; cfl = (-u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
627 else ; cfl = -u(i) * dt * g%IdxT(i+1,j) ;
endif 628 curv_3 = h_l(i+1) + h_r(i+1) - 2.0*h(i+1)
629 uh(i) = g%dy_Cu(i,j) * u(i) * &
630 (h_l(i+1) + cfl * (0.5*(h_r(i+1)-h_l(i+1)) + curv_3*(cfl - 1.5)))
631 h_marg = h_l(i+1) + cfl * ((h_r(i+1)-h_l(i+1)) + 3.0*curv_3*(cfl - 1.0))
634 h_marg = 0.5 * (h_l(i+1) + h_r(i))
636 duhdu(i) = g%dy_Cu(i,j) * h_marg * visc_rem(i)
643 marginal, visc_rem_u)
645 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
646 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
648 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
650 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
652 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h_u
654 real,
intent(in) :: dt
656 logical,
intent(in) :: vol_CFL
659 logical,
intent(in) :: marginal
662 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in),
optional :: visc_rem_u
675 integer :: i, j, k, ish, ieh, jsh, jeh, nz
676 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
682 do k=1,nz ;
do j=jsh,jeh ;
do i=ish-1,ieh
683 if (u(i,j,k) > 0.0)
then 684 if (vol_cfl)
then ; cfl = (u(i,j,k) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
685 else ; cfl = u(i,j,k) * dt * g%IdxT(i,j) ;
endif 686 curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
687 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))
688 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))
689 elseif (u(i,j,k) < 0.0)
then 690 if (vol_cfl)
then ; cfl = (-u(i,j,k)*dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
691 else ; cfl = -u(i,j,k) * dt * g%IdxT(i+1,j) ;
endif 692 curv_3 = h_l(i+1,j,k) + h_r(i+1,j,k) - 2.0*h(i+1,j,k)
693 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))
694 h_marg = h_l(i+1,j,k) + cfl * ((h_r(i+1,j,k)-h_l(i+1,j,k)) + &
695 3.0*curv_3*(cfl - 1.0))
697 h_avg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
700 h_marg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
705 if (marginal)
then ; h_u(i,j,k) = h_marg
706 else ; h_u(i,j,k) = h_avg ;
endif 708 if (
present(visc_rem_u))
then 710 do k=1,nz ;
do j=jsh,jeh ;
do i=ish-1,ieh
711 h_u(i,j,k) = h_u(i,j,k) * visc_rem_u(i,j,k)
712 enddo ;
enddo ;
enddo 721 du, du_max_CFL, du_min_CFL, dt, G, CS, visc_rem, &
722 j, ish, ieh, do_I_in, full_precision, uh_3d)
723 type(ocean_grid_type),
intent(inout) :: G
724 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
725 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
727 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
729 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
731 real,
dimension(SZIB_(G),SZK_(G)),
intent(in) :: visc_rem
738 real,
dimension(SZIB_(G)),
intent(in),
optional :: uhbt
740 real,
dimension(SZIB_(G)),
intent(in) :: du_max_CFL
742 real,
dimension(SZIB_(G)),
intent(in) :: du_min_CFL
744 real,
dimension(SZIB_(G)),
intent(in) :: uh_tot_0
746 real,
dimension(SZIB_(G)),
intent(in) :: duhdu_tot_0
748 real,
dimension(SZIB_(G)),
intent(out) :: du
750 real,
intent(in) :: dt
752 integer,
intent(in) :: j
753 integer,
intent(in) :: ish
754 integer,
intent(in) :: ieh
755 logical,
dimension(SZIB_(G)),
intent(in) :: do_I_in
757 logical,
intent(in),
optional :: full_precision
760 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout),
optional :: uh_3d
763 real,
dimension(SZIB_(G),SZK_(G)) :: &
766 real,
dimension(SZIB_(G)) :: &
777 integer :: i, k, nz, itt, max_itts = 20
778 logical :: full_prec, domore, do_I(szib_(g))
781 full_prec = .true. ;
if (
present(full_precision)) full_prec = full_precision
783 uh_aux(:,:) = 0.0 ; duhdu(:,:) = 0.0
785 if (
present(uh_3d))
then ;
do k=1,nz ;
do i=ish-1,ieh
786 uh_aux(i,k) = uh_3d(i,j,k)
787 enddo ;
enddo ;
endif 790 du(i) = 0.0 ; do_i(i) = do_i_in(i)
791 du_max(i) = du_max_cfl(i) ; du_min(i) = du_min_cfl(i)
792 uh_err(i) = uh_tot_0(i) - uhbt(i) ; duhdu_tot(i) = duhdu_tot_0(i)
793 uh_err_best(i) = abs(uh_err(i))
799 case (:1) ; tol_eta = 1e-6 * cs%tol_eta
800 case (2) ; tol_eta = 1e-4 * cs%tol_eta
801 case (3) ; tol_eta = 1e-2 * cs%tol_eta
802 case default ; tol_eta = cs%tol_eta
805 tol_eta = cs%tol_eta_aux ;
if (itt<=1) tol_eta = 1e-6 * cs%tol_eta_aux
810 if (uh_err(i) > 0.0)
then ; du_max(i) = du(i)
811 elseif (uh_err(i) < 0.0)
then ; du_min(i) = du(i)
812 else ; do_i(i) = .false. ;
endif 815 do i=ish-1,ieh ;
if (do_i(i))
then 816 if ((dt*min(g%IareaT(i,j),g%IareaT(i+1,j))*abs(uh_err(i)) > tol_eta) .or.&
817 (cs%better_iter .and. ((abs(uh_err(i)) > tol_vel * duhdu_tot(i)) .or.&
818 (abs(uh_err(i)) > uh_err_best(i))) ))
then 822 ddu = -uh_err(i) / duhdu_tot(i)
825 if (abs(ddu) < 1.0e-15*abs(du(i)))
then 827 elseif (ddu > 0.0)
then 828 if (du(i) >= du_max(i))
then 829 du(i) = 0.5*(du_prev + du_max(i))
830 if (du_max(i) - du_prev < 1.0e-15*abs(du(i))) do_i(i) = .false.
833 if (du(i) <= du_min(i))
then 834 du(i) = 0.5*(du_prev + du_min(i))
835 if (du_prev - du_min(i) < 1.0e-15*abs(du(i))) do_i(i) = .false.
840 du(i) = du(i) - uh_err(i) / duhdu_tot(i)
841 if ((du(i) >= du_max(i)) .or. (du(i) <= du_min(i))) &
842 du(i) = 0.5*(du_max(i) + du_min(i))
844 if (do_i(i)) domore = .true.
849 if (.not.domore)
exit 851 if ((itt < max_itts) .or.
present(uh_3d))
then ;
do k=1,nz
852 do i=ish-1,ieh ; u_new(i) = u(i,j,k) + du(i) * visc_rem(i,k) ;
enddo 853 call zonal_flux_layer(u_new, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), &
854 uh_aux(:,k), duhdu(:,k), visc_rem(:,k), &
855 dt, g, j, ish, ieh, do_i, cs%vol_CFL)
858 if (itt < max_itts)
then 860 uh_err(i) = -uhbt(i) ; duhdu_tot(i) = 0.0
862 do k=1,nz ;
do i=ish-1,ieh
863 uh_err(i) = uh_err(i) + uh_aux(i,k)
864 duhdu_tot(i) = duhdu_tot(i) + duhdu(i,k)
867 uh_err_best(i) = min(uh_err_best(i), abs(uh_err(i)))
875 if (
present(uh_3d))
then ;
do k=1,nz ;
do i=ish-1,ieh
876 uh_3d(i,j,k) = uh_aux(i,k)
877 enddo ;
enddo ;
endif 883 subroutine set_zonal_bt_cont(u, h_in, h_L, h_R, BT_cont, uh_tot_0, duhdu_tot_0, &
884 du_max_CFL, du_min_CFL, dt, G, CS, visc_rem, &
885 visc_rem_max, j, ish, ieh, do_I)
886 type(ocean_grid_type),
intent(inout) :: G
887 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
888 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
890 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
892 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
894 type(bt_cont_type),
intent(inout) :: BT_cont
897 real,
dimension(SZIB_(G)),
intent(in) :: uh_tot_0
899 real,
dimension(SZIB_(G)),
intent(in) :: duhdu_tot_0
901 real,
dimension(SZIB_(G)),
intent(in) :: du_max_CFL
903 real,
dimension(SZIB_(G)),
intent(in) :: du_min_CFL
905 real,
intent(in) :: dt
907 real,
dimension(SZIB_(G),SZK_(G)),
intent(in) :: visc_rem
914 real,
dimension(SZIB_(G)),
intent(in) :: visc_rem_max
915 integer,
intent(in) :: j
916 integer,
intent(in) :: ish
917 integer,
intent(in) :: ieh
918 logical,
dimension(SZIB_(G)),
intent(in) :: do_I
921 real,
dimension(SZIB_(G)) :: &
954 nz = g%ke ; idt = 1.0/dt
955 min_visc_rem = 0.1 ; cfl_min = 1e-6
958 do i=ish-1,ieh ; zeros(i) = 0.0 ;
enddo 960 duhdu_tot_0, du0, du_max_cfl, du_min_cfl, dt, g, &
961 cs, visc_rem, j, ish, ieh, do_i, .true.)
968 if (do_i(i)) domore = .true.
969 du_cfl(i) = (cfl_min * idt) * g%dxCu(i,j)
970 dur(i) = min(0.0,du0(i) - du_cfl(i))
971 dul(i) = max(0.0,du0(i) + du_cfl(i))
972 famt_l(i) = 0.0 ; famt_r(i) = 0.0 ; famt_0(i) = 0.0
973 uhtot_l(i) = 0.0 ; uhtot_r(i) = 0.0
976 if (.not.domore)
then 977 do k=1,nz ;
do i=ish-1,ieh
978 bt_cont%FA_u_W0(i,j) = 0.0 ; bt_cont%FA_u_WW(i,j) = 0.0
979 bt_cont%uBT_WW(i,j) = 0.0
980 bt_cont%FA_u_E0(i,j) = 0.0 ; bt_cont%FA_u_EE(i,j) = 0.0
981 bt_cont%uBT_EE(i,j) = 0.0
986 do k=1,nz ;
do i=ish-1,ieh ;
if (do_i(i))
then 987 visc_rem_lim = max(visc_rem(i,k), min_visc_rem*visc_rem_max(i))
988 if (visc_rem_lim > 0.0)
then 989 if (u(i,j,k) + dur(i)*visc_rem_lim > -du_cfl(i)*visc_rem(i,k)) &
990 dur(i) = -(u(i,j,k) + du_cfl(i)*visc_rem(i,k)) / visc_rem_lim
991 if (u(i,j,k) + dul(i)*visc_rem_lim < du_cfl(i)*visc_rem(i,k)) &
992 dul(i) = -(u(i,j,k) - du_cfl(i)*visc_rem(i,k)) / visc_rem_lim
994 endif ;
enddo ;
enddo 997 do i=ish-1,ieh ;
if (do_i(i))
then 998 u_l(i) = u(i,j,k) + dul(i) * visc_rem(i,k)
999 u_r(i) = u(i,j,k) + dur(i) * visc_rem(i,k)
1000 u_0(i) = u(i,j,k) + du0(i) * visc_rem(i,k)
1002 call zonal_flux_layer(u_0, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_0, &
1003 fa_marg_0, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1005 call zonal_flux_layer(u_l, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_l, &
1006 fa_marg_l, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1008 call zonal_flux_layer(u_r, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_r, &
1009 fa_marg_r, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1011 do i=ish-1,ieh ;
if (do_i(i))
then 1012 famt_0(i) = famt_0(i) + fa_marg_0(i)
1013 famt_l(i) = famt_l(i) + fa_marg_l(i)
1014 famt_r(i) = famt_r(i) + fa_marg_r(i)
1015 uhtot_l(i) = uhtot_l(i) + uh_l(i)
1016 uhtot_r(i) = uhtot_r(i) + uh_r(i)
1019 do i=ish-1,ieh ;
if (do_i(i))
then 1020 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1021 if ((dul(i) - du0(i)) /= 0.0) &
1022 fa_avg = uhtot_l(i) / (dul(i) - du0(i))
1023 if (fa_avg > max(fa_0, famt_l(i)))
then ; fa_avg = max(fa_0, famt_l(i))
1024 elseif (fa_avg < min(fa_0, famt_l(i)))
then ; fa_0 = fa_avg ;
endif 1026 bt_cont%FA_u_W0(i,j) = fa_0 ; bt_cont%FA_u_WW(i,j) = famt_l(i)
1027 if (abs(fa_0-famt_l(i)) <= 1e-12*fa_0)
then ; bt_cont%uBT_WW(i,j) = 0.0 ;
else 1028 bt_cont%uBT_WW(i,j) = (1.5 * (dul(i) - du0(i))) * &
1029 ((famt_l(i) - fa_avg) / (famt_l(i) - fa_0))
1032 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1033 if ((dur(i) - du0(i)) /= 0.0) &
1034 fa_avg = uhtot_r(i) / (dur(i) - du0(i))
1035 if (fa_avg > max(fa_0, famt_r(i)))
then ; fa_avg = max(fa_0, famt_r(i))
1036 elseif (fa_avg < min(fa_0, famt_r(i)))
then ; fa_0 = fa_avg ;
endif 1038 bt_cont%FA_u_E0(i,j) = fa_0 ; bt_cont%FA_u_EE(i,j) = famt_r(i)
1039 if (abs(famt_r(i) - fa_0) <= 1e-12*fa_0)
then ; bt_cont%uBT_EE(i,j) = 0.0 ;
else 1040 bt_cont%uBT_EE(i,j) = (1.5 * (dur(i) - du0(i))) * &
1041 ((famt_r(i) - fa_avg) / (famt_r(i) - fa_0))
1044 bt_cont%FA_u_W0(i,j) = 0.0 ; bt_cont%FA_u_WW(i,j) = 0.0
1045 bt_cont%uBT_WW(i,j) = 0.0
1046 bt_cont%FA_u_E0(i,j) = 0.0 ; bt_cont%FA_u_EE(i,j) = 0.0
1047 bt_cont%uBT_EE(i,j) = 0.0
1053 subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, CS, LB, vhbt, OBC, &
1054 visc_rem_v, v_cor, vhbt_aux, v_cor_aux, BT_cont)
1055 type(ocean_grid_type),
intent(inout) :: G
1056 type(verticalgrid_type),
intent(in) :: GV
1057 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
1058 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h_in
1060 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out) :: vh
1062 real,
intent(in) :: dt
1065 type(ocean_obc_type),
pointer,
optional :: OBC
1068 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in),
optional :: visc_rem_v
1075 real,
dimension(SZI_(G),SZJB_(G)),
intent(in),
optional :: vhbt
1077 real,
dimension(SZI_(G),SZJB_(G)),
intent(in),
optional :: vhbt_aux
1080 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out),
optional :: v_cor
1083 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(out),
optional :: v_cor_aux
1086 type(bt_cont_type),
pointer,
optional :: BT_cont
1089 real,
dimension(SZI_(G),SZK_(G)) :: &
1091 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
1093 real,
dimension(SZI_(G)) :: &
1100 logical,
dimension(SZI_(G)) :: do_I
1101 real,
dimension(SZI_(G),SZK_(G)) :: &
1109 integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
1110 logical :: do_aux, local_specified_BC, use_visc_rem, set_BT_cont, any_simple_OBC
1111 logical :: local_Flather_OBC, is_simple, local_open_BC
1112 type(obc_segment_type),
pointer :: segment
1114 do_aux = (
present(vhbt_aux) .and.
present(v_cor_aux))
1115 use_visc_rem =
present(visc_rem_v)
1116 local_specified_bc = .false. ; set_bt_cont = .false. ; local_flather_obc = .false.
1117 local_open_bc = .false.
1118 if (
present(bt_cont)) set_bt_cont = (
associated(bt_cont))
1119 if (
present(obc))
then ;
if (
associated(obc))
then ;
if (obc%OBC_pe)
then 1120 local_specified_bc = obc%specified_v_BCs_exist_globally
1121 local_flather_obc = obc%Flather_u_BCs_exist_globally .or. &
1122 obc%Flather_v_BCs_exist_globally
1123 local_open_bc = obc%open_v_BCs_exist_globally
1124 endif ;
endif ;
endif 1125 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
1127 cfl_dt = cs%CFL_limit_adjust / dt
1129 if (cs%aggress_adjust) cfl_dt = i_dt
1135 if (cs%upwind_1st)
then 1136 do j=jsh-1,jeh+1 ;
do i=ish,ieh
1137 h_l(i,j,k) = h_in(i,j,k) ; h_r(i,j,k) = h_in(i,j,k)
1140 call ppm_reconstruction_y(h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), g, lb, &
1141 2.0*gv%Angstrom, cs%monotonic, simple_2nd=cs%simple_2nd)
1143 do i=ish,ieh ; visc_rem(i,k) = 1.0 ;
enddo 1145 if (local_open_bc)
then 1146 do n=1, obc%number_of_segments
1147 segment => obc%segment(n)
1148 if (.not. segment%on_pe .or. segment%specified) cycle
1149 if (segment%direction == obc_direction_n)
then 1151 do k=1,nz ;
do i=segment%HI%isd,segment%HI%ied
1152 h_in(i,j+1,k) = h_in(i,j,k)
1153 h_l(i,j+1,k) = h_in(i,j,k)
1154 h_r(i,j+1,k) = h_in(i,j,k)
1155 h_r(i,j,k) = h_in(i,j,k)
1157 elseif (segment%direction == obc_direction_s)
then 1159 do k=1,nz ;
do i=segment%HI%isd,segment%HI%ied
1160 h_in(i,j,k) = h_in(i,j+1,k)
1161 h_l(i,j,k) = h_in(i,j+1,k)
1162 h_r(i,j,k) = h_in(i,j+1,k)
1163 h_l(i,j+1,k) = h_in(i,j+1,k)
1181 do i=ish,ieh ; do_i(i) = .true. ; visc_rem_max(i) = 0.0 ;
enddo 1184 if (use_visc_rem)
then ;
do i=ish,ieh
1185 visc_rem(i,k) = visc_rem_v(i,j,k)
1186 visc_rem_max(i) = max(visc_rem_max(i), visc_rem(i,k))
1188 call merid_flux_layer(v(:,j,k), h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), &
1189 vh(:,j,k), dvhdv(:,k), visc_rem(:,k), &
1190 dt, g, j, ish, ieh, do_i, cs%vol_CFL)
1191 if (local_specified_bc)
then 1193 if (obc%segment(obc%segnum_v(i,j))%specified) &
1194 vh(i,j,k) = obc%segment(obc%segnum_v(i,j))%normal_trans(i,j,k)
1198 if ((.not.use_visc_rem) .or. (.not.cs%use_visc_rem_max))
then ;
do i=ish,ieh
1199 visc_rem_max(i) = 1.0
1202 if (
present(vhbt) .or. do_aux .or. set_bt_cont)
then 1207 if (visc_rem_max(i) > 0.0) i_vrm = 1.0 / visc_rem_max(i)
1208 if (cs%vol_CFL)
then 1209 dy_s =
ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1210 dy_n =
ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1211 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif 1212 dv_max_cfl(i) = 2.0 * (cfl_dt * dy_s) * i_vrm
1213 dv_min_cfl(i) = -2.0 * (cfl_dt * dy_n) * i_vrm
1214 vh_tot_0(i) = 0.0 ; dvhdv_tot_0(i) = 0.0
1216 do k=1,nz ;
do i=ish,ieh
1217 dvhdv_tot_0(i) = dvhdv_tot_0(i) + dvhdv(i,k)
1218 vh_tot_0(i) = vh_tot_0(i) + vh(i,j,k)
1221 if (use_visc_rem)
then 1222 if (cs%aggress_adjust)
then 1223 do k=1,nz ;
do i=ish,ieh
1224 if (cs%vol_CFL)
then 1225 dy_s =
ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1226 dy_n =
ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1227 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif 1228 dv_lim = 0.499*((dy_s*i_dt - v(i,j,k)) + min(0.0,v(i,j-1,k)))
1229 if (dv_max_cfl(i) * visc_rem(i,k) > dv_lim) &
1230 dv_max_cfl(i) = dv_lim / visc_rem(i,k)
1232 dv_lim = 0.499*((-dy_n*cfl_dt - v(i,j,k)) + max(0.0,v(i,j+1,k)))
1233 if (dv_min_cfl(i) * visc_rem(i,k) < dv_lim) &
1234 dv_min_cfl(i) = dv_lim / visc_rem(i,k)
1237 do k=1,nz ;
do i=ish,ieh
1238 if (cs%vol_CFL)
then 1239 dy_s =
ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1240 dy_n =
ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1241 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif 1242 if (dv_max_cfl(i) * visc_rem(i,k) > dy_s*cfl_dt - v(i,j,k)) &
1243 dv_max_cfl(i) = (dy_s*cfl_dt - v(i,j,k)) / visc_rem(i,k)
1244 if (dv_min_cfl(i) * visc_rem(i,k) < -dy_n*cfl_dt - v(i,j,k)) &
1245 dv_min_cfl(i) = -(dy_n*cfl_dt + v(i,j,k)) / visc_rem(i,k)
1249 if (cs%aggress_adjust)
then 1250 do k=1,nz ;
do i=ish,ieh
1251 if (cs%vol_CFL)
then 1252 dy_s =
ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1253 dy_n =
ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1254 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif 1255 dv_max_cfl(i) = min(dv_max_cfl(i), 0.499 * &
1256 ((dy_s*i_dt - v(i,j,k)) + min(0.0,v(i,j-1,k))) )
1257 dv_min_cfl(i) = max(dv_min_cfl(i), 0.499 * &
1258 ((-dy_n*i_dt - v(i,j,k)) + max(0.0,v(i,j+1,k))) )
1261 do k=1,nz ;
do i=ish,ieh
1262 if (cs%vol_CFL)
then 1263 dy_s =
ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1264 dy_n =
ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1265 else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ;
endif 1266 dv_max_cfl(i) = min(dv_max_cfl(i), dy_s*cfl_dt - v(i,j,k))
1267 dv_min_cfl(i) = max(dv_min_cfl(i), -(dy_n*cfl_dt + v(i,j,k)))
1272 dv_max_cfl(i) = max(dv_max_cfl(i),0.0)
1273 dv_min_cfl(i) = min(dv_min_cfl(i),0.0)
1278 any_simple_obc = .false.
1279 if (
present(vhbt) .or. do_aux .or. set_bt_cont)
then 1280 if (local_specified_bc .or. local_flather_obc)
then ;
do i=ish,ieh
1282 is_simple = obc%segment(obc%segnum_v(i,j))%specified
1283 do_i(i) = .not.(obc%segnum_v(i,j) /= obc_none .and. is_simple)
1284 any_simple_obc = any_simple_obc .or. is_simple
1285 enddo ;
else ;
do i=ish,ieh
1290 if (
present(vhbt))
then 1292 dvhdv_tot_0, dv, dv_max_cfl, dv_min_cfl, dt, g, &
1293 cs, visc_rem, j, ish, ieh, do_i, .true., vh)
1295 if (
present(v_cor))
then ;
do k=1,nz
1296 do i=ish,ieh ; v_cor(i,j,k) = v(i,j,k) + dv(i) * visc_rem(i,k) ;
enddo 1297 if (local_specified_bc)
then ;
do i=ish,ieh
1298 if (obc%segment(obc%segnum_v(i,j))%specified) &
1299 v_cor(i,j,k) = obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1306 dvhdv_tot_0, dv, dv_max_cfl, dv_min_cfl, dt, g, &
1307 cs, visc_rem, j, ish, ieh, do_i, .false.)
1310 do i=ish,ieh ; v_cor_aux(i,j,k) = v(i,j,k) + dv(i) * visc_rem(i,k) ;
enddo 1311 if (local_specified_bc)
then ;
do i=ish,ieh
1312 if (obc%segment(obc%segnum_v(i,j))%specified) &
1313 v_cor_aux(i,j,k) = obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1318 if (set_bt_cont)
then 1320 dv_max_cfl, dv_min_cfl, dt, g, cs, visc_rem, &
1321 visc_rem_max, j, ish, ieh, do_i)
1322 if (any_simple_obc)
then 1324 do_i(i) = (obc%segment(obc%segnum_v(i,j))%specified)
1325 if (do_i(i)) bt_cont%Fa_v_S0(i,j) = gv%H_subroundoff*g%dx_Cv(i,j)
1327 do k=1,nz ;
do i=ish,ieh ;
if (do_i(i))
then 1328 if (abs(obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)) > 0.0) &
1329 bt_cont%Fa_v_S0(i,j) = bt_cont%Fa_v_S0(i,j) + &
1330 obc%segment(obc%segnum_v(i,j))%normal_trans(i,j,k) / &
1331 obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1332 endif ;
enddo ;
enddo 1333 do i=ish,ieh ;
if (do_i(i))
then 1334 bt_cont%Fa_v_N0(i,j) = bt_cont%Fa_v_S0(i,j)
1335 bt_cont%Fa_v_SS(i,j) = bt_cont%Fa_v_S0(i,j)
1336 bt_cont%Fa_v_NN(i,j) = bt_cont%Fa_v_S0(i,j)
1345 if (set_bt_cont)
then ;
if (
associated(bt_cont%h_v))
then 1346 if (
present(v_cor))
then 1348 cs%vol_CFL, cs%marginal_faces, visc_rem_v)
1351 cs%vol_CFL, cs%marginal_faces, visc_rem_v)
1358 subroutine merid_flux_layer(v, h, h_L, h_R, vh, dvhdv, visc_rem, dt, G, J, &
1359 ish, ieh, do_I, vol_CFL)
1360 type(ocean_grid_type),
intent(inout) :: G
1361 real,
dimension(SZI_(G)),
intent(in) :: v
1362 real,
dimension(SZI_(G)),
intent(in) :: visc_rem
1367 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h
1369 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_L
1371 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_R
1373 real,
dimension(SZI_(G)),
intent(inout) :: vh
1375 real,
dimension(SZI_(G)),
intent(inout) :: dvhdv
1377 real,
intent(in) :: dt
1378 integer,
intent(in) :: j
1379 integer,
intent(in) :: ish
1380 integer,
intent(in) :: ieh
1381 logical,
dimension(SZI_(G)),
intent(in) :: do_I
1382 logical,
intent(in) :: vol_CFL
1391 do i=ish,ieh ;
if (do_i(i))
then 1392 if (v(i) > 0.0)
then 1393 if (vol_cfl)
then ; cfl = (v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1394 else ; cfl = v(i) * dt * g%IdyT(i,j) ;
endif 1395 curv_3 = h_l(i,j) + h_r(i,j) - 2.0*h(i,j)
1396 vh(i) = g%dx_Cv(i,j) * v(i) * ( h_r(i,j) + cfl * &
1397 (0.5*(h_l(i,j) - h_r(i,j)) + curv_3*(cfl - 1.5)) )
1398 h_marg = h_r(i,j) + cfl * ((h_l(i,j) - h_r(i,j)) + &
1399 3.0*curv_3*(cfl - 1.0))
1400 elseif (v(i) < 0.0)
then 1401 if (vol_cfl)
then ; cfl = (-v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1402 else ; cfl = -v(i) * dt * g%IdyT(i,j+1) ;
endif 1403 curv_3 = h_l(i,j+1) + h_r(i,j+1) - 2.0*h(i,j+1)
1404 vh(i) = g%dx_Cv(i,j) * v(i) * ( h_l(i,j+1) + cfl * &
1405 (0.5*(h_r(i,j+1)-h_l(i,j+1)) + curv_3*(cfl - 1.5)) )
1406 h_marg = h_l(i,j+1) + cfl * ((h_r(i,j+1)-h_l(i,j+1)) + &
1407 3.0*curv_3*(cfl - 1.0))
1410 h_marg = 0.5 * (h_l(i,j+1) + h_r(i,j))
1412 dvhdv(i) = g%dx_Cv(i,j) * h_marg * visc_rem(i)
1419 marginal, visc_rem_v)
1420 type(ocean_grid_type),
intent(inout) :: G
1421 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
1422 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1424 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
1426 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
1428 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: h_v
1430 real,
intent(in) :: dt
1432 logical,
intent(in) :: vol_CFL
1435 logical,
intent(in) :: marginal
1438 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in),
optional :: visc_rem_v
1451 integer :: i, j, k, ish, ieh, jsh, jeh, nz
1452 ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
1458 do k=1,nz ;
do j=jsh-1,jeh ;
do i=ish,ieh
1459 if (v(i,j,k) > 0.0)
then 1460 if (vol_cfl)
then ; cfl = (v(i,j,k) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1461 else ; cfl = v(i,j,k) * dt * g%IdyT(i,j) ;
endif 1462 curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
1463 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))
1464 h_marg = h_r(i,j,k) + cfl * ((h_l(i,j,k) - h_r(i,j,k)) + &
1465 3.0*curv_3*(cfl - 1.0))
1466 elseif (v(i,j,k) < 0.0)
then 1467 if (vol_cfl)
then ; cfl = (-v(i,j,k)*dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1468 else ; cfl = -v(i,j,k) * dt * g%IdyT(i,j+1) ;
endif 1469 curv_3 = h_l(i,j+1,k) + h_r(i,j+1,k) - 2.0*h(i,j+1,k)
1470 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))
1471 h_marg = h_l(i,j+1,k) + cfl * ((h_r(i,j+1,k)-h_l(i,j+1,k)) + &
1472 3.0*curv_3*(cfl - 1.0))
1474 h_avg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1477 h_marg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1482 if (marginal)
then ; h_v(i,j,k) = h_marg
1483 else ; h_v(i,j,k) = h_avg ;
endif 1484 enddo ;
enddo ;
enddo 1486 if (
present(visc_rem_v))
then 1488 do k=1,nz ;
do j=jsh-1,jeh ;
do i=ish,ieh
1489 h_v(i,j,k) = h_v(i,j,k) * visc_rem_v(i,j,k)
1490 enddo ;
enddo ;
enddo 1498 dv, dv_max_CFL, dv_min_CFL, dt, G, CS, visc_rem, &
1499 j, ish, ieh, do_I_in, full_precision, vh_3d)
1500 type(ocean_grid_type),
intent(inout) :: G
1501 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
1502 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
1504 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
1506 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
1508 real,
dimension(SZI_(G),SZK_(G)),
intent(in) :: visc_rem
1515 real,
dimension(SZI_(G)),
intent(in),
optional :: vhbt
1517 real,
dimension(SZI_(G)),
intent(in) :: dv_max_CFL
1519 real,
dimension(SZI_(G)),
intent(in) :: dv_min_CFL
1521 real,
dimension(SZI_(G)),
intent(in) :: vh_tot_0
1523 real,
dimension(SZI_(G)),
intent(in) :: dvhdv_tot_0
1525 real,
dimension(SZI_(G)),
intent(out) :: dv
1527 real,
intent(in) :: dt
1529 integer,
intent(in) :: j
1530 integer,
intent(in) :: ish
1531 integer,
intent(in) :: ieh
1532 logical,
dimension(SZI_(G)),
intent(in) :: do_I_in
1534 logical,
intent(in),
optional :: full_precision
1537 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout),
optional :: vh_3d
1540 real,
dimension(SZI_(G),SZK_(G)) :: &
1543 real,
dimension(SZI_(G)) :: &
1554 integer :: i, k, nz, itt, max_itts = 20
1555 logical :: full_prec, domore, do_I(szi_(g))
1558 full_prec = .true. ;
if (
present(full_precision)) full_prec = full_precision
1560 vh_aux(:,:) = 0.0 ; dvhdv(:,:) = 0.0
1562 if (
present(vh_3d))
then ;
do k=1,nz ;
do i=ish,ieh
1563 vh_aux(i,k) = vh_3d(i,j,k)
1564 enddo ;
enddo ;
endif 1567 dv(i) = 0.0 ; do_i(i) = do_i_in(i)
1568 dv_max(i) = dv_max_cfl(i) ; dv_min(i) = dv_min_cfl(i)
1569 vh_err(i) = vh_tot_0(i) - vhbt(i) ; dvhdv_tot(i) = dvhdv_tot_0(i)
1570 vh_err_best(i) = abs(vh_err(i))
1576 case (:1) ; tol_eta = 1e-6 * cs%tol_eta
1577 case (2) ; tol_eta = 1e-4 * cs%tol_eta
1578 case (3) ; tol_eta = 1e-2 * cs%tol_eta
1579 case default ; tol_eta = cs%tol_eta
1582 tol_eta = cs%tol_eta_aux ;
if (itt<=1) tol_eta = 1e-6 * cs%tol_eta_aux
1584 tol_vel = cs%tol_vel
1587 if (vh_err(i) > 0.0)
then ; dv_max(i) = dv(i)
1588 elseif (vh_err(i) < 0.0)
then ; dv_min(i) = dv(i)
1589 else ; do_i(i) = .false. ;
endif 1592 do i=ish,ieh ;
if (do_i(i))
then 1593 if ((dt*min(g%IareaT(i,j),g%IareaT(i,j+1))*abs(vh_err(i)) > tol_eta) .or.&
1594 (cs%better_iter .and. ((abs(vh_err(i)) > tol_vel * dvhdv_tot(i)) .or.&
1595 (abs(vh_err(i)) > vh_err_best(i))) ))
then 1599 ddv = -vh_err(i) / dvhdv_tot(i)
1602 if (abs(ddv) < 1.0e-15*abs(dv(i)))
then 1604 elseif (ddv > 0.0)
then 1605 if (dv(i) >= dv_max(i))
then 1606 dv(i) = 0.5*(dv_prev + dv_max(i))
1607 if (dv_max(i) - dv_prev < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1610 if (dv(i) <= dv_min(i))
then 1611 dv(i) = 0.5*(dv_prev + dv_min(i))
1612 if (dv_prev - dv_min(i) < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1617 dv(i) = dv(i) - vh_err(i) / dvhdv_tot(i)
1618 if ((dv(i) >= dv_max(i)) .or. (dv(i) <= dv_min(i))) &
1619 dv(i) = 0.5*(dv_max(i) + dv_min(i))
1621 if (do_i(i)) domore = .true.
1626 if (.not.domore)
exit 1628 if ((itt < max_itts) .or.
present(vh_3d))
then ;
do k=1,nz
1629 do i=ish,ieh ; v_new(i) = v(i,j,k) + dv(i) * visc_rem(i,k) ;
enddo 1630 call merid_flux_layer(v_new, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), &
1631 vh_aux(:,k), dvhdv(:,k), visc_rem(:,k), &
1632 dt, g, j, ish, ieh, do_i, cs%vol_CFL)
1635 if (itt < max_itts)
then 1637 vh_err(i) = -vhbt(i) ; dvhdv_tot(i) = 0.0
1639 do k=1,nz ;
do i=ish,ieh
1640 vh_err(i) = vh_err(i) + vh_aux(i,k)
1641 dvhdv_tot(i) = dvhdv_tot(i) + dvhdv(i,k)
1644 vh_err_best(i) = min(vh_err_best(i), abs(vh_err(i)))
1652 if (
present(vh_3d))
then ;
do k=1,nz ;
do i=ish,ieh
1653 vh_3d(i,j,k) = vh_aux(i,k)
1654 enddo ;
enddo ;
endif 1660 subroutine set_merid_bt_cont(v, h_in, h_L, h_R, BT_cont, vh_tot_0, dvhdv_tot_0, &
1661 dv_max_CFL, dv_min_CFL, dt, G, CS, visc_rem, &
1662 visc_rem_max, j, ish, ieh, do_I)
1663 type(ocean_grid_type),
intent(inout) :: G
1664 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
1665 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_in
1667 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_L
1669 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h_R
1671 type(bt_cont_type),
intent(inout) :: BT_cont
1674 real,
dimension(SZI_(G)),
intent(in) :: vh_tot_0
1676 real,
dimension(SZI_(G)),
intent(in) :: dvhdv_tot_0
1678 real,
dimension(SZI_(G)),
intent(in) :: dv_max_CFL
1680 real,
dimension(SZI_(G)),
intent(in) :: dv_min_CFL
1682 real,
intent(in) :: dt
1684 real,
dimension(SZI_(G),SZK_(G)),
intent(in) :: visc_rem
1691 real,
dimension(SZI_(G)),
intent(in) :: visc_rem_max
1692 integer,
intent(in) :: j
1693 integer,
intent(in) :: ish
1694 integer,
intent(in) :: ieh
1695 logical,
dimension(SZI_(G)),
intent(in) :: do_I
1698 real,
dimension(SZI_(G)) :: &
1718 real :: visc_rem_lim
1721 real :: min_visc_rem
1731 nz = g%ke ; idt = 1.0/dt
1732 min_visc_rem = 0.1 ; cfl_min = 1e-6
1735 do i=ish,ieh ; zeros(i) = 0.0 ;
enddo 1737 dvhdv_tot_0, dv0, dv_max_cfl, dv_min_cfl, dt, g, &
1738 cs, visc_rem, j, ish, ieh, do_i, .true.)
1744 do i=ish,ieh ;
if (do_i(i))
then 1746 dv_cfl(i) = (cfl_min * idt) * g%dyCv(i,j)
1747 dvr(i) = min(0.0,dv0(i) - dv_cfl(i))
1748 dvl(i) = max(0.0,dv0(i) + dv_cfl(i))
1749 famt_l(i) = 0.0 ; famt_r(i) = 0.0 ; famt_0(i) = 0.0
1750 vhtot_l(i) = 0.0 ; vhtot_r(i) = 0.0
1753 if (.not.domore)
then 1754 do k=1,nz ;
do i=ish,ieh
1755 bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1756 bt_cont%vBT_SS(i,j) = 0.0
1757 bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1758 bt_cont%vBT_NN(i,j) = 0.0
1763 do k=1,nz ;
do i=ish,ieh ;
if (do_i(i))
then 1764 visc_rem_lim = max(visc_rem(i,k), min_visc_rem*visc_rem_max(i))
1765 if (visc_rem_lim > 0.0)
then 1766 if (v(i,j,k) + dvr(i)*visc_rem_lim > -dv_cfl(i)*visc_rem(i,k)) &
1767 dvr(i) = -(v(i,j,k) + dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1768 if (v(i,j,k) + dvl(i)*visc_rem_lim < dv_cfl(i)*visc_rem(i,k)) &
1769 dvl(i) = -(v(i,j,k) - dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1771 endif ;
enddo ;
enddo 1773 do i=ish,ieh ;
if (do_i(i))
then 1774 v_l(i) = v(i,j,k) + dvl(i) * visc_rem(i,k)
1775 v_r(i) = v(i,j,k) + dvr(i) * visc_rem(i,k)
1776 v_0(i) = v(i,j,k) + dv0(i) * visc_rem(i,k)
1778 call merid_flux_layer(v_0, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_0, &
1779 fa_marg_0, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1781 call merid_flux_layer(v_l, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_l, &
1782 fa_marg_l, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1784 call merid_flux_layer(v_r, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_r, &
1785 fa_marg_r, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1787 do i=ish,ieh ;
if (do_i(i))
then 1788 famt_0(i) = famt_0(i) + fa_marg_0(i)
1789 famt_l(i) = famt_l(i) + fa_marg_l(i)
1790 famt_r(i) = famt_r(i) + fa_marg_r(i)
1791 vhtot_l(i) = vhtot_l(i) + vh_l(i)
1792 vhtot_r(i) = vhtot_r(i) + vh_r(i)
1795 do i=ish,ieh ;
if (do_i(i))
then 1796 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1797 if ((dvl(i) - dv0(i)) /= 0.0) &
1798 fa_avg = vhtot_l(i) / (dvl(i) - dv0(i))
1799 if (fa_avg > max(fa_0, famt_l(i)))
then ; fa_avg = max(fa_0, famt_l(i))
1800 elseif (fa_avg < min(fa_0, famt_l(i)))
then ; fa_0 = fa_avg ;
endif 1801 bt_cont%FA_v_S0(i,j) = fa_0 ; bt_cont%FA_v_SS(i,j) = famt_l(i)
1802 if (abs(fa_0-famt_l(i)) <= 1e-12*fa_0)
then ; bt_cont%vBT_SS(i,j) = 0.0 ;
else 1803 bt_cont%vBT_SS(i,j) = (1.5 * (dvl(i) - dv0(i))) * &
1804 ((famt_l(i) - fa_avg) / (famt_l(i) - fa_0))
1807 fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1808 if ((dvr(i) - dv0(i)) /= 0.0) &
1809 fa_avg = vhtot_r(i) / (dvr(i) - dv0(i))
1810 if (fa_avg > max(fa_0, famt_r(i)))
then ; fa_avg = max(fa_0, famt_r(i))
1811 elseif (fa_avg < min(fa_0, famt_r(i)))
then ; fa_0 = fa_avg ;
endif 1812 bt_cont%FA_v_N0(i,j) = fa_0 ; bt_cont%FA_v_NN(i,j) = famt_r(i)
1813 if (abs(famt_r(i) - fa_0) <= 1e-12*fa_0)
then ; bt_cont%vBT_NN(i,j) = 0.0 ;
else 1814 bt_cont%vBT_NN(i,j) = (1.5 * (dvr(i) - dv0(i))) * &
1815 ((famt_r(i) - fa_avg) / (famt_r(i) - fa_0))
1818 bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1819 bt_cont%vBT_SS(i,j) = 0.0
1820 bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1821 bt_cont%vBT_NN(i,j) = 0.0
1828 type(ocean_grid_type),
intent(in) :: G
1829 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
1830 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_L
1832 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_R
1835 real,
intent(in) :: h_min
1837 logical,
optional,
intent(in) :: monotonic
1840 logical,
optional,
intent(in) :: simple_2nd
1845 real,
dimension(SZI_(G),SZJ_(G)) :: slp
1846 real,
parameter :: oneSixth = 1./6.
1847 real :: h_ip1, h_im1
1849 logical :: use_CW84, use_2nd
1850 character(len=256) :: mesg
1851 integer :: i, j, isl, iel, jsl, jel, stencil
1853 use_cw84 = .false. ;
if (
present(monotonic)) use_cw84 = monotonic
1854 use_2nd = .false. ;
if (
present(simple_2nd)) use_2nd = simple_2nd
1855 isl = lb%ish-1 ; iel = lb%ieh+1 ; jsl = lb%jsh ; jel = lb%jeh
1858 stencil = 2 ;
if (use_2nd) stencil = 1
1860 if ((isl-stencil < g%isd) .or. (iel+stencil > g%ied))
then 1861 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", & 1862 & "x-halo that needs to be increased by ",i2,".")') &
1863 stencil + max(g%isd-isl,iel-g%ied)
1864 call mom_error(fatal,mesg)
1866 if ((jsl < g%jsd) .or. (jel > g%jed))
then 1867 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", & 1868 & "y-halo that needs to be increased by ",i2,".")') &
1869 max(g%jsd-jsl,jel-g%jed)
1870 call mom_error(fatal,mesg)
1874 do j=jsl,jel ;
do i=isl,iel
1875 h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1876 h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1877 h_l(i,j) = 0.5*( h_im1 + h_in(i,j) )
1878 h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) )
1881 do j=jsl,jel ;
do i=isl-1,iel+1
1882 if ((g%mask2dT(i-1,j) * g%mask2dT(i,j) * g%mask2dT(i+1,j)) == 0.0)
then 1886 slp(i,j) = 0.5 * (h_in(i+1,j) - h_in(i-1,j))
1888 dmx = max(h_in(i+1,j), h_in(i-1,j), h_in(i,j)) - h_in(i,j)
1889 dmn = h_in(i,j) - min(h_in(i+1,j), h_in(i-1,j), h_in(i,j))
1890 slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1895 do j=jsl,jel ;
do i=isl,iel
1900 h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1901 h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1903 h_l(i,j) = 0.5*( h_im1 + h_in(i,j) ) + onesixth*( slp(i-1,j) - slp(i,j) )
1904 h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i+1,j) )
1911 call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
1919 type(ocean_grid_type),
intent(in) :: G
1920 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
1921 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_L
1923 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: h_R
1926 real,
intent(in) :: h_min
1928 logical,
optional,
intent(in) :: monotonic
1931 logical,
optional,
intent(in) :: simple_2nd
1936 real,
dimension(SZI_(G),SZJ_(G)) :: slp
1937 real,
parameter :: oneSixth = 1./6.
1938 real :: h_jp1, h_jm1
1940 logical :: use_CW84, use_2nd
1941 character(len=256) :: mesg
1942 integer :: i, j, isl, iel, jsl, jel, stencil
1944 use_cw84 = .false. ;
if (
present(monotonic)) use_cw84 = monotonic
1945 use_2nd = .false. ;
if (
present(simple_2nd)) use_2nd = simple_2nd
1946 isl = lb%ish ; iel = lb%ieh ; jsl = lb%jsh-1 ; jel = lb%jeh+1
1949 stencil = 2 ;
if (use_2nd) stencil = 1
1951 if ((isl < g%isd) .or. (iel > g%ied))
then 1952 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", & 1953 & "x-halo that needs to be increased by ",i2,".")') &
1954 max(g%isd-isl,iel-g%ied)
1955 call mom_error(fatal,mesg)
1957 if ((jsl-stencil < g%jsd) .or. (jel+stencil > g%jed))
then 1958 write(mesg,
'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", & 1959 & "y-halo that needs to be increased by ",i2,".")') &
1960 stencil + max(g%jsd-jsl,jel-g%jed)
1961 call mom_error(fatal,mesg)
1965 do j=jsl,jel ;
do i=isl,iel
1966 h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
1967 h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
1968 h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) )
1969 h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) )
1972 do j=jsl-1,jel+1 ;
do i=isl,iel
1973 if ((g%mask2dT(i,j-1) * g%mask2dT(i,j) * g%mask2dT(i,j+1)) == 0.0)
then 1977 slp(i,j) = 0.5 * (h_in(i,j+1) - h_in(i,j-1))
1979 dmx = max(h_in(i,j+1), h_in(i,j-1), h_in(i,j)) - h_in(i,j)
1980 dmn = h_in(i,j) - min(h_in(i,j+1), h_in(i,j-1), h_in(i,j))
1981 slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1986 do j=jsl,jel ;
do i=isl,iel
1989 h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
1990 h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
1992 h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) ) + onesixth*( slp(i,j-1) - slp(i,j) )
1993 h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i,j+1) )
2000 call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
2010 subroutine ppm_limit_pos(h_in, h_L, h_R, h_min, G, iis, iie, jis, jie)
2011 type(ocean_grid_type),
intent(in) :: G
2012 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
2013 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_L
2015 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_R
2017 real,
intent(in) :: h_min
2019 integer,
intent(in) :: iis
2020 integer,
intent(in) :: iie
2021 integer,
intent(in) :: jis
2022 integer,
intent(in) :: jie
2025 real :: curv, dh, scale
2026 character(len=256) :: mesg
2029 do j=jis,jie ;
do i=iis,iie
2032 curv = 3.0*(h_l(i,j) + h_r(i,j) - 2.0*h_in(i,j))
2033 if (curv > 0.0)
then 2034 dh = h_r(i,j) - h_l(i,j)
2035 if (abs(dh) < curv)
then 2036 if (h_in(i,j) <= h_min)
then 2037 h_l(i,j) = h_in(i,j) ; h_r(i,j) = h_in(i,j)
2038 elseif (12.0*curv*(h_in(i,j) - h_min) < (curv**2 + 3.0*dh**2))
then 2041 scale = 12.0*curv*(h_in(i,j) - h_min) / (curv**2 + 3.0*dh**2)
2042 h_l(i,j) = h_in(i,j) + scale*(h_l(i,j) - h_in(i,j))
2043 h_r(i,j) = h_in(i,j) + scale*(h_r(i,j) - h_in(i,j))
2054 type(ocean_grid_type),
intent(in) :: G
2055 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: h_in
2056 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_L
2058 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: h_R
2060 integer,
intent(in) :: iis
2061 integer,
intent(in) :: iie
2062 integer,
intent(in) :: jis
2063 integer,
intent(in) :: jie
2066 real :: h_i, RLdiff, RLdiff2, RLmean, FunFac
2067 character(len=256) :: mesg
2070 do j=jis,jie ;
do i=iis,iie
2074 if ( ( h_r(i,j) - h_i ) * ( h_i - h_l(i,j) ) <= 0. )
then 2075 h_l(i,j) = h_i ; h_r(i,j) = h_i
2077 rldiff = h_r(i,j) - h_l(i,j)
2078 rlmean = 0.5 * ( h_r(i,j) + h_l(i,j) )
2079 funfac = 6. * rldiff * ( h_i - rlmean )
2080 rldiff2 = rldiff * rldiff
2081 if ( funfac > rldiff2 ) h_l(i,j) = 3. * h_i - 2. * h_r(i,j)
2082 if ( funfac < -rldiff2 ) h_r(i,j) = 3. * h_i - 2. * h_l(i,j)
2090 function ratio_max(a, b, maxrat)
result(ratio)
2091 real,
intent(in) :: a
2092 real,
intent(in) :: b
2093 real,
intent(in) :: maxrat
2096 if (abs(a) > abs(maxrat*b))
then 2105 type(time_type),
target,
intent(in) :: Time
2106 type(ocean_grid_type),
intent(in) :: G
2107 type(verticalgrid_type),
intent(in) :: GV
2108 type(param_file_type),
intent(in) :: param_file
2110 type(diag_ctrl),
target,
intent(inout) :: diag
2114 #include "version_variable.h" 2115 character(len=40) :: mdl =
"MOM_continuity_PPM" 2117 if (
associated(cs))
then 2118 call mom_error(warning,
"continuity_PPM_init called with associated control structure.")
2124 call log_version(param_file, mdl, version,
"")
2125 call get_param(param_file, mdl,
"MONOTONIC_CONTINUITY", cs%monotonic, &
2126 "If true, CONTINUITY_PPM uses the Colella and Woodward \n"//&
2127 "monotonic limiter. The default (false) is to use a \n"//&
2128 "simple positive definite limiter.", default=.false.)
2129 call get_param(param_file, mdl,
"SIMPLE_2ND_PPM_CONTINUITY", cs%simple_2nd, &
2130 "If true, CONTINUITY_PPM uses a simple 2nd order \n"//&
2131 "(arithmetic mean) interpolation of the edge values. \n"//&
2132 "This may give better PV conservation propterties. While \n"//&
2133 "it formally reduces the accuracy of the continuity \n"//&
2134 "solver itself in the strongly advective limit, it does \n"//&
2135 "not reduce the overall order of accuracy of the dynamic \n"//&
2136 "core.", default=.false.)
2137 call get_param(param_file, mdl,
"UPWIND_1ST_CONTINUITY", cs%upwind_1st, &
2138 "If true, CONTINUITY_PPM becomes a 1st-order upwind \n"//&
2139 "continuity solver. This scheme is highly diffusive \n"//&
2140 "but may be useful for debugging or in single-column \n"//&
2141 "mode where its minimal stencil is useful.", default=.false.)
2142 call get_param(param_file, mdl,
"ETA_TOLERANCE", cs%tol_eta, &
2143 "The tolerance for the differences between the \n"//&
2144 "barotropic and baroclinic estimates of the sea surface \n"//&
2145 "height due to the fluxes through each face. The total \n"//&
2146 "tolerance for SSH is 4 times this value. The default \n"//&
2147 "is 0.5*NK*ANGSTROM, and this should not be set less x\n"//&
2148 "than about 10^-15*MAXIMUM_DEPTH.", units=
"m", &
2149 default=0.5*g%ke*gv%Angstrom_z)
2151 call get_param(param_file, mdl,
"ETA_TOLERANCE_AUX", cs%tol_eta_aux, &
2152 "The tolerance for free-surface height discrepancies \n"//&
2153 "between the barotropic solution and the sum of the \n"//&
2154 "layer thicknesses when calculating the auxiliary \n"//&
2155 "corrected velocities. By default, this is the same as \n"//&
2156 "ETA_TOLERANCE, but can be made larger for efficiency.", &
2157 units=
"m", default=cs%tol_eta)
2158 call get_param(param_file, mdl,
"VELOCITY_TOLERANCE", cs%tol_vel, &
2159 "The tolerance for barotropic velocity discrepancies \n"//&
2160 "between the barotropic solution and the sum of the \n"//&
2161 "layer thicknesses.", units=
"m s-1", default=3.0e8)
2163 call get_param(param_file, mdl,
"CONT_PPM_AGGRESS_ADJUST", cs%aggress_adjust,&
2164 "If true, allow the adjusted velocities to have a \n"//&
2165 "relative CFL change up to 0.5.", default=.false.)
2166 cs%vol_CFL = cs%aggress_adjust
2167 call get_param(param_file, mdl,
"CONT_PPM_VOLUME_BASED_CFL", cs%vol_CFL, &
2168 "If true, use the ratio of the open face lengths to the \n"//&
2169 "tracer cell areas when estimating CFL numbers. The \n"//&
2170 "default is set by CONT_PPM_AGGRESS_ADJUST.", &
2171 default=cs%aggress_adjust, do_not_read=cs%aggress_adjust)
2172 call get_param(param_file, mdl,
"CONTINUITY_CFL_LIMIT", cs%CFL_limit_adjust, &
2173 "The maximum CFL of the adjusted velocities.", units=
"nondim", &
2175 call get_param(param_file, mdl,
"CONT_PPM_BETTER_ITER", cs%better_iter, &
2176 "If true, stop corrective iterations using a velocity \n"//&
2177 "based criterion and only stop if the iteration is \n"//&
2178 "better than all predecessors.", default=.true.)
2179 call get_param(param_file, mdl,
"CONT_PPM_USE_VISC_REM_MAX", &
2180 cs%use_visc_rem_max, &
2181 "If true, use more appropriate limiting bounds for \n"//&
2182 "corrections in strongly viscous columns.", default=.true.)
2183 call get_param(param_file, mdl,
"CONT_PPM_MARGINAL_FACE_AREAS", cs%marginal_faces, &
2184 "If true, use the marginal face areas from the continuity \n"//&
2185 "solver for use as the weights in the barotropic solver. \n"//&
2186 "Otherwise use the transport averaged areas.", default=.true.)
2190 id_clock_update = cpu_clock_id(
'(Ocean continuity update)', grain=clock_routine)
2191 id_clock_correct = cpu_clock_id(
'(Ocean continuity correction)', grain=clock_routine)
2193 cs%tol_eta = cs%tol_eta * gv%m_to_H
2194 cs%tol_eta_aux = cs%tol_eta_aux * gv%m_to_H
2203 stencil = 3 ;
if (cs%simple_2nd) stencil = 2 ;
if (cs%upwind_1st) stencil = 1
integer, parameter, public obc_direction_s
Indicates the boundary is an effective southern boundary.
integer, parameter, public obc_direction_w
Indicates the boundary is an effective western boundary.
integer, parameter, public obc_direction_n
Indicates the boundary is an effective northern boundary.
subroutine merid_flux_layer(v, h, h_L, h_R, vh, dvhdv, visc_rem, dt, G, J, ish, ieh, do_I, vol_CFL)
Evaluates the meridional mass or volume fluxes in a layer.
subroutine set_merid_bt_cont(v, h_in, h_L, h_R, BT_cont, vh_tot_0, dvhdv_tot_0, dv_max_CFL, dv_min_CFL, dt, G, CS, visc_rem, visc_rem_max, j, ish, ieh, do_I)
Sets of a structure that describes the meridional barotropic volume or mass fluxes as a function of b...
integer function, public continuity_ppm_stencil(CS)
continuity_PPM_stencil returns the continuity solver stencil size
Ocean grid type. See mom_grid for details.
subroutine ppm_reconstruction_y(h_in, h_L, h_R, G, LB, h_min, monotonic, simple_2nd)
Calculates left/right edge values for PPM reconstruction.
subroutine set_zonal_bt_cont(u, h_in, h_L, h_R, BT_cont, uh_tot_0, duhdu_tot_0, du_max_CFL, du_min_CFL, dt, G, CS, visc_rem, visc_rem_max, j, ish, ieh, do_I)
Sets a structure that describes the zonal barotropic volume or mass fluxes as a function of barotropi...
Provides the ocean grid type.
Open boundary segment data structure.
subroutine, public continuity_ppm(u, v, hin, h, uh, vh, dt, G, GV, CS, uhbt, vhbt, OBC, visc_rem_u, visc_rem_v, u_cor, v_cor, uhbt_aux, vhbt_aux, u_cor_aux, v_cor_aux, BT_cont)
Time steps the layer thicknesses, using a monotonically limit, directionally split PPM scheme...
subroutine ppm_limit_pos(h_in, h_L, h_R, h_min, G, iis, iie, jis, jie)
This subroutine limits the left/right edge values of the PPM reconstruction to give a reconstruction ...
subroutine zonal_flux_adjust(u, h_in, h_L, h_R, uhbt, uh_tot_0, duhdu_tot_0, du, du_max_CFL, du_min_CFL, dt, G, CS, visc_rem, j, ish, ieh, do_I_in, full_precision, uh_3d)
Returns the barotropic velocity adjustment that gives the desired barotropic (layer-summed) transport...
The BT_cont_type structure contains information about the summed layer transports and how they will v...
Control structure for mom_continuity_ppm.
logical function, public is_root_pe()
A container for loop bounds.
subroutine, public continuity_ppm_end(CS)
Destructor for continuity_ppm_cs.
subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, CS, LB, vhbt, OBC, visc_rem_v, v_cor, vhbt_aux, v_cor_aux, BT_cont)
Calculates the mass or volume fluxes through the meridional faces, and other related quantities...
integer, parameter, public obc_direction_e
Indicates the boundary is an effective eastern boundary.
subroutine zonal_flux_layer(u, h, h_L, h_R, uh, duhdu, visc_rem, dt, G, j, ish, ieh, do_I, vol_CFL)
Evaluates the zonal mass or volume fluxes in a layer.
Solve the layer continuity equation using the PPM method for layer fluxes.
integer, parameter, public obc_none
Controls where open boundary conditions are applied.
real function ratio_max(a, b, maxrat)
Return the maximum ratio of a/b or maxrat.
subroutine ppm_limit_cw84(h_in, h_L, h_R, G, iis, iie, jis, jie)
This subroutine limits the left/right edge values of the PPM reconstruction according to the monotoni...
subroutine zonal_face_thickness(u, h, h_L, h_R, h_u, dt, G, LB, vol_CFL, marginal, visc_rem_u)
Sets the effective interface thickness at each zonal velocity point.
subroutine, public mom_error(level, message, all_print)
subroutine ppm_reconstruction_x(h_in, h_L, h_R, G, LB, h_min, monotonic, simple_2nd)
Calculates left/right edge values for PPM reconstruction.
subroutine meridional_flux_adjust(v, h_in, h_L, h_R, vhbt, vh_tot_0, dvhdv_tot_0, dv, dv_max_CFL, dv_min_CFL, dt, G, CS, visc_rem, j, ish, ieh, do_I_in, full_precision, vh_3d)
Returns the barotropic velocity adjustment that gives the desired barotropic (layer-summed) transport...
subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, CS, LB, uhbt, OBC, visc_rem_u, u_cor, uhbt_aux, u_cor_aux, BT_cont)
Calculates the mass or volume fluxes through the zonal faces, and other related quantities.
subroutine, public continuity_ppm_init(Time, G, GV, param_file, diag, CS)
Initializes continuity_ppm_cs.
subroutine merid_face_thickness(v, h, h_L, h_R, h_v, dt, G, LB, vol_CFL, marginal, visc_rem_v)
Sets the effective interface thickness at each meridional velocity point.