1

I'm having trouble following one of the examples shown in the numpy docs concerning f2py and callback functions. I performed the exact same steps as in the first example (i.e. f2py -c -m callback callback.f) to wrap 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. No matter which callback function I use, the result remains the same (unchanged R). I'm using a recent version of python 3.7 and numpy obtained from conda.

Can you reproduce that problem, or am I doing something wrong?

1
  • This is not of much use but I find the same problem, that foo returns 0 where 110 is expected. Python 3.7 NumPy 1.16.0 Commented Feb 3, 2019 at 21:46

1 Answer 1

2

The problem appears to be caused by a mismatch between the expected and actual data types of the external function 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).
  • 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).

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. A solution is therefore to ensure that FUN has the same return type in Fortran and the Python/F2PY wrapper. This can be achieved in several ways, for example by adding a data type specification REAL*8 FUN in 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

Wrapping this modified CALLBACK.F with python -m numpy.f2py -c -m callback callback.f as in the example, now gives the desired output:

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:

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):

./a.out
 BEFORE:    0.0000000000000000
 AFTER:    0.0000000000000000

Uncommenting both instances of REAL*8 FUN in prog.f and recompiling solves the problem:

./a.out
 BEFORE:    0.0000000000000000
 AFTER:    110.00000000000000
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.