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(:)
99 integer :: i, nsend, nrecv, send_total, recv_total, ierr
103 integer,
allocatable :: src_weights(:), dst_weights(:)
105 call this%init_order(send_pe, recv_pe)
107 nsend =
size(this%send_pe)
108 nrecv =
size(this%recv_pe)
113 allocate(this%sendcounts(
max(1, nsend)), this%sdispls(
max(1, nsend)))
114 allocate(this%recvcounts(
max(1, nrecv)), this%rdispls(
max(1, nrecv)))
122 this%sendcounts(i) = this%send_dof(this%send_pe(i))%size()
123 this%sdispls(i) = send_total
124 send_total = send_total + this%sendcounts(i)
126 allocate(this%send_buf(
max(1, send_total)))
130 this%recvcounts(i) = this%recv_dof(this%recv_pe(i))%size()
131 this%rdispls(i) = recv_total
132 recv_total = recv_total + this%recvcounts(i)
134 allocate(this%recv_buf(
max(1, recv_total)))
136 this%vec_supported = .true.
137 this%vec_ready = .false.
144 allocate(src_weights(
max(1, nrecv)), dst_weights(
max(1, nsend)))
147 call mpi_dist_graph_create_adjacent(
neko_comm, &
148 nrecv, this%recv_pe, src_weights, &
149 nsend, this%send_pe, dst_weights, &
150 mpi_info_null, .false., this%neigh_comm, ierr)
151 deallocate(src_weights, dst_weights)
162 integer :: nsend, nrecv, send_total, recv_total
164 nsend =
size(this%send_pe)
165 nrecv =
size(this%recv_pe)
166 send_total = sum(this%sendcounts)
167 recv_total = sum(this%recvcounts)
171 allocate(this%sendcounts_v(
max(1, nsend)), this%sdispls_v(
max(1, nsend)))
172 allocate(this%recvcounts_v(
max(1, nrecv)), this%rdispls_v(
max(1, nrecv)))
173 this%sendcounts_v = 0
175 this%recvcounts_v = 0
185 if (
allocated(this%send_buf))
deallocate(this%send_buf)
186 if (
allocated(this%recv_buf))
deallocate(this%recv_buf)
187 if (
allocated(this%sendcounts))
deallocate(this%sendcounts)
188 if (
allocated(this%sdispls))
deallocate(this%sdispls)
189 if (
allocated(this%recvcounts))
deallocate(this%recvcounts)
190 if (
allocated(this%rdispls))
deallocate(this%rdispls)
192 if (
allocated(this%send_buf_v))
deallocate(this%send_buf_v)
193 if (
allocated(this%recv_buf_v))
deallocate(this%recv_buf_v)
194 if (
allocated(this%sendcounts_v))
deallocate(this%sendcounts_v)
195 if (
allocated(this%sdispls_v))
deallocate(this%sdispls_v)
196 if (
allocated(this%recvcounts_v))
deallocate(this%recvcounts_v)
197 if (
allocated(this%rdispls_v))
deallocate(this%rdispls_v)
198 this%vec_ready = .false.
200 call mpi_comm_free(this%neigh_comm, ierr)
202 call this%free_order()
203 call this%free_dofs()
212 integer,
intent(in) :: n
213 real(kind=
rp),
dimension(n),
intent(inout) :: u
214 integer,
intent(in) :: tag
215 type(c_ptr),
intent(inout) :: deps
216 type(c_ptr),
intent(inout) :: strm
217 integer :: i, j, dst, off, ndst, ierr
224 do i = 1,
size(this%send_pe)
225 dst = this%send_pe(i)
226 off = this%sdispls(i)
227 ndst = this%sendcounts(i)
228 select type (dofs => this%send_dof(dst)%data)
232 this%send_buf(off + j) = u(dofs(j))
241 call mpi_ineighbor_alltoallv(this%send_buf, this%sendcounts, &
253 integer,
intent(in) :: tag
260 integer,
intent(in) :: n
261 real(kind=
rp),
dimension(n),
intent(inout) :: u
262 type(c_ptr),
intent(inout) :: strm
263 integer :: i, j, src, off, nsrc
270 call mpi_wait(this%request, mpi_status_ignore, ierr)
278 do i = 1,
size(this%recv_pe)
279 src = this%recv_pe(i)
280 off = this%rdispls(i)
281 nsrc = this%recvcounts(i)
282 select type (dofs => this%recv_dof(src)%data)
293 u(dofs(j)) = u(dofs(j)) + this%recv_buf(off + j)
304 u(dofs(j)) = u(dofs(j)) * this%recv_buf(off + j)
315 u(dofs(j)) = min(u(dofs(j)), this%recv_buf(off + j))
326 u(dofs(j)) =
max(u(dofs(j)), this%recv_buf(off + j))
330 call neko_error(
"Unknown operation in gs_nbwait_neighbour")
343 integer,
intent(in) :: n, nc
344 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
345 integer,
intent(in) :: tag
346 type(c_ptr),
intent(inout) :: deps
347 type(c_ptr),
intent(inout) :: strm
348 integer :: i, j, c, dst, off, ndst, ierr
351 do i = 1,
size(this%send_pe)
352 dst = this%send_pe(i)
353 off = this%sdispls(i)
354 ndst = this%sendcounts(i)
355 select type (dofs => this%send_dof(dst)%data)
360 this%send_buf_v(nc*off + (c-1)*ndst + j) = u((c-1)*n + dofs(j))
371 do i = 1,
size(this%send_pe)
372 this%sendcounts_v(i) = nc * this%sendcounts(i)
373 this%sdispls_v(i) = nc * this%sdispls(i)
375 do i = 1,
size(this%recv_pe)
376 this%recvcounts_v(i) = nc * this%recvcounts(i)
377 this%rdispls_v(i) = nc * this%rdispls(i)
379 call mpi_ineighbor_alltoallv(this%send_buf_v, this%sendcounts_v, &
382 this%neigh_comm, this%request, ierr)
390 integer,
intent(in) :: tag, nc
399 integer,
intent(in) :: n, nc
400 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
401 type(c_ptr),
intent(inout) :: strm
402 integer :: i, j, c, src, off, nsrc, ierr
406 call mpi_wait(this%request, mpi_status_ignore, ierr)
412 do i = 1,
size(this%recv_pe)
413 src = this%recv_pe(i)
414 off = this%rdispls(i)
415 nsrc = this%recvcounts(i)
416 select type (dofs => this%recv_dof(src)%data)
423 u((c-1)*n + dofs(j)) = u((c-1)*n + dofs(j)) + &
424 this%recv_buf_v(nc*off + (c-1)*nsrc + j)
432 u((c-1)*n + dofs(j)) = u((c-1)*n + dofs(j)) * &
433 this%recv_buf_v(nc*off + (c-1)*nsrc + j)
441 u((c-1)*n + dofs(j)) = min(u((c-1)*n + dofs(j)), &
442 this%recv_buf_v(nc*off + (c-1)*nsrc + j))
450 u((c-1)*n + dofs(j)) =
max(u((c-1)*n + dofs(j)), &
451 this%recv_buf_v(nc*off + (c-1)*nsrc + j))
456 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_init_vec(this)
Allocate the fused vector exchange buffers and the nc-scaled collective descriptors,...
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...