FMS  2026.01.01-dev
Flexible Modeling System
mpp_pset.F90
1 !***********************************************************************
2 !* Apache License 2.0
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* Licensed under the Apache License, Version 2.0 (the "License");
7 !* you may not use this file except in compliance with the License.
8 !* You may obtain a copy of the License at
9 !*
10 !* http://www.apache.org/licenses/LICENSE-2.0
11 !*
12 !* FMS is distributed in the hope that it will be useful, but WITHOUT
13 !* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14 !* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 !* PARTICULAR PURPOSE. See the License for the specific language
16 !* governing permissions and limitations under the License.
17 !***********************************************************************
18 #ifdef test_mpp_pset
19 !PSET_DEBUG is always turned on in the test program
20 #define PSET_DEBUG
21 #endif
22 
23 !> @defgroup mpp_pset_mod mpp_pset_mod
24 !> @ingroup mpp
25 !> @brief Handles PSETs(Persistent Shared-memory Execution Threads) for mpp modules
26 !!
27 !! @author V. Balaji (v.balaji@noaa.gov)
28 !! @date 2006-01-15
29 
30 !> @addtogroup mpp_pset_mod mpp_pset_mod
31 !> @{
32 module mpp_pset_mod
33 #include <fms_platform.h>
34 
35 #ifdef use_libMPI
36  use mpi_f08, only: mpi_comm
37 #else
38  use gfdl_nompi_f08, only: mpi_comm
39 #endif
40 
41  use mpp_mod, only: mpp_pe, mpp_npes, mpp_root_pe, mpp_send, mpp_recv, &
42  mpp_sync, mpp_error, fatal, warning, stdout, stderr, mpp_chksum, &
44  mpp_init, comm_tag_1, comm_tag_2, comm_tag_3, mpp_sync_self
45  implicit none
46  private
47 
48 !private variables
49  integer :: pe
50  logical :: verbose=.false.
51  logical :: module_is_initialized=.false.
52  character(len=256) :: text
53 !generic interfaces
55  module procedure mpp_pset_broadcast_ptr_scalar
56  module procedure mpp_pset_broadcast_ptr_array
57  end interface
58  interface mpp_send_ptr
59  module procedure mpp_send_ptr_scalar
60  module procedure mpp_send_ptr_array
61  end interface
62  interface mpp_recv_ptr
63  module procedure mpp_recv_ptr_scalar
64  module procedure mpp_recv_ptr_array
65  end interface
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
71  end interface
72 !public type
73  type :: mpp_pset_type
74  private
75  integer :: npset !number of PSETs
76  integer :: next_in_pset, prev_in_pset !next and prev PE in PSET (cyclic)
77  integer :: root_in_pset !PE designated to be the root within PSET
78  logical :: root !true if you are the root PSET
79  integer :: pos !position of current PE within pset
80 !stack is allocated by root
81 !it is then mapped to mpp_pset_stack by mpp_pset_broadcast_ptr
82  real, allocatable :: stack(:)
83  integer, allocatable :: pelist(:) !base PElist
84  integer, allocatable :: root_pelist(:) !a PElist of all the roots
85  integer, allocatable :: pset(:) !PSET IDs
86  integer(POINTER_KIND) :: p_stack
87  integer :: lstack, maxstack, hiWM !current stack length, max, hiWM
88  type(mpi_comm) :: comm
89  character(len=32) :: name
90  logical :: initialized=.false.
91  end type mpp_pset_type
92 !public types
93  public :: mpp_pset_type
94 !public variables
95 !public member functions
96  public :: mpp_pset_create, mpp_pset_sync, mpp_pset_broadcast, &
97  mpp_pset_broadcast_ptr, mpp_pset_check_ptr, mpp_pset_segment_array, &
98  mpp_pset_stack_push, mpp_pset_stack_reset, mpp_pset_print_chksum, &
99  mpp_pset_delete, mpp_pset_root, mpp_pset_numroots, mpp_pset_init, &
100  mpp_pset_get_root_pelist, mpp_pset_print_stack_chksum
101 
102 
103 contains
104  subroutine mpp_pset_init
105  module_is_initialized = .true.
106  end subroutine mpp_pset_init
107 
108  subroutine mpp_pset_delete(pset)
109  type(mpp_pset_type), intent(inout) :: pset
110  integer :: out_unit
111 
112  out_unit = stdout()
113  if( .NOT.pset%initialized )call mpp_error( fatal, &
114  'MPP_PSET_DELETE: called with uninitialized PSET.' )
115 !deallocate arrays...
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
122 !... and set status flag
123  pset%initialized = .false.
124  end subroutine mpp_pset_delete
125 
126  subroutine mpp_send_ptr_scalar( ptr, pe )
127  integer(POINTER_KIND), intent(in) :: ptr
128  integer, intent(in) :: pe
129 
130 !currently only wraps mpp_send
131 !on some architectures, mangling might occur
132  call mpp_send( ptr, pe, tag=comm_tag_1 )
133  end subroutine mpp_send_ptr_scalar
134 
135  subroutine mpp_send_ptr_array( ptr, pe )
136  integer(POINTER_KIND), intent(in) :: ptr(:)
137  integer, intent(in) :: pe
138 
139 !currently only wraps mpp_send
140 !on some architectures, mangling might occur
141  call mpp_send( ptr, size(ptr), pe, tag=comm_tag_2 )
142  end subroutine mpp_send_ptr_array
143 
144  subroutine mpp_recv_ptr_scalar( ptr, pe )
145  integer(POINTER_KIND), intent(inout) :: ptr
146  integer, intent(in) :: pe
147 
148  call mpp_recv( ptr, pe, tag=comm_tag_1 )
149  return
150  end subroutine mpp_recv_ptr_scalar
151 
152  subroutine mpp_recv_ptr_array( ptr, pe )
153  integer(POINTER_KIND), intent(inout) :: ptr(:)
154  integer, intent(in) :: pe
155 
156  call mpp_recv( ptr, size(ptr), pe, tag=comm_tag_2 )
157  return
158  end subroutine mpp_recv_ptr_array
159 
160  subroutine mpp_pset_sync(pset)
161 !this is a replacement for mpp_sync, doing syncs across
162 !shared arrays without calling mpp_sync
163  type(mpp_pset_type), intent(in) :: pset
164 
165  if( .NOT.pset%initialized )call mpp_error( fatal, &
166  'MPP_PSET_SYNC: called with uninitialized PSET.' )
167 !currently does mpp_sync!!! slow!!!
168 !try and make a lightweight pset sync
169  call mpp_sync
170  end subroutine mpp_pset_sync
171 
172  subroutine mpp_pset_broadcast(pset,a)
173 !broadcast value on the root to its sub-threads
174  type(mpp_pset_type), intent(in) :: pset
175  real, intent(inout) :: a
176  integer :: i
177 
178  if( .NOT.pset%initialized )call mpp_error( fatal, &
179  'MPP_PSET_BROADCAST: called with uninitialized PSET.' )
180  if( pset%root )then
181  do i = 1,pset%npset-1
182  call mpp_send( a, pset%pset(i), tag=comm_tag_3 )
183  end do
184  else
185  call mpp_recv( a, pset%root_in_pset, tag=comm_tag_3 )
186  end if
187  call mpp_pset_sync(pset)
188  end subroutine mpp_pset_broadcast
189 
190  subroutine mpp_pset_broadcast_ptr_scalar(pset,ptr)
191 !create a shared array by broadcasting pointer
192 !root allocates memory and passes pointer in
193 !on return all other PSETs will have the pointer to a shared object
194  type(mpp_pset_type), intent(in) :: pset
195  integer(POINTER_KIND), intent(inout) :: ptr
196  integer :: i
197 
198  if( .NOT.pset%initialized )call mpp_error( fatal, &
199  'MPP_PSET_BROADCAST_PTR: called with uninitialized PSET.' )
200  if( pset%root )then
201  do i = 1,pset%npset-1
202  call mpp_send_ptr( ptr, pset%pset(i) )
203  end do
204  else
205  call mpp_recv_ptr( ptr, pset%root_in_pset )
206  end if
207  call mpp_sync_self()
208  end subroutine mpp_pset_broadcast_ptr_scalar
209 
210  subroutine mpp_pset_broadcast_ptr_array(pset,ptr)
211 !create a shared array by broadcasting pointer
212 !root allocates memory and passes pointer in
213 !on return all other PSETs will have the pointer to a shared object
214  type(mpp_pset_type), intent(in) :: pset
215  integer(POINTER_KIND), intent(inout) :: ptr(:)
216  integer :: i
217 
218  if( .NOT.pset%initialized )call mpp_error( fatal, &
219  'MPP_PSET_BROADCAST_PTR: called with uninitialized PSET.' )
220  if( pset%root )then
221  do i = 1,pset%npset-1
222  call mpp_send_ptr( ptr, pset%pset(i) )
223  end do
224  else
225  call mpp_recv_ptr( ptr, pset%root_in_pset )
226  end if
227  call mpp_sync_self()
228 
229  end subroutine mpp_pset_broadcast_ptr_array
230 
231  subroutine mpp_pset_check_ptr(pset,ptr)
232 !checks if the supplied pointer is indeed shared
233  type(mpp_pset_type), intent(in) :: pset
234 #ifdef use_CRI_pointers
235  real :: dummy
236  pointer( ptr, dummy )
237 #else
238  integer(POINTER_KIND), intent(in) :: ptr
239 #endif
240 #ifdef PSET_DEBUG
241  integer(POINTER_KIND) :: p
242  integer :: i
243  if( .NOT.pset%initialized )call mpp_error( fatal, &
244  'MPP_PSET_CHECK_PTR: called with uninitialized PSET.' )
245 !check if this is a shared pointer
246  p = ptr
247  if( pset%root )then
248  do i = 1,pset%npset-1
249  call mpp_send_ptr( p, pset%pset(i) )
250  end do
251  else
252  call mpp_recv_ptr( p, pset%root_in_pset )
253  end if
254  call mpp_pset_sync(pset)
255  if( p.NE.ptr )call mpp_error( fatal, &
256  'MPP_PSET_CHECK_PTR: pointers do not match!' )
257 #else
258 !do nothing if the debug CPP flag isn't on
259 #endif
260  end subroutine mpp_pset_check_ptr
261 
262  subroutine mpp_pset_segment_array( pset, ls, le, lsp, lep )
263 !given input indices ls, le, returns indices lsp, lep
264 !so that segments span the range ls:le with no overlaps.
265 !attempts load balance: also some PSETs might get lsp>lep
266 !so that do-loops will be null
267  type(mpp_pset_type), intent(in) :: pset
268  integer, intent(in) :: ls, le
269  integer, intent(out) :: lsp, lep
270  integer :: i
271 
272  if( .NOT.pset%initialized )call mpp_error( fatal, &
273  'MPP_PSET_SEGMENT_ARRAY: called with uninitialized PSET.' )
274 #ifdef PSET_DEBUG
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
279  call mpp_error( warning, text )
280  end if
281 #endif
282  lep = ls-1 !initialize so that lsp is correct on first pass
283  do i = 0,pset%pos
284  lsp = lep + 1
285  lep = lsp + ceiling( real(le-lsp+1)/(pset%npset-i) ) - 1
286  end do
287  end subroutine mpp_pset_segment_array
288 
289  subroutine mpp_pset_stack_push( pset, ptr, len )
290 !mpp_malloc specialized for shared arrays
291 !len is the length of the required array
292 !lstack is the stack already in play
293 !user should zero lstack (call mpp_pset_stack_reset) when the stack is to be cleared
294  type(mpp_pset_type), intent(inout) :: pset
295  integer, intent(in) :: len
296 #ifdef use_CRI_pointers
297  real :: dummy
298  pointer( ptr, dummy )
299  real :: stack(pset%maxstack)
300  pointer( p, stack )
301 
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
309  call mpp_error( fatal, text )
310  end if
311  p = pset%p_stack !point stack to shared stack pointer
312  ptr = loc( stack(pset%lstack+1) )
313  call mpp_pset_check_ptr(pset,ptr) !make sure ptr is the same across PSETs
314  pset%lstack = pset%lstack + len
315  pset%hiWM = max( pset%hiWM, pset%lstack )
316 #else
317  integer(POINTER_KIND), intent(out) :: ptr
318  call mpp_error( fatal, &
319  'MPP_PSET_STACK_PUSH only works with Cray pointers.' )
320 #endif
321  end subroutine mpp_pset_stack_push
322 
323  subroutine mpp_pset_stack_reset(pset)
324  type(mpp_pset_type), intent(inout) :: pset
325 !reset stack... will reuse any temporary arrays! USE WITH CARE
326 !next few lines are to zero stack contents...
327 !but it's better noone tries to use uninitialized stack variables!
328 ! integer :: l1, l2
329 ! real :: mpp_pset_stack(maxstack)
330 ! pointer( p_mpp_pset_stack, mpp_pset_stack )
331 ! p_mpp_pset_stack = ptr_mpp_pset_stack
332 ! call mpp_pset_array_segment( 1, lstack, l1, l2 )
333 ! mpp_pset_stack(l1:l2) = 0.
334  if( .NOT.pset%initialized )call mpp_error( fatal, &
335  'MPP_PSET_STACK_RESET: called with uninitialized PSET.' )
336  pset%lstack = 0
337  end subroutine mpp_pset_stack_reset
338 
339  subroutine mpp_pset_print_chksum_1d(pset, caller, array)
340 !print a checksum of an array
341 !pass the whole domain seen by root PSET
342 !add lines to check on shared array?
343  type(mpp_pset_type), intent(in) :: pset
344  character(len=*), intent(in) :: caller
345  real, intent(in) :: array(:)
346 
347 #ifdef PSET_DEBUG
348  integer :: errunit
349  logical :: do_print
350  integer(LONG_KIND) :: chksum
351 
352  if( .NOT.pset%initialized )call mpp_error( fatal, &
353  'MPP_PSET_PRINT_CHKSUM: called with uninitialized PSET.' )
354  errunit = stderr()
355 
356  if( pset%root )then
357  do_print = pe.EQ.mpp_root_pe() !set to T to print from all PEs
358  call mpp_set_current_pelist(pset%root_pelist)
359  chksum = mpp_chksum( array )
360  if( do_print ) &
361  write( errunit, '(a,z18)' )trim(caller)//' chksum=', chksum
362  end if
363  call mpp_set_current_pelist(pset%pelist)
364 #endif
365  return
366  end subroutine mpp_pset_print_chksum_1d
367 
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 )
375  p = loc(array)
376 #else
377  array1d = transfer( array, array1d )
378 #endif
379  call mpp_pset_print_chksum(pset, caller, array1d)
380  end subroutine mpp_pset_print_chksum_2d
381 
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(:,:,:) !overload for other ranks
386  real :: array1D( size(array) )
387 #ifdef use_CRI_pointers
388  pointer( p, array1d )
389  p = loc(array)
390 #else
391  array1d = transfer( array, array1d )
392 #endif
393  call mpp_pset_print_chksum(pset, caller, array1d)
394  end subroutine mpp_pset_print_chksum_3d
395 
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 )
403  p = loc(array)
404 #else
405  array1d = transfer( array, array1d )
406 #endif
407  call mpp_pset_print_chksum(pset, caller, array1d)
408  end subroutine mpp_pset_print_chksum_4d
409 
410  subroutine mpp_pset_print_stack_chksum( pset, caller )
411  type(mpp_pset_type), intent(in) :: pset
412  character(len=*), intent(in) :: caller
413 
414  if( .NOT.pset%initialized )call mpp_error( fatal, &
415  'MPP_PSET_PRINT_STACK_CHKSUM: called with uninitialized PSET.' )
416  call mpp_pset_print_chksum( pset, trim(caller)//' stack', &
417  pset%stack(1:pset%lstack) )
418  end subroutine mpp_pset_print_stack_chksum
419 
420 !accessor functions
421  function mpp_pset_root(pset)
422  logical :: mpp_pset_root
423  type(mpp_pset_type), intent(in) :: pset
424 
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
429 
430  function mpp_pset_numroots(pset)
431 !necessary to export root_pelist: caller needs to pre-allocate
432  integer :: mpp_pset_numroots
433  type(mpp_pset_type), intent(in) :: pset
434 
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
439 
440  !> @brief Create a pset
441  !!
442  !! This must be called by all PEs in the parent pelist.
443  !! mpset must be an exact divisor of npes.
444  subroutine mpp_pset_create(npset,pset,stacksize,pelist,comm)
445  integer, intent(in) :: npset !number of PSETs per set
446  type(mpp_pset_type), intent(inout) :: pset
447  integer, intent(in), optional :: stacksize
448  integer, intent(in), optional :: pelist(:)
449  type(mpi_comm), intent(in), optional :: comm
450 
451  integer :: npes
452  type(mpi_comm) :: my_comm
453  integer :: i, j, k, out_unit, errunit
454  integer, allocatable :: my_pelist(:), root_pelist(:)
455 
456  call mpp_init()
457  call mpp_pset_init()
458 
459 #ifdef PSET_DEBUG
460  verbose=.true.
461 #endif
462  out_unit = stdout()
463  errunit = stderr()
464  pe = mpp_pe()
465  if(present(pelist)) then
466  npes = size(pelist(:))
467  else
468  npes = mpp_npes()
469  endif
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
474  call mpp_error( fatal, text )
475  end if
476 
477  !configure out root_pelist
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')
483  my_pelist = pelist
484  my_comm = comm
485  else
486  call mpp_get_current_pelist(my_pelist, comm = my_comm)
487  endif
488  do i = 0,npes/npset-1
489  root_pelist(i) = my_pelist(npset*i)
490  enddo
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!' )
495  pset%npset = npset
496  allocate( pset%pelist(0:npes-1) )
497  allocate( pset%root_pelist(0:npes/npset-1) )
498  pset%comm = my_comm
499  pset%pelist = my_pelist
500 !create the root PElist
501  pset%root_pelist = root_pelist
502  allocate( pset%pset(0:npset-1) )
503  do i = 0,npes/npset-1
504  k = npset*i
505 !designate the root PE, next PE, prev PE
506  do j = 0,npset-1
507  if( pe.EQ.pset%pelist(k+j) )then
508  pset%pset(:) = pset%pelist(k:k+npset-1)
509  pset%pos = j
510  pset%root_in_pset = pset%root_pelist(i)
511  if( j.EQ.0 )then
512  pset%prev_in_pset = pset%pelist(k+npset-1)
513  else
514  pset%prev_in_pset = pset%pelist(k+j-1)
515  end if
516  if( j.EQ.npset-1 )then
517  pset%next_in_pset = pset%pelist(k)
518  else
519  pset%next_in_pset = pset%pelist(k+j+1)
520  end if
521  end if
522  end do
523  end do
524 
525  pset%root = pe.EQ.pset%root_in_pset
526 
527 !stack
528  pset%hiWM = 0 !initialize hi-water-mark
529  pset%maxstack = 1000000 !default
530  if( PRESENT(stacksize) )pset%maxstack = stacksize
531  write( out_unit,'(a,i8)' ) &
532  'MPP_PSET_CREATE: setting stacksize=', pset%maxstack
533  if( pset%root )then
534  allocate( pset%stack(pset%maxstack) )
535 #ifdef use_CRI_pointers
536  pset%p_stack = loc(pset%stack)
537 #endif
538  end if
539  pset%initialized = .true. !must be called before using pset
540  call mpp_pset_broadcast_ptr(pset,pset%p_stack)
541  endif
542 
543  call mpp_declare_pelist(root_pelist)
544 
545  if( verbose )then
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(:)
550  end if
551  end subroutine mpp_pset_create
552 
553  !> @brief Get the root pelist of a pset
554  subroutine mpp_pset_get_root_pelist(pset,pelist,comm)
555  type(mpp_pset_type), intent(in) :: pset
556  integer, intent(out) :: pelist(:)
557  type(mpi_comm), intent(out), optional :: comm
558 
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 )
566  end if
567  pelist(:) = pset%root_pelist(:)
568  if( PRESENT(comm) )then
569  comm = pset%comm
570  end if
571  end subroutine mpp_pset_get_root_pelist
572 
573 end module mpp_pset_mod
574 !> @}
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.
Definition: mpp_util.inc:42
subroutine mpp_set_current_pelist(pelist, no_sync)
Set context pelist.
Definition: mpp_util.inc:514
integer function stderr()
This function returns the current standard fortran unit numbers for error messages.
Definition: mpp_util.inc:50
integer function mpp_npes()
Returns processor count for current pelist.
Definition: mpp_util.inc:420
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:406
subroutine mpp_sync(pelist, do_self)
Synchronize PEs in list.
Calculate parallel checksums.
Definition: mpp.F90:1262
Error handler.
Definition: mpp.F90:385
Receive data from another PE.
Definition: mpp.F90:999
Send data to a receiving PE.
Definition: mpp.F90:1066
subroutine, public mpp_pset_create(npset, pset, stacksize, pelist, comm)
Create a pset.
Definition: mpp_pset.F90:445
subroutine, public mpp_pset_get_root_pelist(pset, pelist, comm)
Get the root pelist of a pset.
Definition: mpp_pset.F90:555
Declare a pelist. The two flavors of this subroutine differ in the type of their comm/commID argument...
Definition: mpp.F90:424
Get the current pelist. The two flavors of this subroutine differ in the type of their comm/commID ar...
Definition: mpp.F90:433