module seq_comm_mct 31,4
!---------------------------------------------------------------------
!
! Purpose: MCT utitlity functions used in sequential CCSM.
! Note that if no MPI, will call MCTs fake version
! (including mpif.h) will be utilized
!
! Author: R. Jacob
!
!---------------------------------------------------------------------
use mct_mod
, only : mct_world_init, mct_die
use shr_sys_mod
, only : shr_sys_abort, shr_sys_flush
use shr_mpi_mod
, only : shr_mpi_chkerr, shr_mpi_bcast
use shr_file_mod
, only : shr_file_getUnit, shr_file_freeUnit
implicit none
save
private
!--------------------------------------------------------------------------
! Public interfaces
!--------------------------------------------------------------------------
public seq_comm_init
public seq_comm_iamin
public seq_comm_iamroot
public seq_comm_mpicom
public seq_comm_iam
public seq_comm_gloiam
public seq_comm_cplpe
public seq_comm_cmppe
public seq_comm_setptrs
public seq_comm_setnthreads
public seq_comm_getnthreads
public seq_comm_printcomms
!--------------------------------------------------------------------------
! Public data
!--------------------------------------------------------------------------
integer, public :: logunit = 6 ! log unit number
integer, public :: loglevel = 1 ! log level
! NOTE: the LNDID must be 1 as this is currently hardwired in
! clm for lnd/rtm mapping. This constraint can be removed when
! clm gets the compid from the driver.
integer, parameter, public :: ncomps = 12
integer, parameter, public :: LNDID = 1
integer, parameter, public :: ATMID = 2
integer, parameter, public :: OCNID = 3
integer, parameter, public :: ICEID = 4
integer, parameter, public :: GLCID = 5
integer, parameter, public :: CPLID = 6
integer, parameter, public :: GLOID = 7
integer, parameter, public :: CPLATMID = 8
integer, parameter, public :: CPLLNDID = 9
integer, parameter, public :: CPLICEID = 10
integer, parameter, public :: CPLOCNID = 11
integer, parameter, public :: CPLGLCID = 12
character(len=8),parameter,private :: IDname(ncomps) = &
(/ ' LND ',' ATM ',' OCN ',' ICE ',' GLC ', &
' CPL ',' GLOBAL ',' CPLATM ',' CPLLND ',' CPLICE ', &
' CPLOCN ',' CPLGLC ' /)
type seq_comm_type
character(len=8) :: name ! my name, see IDname above
integer :: ID ! my id number, see parameters above
integer :: mpicom ! mpicom
integer :: mpigrp ! mpigrp
integer :: npes ! number of pes in comm
integer :: nthreads ! number of omp threads per pe
integer :: iam ! my pe number in mpicom
logical :: iamroot ! am i the root pe in mpicom
integer :: gloiam ! my pe number in mpi_comm_world
integer :: pethreads ! max number of threads on my pe
integer :: cplpe ! a common pe in mpicom from the cpl group for join mpicoms
integer :: cmppe ! a common pe in mpicom from the component group for join mpicoms
logical :: set ! has this datatype been set
end type seq_comm_type
type(seq_comm_type) :: seq_comms(ncomps)
character(*),parameter :: F11 = "(a,a,'(',i3,a,')',a, 3i6,' (',a,i6,')',' (',a,i3,')')"
character(*),parameter :: F12 = "(a,a,'(',i3,a,')',a,2i6,6x,' (',a,i6,')',' (',a,i3,')','(',a,2i6,')')"
character(*),parameter :: F13 = "(a,a,'(',i3,a,')',a,2i6,6x,' (',a,i6,')',' (',a,i3,')')"
#include <mpif.h>
!=======================================================================
contains
!=======================================================================
subroutine seq_comm_init(nmlfile, atm_petlist, lnd_petlist, ice_petlist, ocn_petlist, glc_petlist) 1,22
!----------------------------------------------------------
!
! Arguments
implicit none
character(len=*), intent(IN) :: nmlfile
integer, pointer, optional :: atm_petlist(:)
integer, pointer, optional :: lnd_petlist(:)
integer, pointer, optional :: ice_petlist(:)
integer, pointer, optional :: ocn_petlist(:)
integer, pointer, optional :: glc_petlist(:)
!
! Local variables
!
integer :: ierr,n
character(*),parameter :: subName = '(seq_comm_init) '
integer :: mpi_group_world ! MPI_COMM_WORLD group
integer :: mype,numpes,myncomps,max_threads
integer :: amin,amax,astr
integer :: lmin,lmax,lstr
integer :: imin,imax,istr
integer :: omin,omax,ostr
integer :: gmin,gmax,gstr
integer :: cmin,cmax,cstr
integer :: pelist(3,1) ! start, stop, stride for group
integer, pointer :: comps(:) ! array with component ids
integer, pointer :: comms(:) ! array with mpicoms
integer :: onecomm ! single comm for "old" mct init
integer :: nu, i
logical,save :: first_pass = .true. !
integer :: &
atm_ntasks, atm_rootpe, atm_pestride, atm_nthreads, &
lnd_ntasks, lnd_rootpe, lnd_pestride, lnd_nthreads, &
ice_ntasks, ice_rootpe, ice_pestride, ice_nthreads, &
glc_ntasks, glc_rootpe, glc_pestride, glc_nthreads, &
ocn_ntasks, ocn_rootpe, ocn_pestride, ocn_nthreads, &
cpl_ntasks, cpl_rootpe, cpl_pestride, cpl_nthreads
namelist /ccsm_pes/ &
atm_ntasks, atm_rootpe, atm_pestride, atm_nthreads, &
lnd_ntasks, lnd_rootpe, lnd_pestride, lnd_nthreads, &
ice_ntasks, ice_rootpe, ice_pestride, ice_nthreads, &
glc_ntasks, glc_rootpe, glc_pestride, glc_nthreads, &
ocn_ntasks, ocn_rootpe, ocn_pestride, ocn_nthreads, &
cpl_ntasks, cpl_rootpe, cpl_pestride, cpl_nthreads
!----------------------------------------------------------
! make sure this is first pass and set comms unset
if (.not. first_pass) then
write(logunit,*) trim(subname),' ERROR seq_comm_init already called '
call shr_sys_abort
()
endif
first_pass = .false.
do n = 1,ncomps
seq_comms(n)%set = .false.
seq_comms(n)%mpicom = MPI_COMM_NULL ! do some initialization here
seq_comms(n)%iam = -1
seq_comms(n)%iamroot = .false.
seq_comms(n)%npes = -1
seq_comms(n)%nthreads = -1
seq_comms(n)%gloiam = -1
seq_comms(n)%pethreads = -1
seq_comms(n)%cplpe = -1
seq_comms(n)%cmppe = -1
enddo
! Initialize MPI
! Note that if no MPI, will call MCTs fake version
call mpi_init(ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_init')
call mpi_comm_rank(MPI_COMM_WORLD, mype , ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_rank comm_world')
call mpi_comm_size(MPI_COMM_WORLD, numpes, ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_size comm_world')
! Initialize gloiam on all IDs
do n = 1,ncomps
seq_comms(n)%gloiam = mype
enddo
! Initialize IDs
if (mype == 0) then
! Set default values
atm_ntasks=numpes; atm_rootpe=0; atm_pestride=1; atm_nthreads=1
lnd_ntasks=numpes; lnd_rootpe=0; lnd_pestride=1; lnd_nthreads=1
ice_ntasks=numpes; ice_rootpe=0; ice_pestride=1; ice_nthreads=1
glc_ntasks=numpes; glc_rootpe=0; glc_pestride=1; glc_nthreads=1
ocn_ntasks=numpes; ocn_rootpe=0; ocn_pestride=1; ocn_nthreads=1
cpl_ntasks=numpes; cpl_rootpe=0; cpl_pestride=1; cpl_nthreads=1
! Read namelist if it exists
nu = shr_file_getUnit
()
open(nu,file=trim(nmlfile),status='old', iostat=ierr)
if (ierr == 0) then
ierr = 1
do while( ierr > 0 )
read(nu, nml=ccsm_pes, iostat=ierr)
end do
close(nu)
end if
call shr_file_freeUnit
(nu)
!--- validation of inputs ---
! rootpes >= 0
if (atm_rootpe < 0 .or. lnd_rootpe < 0 .or. ice_rootpe < 0 .or. &
ocn_rootpe < 0 .or. glc_rootpe < 0 .or. cpl_rootpe < 0) then
write(logunit,*) trim(subname),' ERROR: rootpes must be >= 0'
call shr_sys_abort
()
endif
! ! nthreads = 1, temporary
! if (atm_nthreads /= 1 .or. lnd_nthreads /= 1 .or. ice_nthreads /= 1 .or. &
! ocn_nthreads /= 1 .or. cpl_nthreads /= 1) then
! write(logunit,*) trim(subname),' ERROR: nthreads must be 1'
! call shr_sys_abort()
! endif
! ! nthreads should be 1 or something consistent, compute max nthreads
! amax = max(atm_nthreads,lnd_nthreads)
! amax = max(amax ,ice_nthreads)
! amax = max(amax ,ocn_nthreads)
! amax = max(amax ,cpl_nthreads)
! ! check that everything is either 1 or max nthreads
! if ((atm_nthreads /= 1 .and. atm_nthreads /= amax) .or. &
! (lnd_nthreads /= 1 .and. lnd_nthreads /= amax) .or. &
! (ice_nthreads /= 1 .and. ice_nthreads /= amax) .or. &
! (ocn_nthreads /= 1 .and. ocn_nthreads /= amax) .or. &
! (cpl_nthreads /= 1 .and. cpl_nthreads /= amax)) then
! write(logunit,*) trim(subname),' ERROR: nthreads must be consistent'
! call shr_sys_abort()
! endif
endif
! NOTE: Only valid on root pe due to namelist read above, bcast below
if (mype == 0) then
amin = atm_rootpe
amax = atm_rootpe + (atm_ntasks-1)*atm_pestride
astr = atm_pestride
lmin = lnd_rootpe
lmax = lnd_rootpe + (lnd_ntasks-1)*lnd_pestride
lstr = lnd_pestride
imin = ice_rootpe
imax = ice_rootpe + (ice_ntasks-1)*ice_pestride
istr = ice_pestride
omin = ocn_rootpe
omax = ocn_rootpe + (ocn_ntasks-1)*ocn_pestride
ostr = ocn_pestride
gmin = glc_rootpe
gmax = glc_rootpe + (glc_ntasks-1)*glc_pestride
gstr = glc_pestride
cmin = cpl_rootpe
cmax = cpl_rootpe + (cpl_ntasks-1)*cpl_pestride
cstr = cpl_pestride
end if
! create petlist for ESMF components
if(present(atm_petlist)) then
call shr_mpi_bcast(atm_ntasks, MPI_COMM_WORLD, 'atm_ntasks')
call shr_mpi_bcast(atm_rootpe, MPI_COMM_WORLD, 'atm_rootpe')
call shr_mpi_bcast(atm_pestride, MPI_COMM_WORLD, 'atm_pestride')
allocate(atm_petlist(atm_ntasks))
do i = 1, atm_ntasks
atm_petlist(i) = atm_rootpe + (i-1)*atm_pestride
enddo
endif
if(present(lnd_petlist)) then
call shr_mpi_bcast(lnd_ntasks, MPI_COMM_WORLD, 'lnd_ntasks')
call shr_mpi_bcast(lnd_rootpe, MPI_COMM_WORLD, 'lnd_rootpe')
call shr_mpi_bcast(lnd_pestride, MPI_COMM_WORLD, 'lnd_pestride')
allocate(lnd_petlist(lnd_ntasks))
do i = 1, lnd_ntasks
lnd_petlist(i) = lnd_rootpe + (i-1)*lnd_pestride
enddo
endif
if(present(ice_petlist)) then
call shr_mpi_bcast(ice_ntasks, MPI_COMM_WORLD, 'ice_ntasks')
call shr_mpi_bcast(ice_rootpe, MPI_COMM_WORLD, 'ice_rootpe')
call shr_mpi_bcast(ice_pestride, MPI_COMM_WORLD, 'ice_pestride')
allocate(ice_petlist(ice_ntasks))
do i = 1, ice_ntasks
ice_petlist(i) = ice_rootpe + (i-1)*ice_pestride
enddo
endif
if(present(ocn_petlist)) then
call shr_mpi_bcast(ocn_ntasks, MPI_COMM_WORLD, 'ocn_ntasks')
call shr_mpi_bcast(ocn_rootpe, MPI_COMM_WORLD, 'ocn_rootpe')
call shr_mpi_bcast(ocn_pestride, MPI_COMM_WORLD, 'ocn_pestride')
allocate(ocn_petlist(ocn_ntasks))
do i = 1, ocn_ntasks
ocn_petlist(i) = ocn_rootpe + (i-1)*ocn_pestride
enddo
endif
if(present(glc_petlist)) then
call shr_mpi_bcast(glc_ntasks, MPI_COMM_WORLD, 'glc_ntasks')
call shr_mpi_bcast(glc_rootpe, MPI_COMM_WORLD, 'glc_rootpe')
call shr_mpi_bcast(glc_pestride, MPI_COMM_WORLD, 'glc_pestride')
allocate(glc_petlist(glc_ntasks))
do i = 1, glc_ntasks
glc_petlist(i) = glc_rootpe + (i-1)*glc_pestride
enddo
endif
call shr_mpi_bcast(atm_nthreads,MPI_COMM_WORLD,'atm_nthreads')
call shr_mpi_bcast(lnd_nthreads,MPI_COMM_WORLD,'lnd_nthreads')
call shr_mpi_bcast(ocn_nthreads,MPI_COMM_WORLD,'ocn_nthreads')
call shr_mpi_bcast(ice_nthreads,MPI_COMM_WORLD,'ice_nthreads')
call shr_mpi_bcast(glc_nthreads,MPI_COMM_WORLD,'glc_nthreads')
call shr_mpi_bcast(cpl_nthreads,MPI_COMM_WORLD,'cpl_nthreads')
! Create MPI communicator groups
if (mype == 0) then
pelist(1,1) = 0
pelist(2,1) = numpes-1
pelist(3,1) = 1
end if
call mpi_bcast(pelist, size(pelist), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
call seq_comm_setcomm
(GLOID,pelist)
if (mype == 0) then
pelist(1,1) = amin
pelist(2,1) = amax
pelist(3,1) = astr
end if
call mpi_bcast(pelist, size(pelist), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
call seq_comm_setcomm
(ATMID,pelist,atm_nthreads)
if (mype == 0) then
pelist(1,1) = lmin
pelist(2,1) = lmax
pelist(3,1) = lstr
end if
call mpi_bcast(pelist, size(pelist), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
call seq_comm_setcomm
(LNDID,pelist,lnd_nthreads)
if (mype == 0) then
pelist(1,1) = imin
pelist(2,1) = imax
pelist(3,1) = istr
end if
call mpi_bcast(pelist, size(pelist), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
call seq_comm_setcomm
(ICEID,pelist,ice_nthreads)
if (mype == 0) then
pelist(1,1) = gmin
pelist(2,1) = gmax
pelist(3,1) = gstr
end if
call mpi_bcast(pelist, size(pelist), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
call seq_comm_setcomm
(GLCID,pelist,glc_nthreads)
if (mype == 0) then
pelist(1,1) = omin
pelist(2,1) = omax
pelist(3,1) = ostr
end if
call mpi_bcast(pelist, size(pelist), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
call seq_comm_setcomm
(OCNID,pelist,ocn_nthreads)
if (mype == 0) then
pelist(1,1) = cmin
pelist(2,1) = cmax
pelist(3,1) = cstr
end if
call mpi_bcast(pelist, size(pelist), MPI_INTEGER, 0, MPI_COMM_WORLD, ierr)
call seq_comm_setcomm
(CPLID,pelist,cpl_nthreads)
call seq_comm_joincomm
(CPLID,ATMID,CPLATMID)
call seq_comm_joincomm
(CPLID,LNDID,CPLLNDID)
call seq_comm_joincomm
(CPLID,ICEID,CPLICEID)
call seq_comm_joincomm
(CPLID,OCNID,CPLOCNID)
call seq_comm_joincomm
(CPLID,GLCID,CPLGLCID)
max_threads = -1
do n = 1,ncomps
max_threads = max(max_threads,seq_comms(n)%nthreads)
enddo
do n = 1,ncomps
seq_comms(n)%pethreads = max_threads
enddo
! Initialize MCT
! add up valid comps on local pe
myncomps = 0
do n = 1,ncomps
if (seq_comms(n)%mpicom /= MPI_COMM_NULL) then
myncomps = myncomps + 1
endif
enddo
! set comps and comms
allocate(comps(myncomps),comms(myncomps),stat=ierr)
if(ierr/=0) call mct_die(subName,'allocate comps comms',ierr)
myncomps = 0
do n = 1,ncomps
if (seq_comms(n)%mpicom /= MPI_COMM_NULL) then
myncomps = myncomps + 1
if (myncomps > size(comps)) then
write(logunit,*) trim(subname),' ERROR in myncomps ',myncomps,size(comps)
call shr_sys_abort
()
endif
comps(myncomps) = seq_comms(n)%ID
comms(myncomps) = seq_comms(n)%mpicom
onecomm = seq_comms(n)%mpicom ! if one unique comm per pe, then pick any
endif
enddo
if (myncomps /= size(comps)) then
write(logunit,*) trim(subname),' ERROR in myncomps ',myncomps,size(comps)
call shr_sys_abort
()
endif
call mct_world_init(ncomps, MPI_COMM_WORLD, comms, comps)
deallocate(comps,comms)
call seq_comm_printcomms
()
end subroutine seq_comm_init
!---------------------------------------------------------
subroutine seq_comm_setcomm(ID,pelist,nthreads) 7,6
implicit none
integer,intent(IN) :: ID
integer,intent(IN) :: pelist(:,:)
integer,intent(IN),optional :: nthreads
integer :: mpigrp_world
integer :: mpigrp
integer :: mpicom
integer :: ierr
character(*),parameter :: subName = '(seq_comm_setcomm) '
if (ID < 1 .or. ID > ncomps) then
write(logunit,*) subname,' ID out of range, abort ',ID
call shr_sys_abort
()
endif
call mpi_comm_group(MPI_COMM_WORLD, mpigrp_world, ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_group mpigrp_world')
call mpi_group_range_incl(mpigrp_world, 1, pelist, mpigrp,ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_group_range_incl mpigrp')
call mpi_comm_create(MPI_COMM_WORLD, mpigrp, mpicom, ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_create mpigrp')
seq_comms(ID)%set = .true.
seq_comms(ID)%ID = ID
seq_comms(ID)%name = IDname(ID)
seq_comms(ID)%mpicom = mpicom
seq_comms(ID)%mpigrp = mpigrp
if (present(nthreads)) then
seq_comms(ID)%nthreads = nthreads
else
seq_comms(ID)%nthreads = 1
endif
if (mpicom /= MPI_COMM_NULL) then
call mpi_comm_size(mpicom,seq_comms(ID)%npes,ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_size')
call mpi_comm_rank(mpicom,seq_comms(ID)%iam,ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_rank')
if (seq_comms(ID)%iam == 0) then
seq_comms(ID)%iamroot = .true.
else
seq_comms(ID)%iamroot = .false.
endif
else
seq_comms(ID)%npes = -1
seq_comms(ID)%iam = -1
seq_comms(ID)%nthreads = 1
seq_comms(ID)%iamroot = .false.
endif
if (seq_comms(ID)%iamroot) then
write(logunit,F11) trim(subname),' initialize ID ',ID,seq_comms(ID)%name, &
' pelist =',pelist,' npes =',seq_comms(ID)%npes,' nthreads =',seq_comms(ID)%nthreads
endif
end subroutine seq_comm_setcomm
!---------------------------------------------------------
subroutine seq_comm_joincomm(ID1,ID2,ID) 5,9
implicit none
integer,intent(IN) :: ID1 ! src id
integer,intent(IN) :: ID2 ! srd id
integer,intent(IN) :: ID ! computed id
integer :: mpigrp
integer :: mpicom
integer :: ierr
integer :: n,nsize
integer,allocatable :: pe_t1(:),pe_t2(:)
character(*),parameter :: subName = '(seq_comm_joincomm) '
! check that IDs are in valid range, that ID1 and ID2 have
! been set, and that ID has not been set
if (ID1 < 1 .or. ID1 > ncomps) then
write(logunit,*) subname,' ID1 out of range, abort ',ID1
call shr_sys_abort
()
endif
if (ID2 < 1 .or. ID2 > ncomps) then
write(logunit,*) subname,' ID2 out of range, abort ',ID2
call shr_sys_abort
()
endif
if (ID < 1 .or. ID > ncomps) then
write(logunit,*) subname,' ID out of range, abort ',ID
call shr_sys_abort
()
endif
if (.not. seq_comms(ID1)%set .or. .not. seq_comms(ID2)%set) then
write(logunit,*) subname,' ID1 or ID2 not set ',ID1,ID2
call shr_sys_abort
()
endif
if (seq_comms(ID)%set) then
write(logunit,*) subname,' ID already set ',ID
call shr_sys_abort
()
endif
call mpi_group_union(seq_comms(ID1)%mpigrp,seq_comms(ID2)%mpigrp,mpigrp,ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_union mpigrp')
call mpi_comm_create(MPI_COMM_WORLD, mpigrp, mpicom, ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_create mpigrp')
seq_comms(ID)%set = .true.
seq_comms(ID)%ID = ID
seq_comms(ID)%name = IDname(ID)
seq_comms(ID)%mpicom = mpicom
seq_comms(ID)%mpigrp = mpigrp
seq_comms(ID)%nthreads = max(seq_comms(ID1)%nthreads,seq_comms(ID2)%nthreads)
seq_comms(ID)%nthreads = max(seq_comms(ID)%nthreads,1)
if (mpicom /= MPI_COMM_NULL) then
call mpi_comm_size(mpicom,seq_comms(ID)%npes,ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_size')
call mpi_comm_rank(mpicom,seq_comms(ID)%iam,ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_rank')
if (seq_comms(ID)%iam == 0) then
seq_comms(ID)%iamroot = .true.
else
seq_comms(ID)%iamroot = .false.
endif
else
seq_comms(ID)%npes = -1
seq_comms(ID)%iam = -1
seq_comms(ID)%iamroot = .false.
endif
! needs to be excluded until mpi_group_size is added to serial mpi in mct
#if (1 == 0)
if (loglevel > 3) then
! some debug code to prove the join is working ok
! when joining mpicomms, the local rank may be quite different
! from either the global or local ranks of the joining comms
call mpi_group_size(seq_comms(ID1)%mpigrp,nsize,ierr)
allocate(pe_t1(nsize),pe_t2(nsize))
do n = 1,nsize
pe_t1(n) = n-1
pe_t2(n) = -1
enddo
call mpi_group_translate_ranks(seq_comms(ID1)%mpigrp, nsize, pe_t1, mpigrp, pe_t2, ierr)
write(logunit,*) 'ID1 ranks ',pe_t1
write(logunit,*) 'ID1-JOIN ranks ',pe_t2
deallocate(pe_t1,pe_t2)
call mpi_group_size(seq_comms(ID2)%mpigrp,nsize,ierr)
allocate(pe_t1(nsize),pe_t2(nsize))
do n = 1,nsize
pe_t1(n) = n-1
pe_t2(n) = -1
enddo
call mpi_group_translate_ranks(seq_comms(ID2)%mpigrp, nsize, pe_t1, mpigrp, pe_t2, ierr)
write(logunit,*) 'ID2 ranks ',pe_t1
write(logunit,*) 'ID2-JOIN ranks ',pe_t2
deallocate(pe_t1,pe_t2)
endif
#endif
allocate(pe_t1(1),pe_t2(1))
pe_t1(1) = 0
call mpi_group_translate_ranks(seq_comms(ID1)%mpigrp, 1, pe_t1, mpigrp, pe_t2, ierr)
seq_comms(ID)%cplpe = pe_t2(1)
pe_t1(1) = 0
call mpi_group_translate_ranks(seq_comms(ID2)%mpigrp, 1, pe_t1, mpigrp, pe_t2, ierr)
seq_comms(ID)%cmppe = pe_t2(1)
deallocate(pe_t1,pe_t2)
if (seq_comms(ID)%iamroot) then
if (loglevel > 1) then
write(logunit,F12) trim(subname),' initialize ID ',ID,seq_comms(ID)%name, &
' join IDs =',ID1,ID2,' npes =',seq_comms(ID)%npes, &
' nthreads =',seq_comms(ID)%nthreads, &
' cpl/cmp pes =',seq_comms(ID)%cplpe,seq_comms(ID)%cmppe
else
write(logunit,F13) trim(subname),' initialize ID ',ID,seq_comms(ID)%name, &
' join IDs =',ID1,ID2,' npes =',seq_comms(ID)%npes, &
' nthreads =',seq_comms(ID)%nthreads
endif
endif
end subroutine seq_comm_joincomm
!---------------------------------------------------------
subroutine seq_comm_printcomms() 1,6
implicit none
character(*),parameter :: subName = '(seq_comm_printcomms) '
integer :: m,n,mype,npes,cpes,ierr
character(len=256) :: iamstring
character(*),parameter :: F01 = "(4x,a4,4x ,40(1x,a8))"
character(*),parameter :: F02 = "(4x,i4,3x,a1,40(2x,i6,1x))"
character(*),parameter :: F03 = "(4x,i4,3x,a1,a)"
call mpi_comm_size(MPI_COMM_WORLD, npes , ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_size comm_world')
call mpi_comm_rank(MPI_COMM_WORLD, mype , ierr)
call shr_mpi_chkerr
(ierr,subname//' mpi_comm_rank comm_world')
call shr_sys_flush
(logunit)
call mpi_barrier(MPI_COMM_WORLD,ierr)
if (mype == 0) then
! do n = 1,ncomps
! call mpi_group_size(seq_comms(n)%mpigrp, cpes, ierr)
! call shr_mpi_chkerr(ierr,subname//' mpi_group_size')
! write(logunit,*) trim(subName),' comp ntasks,nthreads ',n,trim(seq_comms(n)%name), &
! seq_comms(n)%npes,seq_comms(n)%nthreads
! enddo
write(logunit,*) ' '
write(logunit,*) trim(subName),' ID layout : global pes vs local pe for each ID'
write(logunit,F01) ' gpe',(seq_comms(n)%name,n=1,ncomps),'nthrds'
write(logunit,F01) ' ---',(' ------ ' ,n=1,ncomps),'------'
call shr_sys_flush
(logunit)
endif
iamstring = ' '
do n = 1,ncomps
if (seq_comms(n)%iam >= 0) then
write(iamstring((n-1)*9+1:n*9),"(2x,i6,1x)") seq_comms(n)%iam
endif
enddo
n = ncomps + 1
write(iamstring((n-1)*9+1:n*9),"(2x,i6,1x)") seq_comms(GLOID)%pethreads
call shr_sys_flush
(logunit)
call mpi_barrier(MPI_COMM_WORLD,ierr)
do m = 0,npes-1
if (mype == m) then
! write(logunit,F02) mype,':',(seq_comms(n)%iam,n=1,ncomps)
write(logunit,F03) mype,':',trim(iamstring)
if (m == npes-1) then
write(logunit,*) ' '
endif
endif
call shr_sys_flush
(logunit)
call mpi_barrier(MPI_COMM_WORLD,ierr)
enddo
end subroutine seq_comm_printcomms
!---------------------------------------------------------
subroutine seq_comm_setptrs(ID,mpicom,mpigrp,npes,nthreads,iam,iamroot,gloiam,cplpe,cmppe,pethreads) 54
implicit none
integer,intent(in) :: ID
integer,intent(out),optional :: mpicom
integer,intent(out),optional :: mpigrp
integer,intent(out),optional :: npes
integer,intent(out),optional :: nthreads
integer,intent(out),optional :: iam
logical,intent(out),optional :: iamroot
integer,intent(out),optional :: gloiam
integer,intent(out),optional :: cplpe
integer,intent(out),optional :: cmppe
integer,intent(out),optional :: pethreads
character(*),parameter :: subName = '(seq_comm_setptrs) '
if (ID < 1 .or. ID > ncomps) then
write(logunit,*) subname,' ID out of range, return ',ID
return
endif
if (present(mpicom)) then
mpicom = seq_comms(ID)%mpicom
endif
if (present(mpigrp)) then
mpigrp = seq_comms(ID)%mpigrp
endif
if (present(npes)) then
npes = seq_comms(ID)%npes
endif
if (present(nthreads)) then
nthreads = seq_comms(ID)%nthreads
endif
if (present(iam)) then
iam = seq_comms(ID)%iam
endif
if (present(iamroot)) then
iamroot = seq_comms(ID)%iamroot
endif
if (present(gloiam)) then
gloiam = seq_comms(ID)%gloiam
endif
if (present(cplpe)) then
cplpe = seq_comms(ID)%cplpe
endif
if (present(cmppe)) then
cmppe = seq_comms(ID)%cmppe
endif
if (present(pethreads)) then
pethreads = seq_comms(ID)%pethreads
endif
end subroutine seq_comm_setptrs
!---------------------------------------------------------
subroutine seq_comm_setnthreads(nthreads) 109,1
implicit none
integer,intent(in) :: nthreads
character(*),parameter :: subName = '(seq_comm_setnthreads) '
#ifdef _OPENMP
if (nthreads < 1) then
call shr_sys_abort
(subname//' ERROR: nthreads less than one')
endif
call omp_set_num_threads(nthreads)
#endif
end subroutine seq_comm_setnthreads
!---------------------------------------------------------
integer function seq_comm_getnthreads() 7
implicit none
integer :: omp_get_num_threads
character(*),parameter :: subName = '(seq_comm_getnthreads) '
seq_comm_getnthreads = -1
#ifdef _OPENMP
!$OMP PARALLEL
seq_comm_getnthreads = omp_get_num_threads()
!$OMP END PARALLEL
#endif
end function seq_comm_getnthreads
!---------------------------------------------------------
logical function seq_comm_iamin(ID) 19
implicit none
integer,intent(in) :: ID
character(*),parameter :: subName = '(seq_comm_iamin) '
if (seq_comms(ID)%iam >= 0) then
seq_comm_iamin = .true.
else
seq_comm_iamin = .false.
endif
end function seq_comm_iamin
!---------------------------------------------------------
logical function seq_comm_iamroot(ID) 38
implicit none
integer,intent(in) :: ID
character(*),parameter :: subName = '(seq_comm_iamroot) '
seq_comm_iamroot = seq_comms(ID)%iamroot
end function seq_comm_iamroot
!---------------------------------------------------------
integer function seq_comm_mpicom(ID)
implicit none
integer,intent(in) :: ID
character(*),parameter :: subName = '(seq_comm_mpicom) '
seq_comm_mpicom = seq_comms(ID)%mpicom
end function seq_comm_mpicom
!---------------------------------------------------------
integer function seq_comm_iam(ID)
implicit none
integer,intent(in) :: ID
character(*),parameter :: subName = '(seq_comm_iam) '
seq_comm_iam = seq_comms(ID)%iam
end function seq_comm_iam
!---------------------------------------------------------
integer function seq_comm_gloiam(ID)
implicit none
integer,intent(in) :: ID
character(*),parameter :: subName = '(seq_comm_gloiam) '
seq_comm_gloiam = seq_comms(ID)%gloiam
end function seq_comm_gloiam
!---------------------------------------------------------
integer function seq_comm_cplpe(ID)
implicit none
integer,intent(in) :: ID
character(*),parameter :: subName = '(seq_comm_cplpe) '
seq_comm_cplpe = seq_comms(ID)%cplpe
end function seq_comm_cplpe
!---------------------------------------------------------
integer function seq_comm_cmppe(ID)
implicit none
integer,intent(in) :: ID
character(*),parameter :: subName = '(seq_comm_cmppe) '
seq_comm_cmppe = seq_comms(ID)%cmppe
end function seq_comm_cmppe
!---------------------------------------------------------
end module seq_comm_mct