\section{Simulieren} \subsection{Die Entstehung von Galaxien} \par ''Eine Galaxie ist eine durch Gravitation gebundene große Ansammlung von Sternen, Planetensystemen, Gasnebeln und sonstigen Stellaren Objekten.'' \footnote{\url{https://de.wikipedia.org/wiki/Galaxie}} \par Demnach ist es relativ Einfach eine Galaxie zu generieren: es werden einfach ganz viele Objekte in einen Raum geworfen. Das reicht jedoch nicht um die Objekte als Galaxie definieren zu können, da sie nicht ''durch Gravitation gebunden'' sind. \par Um dies zu tun muss die Kraft zwischen allen Objekten in der Galaxie berechnet werden um damit die Position der jeweiligen Objekte nach einer bestimmten Zeit bestimmen zu können. \par Tut man dies, indem man zwischen allen Objekten die Kräfte berechnet kommt es zu Problemen: die Anzahl der Kraft Berechnungen die durchgeführt werden müssen steigen exponentiell: Die Anzahl der Kräfte die auf \(n\) Sterne wirken lassen sich mit der Formel \( n \cdot (n-1) \) berechnen. Für \( n=3 \) müssen demnach \( 6 \) Kräfte berechnet werden, für \( 100 \) Sterne dagegen \( 9900 \) und für \( 1.000.000 \) Sterne \( \approx 9.99999 \cdot 10^{11} \). Die Anzahl der Kraft Berechnungen, die durchgeführt werden müssen beim Simulieren einer ''echten'' Galaxie mit \( > 200 \cdot 10^6 \) Sternen ist demnach so groß, dass die Anzahl der Kräfte die berechnet werden müssen minimiert werden müssen, um in einer sinnvollen Zeit an ein Ergebnis zu kommen. \par Dies reicht jedoch auch nicht, um eine ''stabile'' Galaxie zu generieren: berechnet man nur die Kräfte die auf ruhende Objekte in einem Reibungsfreiem Raum wirken, würden alle Objekte zum Massen Mittelpunkt gezogen werden und die Galaxie würde somit implodieren. Es ist also nötig auf die Sterne in der Galaxie Anfangs Kräfte zu wirken. Diese Kräfte sind durch die Rotation der Galaxie um den Massen Mittelpunkt der Galaxie definiert, man rotiert also die Galaxie und gleicht durch die Zentripetalkraft die Kraft die alle Sterne Richtung Massen Mittelpunkt zieht aus. Rotiert man die Galaxie jedoch zu schnell, explodiert sie förmlich, da die Sterne nicht mehr zusammengehalten werden und die Fliehkraft sie einfach auseinanderzieht. \subsection{Konzepte} \subsubsection{Zu lösende Probleme} Wie bereits in der Einleitung beschrieben, ist eines der Probleme das Auftritt die Anzahl der nötigen Kraft Berechnungen wodurch der Rechenaufwand quadratisch in Relation zu der Anzahl der Sterne steigt und somit in \( O(n \cdot (n - 1)) \in O(n^2) \) liegt. \par Es kommt ebenfalls zu Problemen, wenn der mittlere Fehler, der bei der Berechnung der Kraft entsteht, größer als die wirkende Kraft wird. Dies passiert unter anderem dann, wenn der Abstand zwischen den Sternen so groß wird, dass die wirkende Kraft so gering ist das sie mithilfe von Computern nicht mehr sinnvoll dargestellt werden kann. Statt nun mit Rundungsfehlern zu rechnen, können diese Sterne, die sehr weit entfernt vom Stern dessen Kräfte berechnet werden sollen, einfach nicht mehr beachtet werden, da sie nicht sinnvoll beitragen. Um diese Sterne jedoch nicht komplett aus der Berechnung auszunehmen, können kleine Cluster an Sternen, welche weit genug vom Stern auf den die Kräfte berechnet werden sollen weg sind und klein genug sind zu einem Pseudo-Stern zusammengefasst werden, welcher durch den Masse Mittelpunkt der Sterne die er repräsentiert definiert ist. Das Konzept wurde 1986 von Josch Barnes und Piet Hut veröffentlicht \cite{barneshut86} und erlaubt es die Anzahl an Kräften, die berechnet werden müssen von \( O(n^2) \) auf \( O(n log(n)) \) zu reduzieren. \subsubsection{Generierung von Quadtrees und entsprechende Bäume} Um Sterne clustern zu können muss die Galaxie in der sich die Sterne befinden in Zellen unterteilt werden. Dazu wird ein Quadtree bzw. Octree (ein k-närer Baum mit 4 bzw. 8 Kindern) aufgebaut, indem die Sterne eingefügt werden. Damit die Stern-cluster gebildet werden können müssen die Sterne sich in den Blättern des Baumes befinden. Die Knoten des Baumes, indem sich die Sterne befinden dürfen somit keine weiteren Kinder besitzen. \par Ein Galaxie wie in Abbildung \ref{fig:cells} dargestellt wird demnach Stern für Stern in einen anfangs leeren Baum eingefügt. Die Größe der ersten Zelle die nach dem einfügen aller Sterne alle Sterne beinhaltet kann falls bekannt ist in was für einem Intervall die Koordinaten der Sterne sich befinden direkt genutzt werden, um die Größe der Zelle zu definieren, andernfalls muss diese erst ermittelt werden, indem die minimal und maximal Koordinaten in der liste an Sternen gesucht werden. Beim Einfügen kann es jedoch wie in Abbildung \ref{fig:insertwithexisting} zu sehen zu Problemen kommen. Im falle, dass der Knoten, indem ein Stern eingefügt werden soll bereits durch einen anderen Stern belegt ist müssen für den jeweiligen Knoten Kinder-Knoten erzeugt werden in den die beiden Sterne eingefügt werden müssen. Dies wird so lange fortgeführt bis sich alle Knoten in den Blättern des Baums befinden. \par Eine Zelle ist durch ihren Mittelpunkt und ihrer Breite definiert, daher verschiebt sich eine Zelle, welche sich eine Ebene ''tiefer'' befinden um ein Viertel ihre Breite und die Breite der neuen Zelle ist im Relation zu der ursprünglichen Zelle gesehen halbiert. \par Nachdem alle Sterne in einen Baum eingefügt wurden und sich in den Blättern des Baumes befinden, wird der Baum rekursiv durchlaufen und es wird für jeden inneren Knoten (Knoten, welche keine Blätter sind) die gesamt Masse ihrer Kinder berechnet und der Massen Mittelpunkt. \subsubsection{Funktion des Barnes-Hut Algorithmus} Um nun zu definierten, welche Cluster zusammengefasst werden und welche nicht wird der Barnes-Hut Algorithmus (\ref{eq:barnes_hut}) verwendet. Dieser berechnet einen Wert \( \theta \) welcher als Referenz dafür genommen werden kann, wie die Relation zwischen der Entfernung zu einem Cluster und der Größe des Clusters ist. Um nun Cluster welche weit genug von einem Stern weg sind und gleichzeitig klein genug sind zu erkennen und herauszufiltern kann der Algorithmus in Kombination mit einem vordefinierten Grenzwert genutzt werden. \begin{figure}[!h] \centering \subfloat[Ein Cluster auf mehreren Sternen]{ \centering \begin{tikzpicture} \tikzstyle{circlestyle}=[shape=circle,thick,fill,draw, inner sep=0cm] \node at (0, 0) {}; \node at (9, 0) {}; % Random seed for RNG \pgfmathsetseed{7}; \foreach \x in {1,...,40} { % Find random numbers \pgfmathrandominteger{\a}{10}{390} \pgfmathrandominteger{\b}{10}{390} % Scale numbers nicely \pgfmathparse{0.005*\a}\let\a\pgfmathresult; \pgfmathparse{0.005*\b}\let\b\pgfmathresult; % draw the circle \fill (\a, \b) circle (0.03); }; % draw a box around the star cluster \draw[] (0,0) rectangle (2, 2); \node[] at (1, 1) (A1) {}; \draw[arrows=<->] (0,-0.2) -- node[midway, align=center, below] {\(d\)} (2,-0.2); % draw a star in the far right of the image \node[circlestyle, minimum size=2pt, label=above:\(s_1\)] at (8, 1) (A2) {}; % draw a line in between the box and the far right of the image \draw[dashed, arrows=<->] (A1) -- node[midway, align=center, above] {\(r\)} (A2); \end{tikzpicture} \label{subfig:ungrouped} } \hfill \subfloat[Die abstraction des obigen Clusters]{ \centering \begin{tikzpicture} \tikzstyle{circlestyle}=[shape=circle,thick,fill,draw, inner sep=0cm] \node at (0, 0) {}; \node at (9, 0) {}; % draw a big star in the far left of the image \node[circlestyle, minimum size=2pt, label=above:\(q_1\)] at (1, 0) (B1) {}; % draw the right star \node[circlestyle, minimum size=2pt, label=above:\(s_1\)] at (8, 0) (B2) {}; % draw a line in between the far left star and the right star \draw[dashed, arrows=<->] (B1) -- node[midway, align=center, above] {\(r\)} (B2); \end{tikzpicture} \label{subfig:grouped} } \caption{Visuelle Darstellung der Funktionsweise des Barnes-Hut Algorithmus. Das Stern Cluster aus \ref{subfig:ungrouped} wird in \ref{subfig:grouped} zu einem Stern abstrahiert.} \end{figure} \begin{equation} \label{eq:barnes_hut} \theta = \frac{d}{r} \end{equation} Ist das Verhältnis zwischen Entfernung \( r \) und Breite \( b \) des Clusters kleiner als der vorher definierte Grenzwert, kann das Cluster zu einem Pseudostern zusammengefasst werden. \subsection{Kraft-Berechnungen} \subsubsection{Die Kraft als Vektor} Um die Kraft als Vektor zu berechnen, welcher ein Stern B auf einen Stern A ausübt, wird die folgende Formel verwendet: \begin{equation} \vec{F}_{AB} = \underbrace{-G \frac{m_A m_B}{|r_{AB}|^2}}_{Scalar} \cdot \underbrace{\frac{r_B - r_A}{|r_B - r_A|}}_{Vector} \end{equation} Die Summe der Kräfte, die auf einen Stern wirken ist somit die Summe aller Kräfte die zwischen dem jeweiligen Stern \( a \) und allen anderen Sternen wirken: \begin{equation} F_{a} = \sum_{\substack{i=0 \\ i\neq a}}^{n-1} F_{ai} \end{equation} \subsubsection{Berechnung der auf einen Stern wirkenden Kraft} \par Um die Kraft, welche auf einen bestimmten Stern wirkt, zu berechnen, wird der Baum von der Wurzel aus rekursiv durchlaufen. Es wird für jeden Knoten das jeweilige \( \theta \) berechnet und mit dem vorher definierten Grenzwert verglichen. Ist das berechnete \( \theta \) kleiner als der vorher definierte Grenzwert wird die Rekursion nicht weiter in den Baum gehen, sondern den jeweiligen Teilbaum zusammenfassen. \par Es ist somit durch den Grenzwert somit eine End-Bedingung gegeben, welche verhindert das zu weit in den Baum vorgedrungen wird und somit auch verhindert, dass Sterne die in einer zu großen Entfernung zu des Ursprungs Stern liegen und dicht genug gruppiert sind in die Berechnung miteinbezogen werden. \par Möchte man die Kraft auf den Stern \( F \) in Abbildung \ref{fig:cells} berechnen berechnet man das \( \theta \) zwischen \( F \) und dem Wurzel-Knoten. Ist das berechnete \( \theta \) größer als der vorher definierte Grenzwert kann statt weiter in den Baum hineinzugehen und weitere Kräfte zu berechnen die Kraft zwischen \( F \) und dem Pseudostern, der durch den Wurzel-knoten dargestellt wird direkt berechnet werden. Andernfalls wird weiter in den Baum hineingegangen und auf der nächsten Baum-Ebene das Entsprechende \( \theta \) zwischen den Sternen berechnet werden. \par Betrachtet man Abbildung \ref{fig:cells} fällt auf das die Zelle in der sich die Sterne \( C \) und \( D \) befinden sehr klein ist und die Entfernung zu dem Stern \( F \) vergleichsweise hoch ist. Es kann also angenommen werden, dass das Theta zwischen \( F \) und der Zelle in der sich \( C \) und \( B \) befinden sehr klein ist. Die Sterne können demnach zusammengefasst werden. \bigskip \begin{figure} \hspace{1.5cm} \begin{minipage}{0.45\textwidth} \begin{tikzpicture}[level 1/.style={level distance=1.5cm}] % First Layer \draw [line width=0.5mm] (0, 0) rectangle (6, 6); % Second Layer \draw [line width=0.25mm] (0, 0) rectangle (3, 3); \draw [line width=0.25mm] (3, 0) rectangle (6, 3); \draw [line width=0.25mm] (0, 3) rectangle (3, 6); \draw [line width=0.25mm] (3, 3) rectangle (6, 6); % Third Layer (South West) \draw [line width=0.125mm] (0, 0) rectangle (1.5, 1.5); \draw [line width=0.125mm] (1.5, 1.5) rectangle (3, 3); % Third Layer (North East) \draw [line width=0.125mm] (3, 3) rectangle (4.5, 4.5); \draw [line width=0.125mm] (4.5, 4.5) rectangle (6, 6); % Forth Layer (North West) \draw [line width=0.125mm] (3, 4.5) rectangle (3.75, 5.25); \draw [line width=0.125mm] (3.75, 5.25) rectangle (4.5, 6); % Draw the nodes \node at (1, 4.5) {$A$}; \node at (4, 5.5) {$B$}; \node at (3.5, 5) {$C$}; \node at (5, 4) {$D$}; \node at (2.75, 2.75) {$E$}; \node at (0.75, 0.75) {$F$}; \node at (2, 0.75) {$G$}; \node at (3.5, 0.75) {$H$}; \end{tikzpicture} \end{minipage} \caption{Unterteilung einer Galaxie in verschiedene Zellen} \label{fig:cells} \end{figure} \begin{figure} \centering \begin{forest} for tree={circle,draw, s sep+=0.25em} [ [A] [ [ [] [B] [C] [] ] [] [] [D] ] [ [] [E] [F] [G] ] [H] ] \end{forest} \caption{Die in Abbildung \ref{fig:cells} dargestellte Galaxie als Baum dargestellt} \end{figure} \begin{figure} \subfloat[Anfangszustand. Der Stern B soll in den Baum, indem sich bereits A befindet, eingefügt werden.]{ \begin{forest} for tree={circle,draw, s sep+=0.25em} [,phantom [B] [ A ] ] \end{forest} } \, \subfloat[Stern B kann nicht eingefügt werden, da der Slot durch A belegt ist, also wird A weiter in den Baum versickert.]{ \begin{forest} for tree={circle,draw, s sep+=0.25em} [,phantom [B] [ [A] [] [] [] ] ] \end{forest} } \, \subfloat[B wird nun eingefügt, da sich B jedoch nicht in einem Blatt befinden, muss B weiter versickert werden.]{ \begin{forest} for tree={circle,draw, s sep+=0.25em} [,phantom [B [A] [] [] [] ] ] \end{forest}\quad\\[2ex] } \, \subfloat[Damit B versickert werden kann, wird der Platz der durch A besetzt wird freigemacht, indem A weiter versickert wird.]{ \begin{forest} for tree={circle,draw, s sep+=0.25em} [B [ [A] [] [] [] ] [] [] [] ] \end{forest}\quad } \, \subfloat[B kann jetzt in den Baum versickert werden und ist nun ein Blatt.]{ \begin{forest} for tree={circle,draw, s sep+=0.25em} [ [ [A] [] [B] [] ] [] [] [] ] \end{forest}\quad } \caption{Schrittweises einfügen des Sternes B in einen Baum, indem sich bereits ein Stern (A) befindet.} \label{fig:insertwithexisting} \end{figure} \subsection{Stabile Galaxien} Um eine stabile Galaxie zu generieren, muss diese rotiert werden damit die Zentrifugalkraft der Kraft, welche die Sterne zum Massemittelpunkt zieht entgegenwirkt. Dies lässt sich einfach berechnen, jedoch entsteht ein großes Problem: Es muss eine Kraft ermittelt werden, welche am Anfang der Simulation wirkt. \par Da das Ziel meines Projektes nicht darin liegt das Anfangswertproblem zu untersuchen, sondern die restliche Simulation stark zu parallelisieren habe ich beschlossen das Problem in ein eigenes, einfach austauschbares Modul zu verpacken und so in der Zukunft einfach austauschbar zu machen. \par Um jedoch eine ''halb'' Stabile Galaxie zu generieren rotierte ich einfach (im zwei Dimenionalem) die Kraft die im ersten Zeitschritt auf den Stern wirkte um 90 Grad. Dadurch rotieren die Sterne anfangs um den Massenmittelpunkt. Dieses Konzept ist in keinem Sinne physikalisch korrekt, es kann jedoch, als Platzhalter genutzt werden bis einer richtige Möglichkeit gefunden wird dies zu berechnen. \subsection{Datenbanken} \subsubsection{Speichern der Sterne} Die Sterne werden in einer Tabelle in Datenbank \mbox{PostgreSQL} gespeichert. Die Tabelle ist wie in Abbildung \ref{fig:stars_table} zu sehen aufgebaut. \begin{figure}[h!] \centering \begin{tabular} {l | l | l | l | l | l} star\_id & \(x\) & \(y\) & \(vx\) & \(vy\) & \(m\) \\ \hline\hline 1 & -300 & 300 & 0 & 0 & 1000 \\ \hline 2 & -200 & -200 & 0 & 0 & 1000 \\ \hline \dots & \dots & \dots & \dots & \dots & \dots \\ \hline n & \(x_n\) & \(y_n\) & \(vx_n\)& \(vy_n\) & \(m_n\) \\ \hline \end{tabular} \caption{Darstellung der Tabelle in der die Sterne gespeichert werden. Die star\_id Spalte beinhaltet eine global einmalige ID wodurch jeder Stern identifiziert werden kann.} \label{fig:stars_table} \end{figure} Dadurch das jeder Stern eine einmalige ID besitzt kann diese verwendet werden, um einfach auf Sterne zu verweisen. Dies ist im Kontext des Einfügens sehr hilfreich, da die Verschiebung eines Sternes durch Ändern der Stern-ID vollzogen werden kann. \par Jeder Stern besitzt eine Position, einer Geschwindigkeit und eine Masse. Dadurch kann man einen Stern definieren, jedoch auch berechnen was für eine Kraft der Stern auf andere Sterne auswirkt. \subsubsection{Speichern von Bäumen} Um die Bäume in denen die Galaxien gespeichert werden in einer Datenbank zu speichern, muss eine einheitliche Struktur definiert werden, um Probleme in der Zukunft zu verhindern. Die Nutzung von speziellen Graphen Datenbanken bietet sich natürlich an, jedoch wird diese starke Spezialisierung schnell zu einem Hindernis. Um nach dem KISS Prinzip\footnote{"Das KISS-Prinzip (englisch Keep it simple, stupid) fordert, zu einem Problem eine möglichst einfache Lösung anzustreben." \url{https://de.wikipedia.org/wiki/KISS-Prinzip}} eine möglichst einfache Lösung zu nutzen werden die Bäume in einer Relationalen Datenbank gespeichert. Jeder Knoten wird dabei in einer Zeile der Datenbank gespeichert und erhält eine global einzigartige ID. Die Kinder in andrem Knoten hängen werden anhand ihrer ID in der Zeile gespeichert, sodass es einfach möglich ist einfach auf diese zuzugreifen und beim rekursiven durchsuchen des Baumes auf diese zuzugreifen. Möchte man einen Teilbaum unterteilen können einfach vier neue Knoten erzeugt werden, welche vom Knoten an dem sie hängen referenziert werden. \begin{figure*}[ht] \begin{tabular} {l | l | l | l | l | l | l | l | l | l} node\_id & box\_width & total\_mass & depth & star\_id & root\_id & isleaf & box\_center & center\_of\_mass & subnodes \\ bigint & numeric & numeric & numeric & bigint & bigint & boolean & numeric[] & numeric[] & numeric[] \\ \hline\hline 2921847 & 1000 & 2000 & 0 & 0 & 1 & False & \{0, 0\} & \{0, 0\} & \{ \(\dots\) \} \\ \hline 2921848 & 500 & 1000 & 1 & 1 & 1 & True & \{-500, 500\} & \{-300, 300\} & \{ \(\dots\) \} \\ \hline 2921849 & 500 & 0 & 1 & 0 & 1 & True & \{500, 500\} & \{0, 0\} & \{ \(\dots\) \} \\ \hline 2921850 & 500 & 1000 & 1 & 2 & 1 & True & \{-500, -500\} & \{-200, -200\} & \{ \(\dots\) \} \\ \hline 2921851 & 500 & 0 & 1 & 0 & 1 & True & \{500, -500\} & \{0, 0\} & \{ \(\dots\) \} \\ \hline \end{tabular} \caption{Darstellung der Tabelle in der ein Baum definiert ist, welcher einmal unterteilt wurde.} \end{figure*}