It is possible to compile a dynamic library from a Fortran source code. The procedure differs slightly from one used to combine C++/C and Python. In fact, the numpy module provides an instrument f2py to create a library from fortran source code. This is one of the most useful resources about this subject.
Below I show an example. First, I write a function in fortran which performs a simple numerical integration using the Euler method.
function value (step) real*8 step real*8 res, value integer intpart integer n, i REAL*8, PARAMETER :: Pi = 3.1415927 remainder = mod (Pi / 2.0, step) n = FLOOR(Pi / 2.0 / step) do i = 0, n, 1 pos = i * step res = res + step * cos(pos) enddo res = res + remainder * cos(Pi / 2.0) value = res return end
This function can be compiled using following instruction:
f2py-2.7 -c --fcompiler=gnu95 -m fun fun.f95
Further I call the library fun.so inside a Python script:
import numpy as np import matplotlib.pyplot as plt import fun grid = np.linspace (0.01, 1.0, 50) res_list = [] for i in range (0, len(grid)): res = fun.value(grid[i]) res_list.append(res) plt.plot(grid, res_list) plt.xlabel('Numerical integration step size') plt.ylabel('Result of integration') plt.savefig('plot.pdf') plt.show()
Since the tool f2py is a part of the numpy package, it is not required to properly transform types as it was the case with ctypes package.
The result of python script run is shown below.
Troubleshooting
Recently using one popular fortran code I have experienced an usual problem. I could have easily compiled the code either using ifort or fortran, but the f2py did not work returning error:
redefinition of ‘f2py_rout_fun_unknown_subroutine’
It was absolutely not clear why subroutine is unknown and where to start searching for the problem. In reality the problem is tiny and could be solved in minutes. The solution is to start from preparing a signature file:
f2py -m sig_file -h sig_file.pyf my_fotran_code.f –overwrite-signature
In this case the signature file sig_file.pyf contains a few function unknown_function() which looks extremely suspicious. Comparing successful definitions of functions with unsuccessful ones I figured out that unsuccessful definitions looked like this:
function fun1(arg1,arg2,arg3) ! tstts
While successful ones did not have any comments at the end of the line. Moving comments to the next line solved the problem completely.
If you use subroutines in fortran instead of functions it is important to declare an intent for f2py:
Cf2py intent(in) in_par
Cf2py intent(inout) out_par
The variable in_par only accept parameters from the python script while out_par also changes the variable declared in Python. More examples can be found here.