Device kernel over PHYSICAL surface cells (ghosts excluded — wall ghosts are inert and seam ghosts are rebuilt by the wrap / exchange, so clamping them would double-count the bank in any area integral). Per wet cell at k = nz:
T = hTr_T/h, S = hTr_S/h, T_f = eos_freezing_point(S, 0) if T < T_f: frazil_heat += ρ·Cp·h·(T_f − T) and hTr_T = h·T_f (exact clamp)
Surface pressure p = 0 (surface-relative hydrostatic zero —
same convention as the surface-flux kernels; the in-situ
layer-centre depression over h_surf/2 is O(1 mK) and ignored,
matching MOM6’s p=0 surface-frazil evaluation). Vanished
columns (h <= H_VANISHED) and land (wet_mask = 0) are
skipped — the division for a PHYSICAL T/S gates on
H_VANISHED per the thin-layer taxonomy. The conditional
write uses an inner if, NOT a do concurrent mask header
(masked DC headers fail tools/dc_audit.py –strict).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | hTr_T(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | hTr_S(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | wet_mask(nx,ny) | |||
| real(kind=wp), | intent(inout) | :: | frazil_heat(nx,ny) | |||
| real(kind=wp), | intent(inout) | :: | heat_budget_frazil(nx,ny,1) | |||
| type(eos_t), | intent(in) | :: | eos | |||
| integer, | intent(in) | :: | nghost | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | d_htr | ||||
| real(kind=wp), | private | :: | h | ||||
| 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 | :: | s_sfc | ||||
| real(kind=wp), | private | :: | t_f | ||||
| real(kind=wp), | private | :: | t_sfc |
pure subroutine ice_frazil_accumulate_impl(hTr_T, hTr_S, h_layer, wet_mask, & frazil_heat, heat_budget_frazil, & eos, nghost, nz, nx, ny) !! Device kernel over PHYSICAL surface cells (ghosts excluded — !! wall ghosts are inert and seam ghosts are rebuilt by the wrap / !! exchange, so clamping them would double-count the bank in any !! area integral). Per wet cell at k = nz: !! !! T = hTr_T/h, S = hTr_S/h, T_f = eos_freezing_point(S, 0) !! if T < T_f: frazil_heat += ρ·Cp·h·(T_f − T) and !! hTr_T = h·T_f (exact clamp) !! !! Surface pressure p = 0 (surface-relative hydrostatic zero — !! same convention as the surface-flux kernels; the in-situ !! layer-centre depression over h_surf/2 is O(1 mK) and ignored, !! matching MOM6's p=0 surface-frazil evaluation). Vanished !! columns (`h <= H_VANISHED`) and land (`wet_mask = 0`) are !! skipped — the division for a PHYSICAL T/S gates on !! `H_VANISHED` per the thin-layer taxonomy. The conditional !! write uses an inner `if`, NOT a `do concurrent` mask header !! (masked DC headers fail tools/dc_audit.py --strict). integer, intent(in) :: nghost, nz, nx, ny real(wp), intent(inout) :: hTr_T(nx, ny, nz) real(wp), intent(in) :: hTr_S(nx, ny, nz) real(wp), intent(in) :: h_layer(nx, ny, nz) real(wp), intent(in) :: wet_mask(nx, ny) real(wp), intent(inout) :: frazil_heat(nx, ny) real(wp), intent(inout) :: heat_budget_frazil(nx, ny, 1) type(eos_t), intent(in) :: eos integer :: i, j, i_lo, i_hi, j_lo, j_hi real(wp) :: h, t_sfc, s_sfc, t_f, d_htr 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(h, t_sfc, s_sfc, t_f, d_htr) h = h_layer(i, j, nz) if (wet_mask(i, j) > 0.5_wp .and. h > H_VANISHED) then t_sfc = hTr_T(i, j, nz)/h s_sfc = hTr_S(i, j, nz)/h t_f = eos_freezing_point(eos, s_sfc, 0.0_wp) if (t_sfc < t_f) then d_htr = h*(t_f - t_sfc) frazil_heat(i, j) = frazil_heat(i, j) & + RHO_WATER*SEAWATER_CP*d_htr heat_budget_frazil(i, j, 1) = heat_budget_frazil(i, j, 1) + d_htr ! Exact clamp: T_after = (h·T_f)/h == T_f. hTr_T(i, j, nz) = h*t_f end if end if end do end subroutine ice_frazil_accumulate_impl