Neko 1.99.3
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
global_interpolation_comm.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2025, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
36 use num_types, only : rp
38 use stack, only : stack_i4_t
39 use, intrinsic :: iso_c_binding
40 use mpi_f08, only : mpi_test, mpi_status_ignore, mpi_status, &
41 mpi_request, mpi_isend, mpi_irecv, mpi_comm
42 !$ use omp_lib
43 implicit none
44 private
45
46
48 type, private :: glb_intrp_comm_mpi_t
50 type(mpi_status) :: status
52 type(mpi_request) :: request
55 logical :: flag
57 real(kind=rp), allocatable :: data(:)
59
61 type, public :: glb_intrp_comm_t
63 type(stack_i4_t), allocatable :: send_dof(:)
66 type(stack_i4_t), allocatable :: recv_dof(:)
68 integer :: pe_size
72 integer, allocatable :: send_pe(:)
74 integer, allocatable :: recv_pe(:)
76 type(glb_intrp_comm_mpi_t), allocatable :: send_buf(:)
78 type(glb_intrp_comm_mpi_t), allocatable :: recv_buf(:)
80 type(mpi_comm) :: comm
81 contains
82 procedure, pass(this) :: init => glb_intrp_comm_init
83 procedure, pass(this) :: free => glb_intrp_comm_free
84 procedure, pass(this) :: init_dofs => glb_intrp_comm_init_dofs
85 procedure, pass(this) :: free_dofs => glb_intrp_comm_free_dofs
86 procedure, pass(this) :: init_order => glb_intrp_comm_init_order
87 procedure, pass(this) :: free_order => glb_intrp_comm_free_order
88 procedure, pass(this) :: nbwait_no_op => glb_intrp_comm_nbwait_no_op
89 procedure, pass(this) :: sendrecv => glb_intrp_comm_sendrecv
90 end type glb_intrp_comm_t
91
92contains
93
95 subroutine glb_intrp_comm_init(this, send_pe, recv_pe, comm)
96 class(glb_intrp_comm_t), intent(inout) :: this
97 type(stack_i4_t), intent(inout) :: send_pe
98 type(stack_i4_t), intent(inout) :: recv_pe
99 type(mpi_comm), intent(inout), optional :: comm
100 integer, pointer :: sp(:), rp(:)
101 integer :: i
102 if (present(comm)) then
103 this%comm = comm
104 else
105 this%comm = neko_comm
106 end if
107
108 call this%init_order(send_pe, recv_pe)
109
110 allocate(this%send_buf(send_pe%size()))
111
112 sp => send_pe%array()
113 do i = 1, send_pe%size()
114 allocate(this%send_buf(i)%data(this%send_dof(sp(i))%size()))
115 end do
116
117 allocate(this%recv_buf(recv_pe%size()))
118
119 rp => recv_pe%array()
120 do i = 1, recv_pe%size()
121 allocate(this%recv_buf(i)%data(this%recv_dof(rp(i))%size()))
122 end do
123
124 end subroutine glb_intrp_comm_init
125
127 subroutine glb_intrp_comm_free(this)
128 class(glb_intrp_comm_t), intent(inout) :: this
129 integer :: i
130
131 if (allocated(this%send_buf)) then
132 do i = 1, size(this%send_buf)
133 if (allocated(this%send_buf(i)%data)) then
134 deallocate(this%send_buf(i)%data)
135 end if
136 end do
137 deallocate(this%send_buf)
138 end if
139
140 if (allocated(this%recv_buf)) then
141 do i = 1, size(this%recv_buf)
142 if (allocated(this%recv_buf(i)%data)) then
143 deallocate(this%recv_buf(i)%data)
144 end if
145 end do
146 deallocate(this%recv_buf)
147 end if
148
149 call this%free_order()
150 call this%free_dofs()
151
152 end subroutine glb_intrp_comm_free
153
154 !Initalize stacks for each rank of dof indices to send/recv
155 subroutine glb_intrp_comm_init_dofs(this, comm_size)
156 class(glb_intrp_comm_t), intent(inout) :: this
157 integer, optional, intent(in) :: comm_size
158 integer :: i
159
160 if (present(comm_size)) then
161 this%pe_size = comm_size
162 else
163 this%pe_size = pe_size
164 end if
165
166 call this%free_dofs()
167
168 allocate(this%send_dof(0:this%pe_size-1))
169 allocate(this%recv_dof(0:this%pe_size-1))
170
171 do i = 0, this%pe_size -1
172 call this%send_dof(i)%init()
173 call this%recv_dof(i)%init()
174 end do
175
176 end subroutine glb_intrp_comm_init_dofs
177
179 class(glb_intrp_comm_t), intent(inout) :: this
180 integer :: i
181
182 if (allocated(this%send_dof)) then
183 do i = 0, this%pe_size - 1
184 call this%send_dof(i)%free()
185 end do
186 deallocate(this%send_dof)
187 end if
188
189 if (allocated(this%recv_dof)) then
190 do i = 0, this%pe_size - 1
191 call this%recv_dof(i)%free()
192 end do
193 deallocate(this%recv_dof)
194 end if
195
196 end subroutine glb_intrp_comm_free_dofs
197
201 subroutine glb_intrp_comm_init_order(this, send_pe, recv_pe)
202 class(glb_intrp_comm_t), intent(inout) :: this
203 type(stack_i4_t), intent(inout) :: send_pe
204 type(stack_i4_t), intent(inout) :: recv_pe
205 integer, contiguous, pointer :: sp(:), rp(:)
206 integer :: i
207
208 allocate(this%send_pe(send_pe%size()))
209
210 sp => send_pe%array()
211 do i = 1, send_pe%size()
212 this%send_pe(i) = sp(i)
213 end do
214
215 allocate(this%recv_pe(recv_pe%size()))
216
217 rp => recv_pe%array()
218 do i = 1, recv_pe%size()
219 this%recv_pe(i) = rp(i)
220 end do
221
222 end subroutine glb_intrp_comm_init_order
223
225 class(glb_intrp_comm_t), intent(inout) :: this
226
227 if (allocated(this%send_pe)) then
228 deallocate(this%send_pe)
229 end if
230
231 if (allocated(this%recv_pe)) then
232 deallocate(this%recv_pe)
233 end if
234
235 end subroutine glb_intrp_comm_free_order
236
238 subroutine glb_intrp_comm_sendrecv(this, send, recv, n_send, n_recv)
239 class(glb_intrp_comm_t), intent(inout) :: this
240 integer, intent(in) :: n_send, n_recv
241 real(kind=rp), dimension(n_send), intent(inout) :: send
242 real(kind=rp), dimension(n_recv), intent(inout) :: recv
243 integer :: i, j, ierr, src, dst, thrdid
244 integer, pointer :: sp(:)
245 integer :: nreqs
246
247 thrdid = 0
248 !$ thrdid = omp_get_thread_num()
249
250 !
251 ! Issue non-blocking receives
252 !
253 do i = 1, size(this%recv_pe)
254 ! We should not need this extra associate block, ant it works
255 ! great without it for GNU, Intel, NEC and Cray, but throws an
256 ! ICE with NAG.
257 ! Issue recv requests, we will later check that these have finished
258 ! in nbwait
259 associate(recv_data => this%recv_buf(i)%data)
260 call mpi_irecv(recv_data, size(recv_data), &
261 mpi_real_precision, this%recv_pe(i), thrdid, &
262 this%comm, this%recv_buf(i)%request, ierr)
263 end associate
264 this%recv_buf(i)%flag = .false.
265 end do
266
267 !
268 ! Issue non-blocking sends
269 !
270 do i = 1, size(this%send_pe)
271 dst = this%send_pe(i)
272 ! Gather data from u into buffers according to indices in send_dof
273 ! We want to send contigous data to each process in send_pe
274 sp => this%send_dof(dst)%array()
275 do concurrent(j = 1:this%send_dof(dst)%size())
276 this%send_buf(i)%data(j) = send(sp(j))
277 end do
278 ! We should not need this extra associate block, ant it works
279 ! great without it for GNU, Intel, NEC and Cray, but throws an
280 ! ICE with NAG.
281 associate(send_data => this%send_buf(i)%data)
282 call mpi_isend(send_data, this%send_dof(dst)%size(), &
283 mpi_real_precision, this%send_pe(i), thrdid, &
284 this%comm, this%send_buf(i)%request, ierr)
285 end associate
286 this%send_buf(i)%flag = .false.
287 end do
288
289 !
290 ! Wait for non-blocking operations
291 !
292
293 nreqs = size(this%recv_pe)
294
295 do while (nreqs .gt. 0)
296 do i = 1, size(this%recv_pe)
297 if (.not. this%recv_buf(i)%flag) then
298 ! Check if we have recieved the data we want
299 call mpi_test(this%recv_buf(i)%request, this%recv_buf(i)%flag, &
300 this%recv_buf(i)%status, ierr)
301 ! If it has been received
302 if (this%recv_buf(i)%flag) then
303 ! One more request has been succesful
304 nreqs = nreqs - 1
306 src = this%recv_pe(i)
307 sp => this%recv_dof(src)%array()
308 !NEC$ IVDEP
309 do concurrent(j = 1:this%recv_dof(src)%size())
310 recv(sp(j)) = this%recv_buf(i)%data(j)
311 end do
312 end if
313 end if
314 end do
315 end do
316 ! Finally, check that the non-blocking sends this rank have issued have also
317 ! completed successfully
318
319 nreqs = size(this%send_pe)
320 do while (nreqs .gt. 0)
321 do i = 1, size(this%send_pe)
322 if (.not. this%send_buf(i)%flag) then
323 call mpi_test(this%send_buf(i)%request, this%send_buf(i)%flag, &
324 mpi_status_ignore, ierr)
325 if (this%send_buf(i)%flag) nreqs = nreqs - 1
326 end if
327 end do
328 end do
329
330 end subroutine glb_intrp_comm_sendrecv
331
334 class(glb_intrp_comm_t), intent(inout) :: this
335 integer :: i, ierr
336 integer :: nreqs
337
338 nreqs = size(this%recv_pe)
339
340 do while (nreqs .gt. 0)
341 do i = 1, size(this%recv_pe)
342 if (.not. this%recv_buf(i)%flag) then
343 ! Check if we have recieved the data we want
344 call mpi_test(this%recv_buf(i)%request, this%recv_buf(i)%flag, &
345 this%recv_buf(i)%status, ierr)
346 ! If it has been received
347 if (this%recv_buf(i)%flag) then
348 ! One more request has been succesful
349 nreqs = nreqs - 1
350 end if
351 end if
352 end do
353 end do
354 ! Finally, check that the non-blocking sends this rank have issued have also
355 ! completed successfully
356
357 nreqs = size(this%send_pe)
358 do while (nreqs .gt. 0)
359 do i = 1, size(this%send_pe)
360 if (.not. this%send_buf(i)%flag) then
361 call mpi_test(this%send_buf(i)%request, this%send_buf(i)%flag, &
362 mpi_status_ignore, ierr)
363 if (this%send_buf(i)%flag) nreqs = nreqs - 1
364 end if
365 end do
366 end do
367
368 end subroutine glb_intrp_comm_nbwait_no_op
369
370
371end module glb_intrp_comm
Definition comm.F90:1
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
Definition comm.F90:51
integer, public pe_size
MPI size of communicator.
Definition comm.F90:59
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:43
Defines global interpolation communication Based on the MPI based gather-scatter kernel.
subroutine glb_intrp_comm_init_dofs(this, comm_size)
subroutine glb_intrp_comm_free(this)
Deallocate MPI based communication method.
subroutine glb_intrp_comm_sendrecv(this, send, recv, n_send, n_recv)
Non-blocking sendrecv.
subroutine glb_intrp_comm_nbwait_no_op(this)
Wait for non-blocking operations.
subroutine glb_intrp_comm_init(this, send_pe, recv_pe, comm)
Initialise MPI based communication method.
subroutine glb_intrp_comm_free_order(this)
subroutine glb_intrp_comm_free_dofs(this)
subroutine glb_intrp_comm_init_order(this, send_pe, recv_pe)
Obtains which ranks to send and receive data from.
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Implements a dynamic stack ADT.
Definition stack.f90:35
MPI buffer for non-blocking operations.
Global interpolation communication method.
Integer based stack.
Definition stack.f90:63