Why is the function not being evaluated correctly?
You are sending the result of the callback function f
directly to the print
method. Because Fortran has no idea what data type f
will returned (since it is not declared and it is not a Fortran function), print
cannot correctly interpret the data to print correctly. if you assign the result to a variable, then print the variable you should see the expected result:
double precision x
....
x = f(xs(1))
print *, x
How to return result
to Python?
You need to inform f2py of the intent of the variables. This is actually possible to do with standard Fortran 90 syntax, which I HIGHLY recommend doing since it makes your code clearer (I know you are using Fortran 90 because you are able to print an entire array without looping over it.).
subroutine stack2(f,xs,result,nf,nxs)
implicit none
integer, intent(in) :: nf, nxs
double precision, intent(in) :: xs(nxs)
double precision, intent(out) :: result(nf)
external f
...
end subroutine stack2
Now, it is clear which variables come into the routine, and which are going out. Note that result
has to be an argument to the subroutine in order for it to be passed out.
f2py
will now understand that result
should be returned from the stack2
function.
Is it possible to evaluate the array xs
at once in Fortran
I'm not sure what you mean exactly, but I assume you want to know if you can do this on the entire array at a time, instead of in a do
loop.
Possibly
Since xs
is an array, you should be able to just pass the whole array to f
and it should operate on the entire array. This might not work, because Fortran requires a function to be ELEMENTAL
to do this, and this might not be within the scope of f2py
. If f2py
does not make the function ELEMENTAL
, then you must do this in a loop.
An issue you might want to address
The line result = result + f(xs(I))
is assigning the same value to every element of result
. It is not clear if this is what you want, but it might be something to address if it is not.
A code-based summary
Below is an example of a version of your code using these new suggestions.
subroutine stack2(f,xs,result,nf,nxs)
implicit none
integer, intent(in) :: nf, nxs
double precision, intent(in) :: xs(nxs)
double precision, intent(out) :: result(nf)
double precision :: x
integer :: I
external f
result = 0.0d0 ! Make this a double constant since result is double
do I = 1,nxs
x = f(xs(I))
result = result + x
print *, x
end do
print *, xs
return ! Not needed in Fortran 90
end subroutine stack2
Note that f2py
will properly figure out the length of your input array, so when you call it you only need to define the length of the result
:
import numpy as np
from stack2 import stack2
def func(x):
return x**2
if __name__ == '__main__':
xs = np.linspace(0.,10.,10)
ans = stack2(func,xs,5) # This was changed
print 'ans:',ans