In Fortran werden numerische Berechnungen durchgeführt, und Diagramme und Analysen gelten für Personen, die Python genannt werden. Es wird angenommen, dass die Ausgabe der numerischen Berechnung eine Binärdatei ist. In Python wird außerdem angenommen, dass Numpy für die Analyse verwendet wird. In diesem Artikel werde ich zuerst das binäre Ausgabeformat von Fortran erläutern und dann beschreiben, wie es in Python gelesen wird.
Es gibt drei Arten von Fortran-Binärausgabeformaten: sequentiell (Auftragssuche), direkt (direkte Suche) und Stream. Schauen wir uns jeden an. Beachten Sie, dass sich die Binärausgabe hier auf form = "unformatiert" bezieht. Nicht form = "binär". (Ich weiß nicht viel über form = "binary")
Ein Format, das vom Anfang der Datei an schreibt. Jedes Mal, wenn Sie schreiben, wird am Anfang und am Ende der Ausgabe ein 4-Byte-Marker hinzugefügt (der 8 Byte betragen kann, wenn er alt ist). Die Anzahl der ausgegebenen Bytes wird am Anfang eingegeben. Es ist notwendig, von Anfang an zu lesen (obwohl es nicht unmöglich ist, mit Stream zu lesen, wenn Sie die Anzahl der Bytes angeben ...)
real(4) :: a=1,b=2
open(10,file="test.seq", form="unformatted", action="write",access="sequential")
write(10) a
write(10) b
Ausgabe durch Angabe der Datensatzlänge (Anzahl der Bytes; recl). Geben Sie bei der Ausgabe rec und die Ausgabeposition an. Daher ist es nicht immer notwendig, von Anfang an zu schreiben (obwohl es normalerweise von Anfang an ausgegeben wird). Es ist praktisch, dass Sie beim Lesen nicht von Anfang an lesen müssen. Im Fall des Intel-Compilers (ifort) beträgt der Standardwert von recl 4 Byte (wenn beispielsweise recl = 4 ist, werden 16 Byte ausgegeben). Es ist sicher, die Annahme von Byte-Recl in Byte-Einheiten als Option zu korrigieren.
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 Stream-Eingabe / Ausgabe wurde in Fortran 2003 und höher hinzugefügt. Ähnlich wie sequentiell, außer dass am Anfang und Ende der Datei keine Markierungen vorhanden sind.
open(10,file="test.stm", form="unformatted", action="write",access="stream")
write(10) a
write(10) b !Pos wird automatisch angegeben.
Die Ausgabeposition kann auch mit pos angegeben werden (Anzahl der Bytes). Wenn Sie bei der Eingabe pos angeben, muss nicht immer von Anfang an gelesen werden.
Es gibt große und kleine Endianer. Wenn nicht angegeben, wird die Standardeinstellung des Computers verwendet. Beides ist in Ordnung, aber es ist sicher, sie einheitlich zu verwenden, damit Sie sie verstehen können. Die zur Kompilierungszeit anzugebende Methode lautet wie folgt
$ gfortran -fconvert=big-endian test.f90
$ ifort -convert=big_endian -assume byterecl test.f90
Sie kann auch mit der open-Anweisung angegeben werden. Geben Sie mit convert an (wahrscheinlich in den meisten Compilern als Erweiterung festgelegt).
open(10, file="test.dat", form="unformatted", action="write, access="stream" , &
& convert="big_endian" )
Es kann mit der Standardbibliothek von Python gelesen werden. Lesen Sie die Binärdatei und konvertieren Sie sie mit np.frombuffer. Wenn Sie die folgende Klasse erstellen, können Sie sie für Fortran verarbeiten. Da es sich bei der Ausgabe um ein eindimensionales Array handelt, konvertieren Sie es bei Bedarf mit Umformung. Die Erklärung von dtype ist nur typisch. Für Details [https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html#] Und
Symbol | Bedeutung |
---|---|
> | Big Endian |
< | Kleiner Inder |
i4 | 4-Byte-Ganzzahl |
f4 | |
f8 |
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") #
f.rewind() #
Der direkte Zugriff ändert den Typ nicht und die Datensatzlänge ist konstant. Legen Sie ihn daher beim Erstellen einer Instanz fest.
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 beginnt bei 1(Fortran-artig)
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))
Sie können es auch mit numpy.fromfile lesen. Geben Sie die Anzahl der Bytes an, die mit dem Versatz mit dem Lesen beginnen sollen, und geben Sie die Anzahl der Elemente an, die mit dtype gelesen werden sollen.
import numpy as np
recl = 200
data = np.fromfile("test.dir",dtype=">"+str(recl)+"f4",count=1,offset=4*recl)[0]
stream
Sie können es mit seek und np.frombuffer lesen, die oben verwendet wurden. seek ist dasselbe wie pos, daher sollte jeder, der die Stream-Ausgabe in Fortran verwenden kann, dies sofort tun können.
Recommended Posts