Les calculs numériques sont effectués dans Fortran, et les diagrammes et analyses sont destinés aux personnes appelées python. On suppose que la sortie du calcul numérique est un fichier binaire. De plus, en python, on suppose que numpy est utilisé pour l'analyse. Dans cet article, je vais d'abord expliquer le format de sortie binaire de Fortran, puis décrire comment le lire en python.
Il existe trois types de formats de sortie binaires Fortran: séquentiel (recherche d'ordre), direct (recherche directe) et flux. Regardons chacun. Notez que la sortie binaire fait ici référence à form = "non formaté". Pas de forme = "binaire". (Je ne connais pas grand chose à form = "binary")
Un format qui écrit depuis le début du fichier. Chaque fois que vous écrivez, un marqueur de 4 octets (qui peut être de 8 octets s'il est ancien) est ajouté au début et à la fin de la sortie. Le nombre d'octets de sortie est entré au début. Il est nécessaire de lire depuis le début (même s'il n'est pas impossible de lire avec stream si vous spécifiez le nombre d'octets ...)
real(4) :: a=1,b=2
open(10,file="test.seq", form="unformatted", action="write",access="sequential")
write(10) a
write(10) b
Sortie en spécifiant la longueur de l'enregistrement (nombre d'octets; recl). Lors de la sortie, spécifiez rec et spécifiez la position de sortie. Par conséquent, il n'est pas toujours nécessaire d'écrire depuis le début (bien qu'il soit généralement généré depuis le début). Il est pratique de ne pas avoir à lire depuis le début lors de la lecture. Dans le cas du compilateur d'Intel (ifort), la valeur par défaut de recl est de 4 octets (par exemple, si recl = 4, 16 octets sont générés). Il est prudent de corriger -assume byte recl en unités d'octets en option.
real(4) :: a=1,b=2
open(10,file="test.dir", form="unformatted", action="write",access="direct",recl=4)
write(10,rec=1) a
write(10,rec=2) b
stream L'entrée / sortie de flux a été ajoutée dans Fortran 2003 et versions ultérieures. Similaire à séquentiel, sauf qu'il n'y a pas de marqueurs au début et à la fin du fichier.
open(10,file="test.stm", form="unformatted", action="write",access="stream")
write(10) a
write(10) b !Pos est automatiquement spécifié.
La position de sortie peut également être spécifiée (nombre d'octets) à l'aide de pos. Si vous spécifiez pos lors de la saisie, il n'est pas toujours nécessaire de lire depuis le début.
Il y a des big endians et des petits endians. S'il n'est pas spécifié, la valeur par défaut de la machine sera utilisée. L'un ou l'autre convient, mais il est prudent de les utiliser de manière unifiée afin que vous puissiez les comprendre. La méthode à spécifier au moment de la compilation est la suivante
$ gfortran -fconvert=big-endian test.f90
$ ifort -convert=big_endian -assume byterecl test.f90
Il peut également être spécifié avec l'instruction open. Spécifiez avec convert (probablement défini comme une extension dans la plupart des compilateurs).
open(10, file="test.dat", form="unformatted", action="write, access="stream" , &
& convert="big_endian" )
Il peut être lu avec la bibliothèque standard de python. Lisez le binaire et convertissez-le avec np.frombuffer. Si vous créez la classe suivante, vous pouvez la gérer pour Fortran. Puisque la sortie est un tableau unidimensionnel, convertissez-le avec un remodelage si nécessaire. L'explication de dtype n'est que typique. Pour plus de détails [https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html#] Et
symbole | sens |
---|---|
> | Big endian |
< | Petit indien |
i4 | Entier de 4 octets |
f4 | Fraction flottante de 4 octets |
f8 | Fraction flottante de 8 octets |
Exemples ci-dessous. Je vais lire un exemple de lecture d'un nombre réel de 4 octets avec 200 éléments.
import numpy as np
import struct
class seq_read :
def __init__(self,filename, endian=">") :
self.f = open(filename, "rb")
self.endian = endian
def read(self, dtype) :
num, = struct.unpack(self.endian+"i",self.f.read(4))
data = np.frombuffer(self.f.read(num), dtype )
num, = struct.unpack(self.endian+"i",self.f.read(4))
return data
def rewind(self) :
self.f.seek(0)
def __del__(self) :
self.f.close()
### example ###
f = seq_read("test.seq", endian=">" )
data = f.read(">i") #entier de 4 octets big endian
f.rewind() #Vers le haut du fichier
L'accès direct ne modifie pas le type et la longueur de l'enregistrement est constante, définissez-la lors de la création d'une instance.
import numpy as np
import struct
class dir_read :
def __init__(self, filename, recl, dtype) :
self.f = open(filename, "rb")
self.recl = recl
self.dtype = dtype
def read(self, rec) : #rec commence à partir de 1(À la Fortran)
self.f.seek((rec-1)*self.recl)
data = np.frombuffer(self.f.read(self.recl), self.dtype)
return data
def __del__(self) :
self.f.close()
### example ###
f2 = dir_read("test.dir",4*200,">f")
print(f2.read(2))
Vous pouvez également le lire en utilisant numpy.fromfile. Spécifiez le nombre d'octets à lire avec offset et spécifiez le nombre d'éléments à lire avec dtype.
import numpy as np
recl = 200
data = np.fromfile("test.dir",dtype=">"+str(recl)+"f4",count=1,offset=4*recl)[0]
stream
Vous pouvez le lire avec seek et np.frombuffer utilisés ci-dessus. seek est le même que pos, donc quiconque peut utiliser la sortie de flux dans Fortran devrait pouvoir le faire tout de suite.
Recommended Posts