I have ran into a problem, while trying to make a bunch of Fortran code work in Python using f2py (in gfortran). My Fortran code has a whole bunch of subroutines and it compiles fine both in gfortran and an online virtual fortran IDE. The subroutine I'm having issues with is a mergesort subroutine (which I took from rosettastone and modified), it looks like this:
subroutine MSort(N, A, A_out)
implicit none
integer, intent(in) :: N
real, dimension(N), intent(in) :: A
real, dimension(N), intent(out) :: A_out
real :: work((size(A) + 1) / 2)
A_out=A
call MergeSort(A_out, work)
contains
subroutine merge(A, B, C)
implicit none
real, target, intent(in) :: A(:), B(:)
real, target, intent(inout) :: C(:)
integer :: i, j, k
if (size(A) + size(B) > size(C)) then
stop
end if
i = 1; j = 1
do k = 1, size(C)
if (i <= size(A) .and. j <= size(B)) then
if (A(i) <= B(j)) then
C(k) = A(i)
i = i + 1
else
C(k) = B(j)
j = j + 1
end if
else if (i <= size(A)) then
C(k) = A(i)
i = i + 1
else if (j <= size(B)) then
C(k) = B(j)
j = j + 1
end if
end do
end subroutine merge
subroutine swap(x, y)
implicit none
real, intent(inout) :: x, y
real :: tmp
tmp = x; x = y; y = tmp
end subroutine
recursive subroutine MergeSort(A, work)
implicit none
real, intent(inout) :: A(:)
real, intent(inout) :: work(:)
integer :: half
half = (size(A) + 1) / 2
if (size(A) < 2) then
continue
else if (size(A) == 2) then
if (A(1) > A(2)) then
call swap(A(1), A(2))
end if
else
call MergeSort(A( : half), work)
call MergeSort(A(half + 1 :), work)
if (A(half) > A(half + 1)) then
work(1 : half) = A(1 : half)
call merge(work(1 : half), A(half + 1:), A)
endif
end if
end subroutine MergeSort
end subroutine MSort
I compiled it with
$ f2py -c -m fprogram fprogram.f90
and inserted import fprogram
in the beginning of my python code (in a jupyter notebook), where I wanted to use it like this (I know original is a list, it's not dimensional issues):
size=len(original_list)
sorted_list=fprogram.MSort(size,original_list)
I got the error message
module 'fprogram' has no attribute 'MSort'
Meanwhile, when I used any other subroutine from fprogram in the same way it works perfectly.
I already modified the fortran code to not have variables with intent(inout)
because in a previous case this has solved my problem, but it didn't work this time. What I can I do to make python recognze this subroutine?
There are 2 different errors.
At first, f2py
creates all lowercase procedures.
Thus, you need to call fprogram.msort
which is exactly what the error message tries to tell you.
On the other hand, f2py
figured out that the argument N
is redundant in python.
Which is why it created a function where N
is an optional paramenter.
Thus, you also need to call it in one of the following ways
sorted_list=fprogram.msort(original_list)
sorted_list=fprogram.msort(original_list, size)
sorted_list=fprogram.msort(original_list, n=size)
How did I find that out? I read the documentation by calling (in the python REPL)
import fprogram
help(fprogram)