3

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?

Shriraj Hegde
  • 829
  • 5
  • 18

1 Answers1

3

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

Shriraj Hegde
  • 829
  • 5
  • 18