Ocean staggered halo exchange — the ONLY backend.
At px==1 / py==1 the X / Y pass never enters a collective: it either
applies ocean_periodic_wrap_* locally or does nothing. That is
what lets this module compile and run against pic-mpi’s serial
backend, which error stops on point-to-point calls by design.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private, | parameter | :: | MAX_REQS | = | 8 |
Upper bound on requests per exchange (2 per active direction x 2 axes) |
| integer, | private, | parameter | :: | TAG_OC_E_TO_W | = | 12 |
Westward send (filled into east-recv on peer) |
| integer, | private, | parameter | :: | TAG_OC_N_TO_S | = | 14 |
Southward send |
| integer, | private, | parameter | :: | TAG_OC_S_TO_N | = | 13 |
Northward send |
| integer, | private, | parameter | :: | TAG_OC_W_TO_E | = | 11 |
Eastward send (filled into west-recv on peer) |
| real(kind=wp), | private, | allocatable | :: | oh_buf_recv_east(:) |
Data sent/received to/from the east neighbour (capacity = (ng+1)*ny_total) |
||
| real(kind=wp), | private, | allocatable | :: | oh_buf_recv_north(:) |
Data sent/received to/from the north neighbour (capacity = (ng+1)*nx_total) |
||
| real(kind=wp), | private, | allocatable | :: | oh_buf_recv_south(:) |
Data sent/received to/from the south neighbour (capacity = (ng+1)*nx_total) |
||
| real(kind=wp), | private, | allocatable | :: | oh_buf_recv_west(:) |
Data sent/received to/from the west neighbour (capacity = (ng+1)*ny_total) |
||
| real(kind=wp), | private, | allocatable | :: | oh_buf_send_east(:) |
Data sent/received to/from the east neighbour (capacity = (ng+1)*ny_total) |
||
| real(kind=wp), | private, | allocatable | :: | oh_buf_send_north(:) |
Data sent/received to/from the north neighbour (capacity = (ng+1)*nx_total) |
||
| real(kind=wp), | private, | allocatable | :: | oh_buf_send_south(:) |
Data sent/received to/from the south neighbour (capacity = (ng+1)*nx_total) |
||
| real(kind=wp), | private, | allocatable | :: | oh_buf_send_west(:) |
Data sent/received to/from the west neighbour (capacity = (ng+1)*ny_total) |
||
| integer, | private | :: | oh_cap_ew | = | 0 |
Allocated capacity for E/W buffers |
|
| integer, | private | :: | oh_cap_ns | = | 0 |
Allocated capacity for N/S buffers |
|
| type(decomp_t), | private | :: | oh_decomp |
Copy of domain decomposition |
|||
| logical, | private | :: | oh_initialised | = | .false. |
True after ocean_halo_init |
|
| integer, | private | :: | oh_nghost | = | 0 |
Ghost cell width |
|
| integer, | private | :: | oh_nx_local | = | 0 |
Physical cells in x on this subdomain |
|
| integer, | private | :: | oh_nx_total | = | 0 |
nx_local + 2*nghost |
|
| integer, | private | :: | oh_ny_local | = | 0 |
Physical cells in y on this subdomain |
|
| integer, | private | :: | oh_ny_total | = | 0 |
ny_local + 2*nghost |
|
| logical, | private | :: | oh_periodic_x | = | .false. |
x axis is reentrant periodic |
|
| logical, | private | :: | oh_periodic_y | = | .false. |
y axis is reentrant periodic |
Two-pass X-then-Y halo exchange for a cell-centred 2D field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total) |
Cell-centred 2D field (nx_total, ny_total) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a cell-centred 3D field. Batched: packs ALL nz layers into one buffer per direction and posts ONE isend+irecv pair per needed direction (not per layer). Buffer index formula: ((L-1)rows + (row-1))width + k_within_strip where L=layer, rows=nyt, width=ng (centre X-pass).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total,nz) |
Cell-centred 3D field (nx_total, ny_total, nz) |
||
| integer, | intent(in) | :: | nz |
Number of vertical layers |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 2D x-face field.
Index map (ng=nghost, nxl=nx_local): Send EAST (ng+1 per j-row): source i = nxl+1..ng+nxl+1 (last i = ng+nxl+1 is owned seam face; first ng are pre-seam interior) → fills east-nbr’s i = 1..ng+1 (west ghosts + seam-copy overwrite)
Recv FROM EAST (ng per j-row): east-nbr sends its i = ng+2..2*ng+1 → fills OUR east ghosts i = ng+nxl+2..ng+nxl+ng+1
Send WEST (ng per j-row): source i = ng+2..2*ng+1 → fills west-nbr’s east ghosts
Recv FROM WEST (ng+1 per j-row): west-nbr sends its owned seam + ng interior → fills OUR i = 1..ng+1
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total+1,oh_ny_total) |
x-face field (nx_total+1, ny_total) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 3D x-face field. Batched: packs ALL nz layers into one buffer per direction. Face-x ownership: west rank sends (ng+1)nytnz eastward, east rank sends ngnytnz westward (D1 asymmetry preserved). Y-pass strip is nxt1ngnz (full face-x i extent × ng rows × nz).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total+1,oh_ny_total,nz) |
x-face field (nx_total+1, ny_total, nz) |
||
| integer, | intent(in) | :: | nz |
Number of vertical layers |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 2D y-face field. Symmetric to face_x_2d with i↔j, x↔y.
Index map (ng=nghost, nyl=ny_local): Send NORTH (ng+1 per i-col): source j = nyl+1..ng+nyl+1 (last j = ng+nyl+1 is owned seam face; my j == north-nbr’s j_N + nyl) → fills north-nbr’s j = 1..ng+1 (south ghosts + seam-copy)
Recv FROM NORTH (ng per i-col): north-nbr sends j = ng+2..2*ng+1 → fills OUR north ghosts j = ng+nyl+2..ng+nyl+ng+1
Send SOUTH (ng per i-col): source j = ng+2..2*ng+1 Recv FROM SOUTH (ng+1 per i-col): fills OUR j = 1..ng+1
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total+1) |
y-face field (nx_total, ny_total+1) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 3D y-face field. Batched: packs ALL nz layers into one buffer per direction. Face-y ownership (D1): south rank sends (ng+1)nxtnz northward, north rank sends ngnxtnz southward. X-pass uses standard centre-style (ng per column per layer over nyt1 rows).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total+1,nz) |
y-face field (nx_total, ny_total+1, nz) |
||
| integer, | intent(in) | :: | nz |
Number of vertical layers |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
True iff a genuine multi-rank seam exists (initialised, px>1 or py>1).
True iff the X axis is split across ranks (px>1); skip the local x wrap.
Y analogue of ocean_halo_is_decomposed_x (py>1).
True if ocean_halo_init has been called and not yet destroyed.
East neighbour rank with periodic wrap-around.
West neighbour rank with periodic wrap-around.
North neighbour rank with periodic wrap-around.
South neighbour rank with periodic wrap-around.
Single-call two-pass exchange of three barotropic fields. Calls the three individual 2D exchanges in order, which each run their own full two-pass X-then-Y exchange.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | eta(oh_nx_total,oh_ny_total) |
Barotropic sea-surface height (nx_total x ny_total) |
||
| real(kind=wp), | intent(inout) | :: | ubt(oh_nx_total+1,oh_ny_total) |
Barotropic u-transport (nx_total+1 x ny_total) |
||
| real(kind=wp), | intent(inout) | :: | vbt(oh_nx_total,oh_ny_total+1) |
Barotropic v-transport (nx_total x ny_total+1) |
||
| logical, | intent(in), | optional | :: | device_resident |
Forwarded to the three individual exchanges. See centre_2d. |
Width-parameterized grouped barotropic exchange (eta+ubt+vbt). Bumps oh_count_bt_group; suppresses the three inner primitive counters exactly as ocean_halo_bt_group_2d does.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | eta(oh_nx_local+2*ng_wide,oh_ny_local+2*ng_wide) |
Barotropic SSH (nx_local+2ng_wide, ny_local+2ng_wide) |
||
| real(kind=wp), | intent(inout) | :: | ubt(oh_nx_local+2*ng_wide+1,oh_ny_local+2*ng_wide) |
Barotropic u-transport (nx_local+2ng_wide+1, ny_local+2ng_wide) |
||
| real(kind=wp), | intent(inout) | :: | vbt(oh_nx_local+2*ng_wide,oh_ny_local+2*ng_wide+1) |
Barotropic v-transport (nx_local+2ng_wide, ny_local+2ng_wide+1) |
||
| integer, | intent(in) | :: | ng_wide |
Wide ghost cell width (>= oh_nghost) |
||
| logical, | intent(in), | optional | :: | device_resident |
Forwarded to the three individual exchanges. See centre_2d. |
Width-parameterized centre-2D halo exchange. Identical algorithm to ocean_halo_centre_2d but operates on a wider ghost band ng_wide (>= oh_nghost). Fail-loud guards prevent ng_wide from exceeding the neighbour interior.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_local+2*ng_wide,oh_ny_local+2*ng_wide) |
Cell-centred 2D field (nx_local + 2ng_wide, ny_local + 2ng_wide) |
||
| integer, | intent(in) | :: | ng_wide |
Wide ghost cell width (>= oh_nghost) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory. Default = .true. |
Release buffers and topology state. Idempotent.
Width-parameterized face-x-2D halo exchange.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_local+2*ng_wide+1,oh_ny_local+2*ng_wide) |
x-face 2D field (nx_local + 2ng_wide + 1, ny_local + 2ng_wide) |
||
| integer, | intent(in) | :: | ng_wide |
Wide ghost cell width (>= oh_nghost) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory. Default = .true. |
Width-parameterized face-y-2D halo exchange.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_local+2*ng_wide,oh_ny_local+2*ng_wide+1) |
y-face 2D field (nx_local + 2ng_wide, ny_local + 2ng_wide + 1) |
||
| integer, | intent(in) | :: | ng_wide |
Wide ghost cell width (>= oh_nghost) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory. Default = .true. |
Initialise topology and allocate persistent device-resident buffers. Idempotent: destroys prior state before re-init on grid change.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(decomp_t), | intent(in) | :: | decomp |
Domain decomposition descriptor |
||
| integer, | intent(in) | :: | nghost |
Ghost cell width |
||
| logical, | intent(in) | :: | periodic_x |
Reentrant periodic in x |
||
| logical, | intent(in) | :: | periodic_y |
Reentrant periodic in y |
||
| integer, | intent(out), | optional | :: | ierr |
Non-zero ( |
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.
| 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 ( |
Compute which directions need actual MPI or local-wrap work.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| logical, | intent(out) | :: | need_w | |||
| logical, | intent(out) | :: | need_e | |||
| logical, | intent(out) | :: | need_s | |||
| logical, | intent(out) | :: | need_n |
Grow the persistent send/recv buffers to hold at least nz layers. Called at the top of each 3D exchange routine before pack/unpack. The 2D routines use the same buffers and always need <= any 3D capacity, so they are unaffected.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nz |
Number of vertical layers required |
Grow the persistent send/recv buffers to hold at least a wide 2D exchange at ghost width ng_wide. Uses the same exit-delete / dealloc / alloc / enter-create pattern as ocean_halo_buffers_ensure_nz. Safe to call with ng_wide == oh_nghost (no-op if already large enough).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | ng_wide |
Wide ghost cell width required |
Two-pass X-then-Y halo exchange for a cell-centred 2D field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total) |
Cell-centred 2D field (nx_total, ny_total) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a cell-centred 2D field. Core body shared by ocean_halo_centre_2d (ng=oh_nghost) and ocean_halo_centre_2d_wide (ng=ng_wide).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_local+2*ng,oh_ny_local+2*ng) |
Cell-centred 2D field |
||
| integer, | intent(in) | :: | ng |
Ghost cell width for this exchange |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory. Default = .true. |
Two-pass X-then-Y halo exchange for a cell-centred 3D field. Batched: packs ALL nz layers into one buffer per direction and posts ONE isend+irecv pair per needed direction (not per layer). Buffer index formula: ((L-1)rows + (row-1))width + k_within_strip where L=layer, rows=nyt, width=ng (centre X-pass).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total,nz) |
Cell-centred 3D field (nx_total, ny_total, nz) |
||
| integer, | intent(in) | :: | nz |
Number of vertical layers |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 2D x-face field.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total+1,oh_ny_total) |
x-face field (nx_total+1, ny_total) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 2D x-face field. Core body shared by ocean_halo_face_x_2d (ng=oh_nghost) and ocean_halo_face_x_2d_wide (ng=ng_wide).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_local+2*ng+1,oh_ny_local+2*ng) |
x-face field (nx_local + 2ng + 1, ny_local + 2ng) |
||
| integer, | intent(in) | :: | ng |
Ghost cell width for this exchange |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory. Default = .true. |
Two-pass X-then-Y halo exchange for a 3D x-face field. Batched: packs ALL nz layers into one buffer per direction. Face-x ownership: west rank sends (ng+1)nytnz eastward, east rank sends ngnytnz westward (D1 asymmetry preserved). Y-pass strip is nxt1ngnz (full face-x i extent × ng rows × nz).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total+1,oh_ny_total,nz) |
x-face field (nx_total+1, ny_total, nz) |
||
| integer, | intent(in) | :: | nz |
Number of vertical layers |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 2D y-face field. Symmetric to face_x_2d with i↔j, x↔y.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total+1) |
y-face field (nx_total, ny_total+1) |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Two-pass X-then-Y halo exchange for a 2D y-face field. Core body shared by ocean_halo_face_y_2d (ng=oh_nghost) and ocean_halo_face_y_2d_wide (ng=ng_wide).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_local+2*ng,oh_ny_local+2*ng+1) |
y-face field (nx_local + 2ng, ny_local + 2ng + 1) |
||
| integer, | intent(in) | :: | ng |
Ghost cell width for this exchange |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory. Default = .true. |
Two-pass X-then-Y halo exchange for a 3D y-face field. Batched: packs ALL nz layers into one buffer per direction. Face-y ownership (D1): south rank sends (ng+1)nxtnz northward, north rank sends ngnxtnz southward. X-pass uses standard centre-style (ng per column per layer over nyt1 rows).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | fld(oh_nx_total,oh_ny_total+1,nz) |
y-face field (nx_total, ny_total+1, nz) |
||
| integer, | intent(in) | :: | nz |
Number of vertical layers |
||
| logical, | intent(in), | optional | :: | device_resident |
If .false., operate on host memory (no OpenACC directives). Default (.true.) is the normal device-resident path. |
Fail-loud validation for wide halo entry points. Called at the top of every *_wide public routine.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | ng_wide |
Requested wide ghost width |
||
| character(len=*), | intent(in) | :: | caller |
Caller name for error messages |