I would like to use f2py
with modern Fortran. In particular I'm trying to get the following basic example to work. This is the smallest useful example I could generate.
! alloc_test.f90
subroutine f(x, z)
implicit none
! Argument Declarations !
real*8, intent(in) :: x(:)
real*8, intent(out) :: z(:)
! Variable Declarations !
real*8, allocatable :: y(:)
integer :: n
! Variable Initializations !
n = size(x)
allocate(y(n))
! Statements !
y(:) = 1.0
z = x + y
deallocate(y)
return
end subroutine f
Note that n
is inferred from the shape of input parameter x
. Note that y
is allocated and deallocated within the body of the subroutine.
When I compile this with f2py
f2py -c alloc_test.f90 -m alloc
And then run in Python
from alloc import f
from numpy import ones
x = ones(5)
print f(x)
I get the following error
ValueError: failed to create intent(cache|hide)|optional array-- must have defined dimensions but got (-1,)
So I go and create and edit the pyf
file manually
f2py -h alloc_test.pyf -m alloc alloc_test.f90
Original
python module alloc ! in
interface ! in :alloc
subroutine f(x,z) ! in :alloc:alloc_test.f90
real*8 dimension(:),intent(in) :: x
real*8 dimension(:),intent(out) :: z
end subroutine f
end interface
end python module alloc
Modified
python module alloc ! in
interface ! in :alloc
subroutine f(x,z,n) ! in :alloc:alloc_test.f90
integer, intent(in) :: n
real*8 dimension(n),intent(in) :: x
real*8 dimension(n),intent(out) :: z
end subroutine f
end interface
end python module alloc
Now it runs but the values of the output z
are always 0
. Some debug printing reveals that n
has the value 0
within the subroutine f
. I assume that I'm missing some f2py
header magic to manage this situation properly.
More generally what is the best way to link the above subroutine into Python? I'd strongly prefer not to have to modify the subroutine itself.
z
. All else is fine. See mine or @Prometheous answer below. The currently accepted answer is an interesting read but doesn't relate much to the issue here. $\endgroup$