Compare commits

...
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

14 Commits

  1. BIN
      docs/.future.tex.swp
  2. BIN
      docs/.generating.tex.swp
  3. 2
      docs/darstellung.tex
  4. 105
      docs/developing.tex
  5. 14
      docs/einleitung.tex
  6. 15
      docs/ergebnisse.tex
  7. 120
      docs/future.tex
  8. 280
      docs/generating.tex
  9. 179
      docs/generieren.tex
  10. 2
      docs/images/galaxy_network.svg
  11. 7
      docs/introduction.tex
  12. 3
      docs/quellenliteraturverzeichniss.tex
  13. 11
      docs/results.tex
  14. 505
      docs/simulating.tex
  15. 486
      docs/simulieren.tex
  16. 18
      docs/titleabstract.tex
  17. 14
      docs/vektoren.tex
  18. 7
      docs/vorgehensweise.tex
  19. BIN
      main.pdf
  20. 44
      main.tex
  21. BIN
      networktikz/build-0aaaabaecd1a0e24478344963afa4f0bbef400cd59d3d9d56de7731d8a582982/main.pdf
  22. BIN
      networktikz/build-2d971d303de0e7ebced63d0fcf1d639ed01c916d63a52ef1e57aa1186a05d864/main.pdf
  23. BIN
      networktikz/build-30740998824c255df20ffa4d9c6eaaa58df812977d22cb27dfb6aded8bbf628b/main.pdf
  24. BIN
      networktikz/build-35ad62dee2b613e409d223048d8379b63088ce5dee671db88737657051c548b8/main.pdf
  25. BIN
      networktikz/build-37f18e65bbfb92356e6f763d5e5d36270f2abf7cc627a5d863b552b16b4a03fa/main.pdf
  26. BIN
      networktikz/build-3c5aa09f4a163ad401138c09153ceed1115cb28627686b637a6e539c0293295f/main.pdf
  27. BIN
      networktikz/build-426b2e16a93486d6427fa694bbf0716f595af4d84602ec208ef173e6c4b5e645/main.pdf
  28. BIN
      networktikz/build-499ebe1b5556e51f625f4d073a43e13c54090707884bbe9d8e408dfca2076597/main.pdf
  29. BIN
      networktikz/build-4c494493f75c1c45ecb73e75612d62edaabefb6b31ed62d1ee194bbe7cd2f04e/main.pdf
  30. BIN
      networktikz/build-5c2e439a6dd3da27c6368675a052ace5436705014148ad109060315a5045c641/main.pdf
  31. BIN
      networktikz/build-600c2e083a230832585ac1b78ed9bb622fee97d930615085b8ec0ff4007a44ca/main.pdf
  32. BIN
      networktikz/build-6109513bb30ee7b0317c65661daa62bde297161ea68293beaabe48a968fb5f89/main.pdf
  33. BIN
      networktikz/build-6d0414a21f720793d3e955c30dd82ee0628a92ab78c81e6c0e4869f55d5a64e2/main.pdf
  34. BIN
      networktikz/build-7ec80a2fb8f5a8cbd110e155c24406f93792478a36b4ad5fc1bad3743c954ee1/main.pdf
  35. BIN
      networktikz/build-9440e3640a87eea4aae4d222948774f9b52c4c10c41c0555aa7090aef3b5e617/main.pdf
  36. BIN
      networktikz/build-a120952ee3b3da2d1f37a49ef850f9d4130c64dd528b90801085d0bdc00aa589/main.pdf
  37. BIN
      networktikz/build-a8c527e5fdb94e77005d4680aeef0b7561af5f6438b7c96c1192c0449353439d/main.pdf
  38. BIN
      networktikz/build-ad6186b2f1ec4b7e4b086ede48996880d1d6ae55f124dd2f0c85e3d365d77f2f/main.pdf
  39. BIN
      networktikz/build-b3108eeb037a58467e062d6ef3e90ee8a1df33889e05ce35a89b27ea5affe620/main.pdf
  40. BIN
      networktikz/build-bcda6e5a3ac8479d737eacf2e813312afae3d429be7a0fa45a535d1f35812856/main.pdf
  41. BIN
      networktikz/build-c6864e68112edd1c637d4381d0eb1e95a10a6c3587dd19c3e3586983a8fcb115/main.pdf
  42. BIN
      networktikz/build-ccfe85b61cc19f386fc2411ece4fb20526c357cf97445911517dacac4730e7bc/main.pdf
  43. BIN
      networktikz/build-d75aebc2af2bbdf1219b7f51ff3e0977bfbbc0a8e312dd736d5aeb59d0ccf08e/main.pdf
  44. BIN
      networktikz/build-e0dd84dbedba1079a90064072c2ed0515ea90013e8b72f6de98747326c779e7c/main.pdf
  45. BIN
      networktikz/build-f0cd4afea87092f34d0eb12163c0835d636f99bd8f4e8a91c3d60e6aa7fc7df9/main.pdf
  46. BIN
      networktikz/build-f55a35ecb99410afd29006389c91a1a3a9f1ca48ca0bb3dbe9f7c9743ac84eec/main.pdf
  47. BIN
      networktikz/build-fa10f2a545be29242e15512accb7b2905d0129dbfbc16124c9f4fed9fa55369d/main.pdf
  48. 1
      networktikz/current-build
  49. 1
      networktikz/last-successful
  50. 46
      networktikz/main.tex
  51. 1
      networktikz/texbox
  52. 1
      texbox

BIN
docs/.future.tex.swp

Binary file not shown.

BIN
docs/.generating.tex.swp

Binary file not shown.

2
docs/darstellung.tex

@ -1,2 +0,0 @@
\section{Darstellung}

105
docs/developing.tex

@ -0,0 +1,105 @@
\section{Developing the required software}
The software was initially written in
Python\footnote{\url{https://www.python.org/}}, but as it started getting
bigger, I switched to Go\footnote{\url{https://golang.org/}} making it much
easier to handle the project and creating clean code. The complete software is
written completely modular and containerized using docker containers that
interact with each other over various APIs.
The overall amount of containers may seem high, but because of the strict
subdivision of the tasks, scaling issues do not occur because when a
bottleneck appears, a new container can be started on a server far away, but
because of the interaction over the http API, the physical location of the
server the docker container is running on is almost\footnote{Servers in a
closer range to each other (normally) have a better connection to each other
making it a lot more efficient to communicate among themselves} neglect able.
The overall interactions in between the contains can be seen in figure
\ref{fig:loadbalancergenerator}
\subsection{Docker Containers}
The complete Codebase is subdivided into individual docker-containers
interacting with each other over http APIs.
\subsubsection{Manager}
The manager container makes requests to various containers and handles the
interactions such as requesting a few stars from the generator container and
routing them to the simulation container. It also controls the Simulator
container instructing it where the database is and what tasks need to be done.
\subsubsection{Database}
The Database container stores all the galaxies in the form of trees that are
needed by the other services. It exposes a API with the following endpoints:
\begin{tabular}{l l}
/new & creates a new tree \\
/printall & print all trees (json) \\
/insert/\{treeindex\} & insert a star \\
/starlist/\{treeindex\} & get all stars in tree (json) \\
/dumptree/\{treeindex\} & dumps the tree (json) \\
\end{tabular}
\subsubsection{Generator}
The generator container accesses the NFW container and random samples the values
it receives from it.
\subsubsection{NFW}
The NFW container exposes a single API endpoint \texttt{/NFW} using the http
parameters \texttt{x}, \texttt{y} and \texttt{z} to calculate the NFW value of
a given star.
\subsubsection{Simulator}
The simulator container gets its data over the simulator trafik instance that
gets data from the manager in the form of a single star using an HTTP-POST
request. If the local simulator container does not allready have a cached copy
of the database tree, it requests it from the databse. It then proceeds by
calculating all the forces acting on the given star and then inserts the result
into a new tree by sending the star data to the database.
\subsubsection{Traefik} \label{subsubsec:traefik}
The traefik container is an important component routing incoming request to
multiple containers making it a perfect load balancer as seen in figure
\ref{fig:loadbalancergenerator}.
\begin{figure}
\centering
\begin{forest}
for tree={,draw, s sep+=0.25em}
[,phantom
[manager, name=manager
[Simulator
[Traefik
[Simu, name=simu1]
[\(\dots\), name=simudots]
[Simu, name=simu2]
]
]
[,phantom
[,phantom
[,phantom
[,phantom, yshift=1cm
[DB, name=db]
]
]
]
]
[Generator
[Traefik
[NFW, name=nfw1]
[\(\dots\), name=nfwdots]
[NFW, name=nfw2]
]
]
]
]
\foreach \a in {1,...,2}{%
\draw[->, dashed] (nfw\a) to[out=south, in=north] (db);
\draw[->, dashed] (simu\a) to[out=south, in=north] (db);
}
\draw[->, dashed] (manager) to[out=south, in=north] (db);
\draw[->, dashed] (simudots) to[out=south, in=north] (db);
\draw[->, dashed] (nfwdots) to[out=south, in=north] (db);
\end{forest}
\caption{Visual representation of a load balancer in front of a collection of NFW containers}
\label{fig:loadbalancergenerator}
\end{figure}

14
docs/einleitung.tex

@ -1,14 +0,0 @@
\section{Einleitung}
Das Projekt ist nach meinem vorletzten Jugend-Forscht Projekt entstanden: Ich
habe ein Praktikum in Astronomischen Rechen Institut in Heidelberg genutzt, um
mit einem Doktoranden\footnote{Tim Tugendhat} das Navarro-Frenk-White Profil,
das zum generieren von Punkt Wolken genutzt wird, zu visualisieren. Anschließend
hat sich das Projekt ein bisschen verlaufen, irgendwann beschloss ich jedoch,
dass das Projekt weiterzuführen und statt nur statische Galaxien zu generieren
dazu überzugehen die Galaxien zu simulieren, also die Entwicklung einer
virtuellen Galaxie zu untersuchen. Eines der Entscheidenden Probleme war die
Laufzeit der Simulation. Das Problem das es zu lösen galt, war die Nutzung von
mehreren Threads mit der Nutzung des Barnes-Hut Algorithmus zu kombinieren.
Das Ergebnis ist sehr schön: Durch die Nutzung der Programmiersprache Go
war das einbauen der Nutzung von mehreren Threads vergleichsweise einfach.

15
docs/ergebnisse.tex

@ -1,15 +0,0 @@
\section{Ergebnisse}
Wie bewertest Du Deine Ergebnisse? Wie passt das zu dem, was Du über Dein Thema
gelesen oder gehört hast? Was ist gut gelaufen im Projekt, was war schlecht,
was könnte noch verbessert werden? Das simulieren von Galaxien ist komplett
ohne Optimierungen ein sehr rechenaufwendiger Prozess, weshalb einer der
wichtigsten aspekte des Projektes war, die effizienz zu erhöhen.
\subsection{Das n-Körper Problem}
Das N-Körper Problem ist blöd (aber notwendig D:) (Und es ermöglicht das ganze
erst!)
\subsection{Beschleunigung der Berechnung von Kräften}
\( n^2 \rightarrow n \cdot log(n) \)
iasd

120
docs/future.tex

@ -0,0 +1,120 @@
\section{Future}
This section contains ideas, concepts and optimizations for the future.
\subsection{Database scaling}
Not being able to scale the database can result in a major bottleneck hindering
the project to grow. The databases need to be able to scale, because they can
only store a so big amount of stars on a single machine.
The database mainly consists of two tables: A table storing all the nodes
building a tree and a table storing all the stars
\subsubsection{Tree table}
The tree table can be subdivided by using different databases for different
quadrants. Staying in 2 Dimensional space, an inner node always contains four
child nodes. Starting at the root node, the four child nodes can be seen as new
root nodes of other databases and be stored accordingly
\subsubsection{Stars table}
The stars table can be simply split up to multiple databases by inserting the
stars randomly into one of the databases.
\subsection{Optimizing up the simulation to over O(\(n \cdot \log(n)\))}
Currently, all the stars in the galaxy are randomly picked out, simulated and
inserted in a "new" galaxy. By instead simulating the galaxies in "waves"
\ref{subsubsec:waves}, the galaxies can be simulated at multiple points for
multiple time steps at once. A problem that arises: it is not possible to take
a snapshot of the galaxy after a time step \(t\). For doing this, the waves
must stop.
\subsubsection{"waves"}\label{subsubsec:waves}
The image below visually describes the concepts of waves:
\bigskip
\begin{figure}[ht!]
\subfloat[Original \qquad \(O(n \cdot \log(n))\)]{
\centering
\begin{tikzpicture}
\draw[->] (-0.1,0,0) -- (8,0) node[right] {$t$};
\draw (0.00,0.1) rectangle (1.00,1.1);
\draw (1.25,0.1) rectangle (2.25,1.1);
\draw (2.50,0.1) rectangle (3.50,1.1);
\draw (3.75,0.1) rectangle (4.75,1.1);
\draw (5.00,0.1) rectangle (6.00,1.1);
\draw (6.25,0.1) rectangle (7.25,1.1);
\draw (0.50,-0.1) rectangle (0.50,0.1);
\draw (1.75,-0.1) rectangle (1.75,0.1);
\draw (3.00,-0.1) rectangle (3.00,0.1);
\draw (4.25,-0.1) rectangle (4.25,0.1);
\draw (5.50,-0.1) rectangle (5.50,0.1);
\draw (6.75,-0.1) rectangle (6.75,0.1);
\draw (0.20,0.1) -- (0.20,1.1); % +0.2
\draw (1.65,0.1) -- (1.65,1.1); % +0.4
\draw (3.10,0.1) -- (3.10,1.1); % +0.6
\draw (4.55,0.1) -- (4.55,1.1); % +0.8
\draw (6.00,0.1) -- (6.00,1.1); % +1.0
\draw (6.45,0.1) -- (6.45,1.1); % +0.2
\end{tikzpicture}
}
\subfloat["Waves" \qquad \(<O(n \cdot \log(n))\)]{
\centering
\begin{tikzpicture}
\draw[->] (-0.1,0,0) -- (8,0) node[right] {$t$};
\draw (0.00,0.1) rectangle (1.00,1.1);
\draw (0.50,-0.1) -- (0.50,0.1);
\draw (0.20,0.1) -- (0.20,1.1); % +0.2
\draw (1.25,0.1) rectangle (2.25,1.1);
\draw (1.75,-0.1) -- (1.75,0.1);
\draw (1.65,0.1) -- (1.65,1.1); % +0.4
\draw (2.50,0.1) rectangle (3.50,1.1);
\draw (3.00,-0.1) -- (3.00,0.1);
\draw (3.10,0.1) -- (3.10,1.1); % +0.6
\draw (3.75,0.1) rectangle (4.75,1.1);
\draw (4.25,-0.1) -- (4.25,0.1);
\draw (4.55,0.1) -- (4.55,1.1); % +0.8
\draw (3.95,0.1) -- (3.95,1.1); % +0.2
% below
\draw (4.375,-0.1) rectangle (5.375,-1.1);
\draw (4.875,0.1) -- (4.875,-0.1);
\draw (5.300,-0.1) -- (5.300,-1.1); % +0.8
\draw (4.700,-0.1) -- (4.700,-1.1); % +0.2
\draw (5.00,0.1) rectangle (6.00,1.1);
\draw (5.50,-0.1) -- (5.50,0.1);
\draw (5.40,0.1) -- (5.40,1.1); % +0.4
\draw (6.25,0.1) rectangle (7.25,1.1);
\draw (6.75,-0.1) -- (6.75,0.1);
\draw (6.85,0.1) -- (6.85,1.1); % +0.6
\end{tikzpicture}
}
\subfloat["Waves" \qquad \(<O(n \cdot \log(n))\)]{
\centering
\begin{tikzpicture}
% rectangle
\draw (0,0) rectangle (4.0,4.0);
% current position
\draw (0.6, 0) -- (0.6, 4);
\draw (3.4, 0) -- (3.4, 4);
% distance
\draw[<->] (0.6, 0.6) -- (3.4, 0.6);
\end{tikzpicture}
}
\caption{The difference in computation when using waves visually depicted. The lines represent which stars are processed}
\end{figure}

280
docs/generating.tex

@ -0,0 +1,280 @@
\section{Generating} \label{sec:generate}
The generation of a static point cloud out of which a galaxy can be abstracted
is an important if not crucial part of the project, because all the other
modules build up opon this part.
\subsection{The Navarro-Frenk-White Profil}
The density distribution function used is the so called Navarro-Frenk-White
profile (NFW-profile). It's main purpose is to define how likley a star with a
distance \( r \) to the midpoint of the galaxie is existing. The profile is
defined in the following way:
\begin{equation} \label{eq:NFW_profile}
\rho_{NFW}(r) = \frac{ 1 }{ \sqrt{ 2 \pi } \cdot \sigma } \cdot
\exp \left( \frac{ -\phi(r) }{ \sigma^{ 2 } } \right)
\end{equation}
\begin{equation*}
\phi(r) = \frac{ 4\pi \cdot G \cdot f_{0} \cdot R_{s}^3 }{ r } \cdot
ln{ \left( 1 + \frac{ r }{ R_{s} } \right) }
\end{equation*}
The NFW-function can now be random sampled (\ref{subsec:random_sampling})
in order to find out if a star exits or not.
\par For finding out if a star with the coordinates \( x_1, x_2, x_3 \) is
exitent, the distance inbetween the star and the midpoint of the galaxy needs
to be determined first using the Pythagorean theorem:
\begin{equation} \label{eq:pythagoras}
r = \sqrt{x_{1}^{2} + x_{2}^{2} + x_{3}^{2} }
\end{equation}
The distance \( r \) to the midpoint of the galaxy is then inserted into the
NFW-profile (\ref{eq:NFW_profile}) resulting in a value \( s \):
\begin{equation}
\rho_{NFW}(r) = \dots = s
\end{equation}
The value \(s\) defines the probability, that a star with the distance \( r \)
from the midpoint of the galaxy exists.
\subsection{Random Sampling} \label{subsec:random_sampling}
For finding out if a star exists, the value \( s \) that was generated using the
NFW-profile is used while random sampling
\begin{equation}\label{range:psi}
\psi = [ \rho(r_{min}); \rho(r_{max}) ]
\end{equation}
Supposing \( s \) is in the intervall \( \psi \), then a random
value \( u \) in the intervall \( \psi \) gets generated. If \( s > u \) is true,
the star gets kept, in any other case (\( s \leq u \)) the star gets abandoned.
\subsubsection{Illustration}
\begin{figure}[!h]
\centering
\subfloat[Example of a star getting generated, because of the condition \(u<\rho(s_1)\) being true]{
\centering
\begin{tikzpicture}
% draw the background grid
\draw[very thin, color=lightgray, step=5mm] (-0.9, -0.9) grid (2.9, 2.9);
% draw the axes
\draw[->] (-1,0) -- (2.5,0) node[right] {$r$};
\draw[->] (0,-1) -- (0,3) node[above] {};
% draw the plot
\draw[scale=0.5, domain=0.21:5, smooth, variable=\x, black]
plot ({\x},{(1/\x) + 1}) node[above] {$\rho(x)$};
% draw the points
\fill (1, 0.4) circle (0.05) node[right] {\(u\)};
\fill (1, 0.75) circle (0.05);
% draw the x-tick
\draw[xshift=0cm](1, 1pt) -- (1, -3pt) node[anchor=north] {$r_{1}$};
% draw the y-ticks
\draw (-0.1, 0.4) -- (0.1, 0.4) node[anchor=east, xshift=-0.1cm] {$u$};
\draw (-0.1, 0.75) -- (0.1, 0.75) node[anchor=east, xshift=-0.1cm] {$\rho(r_1)$};
\end{tikzpicture}
}
~\hfill
\subfloat[Example of a star not getting generated, because of the condition \(u<\rho(s_1)\) being false]{
\centering
\begin{tikzpicture}
% draw the background grid
\draw[very thin, color=lightgray, step=5mm] (-0.9, -0.9) grid (2.9, 2.9);
% draw the axes
\draw[->] (-1,0) -- (2.5,0) node[right] {$r$};
\draw[->] (0,-1) -- (0,3) node[above] {};
% draw the plot
\draw[scale=0.5, domain=0.21:5, smooth, variable=\x, black]
plot ({\x},{(1/\x) + 1}) node[above] {$\rho(x)$};
% draw the points
\fill (1, 2.0) circle (0.05) node[right] {\(u\)};
\fill (1, 0.75) circle (0.05);
% draw the x-tick
\draw[xshift=0cm](1, 1pt) -- (1, -3pt) node[anchor=north] {$r_{1}$};
% draw the y-ticks
\draw (-0.1, 2) -- (0.1, 2) node[anchor=east, xshift=-0.1cm] {$u$};
\draw (-0.1, 0.75) -- (0.1, 0.75) node[anchor=east, xshift=-0.1cm] {$\rho(r_1)$};
\end{tikzpicture}
}
\caption{Plots displaying the two possible outcomes after random sampling}
\end{figure}
A star is generated using the NFW-profile (\ref{eq:NFW_profile}) with a
distance \( r_1 \) to the midpoint of the galaxy. A random value \( s_1 \) is
then generated and if \( s_1 \leq \rho(r_1) \) is true, the star gets
kept. The counterexample can be seen using \( r_2 \) as an examples: because
of \( s_2 \leq \rho(r_1) \) being false.
\kern-1em
\begin{equation}\label{cases:random_sampling}
\begin{cases}
s_1 \leq \rho(r_1) & \rightarrow \text{The star gets kept}\\
s_1 > \rho(r_1) & \rightarrow \text{The star does not get kept}
\end{cases}
\end{equation}
\subsection{Lookup Tables}
Insead of calculating the NFW value (\ref{eq:NFW_profile}) for every star again
and again, the NFW profile can be precalculated and stored in a so called
lookup table. This table has to columns linking the distance of a star to the
midpoint of the galaxy with it's corresponding NFW value.
\begin{center}
\begin{tabular} {l | l}
\( r_n \quad n \in \mathbb{N} \) & \( \rho_n \quad n \in \mathbb{N} \) \\ \hline\hline
\( r_1 \) & \( \rho_1 \) \\ \hline
\( r_2 \) & \( \rho_2 \) \\ \hline
\( r_3 \) & \( \rho_3 \) \\ \hline
\( \dots \) & \( \dots \) \\ \hline
\( r_n \) & \( \rho_n \) \\
\end{tabular}
\end{center}
A problem arises: the table cannot provide as precise values as the actual
function, the solution to this is to scale the table as big as possible, in
this case, we set the step inbetween the values as low as possible without
generating a to big file. A constraint in this process is the amount of RAM in
the system: if the lookuptable gets to big and does not fit into the RAM, the
whole process is not profitable anymore because of the read speed of the normal
medium (as a reference: an SSD can read about 10 times less fast than the RAM).
This process is perfect in a scenario using a single node cluster, but when
using multiple nodes (PCs), this is purely optional because if more
computational power is needed, a new machine is started and added to the
cluster.
\subsection{Speeding up the generations}
There are multiple methods that can be used to speed up the generation of the
star clustes.
A good way is to simply use more processing power: Using \( n \) times as may
Processing cores enables one to generate \( n \) times as many stars in the
same timeframe. This is great, because without optimizing the code, alot more
stars can be generated. A good way to start this is to use some of the servers
from the German server hoster Hetzner. They provide servers with 32 cores and
128 GB of RAM for \( \approx \) 50ct/h. Because the servers do not need to be
rented for a month or eaven an entire year, this is a great way to get alot of
processing power ina small time frame.
Another great aspect concerning the Hetzner servers is, that all the servers
are connected with a possible bandwidth of at least a Gigabit per second (A
test of two servers at the same location even got to over two Gigabits per
second!). Because of this, it is nearly asking us to build a cluster, so that
was the trivial next step.
\subsection{Clustering}
In order to simply scale the generation module, we can use
Docker\footnote{\url{https://www.docker.com}}. Docker provides an easy
interface to implement operating-system level virtualisation using containers.
\begin{figure*}
\centering
\subfloat[The Project structure when ustilizing virtual machines]{
\centering
\forestset{box/.style={ draw, no edge, l=0, l sep=1.5ex, calign=first,
anchor=base west, content format={\strut\forestoption{content}}, if n
children=0{}{ after packing node={ minimum width/.pgfmath=
{s("!l")+max_x("!l")-s("!1")-min_x("!1")}, for children/.wrap pgfmath
arg={s+={##1}}{0}, typeset node}}}}
\begin{forest}
for tree={box}
[Host system[Host Operating System
[Hypervisor
[Guest OS
[Bins/Libs
[NFW1]
]
]
[Guest OS
[Bins/Libs
[NFW2]
]
]
[Guest OS
[Bins/Libs
[NFW3]
]
]
]
]]
\end{forest}
}
\subfloat[The Project structure when utilizing containerization]{
\centering
\forestset{box/.style={ draw, no edge, l=0, l sep=1.5ex, calign=first,
anchor=base west, content format={\strut\forestoption{content}}, if n
children=0{}{ after packing node={ minimum width/.pgfmath=
{s("!l")+max_x("!l")-s("!1")-min_x("!1")}, for children/.wrap pgfmath
arg={s+={##1}}{0}, typeset node}}}}
\begin{forest}
for tree={box}
[Host system[Operating System
[Docker Engine
[Bins/Libs
[NFW1]
]
[Bins/Libs
[NFW2]
]
[Bins/Libs
[NFW3]
]
]
]]
\end{forest}
}
\caption{The two examples above show how the Hypervisor and Guest OS Layer get replaced by Docker}
\end{figure*}
Using this concept, we can simply build a container exposing an API returning
the NFW-value of a given input. In order to scale this container, we need to
insert a reverse proxy in front of the containers routing the traffic to the
right containers. The reverse proxy I used was
Traefik\footnote{\url{https://traefik.io/}}. Traefik itself is a docker
container simplifying the process of setting it up a lot. Using a docker-compose
file, we can define how to startup multiple container at the same time and also label containers.
This can be used by Traefik to manage the containers:
\begin{itemize}
\setlength\itemsep{0.1em}
\item \texttt{"traefik.backend=db"}
\item \texttt{"traefik.frontend.rule=Host:db.docker.local"}
\item \texttt{"traefik.port=80"}
\item \texttt{"traefik.enable=true"}
\end{itemize}
Using the labels shown above, traefik can identify the containers and route
incoming request to ``db.docker.localhost" or to the corresponding container.
\begin{figure}[h!]
\centering
\begin{forest}
for tree={draw, s sep+=0.25em}
[traefik
[NFW1]
[NFW2]
[NFW3]
]
\end{forest}
\caption{Visual representation of a load-balancer (Traefik) handling incoming connections to multiple containers}
\end{figure}
It is important to realize, that in this case, there is no need to establish a
communication channel in between the nodes. This is the case during the process
of simulating the Clusters (\vref{subsec:simulatingclustering} ).

179
docs/generieren.tex

@ -1,179 +0,0 @@
\section{Generieren}
Das Generieren der Statischen Punkt Wolke aus der die Galaxie abstrahiert wird
ist ein wichtiger Bestandteil des Gesamtprojektes, denn alles baut auf ihr auf.
Kurz: um Kräfte zwischen Sternen zu berechnen braucht man erstmal Sterne!
\subsection{Das Navarro-Frenk-White Profil}
Das Navarro-Frenk-White Profil (NFW-Profil) ist ein Profil das genutzt wird, um
die Räumliche Massen Verteilung von dunkler Materie anhand von Halos die in
N-Körper Simulationen simuliert wurden, zu generieren. Das NFW-Profil kann
jedoch auch genutzt werden um die Massen Verteilung von Sternen darzustellen.
Das Profil generiert für einen gegebenen Abstand \( r \) zum Mittelpunkt der
Galaxie eine Wahrscheinlichkeit \( \rho \). Die Funktion sieht dabei wie folgt aus:
NFW
\begin{equation} \label{eq:NFW_profile}
\rho_{NFW}(r) = \frac{ 1 }{ \sqrt{ 2 \pi } \cdot \sigma } \cdot
\exp \left( \frac{ -\phi(r) }{ \sigma^{ 2 } } \right)
\end{equation}
\begin{equation*}
\phi(r) = \frac{ 4\pi \cdot G \cdot f_{0} \cdot R_{s}^3 }{ r } \cdot
ln{ \left( 1 + \frac{ r }{ R_{s} } \right) }
\end{equation*}
Es kann nun mithilfe der Random-Sampling Methode (\ref{subsec:random_sampling})
ermittelt werden, ob ein Stern beibehalten wird oder nicht.
\par Möchte man nun herausfinden wie weit ein Punkt mit der Koordinate \(
(x_{1}, x_{2}, x_{3} \) vom Mittelpunkt des Raumes entfernt ist, kann der Satz
des Pythagoras (\ref{eq:pythagoras}) verwendet werden.
\begin{equation} \label{eq:pythagoras}
r_{3} = \sqrt{x_{1}^{2} + x_{2}^{2} + x_{3}^{2} }
\end{equation}
Der Abstand \( r_{3} \) zum Mittelpunkt des Raumes kann nun in das NFW-Profil
(\ref{eq:NFW_profile}) gegeben werden um einen Wert \( s \) zu ermitteln welcher
beim Random Sampling verwendet wird:
\begin{equation}
\rho_{NFW}(r) = \dots = s
\end{equation}
Dieser Wert \( s \) stellt die Wahrscheinlichkeit dar, das ein Stern der
eine Entfernung \( r \) vom Mittelpunkt der Galaxie besitzt existiert.
Die Galaxie sieht aus der Ferne jetzt jedoch aus wie ein Würfel, da die aus \(
\rho_{NFW_{1}} \) resultierende Kurve abrupt endet. Dies kann gelöst werden,
indem statt \( \rho_{NFW_{1}}(r) \) folgendes gerechnet wird: \(
\rho_{NFW_{1}}(r) - \rho_{NFW_{1}}(r_{max}) = \rho_{NFW_{2}}(r)\)
\paragraph{Veranschaulichung:}~\\
\begin{center}
\begin{tikzpicture}
\draw[very thin, color=lightgray, step=5mm] (-0.9, -0.9) grid (3.9, 2.4);
\draw[->] (-1,0) -- (4,0) node[right] {$x$};
\draw[->] (0,-1) -- (0,2.5) node[above] {$y$};
\draw[scale=0.5, domain=0.25:6.5, smooth, variable=\x, black] plot ({\x},{(1/\x) + 1}) node[above] {$\rho_{NFW_{1}}(x)$};
\draw[scale=0.5, domain=0.25:6.5, smooth, variable=\x, black] plot ({\x},{1/\x}) node[below] {$\rho_{NFW_{2}}(x)$};
\end{tikzpicture}
\end{center}
Problematisch ist hierbei die Tatsache, dass aufgrund der Verschiebung die
Anzahl der Sterne die in Relation zu dem Bereich in dem sie generiert werden
sehr stark sinkt.
\subsection{Random Sampling} \label{subsec:random_sampling}
\begin{equation}\label{range:psi}
\psi = [ \rho(r_{min}); \rho(r_{max}) ]
\end{equation}
Sei \( s \) ein zufälliger Wert im Intervall \( \psi \). Generiert man nun
einen zufälligen Wert \( r \) im Intervall \( \psi \), kann man schauen ob \( s
> r \lor s < r \) gilt. Ist \( r
> s \), wird der Stern verworfen, ist \( r < s \) wird der Stern behalten.
\paragraph{Veranschaulichung:}~\\
\begin{center}
\begin{tikzpicture}
% draw the background grid
\draw[very thin, color=lightgray, step=5mm] (-0.9, -0.9) grid (3.9, 2.4);
% draw the x-ticks
\draw[xshift=0cm](0.5cm, 1pt) -- (0.5cm, -3pt) node[anchor=north] {$r_{1}$};
\draw[xshift=0cm](1.5cm, 1pt) -- (1.5cm, -3pt) node[anchor=north] {$r_{2}$};
% draw the y-ticks
\draw[yshift=0cm](1pt, 0.5cm) -- (-3pt, 0.5cm) node[anchor=east] {$p(r_{1})$};
\draw[yshift=0cm](1pt, 1.0cm) -- (-3pt, 1.0cm) node[anchor=east] {$p(r_{2})$};
% draw the dotted lines connecting the point s_1
\draw[thick, dotted] (0.5, 0) -- (0.5, 0.5);
\draw[thick, dotted] (0, 0.5) -- (0.5, 0.5);
% draw the dotted lines connecting the point s_2
\draw[thick, dotted] (0, 1.0) -- (1.5, 1.0);
\draw[thick, dotted] (1.5, 0) -- (1.5, 1.0);
% draw the axes
\draw[->] (-1,0) -- (4,0) node[right] {$r$};
\draw[->] (0,-1) -- (0,2.5) node[above] {$\psi$};
% draw the plot
\draw[scale=0.5, domain=0.25:6.5, smooth, variable=\x, black]
plot ({\x},{(1/\x) + 1}) node[above] {$\rho_{NFW_{1}}(x)$};
% draw the points
\fill (0.5, 0.5) circle (0.05) node[above] {$s_1$};
\fill (1.5, 1) circle (0.05) node[above] {$s_2$};
\end{tikzpicture}
\end{center}
In der obigen Abbildung ist zu sehen wir zwei zufällige Punkte \( s_1 \) und \( s_2 \)
generiert wurden.
Angenommen es wurde ein Stern generiert für den nach Formel
(\ref{eq:pythagoras}) gilt: \( r = \sqrt{x_{1}^{2} + x_{2}^{2} + x_{3}^{2}} =
\dots = r_1 \). Es wird dann ein Zufälliger Wert \( p(r_2) \) im in
(\ref{range:psi}) definierten Intervall generiert. Die folgenden zwei Fälle
können dann eintreten und werden wie in (\ref{cases:random_sampling})
abgehandelt.
\kern-1em
\begin{equation}\label{cases:random_sampling}
\begin{cases}
s_1 \leq NFW(r_1) & \rightarrow \text{Stern wird beibehalten}\\
s_1 > NFW(r_1) & \rightarrow \text{Stern wird verworfen}
\end{cases}
\end{equation}
\subsection{Lookup Tabellen}
Statt nun für jeden Stern die Distanz des jeweiligen Sternes \( r \) in das
NFW-Profil (\ref{eq:NFW_profile}) einzusetzen, kann das NFW-Profil im vorhinein
berechnet werden. Es wird dabei eine Tabelle erstellt in der die Entfernung des
Sternes zum Mittelpunkt der Galaxie der jeweiligen Wahrscheinlichkeit
zugeordnet wird:
\begin{center}
\begin{tabular} {l | l}
\( r_n \quad n \in \mathbb{N} \) & \( \rho_n \quad n \in \mathbb{N} \) \\ \hline\hline
\( r_1 \) & \( \rho_1 \) \\ \hline
\( r_2 \) & \( \rho_2 \) \\ \hline
\( r_3 \) & \( \rho_3 \) \\ \hline
\( \dots \) & \( \dots \) \\ \hline
\( r_n \) & \( \rho_n \) \\
\end{tabular}
\end{center}
Die Tabelle kann jedoch nicht so genaue Ergebnisse liefern wie das NFW-Profil,
sie kann jedoch so angepasst werden, dass sie in den Arbeitsspeicher passt und
somit das NFW-Profil so genau wie möglich widerspiegelt und das Generieren
stark verbessert. Mit genügend Arbeitsspeicher ist der Fehler dann auch
vernachlässigbar. Ein Kritischer Faktor, der beachtet werden muss wenn
Lookuptabellen genutzt werden, ist die Geschwindigkeit des jeweiligen
Speichermediums. Nutzt man z.B. Eine sehr langsame Festplatte kann es mehr
Sinne machen die jeweiligen Werte direkt zu berechnen. Dagegen ist eine
schnelle SSD (Solid-State-Drive) um einiges schneller.
TODO: Versuchsreihe.
\subsection{Beschleunigung der Generierung}
Es existieren mehrere Möglichkeiten die Generierung der Punkte zu verbessern.
Eine gute Möglichkeit ist die Nutzung von mehr Rechenleistung. Bei der Nutzung
von \( n \) mal sovielen Rechen kernen ist das Generieren von Sternen \( n \)
mal schneller. Die Server des Server-Hosters Hetzner können dabei gut
verwendet werden: Es wird stündlich abgerechnet und 32 Kerne mit 128 GB RAM
kosten \( \approx \) 50ct/h was es ermöglicht für einen vergleichsweisen
Günstigen Preis, sehr viele Koordinaten zu generieren.
Die Ausgabe von jeder Potentiellen Koordinate in die Kommandozeile verlangsamt
die Generierung unglaublich stark, da der Rechner darauf wartet das die Ausgabe
fertig ist bevor er mit der nächsten Rechnung beginnt was zu einer relativ
starken Verlangsamung der Generierung führt.

2
docs/images/galaxy_network.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 28 KiB

7
docs/introduction.tex

@ -0,0 +1,7 @@
\section{Introduction}
Simulating Galaxies seems impossible to anyone without the appropriate
knowledge, but with a bit of patience, it can be done. This is a short
comprehensive overview of how it works and what can be done to improve the
runtime of the software used, making the simulation of galaxies more accessible
to people without multimillion dollar supercomputers.

3
docs/quellenliteraturverzeichniss.tex

@ -1,3 +0,0 @@
\section{Quellen und Literaturverzeichnis}
THE INTERNET!

11
docs/results.tex

@ -0,0 +1,11 @@
\section{Results}
The generation has gotten a lot faster since 2017/2018: The Ability to scale
the amount of cores used over the maximum amount of cores in one physical
machine makes many of the concepts I used before to get results faster
obsolete. My final goal to simulate a spiral galaxy is not that far away
anymore: calculating the forces acting in between all the stars in a galaxy
with \( n \) stars hat decreased from \( O(n) \) to \( O(n \log(n) \). This
means that in a galaxy with \( 10000 \) stars, the overall force acting on
every star in that galaxy can be calculated using only about \( 10^5 \)
calculations and not \( 10^8 \)!

505
docs/simulating.tex

@ -0,0 +1,505 @@
\section{Simulating}
\subsection{Definition of a galaxy}
``A galaxy is a gravitationally bound system of stars, stellar remnants,
interstellar gas, dust, and dark matter."
\footnote{\url{https://en.wikipedia.org/wiki/Galaxy/}}
A galaxy is therefore a space filled with objects that influence one another by
their gravitational force. In order to simulate a galaxy, we can use the point
cloud we generated before (section \vref{sec:generate}) and calculate the forces
acting in between all of the points. We need to modify the points in the point
cloud a bit to be able to abstract them as stars, but this is not a big
problem. The real problems that arise are much worse:
\begin{itemize}
\item The amount of stars in a real galaxy is too big, calculating all the
forces acting in between them gets problematic quickly: (The amount of
calculations needed to calculate the forces acting in between all the stars in
a given galaxy with \(n\) stars lies in \(O(n)\)).
\item Simply calculating the forces acting in between all of the stars is
just not enough, the whole galaxy must be rotated for keeping it stable.
\end{itemize}
\subsection{Calculating the acceleration acting on a star}\label{subsec:calcacceleration}
Calculating the acceleration acting on a star can be done in the following way:
\begin{equation} \label{eq:beschleunigung}
a = G \cdot \frac{\Delta{M_2}}{\Delta{r}^2}
\end{equation}
\begin{equation*}
G = 6.674 \cdot 10^{-11} N \cdot kg^{-2} \cdot m^2
\end{equation*}
\( G \) stands for the Gravitational
Constant\footnote{\url{https://en.wikipedia.org/wiki/Gravitational_constant}},
\( \Delta M \) for the mass of the object that is orbited and \( \Delta r \)
for the distance between the object and the object being orbited. The problem
is, that a star does not orbit around a massive object, but a cluster of loose
objects. This makes it impossible to use the method above to calculate the
acceleration acting on the star.
\subsubsection{Calculating the combined forces acting on a star}
In order to use the Equation \ref{eq:beschleunigung}, it needs to be rebuilt
using vectors in the following way:
\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}
The sum of all forces acting in between a star \( a \) and all other stars in that cluster
is the overall force acting on that star:
\begin{equation} F_{a} = \sum_{\substack{i=0\\i\neq a}}^{n} F_{ai} \end{equation}
\subsubsection{Calculation of the orbital speed}
Normally, the orbital speed can be calculated by equating the force pulling
the stars to the midpoint of the galaxy through gravity \( \left( F_g = G \cdot
\frac{m \cdot M}{r^2} \right) \) and the centripetal force \( \left( F_z =
\frac{m \cdot v^2}{r} \right)\):
\begin{equation}
v = \sqrt{\frac{G \cdot M_{\odot}}{r}}
\end{equation}
\begin{equation*}
M_{\odot} = 5.972 \cdot 10^{24}
\end{equation*}
\begin{equation*}
G = 6.674 \cdot 10^{-11} N \cdot kg^{-2} \cdot m^2
\end{equation*}
The same problem as in \ref{subsec:calcacceleration}, there is no \( M_{\odot}
\) we could orbit around.
\subsection{Problems that need to be solved}
One of the main problems that arises is the growth of the amount of
calculations needed in comparison with the amount of stars in the cluster.
Assuming a cluster contains \( n \) stars, the amount of calculations needed to
calculate the forces in between all the stars in the cluster is in \( O(n^2)
\). This might not seem to be a big problem, but when simulating bigger
galaxies, every new star adds a lot of calculations to the complete amount.
Solving this is done by subdividing the cluster into recursive
octrees\footnote{\url{https://en.wikipedia.org/wiki/Octree}} and using the
Barnes-Hut
algorithm\footnote{\url{https://en.wikipedia.org/wiki/Barnes-Hut_simulation}}
(\ref{subsubsec:barneshut}) on that tree.
\subsection{Trees}
Trees are an important for decreasing the calculations needed to calculate all
the forces acting inside of the galaxy. Generating them and inserting stars has
to be done correctly and with some special conditions in order to make them
usable.
\subsubsection{Generating trees}
Before starting to generate Quadtrees, the components the tree is built out of
must be defined. A node in the tree needs to mainly store a star and \(n\)
other sub trees\footnote{The amount of sub trees is not static making it easier
to switch in between multidimensional trees: a 2 dimensional tree needs 4
sub trees, a 3 dimensional tree needs 8.}.
\begin{figure}[!h]
\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{Subdivision of a 2D Galaxy into multiple cells}
\label{fig:cells}
\source{Adapted from COS126: Barnes-Hut Galaxy Simulator (2003)}
\end{figure}
In order to generate a tree from a galaxy as the one seen in figure
\ref{fig:cells}, the stars need to be inserted into an empty tree one by one.
This is depicted in figure \ref{fig:simpletree}.
\begin{figure}[!h]
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[
[A]
[
[
[]
[B]
[C]
[]
]
[]
[]
[D]
]
[
[]
[E]
[F]
[G]
]
[H]
]
\end{forest}
\caption{The stars from the star cluster depicted in figure \ref{fig:cells} inserted into a Quadtrees one by one}
\label{fig:simpletree}
\end{figure}
Inserting all the stars into a tree can be optimized by not only storing the
stars' coordinate and the sub trees in a node, but also other information such
as the total combined mass of the stars in the current node and the stars in
its sub trees, the center of mass of a node and all of its children, the depth
of the current node in the tree, whether the node is a leaf or not and various
other properties. They can be found out dynamically, but having a place to
store them makes some operations such as calculating the forces in between a
star and a cluster of star a lot easier to handle.
\subsubsection{Inserting stars into a tree}
Inserting a list of stars into a tree is done by inserting all the stars into
the tree one by one. This works fine for the first star, but because of the
rule that all the stars must be inside a leaf node, the seconds star that
should be inserted already creates a problem: The node into which it should be
inserted is all ready blocked by another star, so the star cannot be inserted.
The solution to this is to insert the existing star into its sub tree and then
insert the new star into the tree. Is the problem still arises, the process is
repeated.
\begin{figure}[h!]
\subfloat[Initial condition. The star B should be inserted into the tree in which A is allready inside of.]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[,phantom
[B]
[
A
[]
[]
[]
]
]
\end{forest}
\label{subfig:initialposition}
}
\hfill
\subfloat[The star B cannot be inserted, so the star A gets inserted into it's subtree making the slot in which B should be inserted free.]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[,phantom
[B]
[
[A
[]
[]
[]
]
[]
[]
]
]
\end{forest}
\label{subfig:ashiftdown}
}
\hfill
\subfloat[The star B can now be inserted, but because it is not inside of a leaf, it needs to be inserted into its subtree.]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[,phantom
[B
[A
[]
[]
[]
]
[]
[]
]
]
\end{forest}
\label{subfig:binsert}
}
\hfill\\[2ex]
\subfloat[Inorder to insert the star B into its subtree, the star A must be inserted into its subtree to make place for B.]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[B
[
[A
[]
[]
[]
]
[]
[
[]
[]
[]
]
]
[]
[]
]
\end{forest}\quad
\label{subfig:ashiftdowntwo}
}
\hfill
\subfloat[B can now be inserted into the tree, first into the place that was occupied by A in \ref{subfig:binsert} and then into its subtree.]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[
[
[A
[]
[]
[]
]
[]
[B
[]
[]
[]
]
]
[]
[]
]
\end{forest}\quad
\label{subfig:bshiftdowndouble}
}
\caption{Inserting a star into a tree in which a star is all ready present.}
\label{fig:insertwithexisting}
\source{Adapted from COS126: Barnes-Hut Galaxy Simulator (2003)}
\end{figure}
The complete process can be seen in figure \ref{fig:insertwithexisting}. The
goal is to insert the Star be into a tree, in which a star A is all ready
inside the root node (\ref{subfig:initialposition}). The first step is to
insert the star A into the correct node as seen in (\ref{subfig:ashiftdown}).
The root node is now free, so the star B can be inserted there, but it is still
not inside of a leaf (\ref{subfig:binsert}). Let's assume that B has to be
inserted into the node in which A is in. Because A is all ready inside the
node, A needs to be shifted down into its sub tree
(\ref{subfig:ashiftdowntwo}). The next step is a combination of two: first, B
gets shifted down one layer into the tree and because the next slot B should be
shifted into is free, B can directly get shifted into there as seen in
(\ref{subfig:bshiftdowndouble})
\subsubsection{Applying the Barnes-Hut Algorithm} \label{subsubsec:barneshut}
The Barnes-Hut algorithm can be used to evaluate which forces should be
calculated. In order to do this, one must know the boundary size of every node
in the tree. The boundary of a cell is defined by the midpoint of the cell and
its width, so the biggest mounding box containing the complete galaxy is
defined by (0, 0) and the width of the galaxy. The Barnes-Hut algorithm
defines that a cluster of stars sufficiently far away with a bounding box small
enough can be abstracted as a single stars.
\begin{figure}[!h]
\centering
\subfloat[A cluster of stars]{
\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{fig:ungrouped}
}
\hfill
\subfloat[The abstraction from figure \ref{fig:ungrouped} to a single star]{
\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{fig:grouped}
}
\caption{Visual representation of how the Barnes-Hut algorithm works. The
cluster of stars in \ref{fig:ungrouped} gets abstracted into the single star
\(q_1\) as seen in figure \ref{fig:grouped}}
\label{fig:barneshutsimple}
\source{https://de.wikipedia.org/wiki/Barnes-Hut-Algorithmus}
\end{figure}
The Barnes hut algorithm states that star clusters that are packed in a
sufficient way and are sufficiently far away some other star can be abstracted to
a single star. This is mathematically defined in the following way:
\begin{equation}
\theta = \frac{d}{r}
\end{equation}
Using this function, we can set \( \theta \) to a fixed value and use it as a
threshold for deciding if the force in between a star and a cluster should be
calculated or not. As en example, we consider the figure
\ref{fig:barneshutsimple}. If a cluster of stars is very far away from the star
\( s_1 \) and the size of the cluster \(d\) is small enough, \(\theta\) gets
very small, possibly below the threshold meaning we can combine all the stars in
the bounding box and abstract them to a single one. On the opposite, if a
cluster of stars is very close to the star \( s_1 \) and the bounding box is
very big, \(\theta\) gets very big and gets over the threshold.
[INSERT the section explaining how to find an appropriate theshold here]
Considering the tree from figure \ref{fig:simpletree}, if the forces acting
in between the star F and all other stars should be calculated, the algorithm
walks through the complete tree and tries to get as deep as possible into the
tree. In the first case, the node A is reached and the force A is acting on F is
calculated. In the second case, the algorithm can dive deeper into the tree and
as it reaches the parent node of the two stars B and C, the distance to the
stars gets very big and the bounding box in which B and C are located gets
smaller, so small that \( \theta \) gets under the predefined threshold meaning
the bounding box in which B and C are can be abstracted as a single star whose
position is the mean position of all stars in the sub tree weighted by the mass
of the stars and it's mass is the mean mass of all stars in the sub tree.
This can all be seen in figure \ref{fig:cells} a bit more easy.
\subsection{Simulating a cluster}\label{subsec:simulatingclustering}
The simulation works in a pure brute force way: the forces in between every star
and every other star is calculated:
\begin{figure}[h!]
\begin{lstlisting}
// initialize a vector storing the force
var f Vec2{}
// iterate over all stars
for i in range(0, n):
for j in range(0, n):
// calculate the force acting
f += Forces(stars[i], stars[j])
\end{lstlisting}
\caption{Calculating the force acting on a star using a Brute-Force method}
\label{fig:bruteforce}
\end{figure}
Calculating the forces exerted on j by i:
\begin{equation}
F_{ji} = \underbrace{G \cdot \frac{m_i m_j}{|s_j - s_i|^2}}_{Scalar} \cdot \underbrace{\frac{s_j - s_i}{|s_j - s_i|}}_{Vector}
\end{equation}
\begin{equation}
F_j = \sum_{i=0}^{n} G \cdot \frac{m_i m_j}{|s_j - s_i|^2} \cdot \frac{s_j - s_i}{|s_j - s_i|}
\end{equation}
This is optimized using the Barnes-Hut Algorithm by recursively iterating over
the tree.
The figures \ref{lst:calcallforces} and \ref{lst:calcforce} on page \pageref{lst:calcforce} describe how the forces are calculated.
\begin{figure*}[!h]
\begin{lstlisting}[breaklines=true]
// calcAllForces recursively iterates over all the sub trees and calculates the forces acting on the stars according to the rules defined in the Barnes-Hut Algorithm
func (q tree) calcAllForces(theta float64) {
for subtree in q.subtrees{
// If the subtree contains a star, calculate the forces acting on that star
if subtree.Star != (Star{}) {
q.subtree.calcForces(star, theta)
// In any other case, try to recurse deeper into the tree
} else {
q.subtree.calcAllForces(theta)
}
}
}
\end{lstlisting}
\caption{A go function calculating the forces acting in between all the stars in a given tree representing a galaxy}
\label{lst:calcallforces}
\end{figure*}
\begin{figure*}[!h]
\begin{lstlisting}[breaklines=true]
// calcForces calculates the forces acting on a star by calculating the forces in between it an all the other stars in the tree the method is called on.
func (q tree) calcForces(star Star, theta float64) Vec {
force := Vec{}
// Iterate over all the sub trees connected to the current node
for subtree in q.subtrees {
// If the subtrees contains a star, calculate the forces
if subtree.Star != (Star{}) {
force = Force(star, subtree.star)
// if the subtree is sufficiently far away from the star, calculate the forces acting on the sub cluster of stars
} else if subtree.Theta(star) < theta {
force = Force(star, subtree)
// in any other case, recursively iterate deeper into the tree
} else {
force = subtree.calcForces(star)
}
}
return force
}
\end{lstlisting}
\caption{A go function calculating the forces all the stars in a tree are acting on a star}
\label{lst:calcforce}
\end{figure*}

486
docs/simulieren.tex

@ -1,486 +0,0 @@
\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{<