Reputation:
I have to say that I am not a Fortran-programmer at all. I usually only use Python and C++, but sometimes colleagues have written great Fortran functions that would be great to implement in my Python code for efficiency. I was just about to try the f2py module via IPython's magic function.
For a trivial test, I have the following bubblesort implementation where I want to sort a Python list in place (which I convert to an numpy array laid out in memory the Fortran-style; I assume this would be more efficient than using Python lists right?)
However, the function has no return value here (None
), and I am wondering where my mistake would be!?
The commands to install and load the fortranmagic which uses f2py
%install_ext https://raw.github.com/mgaitan/fortran_magic/master/fortranmagic.py
%load_ext fortranmagic
The Fortran bubblesort code:
%%fortran
SUBROUTINE fortran_bubblesort(a)
REAL, INTENT(in out), DIMENSION(:) :: a
REAL :: temp
INTEGER :: i, j
LOGICAL :: swapped = .TRUE.
DO j = SIZE(a)-1, 1, -1
swapped = .FALSE.
DO i = 1, j
IF (a(i) > a(i+1)) THEN
temp = a(i)
a(i) = a(i+1)
a(i+1) = temp
swapped = .TRUE.
END IF
END DO
IF (.NOT. swapped) EXIT
END DO
END SUBROUTINE fortran_bubblesort
The execution:
x = np.asfortranarray([3,2,1])
y = fortran_bubblesort(x)
print(x, y)
The result:
[3 2 1] None
========
To test that a value can be returned in general, I ran the following code, which works just fine:
%%fortran
SUBROUTINE fortran_sum(x, y, z)
REAL, INTENT(in) :: x,y
REAL, INTENT(out) :: z
z = x + y
END SUBROUTINE fortran_sum
Execute:
fortran_sum(3, 4)
Returns:
7.0
Upvotes: 1
Views: 857
Reputation: 1
I made the original Fortran code of the question working by just replacing both "REAL" statements by "REAL(kind=8)" statements. That way, Fortran's variables match Python's ones.
Also, to get the execution working and to avoid the "None" output, I propose the following lines (note that I've changed the integer inputs by float data to have a correct match):
import numpy as np
x = np.asfortranarray([3.,0., 2.,1.])
print(x)
fortran_bubblesort(x)
print(x)
Execution:
[ 3. 0. 2. 1.]
[ 0. 1. 2. 3.]
Note that I've also added number zero to be more Pythonic ;-)
Upvotes: 0
Reputation: 6898
The problem you are facing has to do with the array dimensions. It looks like that subroutine was yanked from a module, as it uses an assumed-shape dummy array a
. This requires an explicit interface, and I don't know if and/or how f2py
handles that. I've only ever used f2py
using assumed size dummy arrays, which it handles well. This would be the code:
SUBROUTINE fortran_bubblesort(a,n)
INTEGER, INTENT(in) :: n
REAL, INTENT(in out), DIMENSION(n) :: a
REAL :: temp
INTEGER :: i, j
LOGICAL :: swapped = .TRUE.
DO j = SIZE(a)-1, 1, -1
swapped = .FALSE.
DO i = 1, j
IF (a(i) > a(i+1)) THEN
temp = a(i)
a(i) = a(i+1)
a(i+1) = temp
swapped = .TRUE.
END IF
END DO
IF (.NOT. swapped) EXIT
END DO
END SUBROUTINE fortran_bubblesort
In this case, f2py
will notice that n
is just the array dimension, and it will make it an optional argument in the python function.
Upvotes: 0