Lead Image © Kheng Ho Toh, , 123RF.com

Lead Image © Kheng Ho Toh, , 123RF.com

Accessing Fortran code with Python

Scientific Computing

Article from ADMIN 54/2019
By
Fortran functions called from Python bring complex computations to a scriptable language.

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

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus