Accessing Fortran code with Python
Scientific Computing
Soon after C became the first language to be callable from Python, people wanted the same for the millions of lines of proven Fortran code in scientific applications. In the past, combining C and Fortran was dependent on the compiler. The advent of Fortran 2003 [1] brought a standard, compiler-independent C/Fortran interface.
The approach for combining C and Fortran for Python is to write a C wrapper for the Fortran functions and subroutines that you want to use in Python. Then, you build the Python function around the C wrapper and use it as a Python module. Calling the C function calls the Fortran routine. Although a little indirect, the concept is straightforward.
In the first example, I integrate Cython and Fortran.
Fortran/C and Cython
The Fortran 90 [2] website, which lists best practices, discusses how elements of the Fortran 2003 standard [3] can integrate C and Fortran. The iso_c_binding
module of Fortran 2003-compliant compilers matches Fortran and C types with named constants used as KIND
-type parameters in Fortran.
Without writing any C code, Cython can then be used to interface with the Fortran code. The Cython code is written in Fortran with the use of C calling conventions. The Fortran code interface with C uses the iso_c_binding
module to link Cython directly against the Fortran library. Granted, this method doesn't really combine C and Fortran; rather, it uses the standardized Fortran/C interface. However, it really is integrating Fortran and C with Python.
If you are interested, the Fortran 90 website has an example of interfacing Fortran with Python via Cython that is as simple as creating a C interface in Fortran. Another good example can be found on Pierre Augier's website [4].
Fortran/C and ctypes
In the previous article on high-performance Python [5], I presented ctypes
as a way to integrate "foreign" function libraries (i.e., libraries outside of Python) into Python. You can use ctypes
to integrate Fortran code with Python, as well.
The following examples show the multiplication of two integers and the addition of two integers. Save the Fortran integer multiplication code function in file mult.f90
,
integer function multiply(a, b) integer, intent(in) :: a, b multiply = a * b
and save the Fortran integer addition code in file add.f90
:
integer function addtwo(a, b) integer, intent(in) :: a, b addtwo = a + b end function addtwo
You should compile each function individually into shared objects:
$ gfortran -shared -fPIC -g -o mult.so mult.f90 $ gfortran -shared -fPIC -g -o add.so add.f90
For the sake of development, I compile the code with the debug option (-g
), but that is purely a personal preference.
If you want to explore the shareable objects, you can use the Linux nm
tool:
$ nm -ao mult.so | grep multiply mult.so:00000000000005cc T multiply_
Note that the function name in the shareable object has a trailing underscore.
Now you can use the ctypes
module to check whether the objects work with code saved in a file named testfunc.py
(Listing 1). Notice that the variables a
and b
are typed by cytpes
and the Fortran functions are called with a trailing underscore. Also notice that variables are passed to the function by reference; this is different from C code, which passes by value.
Listing 1
Using ctypes
from ctypes import byref, cdll, c_int mult = cdll.LoadLibrary('./mult.so') add = cdll.LoadLibrary('./add.so') a = c_int(2) b = c_int(4) print mult.multiply_(byref(a), byref(b)) print add.addtwo_(byref(a), byref(b))
The output from the Python code is:
$ python3 testfunc.py 8 6
If you like, you can write a simple Python wrapper function for the shareable objects, so it's easier to understand in the main Python code. A wrapper allows you to avoid the trailing underscore in the main Python code, and the use of byref
functions to make it look more Pythonic. The previous article on high-performance Python has an example of how to write wrapper functions [5].
f2py
Early in the development and growth of Python, the desire to integrate Fortran into Python led people to develop the necessary tools. To make the process more accessible, Pearu Peterson decided to create a tool to make porting easier. The tool, f2py
[6], was first released in 1999 and was known as f2py.py
. Eventually, the tool was incorporated into NumPy (numpy.f2py
) and is still there today.
Probably the most popular tool for interfacing Fortran with Python, f2py
has been used in a large number of projects. It creates an extension module that is imported into Python by the import
Python command. The module has automatically generated wrapper functions that create the interface between Fortran and Python.
The f2py
users guide [7] introduction shows three methods of use. Instead of presenting all three methods, I will focus on the "quick and smart way" [8].
The first step is to create a signature file for the Fortran (or C) code (f2py
also accommodates C code) that describes the wrapper for the Fortran or C functions, which f2py
refers to as the functions' "signatures." Usually f2py
can create a signature file for you just by scanning the source. Once the signatures are created, you compile the code to make it ready for Python.
Buy this article as PDF
(incl. VAT)