Physiksimulation/Dokumentation/Projektverlauf/
Datum: 07. Juli 2016
In dieser Woche haben wir uns komplett mit Cython herumgeschlagen.
In Cython haben wir den folgenden Code produziert:
############################### # IMPORTE ############################### import pyximport from libcpp.string cimport string pyximport.install() ############################### # DEFINIERE HEADER # IN CYTHON NEU ############################### cdef extern from "interface.hpp": cdef cppclass Interface: Interface() except+; Interface(double G) except+; void add(double, double, double, double, double, double, double); void run (unsigned int); string step (); ############################### # WRAPPER-KLASSE, # DIE ANDERE PYTHON- # TEILE IMPORTIEREN # KOENNEN ############################### cdef class Zwischengesicht: cdef Interface intfc def __cinit__ (self, double G = -1): print G if G == -1: self.intfc = Interface () else: self.intfc = Interface (G) def add (self, double x, double y, double z, double vx, double vy, double vz, double m): self.intfc.add (x, y, z, vx, vy, vz, m) def run (self, unsigned int n): self.intfc.run (n) def step (self): return self.intfc.step()
Zunächst importieren wir u.A. den String-Datentypen aus der Cython-Bibliothek, da dieser sonst nicht benutzt werden könnte.
Danach definieren wir die Header-Datei unserer Interface-C++-Klasse neu, um sie als Attribut in unserer Zwischengesicht-Klasse benutzen zu können. Die Methoden aus dem Interface führen beim Aufruf direkt den C++-Code aus.
Das Zwischengesicht (uns sind an der Stelle die Namensideen für Interfaces ausgegangen) ist zwar eine Cython-Klasse, aber man kann sie in Python importieren und benutzen, als wäre sie eine ganz normale Python-Klasse (ein Beispiel folgt gleich). An dieser Stelle haben wir einfach die C++-Methoden komplett übernommen, was der Übersichtlichkeit vor allem in der add(double, double, double,…)-Methode etwas schadet. Hier überlegen wir uns zur nächsten Woche eine benutzerfreundlichere Variante.
Benutzen kann man das Ganze nun wie folgt:
from Interface import Zwischengesicht i = Zwischengesicht(0.0002958935421) # mit Gravitationsskonstante i.add (0.003747371174552917, 0.002469565033861764, ...) # lauter unübersichtliche Werte i.run(1000)
Dieser Code initialisiert (z.T. nicht sichtbar) ein neues Universum und alle Komponenten, die zum Berechnen nötig sind. Dazu zählen die Simulationssklasse für die Berechnung und die Auswertungsklasse zum Sammeln der Daten und Schreiben in die Ergebnisdatei. In der 3. Zeile wird ein neues Objekt (hier mit wissenschaftlichen Daten der Sonne) zum Universum hinzugefügt. Danach wird die Simulation gestartet und läuft 1000 unserer Zeiteinheiten (etwa 5 Tage) lang.
An sich funktioniert das Interface wunderbar, die Berechnungen finden statt und es wird in eine Datei geschrieben. Allerdings stimmen diese nicht. Die Planeten fliegen einfach linear an der Sonne vorbei, ohne auch nur ein bisschen beeinflusst zu werden. Das Kuriose dabei ist, dass der exakt gleiche C++-Code, wenn man ihn direkt ausführt, korrekte Ergebnisse liefert. Cython leitet die Werte auch ohne Genauigkeitsverlust genau an C++ weiter. Wie soll das gehen? Die restliche Laborzeit haben wir vergeblich damit verbracht, den Fehler zu finden.
In der nächsten Woche müssen wir natürlich den Fehler in der Berechnung finden, indem wir detaillierte Analysen der einzelnen Programmteile durchführen. Danach sollten wir beginnen, unser Cython-Interface in das Python-Fenster einzuarbeiten, sodass alles in einer runden Gesamtlösung endet.