f2py: Specifying real precision in fortran when interfacing with python?

前端 未结 1 721
囚心锁ツ
囚心锁ツ 2020-12-09 00:24

I am playing around with f2py. I\'m a bit confused about numpy intrinsic types vs. fortran 90 types. It seems like I can only use single precision reals in fortran 90, when

相关标签:
1条回答
  • 2020-12-09 00:42

    In your first example, I don't know why you say it seems like f2py doesn't accept double precision, when test.test.r_dp is double precision. A numpy array that shows a value with a decimal point and no explicit dtype is a double precision array.

    The second example shows a limitation in F2PY's handling of type definitions with kind=<kind>. See the FAQ: http://cens.ioc.ee/projects/f2py2e/FAQ.html#q-what-if-fortran-90-code-uses-type-spec-kind-kind

    To see what is happening, run f2py test.f90 -m test. I get this:

    Reading fortran codes...
        Reading file 'test.f90' (format:free)
    Post-processing...
        Block: test
                Block: test
                    Block: input_sp
                    Block: input_dp
    Post-processing (stage 2)...
        Block: test
            Block: unknown_interface
                Block: test
                    Block: input_sp
                    Block: input_dp
    Building modules...
        Building module "test"...
            Constructing F90 module support for "test"...
              Variables: r_dp sp r_sp dp
                Constructing wrapper function "test.input_sp"...
    getctype: "real(kind=sp)" is mapped to C "float" (to override define dict(real = dict(sp="<C typespec>")) in /Users/warren/tmp/.f2py_f2cmap file).
    getctype: "real(kind=sp)" is mapped to C "float" (to override define dict(real = dict(sp="<C typespec>")) in /Users/warren/tmp/.f2py_f2cmap file).
    getctype: "real(kind=sp)" is mapped to C "float" (to override define dict(real = dict(sp="<C typespec>")) in /Users/warren/tmp/.f2py_f2cmap file).
                  input_sp(val)
                Constructing wrapper function "test.input_dp"...
    getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /Users/warren/tmp/.f2py_f2cmap file).
    getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /Users/warren/tmp/.f2py_f2cmap file).
    getctype: "real(kind=dp)" is mapped to C "float" (to override define dict(real = dict(dp="<C typespec>")) in /Users/warren/tmp/.f2py_f2cmap file).
                  input_dp(val)
        Wrote C/API module "test" to file "./testmodule.c"
        Fortran 90 wrappers are saved to "./test-f2pywrappers2.f90"
    

    Note that it is mapping both "real(kind=sp)" and "real(kind=dp)" to C "float", which is single precision.

    There are several ways to fix this.

    Method 1

    Change the type declarations to "real(kind=4)" and "real(kind=8)" (or "real*4" and "real*8"), respectively.

    Of course, this defeats the purpose of using selected_real_kind, and for some compilers, 4 and 8 are not the correct KIND values for single and double precision. In this case, with gfortran, sp is 4 and dp is 8, so it works.

    Method 2

    Tell f2py how to handle those declarations. This is explained in the f2py FAQ, and it is the approach suggested in the "getctype: ..." messages in the output of f2py shown above.

    In this case, you would create a file called .f2py_f2cmap (in the directory where you are running f2py) that contains the line

    dict(real=dict(sp='float', dp='double'))
    

    Then f2py will do the right thing with those real(sp) and real(dp) declarations.

    Method 3

    It also works to rearrange your code a bit:

    module types
    
    implicit none
    integer, parameter :: sp = selected_real_kind(6,37) ! single precision
    integer, parameter :: dp = selected_real_kind(15,307) ! double precision
    
    real(sp) :: r_sp = 1.0
    real(dp) :: r_dp = 1.0_dp
    
    end module
    
    
    module input
    
    contains 
    
    subroutine input_sp(val)
      use types
      real(sp), intent(in) :: val
      real(sp) :: x
      x = val
      write(*,*) x
    end subroutine
    
    subroutine input_dp(val)
      use types
      real(dp), intent(in) :: val
      real(dp) :: x
      x = val
      write(*,*) dp, val, x
    end subroutine
    
    end module
    

    See Subroutine argument not passed correctly from Python to Fortran for a similar suggestion.

    0 讨论(0)
提交回复
热议问题