I am trying to link a parallel MPI Fortran program to a parallel C library which uses MPI too. The software architecture is Fortran-centered so I'm trying to keep as much as I can on the Fortran side.
So I need to pass the C routines a handle to the MPI communicator. They are of the form
int CFunction(int *something, MPI_Comm *Ccomm)
MPI comes with interfaces to translate a Fortran to a C communicator handle:
MPI_Comm MPI_Comm_f2c(MPI_Fint comm)
However, these routines are supposed to be called from C so right now I've had to add C wrapper functions I can pass the Fortran communicator to:
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;
}
then I had to write a 2nd interface -- to CFunction_FMPI
-- using Fortran's C bindings to allow it to be called from Fortran.
My question is: isn't there any better way to do this, i.e., to avoid the C wrapper with Fortran->C communicator conversion? I think calling MPI_Comm_f2c
directly from Fortran and storing the result in a type(c_ptr)
or integer(c_int)
variable would be best, but I haven't been able to do it since there is no straightforward/general binding between the MPI_Comm
type and Fortran.
No, I don't think there is a much better way to do it. And it is not that much complicated that I would be concerned about it. You can look at a similar function I use at
https://github.com/LadaF/PoisFFT/blob/master/src/f_mpi_comm_c2f.c
It is the opposite direction to your CFunction_FMPI
and just translates the communicator. It is from C to Fortran.
// 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);
}
It is than called from Fortran as
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
The important point is that MPI_Comm_c2f
is in some MPI libraries a C macro, not a function, so you cannot really call it from Fortran. I am quite sure MPI_Comm_f2c
is also allowed to be a macro and you cannot therefore call it from Fortran.
What you can do is to create a Fortran function, which just calls the C wrapper for MPI_Comm_f2c
and than call your C function in Fortran using a bind(C)
interface as
status = CFunction(something, c_comm)
and thus avoid creating a wrapper for each C function. You just need a Fortran interface block for them.
The problem is that you don't have MPI_Comm
in Fortran* in (in practice it is a pointer or an int) so you must use an opaque pointer.
MPI_Comm* f_MPI_Comm_f2c(MPI_Fint Fcomm)
{ MPI_Comm* Ccomm;
Ccomm = malloc(sizeof(MPI_Comm));
*Ccomm = MPI_Comm_f2c(Fcomm);
return Ccomm;
}
which returns an opaque pointer type(c_ptr)
. (Check for potential C coding errors I just even forgot to use semicolons.)
You than just once convert the Fortran communicator to the pointer to the C communicator.
type(c_ptr) :: c_comm
c_comm = f_MPI_Comm_f2c(comm)
* There is a derived type type(MPI_Comm)
in MPI-3, but it contains an integer component which must be converted by the conversion routines anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With