2

直到最近,我一直在使用 IDL 来解决我的大部分计算问题。我最常用的例程之一是一些 fortran90 代码,用 C 语言包装并使用 CALL_EXTERNAL 函数从 IDL 调用(这些都不是我写的)。由于各种原因,我将大部分计算转移到 Python,但我还没有找到一个合并 fortran 代码的好方法。F2PY 似乎是最明显的方法,但实际上生成的模块似乎非常不稳定。

基本上我想知道是否有更好的方法来解决这个问题。似乎重新设计现有的 C 包装器和 Cython 以使用 Python 中的代码应该相对简单,尽管我不得不承认我完全不了解 C/Cython 并且对 python 很陌生,所以任何帮助将不胜感激.

作为参考,我在下面包含了现有的 C 包装器:

#include <stdio.h>

void bvls(int argc, void *argv[]) {

extern void bvls_(); 
int *n, *m, *nsetp, *index, *ierr;     
double **a, **b, **bnd, **w, **x;   
double *rnorm;

a =     (double **) argv[0];
m =     (int *)     argv[1];
n =     (int *)     argv[2];
b =     (double **) argv[3];
bnd =   (double **) argv[4];
x =     (double **) argv[5];
rnorm = (double *)  argv[6];
nsetp = (int *)     argv[7];
w =     (double **) argv[8];
index = (int *)     argv[9];
ierr =  (int *)     argv[10];

bvls_(a,m,n,b,bnd,x,rnorm,nsetp,w,index,ierr); 

}

编辑: 在向其他人提到这一点后,他们建议也应该可以使用 fortran ISO_C_BINDINGS 模块直接与 Cython 交互,绕过对中间 C 包装器的需要。

4

1 回答 1

0

您当前使用的 C 包装器不适合暴露给 Python。您可能需要 Python 中的函数签名来反映 Fortran 签名,而不是现有 C 包装器的笨拙签名。

无论您是保留 C 包装器还是使 Fortran 函数 C 可与 ISO_C_BINDINGS 互操作,最终与 Cython 的交互都无关紧要。您只需要知道要公开的库中的 C 函数的签名。

无论哪种方式,这都是遵循 Cython与外部 C 代码接口的教程并让 Cython 知道您要公开的函数的签名的简单案例。假设您想镜像 Fortran 签名,它看起来像这样:

cdef extern from "bvls.h":
    void bvls(double* a, int m, int n, double* b, double* bnd, double* x,
              double rnorm, int nsetp, double* w, int index, int ierr)

然后创建一个从 Python 调用的惯用函数就很简单了。您可能希望允许调用者为所有double*参数传入 NumPy 数组:

cimport numpy as np

def pybvls(a, int m, int n, b, bnd, x, double rnorm,
           int nsetp, w, int index, int ierr):
    cdef double *a_, *b_, *bnd_, *x_, *w_
    # Get the raw data pointers from NumPy arrays
    a_ = <double *>np.PyArray_DATA(a)
    b_ = <double *>np.PyArray_DATA(b)
    bnd_ = <double *>np.PyArray_DATA(bnd)
    x_ = <double *>np.PyArray_DATA(x)
    w_ = <double *>np.PyArray_DATA(w)
    bvls(a_, m, n, b_, bnd_, x_, rnorm, nsetp, w_, index, ierr)

最后,您可能希望编写为setup.py文件以使用 distutils 为您构建扩展模块,如Cython 文档中所述

于 2013-07-27T13:50:15.277 回答