LCOV - code coverage report
Current view: top level - dynamics/se/dycore - parallel_mod.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 51 65 78.5 %
Date: 2024-12-17 17:57:11 Functions: 3 4 75.0 %

          Line data    Source code
       1             : module parallel_mod
       2             :   ! ---------------------------
       3             :   use shr_kind_mod,   only: r8=>shr_kind_r8
       4             :   ! ---------------------------
       5             :   use dimensions_mod, only : nmpi_per_node, nlev, qsize_d, ntrac_d
       6             :   ! ---------------------------
       7             :   use spmd_utils,     only: MPI_STATUS_SIZE, MPI_MAX_ERROR_STRING, MPI_TAG_UB
       8             : 
       9             :   implicit none
      10             :   private
      11             : 
      12             :   integer,  public, parameter   :: ORDERED         = 1
      13             :   integer,  public, parameter   :: FAST            = 2
      14             :   integer,  public, parameter   :: BNDRY_TAG_BASE  = 0
      15             :   integer,  public, parameter   :: THREAD_TAG_BITS = 9
      16             :   integer,  public, parameter   :: MAX_ACTIVE_MSG = (MPI_TAG_UB/2**THREAD_TAG_BITS) - 1
      17             :   integer,  public, parameter   :: HME_status_size = MPI_STATUS_SIZE
      18             : 
      19             :   integer,  public, parameter   :: HME_BNDRY_P2P   = 1
      20             :   integer,  public, parameter   :: HME_BNDRY_MASHM = 2
      21             :   integer,  public, parameter   :: HME_BNDRY_A2A   = 3
      22             :   integer,  public, parameter   :: HME_BNDRY_A2AO  = 4
      23             : 
      24             :   integer,  public, parameter   :: nrepro_vars = MAX(10, nlev*qsize_d, nlev*ntrac_d)
      25             : 
      26             :   integer,  public              :: MaxNumberFrames
      27             :   integer,  public              :: numframes
      28             :   integer,  public              :: useframes
      29             :   logical,  public              :: PartitionForNodes
      30             :   logical,  public              :: PartitionForFrames
      31             : 
      32             :   ! Namelist-selectable type of boundary comms (AUTO,P2P,A2A,MASHM)
      33             :   integer,  public              :: boundaryCommMethod
      34             : 
      35             :   integer,  public, allocatable :: status(:,:)
      36             :   integer,  public, allocatable :: Rrequest(:)
      37             :   integer,  public, allocatable :: Srequest(:)
      38             : 
      39             :   real(r8), public, allocatable :: FrameWeight(:)
      40             :   integer,  public, allocatable :: FrameIndex(:)
      41             :   integer,  public, allocatable :: FrameCount(:)
      42             :   integer,  public              :: nComPoints
      43             :   integer,  public              :: nPackPoints
      44             : 
      45             :   real(r8), public, allocatable :: global_shared_buf(:,:)
      46             :   real(r8), public              :: global_shared_sum(nrepro_vars)
      47             : 
      48             :   ! ==================================================
      49             :   ! Define type parallel_t for distributed memory info
      50             :   ! ==================================================
      51             :   type, public :: parallel_t
      52             :     integer :: rank                       ! local rank
      53             :     integer :: root                       ! local root
      54             :     integer :: nprocs                     ! number of processes in group
      55             :     integer :: comm                       ! communicator
      56             :     integer :: intracomm                  ! Intra-node communicator
      57             :     integer :: commGraphFull              ! distributed graph topo communicator for all neighbors
      58             :     integer :: commGraphInter             ! distributed graph topo communicator for off-node neighbors
      59             :     integer :: commGraphIntra             ! distributed graph topo communicator for on-node neighbors
      60             :     integer :: groupGraphFull
      61             :     logical :: masterproc
      62             :   end type
      63             : 
      64             :   type (parallel_t), public :: par ! info for distributed memory programming
      65             : 
      66             :   ! ===================================================
      67             :   ! Module Interfaces
      68             :   ! ===================================================
      69             : 
      70             :   public :: initmpi
      71             :   public :: syncmp
      72             :   public :: copy_par
      73             : 
      74             :   interface assignment ( = )
      75             :     module procedure copy_par
      76             :   end interface
      77             : 
      78             : CONTAINS
      79             : 
      80             : ! ================================================
      81             : !   copy_par: copy constructor for parallel_t type
      82             : !
      83             : !
      84             : !   Overload assignment operator for parallel_t
      85             : ! ================================================
      86             : 
      87     1113600 :   subroutine copy_par(par2,par1)
      88             :     type(parallel_t), intent(out) :: par2
      89             :     type(parallel_t), intent(in)  :: par1
      90             : 
      91     1113600 :     par2%rank       = par1%rank
      92     1113600 :     par2%root       = par1%root
      93     1113600 :     par2%nprocs     = par1%nprocs
      94     1113600 :     par2%comm       = par1%comm
      95     1113600 :     par2%intracomm  = par1%intracomm
      96     1113600 :     par2%commGraphFull   = par1%commGraphFull
      97     1113600 :     par2%commGraphInter  = par1%commGraphInter
      98     1113600 :     par2%commGraphIntra  = par1%commGraphIntra
      99     1113600 :     par2%groupGraphFull  = par1%groupGraphFull
     100     1113600 :     par2%masterproc = par1%masterproc
     101             : 
     102     1113600 :   end subroutine copy_par
     103             : 
     104             : ! ================================================
     105             : !  initmpi:
     106             : !  Initializes the parallel (message passing)
     107             : !  environment, returns a parallel_t structure..
     108             : ! ================================================
     109             : 
     110        1536 :   function initmpi(npes_homme) result(par)
     111             :     use cam_logfile,    only: iulog
     112             :     use cam_abortutils, only: endrun
     113             :     use spmd_utils,     only: mpicom, MPI_COMM_NULL, MPI_MAX_PROCESSOR_NAME
     114             :     use spmd_utils,     only: MPI_CHARACTER, MPI_INTEGER, MPI_BAND, iam, npes
     115             : 
     116             :     integer, intent(in) :: npes_homme
     117             : 
     118             :     type(parallel_t)     :: par
     119             : 
     120             :     integer              :: ierr,tmp
     121             :     integer              :: FrameNumber
     122             :     logical :: running   ! state of MPI at beginning of initmpi call
     123             :     character(len=MPI_MAX_PROCESSOR_NAME)               :: my_name
     124        1536 :     character(len=MPI_MAX_PROCESSOR_NAME), allocatable  :: the_names(:)
     125             : 
     126             :     integer, allocatable :: tarray(:)
     127             :     integer              :: namelen, i
     128             :     integer              :: color
     129             : 
     130             :     !================================================
     131             :     !     Basic MPI initialization
     132             :     ! ================================================
     133             : 
     134        1536 :     call MPI_initialized(running, ierr)
     135             : 
     136        1536 :     if (.not.running) then
     137           0 :       call endrun('initmpi: MPI not initialized for SE dycore')
     138             :     end if
     139             : 
     140        1536 :     par%root          = 0
     141        1536 :     par%masterproc    = .FALSE.
     142        1536 :     nmpi_per_node     = 2
     143        1536 :     PartitionForNodes = .TRUE.
     144             : 
     145             :     ! The SE dycore needs to split from CAM communicator for npes > par%nprocs
     146        1536 :     color = iam / npes_homme
     147        1536 :     call mpi_comm_split(mpicom, color, iam, par%comm, ierr)
     148        1536 :     if (iam < npes_homme) then
     149        1536 :       call MPI_comm_size(par%comm, par%nprocs, ierr)
     150        1536 :       call MPI_comm_rank(par%comm, par%rank,  ierr)
     151        1536 :       if ( par%nprocs /= npes_homme) then
     152           0 :         call endrun('INITMPI: SE communicator count mismatch')
     153             :       end if
     154             : 
     155        1536 :       if(par%rank == par%root) then
     156           2 :         par%masterproc = .TRUE.
     157             :       end if
     158             :     else
     159           0 :       par%rank   = 0
     160           0 :       par%nprocs = 0
     161           0 :       par%comm   = MPI_COMM_NULL
     162             :     end if
     163             : 
     164        1536 :     if (par%masterproc) then
     165           2 :       write(iulog, '(a,i0)')'initmpi: Number of MPI processes: ', par%nprocs
     166             :     end if
     167             : 
     168        1536 :     if (iam < npes_homme) then
     169             :       ! ================================================
     170             :       !  Determine where this MPI process is running
     171             :       !   then use this information to determined the
     172             :       !   number of MPI processes per node
     173             :       ! ================================================
     174        1536 :       my_name(:) = ''
     175        1536 :       call MPI_Get_Processor_Name(my_name, namelen, ierr)
     176             : 
     177        4608 :       allocate(the_names(par%nprocs))
     178     1181184 :       do i = 1, par%nprocs
     179     1181184 :         the_names(i)(:) =  ''
     180             :       end do
     181             : 
     182             :       ! ================================================
     183             :       !   Collect all the machine names
     184             :       ! ================================================
     185             :       call MPI_Allgather(my_name, MPI_MAX_PROCESSOR_NAME, MPI_CHARACTER, &
     186        1536 :            the_names,MPI_MAX_PROCESSOR_NAME,MPI_CHARACTER,par%comm,ierr)
     187             : 
     188             :       ! ======================================================================
     189             :       !   Calculate how many other MPI processes are on my node
     190             :       ! ======================================================================
     191        1536 :       nmpi_per_node = 0
     192     1181184 :       do i = 1, par%nprocs
     193     1181184 :         if(TRIM(ADJUSTL(my_name)) .eq. TRIM(ADJUSTL(the_names(i)))) then
     194      196608 :           nmpi_per_node = nmpi_per_node + 1
     195             :         end if
     196             :       end do
     197             : 
     198             :       ! =======================================================================
     199             :       !  Verify that everybody agrees on this number otherwise do not do
     200             :       !  the multi-level partitioning
     201             :       ! =======================================================================
     202        1536 :       call MPI_Allreduce(nmpi_per_node,tmp,1,MPI_INTEGER,MPI_BAND,par%comm,ierr)
     203        1536 :       if(tmp /= nmpi_per_node) then
     204           0 :         if (par%masterproc) then
     205           0 :           write(iulog,*)'initmpi:  disagrement accross nodes for nmpi_per_node'
     206             :         end if
     207           0 :         nmpi_per_node = 1
     208           0 :         PartitionForNodes = .FALSE.
     209             :       else
     210        1536 :         PartitionForNodes = .TRUE.
     211             :       end if
     212             : 
     213        1536 :       if(PartitionForFrames .and. par%masterproc) then
     214           0 :         write(iulog,*)'initmpi: FrameWeight: ', FrameWeight
     215             :       end if
     216             : 
     217        1536 :       deallocate(the_names)
     218             :     end if
     219             : 
     220        1536 :   end function initmpi
     221             : 
     222             :   ! =====================================
     223             :   ! syncmp:
     224             :   !
     225             :   ! sychronize message passing domains
     226             :   !
     227             :   ! =====================================
     228        3072 :   subroutine syncmp(par)
     229             :     use cam_abortutils, only: endrun
     230             :     use spmd_utils,     only: MPI_MAX_ERROR_STRING, MPI_ERROR
     231             : 
     232             :     type (parallel_t), intent(in)       :: par
     233             : 
     234             :     integer                             :: errorcode, errorlen, ierr
     235             :     character(len=MPI_MAX_ERROR_STRING) :: errorstring
     236             : 
     237        3072 :     call MPI_barrier(par%comm, ierr)
     238             : 
     239        3072 :     if(ierr == MPI_ERROR) then
     240           0 :       errorcode = ierr
     241           0 :       call MPI_Error_String(errorcode, errorstring, errorlen, ierr)
     242           0 :       call endrun(errorstring)
     243             :     end if
     244        3072 :   end subroutine syncmp
     245             : 
     246           0 : end module parallel_mod

Generated by: LCOV version 1.14