为什么 MPI_REDUCE 在某些数组位置显示不同的数字?

问题描述 投票:0回答:1
program main_mpi_test

    use mpi
    implicit none
    integer(kind=8) :: n                  
    integer(kind=8) :: max_optical_depth  
    integer(kind=8) :: bin               
    integer(kind=8) :: tmax               
    integer(kind=8) :: sum_scatt          
    integer(kind=8) :: i,j,k
    real(kind=8)    :: rad                

    real(kind=8), dimension(:), allocatable :: send_results, recv_results
    integer :: nrank, nproc,ierr,root

    call MPI_INIT(ierr)
    call MPI_COMM_RANK(MPI_COMM_WORLD, nrank, ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, nproc, ierr)
    call MPI_BARRIER(MPI_COMM_WORLD, ierr)
    root = 0

    max_optical_depth = 10
    bin = 10
    tmax = max_optical_depth*bin

    allocate(send_results(tmax))
    allocate(recv_results(tmax))
    
    do i = nrank+1, tmax, nproc
        rad = real(i)/real(bin)
        send_results(i) = rad
        print*,'send', rad, send_results(i)
    end do

    call MPI_BARRIER(MPI_COMM_WORLD, ierr)
    call MPI_REDUCE(send_results, recv_results, tmax, MPI_DOUBLE_PRECISION, &
                    MPI_SUM, root, MPI_COMM_WORLD, ierr)

    if (nrank ==0) then
        do i = 1, tmax
            rad = real(i)/real(bin)
            print*,'recv',rad, recv_results(i)
        end do
    end if

    call MPI_FINALIZE(ierr)
    deallocate(send_results)
    deallocate(recv_results)

end program main_mpi_test

这是我的代码。 我用

MPI_REDUCE
。我使用 mpiifort 编译器。

问题是当我打印recv_results时,

rad
recv_results
的值必须相等,但在数组中的某些位置显示Nan或大约1e186的大数。 在其他位置,
rad
recv_results
具有相同的值。

如何解决这个问题?

print rad, recv_results

fortran mpi message-passing
1个回答
1
投票

你的程序有不少问题。

  1. 如评论中所述,使用
    real(8)
    integer(8)
    是不好的做法。它们不可移植,可能无法达到您的预期,甚至可能不受编译器支持。从您最喜欢的 Fortran 书籍或教程中了解 Fortran 类型,Vladimir 提供的链接(Fortran:整数*4 vs 整数(4) vs 整数(kind=4)Fortran 90 类型参数)是有用的支持材料。我的首选方法是使用
    iso_fortran_env
    标准模块,请参阅下面的程序
  2. 无论
    integer(8)
    做什么(如果支持的话),它都不太可能与 MPI 库兼容。 MPI(对于大多数例程)是根据默认 Fortran 整数定义的,因此我强烈建议您使用默认 Fortran 整数
  3. 您没有初始化所有数组
    send_results
    。因此,正如您所观察到的,任何结果都是可能的。未初始化的东西可以取任何值,只有运气好它们才会为零。
  4. 只有一个参数的
    Real
    函数将该参数转换为默认实数类型的值,这不是您想要的。这与上面的 1) 密切相关,但是要获得您想要的类型,您需要提供该类型。请参阅下面的我的程序
  5. 虽然不是错误,但在下面的代码中使用
    MPI_Barrier
    是完全没有必要的,只是浪费时间 -
    MPI_Reduce
    已经阻塞了。根据经验,除了测量时序、调试以及可能使用共享内存时,您永远不会需要 mpi_barrier

(对于纯粹主义者来说,我可能也应该调用

MPI_Type_create_f90_real
但我会很懒,假设
MPI_DOUBLE_PRECISION
映射到
real64

无论如何,这是我的程序,它与 gfortran、ifort 和 ifx 一起使用

ijb@ijb-Latitude-5410:~/work/stack$ cat red.f90
Program main_mpi_test

  Use iso_fortran_env, Only : wp => real64

  Use mpi
  
  Implicit None

  Real( wp ), Dimension(:), Allocatable :: send_results, recv_results

  Real( wp )    :: rad                

  Integer :: n                  
  Integer :: max_optical_depth  
  Integer :: bin               
  Integer :: tmax               
  Integer :: sum_scatt          
  Integer :: i,j,k
  Integer :: nrank, nproc, ierr, root

  Logical :: worked
  
  Call MPI_INIT(ierr)
  Call MPI_COMM_RANK(MPI_COMM_WORLD, nrank, ierr)
  Call MPI_COMM_SIZE(MPI_COMM_WORLD, nproc, ierr)
  Call MPI_BARRIER(MPI_COMM_WORLD, ierr)
  root = 0
  
  max_optical_depth = 10
  bin = 10
  tmax = max_optical_depth*bin
  
  Allocate(send_results(tmax))
  Allocate(recv_results(tmax))

  send_results = 0.0_wp
  Do i = nrank+1, tmax, nproc
     rad = Real( i, Kind( rad ) ) / Real( bin, Kind( rad ) )
     send_results(i) = rad
!     Print*,'send', rad, send_results(i)
  End Do
  
  Call MPI_REDUCE(send_results, recv_results, tmax, MPI_DOUBLE_PRECISION, &
       MPI_SUM, root, MPI_COMM_WORLD, ierr)
  
  If (nrank ==0 ) Then
     worked = .true.
     Do i = 1, tmax
        rad = Real( i, Kind( rad ) ) / Real( bin, Kind( rad ) )
!        Write( *, * ) 'recv', rad, recv_results(i)
        worked = worked .And. ( Abs( rad - recv_results(i) ) < 1e-15_wp  )
     End Do
     Write( *, * ) "Worked? ", worked
  End If
  
  Deallocate(send_results)
  Deallocate(recv_results)
  
  Call MPI_FINALIZE(ierr)

End Program main_mpi_test
  
ijb@ijb-Latitude-5410:~/work/stack$ mpif90 -Wall -Wextra -fcheck=all -O -g red.f90
red.f90:18:16:

   18 |   Integer :: i,j,k
      |                1
Warning: Unused variable ‘j’ declared at (1) [-Wunused-variable]
red.f90:18:18:

   18 |   Integer :: i,j,k
      |                  1
Warning: Unused variable ‘k’ declared at (1) [-Wunused-variable]
red.f90:13:14:

   13 |   Integer :: n
      |              1
Warning: Unused variable ‘n’ declared at (1) [-Wunused-variable]
red.f90:17:22:

   17 |   Integer :: sum_scatt
      |                      1
Warning: Unused variable ‘sum_scatt’ declared at (1) [-Wunused-variable]
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 4 ./a.out
 Worked?  T
ijb@ijb-Latitude-5410:~/work/stack$ mpiifort red.f90
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 4 ./a.out
 Worked?  T
ijb@ijb-Latitude-5410:~/work/stack$ mpiifort -fc=ifx red.f90
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 4 ./a.out
 Worked?  T
ijb@ijb-Latitude-5410:~/work/stack$ 
© www.soinside.com 2019 - 2024. All rights reserved.