如何从numpy docs正确运行f2py示例?

时间:2019-02-01 15:05:16

标签: python numpy fortran f2py

在遇到有关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

因此,它返回0.0而不是110.0,其中0.0是Fortran代码中r的初始值。 无论我使用哪个回调函数,结果都将保持不变(不变的R)。 我正在使用从python 3.7获得的numpyconda的最新版本。

你能重现这个问题,还是我做错了什么?

1 个答案:

答案 0 :(得分:2)

问题似乎是由外部函数FUN预期实际数据类型之间的不匹配引起的:

  • 根据implicit data typing rules of Fortran,在CALLBACK.F中,EXTERNAL函数FUN具有隐式类型REAL(因为没有显式类型,或者{ {1}}语句)。
  • 但是,还要查看second example in the documentation的详细信息,其中使用IMPLICIT NONE显式创建了F2PY包装器,您会注意到外部函数{{1 }}被定义为具有f2py -m callback2 -h callback2.pyf callback.f类型(未修改的r签名文件也是如此,因此这是默认的F2PY行为)。

简而言之,问题在于fun期望real*8 :: r返回callback2.pyf的结果,而从Python和F2PY包装器的那一侧定义了外部函数以返回{{1} }结果。因此,一种解决方案是确保FOO在Fortran和Python / F2PY包装器中具有相同的返回类型。这可以通过多种方式来实现,例如,通过在FUN中添加数据类型规范REAL

REAL*8

如示例中用FUN包裹经过修改的REAL*8 FUN,现在将提供所需的输出:

CALLBACK.F

出于兴趣的考虑,可以使用两个文件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 CALLBACK.F在纯Fortran中产生与Python / F2PY中相同的行为:

python -m numpy.f2py -c -m callback callback.f

python
>>> import callback
>>> def f(i): return i*i
...
>>> print(callback.foo(f))
110.0

使用prog.f进行编译,它提供以下输出(实际上与您遇到问题的Python示例相同):

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