直到最近,我一直在使用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包装器的需求。
答案 0 :(得分:0)
您当前使用的C包装器不适合暴露给Python。您可能希望在Python中使用函数签名来镜像Fortran签名,而不是现有C包装器的尴尬签名。
无论是保留C包装还是使Fortran函数C与ISO_C_BINDINGS可互操作,最终与Cython的接口无关紧要。您只需要知道要公开的库中C函数的签名。
无论哪种方式,这都是遵循Interfacing with External C Code的Cython教程的简单案例,让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为您构建扩展模块,如the Cython documentation中所述。