Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
ss16:physiksimulation_doc_cpp [2016/08/13 18:01] markumnus vector3d.cpp hinzugefügt |
ss16:physiksimulation_doc_cpp [2016/08/14 22:11] (aktuell) markumnus |
||
---|---|---|---|
Zeile 3: | Zeile 3: | ||
</a></center></html> | </a></center></html> | ||
- | <- [[ss16:Physiksimulation_doc_components|zurück zur Liste der Komponenten]] | + | **[[ss16:Physiksimulation|Physiksimulation]]/[[ss16:Physiksimulation_Doc_Main|Dokumentation]]/[[ss16:Physiksimulation_doc_components|Komponenten]]/** |
- | + | =====C++-Teil===== | |
- | =====Physiksimulation | C++-Teil===== | + | **INFO**: Soweit nicht anders angegeben, sind die Code-Bestandteile auf dieser Seite aus den jeweiligen Header-Dateien. |
====Programmstruktur==== | ====Programmstruktur==== | ||
Zeile 56: | Zeile 55: | ||
}; | }; | ||
</code> | </code> | ||
+ | |||
+ | |||
+ | ====object.cpp==== | ||
+ | Unsere //Object//s dienen der Aufbewahrung der Werte, die für die Berechnungen wichtig sind sowie einen Namen zur Identifikation. | ||
+ | <code cpp> | ||
+ | #include "vector3d.hpp" | ||
+ | |||
+ | class Object | ||
+ | { | ||
+ | private: | ||
+ | // DEKLARATION DER ATTRIBUTE | ||
+ | std::string name; | ||
+ | Vector3D pos; // Position | ||
+ | Vector3D vel; // Velocity | ||
+ | Vector3D acc; // Acceleration | ||
+ | double vol; // Volume | ||
+ | double den; // Density | ||
+ | double mas; // Mass | ||
+ | bool fix; // is fixed? | ||
+ | | ||
+ | public: | ||
+ | // KONSTRUKTOREN | ||
+ | Object (std::string); | ||
+ | Object (Vector3D, Vector3D); | ||
+ | Object (Vector3D, Vector3D, Vector3D); | ||
+ | | ||
+ | // GETTER | ||
+ | std::string getName() const; | ||
+ | Vector3D getPos() const; | ||
+ | Vector3D getVel() const; | ||
+ | Vector3D getAcc() const; | ||
+ | double getVol() const; | ||
+ | double getDen() const; | ||
+ | double getMass() const; | ||
+ | bool isFixed() const; | ||
+ | | ||
+ | // SETTER | ||
+ | void setPos (Vector3D); | ||
+ | void setVel (Vector3D); | ||
+ | void setAcc (Vector3D); | ||
+ | void setVol (double); | ||
+ | void setDen (double); | ||
+ | void setMass(double); | ||
+ | void setFix (bool); | ||
+ | | ||
+ | // OPERATOR OVERLOADINGS | ||
+ | bool operator== (Object*) const; | ||
+ | | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ====universe.cpp==== | ||
+ | Unser Universe dient als Container für Objects. Im Prinzip funktioniert es wie ein std::vector mit besseren Zugriffsmöglichkeiten. | ||
+ | <code cpp> | ||
+ | #include "object.hpp" | ||
+ | |||
+ | class Universe | ||
+ | { | ||
+ | private: | ||
+ | // DEKLARATION DER ATTRIBUTE | ||
+ | std::vector <Object*> objects; | ||
+ | | ||
+ | public: | ||
+ | // KONSTRUKTOREN | ||
+ | Universe (); | ||
+ | | ||
+ | // DESTRUKTOR | ||
+ | ~Universe (); | ||
+ | | ||
+ | // GETTER | ||
+ | std::vector <Object*> getObjects() const; | ||
+ | Object* getObject (std::string) const; | ||
+ | |||
+ | // SONSTIGE FUNKTIONEN | ||
+ | void add (Object*); | ||
+ | unsigned int size() const; | ||
+ | void remove (Object*); | ||
+ | std::string asString (); | ||
+ | }; | ||
+ | </code> | ||
+ | Die //size()//-Methode gibt die Anzahl der //Object//s zurück, die sich aktuell in diesem Universe befinden. | ||
+ | |||
+ | |||
+ | ====simulation.cpp==== | ||
+ | Die Simulation ist das Herzstück des C++-Teils. Hier laufen die Berechnungen ab, deren Ergebnisse später angezeigt werden.\\ | ||
+ | Hier sind das Euler- und das Runge-Kutta-Verfahren implementiert, wobei wir aktuell nur letzteres tatsächlich nutzen. | ||
+ | <code cpp> | ||
+ | #include "universe.hpp" | ||
+ | |||
+ | class Simulation | ||
+ | { | ||
+ | private: | ||
+ | // DEKLARATION DER ATTRIBUTE | ||
+ | double dt; | ||
+ | const double stdG = 0.0002958935421; | ||
+ | double G; | ||
+ | | ||
+ | Universe* unvrs; | ||
+ | | ||
+ | public: | ||
+ | // KONSTRUKTOR | ||
+ | Simulation (Universe*); | ||
+ | Simulation (Universe*, double); | ||
+ | |||
+ | // FUNKTIONEN | ||
+ | void setG (double); | ||
+ | void setDT (double); | ||
+ | void simulate (); | ||
+ | void simulate (unsigned int); // simuliert n Schritte | ||
+ | void simulate_rk4 (); | ||
+ | void simulate_rk4 (unsigned int); // simuliert n Schritte | ||
+ | |||
+ | // Euler-Verfahren | ||
+ | Vector3D updateForce (unsigned int) const; | ||
+ | void updateAcc (); | ||
+ | void updateVel (); | ||
+ | void updatePos (); | ||
+ | | ||
+ | // Runge-Kutta-Verfahren | ||
+ | void updateVel_rk4 (); | ||
+ | void updatePos_rk4 (); | ||
+ | }; | ||
+ | </code> | ||
+ | Die Hauptmethode ist //simulate_rk4()//. Hier werden die Beschleunigungen (und Kräfte) berechnet, daraus die Geschwindigkeiten und daraus die Positionen.\\ | ||
+ | Dazu ein paar Ausschnitte aus der simulation.cpp: | ||
+ | <code cpp> | ||
+ | void Simulation::simulate_rk4 () | ||
+ | { | ||
+ | updateAcc(); | ||
+ | updateVel_rk4(); | ||
+ | updatePos_rk4(); | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | Bei der Berechnung der Beschleunigungen ist die Berechnung der Kräfte mit eingebunden, denn aus\\ | ||
+ | //F=m*a//\\ | ||
+ | folgt\\ | ||
+ | //a = F/m//\\ | ||
+ | <code cpp> | ||
+ | void Simulation::updateAcc () | ||
+ | { | ||
+ | Vector3D newAcc = Vector3D(0.,0.,0.); | ||
+ | for (unsigned int i = 0; i < unvrs->size(); i++) | ||
+ | { | ||
+ | newAcc = (updateForce(i)/unvrs->getObjects().at(i)->getMass()); | ||
+ | unvrs->getObjects().at(i)->setAcc(newAcc); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | Die Kräfte werden nach [[https://wikimedia.org/api/rest_v1/media/math/render/svg/46315ddb85d544f9eee7bbde7798f6dae9829428|dieser]] Formel in updateForce() berechnet. | ||
+ | <code cpp> | ||
+ | Vector3D Simulation::updateForce (unsigned int a) const // a ist der Index des Object im Universe | ||
+ | { | ||
+ | | ||
+ | std::vector<Object*> objects = unvrs->getObjects(); | ||
+ | std::vector<Vector3D> forces (objects.size(), Vector3D (0.,0.,0.)); | ||
+ | for (unsigned int i = 0; i < objects.size(); i++) | ||
+ | { | ||
+ | if (i != a) // Object wirkt keine Kraft auf sich selbst aus | ||
+ | { | ||
+ | Vector3D abstand_vec (objects.at(a)->getPos() - objects.at(i)->getPos()); | ||
+ | double abstand = objects.at(a)->getPos().abstand(objects.at(i)->getPos()); | ||
+ | | ||
+ | forces.at(a) = forces.at(a) + (abstand_vec * ((objects.at(a)->getMass() * objects.at(i)->getMass())/(abstand*abstand*abstand))* -G); | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | return forces.at(a); | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | Mit den berechneten Beschleunigungen kann man nun mithilfe des Runge-Kutta-Verfahrens die Geschwindigkeiten und analog dazu die Positionen berechnen: | ||
+ | <code cpp> | ||
+ | void Simulation::updateVel_rk4 () | ||
+ | { | ||
+ | std::vector<Object*> objects = unvrs->getObjects(); | ||
+ | Vector3D newVel = Vector3D(0.,0.,0.); | ||
+ | for (unsigned int i = 0; i < objects.size(); i++) | ||
+ | { | ||
+ | Vector3D k1 = (objects.at(i)->getAcc()) * dt; | ||
+ | Vector3D k2 = (objects.at(i)->getAcc() + (k1*0.5)) * dt; | ||
+ | Vector3D k3 = (objects.at(i)->getAcc() + (k2*0.5)) * dt; | ||
+ | Vector3D k4 = (objects.at(i)->getAcc() + (k3)) * dt; | ||
+ | | ||
+ | newVel = objects.at(i)->getVel() + ((k1 + k2*2 + k3*2 + k4)/6); | ||
+ | | ||
+ | objects.at(i)->setVel(newVel); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | |||
+ | ====auswertung.cpp==== | ||
+ | Die Auswertung-Klasse dient dem Sammeln von Daten über das Universum. Hier werden zum Beispiel auch die Positionsdaten der //Object//s in die Ergebnis-Textdatei geschrieben. Dazu dienen die folgenden Funktionen: | ||
+ | <code cpp> | ||
+ | #include "simulation.hpp" | ||
+ | |||
+ | class Auswertung | ||
+ | { | ||
+ | private: | ||
+ | // DEKLARATION DER ATTRIBUTE | ||
+ | Universe* unvrs; | ||
+ | std::vector <std::string> results; | ||
+ | |||
+ | public: | ||
+ | // KONSTRUKTOR | ||
+ | Auswertung(Universe*); | ||
+ | | ||
+ | // ANDERE METHODEN | ||
+ | void clear(); | ||
+ | std::string currentState() const; | ||
+ | void writeToBuffer(); | ||
+ | void writeToFile(); | ||
+ | }; | ||
+ | </code> | ||
+ | Die Funktionalität ist einfach: In jedem Zeitschritt werden die Positionsdaten in den Buffer (hier ein std::vector<std::string>) geschrieben, um das Textdokument nicht permanent öffnen und wieder schließen zu müssen. Sobald eine bestimmte Anzahl an Elementen im Buffer sind (bei uns 50), wird der Inhalt in die Textdatei geschrieben und der Buffer geleert. | ||
+ | |||
+ | |||
+ | ====interface.cpp==== | ||
+ | Diese Klasse ist dazu da, eine Schnittstelle zum C++-Teil zur Verfügung zu stellen. Mithilfe der Methoden des Interfaces kann man alle relevanten Funktionen des C++-Teils steuern: | ||
+ | <code cpp> | ||
+ | #include "auswertung.hpp" | ||
+ | |||
+ | class Interface | ||
+ | { | ||
+ | private: | ||
+ | // DEKLARATION DER ATTRIBUTE | ||
+ | Universe* u; | ||
+ | Simulation* s; | ||
+ | Auswertung* a; | ||
+ | | ||
+ | public: | ||
+ | // KONSTRUKTOR | ||
+ | Interface(); | ||
+ | Interface (double G); | ||
+ | | ||
+ | // METHODEN | ||
+ | void add(std::string, double, double, double, double, double, double, double); | ||
+ | void modify (std::string, double, double, double, double, double, double, double); | ||
+ | void run (unsigned int); | ||
+ | std::string step (); | ||
+ | void setG (double); | ||
+ | void setDT (double); | ||
+ | }; | ||
+ | </code> | ||
+ | Wie man sieht, sind vor allem die add()- und modify()-Methode sehr unübersichtlich. Deshalb werden wir später, im [[ss16:Physiksimulation_Doc_cython|Cython-Teil]], eine besser benutzbare Version davon erstellen. Hier an dieser Stelle vereinfacht es die Benutzung sogar, eine Methode zu haben, die beispielsweise ein Objekt nur im Ganzen hinzufügt.\\ | ||
+ | //setG()// und //setDT()// stellen die Parameter für die Berechnung ein: G ist die Gravitationskonstante und DT die Genauigkeit bei der Berechnung.\\ | ||
+ | //step()// führt einen Berechnungsschritt aus, //run()// so viele, wie angegeben. |