Как передать дескриптор коммуникатора MPI из Fortran в C, используя iso_c_binding

Я пытаюсь связать параллельную программу MPI Fortran с параллельной библиотекой C, которая также использует MPI. Архитектура программного обеспечения ориентирована на Fortran, поэтому я стараюсь максимально использовать Fortran.

Поэтому мне нужно передать подпрограммам C дескриптор коммуникатора MPI. Они имеют форму

  int CFunction(int *something, MPI_Comm *Ccomm)

MPI поставляется с интерфейсами для преобразования Fortran в дескриптор коммуникатора C:

MPI_Comm MPI_Comm_f2c(MPI_Fint comm)

Однако эти подпрограммы должны вызываться из C, поэтому прямо сейчас мне пришлось добавить функции-оболочки C, которым я могу передать коммуникатор Fortran:

int CFunction_FMPI(int *something, MPI_Fint *Fcomm)
{   MPI_Comm Ccomm; int status;
    Ccomm = MPI_Comm_f2c(*Fcomm); // Convert Fortran->C communicator
    status = CFunction(*something,*Ccomm); // Call original function
    return status;
}

затем мне пришлось написать второй интерфейс — для CFunction_FMPI — используя привязки Fortran C, чтобы его можно было вызывать из Fortran.

Мой вопрос: нет ли лучшего способа сделать это, то есть избежать оболочки C с преобразованием коммуникатора Fortran-> C? Я думаю, что лучше всего было бы вызвать MPI_Comm_f2c непосредственно из Фортрана и сохранить результат в переменной type(c_ptr) или integer(c_int), но я не смог этого сделать, поскольку между типом MPI_Comm и Фортраном нет прямой/общей привязки.


person Federico Perini    schedule 01.03.2017    source источник


Ответы (1)


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

https://github.com/LadaF/PoisFFT/blob/master/src/f_mpi_comm_c2f.c

Это противоположное направление вашему CFunction_FMPI и просто переводит коммуникатор. Это с Си на Фортран.

// This function is callable from Fortran. MPI_Comm_c2f itself may be just a macro.

MPI_Fint f_MPI_Comm_c2f(MPI_Comm *comm) {
  return MPI_Comm_c2f(*comm);
}

Затем он вызывается из Фортрана как

interface
    integer function MPI_Comm_c2f(c_handle) bind(C, name="f_MPI_Comm_c2f")
      use iso_c_binding
      type(c_ptr), value :: c_handle
    end function
end interface

Важным моментом является то, что MPI_Comm_c2f в некоторых библиотеках MPI является макросом C, а не функцией, поэтому вы не можете вызвать его из Fortran. Я совершенно уверен, что MPI_Comm_f2c также может быть макросом, и поэтому вы не можете вызывать его из Фортрана.


Что вы можете сделать, так это создать функцию Fortran, которая просто вызывает оболочку C для MPI_Comm_f2c, а затем вызывает вашу функцию C в Fortran, используя интерфейс bind(C) как

status = CFunction(something, c_comm)

и, таким образом, избежать создания оболочки для каждой функции C. Вам просто нужен блок интерфейса Fortran для них.

Проблема в том, что у вас нет MPI_Comm в Fortran* in (на практике это указатель или целое число), поэтому вы должны использовать непрозрачный указатель.

MPI_Comm* f_MPI_Comm_f2c(MPI_Fint Fcomm)
{   MPI_Comm* Ccomm;
    Ccomm = malloc(sizeof(MPI_Comm));
    *Ccomm = MPI_Comm_f2c(Fcomm);
    return Ccomm;
}

который возвращает непрозрачный указатель type(c_ptr). (Проверьте возможные ошибки кодирования C, я просто даже забыл использовать точку с запятой.)

Вы только один раз конвертируете коммуникатор Fortran в указатель на коммуникатор C.

 type(c_ptr) :: c_comm
 c_comm = f_MPI_Comm_f2c(comm)

* В MPI-3 есть производный тип type(MPI_Comm), но он содержит целочисленный компонент, который в любом случае должен быть преобразован процедурами преобразования.

person Vladimir F    schedule 01.03.2017
comment
Спасибо @vladimir-f, ваш подход работает очень хорошо. На самом деле, вызов функции f_MPI_Comm_f2c только один раз в коде позволяет избежать утомительного выделения/освобождения указателя C. Было бы здорово, если бы Fortran предоставил объектно-ориентированную инкапсуляцию MPI, такую ​​как C++... - person Federico Perini; 02.03.2017
comment
На самом деле привязки C++ MPI устарели. Современные привязки Fortran 2008 — довольно хороший шаг вперед. - person Vladimir F; 02.03.2017
comment
Да, но использование файлов .mod из реализации MPI всегда будет зависеть от компилятора, не так ли? Поскольку формат .mod не был стандартизирован, соответствующий заголовок C был бы - person Federico Perini; 02.03.2017
comment
Это что-то другое. C++ ABI также не является независимым от компилятора. Если вы подразумеваете, что все еще используете mpif.h, это действительно не очень хорошая идея. Если MPI скомпилирован для другого компилятора, вы все равно можете получить неприятные сюрпризы, даже если вам удастся скомпилировать. - person Vladimir F; 02.03.2017