f90wrap icon indicating copy to clipboard operation
f90wrap copied to clipboard

f90wrap always chooses single precision Fortran function from interface with single and double precision routines

Open mcuntz opened this issue 4 years ago • 2 comments

Dear James,

this really bugs me because it was a requirement here that all routines exist in a single and in a double precision version. The test code is:

module itestit

  implicit none

  private
  
  public :: testit

  interface testit
     module procedure testit_dp, testit_sp
  end interface testit

  integer, parameter :: sp = kind(1.0)
  integer, parameter :: dp = kind(1.0d0)
  
contains

  function testit_dp(x)

    implicit none

    real(dp), dimension(:), intent(in) :: x
    real(dp)                           :: testit_dp
    
    testit_dp = sum(2.0_dp * x)

  end function testit_dp

  function testit_sp(x)

    implicit none

    real(sp), dimension(:), intent(in) :: x
    real(sp)                           :: testit_sp
    
    testit_sp = sum(1.0_sp * x)

  end function testit_sp

end module itestit

Here, the single precision version sums the input numbers and the double precision version gives double the outcome. So the two calls in Python should give 45 and 90:

from __future__ import division, absolute_import, print_function
import numpy as np
import test

a = np.arange(10, dtype=np.float32)
print(test.itestit.testit(a))

a = np.arange(10, dtype=np.float64)
print(test.itestit.testit(a))

But it returns 45 in both cases. I was thinking that changing the order in the interface or in the file might change, which module procedure it takes, but it always returns 45, i.e. it takes the single precision version.

Kind regards Matthias

mcuntz avatar Mar 12 '20 23:03 mcuntz

You can choose the type mapping in the file kind_map. I am not quite sure if this will solve your question. You can check one of the examples.

zhucaoxiang avatar Jun 30 '20 12:06 zhucaoxiang

Dear Caoxiang,

thanks for the feedback. You are correct. I normally have always the following kind map: # file: kind_map { 'real': {'': 'float', '4': 'float', 'sp': 'float', '8': 'double', 'dp': 'double', '16': 'long_double', 'qp': 'long_double'}, 'complex' : {'': 'complex_float', '4': 'complex_float', 'sp': 'complex_float', 'spc': 'complex_float', '8': 'complex_double', 'dp': 'complex_double', 'dpc': 'complex_double', '16': 'complex_long_double', 'qp': 'complex_long_double', 'qpc': 'complex_long_double'}, 'integer' : {'': 'int', 'i1': 'signed_char', 'i2': 'short', '4': 'int', 'i4': 'int', '8': 'long_long', 'i8': 'long_long'}, }

I then wrap with: f90wrap -m itest -P -k kind_map main.f90 -v

This gives the file f90wrap_mai.f90: ` ! Module itestit defined in file main.f90

subroutine f90wrap_testit_dp(ret_testit_dp, x, n0) use itestit, only: testit implicit none

real(8), intent(out) :: ret_testit_dp
real(8), intent(in), dimension(n0) :: x
integer :: n0
!f2py intent(hide), depend(x) :: n0 = shape(x,0)
ret_testit_dp = testit(x=x)

end subroutine f90wrap_testit_dp

subroutine f90wrap_testit_sp(ret_testit_sp, x, n0) use itestit, only: testit implicit none

real(4), intent(out) :: ret_testit_sp
real(4), intent(in), dimension(n0) :: x
integer :: n0
!f2py intent(hide), depend(x) :: n0 = shape(x,0)
ret_testit_sp = testit(x=x)

end subroutine f90wrap_testit_sp

! End of module itestit defined in file main.f90 `

If I leave out the kind_map from the call to f90wrap, the numbers '8' in the function f90wrap_testit_dp are '4', which is wrong. Now the example gives 90 in case of 32 or 64 bit: ` a = np.arange(10, dtype=np.float32) print(itest.itestit.testit(a))

a = np.arange(10, dtype=np.float64) print(itest.itestit.testit(a)) ` That means it chooses the first routine of the interface no matter what.

I try to attach a very small zip file with the full example including the makefile.

Kind regards Matthias issue107_problem_choosing_the_right_precision.zip

mcuntz avatar Jun 30 '20 21:06 mcuntz