39 use mpi_f08,
only : mpi_comm, mpi_request, mpi_status_ignore, &
40 mpi_info_null, mpi_dist_graph_create_adjacent, &
41 mpi_ineighbor_alltoallv, mpi_wait, mpi_comm_free
43 use,
intrinsic :: iso_c_binding
58 real(kind=
rp),
allocatable :: send_buf(:)
60 real(kind=
rp),
allocatable :: recv_buf(:)
64 integer,
allocatable :: sendcounts(:), sdispls(:)
65 integer,
allocatable :: recvcounts(:), rdispls(:)
67 type(mpi_comm) :: neigh_comm
69 type(mpi_request) :: request
74 real(kind=
rp),
allocatable :: send_buf_v(:)
75 real(kind=
rp),
allocatable :: recv_buf_v(:)
76 integer,
allocatable :: sendcounts_v(:), sdispls_v(:)
77 integer,
allocatable :: recvcounts_v(:), rdispls_v(:)
98 integer :: i, nsend, nrecv, send_total, recv_total, ierr
102 integer,
allocatable :: src_weights(:), dst_weights(:)
104 call this%init_order(send_pe, recv_pe)
106 nsend =
size(this%send_pe)
107 nrecv =
size(this%recv_pe)
112 allocate(this%sendcounts(
max(1, nsend)), this%sdispls(
max(1, nsend)))
113 allocate(this%recvcounts(
max(1, nrecv)), this%rdispls(
max(1, nrecv)))
121 this%sendcounts(i) = this%send_dof(this%send_pe(i))%size()
122 this%sdispls(i) = send_total
123 send_total = send_total + this%sendcounts(i)
125 allocate(this%send_buf(
max(1, send_total)))
129 this%recvcounts(i) = this%recv_dof(this%recv_pe(i))%size()
130 this%rdispls(i) = recv_total
131 recv_total = recv_total + this%recvcounts(i)
133 allocate(this%recv_buf(
max(1, recv_total)))
138 allocate(this%sendcounts_v(
max(1, nsend)), this%sdispls_v(
max(1, nsend)))
139 allocate(this%recvcounts_v(
max(1, nrecv)), this%rdispls_v(
max(1, nrecv)))
140 this%sendcounts_v = 0
142 this%recvcounts_v = 0
144 this%vec_supported = .true.
151 allocate(src_weights(
max(1, nrecv)), dst_weights(
max(1, nsend)))
154 call mpi_dist_graph_create_adjacent(
neko_comm, &
155 nrecv, this%recv_pe, src_weights, &
156 nsend, this%send_pe, dst_weights, &
157 mpi_info_null, .false., this%neigh_comm, ierr)
158 deallocate(src_weights, dst_weights)
167 if (
allocated(this%send_buf))
deallocate(this%send_buf)
168 if (
allocated(this%recv_buf))
deallocate(this%recv_buf)
169 if (
allocated(this%sendcounts))
deallocate(this%sendcounts)
170 if (
allocated(this%sdispls))
deallocate(this%sdispls)
171 if (
allocated(this%recvcounts))
deallocate(this%recvcounts)
172 if (
allocated(this%rdispls))
deallocate(this%rdispls)
174 if (
allocated(this%send_buf_v))
deallocate(this%send_buf_v)
175 if (
allocated(this%recv_buf_v))
deallocate(this%recv_buf_v)
176 if (
allocated(this%sendcounts_v))
deallocate(this%sendcounts_v)
177 if (
allocated(this%sdispls_v))
deallocate(this%sdispls_v)
178 if (
allocated(this%recvcounts_v))
deallocate(this%recvcounts_v)
179 if (
allocated(this%rdispls_v))
deallocate(this%rdispls_v)
181 call mpi_comm_free(this%neigh_comm, ierr)
183 call this%free_order()
184 call this%free_dofs()
193 integer,
intent(in) :: n
194 real(kind=
rp),
dimension(n),
intent(inout) :: u
195 integer,
intent(in) :: tag
196 type(c_ptr),
intent(inout) :: deps
197 type(c_ptr),
intent(inout) :: strm
198 integer :: i, j, dst, off, ndst, ierr
205 do i = 1,
size(this%send_pe)
206 dst = this%send_pe(i)
207 off = this%sdispls(i)
208 ndst = this%sendcounts(i)
209 select type (dofs => this%send_dof(dst)%data)
213 this%send_buf(off + j) = u(dofs(j))
222 call mpi_ineighbor_alltoallv(this%send_buf, this%sendcounts, &
234 integer,
intent(in) :: tag
241 integer,
intent(in) :: n
242 real(kind=
rp),
dimension(n),
intent(inout) :: u
243 type(c_ptr),
intent(inout) :: strm
244 integer :: i, j, src, off, nsrc
251 call mpi_wait(this%request, mpi_status_ignore, ierr)
259 do i = 1,
size(this%recv_pe)
260 src = this%recv_pe(i)
261 off = this%rdispls(i)
262 nsrc = this%recvcounts(i)
263 select type (dofs => this%recv_dof(src)%data)
274 u(dofs(j)) = u(dofs(j)) + this%recv_buf(off + j)
285 u(dofs(j)) = u(dofs(j)) * this%recv_buf(off + j)
296 u(dofs(j)) = min(u(dofs(j)), this%recv_buf(off + j))
307 u(dofs(j)) =
max(u(dofs(j)), this%recv_buf(off + j))
311 call neko_error(
"Unknown operation in gs_nbwait_neighbour")
324 integer,
intent(in) :: n, nc
325 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
326 integer,
intent(in) :: tag
327 type(c_ptr),
intent(inout) :: deps
328 type(c_ptr),
intent(inout) :: strm
329 integer :: i, j, c, dst, off, ndst, ierr
332 do i = 1,
size(this%send_pe)
333 dst = this%send_pe(i)
334 off = this%sdispls(i)
335 ndst = this%sendcounts(i)
336 select type (dofs => this%send_dof(dst)%data)
341 this%send_buf_v(nc*off + (c-1)*ndst + j) = u((c-1)*n + dofs(j))
352 do i = 1,
size(this%send_pe)
353 this%sendcounts_v(i) = nc * this%sendcounts(i)
354 this%sdispls_v(i) = nc * this%sdispls(i)
356 do i = 1,
size(this%recv_pe)
357 this%recvcounts_v(i) = nc * this%recvcounts(i)
358 this%rdispls_v(i) = nc * this%rdispls(i)
360 call mpi_ineighbor_alltoallv(this%send_buf_v, this%sendcounts_v, &
363 this%neigh_comm, this%request, ierr)
371 integer,
intent(in) :: tag, nc
380 integer,
intent(in) :: n, nc
381 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
382 type(c_ptr),
intent(inout) :: strm
383 integer :: i, j, c, src, off, nsrc, ierr
387 call mpi_wait(this%request, mpi_status_ignore, ierr)
393 do i = 1,
size(this%recv_pe)
394 src = this%recv_pe(i)
395 off = this%rdispls(i)
396 nsrc = this%recvcounts(i)
397 select type (dofs => this%recv_dof(src)%data)
404 u((c-1)*n + dofs(j)) = u((c-1)*n + dofs(j)) + &
405 this%recv_buf_v(nc*off + (c-1)*nsrc + j)
413 u((c-1)*n + dofs(j)) = u((c-1)*n + dofs(j)) * &
414 this%recv_buf_v(nc*off + (c-1)*nsrc + j)
422 u((c-1)*n + dofs(j)) = min(u((c-1)*n + dofs(j)), &
423 this%recv_buf_v(nc*off + (c-1)*nsrc + j))
431 u((c-1)*n + dofs(j)) =
max(u((c-1)*n + dofs(j)), &
432 this%recv_buf_v(nc*off + (c-1)*nsrc + j))
437 call neko_error(
"Unknown operation in gs_nbwait_vec_neighbour")
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
type(mpi_comm), public neko_comm
MPI communicator.
Defines a gather-scatter communication method.
integer, parameter, public gs_vec_nc
Maximum number of components handled by the fused vector (multi-component) halo exchange used by gs_o...
Defines gather-scatter communication using MPI neighbourhood collectives.
subroutine gs_nbwait_neighbour(this, u, n, op, strm)
Wait for the neighbourhood collective and reduce the received slabs.
subroutine gs_nbsend_vec_neighbour(this, u, n, nc, tag, deps, strm)
Pack the nc components and launch a single neighbourhood collective.
subroutine gs_nbwait_vec_neighbour(this, u, n, nc, op, strm)
Wait for the vector collective and reduce each received slab into u. Peer i's received slab holds nc ...
subroutine gs_nbrecv_neighbour(this, tag)
No-op: the neighbourhood collective issued in nbsend handles both the send and receive directions,...
subroutine gs_neighbour_free(this)
Deallocate the neighbourhood-collective communication method.
subroutine gs_neighbour_init(this, send_pe, recv_pe)
Initialise the neighbourhood-collective communication method See gs_comm.f90 for details.
subroutine gs_nbsend_neighbour(this, u, n, tag, deps, strm)
Pack the send buffer and initiate the neighbourhood collective. The collective covers both directions...
subroutine gs_nbrecv_vec_neighbour(this, tag, nc)
No-op: the collective is launched in nbsend_vec.
Defines Gather-scatter operations.
integer, parameter, public gs_op_add
integer, parameter, public gs_op_max
integer, parameter, public gs_op_min
integer, parameter, public gs_op_mul
integer, parameter, public rp
Global precision used in computations.
Implements a dynamic stack ADT.
Gather-scatter communication method.
Gather-scatter communication using an MPI neighbourhood collective. The whole halo exchange is carrie...