The two INTERIOR integrals the mass budget and the compensation sink need, reduced on device in one pass:
vol_melt — the meltwater volume (m^3) added this step,
sum(melt*dt/rho_0 * areaT) over active columns;
area_open — the wet area (m^2) the ice does NOT cover.
GHOSTS ARE EXCLUDED (nghost+1 .. n-nghost), exactly as
ocean_accumulate_mass_out excludes them: the console’s totals
are interior integrals, so a source term that counted the halo
would be measuring a different domain than the total it has to
close. The per-cell APPLY still runs over the whole array, like
every other surface kernel — the halo exchange owns the ghosts.
melt*dt_over_rho0 is formed with the same scalar and in the
same order as the apply kernel’s dh, so the two agree to the
last bit per cell and the residual is reduction round-off only.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx |
First dimension (ghosts included). |
||
| integer, | intent(in) | :: | ny |
Second dimension. |
||
| integer, | intent(in) | :: | nghost |
Halo width to exclude on every side. |
||
| real(kind=wp), | intent(in) | :: | dt_over_rho0 |
|
||
| real(kind=wp), | intent(in) | :: | active(nx,ny) |
Composed solve mask. |
||
| real(kind=wp), | intent(in) | :: | wet_mask(nx,ny) |
Static wet (1) / land (0) mask. |
||
| real(kind=wp), | intent(in) | :: | cover_frac(nx,ny) |
Ice-cover fraction (v1 binary). |
||
| real(kind=wp), | intent(in) | :: | melt(nx,ny) |
Melt mass flux (kg/m^2/s). |
||
| real(kind=wp), | intent(in) | :: | areaT(nx,ny) |
Cell area (m^2). |
||
| real(kind=wp), | intent(out) | :: | vol_melt |
Meltwater volume this step (m^3). |
||
| real(kind=wp), | intent(out) | :: | area_open |
Uncovered wet area (m^2). |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | acc_a | ||||
| real(kind=wp), | private | :: | acc_v | ||||
| integer, | private | :: | i | ||||
| integer, | private | :: | i_hi | ||||
| integer, | private | :: | i_lo | ||||
| integer, | private | :: | j | ||||
| integer, | private | :: | j_hi | ||||
| integer, | private | :: | j_lo |
pure subroutine cavity_mass_totals_impl(nx, ny, nghost, dt_over_rho0, active, & wet_mask, cover_frac, melt, areaT, & vol_melt, area_open) !! The two INTERIOR integrals the mass budget and the compensation !! sink need, reduced on device in one pass: !! !! `vol_melt` — the meltwater volume (m^3) added this step, !! `sum(melt*dt/rho_0 * areaT)` over active columns; !! `area_open` — the wet area (m^2) the ice does NOT cover. !! !! GHOSTS ARE EXCLUDED (`nghost+1 .. n-nghost`), exactly as !! `ocean_accumulate_mass_out` excludes them: the console's totals !! are interior integrals, so a source term that counted the halo !! would be measuring a different domain than the total it has to !! close. The per-cell APPLY still runs over the whole array, like !! every other surface kernel — the halo exchange owns the ghosts. !! !! `melt*dt_over_rho0` is formed with the same scalar and in the !! same order as the apply kernel's `dh`, so the two agree to the !! last bit per cell and the residual is reduction round-off only. integer, intent(in) :: nx !! First dimension (ghosts included). integer, intent(in) :: ny !! Second dimension. integer, intent(in) :: nghost !! Halo width to exclude on every side. real(wp), intent(in) :: dt_over_rho0 !! `dt/rho_0`. real(wp), intent(in) :: active(nx, ny) !! Composed solve mask. real(wp), intent(in) :: wet_mask(nx, ny) !! Static wet (1) / land (0) mask. real(wp), intent(in) :: cover_frac(nx, ny) !! Ice-cover fraction (v1 binary). real(wp), intent(in) :: melt(nx, ny) !! Melt mass flux (kg/m^2/s). real(wp), intent(in) :: areaT(nx, ny) !! Cell area (m^2). real(wp), intent(out) :: vol_melt !! Meltwater volume this step (m^3). real(wp), intent(out) :: area_open !! Uncovered wet area (m^2). integer :: i, j, i_lo, i_hi, j_lo, j_hi real(wp) :: acc_v, acc_a i_lo = nghost + 1 i_hi = nx - nghost j_lo = nghost + 1 j_hi = ny - nghost acc_v = 0.0_wp acc_a = 0.0_wp do concurrent(j=j_lo:j_hi, i=i_lo:i_hi) reduce(+:acc_v, acc_a) if (active(i, j) > 0.5_wp) then acc_v = acc_v + melt(i, j)*dt_over_rho0*areaT(i, j) end if if (wet_mask(i, j) > 0.5_wp .and. cover_frac(i, j) < 0.5_wp) then acc_a = acc_a + areaT(i, j) end if end do vol_melt = acc_v area_open = acc_a end subroutine cavity_mass_totals_impl