# Calling Fortran from C

[2013-04-17 Wed]

Eventually, I want to be able to call Fortran from Python. However, as a stepping stone, I first call Fortran from C and then use that for the next step. As an example I'll be using a fractal calculating program. The code can be accessed with

```git clone https://maurow@bitbucket.org/maurow/mauro_learning_fortran.git
cd mauro_learning_fortran
git checkout v0.1
```

and is in the folder `mandel/`.

## The Fortran side

The function `calc_num_iter` in Fortran module `mandel` computes whether the points in the grid `(re,im)` are part of the Mandelbrot set.

`mandel.f90`:

```module mandel
implicit none

integer, parameter :: dp=kind(0.d0) ! double precision

contains

pure function mandel_frac(z, c) result(out)
! The Mandelbrot function z -> z^2 + c
complex(dp), intent(in):: z, c
complex(dp):: out
out = z**2 + c
end function mandel_frac

pure function calc_num_iter(re, im, itermax, escape) result(out)
! Iterates on mandel_frac
real(dp), intent(in):: re(:), im(:), escape
integer, intent(in):: itermax
integer:: out(size(re), size(im))
integer:: ii, jj, kk, itt
complex(dp):: zz, cc

do ii=1,size(re)
do jj=1,size(im)
zz = 0
cc = cmplx(re(ii), im(jj), dp)
itt = 0
do kk=1,itermax
zz = mandel_frac(zz, cc)
itt = kk
if (abs(zz)>escape) then
exit
end if
end do
out(ii,jj) = itt
end do
end do

end function calc_num_iter

end module mandel
```

This can, of course, be used in Fortran like so:

`run_mandel_from_fortran.f90`:

```program mandelbrot
use mandel
implicit none

integer, parameter :: nre=31, nim=21
real(dp), parameter :: rer(2)=[-2._dp, 1._dp], imr(2)=[-1._dp,1._dp]
integer :: ii, jj, kk, out(nre,nim), itermax=99
real(dp) :: re(nre), im(nim), escape=2._dp
complex(dp) :: zz

re = [ (dble(ii)/(nre-1)*(rer(2)-rer(1)) + rer(1) , ii=0, nre-1, 1) ]
im = [ (dble(ii)/(nim-1)*(imr(2)-imr(1)) + imr(1) , ii=0, nim-1, 1) ]

out = calc_num_iter(re, im, itermax, escape)

! plot array as x/y coordinates
do jj=nim,1,-1
print '(30000I3.2)', out(:,jj)
end do

end program mandelbrot
```

Compile it with

```gfortran mandel.f90 run_mandel_from_fortran.f90 -o fout
```

## The wrapper

To make the function `calc_num_iter` available in C it needs to be wrapped using the `iso_c_binding` module (in the Fortran 2003 standard). Resources for the dumb Fortran programmer, like myself, are a bit sparse (e.g. gfortran docs). The fortran wrapper is

`mandel_wrap.f90`:

```module mandel_wrap
! to wrap calc_num_iter for use in C

use iso_c_binding, only: c_double, c_int
use mandel, only:  calc_num_iter

implicit none

contains

! need to make a subroutine as only scalars can be returned
subroutine c_calc_num_iter(nre, re, nim, im, itermax, escape, out) bind(c)
real(c_double), intent(in):: re(nre), im(nim)
real(c_double), intent(in), value:: escape
integer(c_int), intent(in), value:: itermax, nre, nim
! note that in C the indices will be reversed!:
integer(c_int), intent(out):: out(nim, nre)
! thus the transpose here:
out = transpose(calc_num_iter(re, im, itermax, escape))
end subroutine c_calc_num_iter

end module mandel_wrap
```

There are a few things to note:

• `bind(c)` needs to be appended to the wrapper function
• the `c_` variable types are needed to make them C interoperable
• The attribute `value` specifies that this variable uses call by value, which is the standard for C (but not Fortran).
• I define `out` with the indices reversed compared to `calc_num_iter` as Frotran uses column-major and C row-major array storage. I then transpose the result of `calc_num_iter` to make it fit into `out`.

## The C side

Now it is possible to call `c_calc_num_iter` from C.

`run_mandel_from_c.c`:

```#include <stdio.h>
#include <math.h>
#define NRE 31
#define NIM 21

int main ( void ) {
int i, j, itermax=99;
// NOTE: index not reversed!
int res[NRE][NIM];
double re[NRE], im[NIM],  escape=2., dx, dy;

// make real and imaginary vectors
dx = 3.0/(NRE-1);
re[0] = -2.;
for (i=1; i<NRE; i++)
re[i] = re[i-1] + dx;
dy = 2.0/(NIM-1);
im[0] = -1.;
for (i=1; i<NIM; i++){
im[i] = im[i-1] + dy;
if (im[i]<1e-6 && im[i]>-1e-6)
im[i] = 0.; // otherwise result is not equal to Fortran's
}
//printvec(NRE, re);
//printvec(NIM, im);

// call to fortran
c_calc_num_iter(NRE, re, NIM, im, itermax, escape, res);

// print result
printarr(NRE, NIM, res, re, im);
return 0;
}
```

This needs to be compiled:

```gcc -c run_mandel_from_c.c mandel.f90 mandel_wrap.f90
```

Produces the object files `*.o`, which need to be linked into an executable with

```gfortran run_mandel_from_c.o mandel.f90 mandel_wrap.f90 -o cout
```

Note the use of `gfortran` here. Running the same command using `gcc` does not work as the linker does not find the Fortran functions. Probably some flags for `gcc` could solve this?

Next I call `c_calc_num_iter` from python through a cython interface.