Neko 1.99.2
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 type(c_ptr) :: null_ptr = c_null_ptr
244 integer :: i, j, ierr, src, dst, thrdid
245 integer, pointer :: sp(:)
246 integer :: nreqs
247
248 thrdid = 0
249 !$ thrdid = omp_get_thread_num()
250
251 !
252 ! Issue non-blocking receives
253 !
254 do i = 1, size(this%recv_pe)
255 ! We should not need this extra associate block, ant it works
256 ! great without it for GNU, Intel, NEC and Cray, but throws an
257 ! ICE with NAG.
258 ! Issue recv requests, we will later check that these have finished
259 ! in nbwait
260 associate(recv_data => this%recv_buf(i)%data)
261 call mpi_irecv(recv_data, size(recv_data), &
262 mpi_real_precision, this%recv_pe(i), thrdid, &
263 this%comm, this%recv_buf(i)%request, ierr)
264 end associate
265 this%recv_buf(i)%flag = .false.
266 end do
267
268 !
269 ! Issue non-blocking sends
270 !
271 do i = 1, size(this%send_pe)
272 dst = this%send_pe(i)
273 ! Gather data from u into buffers according to indices in send_dof
274 ! We want to send contigous data to each process in send_pe
275 sp => this%send_dof(dst)%array()
276 do concurrent(j = 1:this%send_dof(dst)%size())
277 this%send_buf(i)%data(j) = send(sp(j))
278 end do
279 ! We should not need this extra associate block, ant it works
280 ! great without it for GNU, Intel, NEC and Cray, but throws an
281 ! ICE with NAG.
282 associate(send_data => this%send_buf(i)%data)
283 call mpi_isend(send_data, this%send_dof(dst)%size(), &
284 mpi_real_precision, this%send_pe(i), thrdid, &
285 this%comm, this%send_buf(i)%request, ierr)
286 end associate
287 this%send_buf(i)%flag = .false.
288 end do
289
290 !
291 ! Wait for non-blocking operations
292 !
293
294 nreqs = size(this%recv_pe)
295
296 do while (nreqs .gt. 0)
297 do i = 1, size(this%recv_pe)
298 if (.not. this%recv_buf(i)%flag) then
299 ! Check if we have recieved the data we want
300 call mpi_test(this%recv_buf(i)%request, this%recv_buf(i)%flag, &
301 this%recv_buf(i)%status, ierr)
302 ! If it has been received
303 if (this%recv_buf(i)%flag) then
304 ! One more request has been succesful
305 nreqs = nreqs - 1
307 src = this%recv_pe(i)
308 sp => this%recv_dof(src)%array()
309 !NEC$ IVDEP
310 do concurrent(j = 1:this%recv_dof(src)%size())
311 recv(sp(j)) = this%recv_buf(i)%data(j)
312 end do
313 end if
314 end if
315 end do
316 end do
317 ! Finally, check that the non-blocking sends this rank have issued have also
318 ! completed successfully
319
320 nreqs = size(this%send_pe)
321 do while (nreqs .gt. 0)
322 do i = 1, size(this%send_pe)
323 if (.not. this%send_buf(i)%flag) then
324 call mpi_test(this%send_buf(i)%request, this%send_buf(i)%flag, &
325 mpi_status_ignore, ierr)
326 if (this%send_buf(i)%flag) nreqs = nreqs - 1
327 end if
328 end do
329 end do
330
331 end subroutine glb_intrp_comm_sendrecv
332
335 class(glb_intrp_comm_t), intent(inout) :: this
336 integer :: i, j, src, ierr
337 integer , pointer :: sp(:)
338 integer :: nreqs
339
340 nreqs = size(this%recv_pe)
341
342 do while (nreqs .gt. 0)
343 do i = 1, size(this%recv_pe)
344 if (.not. this%recv_buf(i)%flag) then
345 ! Check if we have recieved the data we want
346 call mpi_test(this%recv_buf(i)%request, this%recv_buf(i)%flag, &
347 this%recv_buf(i)%status, ierr)
348 ! If it has been received
349 if (this%recv_buf(i)%flag) then
350 ! One more request has been succesful
351 nreqs = nreqs - 1
352 end if
353 end if
354 end do
355 end do
356 ! Finally, check that the non-blocking sends this rank have issued have also
357 ! completed successfully
358
359 nreqs = size(this%send_pe)
360 do while (nreqs .gt. 0)
361 do i = 1, size(this%send_pe)
362 if (.not. this%send_buf(i)%flag) then
363 call mpi_test(this%send_buf(i)%request, this%send_buf(i)%flag, &
364 mpi_status_ignore, ierr)
365 if (this%send_buf(i)%flag) nreqs = nreqs - 1
366 end if
367 end do
368 end do
369
370 end subroutine glb_intrp_comm_nbwait_no_op
371
372
373end 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