如何正确 运行 来自 numpy 文档的 f2py 示例?
How to correctly run f2py example from numpy docs?
我无法理解关于 f2py 和回调函数的 examples shown in the numpy docs 之一。
我执行了与第一个示例(即 f2py -c -m callback callback.f
)完全相同的步骤来包装 callback.f
:
C FILE: CALLBACK.F
SUBROUTINE FOO(FUN,R)
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
然而,测试示例中的结果,给了我:
python
>>> import callback
>>> def f(i): return i*i
...
>>> print callback.foo(f)
0.0
因此,它returns 0.0
而不是110.0
,其中0.0
是Fortran代码中r
的初始值。
无论我使用哪个回调函数,结果都是一样的(不变R
)。
我正在使用从 conda
.
获得的 python 3.7
和 numpy
的最新版本
你能重现那个问题吗,还是我做错了什么?
问题似乎是由外部函数 预期 和 实际 数据类型不匹配引起的 FUN
:
- 根据implicit data typing rules of Fortran,在
CALLBACK.F
中,EXTERNAL
函数FUN
有一个隐式类型REAL
(因为没有显式类型,或 IMPLICIT NONE
语句)。
- 但是,还要查看 second example in the documentation 的详细信息,其中 F2PY 包装器是使用
f2py -m callback2 -h callback2.pyf callback.f
显式创建的,您会注意到外部函数 r
的结果 fun
被定义为 real*8 :: r
类型(对于未修改的 callback2.pyf
签名文件也是如此,因此这是默认的 F2PY 行为)。
简而言之,问题是 FOO
期望 FUN
到 return 一个 REAL
结果,而从 Python 和 F2PY 包装器的外部函数被定义为 return 一个 REAL*8
结果。因此,一个解决方案是确保 FUN
在 Fortran 和 Python/F2PY 包装器中具有相同的 return 类型。这可以通过多种方式实现,例如通过在 CALLBACK.F
:
中添加数据类型规范 REAL*8 FUN
C FILE: CALLBACK.F
SUBROUTINE FOO(FUN,R)
REAL*8 FUN
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
如示例中那样用 python -m numpy.f2py -c -m callback callback.f
包装这个修改后的 CALLBACK.F
,现在给出了所需的输出:
python
>>> import callback
>>> def f(i): return i*i
...
>>> print(callback.foo(f))
110.0
出于兴趣,您可以使用两个文件 prog.f
和 fun.f
:
在纯 Fortran 中生成您在 Python/F2PY 中看到的相同行为
C FILE: PROG.F, including subroutine FOO previously in CALLBACK.F
PROGRAM MAIN
C REAL*8 FUN
EXTERNAL FUN
REAL*8 R
R = 0
PRINT *, "BEFORE: ", R
CALL FOO(FUN, R)
PRINT *, "AFTER: ", R
END
C This is copied from CALLBACK.F
SUBROUTINE FOO(FUN,R)
C REAL*8 FUN
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
和
C FILE: FUN.F containing the function to be called by FOO
REAL*8 FUNCTION FUN(I)
INTEGER I
FUN = I*I
END
使用 gfortran -fcheck=all -Wall -g func.f prog.f
编译,它给出以下输出(实际上与有问题的 Python 示例相同):
./a.out
BEFORE: 0.0000000000000000
AFTER: 0.0000000000000000
在 prog.f
中取消注释 REAL*8 FUN
的两个实例并重新编译解决了问题:
./a.out
BEFORE: 0.0000000000000000
AFTER: 110.00000000000000
我无法理解关于 f2py 和回调函数的 examples shown in the numpy docs 之一。
我执行了与第一个示例(即 f2py -c -m callback callback.f
)完全相同的步骤来包装 callback.f
:
C FILE: CALLBACK.F
SUBROUTINE FOO(FUN,R)
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
然而,测试示例中的结果,给了我:
python
>>> import callback
>>> def f(i): return i*i
...
>>> print callback.foo(f)
0.0
因此,它returns 0.0
而不是110.0
,其中0.0
是Fortran代码中r
的初始值。
无论我使用哪个回调函数,结果都是一样的(不变R
)。
我正在使用从 conda
.
python 3.7
和 numpy
的最新版本
你能重现那个问题吗,还是我做错了什么?
问题似乎是由外部函数 预期 和 实际 数据类型不匹配引起的 FUN
:
- 根据implicit data typing rules of Fortran,在
CALLBACK.F
中,EXTERNAL
函数FUN
有一个隐式类型REAL
(因为没有显式类型,或IMPLICIT NONE
语句)。 - 但是,还要查看 second example in the documentation 的详细信息,其中 F2PY 包装器是使用
f2py -m callback2 -h callback2.pyf callback.f
显式创建的,您会注意到外部函数r
的结果fun
被定义为real*8 :: r
类型(对于未修改的callback2.pyf
签名文件也是如此,因此这是默认的 F2PY 行为)。
简而言之,问题是 FOO
期望 FUN
到 return 一个 REAL
结果,而从 Python 和 F2PY 包装器的外部函数被定义为 return 一个 REAL*8
结果。因此,一个解决方案是确保 FUN
在 Fortran 和 Python/F2PY 包装器中具有相同的 return 类型。这可以通过多种方式实现,例如通过在 CALLBACK.F
:
REAL*8 FUN
C FILE: CALLBACK.F
SUBROUTINE FOO(FUN,R)
REAL*8 FUN
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
如示例中那样用 python -m numpy.f2py -c -m callback callback.f
包装这个修改后的 CALLBACK.F
,现在给出了所需的输出:
python
>>> import callback
>>> def f(i): return i*i
...
>>> print(callback.foo(f))
110.0
出于兴趣,您可以使用两个文件 prog.f
和 fun.f
:
C FILE: PROG.F, including subroutine FOO previously in CALLBACK.F
PROGRAM MAIN
C REAL*8 FUN
EXTERNAL FUN
REAL*8 R
R = 0
PRINT *, "BEFORE: ", R
CALL FOO(FUN, R)
PRINT *, "AFTER: ", R
END
C This is copied from CALLBACK.F
SUBROUTINE FOO(FUN,R)
C REAL*8 FUN
EXTERNAL FUN
INTEGER I
REAL*8 R
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END
C END OF FILE CALLBACK.F
和
C FILE: FUN.F containing the function to be called by FOO
REAL*8 FUNCTION FUN(I)
INTEGER I
FUN = I*I
END
使用 gfortran -fcheck=all -Wall -g func.f prog.f
编译,它给出以下输出(实际上与有问题的 Python 示例相同):
./a.out
BEFORE: 0.0000000000000000
AFTER: 0.0000000000000000
在 prog.f
中取消注释 REAL*8 FUN
的两个实例并重新编译解决了问题:
./a.out
BEFORE: 0.0000000000000000
AFTER: 110.00000000000000