Datenstrukturen für endlichen Volumencode: Arrays vs Classes

11

Ich muss einen endlichen Volumencode für Magnetohydrodynamics (MHD) schreiben. Ich habe vorher numerischen Code geschrieben, aber nicht in dieser Größenordnung. Ich wollte nur fragen, welche eine gute Wahl ist, indem ich eine Datenstruktur (objektorientierter Ansatz) mit Klassen verwende oder einfach mehrere Arrays für verschiedene Eigenschaften in Bezug auf Geschwindigkeit, Skalierbarkeit usw. verwende. Ich plane, den Code in Python zu schreiben, und Verwenden Sie fortran für numerisch intensive Teile.

Ein Beispiel für eine Klasse in Python wäre

class Cell:
   def __init__(self, x, y, z, U):

Arrays können einfach definiert werden als

x[nx][ny][nz]
y[nx][ny][nz]
z[nx][ny][nz]
U[nx][ny][nz]

etc.

Einzelgänger
quelle

Antworten:

9

Einfache Antwort: In modernem Python ist jeder Datentyp eine Klasse, sodass formal kein Unterschied zwischen den beiden von Ihnen vorgeschlagenen Lösungen besteht. (Bitte denken Sie daran, Klassen neuen Stils zu verwenden: Klassische Klassen sind veraltet! Siehe http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes )

Nun sollte die Frage lauten: Wie organisiere ich eine effiziente Datenstruktur in Python? Es besteht kein Zweifel, dass die Idee, die Zellen als Array von class CellInstanzen zu organisieren, viel zu ineffizient ist. Sie werden mit einem Durcheinander von Zeigern und nicht zusammenhängenden Daten enden, die wie eine komplizierte verknüpfte Liste organisiert sind. Sie haben natürlich die Möglichkeit, einfach neue Zellen in Ihre Liste einzufügen. Benötigen Sie diese Funktion? Im Gegenteil, Sie haben einen nicht zusammenhängenden Datenspeicher und müssen über verschiedene Indirektionsebenen auf jede Zelle zugreifen.

Wenn Sie Ihre Daten als organisieren, sind die Daten numpy.ndarrayspeicherzusammenhängend, und der Zugriff auf verschiedene Zellen erfolgt einfach über Ihren Speicherblock: platzsparend (kein Speicher für Zeiger verschwendet) und schnell .

Wie von Ethan hervorgehoben, sollten OO-Konzepte verwendet werden, jedoch auf höherer Ebene, sobald eine effiziente Datenstruktur auf niedriger Ebene implementiert wurde, normalerweise durch numpy.ndarray's.

OO-Programmierung bedeutet, Daten an die Methoden zu binden, die auf einer höheren Abstraktionsebene mit den Daten selbst arbeiten. (Ein Beispiel: Ich habe einen FEM-Code implementiert, in dem die Steifheitsmatrix als Klasse mit einer Methode zur spärlichen Superknoten-Cholesky-Faktorisierung definiert wurde. Die erste Implementierung war im Kern: Wenn eine Implementierung außerhalb des Kerns erforderlich war, war dies erforderlich wurde durch Vererbung und minimale Anpassungen an der unterstrichenen Datenspeicherung erhalten. Fast 100% des Superknoten-Cholesky-Codes wurden wiederverwendet.)

Ein letzter, aber entscheidender Kommentar: Ein effizientes numerisches Verfahren ist das Ergebnis einer intelligenten Zuordnung eines Algorithmus und einer Datenstruktur zu Ihrer Zielcomputerarchitektur. Wenn Sie mit der falschen Datenstruktur beginnen, gibt es keine Möglichkeit , die Effizienz wiederherzustellen, ohne sie vollständig neu zu schreiben.

Stefano M.
quelle
@EthanCoon Vielen Dank für Ihren Kommentar zu der anderen Antwort, die mich dazu veranlasste, meine eigene zu schreiben.
Stefano M
10

Ich habe vor ein paar Tagen darüber nachgedacht (auch in Python). Persönlich denke ich nicht, dass objektorientierte Programmierung immer gut zur numerischen Programmierung passt. Sie können sich vom Entwerfen der Klassen ablenken lassen, anstatt nur die Gleichungen zu lösen. Ich bleibe lieber bei einfachen Funktionen, und mit numpy können Sie Ihre Gleichungen vektorisieren lassen, so dass nur sehr wenige Zeilen benötigt werden. Numpy ist ziemlich schnell, da die eigentlichen Berechnungen mit einem C-Backend (oder FORTRAN?) Durchgeführt werden.

Was ich Ihnen empfehlen würde,

  1. Schreiben Sie ein Python-Skript, das die einfachste Version Ihres Problems mithilfe eines funktionalen Ansatzes mit numpy löst. Haben Sie zum Beispiel alles in einer beliebigen Einheit und versuchen Sie es nur mit 1D (oder 2D). In diesem Stadium ist es vollkommen in Ordnung, wenn der Code unordentlich ist. Wichtig ist, dass Sie Ihr Projekt vorantreiben.
  2. Sobald Sie etwas haben, das funktioniert. Identifizieren Sie, wo der Code ausführlich und refraktor ist. In dieser Phase können Sie mit verschiedenen Ideen zur Vereinfachung Ihres Codes herumspielen. Führen Sie möglicherweise Funktionen ein, bei denen Sie feststellen, dass Sie sich wiederholen. Sie können mit der Originalversion vergleichen, damit Sie wissen, dass Sie keine Fehler einführen.
  3. Entscheiden Sie, ob ein objektorientierter Ansatz die Komplexität des Codes weiter reduziert.

Die Hauptbotschaft lautet: Beginnen Sie erst mit dem Schreiben von Klassen, wenn Sie das Problem bereits auf einfachste Weise gelöst haben. Nur wenn Sie Erfahrung mit der Lösung eines Problems sammeln, können Sie Ihre objektorientierte Schnittstelle definieren. Wenn Sie dies vorher tun, wird es wahrscheinlich nur stören.

Boyfarrell
quelle
3
Ich stimme der Aussage nicht zu, dass OO nicht gut für die numerische Programmierung geeignet ist, aber wo es gut passt, ist es auf einem viel höheren Niveau. OO ist sehr nützlich für Dinge wie Physikmodelle, Netze, Löser usw., ist aber auf der Ebene der Zellen fast immer unangemessen.
Ethan Coon
In dem Beitrag wollte ich vor den möglichen Grubenstürzen einer "vorzeitigen Objektivierung" des numerischen Codes warnen, insbesondere wenn man anfängt. Ich bin nicht abgeneigt, Objekte zu verwenden, siehe meinen dritten Punkt: Wenn Objekte die Komplexität verringern können, sind sie eine gute Idee. Ich bin damit einverstanden, dass die von Ihnen angeführten Beispiele eine gute Verwendung sind, aber um an diesen Punkt zu gelangen, ist Erfahrung erforderlich.
Boyfarrell