Pre-size the pack/recv buffers to the worst-case capacity for this run at init time, so that NO device reallocation fires mid-run.
Worst-case capacity derivation:
E/W buffers: (a) 2D face-x send-east: (ng+1)nyt (standard init) (b) batched 3D face-x: (ng+1)nytnz (ensure_nz path) (c) wide 2D face-x: (ng_wide+1)(ny_local+2*ng_wide) (ensure_wide path) worst = max(a, b, c)
N/S buffers: symmetric (transpose x↔y).
Call AFTER ocean_halo_init; calling before init is a programming error (error stop with a clear message). Passing nz = 0 or ng_wide = 0 means “not used” — those arms are skipped. If the computed capacity is already covered by the current allocation, this is a no-op.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz |
Layer count for 3D batched exchanges (0 = not used) |
||
| integer, | intent(in) | :: | ng_wide |
Wide-ghost width for the barotropic march-in (0 = not used) |
||
| integer, | intent(out), | optional | :: | ierr |
Non-zero ( |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | need_ew | ||||
| integer, | private | :: | need_ns | ||||
| integer, | private | :: | ng | ||||
| integer, | private | :: | nxl | ||||
| integer, | private | :: | nxt | ||||
| integer, | private | :: | nyl | ||||
| integer, | private | :: | nyt | ||||
| integer, | private | :: | w_ew | ||||
| integer, | private | :: | w_ns |
subroutine ocean_halo_reserve(nz, ng_wide, ierr) !! Pre-size the pack/recv buffers to the worst-case capacity for this !! run at init time, so that NO device reallocation fires mid-run. !! !! Worst-case capacity derivation: !! !! E/W buffers: !! (a) 2D face-x send-east: (ng+1)*nyt (standard init) !! (b) batched 3D face-x: (ng+1)*nyt*nz (ensure_nz path) !! (c) wide 2D face-x: (ng_wide+1)*(ny_local+2*ng_wide) (ensure_wide path) !! worst = max(a, b, c) !! !! N/S buffers: symmetric (transpose x↔y). !! !! Call AFTER ocean_halo_init; calling before init is a programming error !! (error stop with a clear message). Passing nz = 0 or ng_wide = 0 !! means "not used" — those arms are skipped. If the computed capacity !! is already covered by the current allocation, this is a no-op. integer, intent(in) :: nz !! Layer count for 3D batched exchanges (0 = not used) integer, intent(in) :: ng_wide !! Wide-ghost width for the barotropic march-in (0 = not used) integer, intent(out), optional :: ierr !! Non-zero (`OCEAN_STATUS_ERR_SETUP`) when called before !! `ocean_halo_init` when present; absent behaves as today !! (`error stop`). (F5 residual, P2.4) integer :: need_ew, need_ns integer :: w_ew, w_ns integer :: ng, nyt, nxt, nyl, nxl if (present(ierr)) ierr = OCEAN_STATUS_OK if (.not. oh_initialised) then call fail("ocean_halo_reserve: called before ocean_halo_init. "// & "Call ocean_halo_reserve immediately after ocean_halo_init.", & ierr, OCEAN_STATUS_ERR_SETUP) return end if ng = oh_nghost nyt = oh_ny_total nxt = oh_nx_total nyl = oh_ny_local nxl = oh_nx_local ! (a) 2D base capacity (already set by init, replicated here for clarity) need_ew = (ng + 1)*nyt need_ns = (ng + 1)*nxt ! (b) 3D batched capacity if (nz > 0) then need_ew = max(need_ew, (ng + 1)*nyt*nz) need_ns = max(need_ns, (ng + 1)*nxt*nz) end if ! (c) Wide-ghost 2D capacity if (ng_wide > 0) then w_ew = (ng_wide + 1)*(nyl + 2*ng_wide) w_ns = (ng_wide + 1)*(nxl + 2*ng_wide) need_ew = max(need_ew, w_ew) need_ns = max(need_ns, w_ns) end if if (need_ew <= oh_cap_ew .and. need_ns <= oh_cap_ns) return ! Grow E/W if needed (exit-delete / dealloc / alloc / enter-create) if (need_ew > oh_cap_ew) then !$acc exit data delete(oh_buf_send_east, oh_buf_recv_east, & !$acc& oh_buf_send_west, oh_buf_recv_west) deallocate (oh_buf_send_east, oh_buf_recv_east) deallocate (oh_buf_send_west, oh_buf_recv_west) allocate (oh_buf_send_east(need_ew), oh_buf_recv_east(need_ew)) allocate (oh_buf_send_west(need_ew), oh_buf_recv_west(need_ew)) !$acc enter data create(oh_buf_send_east, oh_buf_recv_east, & !$acc& oh_buf_send_west, oh_buf_recv_west) oh_cap_ew = need_ew end if ! Grow N/S if needed if (need_ns > oh_cap_ns) then !$acc exit data delete(oh_buf_send_north, oh_buf_recv_north, & !$acc& oh_buf_send_south, oh_buf_recv_south) deallocate (oh_buf_send_north, oh_buf_recv_north) deallocate (oh_buf_send_south, oh_buf_recv_south) allocate (oh_buf_send_north(need_ns), oh_buf_recv_north(need_ns)) allocate (oh_buf_send_south(need_ns), oh_buf_recv_south(need_ns)) !$acc enter data create(oh_buf_send_north, oh_buf_recv_north, & !$acc& oh_buf_send_south, oh_buf_recv_south) oh_cap_ns = need_ns end if end subroutine ocean_halo_reserve