I have a subroutine that calculates a large array and writes it to a file. I'm trying to transform that into a function that returns that array. However, I'm getting a very weird error which seems to be connected to the fact that I am returning an array. When I try to return a float (as a test) it works perfectly fine.
Here's the MWE, which I call from python with mwe('dir', 'postpfile', 150, 90.)
:
FUNCTION mwe(dir, postpfile, nz, z_scale)
IMPLICIT NONE
INTEGER :: nz
REAL(KIND=8) :: z_scale
CHARACTER(len=100) :: postpfile
CHARACTER(len=100) :: dir
REAL(kind=8) :: mwe
print*,'dir ', dir
print*,'postpfile ', postpfile
print*,'nz ', nz
print*,'Lz ', z_scale
mwe = 4.5d0
END FUNCTION mwe
This works well and prints, as expected:
dir dir
postpfile postpfile
nz 150
Lz 90.000000000000000
However, if I define the function as an array:
FUNCTION mwe(dir, postpfile, nz, z_scale)
IMPLICIT NONE
INTEGER :: nz
REAL(KIND=8) :: z_scale
CHARACTER(len=100) :: postpfile
CHARACTER(len=100) :: dir
REAL(KIND=8),DIMENSION (2,23) :: mwe
print*,'dir ', dir
print*,'postpfile ', postpfile
print*,'nz ', nz
print*,'Lz ', z_scale
mwe = 4.5d0
END FUNCTION mwe
Then it prints this:
dir postpfile
postpfile ��:����������k�� 2����V@(����H���;�!��v
nz 0
Segmentation fault (core dumped)
I am running f2py version 2, NumPy 1.11.1 and Python 3.5.1.
EDIT
I'm compiling with f2py -c -m fmwe fmwe.f90
, and calling the function with mwe('dir', 'postpfile', 150, 90.)
.
I think the problem is coming from somewhere from lack of the explicit interface. (not sure may be someone else can point out what is the problem more precisely.)
Even though, I am not sure about my explanation, I have 2 working cases. Changing your function into a subroutine or putting your function inside a module (which generates the explicit interface by itself) solves the issue you mentioned.
Below script still can be called like my_sub('dir', 'postpfile', 150, 90.)
from python.
subroutine my_sub(mwe, dir, postpfile, nz, z_scale)
implicit none
integer,intent(in) :: nz
real(KIND=8),intent(in) :: z_scale
chracter(len=100),intent(in) :: postpfile
character(len=100), intent(in) :: dir
real(KIND=8), intent(out) :: mwe(2,23)
print*,'dir ', dir
print*,'postpfile ', postpfile
print*,'nz ', nz
print*,'Lz ', z_scale
mwe = 4.5d0
end subroutine my_sub
If you use the function within a module, you need to make the call from python a little differently; test('dir', 'postpfile', 150, 90.)
.
module test
contains
function mwe(dir, postpfile, nz, z_scale)
implicit none
integer :: nz
real(KIND=8) :: z_scale
chracter :: postpfile
character(len=100) :: dir
real(KIND=8) :: mwe(2,23)
print*,'dir ', dir
print*,'postpfile ', postpfile
print*,'nz ', nz
print*,'Lz ', z_scale
mwe = 4.5d0
end function mwe
end module test
I did not try, but it will probably work with proper Fortran interface
including your function.(assuming existence of the explicit interface is the key)
I hope that someone will complete/correct my answer.