Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用带有多维数组的cffi从python调用fortran dll_Dll_Fortran_Python Cffi - Fatal编程技术网

使用带有多维数组的cffi从python调用fortran dll

使用带有多维数组的cffi从python调用fortran dll,dll,fortran,python-cffi,Dll,Fortran,Python Cffi,我使用一个dll,其中包含微分方程解算器和其他有用的数学工具。不幸的是,这个dll是用Fortran编写的。我的程序是用python 3.7编写的,我使用spyder作为IDE 我成功地从dll调用了easy函数。然而,我似乎无法让需要多维数组的函数正常工作 这是我尝试调用的函数的联机文档: 如果我执行以下代码,内核将在没有错误消息的情况下死亡: import numpy as np import cffi as cf ffi=cf.FFI() lib=ffi.dlopen("C:\Wind

我使用一个dll,其中包含微分方程解算器和其他有用的数学工具。不幸的是,这个dll是用Fortran编写的。我的程序是用python 3.7编写的,我使用spyder作为IDE

我成功地从dll调用了easy函数。然而,我似乎无法让需要多维数组的函数正常工作

这是我尝试调用的函数的联机文档:

如果我执行以下代码,内核将在没有错误消息的情况下死亡:

import numpy as np
import cffi as cf

ffi=cf.FFI()
lib=ffi.dlopen("C:\Windows\SysWOW64\DLL20DDS")
ffi.cdef("""void F01ADF (const int *n, double** a, const int *lda, int *ifail);""")

#Integer
nx = 4
n = ffi.new('const int*', nx)
lda = nx + 1
lda = ffi.new('const int*', lda)
ifail = 0
ifail = ffi.new('int*', ifail)

#matrix to be inversed

ax1 = np.array([5,7,6,5],dtype = float, order = 'F')
ax2 = np.array([7,10,8,7],dtype = float, order = 'F')
ax3 = np.array([6,8,10,9],dtype = float, order = 'F')
ax4 = np.array([5,7,9,10], dtype = float, order = 'F')
ax5 = np.array([0,0,0,0], dtype = float, order = 'F')

ax = (ax1,ax2,ax3,ax4,ax5)

#Array
zx = np.zeros(nx, dtype = float, order = 'F')

a = ffi.cast("double** ", zx.__array_interface__['data'][0])
for i in range(lda[0]):
    a[i] = ffi.cast("double* ", ax[i].__array_interface__['data'][0])

lib.F01ADF(n, a, lda, ifail)
由于一维数组的函数可以工作,我假设多维数组是问题所在

非常感谢您的任何帮助,
Thilo

无法访问您提到的dll会使给出明确答案变得复杂,但是,dll的文档和提供的Python脚本可能足以诊断问题。您的示例中至少有两个问题:

  • C头界面:

    您的文档链接清楚地说明了函数的C头接口应该是什么样子。我对C、Python的cffi或cdef不是很精通,但是函数接口中
    a
    的参数声明似乎是错误的。函数界面中的
    double**a
    (指向double的指针)很可能是
    double a[]
    double*a
    (指向double的指针),如文档中所述

  • 使用Fortran排序定义2d Numpy数组:

  • 请注意,您的Numpy数组
    ax1..5
    是一维数组,因为数组只有一维
    order='F'
    order='C'
    在内存布局和访问方面是等效的。因此,在这里指定
    order='F'
    可能没有预期的效果(Fortran对多维数组使用列主顺序)
  • 变量
    ax
    是Numpy数组的元组,而不是2d Numpy数组,因此在内存中的表示形式与2d数组非常不同(在将数据传递到Fortran dll时,这一点非常重要)
走向解决方案 我的第一步是更正C头接口。接下来,我将使用Fortran排序将
ax
声明为具有二维的适当Numpy数组,然后将其转换为适当的数据类型,如本例所示:

#file: test.py
import numpy as np
import cffi as cf

ffi=cf.FFI()
lib=ffi.dlopen("./f01adf.dll")
ffi.cdef("""void f01adf_ (const int *n, double a[], const int *lda, int *ifail);""")

# integers
nx = 4
n = ffi.new('const int*', nx)
lda = nx + 1
lda = ffi.new('const int*', lda)
ifail = 0
ifail = ffi.new('int*', ifail)

# matrix to be inversed
ax = np.array([[5,  7,  6,  5],
               [7, 10,  8,  7],
               [6,  8, 10,  9],
               [5,  7,  9, 10],
               [0,  0,  0,  0]], dtype=float, order='F')

#  operation on matrix using dll
print("BEFORE:")
print(ax.astype(int))

a = ffi.cast("double* ", ax.__array_interface__['data'][0])
lib.f01adf_(n, a, lda, ifail)

print("\nAFTER:")
print(ax.astype(int))

为了测试的目的,考虑下面的FORTRAN子例程作为您的DLL的替代。它只需将10**(i-1)添加到输入数组

a
的第i列。这将允许检查Python和Fortran之间的接口是否按预期工作,以及数组
a
的预期元素是否在以下位置操作:

!file: f01adf.f90
Subroutine f01adf(n, a, lda, ifail)
  Integer, Intent (In) :: n, lda
  Integer, Intent (Inout) :: ifail
  Real(Kind(1.d0)), Intent (Inout) :: a(lda,*)

  Integer :: i

  print *, "Fortran DLL says: Hello world!"

  If ((n < 1) .or. (lda < n+1)) Then
    ! Input variables not conforming to requirements
    ifail = 2

  Else
    ! Input variables acceptable
    ifail = 0

    ! add 10**(i-1) to the i'th column of 2d array 'a'
    Do i = 1, n
      a(:, i) = a(:, i) + 10**(i-1)
    End Do

  End If

End Subroutine
> gfortran -O3 -shared -fPIC -fcheck=all -Wall -Wextra -std=f2008 -o f01adf.dll f01adf.f90
> python test.py
  BEFORE:
  [[ 5  7  6  5]
  [ 7 10  8  7]
  [ 6  8 10  9]
  [ 5  7  9 10]
  [ 0  0  0  0]]

  Fortran DLL says: Hello world!

  AFTER:
  [[   6   17  106 1005]
  [   8   20  108 1007]
  [   7   18  110 1009]
  [   6   17  109 1010]
  [   1   10  100 1000]]