module MpiUtils implicit none #ifdef MPI ! use mpi leads to .mod compiler incompatibility errors unless you are very careful ! so stick to old method and add manual interface for gcc10+ compatibility include "mpif.h" #if __GNUC__ > 9 interface subroutine MPI_BCAST(BUFFER, COUNT, DATATYPE, ROOT, COMM, IERROR) !GCC$ ATTRIBUTES NO_ARG_CHECK :: BUFFER Type(*) BUFFER INTEGER COUNT, DATATYPE, ROOT, COMM, IERROR end subroutine end interface #endif #endif integer, parameter :: TTimer_dp = Kind(1.d0) Type TTimer real(TTimer_dp) start_time contains procedure :: Start => TTimer_Start procedure :: Time => TTimer_Time procedure :: WriteTime => TTimer_WriteTime end type TTimer contains function GetMpiRank() integer GetMpiRank #ifdef MPI integer ierror call mpi_comm_rank(mpi_comm_world,GetMPIrank,ierror) if (ierror/=MPI_SUCCESS) call MpiStop('MPI fail') #else GetMpiRank=0 #endif end function GetMpiRank function IsMainMPI() logical IsMainMPI IsMainMPI = GetMpiRank() == 0 end function IsMainMPI subroutine MpiStop(Msg) character(LEN=*), intent(in), optional :: Msg integer i #ifdef MPI integer ierror, MpiRank #endif if (present(Msg)) write(*,*) trim(Msg) #ifdef MPI call mpi_comm_rank(mpi_comm_world,MPIrank,ierror) write (*,*) 'MpiStop: ', MpiRank call MPI_ABORT(MPI_COMM_WORLD,i, ierror) #endif i=1 !put breakpoint on this line to debug #ifndef MPI if (msg/='') error stop #endif stop end subroutine MpiStop subroutine MpiStat(MpiID, MpiSize) implicit none integer MpiID,MpiSize #ifdef MPI integer ierror call mpi_comm_rank(mpi_comm_world,MpiID,ierror) if (ierror/=MPI_SUCCESS) call MpiStop('MpiStat: MPI rank') call mpi_comm_size(mpi_comm_world,MpiSize,ierror) #else MpiID=0 MpiSize=1 #endif end subroutine MpiStat subroutine MpiQuietWait !Set MPI thread to sleep, e.g. so can run openmp on cpu instead #ifdef MPI integer ierr, STATUS(MPI_STATUS_SIZE) logical flag integer i, MpiId, MpiSize call MpiStat(MpiID, MpiSize) if (MpiID/=0) then do call MPI_IPROBE(0,0,MPI_COMM_WORLD,flag, MPI_STATUS_IGNORE,ierr) if (flag) then call MPI_RECV(i,1,MPI_INTEGER, 0,0,MPI_COMM_WORLD,status,ierr) exit end if call sleep(1) end do end if #endif end subroutine subroutine MpiWakeQuietWait #ifdef MPI integer j, MpiId, MpiSize, ierr,r call MpiStat(MpiID, MpiSize) if (MpiID==0) then do j=1, MpiSize-1 call MPI_ISSEND(MpiId,1,MPI_INTEGER, j,0,MPI_COMM_WORLD,r,ierr) end do end if #endif end subroutine MpiWakeQuietWait subroutine MpiShareString(S, from) character(LEN=:), allocatable :: S integer from #ifdef MPI integer inlen, rank, ierror rank = GetMpiRank() if (rank==from) inlen=len(S) CALL MPI_Bcast(inlen, 1, MPI_INTEGER, from, MPI_COMM_WORLD, ierror) if (ierror/=MPI_SUCCESS) call MpiStop('MpiShareString: fail') if (rank /= from ) allocate(character(inlen)::S) CALL MPI_Bcast(S, LEN(S), MPI_CHARACTER, from, MPI_COMM_WORLD, ierror) #endif end subroutine MpiShareString function TimerTime() real(TTimer_dp) time real(TTimer_dp) :: TimerTime !$ real(TTimer_dp), external :: omp_get_wtime #ifdef MPI TimerTime = MPI_WTime() #else time = 0 !$ time = OMP_GET_WTIME() if (time==0) call cpu_time(time) TimerTime= time #endif end function TimerTime subroutine TTimer_Start(this, time) class(TTimer) :: this real(TTimer_dp), intent(out), optional :: time this%start_time = TimerTime() if (present(time)) time = this%start_time end subroutine TTimer_Start real(TTimer_dp) function TTimer_Time(this) class(TTimer) :: this TTimer_Time = TimerTime() - this%start_time end function TTimer_Time subroutine TTimer_WriteTime(this,Msg, start) class(TTimer) :: this character(LEN=*), intent(in), optional :: Msg real(TTimer_dp), optional :: start real(TTimer_dp) T, DeltaT character(LEN=:), allocatable :: tmp if (present(start)) then T=start else T=this%start_time end if DeltaT = TimerTime() - T if (present(Msg)) then tmp = trim(Msg)//': ' if (DeltaT > 0.00002 .and. DeltaT < 1000 .and. len_trim(tmp)<24) then write (*,'(a25,f10.5)') tmp, DeltaT else write (*,*) trim(Msg)//': ', DeltaT end if end if if (.not. present(start)) this%start_time = TimerTime() end subroutine TTimer_WriteTime end module MpiUtils