用Cython封装f2py编译的Fortran .so(不经过Python)

2 投票
1 回答
688 浏览
提问于 2025-04-17 20:35

看了一些类似的问题(比如Cython和Fortran - 如何不通过f2py一起编译),我觉得我可能走错了方向,但我想实现的工作流程看起来非常符合Cython/Python的风格,所以我会很惊讶如果下面的事情不可能:

1) 从包含我需要的foo子程序的fortran_func.f源文件中,用f2py编译出fortran_func.so文件。因为我有这个.f源文件,所以我知道正确的函数调用语法。

2) 可能有一个神奇的步骤,涉及到“cdef extern”或者类似的东西。

3) 直接调用这个函数而不需要经过:

import fortran_func

out = fortran_func.foo(x, y)

我的想法是,我在这个函数调用周围有三个for循环,而通过Python导入调用Fortran函数真的很慢。目前我有这个:

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])

我非常希望能得到任何帮助,找出这个神奇的步骤应该是什么!

1 个回答

1

你可以用ctypes这个工具直接调用一个共享的Fortran对象,就像调用C语言的函数一样,而不需要把数据转换成Python的类型。你也可以用cython来做到这一点。我在这里写下了相关内容:

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

下面是总结:

Fortran文件 add.f95:

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

编译命令是:

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

用来调用它的Python代码(注意,'add' 变成了 'add_')是:

#!/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

撰写回答