Iterate the tracer registry and apply constant-kappa_h
horizontal Laplacian diffusion to every tracer whose
do_horizontal_diffusion flag is set. Outer-shim:
forwards each tracer’s hTr to the flat-impl below.
Reuses the same scratch buffers across all tracers in one
call.
Optional active — when present and false the kernel is a
no-op (used by the dyn step to gate on
thermodynamics + thermo-substep cadence).
Optional bc — per-edge OBC tags, resolved to plain host
logicals before the kernel call (mirrors
continuity_zonal_flux; a derived-type dummy must never
reach a do concurrent kernel — mem:separate). Absent =>
WALL on every edge (single-rank default). A non-WALL edge,
or an MPI seam (has_* = .false.), leaves the physical-edge
flux computed rather than hard-zeroed — the halo/periodic-wrap
preamble the split-solver caller runs immediately before this
call has already filled the ghost band with the correct
neighbour/periodic value there.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(ocean_hdiff_tracer_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(inout) | :: | ms | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| logical, | intent(in), | optional | :: | active | ||
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | it | ||||
| logical, | private | :: | wall_e | ||||
| logical, | private | :: | wall_n | ||||
| logical, | private | :: | wall_s | ||||
| logical, | private | :: | wall_w |
subroutine tracer_hdiff(grid, metrics, this, ms, dt, active, bc) !! Iterate the tracer registry and apply constant-`kappa_h` !! horizontal Laplacian diffusion to every tracer whose !! `do_horizontal_diffusion` flag is set. Outer-shim: !! forwards each tracer's hTr to the flat-impl below. !! Reuses the same scratch buffers across all tracers in one !! call. !! !! Optional `active` — when present and false the kernel is a !! no-op (used by the dyn step to gate on !! thermodynamics + thermo-substep cadence). !! !! Optional `bc` — per-edge OBC tags, resolved to plain host !! logicals before the kernel call (mirrors !! `continuity_zonal_flux`; a derived-type dummy must never !! reach a `do concurrent` kernel — mem:separate). Absent => !! WALL on every edge (single-rank default). A non-WALL edge, !! or an MPI seam (`has_* = .false.`), leaves the physical-edge !! flux computed rather than hard-zeroed — the halo/periodic-wrap !! preamble the split-solver caller runs immediately before this !! call has already filled the ghost band with the correct !! neighbour/periodic value there. type(hgrid_t), intent(in) :: grid type(ocean_metrics_t), intent(in) :: metrics type(ocean_hdiff_tracer_t), intent(inout) :: this type(multilayer_state_t), intent(inout) :: ms real(wp), intent(in) :: dt logical, intent(in), optional :: active type(ocean_bc_state_t), intent(in), optional :: bc integer :: it logical :: wall_w, wall_e, wall_s, wall_n if (present(active)) then if (.not. active) return end if if (.not. allocated(ms%tracers)) return if (this%kappa_h <= 0.0_wp) return ! Resolve the physical-edge wall flags on the host — see ! `continuity_zonal_flux` for the identical pattern. Default ! .true. => single-rank, all-wall closed boundary (bit-identical ! to a run with no `bc`). wall_w = .true. wall_e = .true. wall_s = .true. wall_n = .true. if (present(bc)) then wall_w = (ocean_bc_outer_face_tag(bc%west%bc_type) == OBC_WALL) .and. bc%has_west wall_e = (ocean_bc_outer_face_tag(bc%east%bc_type) == OBC_WALL) .and. bc%has_east wall_s = (ocean_bc_outer_face_tag(bc%south%bc_type) == OBC_WALL) .and. bc%has_south wall_n = (ocean_bc_outer_face_tag(bc%north%bc_type) == OBC_WALL) .and. bc%has_north end if ! The mask actuals are chosen ONCE, outside the tracer loop: they are ! passed as ABSENT optionals on the default path (see the `open_u` ! docstring for why an inert stand-in is not available here), and ! an absent optional cannot be selected inside an expression, so ! the select-case is written twice rather than the arguments once. ! Thermo cadence, cold code. if (metrics%use_closed_faces) then do it = 1, size(ms%tracers) if (.not. ms%tracers(it)%do_horizontal_diffusion) cycle select case (ms%tracers(it)%budget_id) case (TRACER_BUDGET_HEAT) call tracer_hdiff_one_impl( & grid%nx_total, grid%ny_total, ms%nz_ml, & grid%nghost, grid%nx_phys, grid%ny_phys, & dt, this%kappa_h, & metrics%dy_cu, metrics%dx_cv, metrics%idxCu, metrics%idyCv, & metrics%iareaT, & ms%h_layer, ms%tracers(it)%hTr, & this%T_centre%data, & this%F_x_face%data, this%F_y_face%data, & wall_w, wall_e, wall_s, wall_n, & open_u=metrics%open_u, open_v=metrics%open_v, & budget=ms%heat_budget_hdiff) case (TRACER_BUDGET_SALT) call tracer_hdiff_one_impl( & grid%nx_total, grid%ny_total, ms%nz_ml, & grid%nghost, grid%nx_phys, grid%ny_phys, & dt, this%kappa_h, & metrics%dy_cu, metrics%dx_cv, metrics%idxCu, metrics%idyCv, & metrics%iareaT, & ms%h_layer, ms%tracers(it)%hTr, & this%T_centre%data, & this%F_x_face%data, this%F_y_face%data, & wall_w, wall_e, wall_s, wall_n, & open_u=metrics%open_u, open_v=metrics%open_v, & budget=ms%salt_budget_hdiff) case default call tracer_hdiff_one_impl( & grid%nx_total, grid%ny_total, ms%nz_ml, & grid%nghost, grid%nx_phys, grid%ny_phys, & dt, this%kappa_h, & metrics%dy_cu, metrics%dx_cv, metrics%idxCu, metrics%idyCv, & metrics%iareaT, & ms%h_layer, ms%tracers(it)%hTr, & this%T_centre%data, & this%F_x_face%data, this%F_y_face%data, & wall_w, wall_e, wall_s, wall_n, & open_u=metrics%open_u, open_v=metrics%open_v) end select end do else do it = 1, size(ms%tracers) if (.not. ms%tracers(it)%do_horizontal_diffusion) cycle select case (ms%tracers(it)%budget_id) case (TRACER_BUDGET_HEAT) call tracer_hdiff_one_impl( & grid%nx_total, grid%ny_total, ms%nz_ml, & grid%nghost, grid%nx_phys, grid%ny_phys, & dt, this%kappa_h, & metrics%dy_cu, metrics%dx_cv, metrics%idxCu, metrics%idyCv, & metrics%iareaT, & ms%h_layer, ms%tracers(it)%hTr, & this%T_centre%data, & this%F_x_face%data, this%F_y_face%data, & wall_w, wall_e, wall_s, wall_n, & budget=ms%heat_budget_hdiff) case (TRACER_BUDGET_SALT) call tracer_hdiff_one_impl( & grid%nx_total, grid%ny_total, ms%nz_ml, & grid%nghost, grid%nx_phys, grid%ny_phys, & dt, this%kappa_h, & metrics%dy_cu, metrics%dx_cv, metrics%idxCu, metrics%idyCv, & metrics%iareaT, & ms%h_layer, ms%tracers(it)%hTr, & this%T_centre%data, & this%F_x_face%data, this%F_y_face%data, & wall_w, wall_e, wall_s, wall_n, & budget=ms%salt_budget_hdiff) case default call tracer_hdiff_one_impl( & grid%nx_total, grid%ny_total, ms%nz_ml, & grid%nghost, grid%nx_phys, grid%ny_phys, & dt, this%kappa_h, & metrics%dy_cu, metrics%dx_cv, metrics%idxCu, metrics%idyCv, & metrics%iareaT, & ms%h_layer, ms%tracers(it)%hTr, & this%T_centre%data, & this%F_x_face%data, this%F_y_face%data, & wall_w, wall_e, wall_s, wall_n) end select end do end if end subroutine tracer_hdiff