отправить сообщение mpi из кода С++ в код fortran 90

Я пытаюсь посмотреть, могу ли я отправить содержимое массива в коде С++ в код 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)).

Вот сторона С++:

# 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

Цифры, которые я получаю на стороне фортрана, не 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 не изменились: спецификация типа данных для каждого отправляемого элемента должна совпадать в сигнатуре типа со спецификацией типа данных, используемой для получения этого элемента (если только один из типов не является MPI_PACKED). Кроме того, тип элемента сообщения должен совпадать с объявлением типа для соответствующего местоположения буфера связи, если тип не MPI_BYTE или MPI_PACKED. Межъязыковое общение допускается, если оно соответствует этим правилам.

Затем он показывает пример, в котором один и тот же сконструированный тип данных используется для отправки сообщения из кода на Фортране и для его получения в фрагменте кода на 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 вместе с MPI_Type_create_f90_real для регистрации соответствующего типа данных MPI.

ИМХО, лучший вариант - полагаться на языковую совместимость между C и Fortran и придерживаться одних и тех же типов данных с обеих сторон. Поскольку ваш набор компиляторов достаточно новый, вы можете использовать механизм ISO_C_BINDING Фортрана для получения типов 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 это параметр времени настройки, отключенный по умолчанию из соображений производительности) и будут выполнять автоматическое преобразование представления (конечность и т. д.) на лету данные пересылаются между узлами с разными архитектурами. Должна быть возможность изящно обрабатывать такой сценарий, используя переносимые типы 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 в программе на Фортране, а не real(8), что является обычным, но не стандартным.

В принципе, вы даже хотели бы беспокоиться о неоднородности, о кодировании чисел с плавающей запятой на машинах, на которых запущены две программы, но для большинства из нас это не проблема.

person Jonathan Dursi    schedule 14.08.2012
comment
Я изменил массив на двойную точность в коде фортрана и на двойную точность в коде С++ и установил тип данных mpi С++ на mpi::double, и массив был успешно передан стороне фортрана. Я думаю, вы правы в том, что 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