2012-09-21 46 views
7

我正在玩f2py。我對numpy內在類型和fortran 90類型有點困惑。似乎我只能在fortran 90中使用單精度實數,與python進行交互時。讓我用一個例子:f2py:在與python接口時指定fortran中的真實精度?

說我有這個Fortran 90的模塊,test.f90,與f2py編譯和蟒蛇進口:

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.f90

然後,在python:

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

IOW,似乎f2py不接受雙精度。將輸入從python傳遞到Fortran 90子例程時,這會變得更加棘手。我說我的模塊擴展到:

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.f90

蟒蛇

>>> 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。

回答

12

在你的第一個例子,我不知道爲什麼你說的好像f2py不接受雙精度,當test.test.r_dp雙精度。顯示帶小數點的值並且沒有顯式dtype的numpy數組是雙精度數組。

第二個例子顯示了F2PY處理類型定義的侷限性,其中kind=<kind>。請參閱常見問題解答: http://cens.ioc.ee/projects/f2py2e/FAQ.html#q-what-if-fortran-90-code-uses-type-spec-kind-kind

要查看正在發生的情況,請運行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" 

。注意,既映射 「真正(KIND = SP)」 和 「真正的(KIND = DP)」 到C 「浮動」,這是單精度。

有幾種方法可以解決這個問題。

方法1名

更改類型聲明爲 「真正的(種= 4)」 和 「真實(種類= 8)」(或 「真實* 4」 和 「真實* 8」), 分別。

當然,這會破壞使用selected_real_kind的目的,對於某些編譯器, 4和8對於單精度和雙精度不是正確的KIND值。 在這種情況下,與gfortran,sp是4和dp是8,所以它的工作原理。

方法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 

了類似的建議見Subroutine argument not passed correctly from Python to Fortran

+0

感謝您的回答。我首先做了方法2,並且工作得很好。但後來我嘗試將它應用到我正在編寫的實際程序中,該程序使用distutils通過setup.py文件等進行編譯。然後我發現只有.f2py_cmap文件是不夠的,儘管它在構建過程中成功應用了來自.f2py_cmap的更改。所以我不得不使用方法3.實際上,我已經爲精度變量的定義使用了一個單獨的模塊,但是我在模塊的頂部使用了'use types'語句,而不是在各個子例程中。 – arne