tracer_advect_zonal_one_impl Subroutine

private pure subroutine tracer_advect_zonal_one_impl(nx, ny, nz, dt, iareaT, wet_T, h, hTr, mass_flux_x, Tr_face_left_x, Tr_face_right_x, budget_adv, budget_w)

Zonal half of tracer_advect_one_impl. Same three-pass pattern (PPM reconstruction → upwind pick into tracer mass flux → forward-Euler update) but only the x-direction half. Reads the input h for the Tr = hTr/h reconstruction. The tracer transport mass_flux_x·Tr_face inherits dy_cu, and the divergence closes with iareaT (= inv_dx on uniform). Mirror-T at land neighbours (C2): a held land column’s tracer is reflected to the local cell so the wet-side face value is unbiased; bit-identical for all-wet (wet_T≡1).

Optional budget_adv: when present, a separate do concurrent loop accumulates −dt·(Tr_face_left_x(i+1)−Tr_face_left_x(i))·iareaT into budget_adv (same divergence written to hTr). The prognostic hTr update loop is UNCHANGED — byte-identical when budget_adv is absent. Used by the console salt/heat closure.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: iareaT(nx,ny)
real(kind=wp), intent(in) :: wet_T(nx,ny)
real(kind=wp), intent(in) :: h(nx,ny,nz)
real(kind=wp), intent(inout) :: hTr(nx,ny,nz)
real(kind=wp), intent(in) :: mass_flux_x(nx+1,ny,nz)
real(kind=wp), intent(inout) :: Tr_face_left_x(nx+1,ny,nz)
real(kind=wp), intent(inout) :: Tr_face_right_x(nx+1,ny,nz)
real(kind=wp), intent(inout), optional :: budget_adv(nx,ny,nz)

Per-cell accumulator for the horizontal-advection budget (same sign/units as hTr). When present, the zonal-flux divergence is added (+=) here after the prognostic update. Absent ⇒ inert (byte-identical to the pre-feature build).

real(kind=wp), intent(in), optional :: budget_w

Bookkeeping weight on the budget_adv increment (absent ⇒ 1, bit-identical). A caller writing OUTSIDE an RK2 stage (the GM operator, after the stage average) passes the reciprocal of the console’s per-step weight, 1/ocean_budget_stage_weight.


Calls

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

Called by

proc~~tracer_advect_zonal_one_impl~~CalledByGraph proc~tracer_advect_zonal_one_impl tracer_advect_zonal_one_impl proc~gm_tracer_advect_x gm_tracer_advect_x proc~gm_tracer_advect_x->proc~tracer_advect_zonal_one_impl proc~tracer_advect_zonal tracer_advect_zonal proc~tracer_advect_zonal->proc~tracer_advect_zonal_one_impl proc~continuity_gm_apply continuity_gm_apply proc~continuity_gm_apply->proc~gm_tracer_advect_x proc~continuity_tracer_step_split continuity_tracer_step_split proc~continuity_tracer_step_split->proc~tracer_advect_zonal proc~run_continuity_chain run_continuity_chain proc~run_continuity_chain->proc~continuity_tracer_step_split proc~run_gm_step run_gm_step proc~run_gm_step->proc~continuity_gm_apply proc~run_stage run_stage proc~run_stage->proc~continuity_tracer_step_split proc~ocean_dyn_step ocean_dyn_step proc~ocean_dyn_step->proc~run_stage proc~ocean_dyn_step_split ocean_dyn_step_split proc~ocean_dyn_step_split->proc~run_gm_step proc~run_stage_split run_stage_split proc~ocean_dyn_step_split->proc~run_stage_split proc~run_stage_split->proc~run_continuity_chain proc~engine_step engine_step proc~engine_step->proc~ocean_dyn_step proc~engine_step->proc~ocean_dyn_step_split

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: Tr_0
real(kind=wp), private :: Tr_face
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
real(kind=wp), private :: dt_b
integer, private :: i
integer, private :: j
integer, private :: k
real(kind=wp), private :: mass_x

Source Code

   pure subroutine tracer_advect_zonal_one_impl(nx, ny, nz, dt, iareaT, wet_T, h, hTr, &
                                                mass_flux_x, &
                                                Tr_face_left_x, Tr_face_right_x, &
                                                budget_adv, budget_w)
      !! Zonal half of `tracer_advect_one_impl`.  Same three-pass
      !! pattern (PPM reconstruction → upwind pick into tracer mass
      !! flux → forward-Euler update) but only the x-direction half.
      !! Reads the input `h` for the Tr = hTr/h reconstruction.  The
      !! tracer transport `mass_flux_x·Tr_face` inherits `dy_cu`, and
      !! the divergence closes with `iareaT` (= `inv_dx` on uniform).
      !! Mirror-T at land neighbours (C2): a held land column's tracer
      !! is reflected to the local cell so the wet-side face value is
      !! unbiased; bit-identical for all-wet (`wet_T≡1`).
      !!
      !! Optional `budget_adv`: when present, a separate `do concurrent`
      !! loop accumulates `−dt·(Tr_face_left_x(i+1)−Tr_face_left_x(i))·iareaT`
      !! into `budget_adv` (same divergence written to `hTr`).  The
      !! prognostic hTr update loop is UNCHANGED — byte-identical when
      !! `budget_adv` is absent.  Used by the console salt/heat closure.
      integer, intent(in) :: nx, ny, nz
      real(wp), intent(in) :: dt
      real(wp), intent(in) :: iareaT(nx, ny)
      real(wp), intent(in) :: wet_T(nx, ny)
      real(wp), intent(in) :: h(nx, ny, nz)
      real(wp), intent(inout) :: hTr(nx, ny, nz)
      real(wp), intent(in) :: mass_flux_x(nx + 1, ny, nz)
      real(wp), intent(inout) :: Tr_face_left_x(nx + 1, ny, nz)
      real(wp), intent(inout) :: Tr_face_right_x(nx + 1, ny, nz)
      real(wp), intent(inout), optional :: budget_adv(nx, ny, nz)
         !! Per-cell accumulator for the horizontal-advection budget
         !! (same sign/units as hTr).  When present, the zonal-flux
         !! divergence is added (+=) here after the prognostic update.
         !! Absent ⇒ inert (byte-identical to the pre-feature build).
      real(wp), intent(in), optional :: budget_w
         !! Bookkeeping weight on the `budget_adv` increment (absent ⇒ 1,
         !! bit-identical).  A caller writing OUTSIDE an RK2 stage (the GM
         !! operator, after the stage average) passes the reciprocal of the
         !! console's per-step weight, `1/ocean_budget_stage_weight`.

      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
      real(wp) :: mass_x, Tr_face, dt_b

      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 = hTr(i, j, k)/h(i, j, k)
         Tr_m1 = ppm_mirror_h(hTr(i - 1, j, k)/h(i - 1, j, k), Tr_0, wet_T(i - 1, j))
         Tr_p1 = ppm_mirror_h(hTr(i + 1, j, k)/h(i + 1, j, k), Tr_0, wet_T(i + 1, j))
         Tr_m2 = ppm_mirror_h(hTr(i - 2, j, k)/h(i - 2, j, k), Tr_m1, wet_T(i - 2, j))
         Tr_p2 = ppm_mirror_h(hTr(i + 2, j, k)/h(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)
         Tr_face_right_x(i, j, k) = Tr_left
         Tr_face_left_x(i + 1, j, k) = Tr_right
      end do
      do concurrent(k=1:nz, j=1:ny)
         Tr_face_left_x(1, j, k) = hTr(1, j, k)/h(1, j, k)
         Tr_face_right_x(1, j, k) = hTr(1, j, k)/h(1, j, k)
         Tr_face_left_x(2, j, k) = hTr(1, j, k)/h(1, j, k)
         Tr_face_right_x(2, j, k) = hTr(2, j, k)/h(2, j, k)
         Tr_face_left_x(3, j, k) = hTr(2, j, k)/h(2, j, k)
         Tr_face_right_x(3, j, k) = hTr(2, j, k)/h(2, j, k)
         Tr_face_right_x(nx - 1, j, k) = hTr(nx - 1, j, k)/h(nx - 1, j, k)
         Tr_face_left_x(nx, j, k) = hTr(nx - 1, j, k)/h(nx - 1, j, k)
         Tr_face_right_x(nx, j, k) = hTr(nx, j, k)/h(nx, j, k)
         Tr_face_left_x(nx + 1, j, k) = hTr(nx, j, k)/h(nx, j, k)
         Tr_face_right_x(nx + 1, j, k) = hTr(nx, j, k)/h(nx, j, k)
      end do

      do concurrent(k=1:nz, j=1:ny, i=1:nx + 1) local(mass_x, Tr_face)
         mass_x = mass_flux_x(i, j, k)
         if (mass_x >= 0.0_wp) then
            Tr_face = Tr_face_left_x(i, j, k)
         else
            Tr_face = Tr_face_right_x(i, j, k)
         end if
         Tr_face_left_x(i, j, k) = mass_x*Tr_face
      end do

      do concurrent(k=1:nz, j=1:ny, i=1:nx)
         hTr(i, j, k) = hTr(i, j, k) - dt* &
                        (Tr_face_left_x(i + 1, j, k) - Tr_face_left_x(i, j, k))*iareaT(i, j)
      end do

      ! Budget accumulator: separate guarded loop so the prognostic update above
      ! is UNCHANGED (byte-identical when budget_adv is absent).  Mirrors the
      ! same divergence that was just applied to hTr — the console uses it to
      ! close the salt/heat conservation residual.
      if (present(budget_adv)) then
         dt_b = dt
         if (present(budget_w)) dt_b = dt*budget_w
         do concurrent(k=1:nz, j=1:ny, i=1:nx)
            budget_adv(i, j, k) = budget_adv(i, j, k) - dt_b* &
                                  (Tr_face_left_x(i + 1, j, k) - Tr_face_left_x(i, j, k))*iareaT(i, j)
         end do
      end if
   end subroutine tracer_advect_zonal_one_impl