изпрати mpi съобщение от c++ код към fortran 90 код

Опитвам се да видя дали мога да изпратя съдържанието на масив в C++ код към Fortran 90 код. Използвам openmpi 1.4.3, създаден с помощта на компилатори intel 11.1.072. Те са инсталирани на Linux версия 2.6.18-108chaos (mockbuild@chaos4builder1) (gcc версия 4.1.2 20080704 (Red Hat 4.1.2-48)).

Ето страната на c++:

# include <cstdlib>
# include <iostream>
# include <mpi.h>
using namespace std;

void printarray (float arg[], int length) {
   for (int n=0; n<length; n++)
    cout << arg[n] << " ";
  cout << "\n";
}

int main(int argc, char *argv[] ){
   float a[10];
   int myrank,i;
   MPI::Init ( argc, argv );
   myrank=MPI::COMM_WORLD.Get_rank();
   cout << "rank "<<myrank<<" is c++ rank."<<std::endl;
   for (i=0;i<10;i++){
      a[i]=10.0;
   }
   printarray(a,10);
   MPI::COMM_WORLD.Send(&a[0],1,MPI::DOUBLE_PRECISION,1,100);
   MPI::Finalize();
}

а ето и страната на f90:

program main
implicit none
include "mpif.h"
integer:: ierr,stat(MPI_STATUS_SIZE)
real(8):: a(10)

call mpi_init(ierr)
a=0
print*,a
call mpi_recv(a(1),10,MPI_DOUBLE_PRECISION,0,100,MPI_COMM_WORLD,stat,ierr)
print*,a
call mpi_finalize(ierr)
end program

след като съм компилирал двата кода, стартирам с

$mpirun -n 1 *c_executable* : -n 1 *fortran_executable* > output

Числата, които получавам от страна на fortran, не са 10.0.


person user1596782    schedule 14.08.2012    source източник
comment
Не използвайте MPI C++ свързванията! Те са премахнати във версията чернова 2 на спецификацията MPI 3.0 и тази промяна най-вероятно ще стигне до окончателния стандарт 3.0. Вместо това използвайте C свързванията - те са доста подобни на тези за Fortran. Използвайте също интерфейса на MPI модула във Fortran: USE mpi вместо include "mpif.h".   -  person Hristo Iliev    schedule 14.08.2012


Отговори (3)


Стандартът MPI наистина има разпоредби за езикова оперативна съвместимост - целият §16.3 на документа MPI 2.2 е посветен на езиковата оперативна съвместимост между Fortran и C.

§16.3.10 Междуезикова комуникация

Правилата за съответствие на типа за комуникации в MPI anr не са променени: спецификацията на типа данни за всеки изпратен елемент трябва да съвпада, в подписа на типа, със спецификацията на типа данни, използвана за получаване на този елемент (освен ако един от типовете не е MPI_PACKED). Освен това типът на елемент от съобщението трябва да съответства на декларацията за тип за съответното местоположение на комуникационния буфер, освен ако типът не е MPI_BYTE или MPI_PACKED. Междуезикова комуникация е разрешена, ако отговаря на тези правила.

След това се показва пример, при който един и същ конструиран тип данни се използва за изпращане на съобщение от код на Fortran и за получаването му в част от C код. Типът е конструиран така, че да позволи на C кода да получава данните в буфер, който принадлежи на Fortran кода, но това, което е по-подходящо за вашия въпрос е, че C кодът използва тип данни, който е конструиран от Fortran MPI_REAL. Използването на типове данни Fortran в C функции и обратното е напълно законно, ако има смисъл:

§16.3.6 MPI непрозрачни обекти - типове данни

... Ако тип данни, дефиниран на един език, се използва за комуникационно повикване на друг език, тогава изпратеното съобщение ще бъде идентично на съобщението, което би било изпратено от първия език: има достъп до същия комуникационен буфер и същото представяне преобразуването се извършва, ако е необходимо. Всички предварително дефинирани типове данни могат да се използват в конструктори на типове данни на всеки език. Ако даден тип данни е ангажиран, той може да се използва за комуникация на всеки език.

(предварително дефинирани MPI типове данни като MPI_REAL и MPI_DOUBLE са ангажирани)

Напротив, използването на типове данни Fortran от едната страна и C типове данни от другата е разрешено, но се счита за непреносимо:

§16.3.10 Междуезикова комуникация

... Реализациите на MPI могат да отслабят тези правила за съвпадение на типове и да позволят съобщенията да се изпращат с типове Fortran и да се получават с типове C и обратно, когато тези типове съвпадат. Т.е., ако типът Fortran INTEGER е идентичен с типа C int, тогава изпълнението на MPI може да позволи изпращането на данни с тип данни MPI_INTEGER и получаването им с тип данни MPI_INT. Такъв код обаче не е преносим.

(подчертаването е мое)

Промяната на REAL(8) на DOUBLE PRECISION не прави нищо за увеличаване на преносимостта на вашия код, тъй като стандартът Fortran не гарантира нищо относно представянето на типа DOUBLE PRECISION - той само казва, че DOUBLE PRECISION е алтернативен спецификатор за един вид тип REAL, а именно вида с двойна точност, който трябва да има по-голяма десетична точност от реалната по подразбиране. Изпращането на REAL(8) с тип данни MPI_DOUBLE_PRECISION не е преносимо. Вместо това една преносима програма би използвала SELECTED_REAL_KIND присъщия на Fortran заедно с MPI_Type_create_f90_real, за да регистрира съответстващ MPI тип данни.

Най-добрият вариант IMHO е да разчитате на езиковата оперативна съвместимост между C и Fortran и да се придържате към едни и същи типове данни от двете страни. Тъй като вашият компилаторен пакет е достатъчно нов, можете да използвате механизма ISO_C_BINDING на Fortran, за да получите REAL и INTEGER видове, съвместими с C, и да използвате C типовете данни в извикванията на Fortran. Например:

USE, INTRINSIC :: ISO_C_BINDING
REAL(C_DOUBLE), DIMENSION(10) :: darray
INTEGER(C_INT) :: ival
...
CALL MPI_SEND(darray, 10, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, ierr)
CALL MPI_BCAST(ival, 1, MPI_INT, 0, MPI_COMM_WORLD, ierr)
...
person Hristo Iliev    schedule 14.08.2012
comment
+1 за изчерпателност! Промяната на REAL(8) на DOUBLE PRECISION не прави нищо за увеличаване на преносимостта -- добре, така е, тъй като REAL(8) не съществува непременно (или означава това, което може да се очаква) за всички компилатори, докато двойната прецизност го прави. OTOH, BIND(C) е добра идея, но на практика, за всяка машина, на която можете да си представите да изчисляте днес, представянето с плаваща запетая ще бъде същото за Fortran или C -- по-голямо притеснение може да бъде кръстосано архитектура за двете програми (от малък до голям порядък), за които трябва да преминете изцяло през различни набори от обръчи. - person Jonathan Dursi; 14.08.2012
comment
@JonathanDursi, повечето общи реализации на MPI (включително Open MPI) поддържат хетерогенни среди (в Open MPI това е опция за време за конфигуриране, деактивирана по подразбиране поради причини за ефективност) и ще извършват автоматично магическо преобразуване на представяне (endinanness и т.н.) в движение на данни, изпращани между възли с различни архитектури. Би трябвало да е възможно да се справите грациозно с такъв сценарий, като използвате преносимите C типове и техните ISO_C_BINDING двойници и останете в рамките на това, което MPI системата за типове данни позволява (напр. без фантазия с MPI_BYTE). - person Hristo Iliev; 14.08.2012

Да, можете да направите това; основният проблем е, че във вашия C++ код вашият a масив е от тип float, а не двойно.

Вие също така изпращате само 1, а не 10 от тези не-двойни; MPI_RECV() пак ще работи, но разбира се другите 9 стойности няма да бъдат зададени.

Нещо друго, което трябва да имате предвид е, че трябва да използвате MPI_DOUBLE в C/C++ и MPI_DOUBLE_PRECISION във Fortran; не е необходимо те да са еднакви и всъщност си представям, че използването на MPI_DOUBLE_PRECISION в C е недефинирано.

Вероятно също така искате да използвате double precision в програмата fortran вместо real(8), което е често срещано, но не е стандартно.

По принцип бихте искали дори да се тревожите за хетерогенността, за кодирането на числата с плаваща запетая на машините, изпълняващи двете програми, но за повечето от нас това не е проблем.

person Jonathan Dursi    schedule 14.08.2012
comment
Промених масива на двойна прецизност в кода fortran и на double в кода на c++ и зададох типа данни c++ mpi на mpi::double и масивът беше успешно комуникиран към страната fortran. Мисля, че сте прави, че mpi_double_precision може да е недефиниран в c. Благодаря! - person user1596782; 14.08.2012
comment
Смесването на MPI типове данни от различни езици е повече от определено в стандарта - вижте моя отговор. - person Hristo Iliev; 14.08.2012

Ето една модифицирана работеща версия на C

#include <stdio.h>
#include <mpi.h>

main(int argc, char **argv) 
{
  int i,ierr, num_procs, my_id;
  double a[10];

  for (i=0;i<10;i++)
  {
    a[i]=10.0;
  }

  ierr = MPI_Init(&argc, &argv);

  printf(" Hello C Code\n"); 

  /**/
  ierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
  ierr = MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
  ierr = MPI_Send(&a[0],10,MPI_DOUBLE,1,100, MPI_COMM_WORLD);  


  ierr = MPI_Finalize(); 

}

Ето модифицирана работна версия на F

    program main
        use mpi

        implicit none
        integer:: ierr,stat(MPI_STATUS_SIZE)
        double precision:: a(10)

        call mpi_init(ierr)

        write(*,*)"Hello F Code"
        a=0
        print*,a
        call mpi_recv(a(1),10,MPI_DOUBLE_PRECISION,0,100,MPI_COMM_WORLD,stat,ierr)
        print*,a
        call mpi_finalize(ierr)
    end program
person momba    schedule 18.10.2013