numpyfortranf2py

How to compile the code with current versions of f2py?


I have a problem getting an old module to work with latest NumPy and f2py version.

Namely, I have this small code to do some vertical averaging:

      module mod_spatialaverage
      contains
      
      subroutine spatialaverage(depdata,
     & vardata,depval,varout,sum_a,sum_b,nz,nx,ny)

      implicit none
      real, intent(in) :: depdata(nz,ny,nx)
      real, intent(in) :: vardata(nz,ny,nx)
      integer, intent(in) :: nz,nx,ny
      real, intent(in) :: depval
      real, intent(out) :: varout(ny,nx)
      real, intent(out) :: sum_a(ny,nx),sum_b(ny,nx)
      integer ii,jj,ilev
      real missing_value,dz
      ! ----------------------------------
      varout=0.0;
      missing_value=-1.e3
      ! ----------------------------------
      do ii = 1,nx
        do jj= 1,ny
        ! if it is landpoint:
        if (depdata(1,jj,ii).le.missing_value) cycle
        ! --------------------------------
          dz=abs(0.0-depdata(1,jj,ii));
          sum_a(jj,ii)=sum_a(jj,ii)+vardata(1,jj,ii)*dz
          sum_b(jj,ii)=sum_b(jj,ii)+dz;
          ! --------------------------------
          do ilev=2,nz
            dz=abs(depdata(ilev,jj,ii)-depdata(ilev-1,jj,ii));         
            if (depdata(ilev,jj,ii).gt.depval) then
              sum_a(jj,ii)=sum_a(jj,ii)+vardata(ilev,jj,ii)*dz
              sum_b(jj,ii)=sum_b(jj,ii)+dz;
            endif
            if (depdata(ilev,jj,ii).lt.depval.and.
     & depdata(ilev-1,jj,ii).gt.depval) then
              dz=abs(depval-depdata(ilev-1,jj,ii))
              sum_a(jj,ii)=sum_a(jj,ii)+vardata(ilev,jj,ii)*dz
              sum_b(jj,ii)=sum_b(jj,ii)+dz;
            endif
          enddo
        ! --------------------------------
        enddo
      enddo
      varout=sum_a/sum_b;
      ! ==================================
      return
      end subroutine spatialaverage

      end module mod_spatialaverage
      ! ==================================================

and Makefile:

bin=f2py
#bin=/storage/software/Python-2.7.6/bin/f2py
# --------------------------------
all: mod_spatialaverage

mod_spatialaverage: mod_spatialaverage.f90
    $(bin) -c -m $@ $<

but during the compilation I get an error:

> p/tmp7boek982/src.linux-x86_64-3.11/mod_spatialaverage-f2pywrappers2.f90:7:36:
> 
>     7 |       use mod_spatialaverage, only : unknown_subroutine
>       |                                    1 Error: Symbol ‘unknown_subroutine’ referenced at (1) not found in module
> ‘mod_spatialaverage’

The code and compilation was working with older f2py (some time ago).

How can I get the compilation and module to work with current versions of f2py? Why is there all of the sudden unknown_subroutine?

The compiler I am using is gfortran, NumPy/f2py is version 1.26.4.


Solution

  • The solution is to convert your source file to a proper free-form Fortran source by adding the & characters at the appropriate lines

          subroutine spatialaverage(depdata, &
         & vardata,depval,varout,sum_a,sum_b,nz,nx,ny)
    
                if (depdata(ilev,jj,ii).lt.depval.and. &
         & depdata(ilev-1,jj,ii).gt.depval) then
    

    The parser for fixed form probably does not work well with modules and similar features as everyone uses them rather in free-form (.f90).

    It is probably a bug in f2py and you may try to report it, but there is no guarantee anybody will actually want to deal with this kind of problem.The Numpy community recently rather tries to avoid dealing with more Fortran.

    Compilation:

    > f2py -c -m mod_spatialaverage mod_spatialaverage.f90
    
    

    Test:

    > ipython
    Python 3.11.11 (main, Dec 06 2024, 17:06:18) [GCC]
    Type 'copyright', 'credits' or 'license' for more information
    IPython 8.31.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: import mod_spatialaverage
    
    In [2]: ?? mod_spatialaverage.mod_spatialaverage.spatialaverage??
    Signature:   mod_spatialaverage.mod_spatialaverage.spatialaverage(*args, **kwargs)
    Type:        fortran
    String form: <fortran function spatialaverage>
    Docstring:  
    varout,sum_a,sum_b = spatialaverage(depdata,vardata,depval,[nz,nx,ny])
    
    Wrapper for ``spatialaverage``.
    
    Parameters
    ----------
    depdata : input rank-3 array('f') with bounds (nz,ny,nx)
    vardata : input rank-3 array('f') with bounds (nz,ny,nx)
    depval : input float
    
    Other Parameters
    ----------------
    nz : input int, optional
        Default: shape(depdata, 0)
    nx : input int, optional
        Default: shape(depdata, 2)
    ny : input int, optional
        Default: shape(depdata, 1)
    
    Returns
    -------
    varout : rank-2 array('f') with bounds (ny,nx)
    sum_a : rank-2 array('f') with bounds (ny,nx)
    sum_b : rank-2 array('f') with bounds (ny,nx)