我想了解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。答案 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
请注意,由于here,interface
的{{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
,result
和Python 3.6.3 :: Intel Corporation
。