drain_parabola_x Subroutine

private pure subroutine drain_parabola_x(nx, ny, nz, wet_T, hTr, hprev, tr, aL, aR, a6)

Rebuild the per-cell zonal CW PPM parabola from the CURRENT Tr = hTr/hprev (V2 — per pass). Interior cells (3..nx-2) use the limited PPM edges; the 2-cell boundary band falls back to PCM (aL=aR=Tr ⇒ swept reduces to the donor value, 1st order), matching tracer_advect_zonal_one_impl’s near-wall band. TODO(MOM6-fidelity): MOM6 advect_tracer keeps full PPM up to the wall (dropping to PCM only at genuine local extrema / zero mask2dCu faces), so we are 1st-order in the 2 cells nearest a true WALL where MOM6 is PPM-with-mask (periodic seams are fine — the wrap restores full PPM). Tracked divergence; revisit if near-wall tracer diffusion matters. a6 = 6·Tr − 3·(aL+aR). Mirror-T at land neighbours (C2); bit-identical for all-wet (wet_T≡1).

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz
real(kind=wp), intent(in) :: wet_T(nx,ny)
real(kind=wp), intent(in) :: hTr(nx,ny,nz)
real(kind=wp), intent(in) :: hprev(nx,ny,nz)
real(kind=wp), intent(inout) :: tr(nx,ny,nz)
real(kind=wp), intent(inout) :: aL(nx,ny,nz)
real(kind=wp), intent(inout) :: aR(nx,ny,nz)
real(kind=wp), intent(inout) :: a6(nx,ny,nz)

Calls

proc~~drain_parabola_x~~CallsGraph proc~drain_parabola_x drain_parabola_x local local proc~drain_parabola_x->local proc~ppm_cell_limiter ppm_cell_limiter proc~drain_parabola_x->proc~ppm_cell_limiter proc~ppm_limited_slope ppm_limited_slope proc~drain_parabola_x->proc~ppm_limited_slope proc~ppm_mirror_h ppm_mirror_h proc~drain_parabola_x->proc~ppm_mirror_h

Called by

proc~~drain_parabola_x~~CalledByGraph proc~drain_parabola_x drain_parabola_x proc~continuity_tracer_drain continuity_tracer_drain proc~continuity_tracer_drain->proc~drain_parabola_x proc~ocean_dyn_flush_tracer_window ocean_dyn_flush_tracer_window proc~ocean_dyn_flush_tracer_window->proc~continuity_tracer_drain proc~ocean_dyn_step ocean_dyn_step proc~ocean_dyn_step->proc~continuity_tracer_drain proc~ocean_dyn_step_split ocean_dyn_step_split proc~ocean_dyn_step_split->proc~continuity_tracer_drain proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~ocean_dyn_flush_tracer_window proc~engine_step engine_step proc~driver_run_ocean->proc~engine_step proc~engine_step->proc~ocean_dyn_step proc~engine_step->proc~ocean_dyn_step_split proc~rdb_ocean_set_tracer rdb_ocean_set_tracer proc~rdb_ocean_set_tracer->proc~ocean_dyn_flush_tracer_window proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: Tr_0
real(kind=wp), private :: Tr_left
real(kind=wp), private :: Tr_m1
real(kind=wp), private :: Tr_m2
real(kind=wp), private :: Tr_p1
real(kind=wp), private :: Tr_p2
real(kind=wp), private :: Tr_right
real(kind=wp), private :: dh_0
real(kind=wp), private :: dh_m1
real(kind=wp), private :: dh_p1
integer, private :: i
integer, private :: j
integer, private :: k

Source Code

   pure subroutine drain_parabola_x(nx, ny, nz, wet_T, hTr, hprev, tr, aL, aR, a6)
      !! Rebuild the per-cell zonal CW PPM parabola from the CURRENT Tr =
      !! hTr/hprev (V2 — per pass).  Interior cells (3..nx-2) use the
      !! limited PPM edges; the 2-cell boundary band falls back to PCM
      !! (aL=aR=Tr ⇒ swept reduces to the donor value, 1st order),
      !! matching tracer_advect_zonal_one_impl's near-wall band.
      !! TODO(MOM6-fidelity): MOM6 advect_tracer keeps full PPM up to the wall
      !! (dropping to PCM only at genuine local extrema / zero `mask2dCu`
      !! faces), so we are 1st-order in the 2 cells nearest a true WALL where
      !! MOM6 is PPM-with-mask (periodic seams are fine — the wrap restores
      !! full PPM).  Tracked divergence; revisit if near-wall tracer
      !! diffusion matters.
      !! a6 = 6·Tr − 3·(aL+aR).  Mirror-T at land neighbours (C2);
      !! bit-identical for all-wet (`wet_T≡1`).
      integer, intent(in) :: nx, ny, nz
      real(wp), intent(in) :: wet_T(nx, ny)
      real(wp), intent(in) :: hTr(nx, ny, nz), hprev(nx, ny, nz)
      real(wp), intent(inout) :: tr(nx, ny, nz), aL(nx, ny, nz), aR(nx, ny, nz)
      real(wp), intent(inout) :: a6(nx, ny, nz)
      integer :: i, j, k
      real(wp) :: Tr_m2, Tr_m1, Tr_0, Tr_p1, Tr_p2
      real(wp) :: dh_m1, dh_0, dh_p1, Tr_left, Tr_right

      ! Concentration field (guard zero thickness).
      do concurrent(k=1:nz, j=1:ny, i=1:nx)
         tr(i, j, k) = hTr(i, j, k)/max(hprev(i, j, k), DRAIN_MIN_H)
      end do
      ! Interior PPM parabola.
      do concurrent(k=1:nz, j=1:ny, i=3:nx - 2) &
         local(Tr_m2, Tr_m1, Tr_0, Tr_p1, Tr_p2, dh_m1, dh_0, dh_p1, Tr_left, Tr_right)
         Tr_0 = tr(i, j, k)
         Tr_m1 = ppm_mirror_h(tr(i - 1, j, k), Tr_0, wet_T(i - 1, j))
         Tr_p1 = ppm_mirror_h(tr(i + 1, j, k), Tr_0, wet_T(i + 1, j))
         Tr_m2 = ppm_mirror_h(tr(i - 2, j, k), Tr_m1, wet_T(i - 2, j))
         Tr_p2 = ppm_mirror_h(tr(i + 2, j, k), Tr_p1, wet_T(i + 2, j))
         call ppm_limited_slope(Tr_m2, Tr_m1, Tr_0, dh_m1)
         call ppm_limited_slope(Tr_m1, Tr_0, Tr_p1, dh_0)
         call ppm_limited_slope(Tr_0, Tr_p1, Tr_p2, dh_p1)
         dh_0 = dh_0*wet_T(i - 1, j)*wet_T(i, j)*wet_T(i + 1, j)
         Tr_left = 0.5_wp*(Tr_m1 + Tr_0) - (dh_0 - dh_m1)/6.0_wp
         Tr_right = 0.5_wp*(Tr_0 + Tr_p1) - (dh_p1 - dh_0)/6.0_wp
         call ppm_cell_limiter(Tr_0, Tr_left, Tr_right)
         aL(i, j, k) = Tr_left
         aR(i, j, k) = Tr_right
         a6(i, j, k) = 6.0_wp*Tr_0 - 3.0_wp*(Tr_left + Tr_right)
      end do
      ! Boundary band (i=1,2 and nx-1,nx): PCM donor (aL=aR=Tr, a6=0).
      do concurrent(k=1:nz, j=1:ny, i=1:nx)
         if (i <= 2 .or. i >= nx - 1) then
            aL(i, j, k) = tr(i, j, k)
            aR(i, j, k) = tr(i, j, k)
            a6(i, j, k) = 0.0_wp
         end if
      end do
   end subroutine drain_parabola_x