2

I have some old fortran code which I want to wrap with f2py and which I am not allowed to change.

The core of the program is some subroutine that depends on user defined subroutines. All of these subroutines share common parameter arrays for exchange of user supplied data between the routines. These parameter arrays are one-dimensional and as such don't expect any predefined input size in the main subroutine headers.

However, it seems, like the python callback function headers need precise information about the actual size of the arrays.

Let's look at an example:

This is my fortran code:

  Subroutine myscript(x,fun,o,n,rpar, ipar)
  external fun
  integer n
  double precision x(n,*)
  double precision o(n)
  double precision rpar(*)
  integer ipar(*)
  write(*,*) n
  !write(*,*) x(1,:)
  call fun(n,x,o,rpar,ipar)
  write(*,*) o
  write(*,*) rpar(1)
  end

And this is my python portion:

    import numpy as np
    import routine
    import ipdb
    def fun(X, rpar):
        print("In Callback function")
        ipdb.set_trace()
        print(X)
        O = X[1,:]
        print(O)
        return O
    O = np.array([1.,0.])
    X = np.identity(2)
    rpar = np.array([1.,1.])

    routine.myscript(X, fun, rpar)

I compiled with f2py -c routine.pyf routine.f and the following header file

    !    -*- f90 -*-
    ! Note: the context of this file is case sensitive.

    python module myscript__user__routines 
    interface myscript_user_interface 
        subroutine fun(n,x,o,rpar,ipar) ! in :routine:routine.f:myscript:unknown_interface
        integer, optional,intent(hide),check(shape(x,0)==n),depend(x) :: n=shape(x,0)
        double precision dimension(n,n),intent(in) :: x
        double precision dimension(n),intent(out),depend(n) :: o
        double precision dimension(100),intent(in) :: rpar
        integer, optional, dimension(*) :: ipar
        end subroutine fun
    end interface myscript_user_interface
    end python module myscript__user__routines
    python module routine ! in 
    interface  ! in :routine
        subroutine myscript(x,fun,o,n,rpar,ipar) ! in :routine:routine.f
        use myscript__user__routines
        double precision dimension(n,*),intent(in,copy) :: x
        external fun
        double precision dimension(n),intent(out),depend(n) :: o
        integer, optional,intent(hide),check(shape(x,0)==n),depend(x) :: n=shape(x,0)
        double precision dimension(shape(rpar,0)) :: rpar
        integer, optional, dimension(2) :: ipar
        end subroutine myscript
    end interface 
    end python module routine

    ! This file was auto-generated with f2py (version:2).
    ! See http://cens.ioc.ee/projects/f2py2e/

The important line in the header file is

   double precision dimension(100),intent(in) :: rpar

when in the python debugger, rpar now is a 100-dimensional array, where the last 98 values are garbage (not surprising).

changing dimension to * just returns an empty array

ipdb> rpar
array([], dtype=float64)

changing dimensions to shape(rpar,0) as in the main routine produces the error

ValueError: negative dimensions are not allowed

Is there an elegant way of letting the python user decide the dimension of the parameter array rpar dynamically? The expected value in the example is 2, because its the dimension of the input array.

I guess I could change the interface and add another integer variable declaring the size of this array. However, this means changing all calls to this subroutine at every occurrence in the code; something I want to avoid

dba
  • 453
  • 3
  • 16

0 Answers0