2012-09-21 8 views
7

Sto giocando con f2py. Sono un po 'confuso riguardo i tipi intrinseci di Numpy e quelli di Fortran 90. Sembra che io possa usare solo reals a precisione singola in fortran 90, quando si interagisce con Python. Permettetemi di illustrare con un esempio:f2py: specificare la precisione reale in fortran quando si interfaccia con python?

Dire che ho questo Fortran 90 modulo, test.f90, per essere compilato con f2py e importati in 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 

e compilare in questo modo:

f2py -c -m prova test.f90

Poi, in pitone:

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

IOW, sembra che f2py non accetti la doppia precisione. Ciò diventa ancora più problematico quando si passa l'input a una subroutine di fortran 90 da python. Di 'Estendo il mio modulo:

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

pitone

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

Così, sembra come qualsiasi la variabile di input da inviare da python deve essere dichiarata a precisione singola. Si tratta di un problema noto con f2py?

Inoltre, come un follow-up domanda: Conversione da sp DP opere, nel senso seguente:

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

Ma mi chiedo se questo è specifica del compilatore a tutti? Posso aspettarmi che la suddetta subroutine faccia la cosa giusta con qualsiasi compilatore su qualsiasi architettura? Durante il test, ho usato gfortran per tutti gli esempi precedenti.

risposta

12

Nel tuo primo esempio, non so perché dici che sembra che f2py non accetti la doppia precisione, quando test.test.r_dpè doppia precisione. Una matrice numpy che mostra un valore con un punto decimale e nessun dtype esplicito è un array a doppia precisione.

Il secondo esempio mostra una limitazione nella gestione di F2PY delle definizioni di tipo con kind=<kind>. Vedere le domande frequenti: http://cens.ioc.ee/projects/f2py2e/FAQ.html#q-what-if-fortran-90-code-uses-type-spec-kind-kind

Per vedere cosa sta succedendo, eseguire f2py test.f90 -m test. Ottengo questo:

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" 

Si noti che è la mappatura sia "reale (tipo = sp)" e "reale (tipo = dp)" a C "galleggiare", che è precisione singola.

Ci sono diversi modi per risolvere questo problema.

dichiarazioni Metodo 1

cambiare il tipo di "real (tipo = 4)" e "reale (tipo = 8)" (o "real * 4" e "real * 8"), rispettivamente.

Naturalmente, questo sconfigge lo scopo di utilizzare selected_real_kind, e per alcuni compilatori, 4 e 8 non sono i valori corretti per GENERE singola e doppia precisione. In questo caso, con gfortran, sp è 4 e dp è 8, quindi funziona.

Metodo 2

Dì f2py come gestire tali dichiarazioni. Questo è spiegato nelle FAQ di f2py ed è l'approccio suggerito nei messaggi "getctype: ..." nell'output di f2py mostrato sopra.

In questo caso, è necessario creare un file chiamato .f2py_f2cmap (nella directory in cui si esegue f2py) che contiene la linea di

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

Poi f2py farà la cosa giusta con quegli real(sp) e real(dp) dichiarazioni.

Metodo 3

funziona anche per riorganizzare il codice un po ':

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 

Vedi Subroutine argument not passed correctly from Python to Fortran un suggerimento simile.

+0

Grazie per la tua risposta. Ho fatto prima il metodo 2, e questo ha funzionato bene. Ma poi ho provato ad applicarlo al programma vero e proprio che sto scrivendo, che usa le distutils per fare la compilazione tramite un file setup.py e così via. Ho poi scoperto che il solo fatto di avere un file .f2py_cmap non era sufficiente, anche se sputa che ha applicato correttamente le modifiche da .f2py_cmap durante la compilazione. Quindi ho dovuto usare il metodo 3. In realtà, stavo già usando un modulo separato per le definizioni delle variabili di precisione, ma avevo l'istruzione 'use types' nella parte superiore del modulo che lo utilizzava, non all'interno delle singole subroutine. – arne

Problemi correlati