How do I retain precision for a Fortran MPI program in a portable way?

前端 未结 3 1971
独厮守ぢ
独厮守ぢ 2020-12-11 01:36

I have a Fortran program where I specify the kind of the numeric data types in an attempt to retain a minimum level of precision, regardless of what compiler is

相关标签:
3条回答
  • 2020-12-11 01:51

    How about:

    integer, parameter :: DOUBLE_PREC = kind(0.0d0)
    integer, parameter :: SINGLE_PREC = kind(0.0e0)
    
    integer, parameter :: MYREAL = DOUBLE_PREC
    
    
    if (MYREAL .eq. DOUBLE_PREC) then
       MPIREAL = MPI_DOUBLE_PRECISION
    else if (MYREAL .eq. SINGLE_PREC) then
       MPIREAL = MPI_REAL
    else
       print *, "Erorr: Can't figure out MPI precision."
       STOP
    end if
    

    and use MPIREAL instead of MPI_DOUBLE_PRECISION from then on.

    0 讨论(0)
  • 2020-12-11 01:54

    Not really an answer, but we have the same problem and use something like this:

    !> Number of digits for single precision numbers
    integer, parameter, public :: single_prec = 6
    !> Number of digits for double precision numbers
    integer, parameter, public :: double_prec = 15
    !> Number of digits for extended double precision numbers
    integer, parameter, public :: xdble_prec = 18
    !> Number of digits for quadruple precision numbers
    integer, parameter, public :: quad_prec = 33
    
    integer, parameter, public :: rk_prec = double_prec
    
    !> The kind to select for default reals
    integer, parameter, public :: rk = selected_real_kind(rk_prec)
    

    And then have an initialization routine where we do:

    !call mpi_type_create_f90_real(rk_prec, MPI_UNDEFINED, rk_mpi, iError)
    !call mpi_type_create_f90_integer(long_prec, long_k_mpi, iError)
    ! Workaround shitty MPI-Implementations.
    select case(rk_prec)
    case(single_prec)
      rk_mpi = MPI_REAL
    case(double_prec)
      rk_mpi = MPI_DOUBLE_PRECISION
    case(quad_prec)
      rk_mpi = MPI_REAL16
    case default
      write(*,*) 'unknown real type specified for mpi_type creation'
    end select
    long_k_mpi = MPI_INTEGER8
    

    While this is not nice, it works reasonably well, and seems to be usable on Cray, IBM BlueGene and conventional Linux Clusters. Best thing to do is push sites and vendors to properly support this in MPI. As far as I know it has been fixed in OpenMPI and planned to be fixed in MPICH by 3.1.1. See OpenMPI Tickets 3432 and 3435 as well as MPICH Tickets 1769 and 1770.

    0 讨论(0)
  • 2020-12-11 02:07

    Use the Fortran 2008 intrinsic STORAGE_SIZE to determine the number bytes that each number requires and send as bytes. Note that STORAGE_SIZE returns the size in bits, so you will need to divide by 8 to get the size in bytes.

    This solution works for moving data but does not help you use reductions. For that you will have to implement a user-defined reduction operation. If that's important to you, I will update my answer with the details.

    For example:

    program main
    
       use mpi
    
       implicit none
    
       integer, parameter :: rsp = selected_real_kind(16)
       integer :: err
       integer :: rank
    
       real(rsp) :: real_var
    
       call MPI_Init(err)
       call MPI_Comm_rank(MPI_COMM_WORLD,rank,err)
    
       if (rank.eq.0) then
          real_var = 1.123456789012345
          call MPI_Send(real_var,storage_size(real_var)/8,MPI_BYTE,1,5,MPI_COMM_WORLD,err)
       else
          call MPI_Recv(real_var,storage_size(real_var)/8,MPI_BYTE,0,5,MPI_COMM_WORLD,&
             MPI_STATUS_IGNORE,err)
       end if
    
       print *, rank, real_var
    
       call MPI_Finalize(err)
    
    end program main
    

    I confirmed that this change corrects the problem and the output I see is:

       0   1.12345683574676513672      
       1   1.12345683574676513672  
    
    0 讨论(0)
提交回复
热议问题