0

I have a subroutine that I'm writing in Fortran to be compiled with f2py and the compilation is failing. I won't post the full subroutine here but a MWE is:

SUBROUTINE mwe(Vars, nxc, nyc, vCorr)
IMPLICIT NONE
real(kind=8), dimension(:,:,:,:) :: Vars
integer :: nxc, nyc
integer :: dims(4), nv, nt, nx, ny
real(kind=8), intent(out), allocatable :: vCorr(:,:,:,:)

dims = shape(Vars)
nv=dims(1)
nt=dims(2)
nx=dims(3)
ny=dims(4)
allocate(vCorr(nv, nt, 2*nxc+1, 2*nyc+1))

print*,size(vCorr)
print*,size(Vars)
END SUBROUTINE

This fails with

/tmp/tmpy43di1/src.linux-x86_64-2.7/mwe-f2pywrappers.f:30:31:

       call mwe(vars, nxc, nyc, vcorr)
                               1
Error: Actual argument for ‘vcorr’ must be ALLOCATABLE at (1)

Which apparently means that f2py doesn't accept allocatable output arrays. So I tried to circumvent this problem by passing the shape Vars as an array, so vCorr doesn't have to be allocated, which led me to this code

SUBROUTINE mwe(Vars, nxc, nyc, dims, vCorr)
IMPLICIT NONE
real(kind=8), dimension(:,:,:,:) :: Vars
integer :: nxc, nyc
integer :: dims(4)
real(kind=8) :: vCorr(dims(1),dims(2),2*nxc+1,2*nyc+1)

print*,size(vCorr)
print*,size(Vars)
END SUBROUTINE

Which fails with this error

/tmp/tmp0Y1S9x/src.linux-x86_64-2.7/mwemodule.c:296:39: error: called object ‘dims’ is not a function or function pointer
   vcorr_Dims[0]=dims(1),vcorr_Dims[1]=dims(2),vcorr_Dims[2]=2 * nxc + 1,vcorr_Dims[3]=2 * nyc + 1;

After some look around I came across this page which leads me to believe (even though I'm using f2py2, and not 3) that this is a bug.

Any suggestions around this?

TomCho
  • 3,204
  • 6
  • 32
  • 83

1 Answers1

0

In the first example f2py does not support allocatable array arguments. They do not fit well with Python arrays.

In the other example f2py does not understand dims(1),dims(2) in vCorr(dims(1),dims(2). It does not support array elements there. This is a bug.

As a workaround use scalar variables for the dimensions

SUBROUTINE mwe(Vars, nxc, nyc, dim1, dim2, vCorr)
  integer, parameter :: dp = kind(1.d0)
  real(dp), dimension(:,:,:,:) :: Vars
  integer :: nxc, nyc
  integer :: dim1, dim2
  real(dp) :: vCorr(dim1,dim2,2*nxc+1,2*nyc+1)

Note: kind=8 is ugly and not portable. The true meaning is NOT 8 bytes, although it does correspond to 8 byte reals in many compilers. But not in all of them. Even the good old double precision is better.

Graham
  • 7,431
  • 18
  • 59
  • 84
  • I understand this, but I was trying to avoid that because my plan is to extend this routine to arrays of more dimensions (probably 6 or more). So it kind of becomes a problem passing that many individual integers in the correct order. Isn't there any other way? – TomCho Apr 10 '17 at 15:19
  • I don't think so. You might try derived type, I expect the same problem. – Vladimir F Героям слава Apr 10 '17 at 15:55