Compare commits

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

21 Commits

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

2
docs/darstellung.tex

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

17
docs/einleitung.tex

@ -1,14 +1,13 @@
\section{Einleitung}
Das Projekt ist nach meinem vorletzten Jugend-Forscht Projekt entstanden: Ich
habe ein Praktikum in Astronomischen Rechen Institut in Heidelberg genutzt, um
Dieses Projekt ist nach meinem vorletzten "Jugend Forscht"-Projekt entstanden: Ich
habe ein Praktikum im Astronomischen Recheninstitut 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
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
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.
war das Einbauen der Nutzung von mehreren Threads vergleichsweise einfach.

93
docs/entwickeln.tex

@ -0,0 +1,93 @@
\section{Entwickeln der nötigen Software}
Die Software habe ich initial in Python\footnote{\url{https://www.python.org/}}
geschrieben, als sie jedoch größer wurde beschloss ich auf die
Programmiersprache Go\footnote{\url{https://golang.org/}} umzusteigen. Die
komplette Software ist in einzelne mithilfe von Docker containerisierten
Micro Services aufgeteilt welche untereinander mithilfe von APIs kommunizieren.
Durch diese starke Unterteilung ist das Skalieren kein Problem mehr und die
Software kann theoretisch auf der kompletten Welt verteilt auf mehreren PCs
laufen, jedoch auch auf einer Maschine.
Die Generelle Verbindung der einzelnen Dienste kann in Abbildung
\ref{fig:loadbalancergenerator} gesehen werden
\subsection{Docker Container}
\subsubsection{Manager}
Der Manager Container ist der Container mit dem der User interagiert. Er
steuert beide Teile der Software: Generieren und Simulieren.
\subsubsection{Database}
Die Datenbank speichert alle generierten Galaxien in der Form von Bäumen und
ermöglicht es den anderen Container über eine Api auf die Bäume zuzugreifen.
Die bereitgestellte API hat folgende Endpunkte:
\begin{tabular}{l l}
/new & Erstellt einen neuen Baum \\
/printall & Zeigt alle Bäume and (json) \\
/insert/\{treeindex\} & Fügt einen Stern ein \\
/starlist/\{treeindex\} & Listet alle Sterne (json) \\
/dumptree/\{treeindex\} & Zeit einen Baum an (json) \\
\end{tabular}
\subsubsection{Generator}
Der Generator Container steuert die NFW Container und erstellt zufällige Werte.
\subsubsection{NFW}
Der NFW Container gibt den entsprechenden Wert aus der NFW Funktion zurück,
nachdem er einen Stern erhalten hat.
\subsubsection{Simulator}
Der Simulations Container bekommt Sterne und verteilt diese auf die Simulations
Container. Diese haben jeweils eine lokale Kopie der Datenbank um nicht die
Datenbank zu stark zu belasten. Nachdem die Simu Container einen Stern
erhalten haben berechnen sie die Kräfte die auf die Sterne wirken und fügen die
Sterne in ihre neue Position in einen neuen Baum ein.
\subsubsection{Traefik} \label{subsubsec:traefik}
Der Traefik Container fungiert als Last verteilugs container, d.h. er verteilt
die einkommenden Anfragen an die jeweiligen Container und sendet die antworten
entsprechend an die richtigen Adressen zurück. \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{Visuelle Darstellung des Systems}
\label{fig:loadbalancergenerator}
\end{figure}

20
docs/ergebnisse.tex

@ -1,15 +1,11 @@
\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
Die Generierung ist dank der Containerisierung sehr stark verbessert. Dadurch,
dass das System im Prinzip auf unendlich viele Server skaliert werden kann,
sind der Generierung keine Grenzen mehr gesetzt. Ich bin somit meinem Finalem
Ziel Spiralgalaxien zu simulieren wieder stark näher gekommen. Die Möglichkeit
Cluster mit einer Laufzeit\footenote{Die Laufzeit wird mithilfe von
Landau-Symbolen \url(https://de.wikipedia.org/wiki/Landau-Symbole)} dargestellt in
\( O(n \log(n) \) statt in \( O(n^s) \) zu simulieren. Dadurch werden in
einer Galaxie statt \( 10^8 \) nur \( 10^5 \) Kräfte berechnet.

258
docs/generieren.tex

@ -1,17 +1,13 @@
\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!
\section{Generieren} \label{sec:generate}
Die Generation einer statischen Punkt Wolke aus der eine Galaxie abstrahiert
werden kann ist ein wichtiger, wenn nicht unerlässlicher Aspekt um das Projekt
nutzen zu können, da alle anderen Module darauf aufbauen
\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
Die Dichte Verteilungsfunktion die genutzt wird heißt Navarro-Frenk-White profil
(NFW-profil). Die Funktion wird dazu genutzt um herauszufinden wie
wahrscheinlich es ist, dass ein Stern mit einem Abstand \( r \) zum Mittelpunkt
der Galaxie existiert. Das Profil ist wie folgt definiert:
\begin{equation} \label{eq:NFW_profile}
\rho_{NFW}(r) = \frac{ 1 }{ \sqrt{ 2 \pi } \cdot \sigma } \cdot
@ -23,116 +19,111 @@ NFW
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.
Die Funktion kann nun mithilfe der Randow Sampling Methode
(\ref{subsec:random_sampling}) genutzt werden um herauszufinden ob ein Stern
existiert 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.
Um herauszufinden, ob ein Stern mit den Koordinaten \(x_1, x_2, x_3\)
existiert, muss die Entfernung zum Mittelpunkt der Galaxie mithilfe vom Satz
des Pythagoras berechnet werden:
\begin{equation} \label{eq:pythagoras}
r_{3} = \sqrt{x_{1}^{2} + x_{2}^{2} + x_{3}^{2} }
r = \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:
Die Distanz \( r \) zum Mittelpunkt der Galaxie wird nun in das NFW-Profil
(\ref{eq:NFW_profile}) eingesetzt wodurch der Wert \( s \) berechnet 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)\)
Der Wert \( s \) definiert die Wahrscheinlichkeit, dass ein Stern mit der
Distanz \( r \) zum Mittelpunkt der Galaxie Existiert.
\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}
\subsection{Random Sampling} \label{subsec:random_sampling}
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.
Um herauszufinden, ob ein Stern existiert oder nicht, wird der im NFW-Profil
berechnete Wert \( s \) mithilfe der Radom Sampling Method verarbeitet.
\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.
Angenommen \( s \) ist in dem Intervall \( \psi \), dann wird ein Zufälliger
Wert \( u \) im Intervall \( \psi \) generiert. Wenn \( s > u \) wahr ist, dann
wird der Stern behalten, in jedem anderem Fall \( s \leq u \) wird der Stern
verworfen.
\paragraph{Veranschaulichung:}~\\
\subsubsection{Abbildung}
\begin{center}
\begin{figure}[!h]
\centering
\subfloat[Der Stern wird generiert, da die Bedingung \( u < \rho(s_1) \) wahr ist]{
\centering
\begin{tikzpicture}
% draw the background grid
\draw[very thin, color=lightgray, step=5mm] (-0.9, -0.9) grid (3.9, 2.4);
\draw[very thin, color=lightgray, step=5mm] (-0.9, -0.9) grid (2.9, 2.9);
% 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 axes
\draw[->] (-1,0) -- (2.5,0) node[right] {$r$};
\draw[->] (0,-1) -- (0,3) node[above] {};
% 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 plot
\draw[scale=0.5, domain=0.21:5, smooth, variable=\x, black]
plot ({\x},{(1/\x) + 1}) node[above] {$\rho(x)$};
% 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 points
\fill (1, 0.4) circle (0.05) node[right] {\(u\)};
\fill (1, 0.75) circle (0.05);
% 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 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[Der Stern wird nicht generiert, da die Bedingung \( u < \rho(s_1) \) falsch ist]{
\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) -- (4,0) node[right] {$r$};
\draw[->] (0,-1) -- (0,2.5) node[above] {$\psi$};
\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.25:6.5, smooth, variable=\x, black]
plot ({\x},{(1/\x) + 1}) node[above] {$\rho_{NFW_{1}}(x)$};
\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 (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}
\fill (1, 2.0) circle (0.05) node[right] {\(u\)};
\fill (1, 0.75) circle (0.05);
In der obigen Abbildung ist zu sehen wir zwei zufällige Punkte \( s_1 \) und \( s_2 \)
generiert wurden.
% draw the x-tick
\draw[xshift=0cm](1, 1pt) -- (1, -3pt) node[anchor=north] {$r_{1}$};
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.
% 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{Funktions Graphen, welche die zwei möglichen Resultate darstellen}
\end{figure}
\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}
s_1 \leq \rho(r_1) & \rightarrow \text{Der Stern wird behalten }\\
s_1 > \rho(r_1) & \rightarrow \text{Der 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
@ -161,8 +152,6 @@ 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.
@ -177,3 +166,106 @@ 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.
\subsection{Cluster}
Um das Generator Modul einfach zu skalieren kann Docker
\footnote{\url{https://docker.com}} verwendet werden. Docker bietet eine einfache
Schnittstelle, um Virtualisierung auf Betriebssystemebene mithilfe von
Containern zu implementieren.
\begin{figure*}
\centering
\subfloat[Das Projekt mithilfe von Virtuellen Maschinen containerisiert]{
\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 Betriebssystem
[Hypervisor
[Gast OS
[Bib.
[NFW1]
]
]
[Gast OS
[Bib.
[NFW2]
]
]
[Gast OS
[Bib.
[NFW3]
]
]
]
]]
\end{forest}
}
\subfloat[Das Projekt mithilfe von Docker containerisiert]{
\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 Betriebssystem
[Hypervisor
[Bib.
[NFW1]
]
[Bib.
[NFW2]
]
[Bib.
[NFW3]
]
]
]]
\end{forest}
}
\caption{Die zwei Beispiele zeigen verschiedene Methoden der Containerisierung}
\end{figure*}
Durch Nutzung dieses Konzeptes können einfach einzelne Dienste gebaut werden,
die über http APIs untereinander Kommunizieren können. Dies ermöglicht es auch,
mehrere Container über einen Reverse-Proxy wie z.B.
Traefik\footnote{\url{https://traefik.io/}}. Traefik selber ist ein
Docker-Container was die Einrichtung sehr vereinfacht und kann automatisch
andere markierte Container erkennen und verwalten. Die folgenden Markierungen
können z.B. genutzt werden um eine Datenbank anzusteuern:
\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}
Durch die aufgelisteten Markierungen kann Traefik die Container erkennen und
eingehende Anfragen entsprechend weiter routen.
\begin{figure}[h!]
\centering
\begin{forest}
for tree={draw, s sep+=0.25em}
[traefik
[NFW1]
[NFW2]
[NFW3]
]
\end{forest}
\caption{Eingehende Anfragen an Traefik werden automatisch an entsprechend gelabelte Container weitergeleitet}
\end{figure}
Es ist in Szenario in dem einzeln Container untereinander nicht
kommunizieren müssen irrelevant eine Verbindung bzw. Netzwerk zwischen den
einzelnen Containern aufzubauen. Dies ist jedoch beim Simulieren nicht der Fall
(\vref{subsec:simulatingclustering} ).

2
docs/images/galaxy_network.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 28 KiB

3
docs/quellenliteraturverzeichniss.tex

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

654
docs/simulieren.tex

@ -1,6 +1,7 @@
\section{Simulieren}
\subsection{Die Entstehung von Galaxien}
\subsection{Spezifikation einer Galaxie}
``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}}
@ -14,215 +15,160 @@ 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:
Dabei entstehen folgende Probleme:
\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}
\begin{itemize}
\item Die Anzahl an Sterne in einer echten Galaxie ist zu groß, die Kräfte
welche zwischen allen Sternen wirken zu berechnen wird schnell problematisch.
Die Laufzeit eines Brute-Force Algorithmus um die Kräfte in einer Galaxie mit
\( n \) Stern zu berechnen liegt in \( O(n) \).
\item Die Galaxie muss rotiert werden, damit sie nicht implodiert
\end{itemize}
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:
\subsection{Die auf einen Stern wirkenden Beschleunigungen berechnen}\label{subsec:calcacceleration}
\begin{equation} F_{a} = \sum_{i=0}^{n-1} F_{ai} \end{equation}
Um die Beschleunigung eines Sternes zu berechnen kann folgende Formel verwendet werden:
\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}}
\begin{equation} \label{eq:beschleunigung}
a = G \cdot \frac{\Delta{M_2}}{\Delta{r}^2}
\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*}
G = 6.674 \cdot 10^{-11} N \cdot kg^{-2} \cdot m^2
\end{equation*}
\( G \) steht hierbei für die Universelle Gravitationskonstante
\footnote{\url{https://en.wikipedia.org/wiki/Gravitational_constant}}, \(
\Delta M \) für die Masse des Objekts das umkreist wird und \( \Delta r \) für
den Abstand zwischen dem Objekt und dem Objekt das umkreist wird. Das Problem
hierbei ist, dass ein Stern nicht um ein anderes stellares Gebilde herum
kreist, sondern um ein Cluster aus losen stellaren Objekten. Es ist somit nicht
möglich die Formel \ref{eq:beschleunigung} zu nutzen.
\subsubsection{Berechnung der Kombinierten Kräfte die auf einen Stern wirken}
Um die Formel \ref{eq:beschleunigung} zu nutzen, muss sie mit Vektoren neu
aufgestellt werden.
\begin{equation}
\text{Wurzel Knoten} = (0, 0), \text{Breite}=b
\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}
\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}
Die Summe aller Kräfte die zwischen dem Sten \( a \) und allen anderen Sternen
in der Punkt Wolke kann wie folgt berechnet werden:
\begin{equation} F_{a} = \sum_{\substack{i=0\\i\neq a}}^{n} F_{ai} \end{equation}
\subsection{Probleme die gelöst werden müssen}
Eines der Hauptprobleme die auftreten ist die Anzahl an Rechenoperationen die
durchgeführt werden müssen im Verhältnis zu der Anzahl von Sternen in der
jeweiligen Punkt Wolke. Angenommen es befinden sich \( n \) Sterne in der
Punkt Wolke, dann werden um alle Kräfte zu berechnen \( O(n^n) \) Kräfte
berechnet. Um dieses Problem zu lösen wird die Galaxie in rekursive Zellen
unterteilt\footnote{\url{https://en.wikipedia.org/wiki/Octree}} und der
Barnes-Haut
Algorithmus\footnote{\url{https://en.wikipedia.org/wiki/Barnes-Hut_simulation}}
wird anschließend verwendet um die Anzahl an Kräfte Berechnungen zu verringern
(\ref{subsubsec:barneshut}).
\subsection{Bäume}
Bäume spielen eine Wichtige Rolle bei der Verringerung der Anzahl an Kräften
die berechnet werden müssen. Die Generierung von Bäumen und das einfügen von
einzelnen Sternen muss mit entsprechenden regeln durchgeführt werden um zu einem
sinnvollen und nutzbarem Ergebnis zu kommen.
\subsubsection{Bäume generieren}
Bevor ein Baum Generiert wird, müssen seine Komponenten definiert werden. Ein
Baum besteht in diesem Fall aus mehreren Nodes, welche einen Stern und Pointer
zu weiteren Nodes speichert.
\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{Unterteilung einer 2 Dimensionalen galaxie in mehrere Zellen}
\label{fig:cells}
\source{Adapted from COS126: Barnes-Hut Galaxy Simulator (2003)}
\end{figure}
\begin{figure}
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[
[A]
Um einen Baum aus einer Galaxie zu generieren, müssen die Sterne einzeln in
einen anfangs leeren Teilbaum eingefügt werden. Das Ergebnis ist für die
Galaxie aus Abbildung \ref{fig:cells} ist in Abbildung \ref{fig:simpletree} zu
sehen.
\begin{figure}[!h]
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[
[A]
[
[
[]
[B]
[C]
[]
]
[]
[B]
[C]
[]
[D]
]
[]
[]
[D]
]
[
[]
[E]
[F]
[G]
[
[]
[E]
[F]
[G]
]
[H]
]
[H]
]
\end{forest}
\caption{Die in Abbildung \ref{fig:cells} dargestellte Galaxie als Baum
dargestellt}
\end{forest}
\caption{Die Galaxie aus Abbildung \ref{fig:cells} als Baum dargestellt}
\label{fig:simpletree}
\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\).
\subsubsection{Sterne in einen Baum einfügen}
\begin{equation} \label{eq:barnes_hut} \theta = \frac{d}{r} \end{equation}
Um eine Liste an Sternen in einen Baum einzufügen werden die Sterne einzeln in
den jeweiligen Baum eingefügt. Dies funktioniert für den ersten Stern ohne
Probleme, ab dem zweiten Stern kommt es jedoch zu Problemen, z.B. blockiert der
erste Stern die Node in den der Zweite Stern eingefügt werden sollte. Die
Lösung ist also, den Stern der die Node blockiert weiter in seine Kinder
einzufügen. Der Prozess kann in Abbildung \ref{fig:insertwithexisting} visuell
nachvollzogen werden.
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{figure}[h!]
\subfloat[Initiale Bedingung. Der Stern Be soll in die Node in der sich bereits der Stern A befindet eingefügt werden.]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[,phantom
@ -235,9 +181,10 @@ werden.
]
]
\end{forest}
\label{subfig:initialposition}
}
\quad
\subfigure[Stern B kann nicht eingefügt werden, da der Slot durch A belegt ist, also wird A weiter in den Baum versickert.]{
\hfill
\subfloat[ Da B nicht eingefügt werden kann, wird A in seine Kinder versickert wodurch der Platz in der Node frei wird]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[,phantom
@ -253,9 +200,10 @@ werden.
]
]
\end{forest}
\label{subfig:ashiftdown}
}
\quad
\subfigure[B wird nun eingefügt, da sich B jedoch nicht in einem Blatt befinden, muss B weiter versickert werden.]{
\hfill
\subfloat[Der Stern B kann nun eingefügt werden, da er sich dann jedoch nicht in einem Blatt befinden muss er in seine Kinder eingefügt werden]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[,phantom
@ -269,10 +217,11 @@ werden.
[]
]
]
\end{forest}\quad\\[2ex]
\end{forest}
\label{subfig:binsert}
}
\quad
\subfigure[Damit B versickert werden kann, wird der Platz der durch A besetzt wird freigemacht, indem A weiter versickert wird.]{
\hfill\\[2ex]
\subfloat[Damit B in seine Kinder versickert werden kann muss der Stern A ebenfalls wieder versickert werden]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[B
@ -293,9 +242,10 @@ werden.
[]
]
\end{forest}\quad
\label{subfig:ashiftdowntwo}
}
\quad
\subfigure[B kann jetzt in den Baum versickert werden und ist nun ein Blatt.]{
\hfill
\subfloat[B kann nun in den entsprechenen Baum eingefügt werden, erst in den Baum in dem sich in Abbildung \ref{subfig:binsert} A befand und anschließend in den entsprechenen Baum]{
\begin{forest}
for tree={circle,draw, s sep+=0.25em}
[
@ -316,171 +266,185 @@ werden.
[]
]
\end{forest}\quad
\label{subfig:bshiftdowndouble}
}
\caption{Schrittweises einfügen des Sternes B in einen Baum, indem sich bereits ein Stern (A) befindet.} \label{fig:insertwithexisting}
\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}
\begin{lstlisting}
if node.hasstar() {
Der komplette Prozess des Einfügens wird in Abbildung \ref{fig:insertwithexisting} beschrieben.
\subsubsection{Anwendung des Barnes-Hut Algorithmus} \label{subsubsec:barneshut}
Der Barnes-Hut Algorithmus wird genutzt um zu bestimmen welche Kräfte berechnet
werden, bzw. nicht werden. Um dies zu tun müssen die Ausmaße der Zelle jeder
Node in dem Baum in der die Galaxie gespeichert ist bekannt sein. Die Ausmaße
sind durch den Mittelpunkt der Zelle und ihrer Breite definiert. Die Ausmaße
der Zelle die un der Wurzel-Node beschrieben ist ist im Normalfall durch ihren
Mittelpunkt bei \((0, 0)\) und einer Breite die größer als die Breite der
Galaxie ist beschrieben.
\begin{figure}[!h]
\centering
\subfloat[Ein cluster an 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{fig:ungrouped}
}
\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
\hfill
\subfloat[Das Cluster aus Abbildung \ref{fig:ungrouped} zu einem einzelnem Stern zusammengefasst]{
\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{
Visuelle Darstellung der Funktionsweise des Barnes-Hut Algorithmus. Das Cluster
in Abbildung \ref{fig:ungrouped} wird zu einem einzelnem Stern \( q_1 \)
abstrahiert \ref{fig:grouped}.}
\label{fig:barneshutsimple}
\source{https://de.wikipedia.org/wiki/Barnes-Hut-Algorithmus}
\end{figure}
method (Vec2) insert() {...}
method (Vec2) insideOf() bool {...}
func newVec2() Vec2 {...}
\end{lstlisting}
Der Barnes-Hut Algorithmus besagt, das Cluster die weit entfernt vom einem
Stern sind und nicht zu groß sind zusammengefasst werden können. Dies ist
Mathematisch wie folgt definiert:
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{equation}
\theta = \frac{d}{r}
\end{equation}
Durch die Nutzung der Funktion kann ein \( \theta \) berechnet werden, welches
als Schwellwert genutzt werden kann um zu entscheiden ob die Kraft zwischen den
jeweiligen Sternen berechnet werden sollen oder nicht. Als Beispiel kann die
Abbildung \ref{fig:barneshutsimple} genutzt werden. Wenn ein Cluster aus
Sternen sehr weit weg und die Zelle indem sich die Sterne befinden sehr klein
ist, wird \(\theta\) vergleichsweise klein, möglicherweise sogar kleiner als
der vorher definierte Grenzwert. Es ist dann möglich, die Sterne in der Zelle
zusammenzufassen indem die Kraft zwischen \(s_1\) und dem Massenmittelpunkt der
Zelle berechnet wird.
Um den Barnes-Hut Algorithmus auf einem Baum anzuwenden, wird der Baum von der
Wurzel aus rekursiv durchlaufen und es wird für jeden knoten das jeweilige
Theta berechnet, sobald der Schwellwert überschritten wird, arbeitet sich der
Algorithmus nicht weiter in den Baum herein.
\subsection{Simulation eines Clusters}\label{subsec:simulatingclustering}
Die Simulation eines Cluster ohne den Barnes-Hut Algorithmus anzuwenden
funktioniert nach der Brute-Force Methode:
\begin{figure}[h!]
\begin{lstlisting}
type Star struct {
C Vec
V Vec
Mass float64
}
// Iteriere ueber alle sterne
for i in range(0, n):
for j in range(0, n):
method (Vec2) insideOf() bool {...}
// Berechne die jeweilige Kraft
...
\end{lstlisting}
\caption{Berechnung der Kräfte mithilfe der Brute-Force Methode}
\label{fig:bruteforce}
\end{figure}
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.
Die Kraft die der Stern \(j\) auf den Stern \(i\) auswirkt wird folgendermaßen
berechnet:
\begin{lstlisting}
type Boundary struct {
Center Vec
HalfDimension float64
}
\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}
function newBoundary() {...}
\end{lstlisting}
\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}
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.
Die Abbildungen \ref{lst:calcallforces} und \ref{lst:calcforce} auf Seite \pageref{lst:calcforce} beschreiben wie die Kräfte berechnet werden.
\begin{lstlisting}
type QuadTree struct {
StarCount int
Boundary Boundary
Star []Vec2
\begin{figure*}[!h]
\begin{lstlisting}[breaklines=true]
// calcAllForces iteriert rekursiv ueber alle sub-baeume und berechnet die Kraft die alle Sterne auf den gegebenen Stern auswirken
func (q tree) calcAllForces(theta float64) {
for subtree in q.subtrees{
NorthWest *QuadTree
NorthEast *QuadTree
SouthWest *QuadTree
SouthEast *QuadTree
// Falls der sub-Baum einen Sten einhaelt, berechne die wirkende Kraft
if subtree.Star != (Star{}) {
q.subtree.calcForces(star, theta)
}
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}
\caption{Eine go-methode welche die Gesamt kraft die auf einen Stern wirkt berechnet}
\label{lst:calcallforces}
\end{figure*}
\begin{figure*}[!h]
\begin{lstlisting}[breaklines=true]
// calcForce berechnet die Kraft die durch alle anderen Sterne in dem jeweiligem Baum auf den Stern wirkt
func (q tree) calcForces(star Star, theta float64) Vec {
force := Vec{}
for subtree in q.subtrees {
// falls das Kind einen Stern beinhaltet, berechne die Kraft
if subtree.Star != (Star{}) {
force = Force(star, subtree.star)
// falls der theta-wert des kindes klein genug ist, berechne die Kraft zwischen dem Stern und dem Massemittelpunkt
} else if subtree.Theta(star) < theta {
force = Force(star, subtree)
// in jedem anderem Fall, rekursiere weiter in dem Baum hinein
} else {
force = subtree.calcForces(star)
}
}
return force
}
\end{lstlisting}
\caption{Eine go-methode welche die Gesamt kraft die auf einen Stern wirkt berechnet}
\label{lst:calcforce}
\end{figure*}

7
docs/titleabstract.tex

@ -1,15 +1,14 @@
% title
\title{\huge Galaxy Simulation\\ \large Jugend Forscht 2018/2019}
\title{\huge Galaxy Simulation}
\date{2018 - 2019}
\author{\Large{Emile Hansmaennel}\\ Theodor-Fliedner-Gymnasium, Heinrich Heine
Universität Düsseldorf}
\author{\Large{Emile Hansmaennel}}
% title with an abstract in a single column
\twocolumn[
\maketitle
\centering
\begin{minipage}{0.7\textwidth}
Ist es möglich die Entstehung von Galaxien zu simulieren? Um diese Frage zu
Ist es möglich die Entstehung von Galaxien zu simulieren? Um diese Frage zu
beantworten bin ich zu dem Schluss gekommen, dass ich das doch einfach mal
ausprobieren sollte. Dazu habe ich das Navarro-Frenk-White Profil implementiert
um anschließen die Kräfte die Zwischen den Sternen wirken zu berechnen. Dabei

14
docs/vektoren.tex

@ -1,14 +0,0 @@
\section{Vektoren}
Die Kräfte die auf die jeweiligen Sterne wirken werden mithilfe von Vektoren
dargestellt. Hierbei ist es sinnvoll eine einheitliche Vektor-länge zu
definieren, welche die Richtung der wirkenden Kraft beschreibt. Die Stärke der
Kraft als Gradient definiert, der von blau (schwach) nach rot (stark) verläuft.
Um die Farbe entsprechend der Kraft darzustellen wird die Stärke der wirkenden
Kraft duch eine Sigmoidfunktion geschoben und das Ergebnis in wiefolgt
verwenden: RGB(val, 0, 1-val).
\begin{equation}
f(x) = \frac{L}{1 + e^{-k(x-x_0)}}
\end{equation}

7
docs/vorgehensweise.tex

@ -1,7 +0,0 @@
\section{Vorgehensweise}
Wie schon in der Einleitung beschrieben habe ich mehrere Techniken kombiniert
um mein Ziel zu erreichen. Das komplette Projekt lässt sich in mehrere
Abschnitte unterteilen: Die Generierung der Punkt Wolke, aus der eine Galaxie
abstrahiert wird. Die Simulation der Galaxie bei der die Kräfte die in der
Galaxie wirken berechnet werden und daraus die Geschwindigkeit und Richtung in
die der Stern fliegt.

BIN
main.pdf

Binary file not shown.

35
main.tex

@ -1,18 +1,30 @@
\documentclass[twocolumn, a4paper, 10pt]{article}
\usepackage[top=2cm, bottom=2cm, left=1.5cm, right=1.5cm]{geometry}
\usepackage[utf8]{inputenc} % support for utf8 chars
%\usepackage[english]{babel}
\usepackage[german]{babel} % german language
\usepackage[german]{babel}
% general math stuff
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amsthm}
\usepackage[hidelinks]{hyperref} % clickable links
\usepackage{graphicx} % graphics
\usepackage{caption} % captions
\usepackage{subfigure}
\usepackage{varioref}
%\usepackage[hidelinks]{hyperref} % clickable links
\usepackage[pdftex,
pdfauthor={Emile Hansmaennel},
pdftitle={Galaxy Simulation},
pdfsubject={Galaxy Simulation},
pdfkeywords={Galaxies, Simulations, Runtime optimization},
pdfproducer={},
pdfcreator={pdflatex},
hidelinks]{hyperref}
\usepackage{graphicx}
\usepackage{caption}
\newcommand{\source}[1]{\vspace{-3pt} \caption*{ \footnotesize{Source: {#1}}} }
\usepackage{subfig}
\usepackage{float}
%\usepackage{lmodern} % even nicer font
\usepackage[stable]{footmisc} % footnotes
\usepackage{svg}
@ -23,7 +35,9 @@
\lstset{
frame=single,
breaklines=true,
language=golang,
numbers=left,
}
% tikz for drawing stuff and forest for nice graphs
@ -33,20 +47,19 @@
\linespread{1}
\hbadness=99999
\setlength{\columnsep}{2em}
\begin{document}
\input{docs/titleabstract.tex}
\tableofcontents
\input{docs/einleitung}
\input{docs/vorgehensweise}
\input{docs/generieren}
\input{docs/simulieren}
\input{docs/entwickeln}
\input{docs/ergebnisse}
\input{docs/darstellung}
\input{docs/vektoren}
\input{docs/fazit}
\input{docs/quellenliteraturverzeichniss}
%\listoffigures
\end{document}

BIN
networktikz/build-0aaaabaecd1a0e24478344963afa4f0bbef400cd59d3d9d56de7731d8a582982/main.pdf

Binary file not shown.

BIN
networktikz/build-2d971d303de0e7ebced63d0fcf1d639ed01c916d63a52ef1e57aa1186a05d864/main.pdf

Binary file not shown.

BIN
networktikz/build-30740998824c255df20ffa4d9c6eaaa58df812977d22cb27dfb6aded8bbf628b/main.pdf

Binary file not shown.

BIN
networktikz/build-35ad62dee2b613e409d223048d8379b63088ce5dee671db88737657051c548b8/main.pdf

Binary file not shown.

BIN
networktikz/build-37f18e65bbfb92356e6f763d5e5d36270f2abf7cc627a5d863b552b16b4a03fa/main.pdf

Binary file not shown.

BIN
networktikz/build-3c5aa09f4a163ad401138c09153ceed1115cb28627686b637a6e539c0293295f/main.pdf

Binary file not shown.

BIN
networktikz/build-426b2e16a93486d6427fa694bbf0716f595af4d84602ec208ef173e6c4b5e645/main.pdf

Binary file not shown.

BIN
networktikz/build-499ebe1b5556e51f625f4d073a43e13c54090707884bbe9d8e408dfca2076597/main.pdf

Binary file not shown.

BIN
networktikz/build-4c494493f75c1c45ecb73e75612d62edaabefb6b31ed62d1ee194bbe7cd2f04e/main.pdf

Binary file not shown.

BIN
networktikz/build-5c2e439a6dd3da27c6368675a052ace5436705014148ad109060315a5045c641/main.pdf

Binary file not shown.

BIN
networktikz/build-600c2e083a230832585ac1b78ed9bb622fee97d930615085b8ec0ff4007a44ca/main.pdf

Binary file not shown.

BIN
networktikz/build-6109513bb30ee7b0317c65661daa62bde297161ea68293beaabe48a968fb5f89/main.pdf

Binary file not shown.

BIN
networktikz/build-6d0414a21f720793d3e955c30dd82ee0628a92ab78c81e6c0e4869f55d5a64e2/main.pdf

Binary file not shown.

BIN
networktikz/build-7ec80a2fb8f5a8cbd110e155c24406f93792478a36b4ad5fc1bad3743c954ee1/main.pdf

Binary file not shown.

BIN
networktikz/build-9440e3640a87eea4aae4d222948774f9b52c4c10c41c0555aa7090aef3b5e617/main.pdf

Binary file not shown.

BIN
networktikz/build-a120952ee3b3da2d1f37a49ef850f9d4130c64dd528b90801085d0bdc00aa589/main.pdf

Binary file not shown.

BIN
networktikz/build-a8c527e5fdb94e77005d4680aeef0b7561af5f6438b7c96c1192c0449353439d/main.pdf

Binary file not shown.

BIN
networktikz/build-ad6186b2f1ec4b7e4b086ede48996880d1d6ae55f124dd2f0c85e3d365d77f2f/main.pdf

Binary file not shown.

BIN
networktikz/build-b3108eeb037a58467e062d6ef3e90ee8a1df33889e05ce35a89b27ea5affe620/main.pdf

Binary file not shown.

BIN
networktikz/build-bcda6e5a3ac8479d737eacf2e813312afae3d429be7a0fa45a535d1f35812856/main.pdf

Binary file not shown.

BIN
networktikz/build-c6864e68112edd1c637d4381d0eb1e95a10a6c3587dd19c3e3586983a8fcb115/main.pdf

Binary file not shown.

BIN
networktikz/build-ccfe85b61cc19f386fc2411ece4fb20526c357cf97445911517dacac4730e7bc/main.pdf

Binary file not shown.

BIN
networktikz/build-d75aebc2af2bbdf1219b7f51ff3e0977bfbbc0a8e312dd736d5aeb59d0ccf08e/main.pdf

Binary file not shown.

BIN
networktikz/build-e0dd84dbedba1079a90064072c2ed0515ea90013e8b72f6de98747326c779e7c/main.pdf

Binary file not shown.

BIN
networktikz/build-f0cd4afea87092f34d0eb12163c0835d636f99bd8f4e8a91c3d60e6aa7fc7df9/main.pdf

Binary file not shown.

BIN
networktikz/build-f55a35ecb99410afd29006389c91a1a3a9f1ca48ca0bb3dbe9f7c9743ac84eec/main.pdf

Binary file not shown.

BIN
networktikz/build-fa10f2a545be29242e15512accb7b2905d0129dbfbc16124c9f4fed9fa55369d/main.pdf

Binary file not shown.

1
networktikz/current-build

@ -1 +0,0 @@
build-4ddc0aed88f40bf536274440b923fffbff0262616c3f9a80380eb57cab239dba

1
networktikz/last-successful

@ -1 +0,0 @@
build-4ddc0aed88f40bf536274440b923fffbff0262616c3f9a80380eb57cab239dba

46
networktikz/main.tex

@ -1,46 +0,0 @@
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit, positioning}
\begin{document}
\begin{tikzpicture}
\node (base) at (0, 0) {};
% generators
\foreach \m in {1, 2, 3} {
\node[draw, below = of base] (generator-\m) at (0, \m) {Generator};
}
% NFW calculators
\foreach \m in {1, 2, 3} {
\node[draw, right = of generator-\m] (NFW-\m) {NFW};
}
% generatortraefik
\node[draw, right = of generator-2] (generatortraefik) {traefik};
% connect the generators with the generatortraefik
\foreach \l in {1, 2, 3} {
\draw (generator-\l.east) -- (generatortraefik.west) {};
}
% connect the generatortraefik with the NFW nodes
\foreach \l in {1, 2, 3} {
\draw (generatortraefik.east) -- (NFW-\l.west) {};
}
\node[draw, fit=
(generator-1)
(generator-2)
(generator-3)
(generatortraefik)
(NFW-1)
(NFW-2)
(NFW-3)
] (boundary) {};
\end{tikzpicture}
\end{document}

1
networktikz/texbox

@ -1 +0,0 @@
Subproject commit 81471429305646a8971fb8cc13a0d96a8bd060b3

1
texbox

@ -1 +0,0 @@
Subproject commit 81471429305646a8971fb8cc13a0d96a8bd060b3