ice_snowfall_ocean_share_impl Subroutine

private pure subroutine ice_snowfall_ocean_share_impl(snow_part_ocn, atm_fprec, sst_seam, ssurf_seam, fprec_ocn_diag, heat_flux_diag, salt_flux_diag, dt_therm, nghost, nx, ny)

Device kernel over PHYSICAL cells (ghosts excluded). Gated on snow_part_ocn(i,j) > 0 rather than a separate wet_mask arg: ice_snow_part_ocn_fill_impl (rdb_ice_thermo_driver) already zeroes snow_part_ocn on land/dry/fully-ice-covered cells, so that field IS the wet-and-ice-free gate this kernel needs – functionally identical to (and cheaper than) re-deriving a wet_mask > 0.5 test here, and keeps this module’s signature to the (grid, ice, dt_therm) seam (no ms dependency).

fprec_ocn_diag is zeroed unconditionally at loop top (this module owns it outright, same contract as heat_flux_diag/ m_melt_diag in ice_thermo_driver_reduce_impl). heat_flux_diag/salt_flux_diag are ADDED to, never zeroed – the ordering contract this module’s docstring states, now the second (salt_flux_diag) / third (heat_flux_diag) contributor.

Reuses the sst_seam/ssurf_seam sample ice_compute_basal_ flux filled earlier in the same thermo window (module docstring) – does not re-derive from ms/eos.

Decl-order: all integer dims declared before the explicit-shape arrays that use them. Inner if gate only (never a masked do concurrent header).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: snow_part_ocn(nx,ny)
real(kind=wp), intent(in) :: atm_fprec(nx,ny)
real(kind=wp), intent(in) :: sst_seam(nx,ny)
real(kind=wp), intent(in) :: ssurf_seam(nx,ny)
real(kind=wp), intent(inout) :: fprec_ocn_diag(nx,ny)
real(kind=wp), intent(inout) :: heat_flux_diag(nx,ny)
real(kind=wp), intent(inout) :: salt_flux_diag(nx,ny)
real(kind=wp), intent(in) :: dt_therm
integer, intent(in) :: nghost
integer, intent(in) :: nx
integer, intent(in) :: ny

Calls

proc~~ice_snowfall_ocean_share_impl~~CallsGraph proc~ice_snowfall_ocean_share_impl ice_snowfall_ocean_share_impl local local proc~ice_snowfall_ocean_share_impl->local proc~ice_enthalpy_liquid ice_enthalpy_liquid proc~ice_snowfall_ocean_share_impl->proc~ice_enthalpy_liquid

Called by

proc~~ice_snowfall_ocean_share_impl~~CalledByGraph proc~ice_snowfall_ocean_share_impl ice_snowfall_ocean_share_impl proc~ice_snowfall_ocean_share ice_snowfall_ocean_share proc~ice_snowfall_ocean_share->proc~ice_snowfall_ocean_share_impl proc~engine_step_ice engine_step_ice proc~engine_step_ice->proc~ice_snowfall_ocean_share proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_step_ice proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step_ice proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: enth_ocean
integer, private :: i
integer, private :: i_hi
integer, private :: i_lo
integer, private :: j
integer, private :: j_hi
integer, private :: j_lo
real(kind=wp), private :: m_ocn

Source Code

   pure subroutine ice_snowfall_ocean_share_impl(snow_part_ocn, atm_fprec, sst_seam, &
                                                 ssurf_seam, fprec_ocn_diag, &
                                                 heat_flux_diag, salt_flux_diag, &
                                                 dt_therm, nghost, nx, ny)
      !! Device kernel over PHYSICAL cells (ghosts excluded). Gated on
      !! `snow_part_ocn(i,j) > 0` rather than a separate `wet_mask` arg:
      !! `ice_snow_part_ocn_fill_impl` (`rdb_ice_thermo_driver`) already
      !! zeroes `snow_part_ocn` on land/dry/fully-ice-covered cells, so
      !! that field IS the wet-and-ice-free gate this kernel needs --
      !! functionally identical to (and cheaper than) re-deriving a
      !! `wet_mask > 0.5` test here, and keeps this module's signature to
      !! the `(grid, ice, dt_therm)` seam (no `ms` dependency).
      !!
      !! `fprec_ocn_diag` is zeroed unconditionally at loop top (this
      !! module owns it outright, same contract as `heat_flux_diag`/
      !! `m_melt_diag` in `ice_thermo_driver_reduce_impl`).
      !! `heat_flux_diag`/`salt_flux_diag` are ADDED to, never zeroed --
      !! the ordering contract this module's docstring states, now the
      !! second (`salt_flux_diag`) / third (`heat_flux_diag`) contributor.
      !!
      !! Reuses the `sst_seam`/`ssurf_seam` sample `ice_compute_basal_
      !! flux` filled earlier in the same thermo window (module
      !! docstring) -- does not re-derive from `ms`/`eos`.
      !!
      !! Decl-order: all integer dims declared before the explicit-shape
      !! arrays that use them. Inner `if` gate only (never a masked
      !! `do concurrent` header).
      integer, intent(in) :: nghost, nx, ny
      real(wp), intent(in) :: snow_part_ocn(nx, ny)
      real(wp), intent(in) :: atm_fprec(nx, ny)
      real(wp), intent(in) :: sst_seam(nx, ny)
      real(wp), intent(in) :: ssurf_seam(nx, ny)
      real(wp), intent(inout) :: fprec_ocn_diag(nx, ny)
      real(wp), intent(inout) :: heat_flux_diag(nx, ny)
      real(wp), intent(inout) :: salt_flux_diag(nx, ny)
      real(wp), intent(in) :: dt_therm

      integer :: i, j, i_lo, i_hi, j_lo, j_hi
      real(wp) :: m_ocn, enth_ocean

      i_lo = nghost + 1
      i_hi = nx - nghost
      j_lo = nghost + 1
      j_hi = ny - nghost

      do concurrent(j=j_lo:j_hi, i=i_lo:i_hi) local(m_ocn, enth_ocean)
         fprec_ocn_diag(i, j) = 0.0_wp
         if (snow_part_ocn(i, j) > 0.0_wp) then
            fprec_ocn_diag(i, j) = snow_part_ocn(i, j)*atm_fprec(i, j)
            m_ocn = fprec_ocn_diag(i, j)*dt_therm
            enth_ocean = ice_enthalpy_liquid(sst_seam(i, j), ssurf_seam(i, j))
            heat_flux_diag(i, j) = heat_flux_diag(i, j) &
                                   - m_ocn*(enth_ocean - ENTH_SNOWFALL)/dt_therm
            ! TODO(PR-16): virtual-salt term; delete when net_massin lands
            ! (fprec_ocn_diag becomes a real freshwater source instead).
            salt_flux_diag(i, j) = salt_flux_diag(i, j) - m_ocn*ssurf_seam(i, j)/dt_therm
         end if
      end do
   end subroutine ice_snowfall_ocean_share_impl