33 #include <fms_platform.h>
36 use mpi_f08,
only: mpi_comm
50 logical :: verbose=.false.
51 logical :: module_is_initialized=.false.
52 character(len=256) :: text
55 module procedure mpp_pset_broadcast_ptr_scalar
56 module procedure mpp_pset_broadcast_ptr_array
59 module procedure mpp_send_ptr_scalar
60 module procedure mpp_send_ptr_array
63 module procedure mpp_recv_ptr_scalar
64 module procedure mpp_recv_ptr_array
67 module procedure mpp_pset_print_chksum_1d
68 module procedure mpp_pset_print_chksum_2d
69 module procedure mpp_pset_print_chksum_3d
70 module procedure mpp_pset_print_chksum_4d
76 integer :: next_in_pset, prev_in_pset
77 integer :: root_in_pset
82 real,
allocatable :: stack(:)
83 integer,
allocatable :: pelist(:)
84 integer,
allocatable :: root_pelist(:)
85 integer,
allocatable :: pset(:)
86 integer(POINTER_KIND) :: p_stack
87 integer :: lstack, maxstack, hiWM
88 type(mpi_comm) :: comm
89 character(len=32) :: name
90 logical :: initialized=.false.
99 mpp_pset_delete, mpp_pset_root, mpp_pset_numroots, mpp_pset_init, &
104 subroutine mpp_pset_init
105 module_is_initialized = .true.
106 end subroutine mpp_pset_init
108 subroutine mpp_pset_delete(pset)
109 type(mpp_pset_type),
intent(inout) :: pset
113 if( .NOT.pset%initialized )
call mpp_error( fatal, &
114 'MPP_PSET_DELETE: called with uninitialized PSET.' )
116 deallocate( pset%pelist )
117 deallocate( pset%root_pelist )
118 deallocate( pset%pset )
119 if( pset%root )
deallocate( pset%stack )
120 write( out_unit,
'(a,i10)' ) &
121 'Deleting PSETs... stack high-water-mark=', pset%hiWM
123 pset%initialized = .false.
124 end subroutine mpp_pset_delete
126 subroutine mpp_send_ptr_scalar( ptr, pe )
127 integer(POINTER_KIND),
intent(in) :: ptr
128 integer,
intent(in) :: pe
132 call mpp_send( ptr, pe, tag=comm_tag_1 )
133 end subroutine mpp_send_ptr_scalar
135 subroutine mpp_send_ptr_array( ptr, pe )
136 integer(POINTER_KIND),
intent(in) :: ptr(:)
137 integer,
intent(in) :: pe
141 call mpp_send( ptr,
size(ptr), pe, tag=comm_tag_2 )
142 end subroutine mpp_send_ptr_array
144 subroutine mpp_recv_ptr_scalar( ptr, pe )
145 integer(POINTER_KIND),
intent(inout) :: ptr
146 integer,
intent(in) :: pe
148 call mpp_recv( ptr, pe, tag=comm_tag_1 )
150 end subroutine mpp_recv_ptr_scalar
152 subroutine mpp_recv_ptr_array( ptr, pe )
153 integer(POINTER_KIND),
intent(inout) :: ptr(:)
154 integer,
intent(in) :: pe
156 call mpp_recv( ptr,
size(ptr), pe, tag=comm_tag_2 )
158 end subroutine mpp_recv_ptr_array
160 subroutine mpp_pset_sync(pset)
163 type(mpp_pset_type),
intent(in) :: pset
165 if( .NOT.pset%initialized )
call mpp_error( fatal, &
166 'MPP_PSET_SYNC: called with uninitialized PSET.' )
170 end subroutine mpp_pset_sync
172 subroutine mpp_pset_broadcast(pset,a)
174 type(mpp_pset_type),
intent(in) :: pset
175 real,
intent(inout) :: a
178 if( .NOT.pset%initialized )
call mpp_error( fatal, &
179 'MPP_PSET_BROADCAST: called with uninitialized PSET.' )
181 do i = 1,pset%npset-1
182 call mpp_send( a, pset%pset(i), tag=comm_tag_3 )
185 call mpp_recv( a, pset%root_in_pset, tag=comm_tag_3 )
187 call mpp_pset_sync(pset)
188 end subroutine mpp_pset_broadcast
190 subroutine mpp_pset_broadcast_ptr_scalar(pset,ptr)
194 type(mpp_pset_type),
intent(in) :: pset
195 integer(POINTER_KIND),
intent(inout) :: ptr
198 if( .NOT.pset%initialized )
call mpp_error( fatal, &
199 'MPP_PSET_BROADCAST_PTR: called with uninitialized PSET.' )
201 do i = 1,pset%npset-1
208 end subroutine mpp_pset_broadcast_ptr_scalar
210 subroutine mpp_pset_broadcast_ptr_array(pset,ptr)
214 type(mpp_pset_type),
intent(in) :: pset
215 integer(POINTER_KIND),
intent(inout) :: ptr(:)
218 if( .NOT.pset%initialized )
call mpp_error( fatal, &
219 'MPP_PSET_BROADCAST_PTR: called with uninitialized PSET.' )
221 do i = 1,pset%npset-1
229 end subroutine mpp_pset_broadcast_ptr_array
231 subroutine mpp_pset_check_ptr(pset,ptr)
233 type(mpp_pset_type),
intent(in) :: pset
234 #ifdef use_CRI_pointers
236 pointer( ptr, dummy )
238 integer(POINTER_KIND),
intent(in) :: ptr
241 integer(POINTER_KIND) :: p
243 if( .NOT.pset%initialized )
call mpp_error( fatal, &
244 'MPP_PSET_CHECK_PTR: called with uninitialized PSET.' )
248 do i = 1,pset%npset-1
254 call mpp_pset_sync(pset)
256 'MPP_PSET_CHECK_PTR: pointers do not match!' )
260 end subroutine mpp_pset_check_ptr
262 subroutine mpp_pset_segment_array( pset, ls, le, lsp, lep )
267 type(mpp_pset_type),
intent(in) :: pset
268 integer,
intent(in) :: ls, le
269 integer,
intent(out) :: lsp, lep
272 if( .NOT.pset%initialized )
call mpp_error( fatal, &
273 'MPP_PSET_SEGMENT_ARRAY: called with uninitialized PSET.' )
275 if( le-ls+1.LT.pset%npset )
then
276 write( text,
'(3(a,i6))' ) &
277 'MPP_PSET_ARRAY_SEGMENT: parallel range (', ls,
',', le, &
278 ') is smaller than the number of threads:', pset%npset
285 lep = lsp + ceiling( real(le-lsp+1)/(pset%npset-i) ) - 1
287 end subroutine mpp_pset_segment_array
289 subroutine mpp_pset_stack_push( pset, ptr, len )
294 type(mpp_pset_type),
intent(inout) :: pset
295 integer,
intent(in) :: len
296 #ifdef use_CRI_pointers
298 pointer( ptr, dummy )
299 real :: stack(pset%maxstack)
302 if( .NOT.pset%initialized )
call mpp_error( fatal, &
303 'MPP_PSET_STACK_PUSH: called with uninitialized PSET.' )
304 if( pset%lstack+len.GT.pset%maxstack )
then
305 write( text,
'(a,3i12)' ) &
306 'MPP_PSET_STACK_PUSH: mpp_pset_stack overflow: '// &
307 .GT.
'len+lstackmaxstack. len, lstack, maxstack=', &
308 len, pset%lstack, pset%maxstack
312 ptr = loc( stack(pset%lstack+1) )
313 call mpp_pset_check_ptr(pset,ptr)
314 pset%lstack = pset%lstack + len
315 pset%hiWM = max( pset%hiWM, pset%lstack )
317 integer(POINTER_KIND),
intent(out) :: ptr
319 'MPP_PSET_STACK_PUSH only works with Cray pointers.' )
321 end subroutine mpp_pset_stack_push
323 subroutine mpp_pset_stack_reset(pset)
324 type(mpp_pset_type),
intent(inout) :: pset
334 if( .NOT.pset%initialized )
call mpp_error( fatal, &
335 'MPP_PSET_STACK_RESET: called with uninitialized PSET.' )
337 end subroutine mpp_pset_stack_reset
339 subroutine mpp_pset_print_chksum_1d(pset, caller, array)
343 type(mpp_pset_type),
intent(in) :: pset
344 character(len=*),
intent(in) :: caller
345 real,
intent(in) :: array(:)
350 integer(LONG_KIND) :: chksum
352 if( .NOT.pset%initialized )
call mpp_error( fatal, &
353 'MPP_PSET_PRINT_CHKSUM: called with uninitialized PSET.' )
357 do_print = pe.EQ.mpp_root_pe()
361 write( errunit,
'(a,z18)' )trim(caller)//
' chksum=', chksum
366 end subroutine mpp_pset_print_chksum_1d
368 subroutine mpp_pset_print_chksum_2d(pset, caller, array)
369 type(mpp_pset_type),
intent(in) :: pset
370 character(len=*),
intent(in) :: caller
371 real,
intent(in) :: array(:,:)
372 real :: array1D( size(array) )
373 #ifdef use_CRI_pointers
374 pointer( p, array1d )
377 array1d = transfer( array, array1d )
380 end subroutine mpp_pset_print_chksum_2d
382 subroutine mpp_pset_print_chksum_3d(pset, caller, array)
383 type(mpp_pset_type),
intent(in) :: pset
384 character(len=*),
intent(in) :: caller
385 real,
intent(in) :: array(:,:,:)
386 real :: array1D( size(array) )
387 #ifdef use_CRI_pointers
388 pointer( p, array1d )
391 array1d = transfer( array, array1d )
394 end subroutine mpp_pset_print_chksum_3d
396 subroutine mpp_pset_print_chksum_4d(pset, caller, array)
397 type(mpp_pset_type),
intent(in) :: pset
398 character(len=*),
intent(in) :: caller
399 real,
intent(in) :: array(:,:,:,:)
400 real :: array1D( size(array) )
401 #ifdef use_CRI_pointers
402 pointer( p, array1d )
405 array1d = transfer( array, array1d )
408 end subroutine mpp_pset_print_chksum_4d
410 subroutine mpp_pset_print_stack_chksum( pset, caller )
411 type(mpp_pset_type),
intent(in) :: pset
412 character(len=*),
intent(in) :: caller
414 if( .NOT.pset%initialized )
call mpp_error( fatal, &
415 'MPP_PSET_PRINT_STACK_CHKSUM: called with uninitialized PSET.' )
417 pset%stack(1:pset%lstack) )
418 end subroutine mpp_pset_print_stack_chksum
421 function mpp_pset_root(pset)
422 logical :: mpp_pset_root
423 type(mpp_pset_type),
intent(in) :: pset
425 if( .NOT.pset%initialized )
call mpp_error( fatal, &
426 'MPP_PSET_ROOT: called with uninitialized PSET.' )
427 mpp_pset_root = pset%root
428 end function mpp_pset_root
430 function mpp_pset_numroots(pset)
432 integer :: mpp_pset_numroots
433 type(mpp_pset_type),
intent(in) :: pset
435 if( .NOT.pset%initialized )
call mpp_error( fatal, &
436 'MPP_PSET_NUMROOTS: called with uninitialized PSET.' )
437 mpp_pset_numroots =
size(pset%root_pelist)
438 end function mpp_pset_numroots
445 integer,
intent(in) :: npset
447 integer,
intent(in),
optional :: stacksize
448 integer,
intent(in),
optional :: pelist(:)
449 type(
mpi_comm),
intent(in),
optional :: comm
453 integer :: i, j, k, out_unit, errunit
454 integer,
allocatable :: my_pelist(:), root_pelist(:)
465 if(
present(pelist))
then
466 npes =
size(pelist(:))
470 if( mod(npes,npset).NE.0 )
then
471 write( text,
'(a,2i6)' ) &
472 'MPP_PSET_CREATE: PSET size (npset) must divide npes exactly:'// &
473 ' npset, npes=', npset, npes
478 allocate(my_pelist(0:npes-1) )
479 allocate(root_pelist(0:npes/npset-1) )
480 if(
present(pelist))
then
481 if(.not.
present(comm))
call mpp_error(fatal, &
482 'MPP_PSET_CREATE: when pelist is present, comm should also be present')
488 do i = 0,npes/npset-1
489 root_pelist(i) = my_pelist(npset*i)
491 write( out_unit,
'(a,i6)' )
'MPP_PSET_CREATE creating PSETs... npset=', npset
492 if(any(my_pelist == pe) )
then
493 if( pset%initialized )
call mpp_error( fatal, &
494 'MPP_PSET_CREATE: PSET already initialized!' )
496 allocate( pset%pelist(0:npes-1) )
497 allocate( pset%root_pelist(0:npes/npset-1) )
499 pset%pelist = my_pelist
501 pset%root_pelist = root_pelist
502 allocate( pset%pset(0:npset-1) )
503 do i = 0,npes/npset-1
507 if( pe.EQ.pset%pelist(k+j) )
then
508 pset%pset(:) = pset%pelist(k:k+npset-1)
510 pset%root_in_pset = pset%root_pelist(i)
512 pset%prev_in_pset = pset%pelist(k+npset-1)
514 pset%prev_in_pset = pset%pelist(k+j-1)
516 if( j.EQ.npset-1 )
then
517 pset%next_in_pset = pset%pelist(k)
519 pset%next_in_pset = pset%pelist(k+j+1)
525 pset%root = pe.EQ.pset%root_in_pset
529 pset%maxstack = 1000000
530 if(
PRESENT(stacksize) )pset%maxstack = stacksize
531 write( out_unit,
'(a,i8)' ) &
532 'MPP_PSET_CREATE: setting stacksize=', pset%maxstack
534 allocate( pset%stack(pset%maxstack) )
535 #ifdef use_CRI_pointers
536 pset%p_stack = loc(pset%stack)
539 pset%initialized = .true.
546 write( errunit,
'(a,4i6)' )
'MPP_PSET_CREATE: pe, root, next, prev=', &
547 pe, pset%root_in_pset, pset%next_in_pset, pset%prev_in_pset
548 write( errunit,* )
'PE ', pe,
' pset=', pset%pset(:)
549 write( out_unit,* )
'root pelist=', pset%root_pelist(:)
556 integer,
intent(out) :: pelist(:)
557 type(
mpi_comm),
intent(out),
optional :: comm
559 if( .NOT.pset%initialized )
call mpp_error( fatal, &
560 'MPP_PSET_GET_ROOT_PELIST: called with uninitialized PSET.' )
561 if(
size(pelist).NE.
size(pset%root_pelist) )
then
562 write( text,
'(a,2i6)' ) &
563 'pelist argument has wrong size: requested, actual=', &
564 size(pelist),
size(pset%root_pelist)
565 call mpp_error( fatal,
'MPP_PSET_GET_ROOT_PELIST: '//text )
567 pelist(:) = pset%root_pelist(:)
568 if(
PRESENT(comm) )
then
573 end module mpp_pset_mod
subroutine mpp_sync_self(pelist, check, request, msg_size, msg_type)
This is to check if current PE's outstanding puts are complete but we can't use shmem_fence because w...
integer function stdout()
This function returns the current standard fortran unit numbers for output.
subroutine mpp_set_current_pelist(pelist, no_sync)
Set context pelist.
integer function stderr()
This function returns the current standard fortran unit numbers for error messages.
integer function mpp_npes()
Returns processor count for current pelist.
integer function mpp_pe()
Returns processor ID.
subroutine mpp_sync(pelist, do_self)
Synchronize PEs in list.
Calculate parallel checksums.
Receive data from another PE.
Send data to a receiving PE.
subroutine, public mpp_pset_create(npset, pset, stacksize, pelist, comm)
Create a pset.
subroutine, public mpp_pset_get_root_pelist(pset, pelist, comm)
Get the root pelist of a pset.
Declare a pelist. The two flavors of this subroutine differ in the type of their comm/commID argument...
Get the current pelist. The two flavors of this subroutine differ in the type of their comm/commID ar...