apply_surface_src_2d_impl Subroutine

private pure subroutine apply_surface_src_2d_impl(hTr, budget, wet_mask, Q_field, inv_scale, k_top, nz, nx, ny)

Stamp inv_scale · Q_field(i,j) · wet_mask(i,j) onto the first LIVE layer (k_top(i,j)) of a tracer’s hTr array, mirror into the matching budget contributor. Explicit-shape dummies so NVHPC stdpar can compile device kernels against static bounds.

Why k_top and not nz. Under a quasi-geopotential coordinate beneath an ice shelf the layers inside the draft are inert fillers, so on a covered column k = nz carries zstar_h_min of water. A flux stamped there is neither diffused down (the vdiff tracer matrix decouples a vanished row to the identity) nor kept (the next ALE remap drains it on h_old <= H_FLOOR) — but the budget mirror on the line below still counts it, so the column leaks exactly the deposit, every thermo step. The atmospheric part of Q_field is zero under cover, but the cavity’s own heat_cavity/salt_cavity pass through ocean_surface_flux_assemble UNMASKED, which is why this is the load-bearing site of the whole k_top slice.

inv_scale = dt/(rho0·cp) for heat, dt/rho0 for salt — a column-invariant multiplier that the caller derives from sf. Q_field carries any (i,j) spatial variation; for the default constant-fill case it is uniform, giving arithmetic identical to the old scalar-broadcast path.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx,ny,nz)
real(kind=wp), intent(inout) :: budget(nx,ny,nz)
real(kind=wp), intent(in) :: wet_mask(nx,ny)
real(kind=wp), intent(in) :: Q_field(nx,ny)
real(kind=wp), intent(in) :: inv_scale
integer, intent(in) :: k_top(nx,ny)

ms%k_top — the first LIVE layer counting down from the top. nz on every column that has no top-side filler (which is every column on every coordinate but z_fixed under a rigid top), so this reads the same memory as the literal nz it replaced and the arithmetic is bit-identical.

integer, intent(in) :: nz
integer, intent(in) :: nx
integer, intent(in) :: ny

Calls

proc~~apply_surface_src_2d_impl~~CallsGraph proc~apply_surface_src_2d_impl apply_surface_src_2d_impl local local proc~apply_surface_src_2d_impl->local

Called by

proc~~apply_surface_src_2d_impl~~CalledByGraph proc~apply_surface_src_2d_impl apply_surface_src_2d_impl proc~ocean_surface_flux_apply_tracers ocean_surface_flux_apply_tracers proc~ocean_surface_flux_apply_tracers->proc~apply_surface_src_2d_impl proc~run_stage run_stage proc~run_stage->proc~ocean_surface_flux_apply_tracers proc~run_stage_split run_stage_split proc~run_stage_split->proc~ocean_surface_flux_apply_tracers 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_stage_split 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

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: cell
integer, private :: i
integer, private :: j

Source Code

   pure subroutine apply_surface_src_2d_impl(hTr, budget, wet_mask, Q_field, &
                                             inv_scale, k_top, nz, nx, ny)
      !! Stamp `inv_scale · Q_field(i,j) · wet_mask(i,j)` onto the first
      !! LIVE layer (`k_top(i,j)`) of a tracer's hTr array, mirror into
      !! the matching budget contributor.  Explicit-shape dummies so
      !! NVHPC stdpar can compile device kernels against static bounds.
      !!
      !! **Why `k_top` and not `nz`.** Under a quasi-geopotential
      !! coordinate beneath an ice shelf the layers inside the draft are
      !! inert fillers, so on a covered column `k = nz` carries
      !! `zstar_h_min` of water.  A flux stamped there is neither
      !! diffused down (the vdiff tracer matrix decouples a vanished row
      !! to the identity) nor kept (the next ALE remap drains it on
      !! `h_old <= H_FLOOR`) — but the budget mirror on the line below
      !! still counts it, so the column leaks exactly the deposit, every
      !! thermo step.  The atmospheric part of `Q_field` is zero under
      !! cover, but the cavity's own `heat_cavity`/`salt_cavity` pass
      !! through `ocean_surface_flux_assemble` UNMASKED, which is why
      !! this is the load-bearing site of the whole `k_top` slice.
      !!
      !! `inv_scale` = dt/(rho0·cp) for heat, dt/rho0 for salt — a
      !! column-invariant multiplier that the caller derives from `sf`.
      !! `Q_field` carries any (i,j) spatial variation; for the default
      !! constant-fill case it is uniform, giving arithmetic identical to
      !! the old scalar-broadcast path.
      !!
      integer, intent(in)    :: nz, nx, ny
      real(wp), intent(inout) :: hTr(nx, ny, nz)
      real(wp), intent(inout) :: budget(nx, ny, nz)
      real(wp), intent(in)    :: wet_mask(nx, ny)
      real(wp), intent(in)    :: Q_field(nx, ny)
      real(wp), intent(in)    :: inv_scale
      integer, intent(in)    :: k_top(nx, ny)
         !! `ms%k_top` — the first LIVE layer counting down from the top.
         !! `nz` on every column that has no top-side filler (which is
         !! every column on every coordinate but `z_fixed` under a rigid
         !! top), so this reads the same memory as the literal `nz` it
         !! replaced and the arithmetic is bit-identical.
      integer :: i, j
      real(wp) :: cell
      do concurrent(j=1:ny, i=1:nx) local(cell)
         cell = inv_scale*Q_field(i, j)*wet_mask(i, j)
         hTr(i, j, k_top(i, j)) = hTr(i, j, k_top(i, j)) + cell
         budget(i, j, k_top(i, j)) = budget(i, j, k_top(i, j)) + cell
      end do
   end subroutine apply_surface_src_2d_impl