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 used to build the program. For example:
integer, parameter :: rsp = selected_real_kind(4)
...
real(kind=rsp) :: real_var
The problem is that I have used MPI to parallelize the code and I need to make sure the MPI communications are specifying the same type with the same precision. I was using the following approach to stay consistent with the approach in my program:
call MPI_Type_create_f90_real(4,MPI_UNDEFINED,rsp_mpi,mpi_err)
...
call MPI_Send(real_var,1,rsp_mpi,dest,tag,MPI_COMM_WORLD,err)
However, I have found that this MPI routine is not particularly well-supported for different MPI implementations, so it's actually making my program non-portable. If I omit the MPI_Type_create
routine, then I'm left to rely on the standard MPI_REAL
and MPI_DOUBLE_PRECISION
data types, but what if that type is not consistent with what selected_real_kind
picks as the real type that will ultimately be passed around by MPI? Am I stuck just using the standard real
declaration for a datatype, with no kind
attribute and, if I do that, am I guaranteed that MPI_REAL
and real
are always going to have the same precision, regardless of compiler and machine?
UPDATE:
I created a simple program that demonstrates the issue I see when my internal reals have higher precision than what is afforded by the MPI_DOUBLE_PRECISION
type:
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,1,MPI_DOUBLE_PRECISION,1,5,MPI_COMM_WORLD,err)
else
call MPI_Recv(real_var,1,MPI_DOUBLE_PRECISION,0,5,MPI_COMM_WORLD,&
MPI_STATUS_IGNORE,err)
end if
print *, rank, real_var
call MPI_Finalize(err)
end program main
If I build and run with 2 cores, I get:
0 1.12345683574676513672
1 4.71241976735884452383E-3998
Now change the 16 to a 15 in selected_real_kind
and I get:
0 1.1234568357467651
1 1.1234568357467651
Is it always going to be safe to use selected_real_kind(15)
with MPI_DOUBLE_PRECISION
no matter what machine/compiler is used to do the build?
wp = selected_real_kind(14,40)
and then usesMPI_DOUBLE_PRECISION
in the MPI calls. As far as I can tell, there is no issue with it. – Nonobservancereal
s always be compatible withMPI_DOUBLE_PRECISION
if I define theirkind
explicitly? – DemiMPI_DOUBLE_PRECISION
. As long as you use between 7 and 15 (inclusive), you ought to be fine to useMPI_DOUBLE_PRECISION
. – NonobservanceMPI_DOUBLE_PRECISION
always mean that the MPI communications are retaining between 7 and 15 digits of precision, regardless of system/compiler? In other words, if I specify myreal
s to have 14 digits precision, and then do my MPI communications withMPI_DOUBLE_PRECISION
, am I ever going to have to be concerned about getting a result like the one I posted, where the number comes out as garbage on the receiving end? – Demiselected_real_kind
, you coulduse ISO_FORTRAN_ENV
and use typesreal32
andreal64
(number of bits) to portably specify single and double precision reals. – Amphictyonyreal32
will always be compatible withMPI_REAL
andreal64
will always be compatible withMPI_DOUBLE_PRECISION
? – Demireal :: var
as opposed toreal(rsp) :: var
? – Demi