LCOV - code coverage report
Current view: | top level - utils - spmd_utils.F90 (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 122 | 478 | 25.5 %
Date: | 2024-12-17 22:39:59 |  | Functions: | 3 | 12 | 25.0 %

              Line data    Source code
           1             : module spmd_utils
           2             :
           3             : !-----------------------------------------------------------------------
           4             : !
           5             : ! Purpose: This module is responsible for miscellaneous SPMD utilities
           6             : !          and information that are shared between dynamics and
           7             : !          physics packages.
           8             : !
           9             : ! Author:
          10             : !   Original routines:  CMS
          11             : !   Module:             T. Henderson, December 2003
          12             : !   swap routines:      P. Worley
          13             : !   fc routines:        P. Worley
          14             : !   SMP node id logic:  P. Worley
          15             : !
          16             : ! $Id$
          17             : !
          18             : !-----------------------------------------------------------------------
          19             :
          20             : !
          21             : ! Performance bug work around for Gemini interconnect
          22             : !
          23             : #ifdef _NO_MPI_RSEND
          24             : #define mpi_rsend mpi_send
          25             : #define mpi_irsend mpi_isend
          26             : #endif
          27             :
          28             : !-----------------------------------------------------------------------
          29             : !- use statements ------------------------------------------------------
          30             : !-----------------------------------------------------------------------
          31             :    use shr_kind_mod,     only: r8 => shr_kind_r8
          32             :    use cam_abortutils,   only: endrun
          33             :
          34             : #if ( defined SPMD )
          35             :    use mpishorthand, only: mpiint, mpii8, mpichar, mpilog, mpipk,      &
          36             :                            mpic16, mpir8, mpir4, mpicom, mpimax
          37             : #endif
          38             :    use cam_logfile,  only: iulog
          39             :
          40             : !-----------------------------------------------------------------------
          41             : !- module boilerplate --------------------------------------------------
          42             : !-----------------------------------------------------------------------
          43             :    implicit none
          44             :    include 'mpif.h'
          45             :    private                   ! Make the default access private
          46             :    save
          47             : !
          48             : ! Forward from mpishorthand.F with the idea of phasing out use of and removing that file
          49             : !
          50             : #ifndef SPMD
          51             :
          52             :    integer :: mpir8
          53             : #endif
          54             : !
          55             : !  Forward these from mpif.h (or mpi.mod), the idea being that this should
          56             : !  be the only module that uses mpi directly, the rest of cam should use spmd_utils
          57             : !
          58             :    public :: mpi_max_processor_name, mpi_max_error_string, mpi_error,        &
          59             :              mpi_integer, mpi_integer8, mpi_character, mpi_double_precision, &
          60             :              mpi_logical, mpi_real8, mpi_real4, mpi_complex16,               &
          61             :              mpi_packed, mpi_tag_ub, mpi_info_null,                          &
          62             :              mpi_comm_null, mpi_group_null, mpi_undefined,                   &
          63             :              mpi_status_size, mpi_success, mpi_status_ignore,                &
          64             :              mpi_max, mpi_min, mpi_sum, mpi_band, mpir8
          65             : #if ( defined SPMD )
          66             :    public :: mpi_address_kind
          67             : #endif
          68             :
          69             : !-----------------------------------------------------------------------
          70             : ! Public interfaces ----------------------------------------------------
          71             : !-----------------------------------------------------------------------
          72             :    public pair      ! $$$here...  originally from eul|sld/spmd_dyn
          73             :    public ceil2     ! $$$here...  originally from eul|sld/spmd_dyn
          74             :    public spmdinit
          75             :    public spmd_utils_readnl
          76             : #if ( defined SPMD )
          77             :    public swapm
          78             :    public fc_gatherv
          79             :    public fc_gathervr4
          80             :    public fc_gathervint
          81             :    public fc_gathervc
          82             :    public altalltoallv
          83             : #endif
          84             :
          85             : !-----------------------------------------------------------------------
          86             : ! Public communication types--------------------------------------------
          87             : !-----------------------------------------------------------------------
          88             :    type, public :: spmd_col_trans
          89             :       ! spmd_col_trans holds information for setting up a communications pattern
          90             :       integer :: source_task
          91             :       integer :: source_index
          92             :       integer :: dest_task
          93             :       integer :: dest_index
          94             :       integer :: mpi_tag
          95             :    end type spmd_col_trans
          96             :
          97             :    type, public :: column_redist_t
          98             :       ! column_redist_t holds information needed to redistribute columns
          99             :       ! Fields used for both send and receive
         100             :       integer          :: mpi_comm = MPI_COMM_NULL  ! Comm for dest tasks
         101             :       integer          :: recv_iam = -1             ! rank in mpi_comm
         102             :       integer          :: recv_master_id = -1       ! rank of mpi_comm 'master'
         103             :       integer          :: max_nflds = 0             ! max fields at one time
         104             :       integer          :: num_rounds = 0            ! # of field sum blocks
         105             :       integer, pointer :: dest_tasks(:) => NULL()   ! Destination tasks
         106             :       integer, pointer :: col_starts(:) => NULL()   ! Global start col per dest
         107             :       integer, pointer :: num_rflds(:) => NULL()    ! # flds per round
         108             :       ! Data used by receiving tasks
         109             :       integer, pointer :: recv_cnts(:) => NULL()    ! # cols from each PE
         110             :       integer, pointer :: recv_disps(:) => NULL()   ! col offsets from each PE
         111             :       integer, pointer :: recv_reorder(:) => NULL() ! Reordering after receive
         112             :       ! Data used by sending tasks
         113             :       integer          :: strt_nfld = -1            ! first field for this task
         114             :       integer          :: my_nflds = 0              ! # fields for this task
         115             :       integer, pointer :: task_sizes(:) => NULL()   ! # of task cols per dest
         116             :       integer, pointer :: task_indices(:) => NULL() ! Global index for each col
         117             :       integer, pointer :: send_disps(:) => NULL()   ! cols offsets to each PE
         118             :       integer, pointer :: send_reorder(:) => NULL() ! Reordering before send
         119             :    end type column_redist_t
         120             :
         121             : !-----------------------------------------------------------------------
         122             : ! Public data ----------------------------------------------------------
         123             : !-----------------------------------------------------------------------
         124             : ! physics-motivated dynamics decomposition request
         125             :    logical, parameter :: def_mirror = .false.                 ! default
         126             :    logical, public    :: phys_mirror_decomp_req = def_mirror
         127             :                          ! flag indicating whether latitudes and their
         128             :                          ! reflections across the equator should be
         129             :                          ! assigned to consecutive processes
         130             :
         131             : #if (defined SPMD)
         132             :    public :: mpicom
         133             :    public :: mpichar
         134             : #else
         135             :    integer, public              :: mpicom
         136             :    integer, public              :: mpichar
         137             : #endif
         138             :    logical, public              :: masterproc
         139             :    integer, public              :: masterprocid
         140             :    integer, public              :: iam
         141             :    integer, public              :: npes
         142             :    integer, public              :: nsmps
         143             :    integer, allocatable, public :: proc_smp_map(:)
         144             :    ! DEFAULT_MASTERPROC is the value of iam which is assigned masterproc duties
         145             :    integer, parameter           :: DEFAULT_MASTERPROC = 0
         146             :    ! spmd_col_trans_mpi_type is a handle to be used for column reordering
         147             :    integer, public, protected   :: spmd_col_trans_mpi_type
         148             :
         149             : !-----------------------------------------------------------------------
         150             : ! Private data ---------------------------------------------------------
         151             : !-----------------------------------------------------------------------
         152             : ! Swap communication protocol options (reduced set):
         153             : !  3, 5:                  nonblocking send
         154             : !  2, 3, 4, 5:            nonblocking receive
         155             : !  4, 5:                  ready send
         156             :    integer, private, parameter :: min_comm_protocol =  2
         157             :    integer, private, parameter :: max_comm_protocol =  5
         158             :    integer, private, parameter :: def_comm_protocol =  4        ! default
         159             :    integer, public :: swap_comm_protocol = def_comm_protocol
         160             :
         161             : ! Swap communication maximum request count:
         162             : ! = -1,0: do not limit number of outstanding send/receive requests
         163             : !    > 0: do not allow more than swap_comm_maxreq outstanding
         164             : !         nonblocking send requests or nonblocking receive requests
         165             :    integer, private, parameter :: def_comm_maxreq = 128        ! default
         166             :    integer, public :: swap_comm_maxreq = def_comm_maxreq
         167             :
         168             : ! Flow-controlled gather option:
         169             : !   < 0: use MPI_Gather
         170             : !  >= 0: use point-to-point with handshaking messages and
         171             : !        preposting receive requests up to
         172             : !         min(max(1,fc_gather_flow_cntl),max_gather_block_size)
         173             : !        ahead
         174             :    integer, private, parameter :: max_gather_block_size = 64 ! max and default
         175             :    integer, public :: fc_gather_flow_cntl = max_gather_block_size
         176             :
         177             : !-----------------------------------------------------------------------
         178             : ! Subroutines and functions --------------------------------------------
         179             : !-----------------------------------------------------------------------
         180             : contains
         181             :
         182             : !========================================================================
         183             :
         184           0 :    integer function pair(np,p,k)
         185             :
         186             :       integer np,p,k,q
         187           0 :       q = ieor(p,k)
         188           0 :       if(q.gt.np-1) then
         189             :          pair = -1
         190             :       else
         191           0 :          pair = q
         192             :       endif
         193             :       return
         194             :
         195             :    end function pair
         196             :
         197             : !========================================================================
         198             :
         199           0 :   integer function ceil2(n)
         200             :      integer n,p
         201           0 :      p=1
         202           0 :      do while(p.lt.n)
         203           0 :         p=p*2
         204             :      enddo
         205           0 :      ceil2=p
         206             :      return
         207             :   end function ceil2
         208             :
         209             : !========================================================================
         210             :
         211        1536 :   subroutine spmdinit( mpicom_atm )
         212             :     !-----------------------------------------------------------------------
         213             :     !
         214             :     ! Purpose: MPI initialization routine:
         215             :     !
         216             :     ! Method: get number of cpus, processes, tids, etc
         217             :     !         dynamics and physics decompositions are set up later
         218             :     !
         219             :     ! Author: CCM Core Group
         220             :     !
         221             :     !-----------------------------------------------------------------------
         222             :
         223             :     implicit none
         224             :     integer, intent(in) :: mpicom_atm
         225             :
         226             : #if ( defined SPMD )
         227             :     !
         228             :     ! Local workspace
         229             :     !
         230             :     integer i,j,c             ! indices
         231             :     integer npthreads         ! thread status
         232             :     integer ier               ! return error status
         233             :     integer length            ! length of name
         234             :     integer max_len           ! maximum name length
         235        1536 :     integer, allocatable :: lengths(:)! max lengths of names for use in gatherv
         236        1536 :     integer, allocatable :: displs(:) ! offsets for use in gatherv
         237             :     logical done
         238        1536 :     character, allocatable                             :: proc_name(:)  ! processor name, this task
         239        1536 :     character, allocatable                             :: proc_names(:) ! processor names, all tasks
         240             :     character(len=mpi_max_processor_name)              :: tmp_name      ! temporary storage
         241        1536 :     character(len=mpi_max_processor_name), allocatable :: smp_names(:)  ! SMP name
         242             :     logical mpi_running       ! returned value indicates if MPI_INIT has been called
         243             :     ! For creating new MPI type for column info transfer
         244             :     integer                        :: h1, hind
         245             :     integer                        :: ierr
         246             :     integer(kind=MPI_ADDRESS_KIND) :: offsets(6)   ! For new MPI types
         247             :     integer                        :: origtypes(6) ! For new MPI types
         248             :     integer(kind=MPI_ADDRESS_KIND) :: extent       ! For new MPI types
         249             :     type(spmd_col_trans)           :: dummy_loc(2) ! For new MPI types
         250             :     type(spmd_col_trans)           :: col_trans_type_temp
         251             :
         252             :     !---------------------------------------------------------------------------
         253             :     !
         254             :     ! Determine CAM MPI communicator group
         255             :     !
         256        1536 :     mpicom  = mpicom_atm
         257             :     !
         258             :     ! Set mpishorthand variables.  Need to set as variables rather than parameters since
         259             :     ! some MPI implementations set values for MPI tags at run time
         260             :     !
         261        1536 :     mpiint  = mpi_integer
         262        1536 :     mpii8   = mpi_integer8
         263        1536 :     mpichar = mpi_character
         264        1536 :     mpilog  = mpi_logical
         265        1536 :     mpir4   = mpi_real4
         266        1536 :     mpir8   = mpi_real8
         267        1536 :     mpic16  = mpi_complex16
         268        1536 :     mpipk   = mpi_packed
         269        1536 :     mpimax  = mpi_max
         270             :     !
         271             :     ! Get my id
         272             :     !
         273        1536 :     call mpi_comm_rank (mpicom, iam, ier)
         274        1536 :     masterprocid = DEFAULT_MASTERPROC
         275        1536 :     if (iam == DEFAULT_MASTERPROC) then
         276           2 :        masterproc = .true.
         277             :     else
         278        1534 :        masterproc = .false.
         279             :     end if
         280             :     !
         281             :     ! Get number of processors
         282             :     !
         283        1536 :     max_len = mpi_max_processor_name
         284        1536 :     call mpi_comm_size (mpicom, npes, ier)
         285        4608 :     allocate ( displs(npes) )
         286        3072 :     allocate ( lengths(npes) )
         287        3072 :     allocate ( proc_name(max_len) )
         288        3072 :     allocate ( proc_names(max_len*npes) )
         289             :
         290             :     !
         291             :     ! Get processor names and send to root.
         292             :     !
         293        1536 :     call mpi_get_processor_name (tmp_name, length, ier)
         294      196608 :     proc_name(:) = ' '
         295       12288 :     do i = 1, length
         296       12288 :        proc_name(i) = tmp_name(i:i)
         297             :     end do
         298             :
         299   149816832 :     proc_names(:) = ' '
         300     1181184 :     lengths(:) = max_len
         301     1181184 :     do i=1,npes
         302     1181184 :        displs(i) = (i-1)*max_len
         303             :     enddo
         304             :     call fc_gathervc (proc_name,  max_len, mpichar, &
         305             :                       proc_names, lengths, displs, mpichar, &
         306        1536 :                       0, mpicom, flow_cntl=-1)
         307        1536 :     if (masterproc) then
         308           2 :        write(iulog,*) npes, 'pes participating in computation'
         309           2 :        write(iulog,*) '-----------------------------------'
         310           2 :        write(iulog,*) 'TASK#  NAME'
         311         516 :        do i=0,min(npes-1,256)  ! dont print too many of these
         312       65792 :           do c=1,max_len
         313       65792 :              tmp_name(c:c) = proc_names(i*max_len+c)
         314             :           enddo
         315         516 :           write(iulog,'(i3,2x,a)') i,trim(tmp_name)
         316             :        end do
         317           2 :        if(npes-1>256) then
         318           2 :           write(iulog,*) '... list truncated at 256'
         319             :        end if
         320             :     end if
         321             :     !
         322             :     ! Identify SMP nodes and process/SMP mapping.
         323             :     ! (Assume that processor names are SMP node names on SMP clusters.)
         324             :     !
         325        4608 :     allocate ( proc_smp_map(0:npes-1) )
         326        1536 :     if (masterproc) then
         327           6 :        allocate ( smp_names(0:npes-1) )
         328        1538 :        smp_names(:) = ' '
         329        1538 :        proc_smp_map(:) = -1
         330             :        !
         331           2 :        nsmps = 1
         332         256 :        do c=1,max_len
         333         256 :           tmp_name(c:c) = proc_names(c)
         334             :        enddo
         335           2 :        smp_names(0) = trim(tmp_name)
         336           2 :        proc_smp_map(0) = 0
         337             :        !
         338        1536 :        do i=1,npes-1
         339      196352 :           do c=1,max_len
         340      196352 :              tmp_name(c:c) = proc_names(i*max_len+c)
         341             :           enddo
         342             :
         343             :           j = 0
         344             :           done = .false.
         345        6898 :           do while ((.not. done) .and. (j < nsmps))
         346        5364 :              if (smp_names(j) .eq. trim(tmp_name)) then
         347        1524 :                 proc_smp_map(i) = j
         348        1524 :                 done = .true.
         349             :              endif
         350        5364 :              j = j + 1
         351             :           enddo
         352             :
         353        1536 :           if (.not. done) then
         354          10 :              smp_names(nsmps) = trim(tmp_name)
         355          10 :              proc_smp_map(i) = nsmps
         356          10 :              nsmps = nsmps + 1
         357             :           endif
         358             :
         359             :        enddo
         360           2 :        deallocate(smp_names)
         361             :     endif
         362        1536 :     call mpibcast(nsmps, 1, mpiint, 0, mpicom)
         363        1536 :     call mpibcast(proc_smp_map, npes, mpiint, 0, mpicom)
         364             :     !
         365        1536 :     deallocate(displs)
         366        1536 :     deallocate(lengths)
         367        1536 :     deallocate(proc_name)
         368        1536 :     deallocate(proc_names)
         369             :
         370             :      ! Create a type for transferring column information
         371        1536 :      allocate(lengths(6))
         372       10752 :      lengths(:) = 1
         373       10752 :      origtypes(:) = MPI_INTEGER
         374        1536 :      h1 = 0
         375        1536 :      h1 = h1 + 1
         376             :      call MPI_Get_address(dummy_loc(1)%source_task,  offsets(h1), ierr)
         377        1536 :      h1 = h1 + 1
         378        1536 :      call MPI_Get_address(dummy_loc(1)%source_index, offsets(h1), ierr)
         379        1536 :      h1 = h1 + 1
         380        1536 :      call MPI_Get_address(dummy_loc(1)%dest_task,    offsets(h1), ierr)
         381        1536 :      h1 = h1 + 1
         382        1536 :      call MPI_Get_address(dummy_loc(1)%dest_index,   offsets(h1), ierr)
         383        1536 :      h1 = h1 + 1
         384        1536 :      call MPI_Get_address(dummy_loc(1)%mpi_tag,      offsets(h1), ierr)
         385        9216 :      do hind = h1, 1, -1
         386        9216 :         offsets(hind) = offsets(hind) - offsets(1)
         387             :      end do
         388           0 :      call MPI_type_create_struct(h1, lengths(1:h1), offsets(1:h1),            &
         389        1536 :           origtypes(1:h1), col_trans_type_temp, ierr)
         390             :      ! Adjust for padding
         391        1536 :      call MPI_Get_address(dummy_loc(1)%source_task, offsets(1), ierr)
         392        1536 :      call MPI_Get_address(dummy_loc(2)%source_task, offsets(2), ierr)
         393        1536 :      extent = offsets(2) - offsets(1)
         394             :      call MPI_type_create_resized(col_trans_type_temp, 0_MPI_ADDRESS_KIND,    &
         395        1536 :           extent, spmd_col_trans_mpi_type, ierr)
         396        1536 :     call MPI_type_commit(spmd_col_trans_mpi_type, ierr)
         397        1536 :     deallocate(lengths)
         398             :
         399             : #else
         400             :     !
         401             :     ! spmd is not defined
         402             :     !
         403             :     mpicom = mpicom_atm
         404             :     iam = 0
         405             :     masterprocid = 0
         406             :     masterproc = .true.
         407             :     npes = 1
         408             :     nsmps = 1
         409             :     allocate ( proc_smp_map(0:0) )
         410             :     proc_smp_map(:) = -1
         411             :
         412             : #endif
         413             :
         414        9216 :   end subroutine spmdinit
         415             :
         416             : #if (defined SPMD)
         417             : !
         418             : !========================================================================
         419             : !
         420           0 :    subroutine swapm (steps, nprocs, swapids,               &
         421           0 :                      sndbuf, sbuf_siz, sndlths, sdispls,   &
         422           0 :                      rcvbuf, rbuf_siz, rcvlths, rdispls,   &
         423             :                      comm, comm_protocol, comm_maxreq      )
         424             :
         425             : !-----------------------------------------------------------------------
         426             : !
         427             : ! Purpose:
         428             : !   Reduced version of original swapm (for swap of multiple messages
         429             : !   using MPI point-to-point routines), more efficiently implementing a
         430             : !   subset of the swap protocols.
         431             : !
         432             : ! Method:
         433             : ! comm_protocol:
         434             : !  = 3 or 5: use nonblocking send
         435             : !  = 2 or 4: use blocking send
         436             : !  = 4 or 5: use handshaking protocol
         437             : ! comm_maxreq:
         438             : !  =-1,0: do not limit number of outstanding send/receive requests
         439             : !     >0: do not allow more than min(comm_maxreq, steps) outstanding
         440             : !         nonblocking send requests or nonblocking receive requests
         441             : !
         442             : ! Author of original version:  P. Worley
         443             : ! Ported to CAM: P. Worley, December 2003
         444             : ! Simplified version: P. Worley, October, 2008
         445             : !
         446             : !-----------------------------------------------------------------------
         447             :
         448             : !-----------------------------------------------------------------------
         449             :    implicit none
         450             : !---------------------------Input arguments--------------------------
         451             : !
         452             :    integer, intent(in)   :: steps              ! number of swaps to initiate
         453             :    integer, intent(in)   :: nprocs             ! size of communicator
         454             :    integer, intent(in)   :: sbuf_siz           ! size of send buffer
         455             :    integer, intent(in)   :: rbuf_siz           ! size of receive buffer
         456             :    integer, intent(in)   :: swapids(steps)     ! MPI process id of swap partners
         457             :
         458             :    integer, intent(in)   :: sndlths(0:nprocs-1)! length of outgoing message
         459             :    integer, intent(in)   :: sdispls(0:nprocs-1)! offset from beginning of send
         460             :                                                !  buffer where outgoing messages
         461             :                                                !  should be sent from
         462             :    integer, intent(in)   :: rcvlths(0:nprocs-1)! length of incoming messages
         463             :    integer, intent(in)   :: rdispls(0:nprocs-1)! offset from beginning of receive
         464             :                                                !  buffer where incoming messages
         465             :                                                !  should be placed
         466             :    real(r8), intent(in)  :: sndbuf(sbuf_siz)   ! outgoing message buffer
         467             :    real(r8), intent(out) :: rcvbuf(rbuf_siz)   ! incoming message buffer
         468             :
         469             :    integer, intent(in)   :: comm               ! MPI communicator
         470             :    integer, intent(in)   :: comm_protocol      ! swap_comm protocol
         471             :    integer, intent(in)   :: comm_maxreq        ! maximum number of outstanding
         472             :                                                !  nonblocking requests
         473             :
         474             : !
         475             : !---------------------------Local workspace-----------------------------
         476             : !
         477             :    integer :: p                                ! process index
         478             :    integer :: istep                            ! loop index
         479             :    integer :: offset_s                         ! index of message beginning in
         480             :                                                !  send buffer
         481             :    integer :: offset_r                         ! index of message beginning in
         482             :                                                !  receive buffer
         483           0 :    integer :: sndids(steps)                    ! send request ids
         484           0 :    integer :: rcvids(steps)                    ! receive request ids
         485           0 :    integer :: hs_rcvids(steps)                 ! handshake receive request ids
         486             :
         487             :    integer :: maxreq, maxreqh                  ! maximum number of outstanding
         488             :                                                !  nonblocking requests (and half)
         489           0 :    integer :: hs_s, hs_r(steps)                ! handshake variables (send/receive)
         490             :    integer :: rstep                            ! "receive" step index
         491             :
         492             :    logical :: handshake, sendd                 ! protocol option flags
         493             :
         494             :    integer :: ier                              ! return error status
         495             :    integer :: status(MPI_STATUS_SIZE)          ! MPI status
         496             : !
         497             : !-------------------------------------------------------------------------------------
         498             : !
         499           0 :    if (steps .eq. 0) return
         500             :
         501             :    ! identify communication protocol
         502           0 :    if ((comm_protocol < 2) .or. (comm_protocol > 5)) then
         503             :       sendd = .true.
         504             :       handshake = .true.
         505             :    else
         506           0 :       if ((comm_protocol .eq. 4) .or. (comm_protocol .eq. 5)) then
         507             :          handshake = .true.
         508             :       else
         509           0 :          handshake = .false.
         510             :       endif
         511             :
         512           0 :       if ((comm_protocol .eq. 2) .or. (comm_protocol .eq. 4)) then
         513             :          sendd = .true.
         514             :       else
         515           0 :          sendd = .false.
         516             :       endif
         517             :    endif
         518             :
         519             :    ! identify maximum number of outstanding nonblocking requests to permit
         520           0 :    if (steps .eq. 1) then
         521             :       maxreq  = 1
         522             :       maxreqh = 1
         523             :    else
         524           0 :       if (comm_maxreq >= -1) then
         525             :          maxreq = comm_maxreq
         526             :       else
         527           0 :          maxreq = steps
         528             :       endif
         529             :
         530           0 :       if ((maxreq .le. steps) .and. (maxreq > 0)) then
         531           0 :          if (maxreq > 1) then
         532           0 :             maxreqh = maxreq/2
         533             :          else
         534             :             maxreq  = 2
         535             :             maxreqh = 1
         536             :          endif
         537             :       else
         538             :          maxreq  = steps
         539             :          maxreqh = steps
         540             :       endif
         541             :    endif
         542             :
         543             : ! Four protocol options:
         544             : !  (1) handshaking + blocking sends
         545           0 :    if ((handshake) .and. (sendd)) then
         546             :
         547             :       ! Initialize handshake variable
         548           0 :       hs_s = 1
         549             :
         550             :       ! Post initial handshake receive requests
         551           0 :       do istep=1,maxreq
         552           0 :          p = swapids(istep)
         553           0 :          if (sndlths(p) > 0) then
         554             :             call mpi_irecv( hs_r(istep), 1, mpiint, p, iam, comm, &
         555           0 :                             hs_rcvids(istep), ier )
         556             :          endif
         557             :       enddo
         558             :
         559             :       ! Post initial receive requests
         560           0 :       do istep=1,maxreq
         561           0 :          p = swapids(istep)
         562           0 :          if (rcvlths(p) > 0) then
         563           0 :             offset_r = rdispls(p)+1
         564           0 :             call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         565           0 :                             comm, rcvids(istep), ier )
         566           0 :             call mpi_send ( hs_s, 1, mpiint, p, p, comm, ier )
         567             :          endif
         568             :       enddo
         569             :       rstep = maxreq
         570             :
         571             :       ! Send (and start receiving) data
         572           0 :       do istep=1,steps
         573           0 :          p = swapids(istep)
         574             :
         575             :          ! Submit new rsend request
         576           0 :          if (sndlths(p) > 0) then
         577           0 :             offset_s = sdispls(p)+1
         578             :             call mpi_wait  ( hs_rcvids(istep), MPI_STATUS_IGNORE, ier )
         579           0 :             call mpi_rsend ( sndbuf(offset_s), sndlths(p), mpir8, p, iam, &
         580           0 :                              comm, ier )
         581             :          endif
         582             :
         583           0 :          if (istep > maxreqh) then
         584             :
         585             :             ! Wait for oldest irecv request to complete
         586           0 :             p = swapids(istep-maxreqh)
         587           0 :             if (rcvlths(p) > 0) then
         588             :                call mpi_wait( rcvids(istep-maxreqh), status, ier )
         589             :             endif
         590             :
         591           0 :             if (rstep < steps) then
         592           0 :                rstep = rstep + 1
         593           0 :                p = swapids(rstep)
         594             :
         595             :                ! Submit a new handshake irecv request
         596           0 :                if (sndlths(p) > 0) then
         597             :                   call mpi_irecv( hs_r(rstep), 1, mpiint, p, iam, comm, &
         598           0 :                                   hs_rcvids(rstep), ier )
         599             :                endif
         600             :
         601             :                ! Submit a new irecv request
         602           0 :                if (rcvlths(p) > 0) then
         603           0 :                   offset_r = rdispls(p)+1
         604           0 :                   call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         605           0 :                                   comm, rcvids(rstep), ier )
         606           0 :                   call mpi_send ( hs_s, 1, mpiint, p, p, comm, ier )
         607             :                endif
         608             :             endif
         609             :
         610             :          endif
         611             : !
         612             :       enddo
         613             :
         614             :       ! wait for rest of receive requests to complete
         615           0 :       do istep=steps-maxreqh+1,steps
         616           0 :          p = swapids(istep)
         617           0 :          if (rcvlths(p) > 0) then
         618             :             call mpi_wait( rcvids(istep), status, ier )
         619             :          endif
         620             :       enddo
         621             :
         622             : !  (2) handshaking + nonblocking sends
         623           0 :    elseif ((handshake) .and. (.not. sendd)) then
         624             :
         625             :       ! Initialize handshake variable
         626           0 :       hs_s = 1
         627             :
         628             :       ! Post initial handshake receive requests
         629           0 :       do istep=1,maxreq
         630           0 :          p = swapids(istep)
         631           0 :          if (sndlths(p) > 0) then
         632             :             call mpi_irecv( hs_r(istep), 1, mpiint, p, iam, comm, &
         633           0 :                             hs_rcvids(istep), ier )
         634             :          endif
         635             :       enddo
         636             :
         637             :       ! Post initial receive requests
         638           0 :       do istep=1,maxreq
         639           0 :          p = swapids(istep)
         640           0 :          if (rcvlths(p) > 0) then
         641           0 :             offset_r = rdispls(p)+1
         642           0 :             call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         643           0 :                             comm, rcvids(istep), ier )
         644           0 :             call mpi_send ( hs_s, 1, mpiint, p, p, comm, ier )
         645             :          endif
         646             :       enddo
         647             :       rstep = maxreq
         648             :
         649             :       ! Send (and start receiving) data
         650           0 :       do istep=1,steps
         651           0 :          p = swapids(istep)
         652             :
         653             :          ! Submit new irsend request
         654           0 :          if (sndlths(p) > 0) then
         655           0 :             offset_s = sdispls(p)+1
         656             :             call mpi_wait  ( hs_rcvids(istep), MPI_STATUS_IGNORE, ier )
         657           0 :             call mpi_irsend( sndbuf(offset_s), sndlths(p), mpir8, p, iam, &
         658           0 :                              comm, sndids(istep), ier )
         659             :          endif
         660             :
         661           0 :          if (istep > maxreqh) then
         662             :
         663             :             ! Wait for oldest irecv request to complete
         664           0 :             p = swapids(istep-maxreqh)
         665           0 :             if (rcvlths(p) > 0) then
         666             :                call mpi_wait( rcvids(istep-maxreqh), status, ier )
         667             :             endif
         668             :
         669           0 :             if (rstep < steps) then
         670           0 :                rstep = rstep + 1
         671           0 :                p = swapids(rstep)
         672             :
         673             :                ! Submit a new handshake irecv request
         674           0 :                if (sndlths(p) > 0) then
         675             :                   call mpi_irecv( hs_r(rstep), 1, mpiint, p, iam, comm, &
         676           0 :                                   hs_rcvids(rstep), ier )
         677             :                endif
         678             :
         679             :                ! Submit a new irecv request
         680           0 :                if (rcvlths(p) > 0) then
         681           0 :                   offset_r = rdispls(p)+1
         682           0 :                   call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         683           0 :                                   comm, rcvids(rstep), ier )
         684           0 :                   call mpi_send ( hs_s, 1, mpiint, p, p, comm, ier )
         685             :                endif
         686             :             endif
         687             :
         688             :             ! Wait for outstanding i(r)send request to complete
         689           0 :             p = swapids(istep-maxreqh)
         690           0 :             if (sndlths(p) > 0) then
         691             :                call mpi_wait( sndids(istep-maxreqh), status, ier )
         692             :             endif
         693             :
         694             :          endif
         695             :
         696             :       enddo
         697             :
         698             :       ! wait for rest of send and receive requests to complete
         699           0 :       do istep=steps-maxreqh+1,steps
         700           0 :          p = swapids(istep)
         701           0 :          if (rcvlths(p) > 0) then
         702             :             call mpi_wait( rcvids(istep), status, ier )
         703             :          endif
         704           0 :          if (sndlths(p) > 0) then
         705             :             call mpi_wait( sndids(istep), status, ier )
         706             :          endif
         707             :       enddo
         708             :
         709             : !  (3) no handshaking + blocking sends
         710           0 :    elseif ((.not. handshake) .and. (sendd)) then
         711             :
         712             :       ! Post receive requests
         713           0 :       do istep=1,maxreq
         714           0 :          p = swapids(istep)
         715           0 :          if (rcvlths(p) > 0) then
         716           0 :             offset_r = rdispls(p)+1
         717           0 :             call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         718           0 :                             comm, rcvids(istep), ier )
         719             :          endif
         720             :       enddo
         721             :       rstep = maxreq
         722             :
         723             :       ! Send (and start receiving) data
         724           0 :       do istep=1,steps
         725           0 :          p = swapids(istep)
         726             :
         727             :          ! Submit new send request
         728           0 :          if (sndlths(p) > 0) then
         729           0 :             offset_s = sdispls(p)+1
         730           0 :             call mpi_send( sndbuf(offset_s), sndlths(p), mpir8, p, iam, &
         731           0 :                            comm, ier )
         732             :          endif
         733             :
         734           0 :          if (istep > maxreqh) then
         735             :
         736             :             ! Wait for oldest irecv request to complete
         737           0 :             p = swapids(istep-maxreqh)
         738           0 :             if (rcvlths(p) > 0) then
         739             :                call mpi_wait( rcvids(istep-maxreqh), status, ier )
         740             :             endif
         741             :
         742             :             ! Submit a new irecv request
         743           0 :             if (rstep < steps) then
         744           0 :                rstep = rstep + 1
         745           0 :                p = swapids(rstep)
         746           0 :                if (rcvlths(p) > 0) then
         747           0 :                   offset_r = rdispls(p)+1
         748           0 :                   call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         749           0 :                                   comm, rcvids(rstep), ier )
         750             :                endif
         751             :             endif
         752             :
         753             :          endif
         754             :
         755             :       enddo
         756             :
         757             :       ! wait for rest of send and receive requests to complete
         758           0 :       do istep=steps-maxreqh+1,steps
         759           0 :          p = swapids(istep)
         760           0 :          if (rcvlths(p) > 0) then
         761             :             call mpi_wait( rcvids(istep), status, ier )
         762             :          endif
         763             :       enddo
         764             :
         765             : !  (4) no handshaking + nonblocking sends
         766           0 :    elseif ((.not. handshake) .and. (.not. sendd)) then
         767             :
         768             :       ! Post receive requests
         769           0 :       do istep=1,maxreq
         770           0 :          p = swapids(istep)
         771           0 :          if (rcvlths(p) > 0) then
         772           0 :             offset_r = rdispls(p)+1
         773           0 :             call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         774           0 :                             comm, rcvids(istep), ier )
         775             :          endif
         776             :       enddo
         777             :       rstep = maxreq
         778             :
         779             :       ! Send (and start receiving) data
         780           0 :       do istep=1,steps
         781           0 :          p = swapids(istep)
         782             :
         783             :          ! Submit new isend request
         784           0 :          if (sndlths(p) > 0) then
         785           0 :             offset_s = sdispls(p)+1
         786           0 :             call mpi_isend( sndbuf(offset_s), sndlths(p), mpir8, p, iam, &
         787           0 :                             comm, sndids(istep), ier )
         788             :          endif
         789             :
         790           0 :          if (istep > maxreqh) then
         791             :
         792             :             ! Wait for oldest irecv request to complete
         793           0 :             p = swapids(istep-maxreqh)
         794           0 :             if (rcvlths(p) > 0) then
         795             :                call mpi_wait( rcvids(istep-maxreqh), status, ier )
         796             :             endif
         797             :
         798             :             ! Submit a new irecv request
         799           0 :             if (rstep < steps) then
         800           0 :                rstep = rstep + 1
         801           0 :                p = swapids(rstep)
         802           0 :                if (rcvlths(p) > 0) then
         803           0 :                   offset_r = rdispls(p)+1
         804           0 :                   call mpi_irecv( rcvbuf(offset_r), rcvlths(p), mpir8, p, p, &
         805           0 :                                   comm, rcvids(rstep), ier )
         806             :                endif
         807             :             endif
         808             :
         809             :             ! Wait for outstanding i(r)send request to complete
         810           0 :             p = swapids(istep-maxreqh)
         811           0 :             if (sndlths(p) > 0) then
         812             :                call mpi_wait( sndids(istep-maxreqh), status, ier )
         813             :             endif
         814             :
         815             :          endif
         816             :
         817             :       enddo
         818             :
         819             :       ! wait for rest of send and receive requests to complete
         820           0 :       do istep=steps-maxreqh+1,steps
         821           0 :          p = swapids(istep)
         822           0 :          if (rcvlths(p) > 0) then
         823             :             call mpi_wait( rcvids(istep), status, ier )
         824             :          endif
         825           0 :          if (sndlths(p) > 0) then
         826             :             call mpi_wait( sndids(istep), status, ier )
         827             :          endif
         828             :       enddo
         829             :
         830             :    endif
         831             :
         832             :    return
         833             :
         834             :    end subroutine swapm
         835             : !
         836             : !========================================================================
         837             :
         838             : !-----------------------------------------------------------------------
         839             : !
         840             : ! Purpose: gather collective with additional flow control, so as to
         841             : !          be more robust when used with high process counts.
         842             : !          If flow_cntl optional parameter
         843             : !           < 0: use MPI_Gather
         844             : !          >= 0: use point-to-point with handshaking messages and
         845             : !                preposting receive requests up to
         846             : !                 min(max(1,flow_cntl),max_gather_block_size)
         847             : !                ahead if optional flow_cntl parameter is present.
         848             : !                Otherwise, fc_gather_flow_cntl is used in its place.
         849             : !          Default value is 64.
         850             : !
         851             : ! Entry points:
         852             : !      fc_gatherv       functionally equivalent to mpi_gatherv
         853             : !      fc_gathervr4     functionally equivalent to mpi_gatherv for real*4 data
         854             : !      fc_gathervint    functionally equivalent to mpi_gatherv for integer data
         855             : !      fc_gathervc      functionally equivalent to mpi_gatherv for character data
         856             : !
         857             : ! Author: P. Worley
         858             : !-----------------------------------------------------------------------
         859             :
         860             : !
         861             : !========================================================================
         862             : !
         863           0 :    subroutine fc_gatherv (sendbuf, sendcnt, sendtype, &
         864             :                          recvbuf, recvcnts, displs, recvtype, &
         865             :                          root, comm, flow_cntl )
         866             : !
         867             : ! Collects different messages from each process on masterproc
         868             : !
         869             :    use shr_kind_mod,   only: r8 => shr_kind_r8
         870             :    use mpishorthand
         871             :    use cam_abortutils, only: endrun
         872             :    use cam_logfile,    only: iulog
         873             :
         874             : #if defined( WRAP_MPI_TIMING )
         875             :    use perf_mod
         876             : #endif
         877             :
         878             :    implicit none
         879             :
         880             :    real (r8), intent(in)  :: sendbuf(*)
         881             :    real (r8), intent(out) :: recvbuf(*)
         882             :    integer, intent(in) :: displs(*)
         883             :    integer, intent(in) :: sendcnt
         884             :    integer, intent(in) :: sendtype
         885             :    integer, intent(in) :: recvcnts(*)
         886             :    integer, intent(in) :: recvtype
         887             :    integer, intent(in) :: root
         888             :    integer, intent(in) :: comm
         889             :    integer, optional, intent(in) :: flow_cntl
         890             :
         891             :    real (r8) :: signal
         892             :    logical fc_gather         ! use explicit flow control?
         893             :    integer gather_block_size ! number of preposted receive requests
         894             :
         895             :    integer :: mytid, mysize, mtag, p, q, i, count
         896             :    integer :: preposts, head, tail
         897             :    integer :: rcvid(max_gather_block_size)
         898             :    integer :: status(MPI_STATUS_SIZE)
         899             :    integer ier               ! MPI error code
         900             :
         901           0 :    if ( present(flow_cntl) ) then
         902           0 :       if (flow_cntl >= 0) then
         903           0 :          gather_block_size = min(max(1,flow_cntl),max_gather_block_size)
         904             :          fc_gather = .true.
         905             :       else
         906             :          fc_gather = .false.
         907             :       endif
         908             :    else
         909           0 :       if (fc_gather_flow_cntl >= 0) then
         910           0 :          gather_block_size = min(max(1,fc_gather_flow_cntl),max_gather_block_size)
         911             :          fc_gather = .true.
         912             :       else
         913             :          fc_gather = .false.
         914             :       endif
         915             :    endif
         916             :
         917             :    if (fc_gather) then
         918             :
         919             : #if defined( WRAP_MPI_TIMING )
         920             :       call t_startf ('fc_gatherv_r8')
         921             : #endif
         922           0 :       call mpi_comm_rank (comm, mytid, ier)
         923           0 :       call mpi_comm_size (comm, mysize, ier)
         924           0 :       mtag = 0
         925           0 :       if (root .eq. mytid) then
         926             :
         927             : ! prepost gather_block_size irecvs, and start receiving data
         928           0 :          preposts = min(mysize-1, gather_block_size)
         929           0 :          head = 0
         930           0 :          count = 0
         931           0 :          do p=0, mysize-1
         932           0 :             if (p .ne. root) then
         933           0 :                q = p+1
         934           0 :                if (recvcnts(q) > 0) then
         935           0 :                   count = count + 1
         936           0 :                   if (count > preposts) then
         937           0 :                      tail = mod(head,preposts) + 1
         938           0 :                      call mpi_wait (rcvid(tail), status, ier)
         939             :                   end if
         940           0 :                   head = mod(head,preposts) + 1
         941           0 :                   call mpi_irecv ( recvbuf(displs(q)+1), recvcnts(q), &
         942           0 :                                    recvtype, p, mtag, comm, rcvid(head), &
         943           0 :                                    ier )
         944           0 :                   call mpi_send ( signal, 1, mpir8, p, mtag, comm, ier )
         945             :                end if
         946             :             end if
         947             :          end do
         948             :
         949             : ! copy local data
         950           0 :          q = mytid+1
         951           0 :          do i=1,sendcnt
         952           0 :             recvbuf(displs(q)+i) = sendbuf(i)
         953             :          enddo
         954             :
         955             : ! wait for final data
         956           0 :          do i=1,min(count,preposts)
         957           0 :             call mpi_wait (rcvid(i), status, ier)
         958             :          enddo
         959             :
         960             :       else
         961             :
         962           0 :          if (sendcnt > 0) then
         963             :             call mpi_recv ( signal, 1, mpir8, root, mtag, comm, &
         964           0 :                             status, ier )
         965             :             call mpi_rsend ( sendbuf, sendcnt, sendtype, root, mtag, &
         966           0 :                              comm, ier )
         967             :          end if
         968             :
         969             :       endif
         970           0 :       if (ier /= mpi_success) then
         971           0 :          write(iulog,*)'fc_gatherv_r8 failed ier=',ier
         972           0 :          call endrun
         973             :       end if
         974             : #if defined( WRAP_MPI_TIMING )
         975             :       call t_stopf ('fc_gatherv_r8')
         976             : #endif
         977             :
         978             :    else
         979             :
         980             : #if defined( WRAP_MPI_TIMING )
         981             :       call t_startf ('mpi_gatherv')
         982             : #endif
         983             :       call mpi_gatherv (sendbuf, sendcnt, sendtype, &
         984             :                         recvbuf, recvcnts, displs, recvtype, &
         985           0 :                         root, comm, ier)
         986           0 :       if (ier /= mpi_success) then
         987           0 :          write(iulog,*)'mpi_gatherv failed ier=',ier
         988           0 :          call endrun
         989             :       end if
         990             : #if defined( WRAP_MPI_TIMING )
         991             :       call t_stopf ('mpi_gatherv')
         992             : #endif
         993             :
         994             :    endif
         995             :
         996           0 :    return
         997             :    end subroutine fc_gatherv
         998             : !
         999             : !========================================================================
        1000             : !
        1001           0 :    subroutine fc_gathervr4 (sendbuf, sendcnt, sendtype, &
        1002             :                            recvbuf, recvcnts, displs, recvtype, &
        1003             :                            root, comm, flow_cntl )
        1004             : !
        1005             : ! Collects different messages from each process on masterproc
        1006             : !
        1007             :    use shr_kind_mod,   only: r4 => shr_kind_r4, r8 => shr_kind_r8
        1008             :    use mpishorthand
        1009             :    use cam_abortutils, only: endrun
        1010             :    use cam_logfile,    only: iulog
        1011             :
        1012             : #if defined( WRAP_MPI_TIMING )
        1013             :    use perf_mod
        1014             : #endif
        1015             :
        1016             :    implicit none
        1017             :
        1018             :    real (r4), intent(in)  :: sendbuf(*)
        1019             :    real (r4), intent(out) :: recvbuf(*)
        1020             :    integer, intent(in) :: displs(*)
        1021             :    integer, intent(in) :: sendcnt
        1022             :    integer, intent(in) :: sendtype
        1023             :    integer, intent(in) :: recvcnts(*)
        1024             :    integer, intent(in) :: recvtype
        1025             :    integer, intent(in) :: root
        1026             :    integer, intent(in) :: comm
        1027             :    integer, optional, intent(in) :: flow_cntl
        1028             :
        1029             :    real (r8) :: signal
        1030             :    logical fc_gather         ! use explicit flow control?
        1031             :    integer gather_block_size ! number of preposted receive requests
        1032             :
        1033             :    integer :: mytid, mysize, mtag, p, q, i, count
        1034             :    integer :: preposts, head, tail
        1035             :    integer :: rcvid(max_gather_block_size)
        1036             :    integer :: status(MPI_STATUS_SIZE)
        1037             :    integer ier               ! MPI error code
        1038             :
        1039           0 :    if ( present(flow_cntl) ) then
        1040           0 :       if (flow_cntl >= 0) then
        1041           0 :          gather_block_size = min(max(1,flow_cntl),max_gather_block_size)
        1042             :          fc_gather = .true.
        1043             :       else
        1044             :          fc_gather = .false.
        1045             :       endif
        1046             :    else
        1047           0 :       if (fc_gather_flow_cntl >= 0) then
        1048           0 :          gather_block_size = min(max(1,fc_gather_flow_cntl),max_gather_block_size)
        1049             :          fc_gather = .true.
        1050             :       else
        1051             :          fc_gather = .false.
        1052             :       endif
        1053             :    endif
        1054             :
        1055             :    if (fc_gather) then
        1056             :
        1057             : #if defined( WRAP_MPI_TIMING )
        1058             :       call t_startf ('fc_gatherv_r4')
        1059             : #endif
        1060           0 :       call mpi_comm_rank (comm, mytid, ier)
        1061           0 :       call mpi_comm_size (comm, mysize, ier)
        1062           0 :       mtag = 0
        1063           0 :       if (root .eq. mytid) then
        1064             :
        1065             : ! prepost gather_block_size irecvs, and start receiving data
        1066           0 :          preposts = min(mysize-1, gather_block_size)
        1067           0 :          head = 0
        1068           0 :          count = 0
        1069           0 :          do p=0, mysize-1
        1070           0 :             if (p .ne. root) then
        1071           0 :                q = p+1
        1072           0 :                if (recvcnts(q) > 0) then
        1073           0 :                   count = count + 1
        1074           0 :                   if (count > preposts) then
        1075           0 :                      tail = mod(head,preposts) + 1
        1076           0 :                      call mpi_wait (rcvid(tail), status, ier)
        1077             :                   end if
        1078           0 :                   head = mod(head,preposts) + 1
        1079           0 :                   call mpi_irecv ( recvbuf(displs(q)+1), recvcnts(q), &
        1080           0 :                                    recvtype, p, mtag, comm, rcvid(head), &
        1081           0 :                                    ier )
        1082           0 :                   call mpi_send ( signal, 1, mpir8, p, mtag, comm, ier )
        1083             :                end if
        1084             :             end if
        1085             :          end do
        1086             :
        1087             : ! copy local data
        1088           0 :          q = mytid+1
        1089           0 :          do i=1,sendcnt
        1090           0 :             recvbuf(displs(q)+i) = sendbuf(i)
        1091             :          enddo
        1092             :
        1093             : ! wait for final data
        1094           0 :          do i=1,min(count,preposts)
        1095           0 :             call mpi_wait (rcvid(i), status, ier)
        1096             :          enddo
        1097             :
        1098             :       else
        1099             :
        1100           0 :          if (sendcnt > 0) then
        1101             :             call mpi_recv ( signal, 1, mpir8, root, mtag, comm, &
        1102           0 :                             status, ier )
        1103             :             call mpi_rsend ( sendbuf, sendcnt, sendtype, root, mtag, &
        1104           0 :                              comm, ier )
        1105             :           end if
        1106             :
        1107             :       endif
        1108           0 :       if (ier /= mpi_success) then
        1109           0 :          write(iulog,*)'fc_gatherv_r4 failed ier=',ier
        1110           0 :          call endrun
        1111             :       end if
        1112             : #if defined( WRAP_MPI_TIMING )
        1113             :       call t_stopf ('fc_gatherv_r4')
        1114             : #endif
        1115             :
        1116             :    else
        1117             :
        1118             : #if defined( WRAP_MPI_TIMING )
        1119             :       call t_startf ('mpi_gatherv')
        1120             : #endif
        1121             :       call mpi_gatherv (sendbuf, sendcnt, sendtype, &
        1122             :                         recvbuf, recvcnts, displs, recvtype, &
        1123           0 :                         root, comm, ier)
        1124           0 :       if (ier /= mpi_success) then
        1125           0 :          write(iulog,*)'mpi_gatherv failed ier=',ier
        1126           0 :          call endrun
        1127             :       end if
        1128             : #if defined( WRAP_MPI_TIMING )
        1129             :       call t_stopf ('mpi_gatherv')
        1130             : #endif
        1131             :
        1132             :    endif
        1133             :
        1134           0 :    return
        1135             :    end subroutine fc_gathervr4
        1136             : !
        1137             : !========================================================================
        1138             : !
        1139           0 :    subroutine fc_gathervint (sendbuf, sendcnt, sendtype, &
        1140             :                             recvbuf, recvcnts, displs, recvtype, &
        1141             :                             root, comm, flow_cntl )
        1142             : !
        1143             : ! Collects different messages from each process on masterproc
        1144             : !
        1145             :    use shr_kind_mod,   only: r8 => shr_kind_r8
        1146             :    use mpishorthand
        1147             :    use cam_abortutils, only: endrun
        1148             :    use cam_logfile,    only: iulog
        1149             :
        1150             : #if defined( WRAP_MPI_TIMING )
        1151             :    use perf_mod
        1152             : #endif
        1153             :
        1154             :    implicit none
        1155             :
        1156             :    integer, intent(in)  :: sendbuf(*)
        1157             :    integer, intent(out) :: recvbuf(*)
        1158             :    integer, intent(in) :: displs(*)
        1159             :    integer, intent(in) :: sendcnt
        1160             :    integer, intent(in) :: sendtype
        1161             :    integer, intent(in) :: recvcnts(*)
        1162             :    integer, intent(in) :: recvtype
        1163             :    integer, intent(in) :: root
        1164             :    integer, intent(in) :: comm
        1165             :    integer, optional, intent(in) :: flow_cntl
        1166             :
        1167             :    real (r8) :: signal
        1168             :    logical fc_gather         ! use explicit flow control?
        1169             :    integer gather_block_size ! number of preposted receive requests
        1170             :
        1171             :    integer :: mytid, mysize, mtag, p, q, i, count
        1172             :    integer :: preposts, head, tail
        1173             :    integer :: rcvid(max_gather_block_size)
        1174             :    integer :: status(MPI_STATUS_SIZE)
        1175             :    integer ier               ! MPI error code
        1176             :
        1177           0 :    if ( present(flow_cntl) ) then
        1178           0 :       if (flow_cntl >= 0) then
        1179           0 :          gather_block_size = min(max(1,flow_cntl),max_gather_block_size)
        1180             :          fc_gather = .true.
        1181             :       else
        1182             :          fc_gather = .false.
        1183             :       endif
        1184             :    else
        1185           0 :       if (fc_gather_flow_cntl >= 0) then
        1186           0 :          gather_block_size = min(max(1,fc_gather_flow_cntl),max_gather_block_size)
        1187             :          fc_gather = .true.
        1188             :       else
        1189             :          fc_gather = .false.
        1190             :       endif
        1191             :    endif
        1192             :
        1193             :    if (fc_gather) then
        1194             :
        1195             : #if defined( WRAP_MPI_TIMING )
        1196             :       call t_startf ('fc_gatherv_int')
        1197             : #endif
        1198           0 :       call mpi_comm_rank (comm, mytid, ier)
        1199           0 :       call mpi_comm_size (comm, mysize, ier)
        1200           0 :       mtag = 0
        1201           0 :       if (root .eq. mytid) then
        1202             :
        1203             : ! prepost gather_block_size irecvs, and start receiving data
        1204           0 :          preposts = min(mysize-1, gather_block_size)
        1205           0 :          head = 0
        1206           0 :          count = 0
        1207           0 :          do p=0, mysize-1
        1208           0 :             if (p .ne. root) then
        1209           0 :                q = p+1
        1210           0 :                if (recvcnts(q) > 0) then
        1211           0 :                   count = count + 1
        1212           0 :                   if (count > preposts) then
        1213           0 :                      tail = mod(head,preposts) + 1
        1214           0 :                      call mpi_wait (rcvid(tail), status, ier)
        1215             :                   end if
        1216           0 :                   head = mod(head,preposts) + 1
        1217           0 :                   call mpi_irecv ( recvbuf(displs(q)+1), recvcnts(q), &
        1218           0 :                                    recvtype, p, mtag, comm, rcvid(head), &
        1219           0 :                                    ier )
        1220           0 :                   call mpi_send ( signal, 1, mpir8, p, mtag, comm, ier )
        1221             :                end if
        1222             :             end if
        1223             :          end do
        1224             :
        1225             : ! copy local data
        1226           0 :          q = mytid+1
        1227           0 :          do i=1,sendcnt
        1228           0 :             recvbuf(displs(q)+i) = sendbuf(i)
        1229             :          enddo
        1230             :
        1231             : ! wait for final data
        1232           0 :          do i=1,min(count,preposts)
        1233           0 :             call mpi_wait (rcvid(i), status, ier)
        1234             :          enddo
        1235             :
        1236             :       else
        1237             :
        1238           0 :          if (sendcnt > 0) then
        1239             :             call mpi_recv ( signal, 1, mpir8, root, mtag, comm, &
        1240           0 :                             status, ier )
        1241             :             call mpi_rsend ( sendbuf, sendcnt, sendtype, root, mtag, &
        1242           0 :                              comm, ier )
        1243             :           end if
        1244             :
        1245             :       endif
        1246           0 :       if (ier /= mpi_success) then
        1247           0 :          write(iulog,*)'fc_gatherv_int failed ier=',ier
        1248           0 :          call endrun
        1249             :       end if
        1250             : #if defined( WRAP_MPI_TIMING )
        1251             :       call t_stopf ('fc_gatherv_int')
        1252             : #endif
        1253             :
        1254             :    else
        1255             :
        1256             : #if defined( WRAP_MPI_TIMING )
        1257             :       call t_startf ('mpi_gatherv')
        1258             : #endif
        1259             :       call mpi_gatherv (sendbuf, sendcnt, sendtype, &
        1260             :                         recvbuf, recvcnts, displs, recvtype, &
        1261           0 :                         root, comm, ier)
        1262           0 :       if (ier /= mpi_success) then
        1263           0 :          write(iulog,*)'mpi_gatherv failed ier=',ier
        1264           0 :          call endrun
        1265             :       end if
        1266             : #if defined( WRAP_MPI_TIMING )
        1267             :       call t_stopf ('mpi_gatherv')
        1268             : #endif
        1269             :
        1270             :    endif
        1271             :
        1272           0 :    return
        1273             :    end subroutine fc_gathervint
        1274             : !
        1275             : !========================================================================
        1276             : !
        1277        1536 :    subroutine fc_gathervc (sendbuf, sendcnt, sendtype, &
        1278             :                            recvbuf, recvcnts, displs, recvtype, &
        1279             :                            root, comm, flow_cntl )
        1280             : !
        1281             : ! Collects different messages from each process on masterproc
        1282             : !
        1283             :    use shr_kind_mod,   only: r8 => shr_kind_r8
        1284             :    use mpishorthand
        1285             :    use cam_abortutils, only: endrun
        1286             :    use cam_logfile,    only: iulog
        1287             :
        1288             : #if defined( WRAP_MPI_TIMING )
        1289             :    use perf_mod
        1290             : #endif
        1291             :
        1292             :    implicit none
        1293             :
        1294             :    character, intent(in)  :: sendbuf(*)
        1295             :    character, intent(out) :: recvbuf(*)
        1296             :    integer, intent(in) :: displs(*)
        1297             :    integer, intent(in) :: sendcnt
        1298             :    integer, intent(in) :: sendtype
        1299             :    integer, intent(in) :: recvcnts(*)
        1300             :    integer, intent(in) :: recvtype
        1301             :    integer, intent(in) :: root
        1302             :    integer, intent(in) :: comm
        1303             :    integer, optional, intent(in) :: flow_cntl
        1304             :
        1305             :    real (r8) :: signal
        1306             :    logical fc_gather         ! use explicit flow control?
        1307             :    integer gather_block_size ! number of preposted receive requests
        1308             :
        1309             :    integer :: mytid, mysize, mtag, p, q, i, count
        1310             :    integer :: preposts, head, tail
        1311             :    integer :: rcvid(max_gather_block_size)
        1312             :    integer :: status(MPI_STATUS_SIZE)
        1313             :    integer ier               ! MPI error code
        1314             :
        1315        1536 :    if ( present(flow_cntl) ) then
        1316        1536 :       if (flow_cntl >= 0) then
        1317           0 :          gather_block_size = min(max(1,flow_cntl),max_gather_block_size)
        1318             :          fc_gather = .true.
        1319             :       else
        1320             :          fc_gather = .false.
        1321             :       endif
        1322             :    else
        1323           0 :       if (fc_gather_flow_cntl >= 0) then
        1324           0 :          gather_block_size = min(max(1,fc_gather_flow_cntl),max_gather_block_size)
        1325             :          fc_gather = .true.
        1326             :       else
        1327             :          fc_gather = .false.
        1328             :       endif
        1329             :    endif
        1330             :
        1331             :    if (fc_gather) then
        1332             :
        1333             : #if defined( WRAP_MPI_TIMING )
        1334             :       call t_startf ('fc_gatherv_char')
        1335             : #endif
        1336           0 :       call mpi_comm_rank (comm, mytid, ier)
        1337           0 :       call mpi_comm_size (comm, mysize, ier)
        1338           0 :       mtag = 0
        1339           0 :       if (root .eq. mytid) then
        1340             :
        1341             : ! prepost gather_block_size irecvs, and start receiving data
        1342           0 :          preposts = min(mysize-1, gather_block_size)
        1343           0 :          head = 0
        1344           0 :          count = 0
        1345           0 :          do p=0, mysize-1
        1346           0 :             if (p .ne. root) then
        1347           0 :                q = p+1
        1348           0 :                if (recvcnts(q) > 0) then
        1349           0 :                   count = count + 1
        1350           0 :                   if (count > preposts) then
        1351           0 :                      tail = mod(head,preposts) + 1
        1352           0 :                      call mpi_wait (rcvid(tail), status, ier)
        1353             :                   end if
        1354           0 :                   head = mod(head,preposts) + 1
        1355           0 :                   call mpi_irecv ( recvbuf(displs(q)+1), recvcnts(q), &
        1356           0 :                                    recvtype, p, mtag, comm, rcvid(head), &
        1357           0 :                                    ier )
        1358           0 :                   call mpi_send ( signal, 1, mpir8, p, mtag, comm, ier )
        1359             :                end if
        1360             :             end if
        1361             :          end do
        1362             :
        1363             : ! copy local data
        1364           0 :          q = mytid+1
        1365           0 :          do i=1,sendcnt
        1366           0 :             recvbuf(displs(q)+i) = sendbuf(i)
        1367             :          enddo
        1368             :
        1369             : ! wait for final data
        1370           0 :          do i=1,min(count,preposts)
        1371           0 :             call mpi_wait (rcvid(i), status, ier)
        1372             :          enddo
        1373             :
        1374             :       else
        1375             :
        1376           0 :          if (sendcnt > 0) then
        1377             :             call mpi_recv ( signal, 1, mpir8, root, mtag, comm, &
        1378           0 :                             status, ier )
        1379             :             call mpi_rsend ( sendbuf, sendcnt, sendtype, root, mtag, &
        1380           0 :                              comm, ier )
        1381             :           end if
        1382             :
        1383             :       endif
        1384           0 :       if (ier /= mpi_success) then
        1385           0 :          write(iulog,*)'fc_gatherv_char failed ier=',ier
        1386           0 :          call endrun
        1387             :       end if
        1388             : #if defined( WRAP_MPI_TIMING )
        1389             :       call t_stopf ('fc_gatherv_char')
        1390             : #endif
        1391             :
        1392             :    else
        1393             :
        1394             : #if defined( WRAP_MPI_TIMING )
        1395             :       call t_startf ('mpi_gatherv')
        1396             : #endif
        1397             :       call mpi_gatherv (sendbuf, sendcnt, sendtype, &
        1398             :                         recvbuf, recvcnts, displs, recvtype, &
        1399        1536 :                         root, comm, ier)
        1400        1536 :       if (ier /= mpi_success) then
        1401           0 :          write(iulog,*)'mpi_gatherv failed ier=',ier
        1402           0 :          call endrun
        1403             :       end if
        1404             : #if defined( WRAP_MPI_TIMING )
        1405             :       call t_stopf ('mpi_gatherv')
        1406             : #endif
        1407             :
        1408             :    endif
        1409             :
        1410        1536 :    return
        1411             :    end subroutine fc_gathervc
        1412             : !
        1413             : !========================================================================
        1414             : #endif
        1415             :
        1416             : !-----------------------------------------------------------------------
        1417             : !
        1418             : ! Purpose: implementations of MPI_Alltoall using different messaging
        1419             : !          layers and different communication protocols, controlled
        1420             : !          by option argument:
        1421             : !  0: use mpi_alltoallv
        1422             : !  1: use point-to-point MPI-1 two-sided implementation
        1423             : !  2: use point-to-point MPI-2 one-sided implementation if supported,
        1424             : !       otherwise use MPI-1 implementation
        1425             : !  3: use Co-Array Fortran implementation if supported,
        1426             : !       otherwise use MPI-1 implementation
        1427             : !  otherwise use mpi_sendrecv implementation
        1428             : !
        1429             : ! Entry points:
        1430             : !      altalltoallv
        1431             : !
        1432             : ! Author: P. Worley
        1433             : !-----------------------------------------------------------------------
        1434             :
        1435             : #if (defined SPMD)
        1436             : !****************************************************************
        1437           0 :    subroutine altalltoallv (option, mytid, nprocs, steps, dests, &
        1438           0 :                  sendbuf, sbuf_siz, sendcnts, sdispls, sendtype, &
        1439           0 :                  recvbuf, rbuf_siz, recvcnts, rdispls, recvtype, &
        1440             :                  msgtag, pdispls, desttype, recvwin, comm)
        1441             : !
        1442             : ! All-to-all scatter/gather implemented using Co-Array
        1443             : ! Fortran one-sided commands, MPI-2 one sided commands,
        1444             : ! SWAP module MPI-1 commands, MPI_ALLTOALLV or MPI_SENDRECV.
        1445             : !
        1446             : #if defined( WRAP_MPI_TIMING )
        1447             :    use perf_mod
        1448             : #endif
        1449             :
        1450             :    implicit none
        1451             :
        1452             :    integer, intent(in) :: option               ! 0: mpi_alltoallv
        1453             :                                                ! 1: swap package
        1454             :                                                ! 2: mpi2
        1455             :                                                ! 3: co-array fortran
        1456             :                                        ! otherwise: sendrecv
        1457             :    integer, intent(in) :: mytid
        1458             :    integer, intent(in) :: nprocs
        1459             :    integer, intent(in) :: steps
        1460             :    integer, intent(in) :: dests(steps)
        1461             :    integer, intent(in) :: sbuf_siz
        1462             :    integer, intent(in) :: sendcnts(0:nprocs-1)
        1463             :    integer, intent(in) :: sdispls(0:nprocs-1)
        1464             :    integer, intent(in) :: sendtype
        1465             :    integer, intent(in) :: rbuf_siz
        1466             :    integer, intent(in) :: recvcnts(0:nprocs-1)
        1467             :    integer, intent(in) :: rdispls(0:nprocs-1)
        1468             :    integer, intent(in) :: recvtype
        1469             :    integer, intent(in) :: msgtag
        1470             :    integer, intent(in) :: pdispls(0:nprocs-1)   ! displacement at
        1471             :                                                 !  destination
        1472             :    integer, intent(in) :: desttype
        1473             :    integer, intent(in) :: recvwin
        1474             :    integer, intent(in) :: comm
        1475             :
        1476             : #if (defined CAF)
        1477             :    real (r8), intent(in)  :: sendbuf(sbuf_siz)[*]
        1478             :    real (r8), intent(out) :: recvbuf(rbuf_siz)[*]
        1479             :
        1480             :    integer :: istart, iend, jstart, jend
        1481             : #else
        1482             :    real (r8), intent(in)  :: sendbuf(sbuf_siz)
        1483             :    real (r8), intent(out) :: recvbuf(rbuf_siz)
        1484             : #endif
        1485             :
        1486             :    integer :: loption          ! local copy of option
        1487             :    integer :: dest             ! MPI remote process id
        1488             :    integer :: ier              ! MPI error code
        1489             :    integer :: i                ! loop index
        1490             :    integer :: sndids(steps)    ! nonblocking MPI send request ids
        1491             :    integer :: rcvids(steps)    ! nonblocking MPI recv request ids
        1492             :    integer :: status(MPI_STATUS_SIZE)
        1493             : #if ( defined MPI2)
        1494             :    integer(kind=MPI_ADDRESS_KIND) :: ddispls
        1495             : #endif
        1496             :
        1497             : !-----------------------------------------------------------------------
        1498           0 :    loption = option
        1499             :
        1500             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1501             : !  using MPI library collective MPI_ALLTOALLV
        1502             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1503           0 :    if (loption .eq. 0) then
        1504             :
        1505             : #if defined( WRAP_MPI_TIMING )
        1506             :       call t_startf ('mpi_alltoallv')
        1507             : #endif
        1508             :       call mpi_alltoallv (sendbuf, sendcnts, sdispls, sendtype, &
        1509             :                           recvbuf, recvcnts, rdispls, recvtype, &
        1510           0 :                           comm, ier)
        1511             : !
        1512             : ! test for error
        1513           0 :       if (ier/=mpi_success) then
        1514           0 :          write(iulog,*)'altalltoallv (mpi_alltoallv) failed ier=',ier
        1515           0 :          call endrun
        1516             :       end if
        1517             : #if defined( WRAP_MPI_TIMING )
        1518             :       call t_stopf ('mpi_alltoallv')
        1519             : #endif
        1520             :
        1521             :    else
        1522             :
        1523             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1524             : !  Co-Array Fortran implementation of alltoallv
        1525             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1526           0 :       if (loption .eq. 3) then
        1527             :
        1528             : #if ( defined CAF )
        1529             : #if defined( WRAP_MPI_TIMING )
        1530             :          call t_startf ('caf_alltoallv')
        1531             : #endif
        1532             :          if (this_image() .ne. (mytid+1)) then
        1533             :             call endrun('altalltoallv (caf_alltoallv) failed: MPI id .ne. CAF id')
        1534             :          endif
        1535             :
        1536             :          call sync_images()
        1537             :
        1538             :          do i = 1, steps
        1539             :             dest = dests(i)
        1540             :             if (sendcnts(dest) > 0) then
        1541             :                istart = sdispls(dest)+1
        1542             :                iend   = istart+sendcnts(dest)-1
        1543             :                jstart = pdispls(dest)+1
        1544             :                jend   = jstart+sendcnts(dest)-1
        1545             :                recvbuf(jstart:jend)[dest+1] = sendbuf(istart:iend)
        1546             :             end if
        1547             :          end do
        1548             :
        1549             :          call sync_images()
        1550             : #if defined( WRAP_MPI_TIMING )
        1551             :          call t_stopf ('caf_alltoallv')
        1552             : #endif
        1553             : #else
        1554             :          loption = -1
        1555             : #endif
        1556             :
        1557             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1558             : !  MPI-2 one-sided implementation of alltoallv
        1559             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1560           0 :       elseif (loption .eq. 2) then
        1561             : #ifdef MPI2
        1562             : #if defined( WRAP_MPI_TIMING )
        1563             :          call t_startf ('mpi2_alltoallv')
        1564             : #endif
        1565             :          call mpi_win_fence(0,recvwin,ier)
        1566             :          do i=1, steps
        1567             :             dest = dests(i)
        1568             :             if (sendcnts(dest) > 0) then
        1569             :                ddispls = pdispls(dest)
        1570             :                call mpi_put(sendbuf(sdispls(dest)+1), sendcnts(dest), sendtype, &
        1571             :                             dest, ddispls, sendcnts(dest), desttype, &
        1572             :                             recvwin, ier)
        1573             :             endif
        1574             :          end do
        1575             : !
        1576             : ! wait for completion
        1577             :          call mpi_win_fence(0,recvwin,ier)
        1578             :          if (ier/=mpi_success) then
        1579             :             write(iulog,*)'altalltoallv (mpi2_alltoallv) failed ier=',ier
        1580             :             call endrun
        1581             :          end if
        1582             : #if defined( WRAP_MPI_TIMING )
        1583             :          call t_stopf ('mpi2_alltoallv')
        1584             : #endif
        1585             : #else
        1586             :          loption = -1
        1587             : #endif
        1588             :
        1589             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1590             : !  MPI-1 two-sided implementation of alltoallv
        1591             : !  using SWAP routines
        1592             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1593           0 :       elseif (loption .eq. 1) then
        1594             : #if defined( WRAP_MPI_TIMING )
        1595             :          call t_startf ('swap_alltoallv')
        1596             : #endif
        1597             :
        1598             :          call swapm(steps, nprocs, dests,                      &
        1599             :                     sendbuf, sbuf_siz, sendcnts, sdispls,      &
        1600             :                     recvbuf, rbuf_siz, recvcnts, rdispls,      &
        1601           0 :                     comm, swap_comm_protocol, swap_comm_maxreq )
        1602             : !
        1603             : #if defined( WRAP_MPI_TIMING )
        1604             :          call t_stopf ('swap_alltoallv')
        1605             : #endif
        1606             :
        1607             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1608             : !  Anything else defined to be MPI_SENDRECV implementation
        1609             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1610             :       else
        1611             : !
        1612             :          loption = -1
        1613             : !
        1614             :       endif
        1615             :
        1616             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1617             : !  MPI_SENDRECV implementation of alltoallv
        1618             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1619           0 :       if (loption .eq. -1) then
        1620             : #if defined( WRAP_MPI_TIMING )
        1621             :          call t_startf ('mpi1_alltoallv')
        1622             : #endif
        1623           0 :          do i=1, steps
        1624           0 :             dest = dests(i)
        1625           0 :             call mpi_sendrecv (sendbuf(sdispls(dest)+1), sendcnts(dest), &
        1626             :                                sendtype, dest, msgtag,                   &
        1627           0 :                                recvbuf(rdispls(dest)+1), recvcnts(dest), &
        1628             :                                recvtype, dest, msgtag,                   &
        1629           0 :                                comm, status, ier)
        1630             :          end do
        1631             : !
        1632             : ! test for error
        1633           0 :          if (ier/=mpi_success) then
        1634           0 :             write(iulog,*)'altalltoallv (mpi1_alltoallv) failed ier=',ier
        1635           0 :             call endrun
        1636             :          end if
        1637             :
        1638             : #if defined( WRAP_MPI_TIMING )
        1639             :          call t_stopf ('mpi1_alltoallv')
        1640             : #endif
        1641             :       endif
        1642             :
        1643             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1644             : !  Local copy (if necessary)
        1645             : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        1646           0 :       if (sendcnts(mytid) > 0) then
        1647           0 :          do i=1,sendcnts(iam)
        1648           0 :             recvbuf(rdispls(mytid)+i) = sendbuf(sdispls(mytid)+i)
        1649             :          enddo
        1650             :       endif
        1651             : !
        1652             :    endif
        1653             : !
        1654           0 :    return
        1655             :    end subroutine altalltoallv
        1656             :
        1657             : #endif
        1658             :
        1659        1536 :    subroutine spmd_utils_readnl(nlfile)
        1660             : !-----------------------------------------------------------------------
        1661             : !
        1662             : ! Purpose:
        1663             : !   Read spmd utils namelist to set swap communication protocol options as
        1664             : !   well as the flow control gather options
        1665             : !
        1666             : ! Method:
        1667             : ! spmd_utils_readnl:
        1668             : !
        1669             : ! Author of original version:  J. Truesdale
        1670             : !
        1671             : !-----------------------------------------------------------------------
        1672             :
        1673             : !-----------------------------------------------------------------------
        1674             :      use namelist_utils,  only: find_group_name
        1675             :      use units,           only: getunit, freeunit
        1676             :      use mpishorthand
        1677             :
        1678             :      implicit none
        1679             : !---------------------------Input arguments--------------------------
        1680             : !
        1681             :      character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
        1682             :
        1683             : #if ( defined SPMD )
        1684             : !---------------------------Local variables--------------------------
        1685             : !
        1686             :      integer :: unitn, ierr
        1687             :      character(len=*), parameter :: subname = 'spmd_utils_readnl'
        1688             :
        1689             :      namelist /spmd_utils_nl/ swap_comm_protocol,swap_comm_maxreq,fc_gather_flow_cntl
        1690             :
        1691             : !-----------------------------------------------------------------------------
        1692             :
        1693        1536 :      if (masterproc) then
        1694           2 :         unitn = getunit()
        1695           2 :         open( unitn, file=trim(nlfile), status='old' )
        1696           2 :         call find_group_name(unitn, 'spmd_utils_nl', status=ierr)
        1697           2 :         if (ierr == 0) then
        1698           0 :            read(unitn, spmd_utils_nl, iostat=ierr)
        1699           0 :            if (ierr /= 0) then
        1700           0 :               call endrun(subname // ':: ERROR reading namelist')
        1701             :            end if
        1702           0 :            write(iulog,*) 'Read in spmd_utils_nl namelist from: ', trim(nlfile)
        1703             :         end if
        1704           2 :         close(unitn)
        1705           2 :         call freeunit(unitn)
        1706             :
        1707             :
        1708           2 :         if ((swap_comm_protocol < min_comm_protocol) .or. &
        1709             :              (swap_comm_protocol > max_comm_protocol)) then
        1710             :            write(iulog,*)                                        &
        1711           0 :                 'SPMD_UTILS_READNL:  ERROR:  swap_comm_protocol=', &
        1712           0 :                 swap_comm_protocol, ' is out of range.'
        1713             :            write(iulog,*)                                        &
        1714           0 :                 '  It must be between ', min_comm_protocol,' and ',&
        1715           0 :                 max_comm_protocol
        1716             :            write(iulog,*)                                        &
        1717           0 :                 '  Using default value.'
        1718           0 :            swap_comm_protocol = def_comm_protocol
        1719             :         endif
        1720             :
        1721           2 :         write(iulog,*) 'SPMD SWAP_COMM OPTIONS: '
        1722           2 :         write(iulog,*) '  swap_comm_protocol = ', swap_comm_protocol
        1723           2 :         write(iulog,*) '  swap_comm_maxreq   = ', swap_comm_maxreq
        1724           2 :         write(iulog,*) 'SPMD FLOW CONTROL GATHER OPTION: '
        1725           2 :         write(iulog,*) '  fc_gather_flow_cntl = ', fc_gather_flow_cntl
        1726             :      endif
        1727             :
        1728             :      ! Broadcast namelist variables
        1729        1536 :      call mpibcast (swap_comm_protocol , 1,   mpiint ,  0, mpicom)
        1730        1536 :      call mpibcast (swap_comm_maxreq   , 1,   mpiint ,  0, mpicom)
        1731        1536 :      call mpibcast (fc_gather_flow_cntl, 1,   mpiint ,  0, mpicom)
        1732             : #endif
        1733             :
        1734        1536 :    end subroutine spmd_utils_readnl
        1735             :
        1736           0 :  end module spmd_utils

Generated by: LCOV version 1.14