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 | Intent | Optional | 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. |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | it |
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