14

私はf2pyで遊んでいます。numpyの組み込み型とFortran90型について少し混乱しています。Pythonと対話する場合、Fortran90では単精度実数しか使用できないようです。例を挙げて説明しましょう。

このFortran90モジュールtest.f90をf2pyでコンパイルし、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

そして私はこのようにコンパイルします:

f2py -c -m test test.f90

次に、Pythonで:

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

IOW、f2pyは倍精度を受け入れないようです。これは、PythonからFortran90サブルーチンに入力を渡すときにさらに問題になります。モジュールを次のように拡張するとします。

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

したがって、Pythonから送信される入力変数は、単精度で宣言する必要があるようです。これはf2pyの既知の問題ですか?

また、フォローアップの質問として:spからdpへの変換は、次の意味で機能します。

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

しかし、これはコンパイラ固有のものなのだろうか?上記のサブルーチンが、任意のアーキテクチャの任意のコンパイラで正しいことを実行することを期待できますか?テストするとき、私は上記のすべての例でgfortranを使用しました。

4

1 に答える 1

16

test.test.r_dp 最初の例では、f2pyが倍精度を受け入れないように見えると言う理由がわかりません。小数点を含む値を示し、明示的な dtype がない numpy 配列は、倍精度配列です。

2 番目の例は、F2PY による型定義の取り扱いの制限を示していkind=<kind>ます。FAQ を参照してください: https://numpy.org/doc/stable/f2py/advanced.html#dealing-with-kind-specifiers

何が起こっているかを確認するには、 を実行しf2py test.f90 -m testます。私はこれを得る:

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"

「real(kind=sp)」と「real(kind=dp)」の両方を単精度の C の「float」にマッピングしていることに注意してください。

これを修正するにはいくつかの方法があります。

方法 1

型宣言をそれぞれ「real(kind=4)」と「real(kind=8)」(または「real 4」と「real 8」) に変更します。

もちろん、これは を使用する目的にselected_real_kind反します。一部のコンパイラでは、4 と 8 は単精度と倍精度の正しい KIND 値ではありません。この場合、gfortran ではsp4 でdp8 であるため、機能します。

方法 2

これらの宣言の処理方法を f2py に伝えます。これは f2py FAQ で説明されており、上記の f2py の出力の「getctype: ...」メッセージで提案されているアプローチです。

この場合、次.f2py_f2cmapの行を含む (f2py を実行しているディレクトリに) という名前のファイルを作成します。

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

そうすれば、f2py はそれらreal(sp)real(dp)宣言で正しいことを行います。

方法 3

また、コードを少し再配置することもできます。

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

同様の提案については、サブルーチン引数が Python から Fortran に正しく渡されないを参照してください。

于 2012-09-21T04:46:45.847 に答える