2012-09-21 6 views
7

Ich spiele mit f2py herum. Ich bin etwas verwirrt über numpige intrinsische Typen vs. Fortran 90 Typen. Es scheint, als ob ich in Fortran 90 nur Einzelpräzisions-Reale verwenden kann, wenn ich mit Python interagiere. Lassen Sie mich mit einem Beispiel illustrieren:f2py: Spezifizieren Sie echte Genauigkeit in Fortran, wenn Sie mit Python interagieren?

Sagen, ich habe dieses Fortran 90-Modul, test.f90, mit f2py und importiert in Python erstellt werden:

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 

und ich kompilieren wie folgt aus:

f2py -c -m Test test.f90

Dann in python:

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

IOW, Es scheint, als ob f2py keine doppelte Genauigkeit akzeptiert. Dies wird noch problematischer, wenn die Eingabe von python an eine Fortran 90-Subroutine übergeben wird. Sagen, dass ich mein Modul zu erweitern:

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 scheint es, wie jeder Die von python zu sendende Eingabevariable muss als einfache Genauigkeit deklariert werden. Ist das ein bekanntes Problem mit f2py?

Auch als Follow-up-Frage: von sp Converting Werke dp, im folgenden Sinn:

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

Aber ich frage mich, ob dieser Compiler überhaupt spezifisch ist? Kann ich erwarten, dass die obige Subroutine mit jedem Compiler in jeder Architektur das Richtige tut? Beim Testen verwendete ich Gfortran für alle obigen Beispiele.

Antwort

12

In Ihrem ersten Beispiel, ich weiß nicht, warum Sie sagen, es scheint, als ob f2py nicht mit doppelter Genauigkeit nicht akzeptiert, wenn test.test.r_dp doppelte Genauigkeit ist. Ein numpiges Array, das einen Wert mit einem Dezimalpunkt und keinen expliziten dtype anzeigt, ist ein Array mit doppelter Genauigkeit.

Das zweite Beispiel zeigt eine Einschränkung in der Handhabung von Typdefinitionen durch F2PY mit . Siehe FAQ: http://cens.ioc.ee/projects/f2py2e/FAQ.html#q-what-if-fortran-90-code-uses-type-spec-kind-kind

Um zu sehen, was geschieht, laufen f2py test.f90 -m test. Ich bekomme diese:

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" 

Beachten Sie, dass es ist die Abbildung sowohl "real (Art = sp)" und "real (Art = dp)" C "float", die mit einfacher Genauigkeit ist.

Es gibt mehrere Möglichkeiten, dies zu beheben.

Methode 1

Ändern der Typdeklarationen in "real (Art = 4)" und "real (Art = 8)" (oder "real * 4" und "real * 8"), beziehungsweise.

Natürlich vereitelt dies den Zweck der Verwendung selected_real_kind, und für einige Compiler, 4 und 8 sind nicht die richtigen KIND-Werte für einfache und doppelte Genauigkeit. In diesem Fall, mit Gfortran, sp ist 4 und ist 8, so dass es funktioniert.

Methode 2

Sagen f2py, wie diese Erklärungen zu behandeln. Dies wird in der FAQ-FAQ erklärt, und es ist der Ansatz vorgeschlagen in den "Getctype: ..." Nachrichten in der Ausgabe von f2py oben gezeigt.

In diesem Fall würden Sie eine Datei .f2py_f2cmap (in dem Verzeichnis, in dem Sie f2py ausgeführt werden) genannt erstellen, die enthält die Zeile

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

Dann tun f2py das Richtige mit diesen real(sp) und real(dp) Erklärungen.

Methode 3

Es funktioniert auch Ihren Code ein wenig neu zu ordnen:

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 

Siehe Subroutine argument not passed correctly from Python to Fortran für einen ähnlichen Vorschlag.

+0

Danke für Ihre Antwort. Ich habe zuerst Methode 2, und das hat gut funktioniert. Aber dann habe ich versucht, dies auf das eigentliche Programm anzuwenden, das ich schreibe, das disttitils verwendet, um die Kompilierung über eine setup.py-Datei und so weiter zu machen. Ich fand dann heraus, dass es nicht genug war, nur eine .f2py_cmap-Datei zu haben, obwohl es aussprach, dass während des Builds Änderungen von .f2py_cmap erfolgreich angewendet wurden. Also musste ich Methode 3 verwenden. Eigentlich verwendete ich bereits ein separates Modul für die Definitionen von Präzisionsvariablen, aber ich hatte die Anweisung "use types" am oberen Ende des Moduls, das es verwendete, nicht innerhalb der einzelnen Unterprogramme. – arne