Как использовать подпрограммы fortran90 в python с Cython и iso_c_bindings

До недавнего времени я использовал IDL для решения большинства своих вычислительных задач. Одна из моих наиболее часто используемых подпрограмм — это фрагмент кода fortran90, завернутый в C и вызываемый из IDL с помощью функции CALL_EXTERNAL (ничего из этого не написано мной). По разным причинам я переношу большинство вычислений на Python, но не нашел хорошего способа включения кода на Фортране. Кажется, что 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.


person maquisdefraud    schedule 18.01.2013    source источник
comment
Что вы подразумеваете под нестабильным f2py созданным модулем?   -  person kynan    schedule 27.07.2013


Ответы (1)


Оболочка 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. Возможно, вы захотите разрешить вызывающей стороне передавать массивы NumPy для всех аргументов double*:

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.

person kynan    schedule 27.07.2013