[英]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.7
和numpy
的最新版本。
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
的预期数据类型和实际数据类型之间的不匹配引起的:
CALLBACK.F
, the EXTERNAL
function FUN
has an implicit type REAL
(since there is no explicit type, or IMPLICIT NONE
statement). 根据Fortran的隐式数据键入规则 ,在CALLBACK.F
, EXTERNAL
函数FUN
具有隐式类型REAL
(因为没有显式类型或IMPLICIT NONE
语句)。 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.F
与python -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.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
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.