Binding C++ and Fortran - c++

I want to combine C++ and Fortran together. My Fortran code will use a C++ function and C++ function changes variables of Fortran and sends them back. The C++ function is built with other C++ codes, e.g. the C++ function will use some sub-function in other .cpp file. I make the Fortran code with ifort and I added that C++ function as one object file, test.o in my Fortran makefile. I also put every needed C++ .o file(support test.o) in makefile. It shows the error
#6633, "The type of the actual argument differs from the type of the dummy argument".
Here is the code.
Fortran code
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE
implicit double precision(a-h,o-z),integer(i-n)
Interface
integer (C_INT) function SolveBIE_(x, y, aa, m) BIND(C, NAME='SolveBIE_')
use, intrinsic :: ISO_C_BINDING
implicit none
type (C_PTR), value :: x
type (C_PTR), value :: y
type (C_PTR), value :: aa
integer (C_INT), value :: m
end function SolveBIE_
end Interface
integer (C_INT) :: m
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: x
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: y
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: aa
ALLOCATE(x(0:MAXLEN,MAXINTERFACES))
ALLOCATE(y(0:MAXLEN,MAXINTERFACES))
ALLOCATE(aa(0:MAXLEN,MAXINTERFACES))
My Fortran code run
mm = SolveBIE_(x(1,1),y(1,1),aa(1,1),m)
Using the C++ code and where the error is from, on x, y, aa
I use x(1,1) instead of x, because if using x, then there is another error
#6634,"the shape matching rules of actual arguments and dummy arguments have been violated"`
I don't understand why it should be x(1,1). Why is this working, not x?
My C++ code
#ifdef __cplusplus
extern "C" {
#endif
int solveBIE_(double *ini_bdry_x, double *ini_bdry_y, double *ini_bdry_um, int *fM)
{
double(*bdry_node)[2] = new double[M1][2];
for (int k = 0; k < M; k++) {
bdry_node[k+1][0] = ini_bdry_x[k+1];
bdry_node[k+1][1] = ini_bdry_y[k+1];
bdry_theta[k+1] = Atan(ini_bdry_x[k+1], ini_bdry_y[k+1]);}
... some functions in other .cpp file

The way your interface is written, you have to construct a C_PTR to array x and pass that as the first argument:
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE, C_PTR, C_LOC
! ...
type(C_PTR) PTRx
! ...
PTRx = C_LOC(x(LBOUND(x,1),LBOUND(x,2)))
! ...
mm = solveBIE_(PTRx, PTRy, PTRaa, m)
As shown above, you would have to fix the next two arguments as well. But you need to rewrite the interface for argument fM because as matters stand, Fortran will pass an integer by value whereas C++ is expecting a pointer. Given that, I would rewrite the interface completely, using the names given for the arguments in the C++ function and passing everything by reference. Names for dummy arguments are potentially visible in Fortran, so it's useful for them to be meaningful. In the following I assume that fM points to a scalar in the callee:
Interface
function SolveBIE_(ini_bdry_x, ini_bdry_y, ini_bdry_um, fM) &
BIND(C, NAME='SolveBIE_')
import
implicit none
integer(C_INT) SolveBIE_
real(C_DOUBLE) :: ini_bdry_x(*)
real(C_DOUBLE) :: ini_bdry_y(*)
real(C_DOUBLE) :: ini_bdry_um(*)
integer (C_INT) :: fM
end function SolveBIE_
end Interface
Then later on you can invoke it more or less normally as
mm = SolveBIE_(x,y,aa,m)
Note that x(1,1) was wrong because LBOUND(x,1) = 0, not 1!

Related

How do I convert an array of structs into an array of derived type with ISO C BINDINGS?

I have the following test C library:
#include <stdlib.h>
struct mystruct {
int a;
double b;
};
struct mystruct *return_array_of_structs(int *size);
struct mystruct *return_array_of_structs(int *size) {
int i;
struct mystruct *ptr;
ptr = malloc(sizeof(struct mystruct)*10);
for(i=0; i<10; i++) {
ptr[i].a = i+1;
ptr[i].b = (i+1)*1.0L;
}
*size=10;
return ptr;
}
And the following module intended to be compiled with f2py:
module test_c_lib
use iso_c_binding
implicit none
type :: t_mystruct
integer :: a
real(8) :: b
end type
contains
subroutine test()
use iso_c_binding
type(c_ptr) :: ret_c_ptr
integer :: length
! Interface to C function
interface
type(c_ptr) function c_return_array_of_structs(a) bind(C, name="return_array_of_structs")
import
integer(c_int) :: a
end function
end interface
! Call C function
ret_c_ptr = c_return_array_of_structs(length)
end subroutine
end module
The following makefile compiles this:
f_mod.so: f_mod.f90 c_lib.o
f2py -c f_mod.f90 c_lib.o -m f_mod
c_lib.o: c_lib.c
gcc -c -fpic c_lib.c -o c_lib.o
I can load the library in Python normally and execute the test() subroutine without problems.
import f_mod
f_mod.test_c_lib.test()
But I do not how to convert ret_c_ptr into an array of derived type t_mystruct that I can normally operate as an array in Fortran. Any hint?
Note: the question is related to iso c bindings and Fortran, not to f2py or its integration with Python.
If you have a C pointer and want to associate a Fortran pointer with the target of that C pointer, you want to use c_f_pointer to do that association. c_f_pointer doesn't (generally) care whether the type is an intrinsic one or not, or scalar or not.
Let's define the Fortran derived type as an interoperable1 one:
type, bind(c) :: t_mystruct
integer(c_int) :: a
real(c_double) :: b
end type
and then have a Fortran pointer array of that type:
type(t_mystruct), pointer :: ptr_f(:)
With ptr_c pointing to a suitable lump of memory we can do the association:
call c_f_pointer(ptr_c, ptr_f, [length])
to make ptr_f an array of shape [length] pointing to the C target.
1 Being interoperable isn't necessary, but it's certainly helpful to be if it can be.
The right answer to this question is the one provided by francescalus above, however I include the complete excerpt of code with the functions exposed by f2py to Python.
f2py will not allow to return numpy arrays of derived types (which would be a numpy vector of a custom dtype), so you need to return individual vectors per field. Also f2py can not return allocatable arrays without explicit size, therefore this function needs to be split into two calls, one to get the length and another one to get the actual array.
While these are clear limitations of f2py this allows to call directly Fortran functions (or C encapsulated functions as in this example) and get numpy arrays as return values.
The code is not optimised as it implies invoking the C function twice, maybe there is the possibility to use sort kind of static variable like in C, so the second invoke would already had computed the values, although I do not know:
if that is possible at all in Fortran
if that is possible within the context of a shared object (which is what f2py creates from the module)
As there is not that many examples around f2py this might be useful for someone:
module test_c_lib
use iso_c_binding
implicit none
type, bind(c) :: t_mystruct
integer(c_int) :: a
real(c_double) :: b
end type
contains
subroutine get_array_len(l)
use iso_c_binding
integer, intent(out) :: l
type(c_ptr) :: ret_c_ptr
integer :: length
! Interface to C function
interface
type(c_ptr) function c_return_array_of_structs(a) bind(C, name="return_array_of_structs")
import
integer(c_int) :: a
end function
end interface
! Call C function
ret_c_ptr = c_return_array_of_structs(length)
l = length
end subroutine
subroutine get_array(l, a, b)
use iso_c_binding
integer, intent(in) :: l
integer, intent(out) :: a(l)
real(8), intent(out) :: b(l)
type(c_ptr) :: ret_c_ptr
type(t_mystruct), pointer :: f_ptr(:)
integer :: length
! Interface to C function
interface
type(c_ptr) function c_return_array_of_structs(a) bind(C, name="return_array_of_structs")
import
integer(c_int) :: a
end function
end interface
! Call C function
ret_c_ptr = c_return_array_of_structs(length)
call c_f_pointer(ret_c_ptr, f_ptr, [length])
a = f_ptr%a
b = f_ptr%b
end subroutine
end module

How to receive an array using iso_c_binding in Fortran [duplicate]

This question already has answers here:
Fortran interface to call a C function that return a pointer
(3 answers)
Fortran interface to call a C function that returns a pointer to an array
(2 answers)
Closed 1 year ago.
I am working to encapsulate a C library using f2py (to later use them in python/numpy). After getting help here to get the first encapsulation working I am now trying to encapsulate more complex types, specifically C functions returning arrays allocated via malloc.
This is the C library mockup (c_lib.c):
#include <stdlib.h>
double multiply_numbers(double a, double b);
double *get_array(double a);
double multiply_numbers(double a, double b) {
return a*b;
}
double *get_array(double a) {
double *retval;
int i;
retval = malloc(100*sizeof(a));
for(i=0; i<100; i++) {
retval[i] = i*a;
}
return retval;
}
I can succesfully encapsulate the basic multiply_numbers function (f_mod.f90):
module test_c_lib
use iso_c_binding
implicit none
contains
subroutine multiply(x, y, z)
use iso_c_binding
real(8), intent(in) :: x
real(8), intent(in) :: y
real(8), intent(out) :: z
! Interface to C function
interface
real(c_double) function c_multiply_numbers(a, b) bind(C, name="multiply_numbers")
import
real(c_double), value :: a,b
end function
end interface
! Call C function
z = c_multiply_numbers(x,y)
end subroutine
end module
I compile everything using this makefile:
f_mod.so: f_mod.f90 c_lib.o
f2py -c f_mod.f90 c_lib.o -m f_mod
c_lib.o: c_lib.c
gcc -c -fpic c_lib.c -o c_lib.o
But I am struggling to understand how would I code the subroutine that wraps the C function get_array.
Specifically,
how do I receive a 100 items array?
which would be the interface definition?
Note: I have not tried anything because I do not where to start.
EDIT
With francescalous comments I have been able to encapsulate the function and make it work. It is worth to note that f2py might require the extra step of assigning the Fortran pointer to a Fortran array. I am not sure on this point but I can not get f2py compiled when trying to output the Fortran pointer directly.
This is the final wrapper subroutine in Fortran for f2py:
subroutine get_array(x, z)
use iso_c_binding
real(8), intent(in) :: x
real(8), intent(out) :: z(100)
! Auxiliary variables to convert C pointer to Fortran Array
type(c_ptr) :: ret_c_ptr
real(8), pointer :: f_ptr(:)
! Interface to C function
interface
type(c_ptr) function c_get_array(a) bind(C, name="get_array")
import
real(c_double), value :: a
end function
end interface
! Call C function
ret_c_ptr = c_get_array(x)
call c_f_pointer(ret_c_ptr, f_ptr, [100])
! Assign Fortran pointer to Fortran output array
z = f_ptr
end subroutine

Fortran Wrapper calling C functions

I have a C function that uses structures. I developed a Fortran Wrapper which calls the C function. Both libraries are built successfully. I have passed the variables form the PSCAD model and run the case. The PSCAD model is throwing the error.
Error Message:
Type Id Component Namespace Description
dll_df FORTRA~1.LIB(dlltestx.obj) : error LNK2019: unresolved external symbol _test_cfun referenced in function _AUX_CFUN
C-Code:
// This is an example of an exported variable
typedef struct _goose_c
{
int in1;
float in2;
}goose_c;
__declspec(dllexport) void test_cfunc(goose_c *V, double *out1)
{
//*out1 = (*V).in1 + (*V).in2;
*out1 = V->in1 + V->in2;
}
Fortran Wrapper Code:
SUBROUTINE AUX_CFUN(ip1, ip2, out1)
use, intrinsic :: iso_c_binding
implicit none
integer, intent(in) :: ip1
real, intent(in) :: ip2
real, intent(out) :: out1
type, bind(C) :: goose_t
integer(c_int) :: in1
real(c_double) :: in2
end type goose_t
type(goose_t) :: goose_f
! Fortran 90 interface to a C procedure
INTERFACE
SUBROUTINE TEST_CFUN (goose_f,out1) bind (C)
use iso_c_binding
import :: goose_t
type(goose_t), intent (in) :: goose_f
real(c_double), intent (out) :: out1
END SUBROUTINE TEST_CFUN
END INTERFACE
goose_f%in1 = ip1
goose_f%in2 = ip2
! call of the C procedure
CALL TEST_CFUN(goose_f,out1)
RETURN
END SUBROUTINE AUX_CFUN
The bind (C) clause in the interface should be completed with the exact (including the correct case) C name of the function you want to interface; so in your example it should read bind (C, name='test_cfunc'). The Fortran name associated to the C function (TEST_CFUN in your example) can be in principle different, it's up to you to decide whether this is a good idea or not, and it is used in your fortran program with the usual fortran rules, so it is case-insensitive.

Is it possible to pass a c++ vector of pointers to fortran?

I need to pass a vector of pointers from c++ to a Fortran dll and I do not know if this is possible.
I tried searching but I could not really find and answer to my question.
The idea is the following:
Fortran side
!DEC$ATTRIBUTES DLLEXPORT :: TO_FORTRAN
integer function TO_FORTRAN (test4) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
REAL, intent(in) :: test4(3)
REAL, pointer :: test5
call C_F_POINTER(C_LOC(test4),test5)
TO_FORTRAN = 0
END
c++ code
std::vector<float> test1(3);
std::vector<float> test2(3);
std::vector<float> test3(3);
std::vector<float*> test4(3);
test4[0] = test1.data();
test4[1] = test2.data();
test4[2] = test3.data();
TO_FORTRAN(test4);
If it is really an array of pointers, you need to treat it like an array of pointers at the Fortran side as well. You also have keep in mind they are pointers to arrays, not just scale real numbers (although they may be represented the same way in C).
!DEC$ATTRIBUTES DLLEXPORT :: TO_FORTRAN
integer function TO_FORTRAN (test4) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
type(c_ptr), intent(in) :: test4(3)
REAL, pointer :: test1(:), test2(:), test3(:)
call C_F_POINTER(test4(1),test1, [3])
call C_F_POINTER(test4(2),test2, [3])
call C_F_POINTER(test4(3),test3, [3])
TO_FORTRAN = 0
END FUNCTION
and
TO_FORTRAN(test4.data());

Pass real part of a complex array to a subroutines in fortran

Is it possible to pass real part of a complex array to a subroutine in Fortran without storing the real part in another array and pass that? e.g. instead of
Z = complex array;
X = real(Z)
call foo(X)
Do the following
Z = complex array
call foo(real(Z))
This gives me a compiler error! I am using an intel compiler ifort.
Sure, it works:
module testmod
implicit none
integer, parameter :: dp = kind(1.0d0)
contains
subroutine realsub(array)
real(dp), intent(in) :: array(:)
print *, array
end subroutine realsub
end module testmod
program testprog
use testmod
implicit none
complex(dp) :: array(3)
array(:) = [ (1.0_dp, 1.0_dp), (3.0_dp, 2.0_dp), (-1.0_dp, 3.0_dp) ]
call realsub(real(array))
end program testprog