使用F2PY

时间:2017-03-14 16:31:59

标签: python numpy fortran f2py

我想了解F2PY的工作原理。为此,我编写了一个简单的Fortran函数,它将数组作为输入并返回数组元素的总和。

我写了三个不同版本的相同函数,我希望它们具有相同的结果:

function rsum(arr)
real, dimension(:), intent(in) :: arr
real :: rsum
rsum=sum(arr)
end function rsum

function rsum1(arr)
real(8), dimension(:), intent(in) :: arr
real(8) :: rsum1
rsum1=sum(arr)
end function rsum1

function rsum2(arr) result(s)
real, dimension(:), intent(in) :: arr
real :: s
s=sum(arr)
end function rsum2

function rsum3(arr) result(s)
real(8), dimension(:), intent(in) :: arr
real(8) :: s
s=sum(arr)
end function rsum3

我测试这些函数的python脚本如下:

from numpy import *
import ftest as f

a=array(range(3))

print(f.rsum(a))
print(f.rsum1(a))
print(f.rsum2(a))
print(f.rsum3(a))

但结果如下:

3.0
0.0
3.0
3.0

除了rsum1 0.0之外,所有结果都是正确的。我发现更奇怪的是rsum3,其中我只更改了函数结果的名称(或者,至少,我认为我这样做了),完美地工作!

我知道这与Fortran和numpy之间的类型转换有关,但我不明白问题所在。

PS:我最近才学会了Fortran。

1 个答案:

答案 0 :(得分:1)

简短答案和解决方法

此问题的根本原因与在函数中使用假定形状的伪参数(即arr)有关。 Fortran要求此类函数具有显式接口。 @VladimirF对此问题({?3}}给出了一个极好的答案,表明问题的首选解决方案是将函数放在模块中。假设带有功能的代码清单保存在名为funcs.f90的文件中,则只需将其放入模块中,例如称为mod_funcs.f90,如下所示:

module mod_funcs
    implicit none
    contains
        include "funcs.f90"
end module mod_funcs

用F2PY python -m numpy.f2py -m ftest -c mod_funcs.f90包装,将python测试脚本中的import语句更新为from ftest import mod_funcs as f,然后运行它以得到预期的结果:

3.0
3.0
3.0
3.0

更长的答案和解释

Fortran function被F2PY包裹在subroutine中。为了以符合Fortran标准的方式支持假定形状的数组,F2PY创建的子例程包装器包含interface,用于具有假定形状伪参数的用户定义函数。您可以通过在使用F2PY进行包装时指定带有--build-dir标志的构建目录来查看这些包装器,例如像这样:

python -m numpy.f2py --build-dir .\build -m ftest -c funcs.f90

看一下为 problematic 函数rsum1创建的包装器(我正在从ftest-f2pywrappers.f逐字复制以保持F2PY的缩进):

subroutine f2pywraprsum1 (rsum1f2pywrap, arr, f2py_arr_d0)
integer f2py_arr_d0
real(8) arr(f2py_arr_d0)
real(8) rsum1f2pywrap
interface
function rsum1(arr) 
    real(8), dimension(:),intent(in) :: arr
end function rsum1
end interface
rsum1f2pywrap = rsum1(arr)
end

请注意,由于hereinterface的{​​{1}}表示一个函数,其数据类型为rsum1不是 real如预期-接口中的数据类型不匹配!这就解释了为什么在原始示例中,具有显式real(8)语句(result)的看似相同的函数返回正确的结果,其结果具有正确的数据类型。通过命名函数,rsum3具有正确的接口。如果您将rsum的名称更改为例如rsum,其F2PY子例程包装器接口中的隐式数据键入规则将暗示它具有isum的结果,并且您将获得以下输出(经过修改,以反映来自{{1}的名称更改) }到integer)的Python脚本:

fsum

在我看来,F2PY如何为具有假定形状的虚拟参数的函数创建接口似乎存在错误(可以通过将这些函数直接放入模块中,或者通过显式声明函数的返回值来绕过该错误)使用isum)。

为了完整起见,我使用0.0 0.0 3.0 3.0 resultPython 3.6.3 :: Intel Corporation