2017-04-26 2 views
1

Je me bats depuis quelques jours avec un appel MPI_REDUCE dans un code de modèle de transport atmosphérique gfortran, ayant de bons paramètres d'entrée, mais retournant des résultats très déraisonnables dans le recvbuf du maître. Je suis en mesure de reproduire le problème dans un exemple simple, comme suit:MPI_REDUCE renvoie une mauvaise réponse pour 1000x1000x6 REAL array

PROGRAM TEST 

    USE mpi 

    IMPLICIT NONE 

    INTEGER my_rank, size, ierror 
    INTEGER, PARAMETER :: nx=1000, ny=1000, nz=6 
    INTEGER :: buffsize 

    REAL, DIMENSION(nx, ny, nz) :: u, v 

    call MPI_INIT(ierror) 
    call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD, my_rank, ierror) 

    PRINT *, 'my_rank, size: ', my_rank, size 

    buffsize = nx*ny*nz 

    u = my_rank + 1 

    PRINT *, 'PE: ', my_rank, ', Before reduce, SHAPE(u): ', SHAPE(u) 
    PRINT *, 'PE: ', my_rank, ', Before reduce, SUM(u): ', SUM(u) 

    CALL MPI_REDUCE(u, v, buffsize, MPI_REAL, & 
&     MPI_SUM, 0, MPI_COMM_WORLD, ierror) 

    CALL MPI_BARRIER(MPI_COMM_WORLD, ierror) 

    PRINT *, 'PE: ', my_rank, ', after reduce, ierror: ', ierror 
    PRINT *, 'PE: ', my_rank, ', after reduce, SUM(u): ', SUM(u) 
    PRINT *, 'PE: ', my_rank, ', after reduce, SUM(v): ', SUM(v) 

    CALL MPI_FINALIZE(ierror) 

END PROGRAM test 

Il retourne:

mpirun -np 2 ./test3 
my_rank, size:   0   2 
my_rank, size:   1   2 
PE:   1 , Before reduce, SHAPE(u):   1000  1000   6 
PE:   0 , Before reduce, SHAPE(u):   1000  1000   6 
PE:   0 , Before reduce, SUM(u): 6000000.00  
PE:   1 , Before reduce, SUM(u): 12000000.0  
PE:   0 , after reduce, ierror:   0 
PE:   1 , after reduce, ierror:   0 
PE:   1 , after reduce, SUM(u): 12000000.0  
PE:   0 , after reduce, SUM(u): 6000000.00  
PE:   1 , after reduce, SUM(v): 0.00000000  
PE:   0 , after reduce, SUM(v): 18407592.0  

PE0 « devrait » être montrant 18.000.000,0 comme SUM (v) dans le dernier ligne.

Si je mets le paramètre nz dans le code de 6 à 5, l'exécution produit des résultats corrects. Ce qui est vraiment déroutant, c'est qu'il se comporte de la sorte, renvoyant la même somme de valeurs réduites sur a) une instance AWS EC2 avec gfortran 5.3 et openmpi, b) gfortran 5.4 avec mpich, et c) un gfortran 4.4 avec openmpi.

Si je change le type de tableau en DOUBLE PRECISION (aussi bien que cela spécifie que dans l'appel MPI_REDUCE) cela fonctionne bien, même pour des tableaux beaucoup plus grands. Si j'utilise REAL4 plutôt que REAL, cela produit les mêmes mauvais résultats. Je sais que cela doit être simple et que je suis un vrai idiot ici, mais je ne comprends tout simplement pas cela. J'ai lu quelques suggestions que ma taille de tampon doit être une valeur entière inférieure à 2^31-1, mais c'est certainement le cas ici.

Répondre

3

Cela n'a rien à voir avec MPI, juste une question de précision de sommation:

PROGRAM TEST 
    IMPLICIT NONE 
    INTEGER, PARAMETER :: nx=1000, ny=1000, nz=6 
    REAL, DIMENSION(nx, ny, nz) :: u 
    u = 3 
    PRINT *, SUM(u) 
END PROGRAM test 

Renvoie le même résultat. Si vous ajoutez un grand nombre à un petit nombre, il peut y avoir des problèmes d'arrondi, dans une somme de nombreux petits nombres, cet effet peut cumuler une erreur significative. Il existe des algorithmes de sommation pour empêcher cet effet, comme Kahan summation, apparemment le SUM de Fortran n'est pas implémenté de cette façon.

+4

Fortran ne précise en effet pas comment «somme» fonctionne, mais simplement que le résultat «a une valeur égale à une approximation dépendant du processeur de la somme». Différents compilateurs traitent cela comme un problème de qualité de mise en œuvre, comme on peut le voir dans [cette autre question] (https://stackoverflow.com/q/25316371). – francescalus