Best Practices beim Lesen und Arbeiten mit Fortran geordneten Arrays mit numpy

8

Ich lese ascii und binäre Dateien, die alle dreidimensionale Arrays in Fortran-Reihenfolge angeben. Ich möchte einige willkürliche Manipulationen an diesen Arrays durchführen und sie dann in das gleiche ASCII- oder Binärformat exportieren.

Ich bin verwirrt über die besten Möglichkeiten, mit diesen Arrays in meiner Bibliothek umzugehen. Mein derzeitiges Design scheint fehleranfällig zu sein, da ich die Dinge von der Standard-C-Reihenfolge neu gestalten muss, wenn ein neues Array erstellt wird.

Aktuelles Design:

Ich habe ein paar Funktionen, die diese Dateien lesen und numpy Arrays zurückgeben. Die Lesefunktionen verhalten sich alle ähnlich und lesen im Wesentlichen die Daten ein und geben etwas zurück:

return array.reshape((i, j, k), order='F')

So wie ich es verstehe, gebe ich eine Ansicht für die Fortran-Reihenfolge auf das ursprüngliche Array zurück.

Mein Code geht davon aus, dass alle Arrays in der gleichen Reihenfolge sind. Dies bedeutet, dass neue Operationen, die ein neues Array erstellen könnten, dafür sorgen, dass reshape verwendet wird, um es in die Fortran-Reihenfolge zurück zu konvertieren.

Dies scheint sehr fehleranfällig zu sein, da ich jede Operation, die ein neues Array erstellt, genau beobachten muss und sicherstellen muss, dass es in eine Fortran-Reihenfolge umgeformt wird, da der Standard normalerweise C-Reihenfolge ist.

Ich muss später vielleicht diese Arrays wieder in Binär- oder ASCII-Dateien exportieren und muss die Fortran-Reihenfolge beibehalten. Also verwende ich numpy.nditer , um jedes Element in der Fortran-Reihenfolge zu schreiben.

Bedenken:

  • Der derzeitige Ansatz scheint sehr fehleranfällig zu sein, da ich typischerweise in C-Reihenfolge denke. Ich habe Angst, dass ich immer gebissen werde, wenn ich Aufrufe von reshape vergesse, die Dinge in C-Reihenfolge erzwingen.

    • Ich möchte mich nicht um die Anordnung der Array-Elemente kümmern müssen, außer beim Lesen der Eingabedateien oder beim Schreiben der Daten in die Ausgabedateien.
  • Der aktuelle Ansatz scheint unordentlich zu sein, weil die Indizes unterschiedlich interpretiert werden können und die Dinge verwirrend werden können.

    • Beim Umgang mit Fortran-Arrays ist die Reihenfolge der Tupel für Indizes rückwärts, richtig?
    • Also bedeutet x[(1, 2, 3)] für ein Fortran-Array k = 1, j = 2 und i = 3, während x[(1, 2, 3)] für ein Array mit C-Ordnung bedeutet k = 3, j = 2, i = 1 richtig?
    • Das bedeutet, dass ich und die Benutzer meiner Bibliothek immer an Indizes in (k, j, i) Reihenfolge denken müssen, nicht an das, was wir C / Python-Programmierer normalerweise denken (i, j, k).

Frage:

Gibt es eine Best Practice für solche Dinge? In einer idealen Welt würde ich gerne die Fortran-geordneten Arrays lesen und dann die Bestellung vergessen, bis ich in eine Datei exportiert habe. Ich fürchte jedoch, dass ich die Indizes usw. falsch interpretiere.

Ich habe die einzige Dokumentation gelesen, die ich finden kann, Ссылка . Das Konzept erscheint mir jedoch immer noch so klar wie Schlamm. Vielleicht brauche ich nur eine andere Erklärung für die nackten Dokumente, Ссылка .

    
durden2.0 13.03.2014, 17:03
quelle

1 Antwort

12
___ tag123python ___ Python ist eine dynamische und stark typisierte Programmiersprache, die die Usability betont. Zwei ähnliche, aber größtenteils inkompatible Versionen von Python sind weit verbreitet (2 und 3). Wenn Sie eine versionsspezifische Python-Frage haben, sollten Sie die Tags [python-2.7] oder [python-3.x] zusätzlich zum Tag [python] verwenden. Wenn Sie eine Python-Variante wie jython, pypy, iron-python usw. verwenden, kennzeichnen Sie diese bitte entsprechend. ___ qstnhdr ___ Best Practices beim Lesen und Arbeiten mit Fortran geordneten Arrays mit numpy ___ antwort22406034 ___

Numpy abstrahiert den Unterschied zwischen Fortran-Ordnung und C-Ordnung auf der Python-Ebene. (Tatsächlich können Sie sogar andere Ordnungen für & gt; 2d-Arrays mit numpy haben. Sie werden alle auf der Python-Ebene gleich behandelt.)

Das einzige Mal, wenn Sie sich über die C-zu-F-Sortierung Gedanken machen müssen, ist das Lesen / Schreiben auf die Festplatte oder das Übergeben des Arrays an Funktionen auf niedrigerer Ebene.

Ein einfaches Beispiel

Lassen Sie uns als Beispiel ein einfaches 3D-Array in C-Reihenfolge und Fortran-Reihenfolge erstellen:

%Vor%

Beachten Sie, dass beide identisch aussehen (sie sind auf der Ebene, mit der wir interagieren). Wie können Sie feststellen, dass sie in verschiedenen Ordnungen sind? Werfen wir zuerst einen Blick auf die Flaggen (achten Sie auf C_CONTIGUOUS vs F_CONTIGUOUS ):

%Vor%

Und wenn Sie den Flags nicht vertrauen, können Sie die Speicherreihenfolge effektiv anzeigen, indem Sie arr.ravel(order='K') betrachten. Die order='K' ist wichtig. Andernfalls wird beim Aufruf von arr.ravel() unabhängig vom Speicherlayout des Arrays die Ausgabe in C-Reihenfolge angezeigt. order='K' verwendet das Speicherlayout.

%Vor%

Die Differenz wird tatsächlich in strides des Arrays dargestellt (und gespeichert). Beachten Sie, dass c_order 's strides (72, 24, 8) sind, während f_order ' s strides (8, 24, 72) sind.

Nur um zu beweisen, dass die Indexierung genauso funktioniert:

%Vor%

Lesen und Schreiben

Der Hauptort, an dem Sie Probleme damit bekommen, ist, wenn Sie von der Festplatte lesen oder auf die Festplatte schreiben. Viele Dateiformate erwarten eine bestimmte Reihenfolge. Ich vermute, dass Sie mit seismischen Datenformaten arbeiten, und die meisten von ihnen (z. B. Geoprobe .vol, und ich denke Petrels Volumenformat) schreiben im Wesentlichen einen binären Header und dann ein Fortran-geordnetes 3D-Array auf die Festplatte / p>

In diesem Sinne benutze ich als Beispiel einen kleinen seismischen Würfel (Auszug einiger Daten aus meiner Dissertation).

Bei beiden handelt es sich um binäre Arrays von uint8 s mit einer Form von 50x100x198. Einer ist in C-Reihenfolge, während der andere in Fortran-Reihenfolge ist. c_order.dat f_order.dat

Um sie zu lesen:

%Vor%

Beachten Sie, dass der einzige Unterschied darin besteht, das Speicherlayout für reshape anzugeben. Das Speicherlayout der beiden Arrays ist immer noch anders (Neugestaltung erstellt keine Kopie), aber sie werden identisch auf der Python-Ebene behandelt.

Nur um zu beweisen, dass die Dateien wirklich in einer anderen Reihenfolge geschrieben sind:

%Vor%

Lassen Sie uns das Ergebnis visualisieren:

%Vor%

Beachten Sie, dass wir sie auf die gleiche Weise indiziert haben, und sie werden identisch angezeigt.

Häufige Fehler mit IO

Als Erstes sollten wir versuchen, die Fortran-geordnete Datei so zu lesen, als ob sie C-geordnet wäre, und dann das Ergebnis betrachten (indem wir die Funktion plot oben verwenden):

%Vor%

Nicht so gut!

Sie haben erwähnt, dass Sie "umgekehrte" Indices verwenden müssen. Dies liegt wahrscheinlich daran, dass Sie das, was in der obigen Abbildung passiert ist, behoben haben, indem Sie etwas wie (beachten Sie die umgekehrte Form!) Gemacht haben:

%Vor%

Stellen wir uns vor, was passiert:

%Vor%

Beachten Sie, dass das Bild ganz rechts (das Zeitfenster) des ersten Plots mit einer transponierten Version des Bildes ganz links neben dem zweiten Plot übereinstimmt.

Gleichermaßen ergeben print rev_f_order[1,2,3] und print c_order[3,2,1] beide 140 , während die Indexierung auf die gleiche Weise zu einem anderen Ergebnis führt.

Hier kommen im Grunde Ihre umgekehrten Indizes her. Numpy denkt, dass es sich um ein C-geordnetes Array mit einer anderen Form handelt. Beachten Sie, wenn wir die Flags betrachten, sind sie beide C-zusammenhängend im Speicher:

%Vor%

Dies liegt daran, dass ein Fortran-geordnetes Array einem C-geordneten Array mit der umgekehrten Form entspricht.

Schreiben auf Festplatte in Fortran-Order

Es gibt eine zusätzliche Falte beim Schreiben eines numpigen Arrays auf Festplatte in Fortran-Reihenfolge.

Wenn Sie nichts anderes angeben, wird das Array unabhängig vom Speicherlayout in C-Reihenfolge geschrieben! (In der Dokumentation zu ndarray.tofile gibt es eine klare Anmerkung, aber es ist ein gewöhnlicher Fehler. Das umgekehrte Verhalten wäre jedoch falsch, i.m.o.)

Daher müssen Sie, ungeachtet des Speicherlayouts eines Arrays, um es in Fortran-Reihenfolge auf Festplatte zu schreiben:

%Vor%

Wenn Sie es als ASCII schreiben, gilt das Gleiche. Verwende ravel(order='F') und schreibe dann das 1-dimensionale Ergebnis heraus.

    
___ tag123numpy ___ NumPy ist eine wissenschaftliche und numerische Erweiterung der Programmiersprache Python. ___ qstntxt ___

Ich lese ascii und binäre Dateien, die alle dreidimensionale Arrays in Fortran-Reihenfolge angeben. Ich möchte einige willkürliche Manipulationen an diesen Arrays durchführen und sie dann in das gleiche ASCII- oder Binärformat exportieren.

Ich bin verwirrt über die besten Möglichkeiten, mit diesen Arrays in meiner Bibliothek umzugehen. Mein derzeitiges Design scheint fehleranfällig zu sein, da ich die Dinge von der Standard-C-Reihenfolge neu gestalten muss, wenn ein neues Array erstellt wird.

Aktuelles Design:

Ich habe ein paar Funktionen, die diese Dateien lesen und numpy Arrays zurückgeben. Die Lesefunktionen verhalten sich alle ähnlich und lesen im Wesentlichen die Daten ein und geben etwas zurück:

%code%

So wie ich es verstehe, gebe ich eine Ansicht für die Fortran-Reihenfolge auf das ursprüngliche Array zurück.

Mein Code geht davon aus, dass alle Arrays in der gleichen Reihenfolge sind. Dies bedeutet, dass neue Operationen, die ein neues Array erstellen könnten, dafür sorgen, dass %code% verwendet wird, um es in die Fortran-Reihenfolge zurück zu konvertieren.

Dies scheint sehr fehleranfällig zu sein, da ich jede Operation, die ein neues Array erstellt, genau beobachten muss und sicherstellen muss, dass es in eine Fortran-Reihenfolge umgeformt wird, da der Standard normalerweise C-Reihenfolge ist.

Ich muss später vielleicht diese Arrays wieder in Binär- oder ASCII-Dateien exportieren und muss die Fortran-Reihenfolge beibehalten. Also verwende ich %code% , um jedes Element in der Fortran-Reihenfolge zu schreiben.

Bedenken:

  • Der derzeitige Ansatz scheint sehr fehleranfällig zu sein, da ich typischerweise in C-Reihenfolge denke. Ich habe Angst, dass ich immer gebissen werde, wenn ich Aufrufe von %code% vergesse, die Dinge in C-Reihenfolge erzwingen.

    • Ich möchte mich nicht um die Anordnung der Array-Elemente kümmern müssen, außer beim Lesen der Eingabedateien oder beim Schreiben der Daten in die Ausgabedateien.
  • Der aktuelle Ansatz scheint unordentlich zu sein, weil die Indizes unterschiedlich interpretiert werden können und die Dinge verwirrend werden können.

    • Beim Umgang mit Fortran-Arrays ist die Reihenfolge der Tupel für Indizes rückwärts, richtig?
    • Also bedeutet %code% für ein Fortran-Array k = 1, j = 2 und i = 3, während %code% für ein Array mit C-Ordnung bedeutet k = 3, j = 2, i = 1 richtig?
    • Das bedeutet, dass ich und die Benutzer meiner Bibliothek immer an Indizes in (k, j, i) Reihenfolge denken müssen, nicht an das, was wir C / Python-Programmierer normalerweise denken (i, j, k).

Frage:

Gibt es eine Best Practice für solche Dinge? In einer idealen Welt würde ich gerne die Fortran-geordneten Arrays lesen und dann die Bestellung vergessen, bis ich in eine Datei exportiert habe. Ich fürchte jedoch, dass ich die Indizes usw. falsch interpretiere.

Ich habe die einzige Dokumentation gelesen, die ich finden kann, Ссылка . Das Konzept erscheint mir jedoch immer noch so klar wie Schlamm. Vielleicht brauche ich nur eine andere Erklärung für die nackten Dokumente, Ссылка .

    
___
Joe Kington 14.03.2014, 13:13
quelle

Tags und Links