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)
273 u(dofs(j)) = u(dofs(j)) + this%recv_buf(off + j)
283 u(dofs(j)) = u(dofs(j)) * this%recv_buf(off + j)
293 u(dofs(j)) = min(u(dofs(j)), this%recv_buf(off + j))
303 u(dofs(j)) =
max(u(dofs(j)), this%recv_buf(off + j))
307 call neko_error(
"Unknown operation in gs_nbwait_neighbour")
320 integer,
intent(in) :: n, nc
321 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
322 integer,
intent(in) :: tag
323 type(c_ptr),
intent(inout) :: deps
324 type(c_ptr),
intent(inout) :: strm
325 integer :: i, j, c, dst, off, ndst, ierr
328 do i = 1,
size(this%send_pe)
329 dst = this%send_pe(i)
330 off = this%sdispls(i)
331 ndst = this%sendcounts(i)
332 select type (dofs => this%send_dof(dst)%data)
337 this%send_buf_v(nc*off + (c-1)*ndst + j) = u((c-1)*n + dofs(j))
348 do i = 1,
size(this%send_pe)
349 this%sendcounts_v(i) = nc * this%sendcounts(i)
350 this%sdispls_v(i) = nc * this%sdispls(i)
352 do i = 1,
size(this%recv_pe)
353 this%recvcounts_v(i) = nc * this%recvcounts(i)
354 this%rdispls_v(i) = nc * this%rdispls(i)
356 call mpi_ineighbor_alltoallv(this%send_buf_v, this%sendcounts_v, &
359 this%neigh_comm, this%request, ierr)
367 integer,
intent(in) :: tag, nc
376 integer,
intent(in) :: n, nc
377 real(kind=
rp),
dimension(nc*n),
intent(inout) :: u
378 type(c_ptr),
intent(inout) :: strm
379 integer :: i, j, c, src, off, nsrc, ierr
383 call mpi_wait(this%request, mpi_status_ignore, ierr)
389 do i = 1,
size(this%recv_pe)
390 src = this%recv_pe(i)
391 off = this%rdispls(i)
392 nsrc = this%recvcounts(i)
393 select type (dofs => this%recv_dof(src)%data)
400 u((c-1)*n + dofs(j)) = u((c-1)*n + dofs(j)) + &
401 this%recv_buf_v(nc*off + (c-1)*nsrc + j)
409 u((c-1)*n + dofs(j)) = u((c-1)*n + dofs(j)) * &
410 this%recv_buf_v(nc*off + (c-1)*nsrc + j)
418 u((c-1)*n + dofs(j)) = min(u((c-1)*n + dofs(j)), &
419 this%recv_buf_v(nc*off + (c-1)*nsrc + j))
427 u((c-1)*n + dofs(j)) =
max(u((c-1)*n + dofs(j)), &
428 this%recv_buf_v(nc*off + (c-1)*nsrc + j))
433 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...