about summary refs log tree commit diff
path: root/docs/simulieren.tex
blob: 544346e293a196724650b31f55ab2b6c0e41ea28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
\section{Simulieren}

\subsection{Die Entstehung von Galaxien}
``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}}

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.

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.

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 Massenmittelpunkt 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 Massenmittelpunkt der Galaxie definiert, man rotiert also die Galaxie und
gleicht durch die Zentripetalkraft, die Kraft die Alle Sterne Richtung
Massenmittelpunkt 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{Berechnung der Beschleunigungen}
Um die Beschleunigung die auf einen Stern wirkt zu berechnen wird folgendes
berechnet:

\begin{equation} \label{eq:beschleunigung}
    a = G \cdot \frac{\Delta{M_2}}{\Delta{r}^2}
\end{equation}

\( G \) steht hier für die Universelle Gravitationskraft, \( \Delta M \) für die
Masse des Objektes das Umkreist wird und \( \Delta r \) für die Entfernung zum
Mittelpunkt des Objektes das umkreist wird.
Problem ist, dass kein Objekt umkreist wird sondern eine große Anzahl an Sternen.
Es ist also nicht möglich mithilfe von herkömmlichen Methoden die Beschleunigung
die auf einen Stern wirkt zu berechnen.

TODO: und jetzt?

\subsubsection{Die Kraft als Vektor}
Um die Kraft als Vektor darzustellen, muss die Formel \ref{eq:beschleunigung}
mithilfe von Vektoren wiefolgt neu aufgestellt werden:

\begin{equation} \vec{F}_{12} = \underbrace{-G \frac{m_1 m_2}{|r_{12}|^2}}_{Scalar}
\cdot \underbrace{\frac{r_2 - r_1}{|r_2 - r_1|}}_{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_{i=0}^{n-1} F_{ai} \end{equation}

\subsubsection{Berechnung der Umlaufgeschwindigkeit}
Die Umlaufgeschwindigkeit kann berechnet werden, indem die Kraft die die Sterne
in die Mitte der Galaxie zieht \( \left( F = G \cdot \frac{m \cdot M}{r^2}
\right) \) mit der Zentripetalkraft \( \left( F_z = \frac{m \cdot v^2}{r}
\right)\) gleichgesetzt wird:

\begin{equation}
v = \sqrt{\frac{G \cdot M_E}{r}}
\end{equation}

\( M_E \) steht dabei für die Masse der Erde, \( G \) für die
Gravitationskonstante und \( r \) für den Bahn Radius.  Da wir jedoch nicht in
der Erdumlaufbahn, sondern in einer Galaxien Umlaufbahn hantieren, können wir
nicht die Masse der Erde nutzen. Wir müssen daher eine andere Möglichkeit
nutzen, die Größe der Masse, die den Stern in Richtung Massenmittelpunkt zieht zu
berechnen.

\subsubsection{Ellipsen und die Geschwindigkeit der Sterne}
Da die Sterne nicht auf perfekten Kreisbahnen um den Mittelpunkt der Galaxie
fliegen muss in betracht gezogen werden wie die Sterne auf Elliptischen Bahnen
orbitieren.  Wichtigt ist dabei die Geschwindigkeit, diese muss zwischen der
ersten Kosmischen Geschwindigkeit \( v_k \) und der zweiten Kosmischen
Geschwindigkeit \( v_P \) liegen. Die beiden Kosmischen Geschwindigkeiten sind
folgendermaßen definiert:

\begin{equation}
v_{k1} = \sqrt{\frac{GM}{r}}
\end{equation}
\begin{equation}
v_{k2} = \sqrt{\frac{2GM}{r}}
\end{equation}

Die Tatsache das die Sterne auf Elliptischen Bahnen unterwegs sind ist für die
Berechnung irrelevant, da eh für jeden Zeitschritt \( t \) eine neue Kraft
berechnet wird aus der eine Beschleunigung berechnet wird die wiederum die neue
Position des Sternes ergibt.  Hält man die Geschwindigkeit der Sterne somit im
Intervall \( (v_{k1} ; v_{k2}) \), dann ergibt sich (in der Theorie) von
alleine eine elliptische Bahn.

\subsection{Entwicklung der nötigen Software}
Die Software ist komplett in Golang geschrieben was die Nutzung von mehreren
Threads mithilfe von Go-Methoden stark vereinfacht. Um den Barnes-Hut
Algorithmus anzuwenden muss die Galaxie in einen Octree unterteilt werden.
Dabei wird eine Zelle definiert die alle Sterne beinhaltet welche anschließen
solange unterteilt, bis eine der drei End Bedingungen eintrifft.

\subsubsection{Zu lösende Probleme}
Ein Problem das auftritt wenn die Kräfte zwischen allen Sternen berechnet
werden ist, dass der Rechenaufwand \( O(n \cdot n-1) \approx O(n^2) \) beträgt.

Es kommt 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, das die wirkende Kraft so gering ist
das sie mithilfe von Computern nicht mehr sinnvoll dargestellt wird.
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 dieses Problem zu lösen wird der Barnes-Hut Algorithmus verwenden. Dieser Algorithmus
unterteilt einen Bereich in variabel große Zellen und mindert die Laufzeit von \( O(n^2) \) auf
\( O(n \log(n) \).

\subsubsection{Generierung von Quadtrees und die Nutzung des Barnes-Hut
Algorithmus}

Um nun einen Quadtree (einen k-nären Baum mit jeweils vier Kindern) zu
generieren die die komplette Galaxie umfasst, muss erstmal definiert werden wie
groß die Galaxie überhaupt ist. Dazu werden, falls bereits Sterne vorliegen,
die jeweiligen Extrempunkte (minimales x, minimales y, maximales x und
maximales y) bestimmt und die Wurzel Zelle mithilfe diese Werte entsprechend
skaliert.  Falls jedoch noch nicht bekannt ist wie groß die Galaxie sein wird,
muss abgeschätzt werden wir groß sie werden könnte, d.h.: es wird bei der
Generierung geschaut in was für einem Bereich die Sterne Generiert werden. 

\begin{equation}
    \text{Wurzel Knoten} = (0, 0), \text{Breite}=b
\end{equation}

\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}
\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}

Um die Kraft die auf einen bestimmten Stern wirkt zu berechnen, wird der Baum
von der Wurzel aus nach unten durchlaufen.  Beispiel: Berechnung der Kraft die
auf den Stern A wirkt. Der 'Quadtree' wird von oben nach unten durchgegangen,
also wird das Verhältnis zwischen der Entfernung des Massemittelpunktes zu dem
Stern A (\(\approx 42\)) und der Breite der jeweiligen Zelle (100) berechnet
(Formel \ref{eq:barnes_hut}): \( \frac{100}{43} \not> \theta = 0.5\).

\begin{equation} \label{eq:barnes_hut} \theta = \frac{d}{r} \end{equation}

Ist das Verhältnis größer als ein im vorhinein definierter Grenzwert \( \theta
\), dann wird weiter in den Quadtree ineingegangen und eine Ebene tiefer
rekursiv weitergeprüft.

Hierbei ist es wichtig, dass die Sterne richtig in den Baum eingefügt wurden,
d.h.: Die eigentlichen Sterne müssen in den Blättern liegen. Um dies zu
erreichen, müssen die Sterne beim einfügen immer in der Blätter verschoben
werden.

\begin{figure}
\subfigure[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}
}
\quad
\subfigure[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}
}
\quad
\subfigure[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]
}
\quad
\subfigure[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
}
\quad
\subfigure[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}

\begin{lstlisting}
if node.hasstar() {

}
\end{lstlisting}

Wie in Abbildung \ref{fig:insertwithexisting} zu sehen ist, wird erst der
bereits existierende Stern weiter in den Baum versickert, der Stern welcher
eingefügt werden soll wird danach ebenfalls in den Baum Versickert bis er sich
in einem der Blätter befindet.

Die Koordinate des Massenmittelpunktes \( \varsigma \) des jeweiligen Knotens
kann wie in Formel (\ref{eq:mean_mass}) beschrieben berechnet werden:

\begin{equation} \label{eq:mean_mass}
\varsigma = \left( \dfrac{ \displaystyle \sum_{i=0}^{n} x_i \cdot m_i }{
\displaystyle \sum_{i=0}^{n} m_i } , \frac{ \displaystyle \sum_{i=0}^{n} y_i
\cdot m_i }{ \displaystyle \sum_{i=0}^{n} m_i } \right)
\end{equation}

Es ist somit durch \( \theta \) 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 dem ursprungssten liegen und dicht
genug grupiert sind zusammengefasst werden.

\subsubsection{Implementierung des Quadtrees}
Um generell irgendwas zu tun muss in fast allen fällen etwas definiert werden.
Zur Simulation von Galaxien brauchen wir vor allem eine Methode, Sterne
einheitlich zu definieren. Der unten definierte Vec2-typ kann einen Vektor oder
eine Koordinate darstellen was ihn in der Anwendung zu einem praktischen
Hilfsmittel macht.  Er speichert die X und Y Komponente der jeweiligen Struktur
die er darstellen soll als float64-typ.

\begin{lstlisting}
type Vec struct {
        X               float64
        Y               float64
        Z               float64
}

method (Vec2) insert() {...}
method (Vec2) insideOf() bool {...}
func newVec2() Vec2 {...}
\end{lstlisting}

Mithilfe des Vec2-typens kann ein Kompletter Stern definiert werden. Dabei wird
ein Stern mithilfe seine Position \( C \), seiner Geschwindigkeit \( V \), und
seiner Masse \( M \) beschrieben.

\begin{lstlisting}
type Star struct {
        C               Vec
        V               Vec
        Mass            float64
}

method (Vec2) insideOf() bool {...}
\end{lstlisting}

Um einen sogennanten quadtree bzw. octree aufzubauen wird erstmal eine
Räumliche Begrenzung benötigt, die einem Raum beschriebt indem die Sterne
enthalten sind oder nicht.  Diese grenze ist als `Boundary` definiert, es wird
dabei der Mittelpunkt der Begrenzung und die kürzeste Entfernung zwischen
mittelpunkt und äußerer Begrenzung genutzt um den Raum zu definieren.

\begin{lstlisting}
type Boundary struct {
        Center          Vec
        HalfDimension   float64
}

function newBoundary() {...}
\end{lstlisting}

Der eigentliche QuadTree bzw. Octree beinhaltet einige Informationen: Die
Anzahl in ihm enthaltene Sterne, die Räumliche Ausbereitung, die eigentlichen
Sterne als Star2D definiert und die Rekursionstiefe als integer. Die Definition
des Quadtrees der Unten zu sehen ist enthält Zeiger zu den Kindern des
Quadtrees und ist somit rekursiv definiert was es einfach macht neue Kinder zu
erstellen, da diese eine Kopie ihre Eltern mit einer anderen Begrenzung
darstellen wodurch die in ihnen enthaltenen Sterne weniger werden.

\begin{lstlisting}
type QuadTree struct {
        StarCount       int
        Boundary        Boundary
        Star            []Vec2

        NorthWest       *QuadTree
        NorthEast       *QuadTree
        SouthWest       *QuadTree
        SouthEast       *QuadTree

        ReccursionDepth int
}
method (QuadTree) insert(Star) bool {...}
method (QuadTree) subdivide() {...}
\end{lstlisting}

\subsubsection{Benchmarking}

Um den Geschwindigkeit Vorteil darzustellen, kann die Kraft zwischen \(n\)
homogen verteilten Sternen berechnet werden. Einmal mit der Brute-Force Methode
und einmal mit der im Barnes-Hut Algorithmus beschriebenen Methode.

\subsubsection{Runge-Kutta Methoden}
Die Runge-Kutta Methode wird genutzt, um die Position eines Objektes nach einer
Beliebigen Zeit zu approximieren. Dabei kann, bei Nutzung eines möglich kleinen
Zeit Schrittes, ein sehr genaues Ergebnis erzielt werden.  In unserem Fall
haben wir einen Stern auf den eine Kraft wirkt. Wir wollen die Position des
Sterns nach einem Zeit schritt berechnen, jedoch auch eine andere Kraft mit
einbringen um die Sterne auf eine Elliptische Bahn um die Mitte der Galaxie zu
bringen.  Die Geschwindigkeit die der Stern dabei annimmt kann mit der
folgenden Formel berechnet werden:

\begin{equation}
    v = \sqrt{ar}
\end{equation}

\subsubsection{Goroutines}
Die Nutzung von mehreren sogenannten Go-Methoden ist unglaublich effektiv, da
es die Zeit die gebraucht wird das Programm auszuführen drastisch verringert.
Die Implementation ist ebenfalls unglaublich einfach, es recht

\subsection{Netzwerk}

Damit das Projekt so gut wie möglich skaliert, wird die Anwendung in mehrere
kleine Dienste aufgeteilt die jeweils eine Funktion übernehmen und
untereinander kommunizieren. Dabei läuft jede Anwendung in einem eigenen
Container (siehe \ref{subsubsec:Docker}) und kann somit in falle eines
Nadelöhrs mehrfach gestartet werden und über einen Reverse-http-Proxy (siehe
\ref{subsubsec:Traefik}) mit Daten versorgt werden.

\subsubsection{Die verschiedenen Dienste}
Um die Generierung der Punkt Wolken und die anschließende Simulation der Wolke
in einzelne Micro Services aufzuspalten muss erstmal definiert werden für welche
Dienste es überhaupt Sinn macht sie in einzelne Instanzen abhängig bzw.
unabhängig von einander agieren.

\subsubsection{Docker} \label{subsubsec:Docker}
\begin{quote}
\begin{minipage}{\linewidth}
\stepcounter{footnote}
\renewcommand\thempfootnote{\arabic{footnote}}
``Docker vereinfacht die Bereitstellung von Anwendungen, weil sich Container,
die alle nötigen Pakete enthalten, leicht als Dateien transportieren und
installieren lassen. Container gewährleisten die Trennung und Verwaltung der
auf einem Rechner genutzten Ressourcen. Das beinhaltet laut Aussage der
Entwickler: Code, Laufzeit Modul, System Werkzeuge, Systembibliotheken – alles
was auf einem Rechner installiert werden kann.``~\footnote{\url{https://de.wikipedia.org/wiki/Docker_(Software)}}
\end{minipage}
\end{quote}

\subsubsection{Docker-compose}
Damit nicht alle Container per Hand auf jedem System gestartet werden müssen
wird eine sogenannte Docker-compose Datei erstellt, diese ermöglicht es einem
die komplette Docker Konfiguration in einer Datei zu bündeln und somit auch die
jeweiligen Netzwerke einfacher zu konfigurieren.

\subsubsection{Traefik} \label{subsubsec:Traefik}
\subsubsection{Kubernetes}
\subsubsection{Grafana}