F2py: specifying real precision in fortran when interacting with python?

I play with f2py. I am a little confused about the numpy intrinsic type versus fortran 90 types. It seems that I can only use single prefix variables in fortran 90 when interacting with python. Let me illustrate an example:

Let's say I have this fortran 90 module, test.f90, which needs to be compiled with f2py and imported into python:

module test 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 

and I compile like this:

f2py -c -m test test.f90

Then in python:

 >>> import test >>> test.test.r_sp array(1.0, dtype=float32) >>> test.test.r_dp array(1.0) 

IOW, it seems f2py does not accept double precision. This becomes even more problematic when passing input to the fortran 90 routine from python. Let's say I expand my module to:

 module test 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 contains subroutine input_sp(val) real(sp), intent(in) :: val real(sp) :: x x = val write(*,*) x end subroutine subroutine input_dp(val) real(dp), intent(in) :: val real(dp) :: x x = val write(*,*) x end subroutine end module 

f2py -c -m test test.f90

Python

 >>> import test >>> test.test.input_sp(array(1.0,dtype=float32)) 1.0000000 >>> test.test.input_sp(array(1.0,dtype=float64)) 1.0000000 >>> test.test.input_dp(array(1.0,dtype=float32)) -1.15948430791165406E+155 >>> test.test.input_dp(array(1.0,dtype=float64)) 

-1.15948430791165406E + 155

So it seems that any input variable that should be sent with python should be declared single precision. Is this a known issue with f2py?

Also, as the next question: Converting from sp to dp works in the following sense:

 subroutine input_sp_to_dp(val) real(sp), intent(in) :: val(2) real(dp) :: x(2) x = val write(*,*) x end subroutine 

But I wonder if this is a compiler at all? Can I expect the above routine to do the same with any compiler in any architecture? In testing, I used gfortran for all the examples above.

+7
source share
1 answer

In the first example, I don’t know why you say that f2py does not accept double precision when test.test.r_dp is double precision. The numpy array, which shows a value with a decimal point and without an explicit dtype, is a double precision array.

The second example shows the restriction in processing F2PY type definitions using 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 happens, run f2py test.f90 -m test . I get the following:

 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 maps 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 these ads. This is explained in the f2py FAQ, and this is the approach suggested in the "getctype: ..." messages in the f2py output shown above.

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

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

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

Method 3

It also works to slightly modify the code:

 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 The routine argument is not passed correctly from Python to Fortran for a similar sentence.

+12
source

All Articles