FE-Project
Loading...
Searching...
No Matches
scale_meshfieldcomm_base.F90
Go to the documentation of this file.
1!-------------------------------------------------------------------------------
2!> module FElib / Data / Communication base
3!!
4!! @par Description
5!! Base module to manage data communication for element-based methods
6!!
7!! @author Yuta Kawai, Team SCALE
8!<
9#include "scaleFElib.h"
11
12 !-----------------------------------------------------------------------------
13 !
14 !++ used modules
15 !
16 use scale_precision
17 use scale_io
18 use scale_prc, only: &
19 prc_abort
20
22 use scale_mesh_base, only: meshbase
23 use scale_meshfield_base, only: &
25 use scale_localmesh_base, only: &
27
28 !-----------------------------------------------------------------------------
29 implicit none
30 private
31
32 !-----------------------------------------------------------------------------
33 !
34 !++ Public type & procedure
35 !
36
37 !> Derived type to manage data communication at a face between adjacent local meshes
38 type, public :: localmeshcommdata
39 class(localmeshbase), pointer :: lcmesh
40 real(rp), allocatable :: send_buf(:,:) !< Buffer for sending data
41 real(rp), allocatable :: recv_buf(:,:) !< Buffer for receiving data
42 integer :: nnode_lcmeshface !< Number of nodes at a face
43 integer :: s_tileid !< Destination tile ID
44 integer :: s_faceid !< Destination face ID
45 integer :: s_panelid !< Destination panel ID
46 integer :: s_rank !< Destination MPI rank
47 integer :: s_tilelocalid !< Destination local tile ID
48 integer :: faceid !< Own face ID
49 contains
50 procedure, public :: init => localmeshcommdata_init
51 procedure, public :: final => localmeshcommdata_final
52 procedure, public :: sendrecv => localmeshcommdata_sendrecv
53 procedure, public :: pc_init_recv => localmeshcommdata_pc_init_recv
54 procedure, public :: pc_init_send => localmeshcommdata_pc_init_send
55 end type
56
57 !> Base derived type to manage data communication
58 type, abstract, public :: meshfieldcommbase
59 integer :: sfield_num !< Number of scalar fields
60 integer :: hvfield_num !< Number of horizontal vector fields
61 integer :: htensorfield_num !< Number of horizontal tensor fields
62 integer :: field_num_tot !< Total number of fields
63 integer :: nfaces_comm !< Number of faces where halo data is communicated
64
65 integer :: bufsize_per_field !< Buffer size per a field data
66
67 class(meshbase), pointer :: mesh
68 real(rp), allocatable :: send_buf(:,:,:) !< Buffer for sending data
69 real(rp), allocatable :: recv_buf(:,:,:) !< Buffer for receiving data
70 integer, allocatable :: request_send(:)
71 integer, allocatable :: request_recv(:)
72
73 type(localmeshcommdata), allocatable :: commdata_list(:,:)
74 integer, allocatable :: is_f(:,:)
75 integer, allocatable :: nnode_lcmeshallface(:)
76
77 logical :: mpi_pc_flag !< Flag whether persistent communication is used
78 logical :: use_mpi_pc_fujitsu_ext !< Flag whether Fujitsu extension routines are used for persistent communication
79 integer, allocatable :: request_pc(:)
80
81 integer :: req_counter
82 logical :: call_wait_flag_sub_get !< Flag whether MPI_wait need to be called before getting halo data from recv_buf
83
84 integer :: obj_ind
85
86 !-
87 logical :: use_vmap_wide_flag
88 integer, allocatable :: vmapb_size(:)
89 integer, allocatable :: vmapb2(:)
90 contains
91 procedure(meshfieldcommbase_put), public, deferred :: put
92 procedure(meshfieldcommbase_get), public, deferred :: get
93 procedure(meshfieldcommbase_exchange), public, deferred :: exchange
94 procedure, public :: prepare_pc => meshfieldcommbase_prepare_pc
95 end type meshfieldcommbase
96
106
107 !> Container to save a pointer of MeshField(1D, 2D, 3D) object
108 type, public :: meshfieldcontainer
109 class(meshfield1d), pointer :: field1d
110 class(meshfield2d), pointer :: field2d
111 class(meshfield3d), pointer :: field3d
112 end type
113
114 interface
115 subroutine meshfieldcommbase_put(this, field_list, varid_s)
116 import meshfieldcommbase
117 import meshfieldcontainer
118 class(meshfieldcommbase), intent(inout) :: this
119 type(meshfieldcontainer), intent(in) :: field_list(:)
120 integer, intent(in) :: varid_s
121 end subroutine meshfieldcommbase_put
122
123 subroutine meshfieldcommbase_get(this, field_list, varid_s)
124 import meshfieldcommbase
125 import meshfieldcontainer
126 class(meshfieldcommbase), intent(inout) :: this
127 type(meshfieldcontainer), intent(inout) :: field_list(:)
128 integer, intent(in) :: varid_s
129 end subroutine meshfieldcommbase_get
130
131 subroutine meshfieldcommbase_exchange(this, do_wait)
132 import meshfieldcommbase
133 class(meshfieldcommbase), intent(inout), target :: this
134 logical, intent(in), optional :: do_wait
135 end subroutine meshfieldcommbase_exchange
136
137 subroutine meshfieldcomm_final(this)
138 import meshfieldcommbase
139 class(meshfieldcommbase), intent(inout) :: this
140 end subroutine meshfieldcomm_final
141 end interface
142
143 !-----------------------------------------------------------------------------
144 !
145 !++ Public parameters & variables
146 !
147
148 !-----------------------------------------------------------------------------
149 !
150 !++ Private procedure
151 !
152
153 !-----------------------------------------------------------------------------
154 !
155 !++ Private parameters & variables
156 !
157
158 integer :: obj_ind = 0
159 integer, parameter :: OBJ_INDEX_MAX = 8192
160
161contains
162
163!> Initialize a base object to manage data communication of fields
164!!
165!! @param sfield_num Number of scalar fields
166!! @param hvfield_num Number of horizontal vector fields
167!! @param htensorfield_num Number of horizontal tensor fields
168!! @param bufsize_per_field Buffer size per a field
169!! @param comm_face_num Number of faces on a local mesh which perform data communication
170!! @param Nnode_LCMeshFace Array to store the number of nodes
171!OCL SERIAL
172 subroutine meshfieldcommbase_init( this, &
173 sfield_num, hvfield_num, htensorfield_num, bufsize_per_field, comm_face_num, &
174 Nnode_LCMeshFace, mesh )
175
176 implicit none
177
178 class(meshfieldcommbase), intent(inout) :: this
179 class(meshbase), intent(in), target :: mesh
180 integer, intent(in) :: sfield_num
181 integer, intent(in) :: hvfield_num
182 integer, intent(in) :: htensorfield_num
183 integer, intent(in) :: bufsize_per_field
184 integer, intent(in) :: comm_face_num
185 integer, intent(in) :: nnode_lcmeshface(comm_face_num,mesh%local_mesh_num)
186
187 integer :: n, f
188 class(localmeshbase), pointer :: lcmesh
189 !-----------------------------------------------------------------------------
190
191 !$acc enter data create(this)
192 this%mesh => mesh
193 this%sfield_num = sfield_num
194 this%hvfield_num = hvfield_num
195 this%htensorfield_num = htensorfield_num
196 this%field_num_tot = sfield_num + hvfield_num*2 + htensorfield_num*4
197 this%nfaces_comm = comm_face_num
198 !$acc update device(this%sfield_num, this%hvfield_num, this%htensorfield_num, this%field_num_tot, this%nfaces_comm)
199 !$acc enter data attach(this%mesh)
200
201 if (this%field_num_tot > 0) then
202 allocate( this%send_buf(bufsize_per_field, this%field_num_tot, mesh%LOCAL_MESH_NUM) )
203 allocate( this%recv_buf(bufsize_per_field, this%field_num_tot, mesh%LOCAL_MESH_NUM) )
204 allocate( this%request_send(comm_face_num*mesh%LOCAL_MESH_NUM) )
205 allocate( this%request_recv(comm_face_num*mesh%LOCAL_MESH_NUM) )
206 !$acc enter data create(this%send_buf, this%recv_buf, this%request_send, this%request_recv)
207
208 allocate( this%commdata_list(comm_face_num,mesh%LOCAL_MESH_NUM) )
209 allocate( this%is_f(comm_face_num,mesh%LOCAL_MESH_NUM) )
210 allocate( this%Nnode_LCMeshAllFace(mesh%LOCAL_MESH_NUM) )
211 !$acc enter data create(this%is_f, this%Nnode_LCMeshAllFace)
212
213 do n=1, mesh%LOCAL_MESH_NUM
214 this%is_f(1,n) = 1
215 do f=2, this%nfaces_comm
216 this%is_f(f,n) = this%is_f(f-1,n) + nnode_lcmeshface(f-1,n)
217 end do
218 this%Nnode_LCMeshAllFace(n) = sum(nnode_lcmeshface(:,n))
219
220 call mesh%GetLocalMesh(n, lcmesh)
221 do f=1, this%nfaces_comm
222 call this%commdata_list(f,n)%Init( this, lcmesh, f, nnode_lcmeshface(f,n) )
223 end do
224 end do
225 !$acc update device(this%is_f, this%Nnode_LCMeshAllFace)
226 !$acc enter data copyin(this%commdata_list)
227#ifdef _OPENACC
228 do n=1, mesh%LOCAL_MESH_NUM
229 do f=1, this%nfaces_comm
230 call localmeshcommdata_setupforgpu( this%commdata_list(f,n) )
231 end do
232 end do
233#endif
234 end if
235
236 this%MPI_pc_flag = .false.
237
238 obj_ind = obj_ind + 1
239 if ( obj_ind > obj_index_max ) then
240 log_error("MeshFieldCommBase_Init",*) 'obj_ind > OBJ_INDEX_MAX. Check!'
241 call prc_abort
242 end if
243 this%obj_ind = obj_ind
244
245 return
246 end subroutine meshfieldcommbase_init
247
248!> Finalize a base object to manage data communication of fields
249!!
250!OCL SERIAL
251 subroutine meshfieldcommbase_final( this )
252 implicit none
253
254 class(meshfieldcommbase), intent(inout) :: this
255
256 integer :: n, f
257 integer :: ireq
258 integer :: ierr
259 !-----------------------------------------------------------------------------
260
261 if (this%field_num_tot > 0) then
262 !$acc exit data delete(this%send_buf, this%recv_buf)
263 deallocate( this%send_buf, this%recv_buf )
264 !$acc exit data delete(this%request_send, this%request_recv)
265 deallocate( this%request_send, this%request_recv )
266
267 do n=1, this%mesh%LOCAL_MESH_NUM
268 do f=1, this%nfaces_comm
269 call this%commdata_list(f,n)%Final()
270 end do
271 end do
272 !$acc exit data delete(this%commdata_list, this%is_f, this%Nnode_LCMeshAllFace)
273 deallocate( this%commdata_list, this%is_f, this%Nnode_LCMeshAllFace )
274
275 if ( this%MPI_pc_flag ) then
276 do ireq=1, this%req_counter
277 call mpi_request_free( this%request_pc(ireq), ierr )
278 end do
279 deallocate( this%request_pc )
280 end if
281 end if
282
283 if ( allocated(this%VMapB_size) ) then
284 !$acc exit data delete(this%VMapB_size)
285 deallocate(this%VMapB_size)
286 end if
287 if ( this%use_vmap_wide_flag ) then
288 !$acc exit data delete(this%VMapB2)
289 deallocate( this%VMapB2 )
290 end if
291
292 return
293 end subroutine meshfieldcommbase_final
294
295!> Prepare persistent communication
296!!
297!! @param use_mpi_pc_fujitsu_ext Flag whether the extension routines of Fujitsu MPI are used
298!!
299!OCL SERIAL
300 subroutine meshfieldcommbase_prepare_pc( this, &
301 use_mpi_pc_fujitsu_ext )
302 implicit none
303 class(meshfieldcommbase), intent(inout) :: this
304 logical, intent(in), optional :: use_mpi_pc_fujitsu_ext
305
306 integer :: n, f
307 !-----------------------------------------------------------------------------
308
309 this%MPI_pc_flag = .true.
310
311#ifdef __FUJITSU
312 this%use_mpi_pc_fujitsu_ext = .true.
313#else
314 this%use_mpi_pc_fujitsu_ext = .false.
315#endif
316 if ( present(use_mpi_pc_fujitsu_ext) ) then
317 this%use_mpi_pc_fujitsu_ext = use_mpi_pc_fujitsu_ext
318#ifndef __FUJITSU
319 if ( use_mpi_pc_fujitsu_ext ) then
320 log_error("MeshFieldCommBase_prepare_PC",*) 'use_mpi_pc_fujitsu_ext=.true., but Fujitsu MPI is unavailable. Check!'
321 call prc_abort
322 end if
323#endif
324 end if
325
326 if (this%field_num_tot > 0) then
327 allocate( this%request_pc(2*this%nfaces_comm*this%mesh%LOCAL_MESH_NUM) )
328 end if
329
330 this%req_counter = 0
331 do n=1, this%mesh%LOCAL_MESH_NUM
332 do f=1, this%nfaces_comm
333 call this%commdata_list(f,n)%PC_Init_recv( &
334 this%req_counter, this%request_pc(:), & ! (inout)
335 this%obj_ind, this%use_mpi_pc_fujitsu_ext ) ! (in)
336 end do
337 end do
338 do n=1, this%mesh%LOCAL_MESH_NUM
339 do f=1, this%nfaces_comm
340 call this%commdata_list(f,n)%PC_Init_send( &
341 this%req_counter, this%request_pc(:), & ! (inout)
342 this%obj_ind, this%use_mpi_pc_fujitsu_ext ) ! (in)
343 end do
344 end do
345
346 return
347 end subroutine meshfieldcommbase_prepare_pc
348
349!> Exchange halo data
350!!
351!! @param commdata_list Array of LocalMeshCommData objects which manage information and halo data
352!! @param do_wait Flag whether MPI_waitall is called and move tmp data of LocalMeshCommData object to a recv buffer
353!OCL SERIAL
354 subroutine meshfieldcommbase_exchange_core( this, commdata_list, do_wait )
355#ifdef __FUJITSU
356 use mpi_ext, only: &
357 fjmpi_prequest_startall
358#endif
359! use mpi, only: &
360! MPI_startall
361 use scale_prof
362 implicit none
363
364 class(meshfieldcommbase), intent(inout) :: this
365 type(localmeshcommdata), intent(inout), target :: commdata_list(this%nfaces_comm, this%mesh%local_mesh_num)
366 logical, intent(in), optional :: do_wait
367
368 integer :: n, f
369 integer :: ierr
370 logical :: do_wait_
371
372 integer :: i
373 type(localmeshcommdata), pointer :: lcommdata
374 !-----------------------------------------------------------------------------
375
376 if ( present(do_wait) ) then
377 do_wait_ = do_wait
378 else
379 do_wait_ = .true.
380 end if
381
382! call PROF_rapstart( 'meshfiled_comm_ex_core', 3)
383 !
384 if ( this%MPI_pc_flag ) then
385#ifdef _OPENACC
386 do n=1, this%mesh%LOCAL_MESH_NUM
387 do f=1, this%nfaces_comm
388 lcommdata => commdata_list(f,n)
389 if ( lcommdata%s_rank /= lcommdata%lcmesh%PRC_myrank ) then
390 !$acc update host(lcommdata%send_buf) async(1)
391 end if
392 end do
393 end do
394 !$acc wait(1)
395
396#endif
397 !$omp parallel
398 !$omp master
399 if ( this%use_mpi_pc_fujitsu_ext ) then
400#ifdef __FUJITSU
401 ! Use Fujitsu MPI extension for persistent communication
402 call fjmpi_prequest_startall( this%req_counter, this%request_pc(1:this%req_counter), ierr )
403#endif
404 else
405 call mpi_startall( this%req_counter, this%request_pc(1:this%req_counter), ierr )
406 end if
407 !$omp end master
408
409 !$omp do collapse(2) private(lcommdata)
410 do n=1, this%mesh%LOCAL_MESH_NUM
411 do f=1, this%nfaces_comm
412 lcommdata => commdata_list(f,n)
413 if ( lcommdata%s_rank == lcommdata%lcmesh%PRC_myrank ) then
414#ifdef _OPENACC
415 call set_recvbuf_from_sendbuf_lc( commdata_list(abs(lcommdata%s_faceID), lcommdata%s_tilelocalID)%recv_buf, &
416 lcommdata%send_buf, size(lcommdata%send_buf) )
417#else
418 commdata_list(abs(lcommdata%s_faceID), lcommdata%s_tilelocalID)%recv_buf(:,:) &
419 = lcommdata%send_buf(:,:)
420#endif
421 end if
422 end do
423 end do
424 !$acc wait(1)
425 !$omp end parallel
426 else
427 this%req_counter = 0
428 do n=1, this%mesh%LOCAL_MESH_NUM
429 do f=1, this%nfaces_comm
430 call commdata_list(f,n)%SendRecv( &
431 this%req_counter, this%request_send, this%request_recv, & ! (inout)
432 commdata_list ) ! (inout)
433 end do
434 end do
435 !$acc wait(1)
436 end if
437
438! call PROF_rapend( 'meshfiled_comm_ex_core', 3)
439
440 if ( do_wait_ ) then
441 call meshfieldcommbase_wait_core( this, commdata_list )
442 this%call_wait_flag_sub_get = .false.
443 else
444 this%call_wait_flag_sub_get = .true.
445 end if
446
447 return
449
450!> Wait data communication and move tmp data of LocalMeshCommData object to a recv buffer
451!!
452!! @param commdata_list Array of LocalMeshCommData objects which manage information and halo data
453!OCL SERIAL
454 subroutine meshfieldcommbase_wait_core( this, commdata_list, &
455 field_list, dim, varid_s, lcmesh_list )
456 use mpi, only: &
457! MPI_waitall, &
458 mpi_status_size
459 use scale_prof
460 implicit none
461
462 class(meshfieldcommbase), intent(inout) :: this
463 type(localmeshcommdata), intent(inout), target :: commdata_list(this%nfaces_comm, this%mesh%local_mesh_num)
464 type(meshfieldcontainer), intent(inout), optional :: field_list(:)
465 integer, intent(in), optional :: dim
466 integer, intent(in), optional :: varid_s
467 class(localmeshbase), intent(in), optional, target :: lcmesh_list(:)
468
469 integer :: ierr
470 integer :: stat_send(mpi_status_size, this%req_counter)
471 integer :: stat_recv(mpi_status_size, this%req_counter)
472 integer :: stat_pc(mpi_status_size, this%req_counter)
473
474 integer :: n, f
475 integer :: i, var_id
476 integer :: irs(this%nfaces_comm,this%mesh%local_mesh_num), ire(this%nfaces_comm,this%mesh%local_mesh_num)
477
478 class(localmeshbase), pointer :: lcmesh
479 integer :: val_size(this%mesh%local_mesh_num)
480 !----------------------------
481
482! call PROF_rapstart( 'meshfiled_comm_wait_core', 2)
483 if ( this%MPI_pc_flag ) then
484 if (this%req_counter > 0) then
485 call mpi_waitall( this%req_counter, this%request_pc(1:this%req_counter), stat_pc, ierr )
486 end if
487 else
488 if ( this%req_counter > 0 ) then
489 call mpi_waitall( this%req_counter, this%request_recv(1:this%req_counter), stat_recv, ierr )
490 call mpi_waitall( this%req_counter, this%request_send(1:this%req_counter), stat_send, ierr )
491 end if
492 end if
493
494#ifdef _OPENACC
495 do n=1, this%mesh%LOCAL_MESH_NUM
496 do f=1, this%nfaces_comm
497 if ( commdata_list(f,n)%s_rank /= commdata_list(f,n)%lcmesh%PRC_myrank ) then
498 !$acc update device( commdata_list(f,n)%recv_buf ) async(1)
499 end if
500 end do
501 end do
502#endif
503
504! call PROF_rapend( 'meshfiled_comm_wait_core', 2)
505
506 !---------------------
507
508! call PROF_rapstart( 'meshfiled_comm_wait_post', 2)
509
510 if ( present(field_list) ) then
511 do n=1, this%mesh%LOCAL_MESH_NUM
512 lcmesh => lcmesh_list(n)
513 val_size(n) = lcmesh%refElem%Np * lcmesh%NeA
514 irs(1,n) = lcmesh%refElem%Np * lcmesh%Ne + 1
515 do f=1, this%nfaces_comm
516 ire(f,n) = irs(f,n) + commdata_list(f,n)%Nnode_LCMeshFace - 1
517 if (f<this%nfaces_comm) irs(f+1,n) = ire(f,n) + 1
518 end do
519 end do
520
521 !$omp parallel do private(var_id,n,i,f) collapse(3)
522 !$acc parallel loop gang collapse(3) present(field_list, commdata_list) copyin(irs, ire, val_size) async(1)
523 do n=1, this%mesh%LOCAL_MESH_NUM
524 do i=1, size(field_list)
525 do f=1, this%nfaces_comm
526 var_id = varid_s + i - 1
527
528 if (dim==1) then
529 call set_bounddata( field_list(var_id)%field1d%local(n)%val, val_size(n), irs(f,n), ire(f,n), commdata_list(f,n)%recv_buf(:,var_id) )
530 else if (dim==2) then
531 call set_bounddata( field_list(var_id)%field2d%local(n)%val, val_size(n), irs(f,n), ire(f,n), commdata_list(f,n)%recv_buf(:,var_id) )
532 else if (dim==3) then
533 call set_bounddata( field_list(var_id)%field3d%local(n)%val, val_size(n), irs(f,n), ire(f,n), commdata_list(f,n)%recv_buf(:,var_id) )
534 end if
535 end do ! end loop for face
536 end do
537 end do
538#ifdef _OPENACC
539 do n=1, this%mesh%LOCAL_MESH_NUM
540 do i=1, size(field_list)
541 do f=1, this%nfaces_comm
542 var_id = varid_s + i - 1
543 if (dim==1) then
544 !$acc update device( field_list(var_id)%field1d%local(n)%val(irs(f,n):ire(f,n)) ) async(1)
545 else if (dim==2) then
546 !$acc update device( field_list(var_id)%field2d%local(n)%val(irs(f,n):ire(f,n)) ) async(1)
547 else if (dim==3) then
548 !$acc update device( field_list(var_id)%field3d%local(n)%val(irs(f,n):ire(f,n)) ) async(1)
549 end if
550 end do ! end loop for face
551 end do
552 end do
553#endif
554
555 else
556
557 do n=1, this%mesh%LOCAL_MESH_NUM
558 irs(1,n) = 1
559 do f=1, this%nfaces_comm
560 ire(f,n) = irs(f,n) + commdata_list(f,n)%Nnode_LCMeshFace - 1
561 if (f<this%nfaces_comm) irs(f+1,n) = ire(f,n) + 1
562 end do
563 end do
564
565 !$omp parallel do private(n,var_id,f) collapse(3)
566 !$acc parallel loop gang collapse(3) present(this%recv_buf, commdata_list) copyin(irs, ire) async(1)
567 do n=1, this%mesh%LOCAL_MESH_NUM
568 do var_id=1, this%field_num_tot
569 do f=1, this%nfaces_comm
570#ifdef _OPENACC
571 call set_bounddata( this%recv_buf(:,var_id,n), size(this%recv_buf(:,var_id,n)), irs(f,n), ire(f,n), commdata_list(f,n)%recv_buf(:,var_id) )
572#else
573 this%recv_buf(irs(f,n):ire(f,n),var_id,n) = commdata_list(f,n)%recv_buf(:,var_id)
574#endif
575 end do ! end loop for face
576 end do
577 end do
578 end if
579
580 !$acc wait(1)
581! call PROF_rapend( 'meshfiled_comm_wait_post', 2)
582 return
583 contains
584!OCL SERIAL
585 subroutine set_bounddata( var, IA, irs_, ire_, recv_buf )
586 implicit none
587 integer, intent(in) :: IA
588 real(RP), intent(inout) :: var(IA)
589 integer, intent(in) :: irs_, ire_
590 real(RP), intent(in) :: recv_buf(ire_-irs_+1)
591
592 integer :: ii
593 !-----------------------------
594 !$acc routine vector
595
596 !$acc loop vector
597 do ii=1, size(recv_buf)
598 var(irs_+ii-1) = recv_buf(ii)
599 end do
600 return
601 end subroutine set_bounddata
602 end subroutine meshfieldcommbase_wait_core
603
604!> Extract halo data from data array with MeshField object and set it to the receiving buffer
605!OCL SERIAL
606 subroutine meshfieldcommbase_extract_bounddata(var, refElem, mesh, buf)
607 implicit none
608
609 class(elementbase), intent(in) :: refelem
610 class(localmeshbase), intent(in) :: mesh
611 real(rp), intent(in) :: var(refelem%np * mesh%nea)
612 real(rp), intent(out) :: buf(size(mesh%vmapb))
613
614 integer :: i
615 !-----------------------------------------------------------------------------
616 !$omp parallel do
617 !$acc parallel loop present(var, mesh%VmapB, buf)
618!OCL PREFETCH
619 do i=1, size(buf)
620 buf(i) = var(mesh%VmapB(i))
621 end do
622 return
624
625!> Extract halo data from data array with MeshField object and set it to the receiving buffer
626!OCL SERIAL
627 subroutine meshfieldcommbase_extract_bounddata2(var, VMapB, VMapB_size, NpxNeA, buf)
628 implicit none
629 integer, intent(in) :: vmapb_size
630 integer, intent(in) :: npxnea
631 real(rp), intent(in) :: var(npxnea)
632 integer, intent(in) :: vmapb(vmapb_size)
633 real(rp), intent(out) :: buf(vmapb_size)
634
635 integer :: i
636 !-----------------------------------------------------------------------------
637 !$omp parallel do
638 !$acc parallel loop present(var, VmapB, buf) async(1)
639!OCL PREFETCH
640 do i=1, size(buf)
641 buf(i) = var(vmapb(i))
642 end do
643 return
645
646!> Extract halo data from data array with MeshField object and set it to the receiving buffer
647!!
648!! Note: We assume that the size of VmapB is the same for all local meshes.
649!! For the future, this subroutine should be modified to handle the case with different sizes of VmapB among local meshes.
650!!
651!OCL SERIAL
652 subroutine meshfieldcommbase_extract_bounddata_2(field_list, dim, varid_s, lcmesh_list, vmapB_size, buf)
653 implicit none
654 type(meshfieldcontainer), intent(in), target :: field_list(:)
655 integer, intent(in) :: varid_s !< Starting variable ID to extract halo data
656 integer, intent(in) :: dim !< Number of dimensions of the field (1, 2, or 3)
657 class(localmeshbase), intent(in), target :: lcmesh_list(:) !< Array of local mesh objects to extract halo data
658 integer, intent(in) :: vmapb_size !< Size of VmapB (we assume that the size of VmapB is the same for all local meshes)
659 real(rp), intent(out) :: buf(vmapb_size,size(field_list),size(lcmesh_list))
660
661 class(localmeshbase), pointer :: lcmesh
662 integer :: varid
663 integer :: i, n
664
665 integer :: field_num
666 !-----------------------------------------------------------------------------
667
668 field_num = size(field_list)
669
670 do n=1, size(lcmesh_list)
671 lcmesh => lcmesh_list(n)
672 i = 1
673 do while( i <= field_num )
674 varid = varid_s + i - 1
675 if ( i+1 <= field_num ) then
676 if (dim==1) then
677 call extract_bounddata_var2( buf(:,varid,n), buf(:,varid+1,n), field_list(varid)%field1d%local(n)%val, field_list(varid+1)%field1d%local(n)%val, lcmesh, lcmesh%refElem )
678 else if(dim==2) then
679 call extract_bounddata_var2( buf(:,varid,n), buf(:,varid+1,n), field_list(varid)%field2d%local(n)%val, field_list(varid+1)%field2d%local(n)%val, lcmesh, lcmesh%refElem )
680 else if(dim==3) then
681 call extract_bounddata_var2( buf(:,varid,n), buf(:,varid+1,n), field_list(varid)%field3d%local(n)%val, field_list(varid+1)%field3d%local(n)%val, lcmesh, lcmesh%refElem )
682 end if
683 i = i + 2
684 else
685 if (dim==1) then
686 call meshfieldcommbase_extract_bounddata2( field_list(varid)%field1d%local(n)%val, lcmesh%VMapB, size(lcmesh%VMapB), lcmesh%refElem%Np*lcmesh%NeA, buf(:,varid,n) )
687 else if(dim==2) then
688 call meshfieldcommbase_extract_bounddata2( field_list(varid)%field2d%local(n)%val, lcmesh%VMapB, size(lcmesh%VMapB), lcmesh%refElem%Np*lcmesh%NeA, buf(:,varid,n) )
689 else if(dim==3) then
690 call meshfieldcommbase_extract_bounddata2( field_list(varid)%field3d%local(n)%val, lcmesh%VMapB, size(lcmesh%VMapB), lcmesh%refElem%Np*lcmesh%NeA, buf(:,varid,n) )
691 end if
692 i = i + 1
693 end if
694 end do
695 !!$acc update host( buf(:,varid_s:field_num,n) )
696 end do
697 !$acc wait(1)
698
699 return
700 contains
701!OCL SERIAL
702 subroutine extract_bounddata_var2( buf1_, buf2_, var1, var2, lmesh, elem )
703 implicit none
704 class(localmeshbase), intent(in) :: lmesh
705 class(elementbase), intent(in) :: elem
706 real(rp), intent(out) :: buf1_(size(lmesh%vmapb))
707 real(rp), intent(out) :: buf2_(size(lmesh%vmapb))
708 real(rp), intent(inout) :: var1(elem%np*lmesh%nea)
709 real(rp), intent(inout) :: var2(elem%np*lmesh%nea)
710
711 integer :: ii, b
712 !-----------------------------
713 !$omp parallel do
714 !$acc parallel loop present(buf1_, buf2_, var1, var2, lmesh%vmapB) async(1)
715!OCL PREFETCH
716 do ii=1, size(buf1_)
717 b = lmesh%vmapB(ii)
718 buf1_(ii) = var1(b)
719 buf2_(ii) = var2(b)
720 end do
721 return
722 end subroutine extract_bounddata_var2
724
725!> Extract halo data from data array with MeshField object and set it to the recieving buffer
726!OCL SERIAL
727 subroutine meshfieldcommbase_extract_bounddata_3(field_list, dim, varid_s, lcmesh_list, VMapB2, VMapB2_size, buf)
728 implicit none
729 class(meshfieldcontainer), intent(in), target :: field_list(:)
730 integer, intent(in) :: varid_s
731 integer, intent(in) :: dim
732 class(localmeshbase), intent(in), target :: lcmesh_list(:)
733 integer, intent(in) :: vmapb2_size
734 integer, intent(in) :: vmapb2(vmapb2_size)
735 real(rp), intent(out) :: buf(vmapb2_size,size(field_list),size(lcmesh_list))
736
737 class(localmeshbase), pointer :: lcmesh
738 integer :: varid
739 integer :: i, n
740
741 integer :: field_num
742 !-----------------------------------------------------------------------------
743
744 field_num = size(field_list)
745
746 do n=1, size(lcmesh_list)
747 lcmesh => lcmesh_list(n)
748 i = 1
749 do while( i <= field_num )
750 varid = varid_s + i - 1
751 if ( i+1 <= field_num ) then
752 if (dim==1) then
753 call extract_bounddata_var2( buf(:,varid,n), buf(:,varid+1,n), &
754 vmapb2, vmapb2_size, field_list(varid)%field1d%local(n)%val, field_list(varid+1)%field1d%local(n)%val, lcmesh%refElem%Np * lcmesh%NeA )
755 else if(dim==2) then
756 call extract_bounddata_var2( buf(:,varid,n), buf(:,varid+1,n), &
757 vmapb2, vmapb2_size, field_list(varid)%field2d%local(n)%val, field_list(varid+1)%field2d%local(n)%val, lcmesh%refElem%Np * lcmesh%NeA )
758 else if(dim==3) then
759 call extract_bounddata_var2( buf(:,varid,n), buf(:,varid+1,n), &
760 vmapb2, vmapb2_size, field_list(varid)%field3d%local(n)%val, field_list(varid+1)%field3d%local(n)%val, lcmesh%refElem%Np * lcmesh%NeA )
761 end if
762 i = i + 2
763 else
764 if (dim==1) then
765 call meshfieldcommbase_extract_bounddata2( field_list(varid)%field1d%local(n)%val, vmapb2, vmapb2_size, lcmesh%refElem%Np*lcmesh%NeA, &
766 buf(:,varid,n) )
767 else if(dim==2) then
768 call meshfieldcommbase_extract_bounddata2( field_list(varid)%field2d%local(n)%val, vmapb2, vmapb2_size, lcmesh%refElem%Np*lcmesh%NeA, &
769 buf(:,varid,n) )
770 else if(dim==3) then
771 call meshfieldcommbase_extract_bounddata2( field_list(varid)%field3d%local(n)%val, vmapb2, vmapb2_size, lcmesh%refElem%Np*lcmesh%NeA, &
772 buf(:,varid,n) )
773 end if
774 i = i + 1
775 end if
776 end do
777 end do
778 return
779 contains
780!OCL SERIAL
781 subroutine extract_bounddata_var2( buf1_, buf2_, VMapB, VMapB_size, var1, var2, varSize )
782 implicit none
783 integer, intent(in) :: vmapb_size
784 real(rp), intent(out) :: buf1_(vmapb_size)
785 real(rp), intent(out) :: buf2_(vmapb_size)
786 integer, intent(in) :: vmapb(vmapb_size)
787 integer, intent(in) :: varsize
788 real(rp), intent(inout) :: var1(varsize)
789 real(rp), intent(inout) :: var2(varsize)
790
791 integer :: ii
792 !-----------------------------
793 !$omp parallel do
794!OCL PREFETCH
795 do ii=1, vmapb_size
796 buf1_(ii) = var1(vmapb(ii))
797 buf2_(ii) = var2(vmapb(ii))
798 end do
799 return
800 end subroutine extract_bounddata_var2
802
803!> Extract halo data from the receiving buffer and set it to data array with MeshField object
804 subroutine meshfieldcommbase_set_bounddata(buf, refElem, mesh, var)
805 implicit none
806
807 class(elementbase), intent(in) :: refelem
808 class(localmeshbase), intent(in) :: mesh
809 real(rp), intent(in) :: buf(size(mesh%vmapb))
810 real(rp), intent(inout) :: var(refelem%np * mesh%nea)
811
812 integer :: ii, iis
813 !-----------------------------------------------------------------------------
814
815#ifdef _OPENACC
816 iis = refelem%Np*mesh%NeE
817 !$acc parallel loop present(buf, var) async(1)
818 do ii=1, size(buf)
819 var(iis+ii) = buf(ii)
820 end do
821#else
822 var(refelem%Np*mesh%NeE+1:refelem%Np*mesh%NeE+size(buf)) = buf(:)
823#endif
824 return
825 end subroutine meshfieldcommbase_set_bounddata
826
827!> Extract halo data from the recieving buffer and set it to data array with MeshField object
828 subroutine meshfieldcommbase_set_bounddata_3(buf, refElem, mesh, vmapB, vmapB_size, var)
829 implicit none
830
831 class(elementbase), intent(in) :: refelem
832 class(localmeshbase), intent(in) :: mesh
833 integer, intent(in) :: vmapb_size
834 integer, intent(in) :: vmapb(vmapb_size)
835 real(rp), intent(in) :: buf(vmapb_size)
836 real(rp), intent(inout) :: var(refelem%np * mesh%nea)
837 !-----------------------------------------------------------------------------
838
839 var(refelem%Np*mesh%NeE+1:refelem%Np*mesh%NeE+size(buf)) = buf(:)
840 return
842
843 !-------------------------------------------
844
845 !> Initialize an object to manage data communication of fields for a face on a local mesh
846 subroutine localmeshcommdata_init( this, comm, lcmesh, faceID, Nnode_LCMeshFace )
847 implicit none
848
849 class(localmeshcommdata), intent(inout) :: this
850 class(meshfieldcommbase), intent(in) :: comm
851 class(localmeshbase), intent(in), target :: lcmesh
852 integer, intent(in) :: faceid
853 integer, intent(in) :: nnode_lcmeshface
854 !-----------------------------------------------------------------------------
855
856 this%lcmesh => lcmesh
857 this%Nnode_LCMeshFace = nnode_lcmeshface
858
859 !-
860 this%s_tileID = comm%mesh%tileID_globalMap(faceid, lcmesh%tileID)
861 this%s_faceID = comm%mesh%tileFaceID_globalMap(faceid, lcmesh%tileID)
862 this%s_panelID = comm%mesh%tilePanelID_globalMap(faceid, lcmesh%tileID)
863 this%s_rank = comm%mesh%PRCrank_globalMap(this%s_tileID)
864 this%s_tilelocalID = comm%mesh%tileID_global2localMap(this%s_tileID)
865 this%faceID = faceid
866
867 allocate( this%send_buf(nnode_lcmeshface, comm%field_num_tot))
868 allocate( this%recv_buf(nnode_lcmeshface, comm%field_num_tot))
869 return
870 end subroutine localmeshcommdata_init
871
872 subroutine localmeshcommdata_setupforgpu( this )
873 implicit none
874 type(localmeshcommdata), intent(inout) :: this
875 !-----------------------------------------------------------------------------
876 !$acc enter data create(this%send_buf, this%recv_buf)
877 !$acc enter data attach(this%lcmesh)
878 return
879 end subroutine localmeshcommdata_setupforgpu
880
881 !> Send and receive halo data for a face on a local mesh
882 subroutine localmeshcommdata_sendrecv( this, &
883 req_counter, req_send, req_recv, &
884 lccommdat_list )
885
886 use scale_prc, only: &
887 prc_local_comm_world
888 use mpi, only: &
889 !MPI_isend, MPI_irecv, &
890 mpi_double_precision
891 implicit none
892
893 class(localmeshcommdata), intent(inout) :: this
894 integer, intent(inout) :: req_counter
895 integer, intent(inout) :: req_send(:)
896 integer, intent(inout) :: req_recv(:)
897 type(localmeshcommdata), intent(inout) :: lccommdat_list(:,:)
898
899 integer :: tag
900 integer :: bufsize
901 integer :: ierr
902 !-------------------------------------------
903
904 if ( this%s_rank /= this%lcmesh%PRC_myrank ) then
905
906 !$acc update host(this%send_buf) async(1)
907 !$acc wait(1)
908
909 req_counter = req_counter + 1
910
911 tag = 10 * this%lcmesh%tileID + this%faceID
912 bufsize = size(this%recv_buf)
913 call mpi_irecv( this%recv_buf(1,1), bufsize, mpi_double_precision, &
914 this%s_rank, tag, prc_local_comm_world, &
915 req_recv(req_counter), ierr)
916
917 bufsize = size(this%send_buf)
918 tag = 10 * this%s_tileID + abs(this%s_faceID)
919 call mpi_isend( this%send_buf(1,1), bufsize, mpi_double_precision, &
920 this%s_rank, tag, prc_local_comm_world, &
921 req_send(req_counter), ierr )
922
923 else if ( this%s_rank == this%lcmesh%PRC_myrank ) then
924#ifdef _OPENACC
925 call set_recvbuf_from_sendbuf_lc( lccommdat_list(abs(this%s_faceID), this%s_tilelocalID)%recv_buf, &
926 this%send_buf, size(this%send_buf) )
927#else
928 lccommdat_list(abs(this%s_faceID), this%s_tilelocalID)%recv_buf(:,:) &
929 = this%send_buf(:,:)
930#endif
931 end if
932
933 return
934 end subroutine localmeshcommdata_sendrecv
935#ifdef _OPENACC
936 subroutine set_recvbuf_from_sendbuf_lc( recv_buf, send_buf, buf_size )
937 implicit none
938 integer, intent(in) :: buf_size
939 real(rp), intent(out) :: recv_buf(buf_size)
940 real(rp), intent(in) :: send_buf(buf_size)
941
942 integer :: i
943 !-----------------------------
944 !$acc parallel loop present(recv_buf, send_buf) async(1)
945 do i=1, buf_size
946 recv_buf(i) = send_buf(i)
947 end do
948 return
949 end subroutine set_recvbuf_from_sendbuf_lc
950#endif
951
952 !> Initialize persistent communication for sending halo data
953 subroutine localmeshcommdata_pc_init_send( this, &
954 req_counter, req, obj_ind_ , &
955 use_mpi_pc_fujisu_ext )
956
957 use scale_prc, only: &
958 prc_local_comm_world
959 use mpi, only: &
960 mpi_double_precision!, &
961! MPI_send_init
962#ifdef __FUJITSU
963 use mpi_ext, only: &
964 fjmpi_prequest_send_init
965#endif
966 implicit none
967
968 class(localmeshcommdata), intent(inout) :: this
969 integer, intent(inout) :: req_counter
970 integer, intent(inout) :: req(:)
971 integer, intent(in) :: obj_ind_
972 logical, intent(in) :: use_mpi_pc_fujisu_ext
973
974 integer :: tag
975 integer :: bufsize
976 integer :: ierr
977 !-------------------------------------------
978
979 if ( this%s_rank /= this%lcmesh%PRC_myrank ) then
980 req_counter = req_counter + 1
981
982 bufsize = size(this%send_buf)
983! tag = 1000 * this%s_tileID + 10 * obj_ind_ + abs(this%s_faceID)
984 tag = obj_ind_
985
986 if ( use_mpi_pc_fujisu_ext ) then
987#ifdef __FUJITSU
988 call fjmpi_prequest_send_init( this%send_buf(1,1), bufsize, mpi_double_precision, &
989 this%s_rank, tag, prc_local_comm_world, &
990 req(req_counter), ierr )
991#endif
992 else
993 call mpi_send_init( this%send_buf(1,1), bufsize, mpi_double_precision, &
994 this%s_rank, tag, prc_local_comm_world, &
995 req(req_counter), ierr )
996 end if
997 end if
998
999 return
1000 end subroutine localmeshcommdata_pc_init_send
1001 !> Initialize persistent communication for receiving halo data
1002 subroutine localmeshcommdata_pc_init_recv( this, &
1003 req_counter, req, obj_ind_, &
1004 use_mpi_pc_fujisu_ext )
1005
1006 use scale_prc, only: &
1007 prc_local_comm_world
1008 use mpi, only: &
1009 mpi_double_precision!, &
1010! MPI_recv_init
1011#ifdef __FUJITSU
1012 use mpi_ext, only: &
1013 fjmpi_prequest_recv_init
1014#endif
1015 implicit none
1016
1017 class(localmeshcommdata), intent(inout) :: this
1018 integer, intent(inout) :: req_counter
1019 integer, intent(inout) :: req(:)
1020 integer, intent(in) :: obj_ind_
1021 logical, intent(in) :: use_mpi_pc_fujisu_ext
1022
1023 integer :: tag
1024 integer :: bufsize
1025 integer :: ierr
1026 !-------------------------------------------
1027
1028 if ( this%s_rank /= this%lcmesh%PRC_myrank ) then
1029 req_counter = req_counter + 1
1030
1031 bufsize = size(this%recv_buf)
1032! tag = 1000 * this%lcmesh%tileID + 10 * obj_ind_ + this%faceID
1033 tag = obj_ind_
1034
1035 if ( use_mpi_pc_fujisu_ext ) then
1036#ifdef __FUJITSU
1037 call fjmpi_prequest_recv_init( this%recv_buf(1,1), bufsize, mpi_double_precision, &
1038 this%s_rank, tag, prc_local_comm_world, &
1039 req(req_counter), ierr )
1040#endif
1041 else
1042 call mpi_recv_init( this%recv_buf(1,1), bufsize, mpi_double_precision, &
1043 this%s_rank, tag, prc_local_comm_world, &
1044 req(req_counter), ierr )
1045 end if
1046 end if
1047
1048 return
1049 end subroutine localmeshcommdata_pc_init_recv
1050
1051 !> Finalize an object to manage data communication of fields for a face on a local mesh
1052 subroutine localmeshcommdata_final( this )
1053 implicit none
1054
1055 class(localmeshcommdata), intent(inout) :: this
1056 !-----------------------------------------------------------------------------
1057
1058 !$acc exit data delete(this%send_buf, this%recv_buf)
1059 deallocate( this%send_buf )
1060 deallocate( this%recv_buf )
1061 return
1062 end subroutine localmeshcommdata_final
1063
1064end module scale_meshfieldcomm_base
module FElib / Element / Base
module FElib / Mesh / Local, Base
module FElib / Mesh / Base
module FElib / Data / base
module FElib / Data / Communication base
subroutine, public meshfieldcommbase_extract_bounddata(var, refelem, mesh, buf)
Extract halo data from data array with MeshField object and set it to the receiving buffer.
subroutine, public meshfieldcommbase_extract_bounddata_3(field_list, dim, varid_s, lcmesh_list, vmapb2, vmapb2_size, buf)
Extract halo data from data array with MeshField object and set it to the recieving buffer.
subroutine, public meshfieldcommbase_final(this)
Finalize a base object to manage data communication of fields.
subroutine, public meshfieldcommbase_wait_core(this, commdata_list, field_list, dim, varid_s, lcmesh_list)
Wait data communication and move tmp data of LocalMeshCommData object to a recv buffer.
subroutine, public meshfieldcommbase_set_bounddata(buf, refelem, mesh, var)
Extract halo data from the receiving buffer and set it to data array with MeshField object.
subroutine, public meshfieldcommbase_set_bounddata_3(buf, refelem, mesh, vmapb, vmapb_size, var)
Extract halo data from the recieving buffer and set it to data array with MeshField object.
subroutine, public meshfieldcommbase_init(this, sfield_num, hvfield_num, htensorfield_num, bufsize_per_field, comm_face_num, nnode_lcmeshface, mesh)
Initialize a base object to manage data communication of fields.
subroutine, public meshfieldcommbase_extract_bounddata_2(field_list, dim, varid_s, lcmesh_list, vmapb_size, buf)
Extract halo data from data array with MeshField object and set it to the receiving buffer.
subroutine, public meshfieldcommbase_extract_bounddata2(var, vmapb, vmapb_size, npxnea, buf)
Extract halo data from data array with MeshField object and set it to the receiving buffer.
subroutine, public meshfieldcommbase_exchange_core(this, commdata_list, do_wait)
Exchange halo data.
subroutine set_bounddata(var, ia, irs_, ire_, recv_buf)
Derived type representing an arbitrary finite element.
Derived type to manage a local computational domain (base type)
Base type to manage a computational mesh.
Derived type representing a field with 1D mesh.
Derived type representing a field with 2D mesh.
Derived type representing a field with 3D mesh.
Derived type representing a field (base type)
Derived type to manage data communication at a face between adjacent local meshes.
Base derived type to manage data communication.
Container to save a pointer of MeshField(1D, 2D, 3D) object.