f2py – usare codice Fortran in Python

jakeTutto è partito da qui: Numba vs. Cython: Take 2.

Jake VanderPlas è un tipo tosto, fareste bene a seguirlo. Si presenta così: “I’m an NSF post-doctoral fellow at University of Washington, where I research and teach in Astronomy, Astrophysics, and Machine Learning“.

Jake accenna a f2py. Ehi! potrebbe essere utile a chi ha vecchia roba scritta in Fortran, magari si riesce a metterle un’interfaccia grafica o fare altre mescite di quelle che, fa … beh! Chissà, vediamo.

Intanto salta fuori che f2py è un programma a se stante che compila il codice Fortran (usando il compilatore che hai, dev’essercene uno) creando una libreria (.so), quelle che Python chiama moduli.
Ma è anche un modulo di NumPy, cioè Python. Ed è tutto scritto in Python.
Allora la prima cosa da fare (è da tanto che mi dicevo di farlo) è installare NumPy: f2py è lì. Installare NumPy richiede 952MB di spazio su disco! OK, c’è tempo per un caffè lungo.

Fatto, viene installato anche SciPy, ne ho già parlato in passato. Per vedere comincio a riprodurre l’esempio preso dalla documentazione, questa è la subroutine in Fortan 77:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
C FILE: FIB1.F
      SUBROUTINE FIB(A,N)
C
C     CALCULATE FIRST N FIBONACCI NUMBERS
C
      INTEGER N
      REAL*8 A(N)
      DO I=1,N
         IF (I.EQ.1) THEN
            A(I) = 0.0D0
         ELSEIF (I.EQ.2) THEN
            A(I) = 1.0D0
         ELSE 
            A(I) = A(I-1) + A(I-2)
         ENDIF
      ENDDO
      END
C END FILE FIB1.F

Si crea il modulo Python con il comando:

f2py -c fib1.f -m fib1

e questo è il file di Python:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import numpy as np
import fib1 #quello in Fortran

a = np.zeros(10, 'd')
fib1.fib(a)
print a

f1

OK, vediamo se si può migliorare: Fibonacci restituisce interi, anzi ai tempi di Leonardo Pisano (Fibonacci per i matematti) i float non erano conosciuti. E meno che mai in doppia precisione (come si dice in Fortran).

Le modifiche sono minime:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
C FILE: FIB2.F
      SUBROUTINE FIB(A,N)
C
C     CALCULATE FIRST N FIBONACCI NUMBERS
C versione modificata, uso interi
      INTEGER N
      INTEGER A(N)
      DO I=1,N
         IF (I.EQ.1) THEN
            A(I) = 0.0D0
         ELSEIF (I.EQ.2) THEN
            A(I) = 1.0D0
         ELSE 
            A(I) = A(I-1) + A(I-2)
         ENDIF
      ENDDO
      END
C END FILE FIB2.F

che compilo con

f2-0

f2py riempie il terminale di scritte, roba da preoccuparsi se uno non sapesse che è normale. Ecco lo script Python

#!/usr/bin/python
# -*- coding: utf-8 -*-

#modificato, uso interi

import numpy as np
import fib2 #quello in Fortran

a = np.zeros(10, 'int')
fib2.fib(a)
print a

f2-1

OK. Vediamo qualche caso tipico, non quelli presenti nei tutorial, ma quelli che so che possono capitare, per esempio un “Hello World!” poco funzionale, chissà se funziona.

1
2
3
4
5
      subroutine hw
c scrive il classico saluto

      print *, "Hello World!"
      end

Ho dovuto usare la sintassi vecchia, quella fixed-form, in attesa di leggere il manuale. Ma un passo per volta.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import hw
print "Adesso chiamo il Fortran"
hw.hw()
print "Fatto, OK?"

hw

OK. La pessima abitudine dei programmatori di una volta era di scrivere su file quando capita (visto che mi sto funzionalizzando?), vediamo:

1
2
3
4
5
6
7
8
      subroutine hw2
c scrive il classico saluto

      print *, "Hello World!"
      open(1, file = "prova-f2py.txt")
      write(1, '("Hello World!")')
      close(1)
      end

Per sicurezza ho controllato che con un main in Fortran funzionasse, non si sa mai… È OK.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import hw2
print "Adesso chiamo il Fortran"
hw2.hw2()
print "Fatto, OK?"

hw2

OK, continua a funzionare. E se uno ha una subroutine che ne chiama un’altra in un altro file cosa succede?

1
2
3
4
      subroutine hw3

      call hw2  
      end

La hw2 è la stessa del caso precedente. Il comando per f2py è:

f2py -c hw3.f hw2.f -m hw3

e poi:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import hw3
print "Adesso chiamo il Fortran"
hw2.hw2()
print "Fatto, OK?"

hw3

Chissà se posso passare una stringa al Fortran?

1
2
3
4
5
6
      integer function fs(st)
      character*(*) st

      print *, st
      fs = len(st)
      end
#!/usr/bin/python
# -*- coding: utf-8 -*-

import fs

msg = "f2py rockz!"
print "Adesso chiamo il Fortran"
res = fs.fs(msg)
print res
print "Fatto, OK?"

fs

OK! Un’ultima cosa, poi mi leggo tutto il manuale ma per intanto il free-form, non so se non si possa semplificare, questo è quello che sono riuscito a ottenere finora:

1
2
3
4
5
6
7
8
9
module fhw
  integer i
contains
  subroutine hw
    ! scrive il classico saluto

    print *, "Hello World!"
  end subroutine hw
end module fhw
#!/usr/bin/python
# -*- coding: utf-8 -*-

import hw
print "Adesso chiamo il Fortran"
hw.hw()
print "Fatto, OK?"

hw

No! è solo questione di mettere l’estensione .f90 e funziona tutto:

1
2
3
4
5
subroutine hw
! scrive il classico saluto

print *, "Hello World!"
end subroutine hw
#!/usr/bin/python
# -*- coding: utf-8 -*-

import hw
print "Adesso chiamo il Fortran"
hw.hw()
print "Fatto, OK?"

L’output è uguale al precedente.

Quasi dimenticavo:
NumPy è opera di Travis E. Oliphant, con il cotributo di numerosi collaboratori, vedi Origins of NumPy in Guide to NumPy.
f2py è stato scritto da Pearu Peterson.

Bellissima (anche se l’ho solo scorsa per adesso) la Guide to Numpy, se si ha fretta c’è anche An introduction to Numpy and Scipy. E poi c’è il Cookbook, il sito di SciPy dove ci sono ovviamente NumPy e f2py.

Quindi, conclusione provvisoria: si può usare? Forse, dipende. Leggo il manuale e vi dico.
Prossimamente… forse… 😉

Posta un commento o usa questo indirizzo per il trackback.

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: