与F2PY numpy的阵列上使用Fortran函数时不一致的结果

问题描述 投票:3回答:1

我想了解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最近。

python numpy fortran f2py
1个回答
1
投票

简短的回答和解决方法

该问题的根本原因是与使用的假定形状伪参数(即arr)在功能。 Fortran语言需要这样的功能有明确的接口。 @VladimirF给了一个很好的答案,关于这一点你(有关?)问题here,表明首选的方案是把功能模块中。假设你的代码函数列表保存在一个名为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语言functions由F2PY包裹在subroutines。为了支持假定形状阵列在Fortran符合标准的方式,创建F2PY子程序包装包含interfaces用于与假定形状伪参数的用户定义的函数。您可以通过使用F2PY包裹时指定一个build目录用--build-dir标志,例如看看这些包装像这样:

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

看着这对有问题的功能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

需要注意的是,由于implicit data typing rules,为interfacersum1意味着函数real数据类型,无法按照预期的real(8) - 所以在接口数据类型不匹配!这就解释了为什么有一个明确的result声明(rsum3)看似相同的功能,在你原来的例子返回正确的结果,其结果具有正确的数据类型。通过在命名你的职责造化,rsum有正确的接口。如果更改rsum的名字例如isum在其F2PY子程序封装接口隐式数据类型规则将意味着它有一个integer结果,你会从你的(修改以反映名称的更改从fsumisum)python脚本输出如下:

0.0
0.0
3.0
3.0

所以对我来说看起来好像有可能在F2PY如何创建一个用于虚拟形状的哑参数的函数接口(可以直接把这些功能集成到一个模块可以绕过一个bug,或者通过使用功能result的明确声明返回值)。

为了完整起见,我用Python 3.6.3 :: Intel Corporation,与NumPy 1.14.3GNU Fortran (GCC) 8.2.0

© www.soinside.com 2019 - 2024. All rights reserved.