2016-05-06 6 views
1

Ich habe eine Binärdatei, die ich in Python lesen möchte. Die Datei besteht aus drei Teilen: einer Liste von Wellenzahlen, einer Liste von Temperaturen und einer Liste von Trübungen als Funktion von Temperatur und Druck. Ich möchte die ersten zwei davon als Vektoren a und b und die dritte als 2D-Array c so importieren, dass c [x, y] a [x] und b [y] entspricht.Lesen von Daten von FORTRAN90-Datei generiert in NUMPY-Array

Ein bestehender FORTRAN90 Code ist in der Lage, dies zu erreichen, wie folgt:

integer nS, nT 
parameter (nS = 3000) 
parameter (nT = 9) 

real(8) wn_arr(nS)  ! wavenumber [cm^-1] 
real(8) temp_arr(nT) ! temperature [K] 
real(8) abs_arr(nS,nT) ! absorption coefficient [cm^-1/amagat^2] 

open(33,file=trim(datadir)//'CO2_dimer_data',form='unformatted') 
read(33) wn_arr 
read(33) temp_arr 
read(33) abs_arr 
close(33) 

ich folgenden Python-Code versucht:

f=scipy.io.FortranFile('file', 'r') 
a_ref=f.read_reals(np.float64) #wavenumber (cm**-1) 
b=f.read_reals(np.float64) #temperature (K) 
c=f.read_reals(np.float64).reshape((3000,9)) 

Dies ist jedoch erzeugt Ergebnisse, die nicht korrekt sind. Ich vermute, das liegt daran, dass Fortran Arrays in einer anderen Reihenfolge in die Datei schreibt als Python. Das einfache Hinzufügen von order = 'F' zum Umformbefehl funktioniert jedoch nicht. Ich vermute, das ist so, weil abscoeff_ref beim Einlesen bereits abgeflacht ist.

Irgendwelche Gedanken?

+2

Fortran unformatierte Dateien sind ein tragbarer Albtraum. Im Allgemeinen können Sie nur erwarten, dass sie funktionieren, wenn Sie mit demselben Compiler auf derselben Hardware lesen/schreiben (da die Record-Begrenzer nicht standardisiert sind). Es sieht so aus, als ob "scipy.io.FortanFile" davon ausgeht, dass die Datensätze mit 'gfortran' auf einer' x86_64' Architektur geschrieben wurden. Ist das der Compiler/Architektur, die Sie verwenden? – mgilson

+0

Die Antwort hängt davon ab, wie oft Sie diese Datei lesen müssen und wie tragbar das ganze System sein soll.Ihr größtes Problem ist, wie mgilson bereits gesagt hat, dass die Datei in einem unformatierten SEQUENTIAL-Format vorliegt, das nicht nur die Daten, sondern auch eine Anfangs- und Endaufzeichnung um jeden Datensatz speichert (= etwa jede geschriebene Variable), die Größe davon ist Compiler abhängig. Wenn Sie nur die Datei lesen und sich nicht um die Portabilität kümmern möchten, versuchen Sie, den Parsing-Code selbst zu schreiben. Ich habe keine Erfahrung mit der scipy.io.FortranFile-Methode, aber ihre Optionen scheinen begrenzt und wenn es nicht funktioniert ... – StefanS

+0

Ohne die Datei ist es schwer, Ihnen mit Code zu helfen, aber ich habe unformatiert gelesen (direkter Zugriff, nicht sequentiell) Fortran-Dateien mit numpy.fromfile. Sie müssen die file.seek() -Methode verwenden, um die Marker für Anfangs- und Endaufzeichnung zu überspringen und mit ihrer Größe zu spielen, bis Sie die richtige getroffen haben (verwenden Sie 4 oder 1 Byte zum Starten, diese sollten die gebräuchlichsten sein) Einsen). – StefanS

Antwort

2

Ihnen eine Vorstellung davon zu geben, was ich in meiner zweiten Bemerkung gemeint, machte ich eine Mock-up:

testwrite.f90, mit gfortran zusammengestellt 4.8.4: Es schreibt grundsätzlich eine unformatierte, sequentielle Datei mit dem Arrays Sie haben angegeben (nur viel kleiner, um sie mit dem Auge vergleichen zu können), gefüllt mit beliebigen Daten. Es druckt auch die Arrays.

implicit none 
integer nS, nT, i ,j 
parameter (nS = 10) 
parameter (nT = 3) 

real(8) wn_arr(nS)  ! wavenumber [cm^-1] 
real(8) temp_arr(nT) ! temperature [K] 
real(8) abs_arr(nS,nT) ! absorption coefficient [cm^-1/amagat^2] 

wn_arr = (/ (i, i=1,nS) /) 
temp_arr = (/ (270+i, i=1,nT) /) 
abs_arr = reshape((/ ((10*j+i, i=1,nS), j=1,nT) /), (/nS, nT/)) 

print*, wn_arr 
print*, '-----------------' 
print*, temp_arr 
print*, '-----------------' 
print*, abs_arr 
print*, '-----------------' 
print*, 'abs_arr(5,3) = ', abs_arr(5,3) 

open(33,file='test.out',form='unformatted') 
write(33) wn_arr 
write(33) temp_arr 
write(33) abs_arr 
close(33) 

end 

testread.py, getestet mit Python 2.7.6, liest dann die oben geschriebene Datei und druckt auch die Arrays. Für mich ist die Ausgabe beider Programme gleich. YMMV.

import numpy as np 

rec_delim = 4 # This value depends on the Fortran compiler 
nS = 10 
nT = 3 

with open('test.out', 'rb') as infile: 
    infile.seek(rec_delim, 1) # begin record 
    wn_arr = np.fromfile(file=infile, dtype=np.float64, count=nS) 
    infile.seek(rec_delim, 1) # end record 
    infile.seek(rec_delim, 1) # begin record 
    temp_arr = np.fromfile(file=infile, dtype=np.float64, count=nT) 
    infile.seek(rec_delim, 1) # end record 
    infile.seek(rec_delim, 1) # begin record 
    abs_arr = np.fromfile(file=infile, 
         dtype=np.float64).reshape((nS, nT), order='F') 
    infile.seek(rec_delim, 1) # end record 

print(wn_arr) 
print(temp_arr) 
print(abs_arr) 
# The array has the same shape, but Fortran starts index (per default at least) 
# at 1 and Python at 0: 
print('abs_arr(5,3) = ' + str(abs_arr[4,2])) 

Kurze Erklärung: Ich öffne die Datei in einer mit Block (guten Praxis in Python) und dann trete ich durch die Datei, mit dem Wissen, wie die Datei geschrieben wird. Dies macht es unportabel. infile.seek (4, 1) verschiebt den Lesezeiger von Python um 4 Bytes von der aktuellen Position (die Option 1), weil ich weiß, dass die Datei mit einem 4 Zeichen langen Marker beginnt (gfortran) .

Dann benutze ich numpy.fromfile, um count = 10 Werte von float64 zu lesen, welches das Wellenzahl-Array ist.

Als nächstes muss ich die End-Aufzeichnung überspringen und Marker starten. Dies könnte natürlich auch von infile.seel (8, 1) übernommen werden.

Dann lese ich das Temperatur-Array, überspringe End-Record und beginne die Marker erneut und lese das 2D-Array. Die Daten in der Datei wissen nicht, dass es 2D ist, also muss ich es umformen, indem ich die Fortran-Reihenfolge verwende. Die letzte .seek() ist falsch, ich wollte nur die Struktur hervorheben.

Ich wiederhole dringend, dass Sie kein größeres System auf Code wie diesem bauen. Es ist in Ordnung für eine einmalige, aber schrecklich für etwas, das Sie wieder verwenden oder teilen müssen.

+0

Danke, das scheint sehr hilfreich zu sein! Wird versuchen zu implementieren. –