简体   繁体   English

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

[英]How to correctly run f2py example from numpy docs?

I'm having trouble following one of the examples shown in the numpy docs concerning f2py and callback functions. 我在遵循numpy文档中显示的有关f2py和回调函数的示例之一时遇到了麻烦。 I performed the exact same steps as in the first example (ie f2py -c -m callback callback.f ) to wrap callback.f : 我执行了与第一个示例完全相同的步骤(即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

However, testing the result as in the example, gives me: 但是,如示例中那样测试结果会给我:

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

Thus, it returns 0.0 instead of 110.0 , where 0.0 is the initial value of r in the Fortran code. 因此,它返回0.0而不是110.0 ,其中0.0是Fortran代码中r的初始值。 No matter which callback function I use, the result remains the same (unchanged R ). 无论我使用哪个回调函数,结果都将保持不变( R不变)。 I'm using a recent version of python 3.7 and numpy obtained from conda . 我正在使用从conda获得的python 3.7numpy的最新版本。

Can you reproduce that problem, or am I doing something wrong? 您可以重现该问题,还是我做错了什么?

The problem appears to be caused by a mismatch between the expected and actual data types of the external function FUN : 该问题似乎是由外部函数FUN预期数据类型和实际数据类型之间的不匹配引起的:

  • According to the implicit data typing rules of Fortran , in CALLBACK.F , the EXTERNAL function FUN has an implicit type REAL (since there is no explicit type, or IMPLICIT NONE statement). 根据Fortran隐式数据键入规则 ,在CALLBACK.FEXTERNAL函数FUN具有隐式类型REAL (因为没有显式类型或IMPLICIT NONE语句)。
  • However, also looking at the details of the second example in the documentation , where the F2PY wrapper is created explicitly using f2py -m callback2 -h callback2.pyf callback.f , you will note that the result r of the external function fun is defined as having type real*8 :: r (this is also true for the unmodified callback2.pyf signature file, so this is the default F2PY behaviour). 但是,还要查看文档中第二个示例的详细信息,其中使用f2py -m callback2 -h callback2.pyf callback.f显式创建F2PY包装器,您会注意到定义了外部函数fun的结果r与类型为real*8 :: r (对于未修改的callback2.pyf签名文件也是如此,因此这是默认的F2PY行为)。

In short the problem is that FOO expects FUN to return a REAL result, while from the Python and F2PY wrapper's side the external function is defined to return a REAL*8 result. 简而言之,问题是FOO期望FUN返回REAL结果,而从Python和F2PY包装器的那一侧定义了外部函数以返回REAL*8结果。 A solution is therefore to ensure that FUN has the same return type in Fortran and the Python/F2PY wrapper. 因此,一种解决方案是确保FUN在Fortran和Python / F2PY包装器中具有相同的返回类型。 This can be achieved in several ways, for example by adding a data type specification REAL*8 FUN in CALLBACK.F : 这可以通过多种方式实现,例如,通过在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

Wrapping this modified CALLBACK.F with python -m numpy.f2py -c -m callback callback.f as in the example, now gives the desired output: 如示例中所示,将修改后的CALLBACK.Fpython -m numpy.f2py -c -m callback callback.f ,现在得到所需的输出:

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

For interest sake, the same behaviour that you saw in Python/F2PY can be produced in pure Fortran using two files prog.f and fun.f : 出于兴趣考虑,可以使用两个文件prog.ffun.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

and

C FILE: FUN.F containing the function to be called by FOO
      REAL*8 FUNCTION FUN(I)
      INTEGER I
      FUN = I*I
      END

Compiled using gfortran -fcheck=all -Wall -g func.f prog.f , it gives the following output (in effect the same as your problematic Python example): 使用gfortran -fcheck=all -Wall -g func.f prog.f ,它给出以下输出(实际上与有问题的Python示例相同):

./a.out
 BEFORE:    0.0000000000000000
 AFTER:    0.0000000000000000

Uncommenting both instances of REAL*8 FUN in prog.f and recompiling solves the problem: prog.f取消对REAL*8 FUN两个实例的注释并重新编译可以解决此问题:

./a.out
 BEFORE:    0.0000000000000000
 AFTER:    110.00000000000000

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM