Shriraj Hegde
Shriraj Hegde

Reputation: 1082

f2py gives error when subroutine contains internal procedures (but compiles successfully with gfortran)

Following program compiles(in f2py) when the subroutine doesn't contain any internal procedures but fails to compile in f2py (compiles with gfortran) when it contains any internal procedure

Fortran code:

subroutine example(array)
    implicit none
    real*8::array(:,:)
    INTEGER::i,j
!f2py intent(inout)::array

    do i=1,3
        do j=1,3
            array(i,j)=10*i+j
        enddo
        ! print*,''
    enddo
    call tentimes(array)
    RETURN

    contains

    subroutine tentimes(array)
        implicit none
!f2py intent(inout):array
        real*8::array(:,:)
        array=array*10
    end subroutine tentimes



end subroutine example



program dummy
    implicit none
    
end program dummy

compiled with python -m numpy.f2py -c allocate.f90 -m ftest

and the python code :

import numpy as np

a=np.zeros((3,3),order="F")

print(a)
res=ftest.example(a)
print(a)

Why is this happening?

Error generated by f2py:

compiling Fortran sources
Fortran f77 compiler: /usr/bin/gfortran -Wall -g -ffixed-form -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran f90 compiler: /usr/bin/gfortran -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran fix compiler: /usr/bin/gfortran -Wall -g -ffixed-form -fno-second-underscore -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
compile options: '-I/tmp/tmpwd_qygau/src.linux-x86_64-3.9 -I/home/srj/.local/lib/python3.9/site-packages/numpy/core/include -I/usr/include/python3.9 -c'
gfortran:f90: allocate.f90
allocate.f90:17:31:

   17 |     subroutine tentimes(array_i)
      |                               1
Warning: Unused dummy argument ‘array_i’ at (1) [-Wunused-dummy-argument]
allocate.f90:17:23:

   17 |     subroutine tentimes(array_i)
      |                       ^
Warning: ‘tentimes’ defined but not used [-Wunused-function]
gfortran:f90: /tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90
/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90:13:17:

   13 |                 subroutine tentimes(array_i)
      |                 1
Error: Unclassifiable statement at (1)
/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90:15:39:

   15 |                 end subroutine tentimes
      |                                       1
Error: Expected label ‘example’ for END SUBROUTINE statement at (1)
/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90:14:53:

   14 |                     real*8, dimension(:,:) :: array_i
      |                                                     1
Error: Array ‘array_i’ at (1) cannot have a deferred shape
error: Command "/usr/bin/gfortran -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops -I/tmp/tmpwd_qygau/src.linux-x86_64-3.9 -I/home/srj/.local/lib/python3.9/site-packages/numpy/core/include -I/usr/include/python3.9 -c -c /tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90 -o /tmp/tmpwd_qygau/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.o" failed with exit status 1

Similar nested procedures work well in gfortran. Why does this error happen? How to rectify this?

Upvotes: 3

Views: 424

Answers (1)

Shriraj Hegde
Shriraj Hegde

Reputation: 1082

EDIT: The better way is to use f2py is "the smart way"

just doing this works well

python -m numpy.f2py allocate.f90 -m ftest -h ftest.pyf && \
python -m numpy.f2py -c ftest.pyf allocate.f90

Since this bypasses generating FORTRAN interface.


Okay, I confirmed it's a bug in f2py, the generated code in f2pywrappers2.f90 has an error

f2py produces:

!     -*- f90 -*-
!     This file is autogenerated with f2py (version:1.21.2)
!     It contains Fortran 90 wrappers to fortran functions.

      subroutine f2pywrapexample (array, f2py_array_d0, f2py_array_d1)
      integer f2py_array_d0
      integer f2py_array_d1
      real*8 array(f2py_array_d0,f2py_array_d1)
      interface
      
            subroutine example(array) 
                real*8, dimension(:,:),intent(inout) :: array
                subroutine tentimes(array) 
                    real*8, dimension(:,:) :: array
                end subroutine tentimes
            end subroutine example
      end interface
      call example(array)
      end

correct code:

      subroutine f2pywrapexample (array, f2py_array_d0, f2py_array_d1)
      integer f2py_array_d0
      integer f2py_array_d1
      real*8 array(f2py_array_d0,f2py_array_d1)
      interface
      
            subroutine example(array) 
                real*8, dimension(:,:),intent(inout) :: array
            end subroutine example
            subroutine tentimes(array) 
                real*8, dimension(:,:) :: array
            end subroutine tentimes
      end interface
      call example(array)
      end

the interface shouldn't actually contain nested procedures, even though the subroutine has a nested procedure

fixing this, then generating the corresponding object, placing it in the correct temp folder and manually linking with the command

/usr/bin/gfortran -Wall -g -Wall -g -shared /tmp/tmpfw0ammli/tmp/tmpfw0ammli/src.linux-x86_64-3.9/ftestmodule.o /tmp/tmpfw0ammli/tmp/tmpfw0ammli/src.linux-x86_64-3.9/fortranobject.o /tmp/tmpfw0ammli/allocate.o /tmp/tmpfw0ammli/tmp/tmpfw0ammli/src.linux-x86_64-3.9/ftest-f2pywrappers2.o -L/usr/lib/gcc/x86_64-redhat-linux/11 -L/usr/lib/gcc/x86_64-redhat-linux/11 -L/usr/lib64 -lgfortran -o ./ftest.cpython-39-x86_64-linux-gnu.so

this succeeded, and python prints correct output.

enter image description here

Upvotes: 3

Related Questions