beridel
beridel

Reputation: 23

Wrapping a f2py-compiled Fortran .so with Cython (without passing by python)

Looking at some other similar questions (Cython and fortran - how to compile together without f2py), I may be going about this the wrong way, but the workflow I'd like to put in place seems so cythonic/pythonic that I would be surprised if the following isn't possible:

1) Compile a fortran_func.so with f2py from the fortran_func.f source file that contains the foo subroutine I need. Seeing as I have the .f source, I do know the correct function call syntax.

2) Magic step perhaps involving a "cdef extern" or something similar.

3) Directly call the function without having to pass by:

import fortran_func

out = fortran_func.foo(x, y)

The idea is that I have three for loops around this function call and calling the fortran function through a python import is really slow. Currently I have this:

import fortran_func

cdef np.ndarray[double, ndim=3] cy_func(double[::1] x,
                                        double[::1] y,
                                        double[::1] z,
                                        int N):
    cdef:
        int i, j, k
        np.ndarray[double, ndim=3] out

    out = np.zeros((N, N, N), dtype=np.float64)

    for i in range(N): # fast C loops
        for j in range(N):
            for k in range(N):
                # extremely slow python call
                out[i,j,k] = fortran_func.foo(x[i], y[j], z[k])

                # would prefer a fast, direct function call
                # out[i,j,k] = foo(x[i], y[j], z[k])

I would very much appreciate any help in finding out what this magic step should be!

Upvotes: 2

Views: 701

Answers (1)

Matthias123
Matthias123

Reputation: 892

You can call a shared fortran object as a c-function with ctypes without converting to python types. You should be able to do so with cython as well. I wrote it down here:

http://pythology.blogspot.fr/2014/03/wrapping-fortran-and-python-without-f2py.html

This is the summary:

fortran file add.f95:

subroutine add(a,b,c)    
    implicit none
    integer a,b,c
    c = a + b 
end

compile with:

gfortran -shared -fPIC add.f95 -o add.so

the python code to call it (careful, 'add' becomes 'add_') is:

#!/usr/bin/env python

from ctypes import c_int, byref, cdll

a = c_int(3)
b = c_int(4)
c = c_int()

addlib = cdll.LoadLibrary('./add.so')
addlib.add_(byref(a),byref(b),byref(c))
print c

Upvotes: 1

Related Questions