Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call functions from a shared fortran library in python

I would like to call some functions from a Fortran shared library in Python. I have found some links on the net and read them, and according what I found, I should do

libadd = cdll.LoadLibrary('./libbin.so') 

to load the shared object. However, this shared object includes some symbols from another shared library. I read the help of cdll however it does not seem possible to load several shared object files at the same time. How may I call functions from this Fortran library, which is most probably compiled by the Intel Fortran compiler?

like image 810
Umut Tabak Avatar asked Apr 27 '11 23:04

Umut Tabak


People also ask

Which of the given Python package supports tools for integrating C C ++/ Fortran code?

A tool called Instant can be used to put C or C++ code inline in Python code and get automatically compiled as an extension library, much in the same way as F2PY does. Instant has good support for NumPy arrays and is very easy to use.

Is NumPy based on Fortran?

Various NumPy modules use FORTRAN 77 libraries, so you'll also need a FORTRAN 77 compiler installed. Note that NumPy is developed mainly using GNU compilers.

Is Fortran in Python?

The answer is most likely yes! Most of the functions and routines found in NumPy and SciPy are actually compiled Fortran (or C/C++) routines which provide highly efficient and fast solvers for multiple problems.


2 Answers

You'll need to know the signatures of the functions in the shared object. Do you have the source code, or some reference which explains the function names and argument types?

For example, I have this source code (mult.f90):

integer function multiply(a, b)
    integer, intent(in) :: a, b
    multiply = a * b
end function multiply

.. and to demonstrate how you can load and use multiple shared objects at once, I also have (add.f90):

integer function addtwo(a, b)
    integer, intent(in) :: a, b
    addtwo = a + b
end function addtwo

Compile, examine symbols:

% gfortran-4.4 -shared -fPIC -g -o mult.so mult.f90
% gfortran-4.4 -shared -fPIC -g -o add.so add.f90
% nm -ao mult.so | grep multiply
mult.so:00000000000005cc T multiply_

Notice the symbol name in the shared object has an underscore appended. Since I have the source, I know that the signature is multiply_(int *a, int *b), so it is easy to invoke that function from 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))

Output:

8
6
like image 114
samplebias Avatar answered Oct 03 '22 22:10

samplebias


I would add to @sameplebias answer, that one can use the iso_c_binding module to force (any) fortran compiler to produce the correct C signature. Example of usage:

module fmesh_wrapper

use iso_c_binding, only: c_double, c_int
use fmesh, only: mesh_exp

implicit none

contains

subroutine c_mesh_exp(r_min, r_max, a, N, mesh) bind(c)
real(c_double), intent(in) :: r_min
real(c_double), intent(in) :: r_max
real(c_double), intent(in) :: a
integer(c_int), intent(in) :: N
real(c_double), intent(out) :: mesh(N)
call mesh_exp(r_min, r_max, a, N, mesh)
end subroutine

! wrap more functions here
! ...

end module

this will have the following C signature:

void c_mesh_exp(double *r_min, double *r_max, double *a, int *N,
        double *mesh);

and then you can call it from Python as usual. The advantage of this approach is that it works on all platforms (without using any special compiler options).

like image 43
Ondřej Čertík Avatar answered Oct 03 '22 23:10

Ondřej Čertík