Meridional half of tracer_advect_one_impl. Same shape
as the zonal impl, applied to y. In the split flow, h
here is the post-zonal-apply thickness so the Tr = hTr/h
reconstruction stays consistent with what continuity used
in continuity_meridional_flux. iareaT = inv_dy on
uniform metrics; mass_flux_y carries dx_cv. Mirror-T at
land neighbours (C2); bit-identical for all-wet.
Optional budget_adv: accumulates −dt·(Tr_face_left_y(i,j+1)
−Tr_face_left_y(i,j))·iareaT into budget_adv. Absent ⇒
inert. Called in sequence after the zonal impl so the two
directions compose via += into the same accumulator array.
| Type | Intent | Optional | 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_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_left_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | Tr_face_right_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout), | optional | :: | budget_adv(nx,ny,nz) |
Per-cell meridional-advection budget accumulator (PSU·m or °C·m per cell). Added to the same array as the zonal half so the net entry covers both directions. Absent ⇒ inert. |
|
| real(kind=wp), | intent(in), | optional | :: | budget_w |
Bookkeeping weight on the |
| 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_y |
pure subroutine tracer_advect_meridional_one_impl(nx, ny, nz, dt, iareaT, wet_T, h, hTr, & mass_flux_y, & Tr_face_left_y, Tr_face_right_y, & budget_adv, budget_w) !! Meridional half of `tracer_advect_one_impl`. Same shape !! as the zonal impl, applied to y. In the split flow, `h` !! here is the post-zonal-apply thickness so the Tr = hTr/h !! reconstruction stays consistent with what continuity used !! in `continuity_meridional_flux`. `iareaT` = `inv_dy` on !! uniform metrics; `mass_flux_y` carries `dx_cv`. Mirror-T at !! land neighbours (C2); bit-identical for all-wet. !! !! Optional `budget_adv`: accumulates `−dt·(Tr_face_left_y(i,j+1) !! −Tr_face_left_y(i,j))·iareaT` into `budget_adv`. Absent ⇒ !! inert. Called in sequence after the zonal impl so the two !! directions compose via `+=` into the same accumulator array. 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_y(nx, ny + 1, nz) real(wp), intent(inout) :: Tr_face_left_y(nx, ny + 1, nz) real(wp), intent(inout) :: Tr_face_right_y(nx, ny + 1, nz) real(wp), intent(inout), optional :: budget_adv(nx, ny, nz) !! Per-cell meridional-advection budget accumulator (PSU·m or !! °C·m per cell). Added to the same array as the zonal half !! so the net entry covers both directions. Absent ⇒ inert. real(wp), intent(in), optional :: budget_w !! Bookkeeping weight on the `budget_adv` increment; see the !! zonal impl. Absent ⇒ 1, bit-identical. 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_y, Tr_face, dt_b do concurrent(k=1:nz, j=3:ny - 2, i=1:nx) & 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, j - 1, k)/h(i, j - 1, k), Tr_0, wet_T(i, j - 1)) Tr_p1 = ppm_mirror_h(hTr(i, j + 1, k)/h(i, j + 1, k), Tr_0, wet_T(i, j + 1)) Tr_m2 = ppm_mirror_h(hTr(i, j - 2, k)/h(i, j - 2, k), Tr_m1, wet_T(i, j - 2)) Tr_p2 = ppm_mirror_h(hTr(i, j + 2, k)/h(i, j + 2, k), Tr_p1, wet_T(i, j + 2)) 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, j - 1)*wet_T(i, j)*wet_T(i, j + 1) 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_y(i, j, k) = Tr_left Tr_face_left_y(i, j + 1, k) = Tr_right end do do concurrent(k=1:nz, i=1:nx) Tr_face_left_y(i, 1, k) = hTr(i, 1, k)/h(i, 1, k) Tr_face_right_y(i, 1, k) = hTr(i, 1, k)/h(i, 1, k) Tr_face_left_y(i, 2, k) = hTr(i, 1, k)/h(i, 1, k) Tr_face_right_y(i, 2, k) = hTr(i, 2, k)/h(i, 2, k) Tr_face_left_y(i, 3, k) = hTr(i, 2, k)/h(i, 2, k) Tr_face_right_y(i, 3, k) = hTr(i, 2, k)/h(i, 2, k) Tr_face_right_y(i, ny - 1, k) = hTr(i, ny - 1, k)/h(i, ny - 1, k) Tr_face_left_y(i, ny, k) = hTr(i, ny - 1, k)/h(i, ny - 1, k) Tr_face_right_y(i, ny, k) = hTr(i, ny, k)/h(i, ny, k) Tr_face_left_y(i, ny + 1, k) = hTr(i, ny, k)/h(i, ny, k) Tr_face_right_y(i, ny + 1, k) = hTr(i, ny, k)/h(i, ny, k) end do do concurrent(k=1:nz, j=1:ny + 1, i=1:nx) local(mass_y, Tr_face) mass_y = mass_flux_y(i, j, k) if (mass_y >= 0.0_wp) then Tr_face = Tr_face_left_y(i, j, k) else Tr_face = Tr_face_right_y(i, j, k) end if Tr_face_left_y(i, j, k) = mass_y*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_y(i, j + 1, k) - Tr_face_left_y(i, j, k))*iareaT(i, j) end do ! Budget accumulator: same guarded pattern as the zonal half. 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_y(i, j + 1, k) - Tr_face_left_y(i, j, k))*iareaT(i, j) end do end if end subroutine tracer_advect_meridional_one_impl