Flat do concurrent kernel behind ocean_surface_stress_apply_cover
— explicit-shape dummies, integer dims first (decl-order, ifx
THIS IS top_drag_fill_face_cover_impl‘S RULE, APPLIED IN PLACE.
The face projection is stated once, in rdb_ocean_top_drag’s
module docstring (§ The FACE cover rule), and there are two
implementations of it only because one fills face ARRAYS the drag
kernel reads per step and the other multiplies tau in place at
configure — materialising two more face arrays here, in a slot
that exists whether or not there is a cavity, to then throw them
away, is the worse trade. They are kept identical by a TEST
(cavity_cover_face_rule_matches_top_drag), which is the same
way mirror_of_bottom_drag keeps the top and bottom drag one
closure rather than two. Both halves of the rule matter:
max(cover(i-1,j), cover(i,j)),
so the CALVING-FRONT face is closed to the wind exactly where
it is opened to the drag;i = 1, i = nx+1, j = 1, j = ny+1) are left
UNTOUCHED, because they have only one neighbour in range.
Inventing a one-sided cover there would (a) disagree with the
drag’s cover_u = 0 and (b) clobber a periodic tau ghost
that the halo seam had already wrapped — this routine runs
AFTER ocean_seam_refresh_surface_stress. Those faces carry
no prognostic velocity, so leaving them alone is not an
approximation.| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | tau_x(nx+1,ny) | |||
| real(kind=wp), | intent(inout) | :: | tau_y(nx,ny+1) | |||
| real(kind=wp), | intent(in) | :: | cover_frac(nx,ny) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | cov | ||||
| integer, | private | :: | i | ||||
| integer, | private | :: | j |
pure subroutine ocean_surfstress_cover_impl(tau_x, tau_y, cover_frac, nx, ny) !! Flat `do concurrent` kernel behind `ocean_surface_stress_apply_cover` !! — explicit-shape dummies, integer dims first (decl-order, ifx !! #8586). !! !! THIS IS `top_drag_fill_face_cover_impl`'S RULE, APPLIED IN PLACE. !! The face projection is stated once, in `rdb_ocean_top_drag`'s !! module docstring (§ The FACE cover rule), and there are two !! implementations of it only because one fills face ARRAYS the drag !! kernel reads per step and the other multiplies `tau` in place at !! configure — materialising two more face arrays here, in a slot !! that exists whether or not there is a cavity, to then throw them !! away, is the worse trade. They are kept identical by a TEST !! (`cavity_cover_face_rule_matches_top_drag`), which is the same !! way `mirror_of_bottom_drag` keeps the top and bottom drag one !! closure rather than two. Both halves of the rule matter: !! !! * interior faces take the OR, `max(cover(i-1,j), cover(i,j))`, !! so the CALVING-FRONT face is closed to the wind exactly where !! it is opened to the drag; !! * RIM faces (`i = 1`, `i = nx+1`, `j = 1`, `j = ny+1`) are left !! UNTOUCHED, because they have only one neighbour in range. !! Inventing a one-sided cover there would (a) disagree with the !! drag's `cover_u = 0` and (b) clobber a periodic `tau` ghost !! that the halo seam had already wrapped — this routine runs !! AFTER `ocean_seam_refresh_surface_stress`. Those faces carry !! no prognostic velocity, so leaving them alone is not an !! approximation. integer, intent(in) :: nx, ny real(wp), intent(inout) :: tau_x(nx + 1, ny), tau_y(nx, ny + 1) real(wp), intent(in) :: cover_frac(nx, ny) integer :: i, j real(wp) :: cov do concurrent(j=1:ny, i=2:nx) local(cov) cov = max(cover_frac(i - 1, j), cover_frac(i, j)) tau_x(i, j) = tau_x(i, j)*(1.0_wp - cov) end do do concurrent(j=2:ny, i=1:nx) local(cov) cov = max(cover_frac(i, j - 1), cover_frac(i, j)) tau_y(i, j) = tau_y(i, j)*(1.0_wp - cov) end do end subroutine ocean_surfstress_cover_impl