tracer_hdiff Subroutine

public 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.

Arguments

Type IntentOptional 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

Calls

proc~~tracer_hdiff~~CallsGraph proc~tracer_hdiff tracer_hdiff proc~ocean_bc_outer_face_tag ocean_bc_outer_face_tag proc~tracer_hdiff->proc~ocean_bc_outer_face_tag proc~tracer_hdiff_one_impl tracer_hdiff_one_impl proc~tracer_hdiff->proc~tracer_hdiff_one_impl local local proc~tracer_hdiff_one_impl->local

Called by

proc~~tracer_hdiff~~CalledByGraph proc~tracer_hdiff tracer_hdiff proc~run_continuity_chain run_continuity_chain proc~run_continuity_chain->proc~tracer_hdiff proc~run_stage run_stage proc~run_stage->proc~tracer_hdiff proc~ocean_dyn_step ocean_dyn_step proc~ocean_dyn_step->proc~run_stage proc~run_stage_split run_stage_split proc~run_stage_split->proc~run_continuity_chain proc~engine_step engine_step proc~engine_step->proc~ocean_dyn_step proc~ocean_dyn_step_split ocean_dyn_step_split proc~engine_step->proc~ocean_dyn_step_split proc~ocean_dyn_step_split->proc~run_stage_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
logical, private :: wall_e
logical, private :: wall_n
logical, private :: wall_s
logical, private :: wall_w

Source Code

   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