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).
| Type | Intent | Optional | 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 |
| 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 |
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