gpt4 book ai didi

python - 使用 Ctypes 从 Python 调用 Fortran 时返回数组

转载 作者:太空狗 更新时间:2023-10-30 02:28:43 25 4
gpt4 key购买 nike

如何使用 ctypes 将数组从 Fortran 返回到 Python?

例如,我将一个数组(长度为 5)从 Python 传递给 Fortran。使用相同的值创建输出数组。然后,它被传递回 Python。在 Fortran 中,这些值是正确的,但在被发送回 Python 后,它们就不正确了。我的设置不允许阵列正确通过怎么办?

我的 Fortran 代码(例如 test.f)包含以下内容:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C)

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray

print *, "outArray from within Fortran"
do i = 1, lenInOut
outArray(i) = inArray(i)
print *, outArray(i)
end do
return
end subroutine mySub

这被编译为.so:

ifort -g -O0 -fpic -traceback -c -o "test.o" "../test.f"
ifort -shared -o "mylib.so" ./test.o

Python代码如下:

from ctypes import *

mylib = CDLL('mylib.so')

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = IntType(5)
inputoutput = ArrayType(0,0,0,0,0)

mylib.mySub.argtypes = [ArrayType,IntType,ArrayType]
mylib.mySub.restype = ArrayType

output = mylib.mySub(input1,input2,inputoutput)

print '------------------------------------------------------'
print 'output within Python'
print output
a = [0,1,2,3,4]
for ii in a: print output[ii]

输出如下:

#outArray from within Fortran
#1.10000000000000
#2.20000000000000
#3.30000000000000
#4.40000000000000
#5.50000000000000
#------------------------------------------------------
#output within Python
#<__main__.c_double_Array_5 object at 0x10aa830>
#2.96439387505e-323
#6.91177308417e-310
#1.48219693752e-323
#6.91177308238e-310
#6.91177319086e-310

最佳答案

一些事情:

  • Fortran 使用引用调用,即默认传递指针。但是,通过指定 VALUE,您可以改为按值调用。你这样做只是为了 lenInOut,所以正确的 argtypes
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
  • 这里有一个子例程,而不是一个函数。所以你没有得到输出。相反,您的代码填充数组 outArray。 Python 代码中的数组 output 永远不会被触及,并将打印未定义的值。正如@eryksun 指出的那样,您可能希望明确声明以避免从堆栈/返回值寄存器返回垃圾:
mylib.mySub.restype = None
  • 此外,尽管您指定了bind(c),但并未准确指定函数的名称。如果在 bind 属性中未指定 name,则必须使用小写,请参见。 Fortran 2008 条款 15.5.2 p2(感谢@francescalus)。为避免此问题,请提供 bind(c, name='mySub')

  • 虽然您指定了 IMPLICIT NONE,但未声明 i

进一步改进:

  • 您不需要在子例程结束时使用return

  • 由于 ctypes 转换器可以处理 Python int 值,您可以直接使用 input2 = 5(感谢@eryksun 的提示)

  • 所有 ctypes 缓冲区最初都为零,因此您可以将 inputoutput 的初始化简化为 inputoutput = ArrayType()(感谢@eryksun 的提示)


完整的代码如下:

测试.f90:

SUBROUTINE mySub(inArray, lenInOut, outArray) BIND(C, NAME='mySub')

USE ISO_C_BINDING
IMPLICIT NONE

INTEGER(C_INT), INTENT(IN), VALUE :: lenInOut
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(IN) :: inArray
REAL(C_DOUBLE), DIMENSION(lenInOut), INTENT(OUT) :: outArray
integer :: i

print *, "outArray from within Fortran"
do i = 1, lenInOut
outArray(i) = inArray(i)
print *, outArray(i)
end do

end subroutine mySub

测试.py:

from ctypes import *

mylib = CDLL('./mylib.so')
mylib.mySub.argtypes = [ POINTER(c_double), c_int, POINTER(c_double) ]
mylib.mySub.restype = None

ArrayType = c_double*5
IntType = c_int
input1 = ArrayType(1.1,2.2,3.3,4.4,5.5)
input2 = 5
inputoutput = ArrayType()

mylib.mySub( input1, input2, inputoutput )

print '------------------------------------------------------'
print 'output within Python'
a = [0,1,2,3,4]
for ii in a: print inputoutput[ii]

关于python - 使用 Ctypes 从 Python 调用 Fortran 时返回数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35561782/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com