tracer_advect_vertical Subroutine

public subroutine tracer_advect_vertical(grid, this, ms, dt, active)

Apply first-order upwind-in-z vertical advection to every registered tracer, then update h_layer by the same vertical mass-flux divergence. Updating h is what makes the kernel CWC-consistent — uniform T = hTr/h stays uniform regardless of how divergent the w field is.

Order matters: tracers read the pre-update h_layer for their upwind concentration; h_layer is updated only after all tracers have run.

Eulerian-z mode: the h update here exactly cancels the horizontal h update produced by continuity_tracer_step_split (both consume the same flux_h_layer — the total horizontal divergence summed over both substeps), so h_layer stays at its initial z-coordinate values.

Per-tracer do_vertical_exchange gate lets diagnostic / forced tracers opt out without affecting horizontal advection.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_vertical_advection_t), intent(inout) :: this
type(multilayer_state_t), intent(inout) :: ms
real(kind=wp), intent(in) :: dt
logical, intent(in), optional :: active

Optional gate (thermo cadence). Absent ⇒ kernel runs; present-and-false ⇒ early return.


Calls

proc~~tracer_advect_vertical~~CallsGraph proc~tracer_advect_vertical tracer_advect_vertical proc~apply_w_to_h_layer apply_w_to_h_layer proc~tracer_advect_vertical->proc~apply_w_to_h_layer proc~tracer_advect_vertical_one_impl tracer_advect_vertical_one_impl proc~tracer_advect_vertical->proc~tracer_advect_vertical_one_impl local local proc~tracer_advect_vertical_one_impl->local

Called by

proc~~tracer_advect_vertical~~CalledByGraph proc~tracer_advect_vertical tracer_advect_vertical proc~run_continuity_chain run_continuity_chain proc~run_continuity_chain->proc~tracer_advect_vertical proc~run_gm_step run_gm_step proc~run_gm_step->proc~tracer_advect_vertical proc~run_stage run_stage proc~run_stage->proc~tracer_advect_vertical 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 proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_step proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean

Variables

Type Visibility Attributes Name Initial
integer, private :: it

Source Code

   subroutine tracer_advect_vertical(grid, this, ms, dt, active)
      !! Apply first-order upwind-in-z vertical advection to every
      !! registered tracer, then update `h_layer` by the same
      !! vertical mass-flux divergence.  Updating h is what makes
      !! the kernel CWC-consistent — uniform `T = hTr/h` stays
      !! uniform regardless of how divergent the w field is.
      !!
      !! Order matters: tracers read the pre-update `h_layer` for
      !! their upwind concentration; `h_layer` is updated only
      !! after all tracers have run.
      !!
      !! Eulerian-z mode: the h update here exactly cancels the
      !! horizontal h update produced by
      !! `continuity_tracer_step_split` (both consume
      !! the same `flux_h_layer` — the total horizontal divergence
      !! summed over both substeps), so `h_layer` stays at its
      !! initial z-coordinate values.
      !!
      !! Per-tracer `do_vertical_exchange` gate lets diagnostic /
      !! forced tracers opt out without affecting horizontal
      !! advection.
      type(hgrid_t), intent(in) :: grid
      type(ocean_vertical_advection_t), intent(inout) :: this
      type(multilayer_state_t), intent(inout) :: ms
      real(wp), intent(in) :: dt
      logical, intent(in), optional :: active
         !! Optional gate (thermo cadence).  Absent ⇒ kernel runs;
         !! present-and-false ⇒ early return.

      integer :: it

      if (present(active)) then
         if (.not. active) return
      end if
      if (allocated(ms%tracers)) then
         do it = 1, size(ms%tracers)
            if (.not. ms%tracers(it)%do_vertical_exchange) cycle
            select case (ms%tracers(it)%budget_id)
            case (TRACER_BUDGET_HEAT)
               call tracer_advect_vertical_one_impl( &
                  grid%nx_total, grid%ny_total, ms%nz_ml, dt, &
                  ms%h_layer, ms%w_interface, ms%tracers(it)%hTr, &
                  this%F_face%data, budget=ms%heat_budget_vert_adv)
            case (TRACER_BUDGET_SALT)
               call tracer_advect_vertical_one_impl( &
                  grid%nx_total, grid%ny_total, ms%nz_ml, dt, &
                  ms%h_layer, ms%w_interface, ms%tracers(it)%hTr, &
                  this%F_face%data, budget=ms%salt_budget_vert_adv)
            case default
               call tracer_advect_vertical_one_impl( &
                  grid%nx_total, grid%ny_total, ms%nz_ml, dt, &
                  ms%h_layer, ms%w_interface, ms%tracers(it)%hTr, &
                  this%F_face%data)
            end select
         end do
      end if

      call apply_w_to_h_layer(grid%nx_total, grid%ny_total, ms%nz_ml, dt, &
                              ms%w_interface, ms%h_layer)
   end subroutine tracer_advect_vertical