Das Programm

Da wir anfangs unglaublich viele Ideen hatten, und im Hinterkopf vielleicht schon die unterdrückte Ahnung, dass wir es wahrscheinlich nicht schaffen würden, einen Fischschwarm mit männlichen und weiblichen, alten und jungen Fischen, Fischen, die neu geboren werden und sterben, im Laufe ihres Lebens von Hunger, Gruppenzusammenhalt, Müdigkeit und spontaner Erschöpfung getrieben werden etc., zu simulieren, wollten wir ein Programm schreiben, das beliebig erweiterbar ist. Rausgekommen ist eine einfache Grundstruktur, aus einer Weltklasse und einer Klasse für die Fischobjekte, wobei das Verhalten des Fisches so simuliert wird, dass es aus vielen Einzelinteressen besteht, aus denen ein Kompromiss geschlossen wird. Dadurch können die einzelnen Interessen der Fische unabhängig voneinander verändert und verbessert werden oder ganz neue hinzugefügt werden, es können auch ganz neue Handlungsmotive hinzugefügt werden.
Da wir mit einem kartesischen Koordinatensystem so arbeiten, dass die Positionen von Fischen, Hindernissen und Essen als Vektoren in unterschiedlichen Arrays der Weltklasse gespeichert werden, könnte man auch da weitere Kategorien hinzufügen, die dann wiederum nur von der Funktion des Fischverhaltens berücksichtigt werden müssen, die sich damit befassen. Zum Beispiel sind Hindernisse dem Teil des Fisches, der sich mit Essen befasst, ganz egal – dadurch kann das Programm von uns oder einer anderen Mathesisgruppe unkompliziert weiterentwickelt werden.
Das genaue Verhalten der Fische, also wie genau sie ihre Richtung synchronisieren, wie sie Hunger und Müdgkeit abwegen usw., haben wir im Grunde nur grob geschätzt. Daraus folgt, dass wir mit einer ganzen Menge Konstanten arbeiten, die wir auch nur geschätzt haben, die aber falsch gewählt zu unpassenden Resultaten führen könnten. Um die systematisch ausprobieren zu können, ohne im Programmcode nach jeder Verwendung von 0.95 als Trägheit suchen zu müssen, haben wir all diese Stellschrauben am Anfang des Programms gesammelt und mit möglichst selbsterklärenden Namen versehen.
Aufbau
Das Programm besteht aus zwei Klassen, die eigentlich die ganze Arbeit machen: Der Klasse welt und der Klasse fisch.
Die Welt Klasse enthält zwei Methoden: einen Konstruktor, der die Anfangskonstellation herstellt und eine main-Funktion, aus der heraus im laufenden Programm alles passiert.
Die Klasse Fisch enthält alle Funktionen (im herkömmlichen sowie im objektorientierten Sinne), die ein einzelner Fisch haben soll:
–          einen Konstruktor, der die Position des Fisches speichert, sich im Raum an dieser Stelle anzeigt und die anfänglichen Eigenschaften des Fisches speichert  (die Werte für hunger, muedigkeit und schlafnot sowie, dass der Fisch gerade nicht schläft) .
–          einer Funktion anfangsgeschwindigkeit; sie ist dafür gedacht, dass der Konstruktor sie aufrufen kann, um zum ersten mal Richtung und Geschwindigkeit des Fisches statt zufällig so zu bestimmen, dass die Fische in einem approximierten Kreis um die z-Achse schwimmen.
–          Die Funktionen essen, nachbar, hindernis und schlaf. Dabei geben die ersten drei genannten Funktionen jeweils den Impuls zurück, mit dem der Fisch seine Bewegung ändern sollte, hätte er nur jeweils ein Interesse (zu essen, bei den Nachbarn zu bleiben und dem nächsten Hindernis auszuweichen), schlaf gibt einen Wert zurück, der so ausgewertet ist, dass der Fisch nach längerer Zeit wach sein eine größere schlafnot hat und sich dementsprechend schlafen legt, allerdings nur, wenn die Dringlichkeit größer ist als die Dringlichkeit des Impulses, mit dem er sich sonst bewegt hätte – wobei Dringlichkeit vereinfachter Weise dem Betrag des Impulses entspricht. Das Abwegen und vereinen der Einzelinteressen findet in der Funktion neuebewegung statt:
–          Der Funktion neuebewegung, die den Impuls berechnet, mit dem ein Fisch seine momentane Bewegung ändert, indem die verschiedenen Interessen abgewogen und nach einem relativ einfachen Algorythmus zum Gesamtimpuls ausgewertet werden
–          Der Funktion bewegen, die, sofern die vom Fisch gespeicherte Bewegung ausgeführt wird. Der Fisch hat zu jeder Zeit eine Bewegung gespeichert, die sich nur bei neuebewegung ändert; wird neuebewegung zwischen zwei Bewegungseinheiten nicht aufgerufen, schwimmt er mit nur durch die Trägheit langsamer werdender Geschwindigkeit gradeaus. Da auch ein schlafender Fisch gradeausschwimmt, ohne aktiv Einfluss auf seine Bewegung zu nehmen, passiert das unabhängig davon. In dieser Funktion wird allerdings auch das Abnehmen der schlafnot geregelt, die irgendwann zum Aufwachen führt. Bevor die Bewegung ausgeführt wird, wird die Funktion kollision aufgerufen:
–          Einer Funktion kollision, die überprüft, ob eine noch nicht ausgeführte Bewegung überhaupt möglich ist oder dazu führen würde, dass sich der Fisch an einem Ort befindet, an demsich  schon ein anderer Fisch oder ein Hindernis aufhält.
Die Positionen der Fische, Hindernisse und der Nahrung sowie Bewegung und Impuls der Fische sind als Vektoren realisiert, für die wir noch ein paar für uns ohne viel Recherche einfach zu verwenden Hilfprogramme geschrieben haben, die uns die Arbeit mit den Vektoren erleichtern, und zwar für das Skalarprodukt, den Abstand zwischen zwei Vektoren, das Kreuzrodukt und den Vektorbetrag.

Interessant sind vor allem die Funktionsweise von neuebewegung mit den davon verwendeten Funktionen und die main-Funktion der Klasse welt.
Die main-Funktion besteht aus einer großen Schleife, die so oft ausgeführt wird, wie sich jeder Fisch bewegen soll. Innerhalb der Schleife wird dann jeder Fisch aufgerufen, sich zu bewegen.
Da wir vor der Realisierung unserer Idee nicht gut abschätzen konnten, wie rechenintensiv das Programm wird, wollten wir dem Problem vorbeugen, dass im Endeffekt nur ein Haufen Punkte zu sehen sind, von denen sich alle paar Sekunden nur einer bewegt.  Daher haben wir das „Überdenken“ der Bewegung von der Ausführung der Bewegung getrennt (neuebewegung und bewegen), und lassen in jeder Iteration der Hauptschleife einen verstellbaren Anteil der Fische ihre Bewegung neu berechnen. Das wird in einer Schleife realisiert, die z.B. zufällige 20% der Fische neuebewegung aufrufen lässt, danach lässt eine zweite Schleife jeden Fisch seine Bewegung ausführen.
Diese Struktur ermöglicht auch, die einzelnen Komponenten zu verfeinern oder weitere hinzuzufügen, so dass das Fischverhalten besser immitiert werden kann.

Bei der Berechnung einer Bewegungsveränderung von neuebewegung werden zunächst drei Vektoren erzeugt, nachbarimpuls, essensimpuls, hindernisimpuls und schlafimpuls, die von den dafür zuständigen Funktionen mit den Werten befüllt werden, die dafür Sorgen würden, dass der Fisch genau das eine Interesse hat, z.B. zum Essen zu schwimmen. Diese werden berechnet, dazu später im Einzelnen noch mehr.
Zunächst wird geprüft, ob der Wert der integer Zahl schlafimpuls größer als der Betrag jedes anderen Impulses ist. Das bedeutet, es wird geprüft, ob zu schlafen gerade das intensivste Bedürfnis des Fisches ist, falls das der Fall ist, wechselt der Fisch in der Zustand schlafend.
Falls der Fisch jetzt nicht schläft, wird der Gesamtimpuls berechnet. Dazu wird die Summe aus nachbarimpuls und essensimpuls gebildet, und abhängig von einer weiteren Variablen des Fisches, muedigkeit, im Betrag verändert.
Muedigkeit soll ein Maß für die spontane Erschöpfung darstellen, die Funktionsweise kann man sich ungefähr so vorstellen: Setzt der Fisch einen Impuls, strengt er sich an und muedigkeit wird größer. Mit der Zeit erholt der Fisch sich aber auch von früheren Anstrengungen, daher setzt sich die akute Erschöpfung aus dem Halben der bisherigen Erschöpfung und dem Betrag des neu gesetzten Impulses zusammen, abzüglich einer Konstanten, die angibt, wie stark sich die Fische in jedem Schritt erholen. Das führt dazu, dass der Fisch in jedem Schritt einen Impuls setzen kann, der so stark ist wie der Wert von der Erholung pro Schritt, da dann die Erschöpfung mit der Zeit gegen Null geht, es handelt sich dann um eine Zerfallsfunktion mit Halbwertszeit 1.
So entsteht ein Wert für den Gesamtimpuls, der dazu führen würde, dass ein Fischimmer in die Nähe von Essen schwimmen würde, aber niemals genau dorthin, da es immer eine kleine Abweichung durch das Interesse, bei den Nachbarn zu bleiben, geben würde. Deshalb wird, wenn der Impuls zum Essen zu schwimmen der größte ist, dieser zum Gesamtimpuls, also setzt für kurze Zeit die Orientierung an der Gruppe aus. Das soll funktionieren, da ein Fisch die Wichtigkeit, zu Nahrung zu schwimmen, als höher einstuft, wenn sich welche in der Nähe befindet. Das macht Sinn, da der Aufwand, dorthin zu schwimmen, geringer ist. Im Programmablauf zeigt sich aber, dass es tatsächlich nicht ausreicht, damit die Fische genau durch die Punkte schwimmen, an denen sich Nahrung befindet. Daran müssen wir noch arbeiten.
Da in bewegung die Trägheit das einzige ist, was einen Fisch bremst, und diese genauso groß bei einem schlafenden wie bei einem nicht denkenden Fisch ist, kann man auch nicht erkennen, ob die Fische tatsächlich schlafen – ein weiterer Punkt, an dem noch Verbesserungsbedarf besteht. Das könnte dadurch realisiert werden, dass die Trägheit wesentlich erhöht wird, Fische, die nicht denken, aber Impulse zur Geschwindigkeitserhaltung setzen.
Jetzt hat sich der Fisch also einen möglichen Impuls ausgedacht, der schon alle bisher programmierten Interessen berücksichtigt. Bevor es dabei belassen werden kann, muss aber noch geprüft werden, ob es so nicht so einer Kollision mit einem anderen Fisch oder einem Hindernis käme. Außerdem muss geprüft werden, ob die spontane Erschöpfung nicht den maximalen Wert dafür überschreitet. Das haben wir so realisiert, dass wir in einer whileschleife beides überprüfen, die erst verlassen wird, wenn alle Bedingungen erfüllt sind. Käme es zu einer Kollision, wird ein zufälliger Ausweichimpuls zu dem berechneten Impuls addiert. Wird der Fisch dann überlastet, wird der Impuls ein wenig abgeschwächt.
Wird aus einem der beiden Gründe der Impuls geändert, muss wieder überprüft werden, ob der neue Wert kompatibel zu der anderen Bedingung ist.
Das ist der Teil des Fischverhaltens der auch dafür sorgt, dass der Fisch einem Hindernis ausweicht, weshalb wir hindernisimpuls und die dafür geschriebene Funktion vorläufig noch gar nicht benutzt haben, bis wir einen vorrausschauenderen Algorythmus zum Ausweichen haben, sucht sich der Fisch einfach einen zufälligen Weg um das Hindernis herum.
Zuletzt wird die Bewegung des Fisches um den Impuls geändert, Hunger und Schlafnot erhöhen sich abhängig von der Stärke des neues Impulses.

Um das Verhalten genau zu verstehen, muss ich allerdings noch erklären, wie die hypotischen Impulse für die Einzelinteressen berechnet werden.
Fangen wir mit der Funktion essen an: es gibt eine Konstante, die den maximalen Wert für Hunger enthält. Ist der Hunger kleiner als ein Drittel davon, wird der Nullvektor zurückgegeben, es besteht kein Grund, in Richtung von Nahrung zu schwimmen. Dann sucht sich der Fisch das Essen, das ihm am nächsten ist, von da aus berechnet er den Impuls, der nötig wäre, um genau dahin zu schwimmen. Das ist die fertige Richtung.
Ist der nötige Impuls klein (kleiner als das doppelte der Erholung pro Schritt), wird er auch in der Länge nicht verändert, damit ein Fisch, der in der Nähe von Nahrung ist, genau dorthin schwimmt. Ansonsten wird die Bewegung des Fisches sowie die Richtung, in die es zum Essen geht, auf einen Vektor mit dem Betrag 1 genormt, die Differenz gebildet und mit der Geschwindigkeit des Fisches multipliziert, so dass man den Impuls erhält, der den Fisch auf eine grade Bahn in Richtung der nächsten Nahrung bringen würde. Das soll den Fisch dazu bringen, in die nähe von Nahrung zu schwimmen, so dass hier die Geschwindigkeit keine so wichtige Rolle spielt. Das genaue Treffen wird dann eingeleitet, wenn sich der Fisch schon relativ nah an seiner Nahrung befindet.
Wenn der Hunger jetzt eine Grenze von 70% des maximalen Hungers überschreitet, wird dieser Wert so zurückgegeben, ansonsten abhängig vom Hunger abgeschwächt.
Es gibt also vier Fälle: 1. Der Hunger ist klein, es gibt überhaupt keinen Grund, die Bewegung vom Essen abhängig zu machen. 2. Der Hunger ist da, aber noch so stark, dass der Fisch nur leicht Richtung Essen schwimmt. 3. Der Hunger ist so groß, dass die Bewegung so umgelenkt werden soll, dass der Fisch genau Richtung Essen schwimmt. Der vierte Fall ist der, dass es sehr wenig Anstrengung kosten würde, genau durch den Punkt mit der Nahrung zu schwimmen, so dass genau das passieren soll.

Der Gruppenzusammenhalt besteht genau genommen wieder aus zwei Einzelinteressen, aus denen ein gewichteter (auch verstellbarer) Kompromiss geschlossen wird: zum einen, die Richtung und Geschwindigkeit dem Durchschnittswert des Schwarms anzugleichen und zum anderen, den Abstand zu den nächsten n Nachbarn dem durchschnittlichen Abstand zwischen diesen anzugleichen. N ist hier wieder eine der am Anfang des Programms definierten Variablen, dessen Wert wir durch ausprobieren abgeschätzt haben.
Um den Anreiz zu ermitteln, der den Abstand zu den Nachbarn angleichen soll, werden die nächsten n Nachbarn ermittelt und vereinfachter Weise der Mittelpunkt der Gruppe gebildet. Die Verbindung zu diesem Ziel entspricht der Richtung des Impulses, die Stärke hängt vom Abstand der Nachbarn unter sich und einer „Verklumpungskonstante“ ab, einem Wert, der den angestrebten Abstand um einen Faktor verringert, um den Zusammenhalt zu stärken.

Der Gruppenzusammenhalt soll zwei für Schwärme sehr typische Verhalten bewirken: zum einen, dass sich in einem Schwarm die Dichte schlagartig ändern kann, also im ganzen Schwarm ohne einen zentralen Befehl auf einmal die Individuen weiter voneinander oder zusammen schwimmen. Deswegen gibt es auch keine Konstante für den angestrebten Abstand zu den Nachbarn, stattdessen ist der nur abhängig von den Abständen der anderen Schwarmmitgliedern.
Dass allein das für das typische Schwarmverhalten, bei dem die Individuen zusammen bleiben, nicht ausreicht, haben wir gemerkt, als wir nur diesen Teil des Schwarmzusammenhalts implementiert hatten: da die individuellen Interessen der Fische (bisher nur Essen) die einzelnen in unterschiedliche Richtungen treiben, konnte sich der Schwarm als Ganzes nicht mehr bewegen. Jeder Fisch, der in eine Richtung geschwommen ist, hat seine Nachbarn zwar auch in diese Richtung „gezogen“, da sie bei ihm bleiben wollten, in der Summe hat sich aber keine Bewegung des Schwarms als Ganzes gebildet.
Also ergänzten wir eine Komponente, die nicht nur Ort, sondern auch Bewegung der Fische synchronisieren sollte.
Dieser Teil lässt sich relativ einfach berechnen, indem in einer Schleife die durchschnittliche Bewegung des Schwarms berechnet wird, die Differenz zur eigenen Bewegung ist das Ergebnis.
Das hat zu mindest dazu geführt, dass wir jetzt einen Haufen Punkte haben, die sich in irgendeiner Weise gemeinsam bewegen.

Viele Ideen zur Verbesserung und Erweiterung haben wir noch nicht umgesetzt, und bisher ist jeder Programmteil nur ein erster Entwurf. Im Laufe des Programmierens haben wir an der Stelle weitere Feinheiten entdeckt, die man beachten muss und Ideen entwickelt, mit denen man das Verhalten realistischer machen könnte. Die Idee einer nicht zentralen Organisation, die ein komplexes Gesamtverhalten hervorruft, konnten wir aber in erster Ausführung schon umsetzen.

Ablauf des Programmierens

Unser Ablauf beim Programmierens gingen wir nach Objektschaffung: erst die Welt, danach die Fische.
Wir haben zuerst die Welt erschaffen, die die Fische und die Hindernisse als Attribute beinhaltet. Wir wollten damit erstmal die Grundlage schaffen, da jeder Fisch durch die Welt aufgerufen wird, heißt: ohne Welt keine Fischbewegung. Dies ging auch relativ schnell, da die Welt nicht besonders viele Methoden hat, und wir beschlossen hatten die physikalischen Eigenschaften erst einmal außen vor zu lassen.
Weiter ging es mit dem Fisch, der immer weiter „ausgebaut“ wurde/wird.
Angefangen haben wir mit den allgemeinen Attributen, die wir deklariert und initialisiert haben. Das sind diejenigen Attribute, die wir auch im Konzept aufgezeigt haben. Zunächst war diese Liste sehr kurz, wurde aber über die Zeit in der wir programmiert haben immer länger.
Dann kam die Visualisierung. Diese war sehr einfach, und sehr wichtig, weil wir damit immer überprüfen konnten was unser Programm denn schon so kann, und wie sich die Fische bewegen. Damit können wir auch gleichzeitig während der ganzen Programmierzeit sehen welche Methoden noch nicht funktionieren. Beispielsweise haben wir eine Methode geschrieben, die einen Fisch ausweichen lassen soll sobald es gegen ein Hindernis schwimmt. Und obwohl unser Programm lief, konnten die Fische durch die Hindernisse hindurch schwimmen, was uns zeigt: wir haben zwar keinen Fehler gehabt, der unser Programm unkompilierbar gemacht hat, und trotzdem hatten wir Fehler drin, welche das Programm nicht das Richtige hat ausführen lassen. Damit ist die Visualisierung sehr wichtig. Außerdem, konnten wir so den Fortschritt unseres Programms sehr gut nachvollziehen.
Weitergehend haben wir nun angefangen uns mit dem verschiedenen Methoden des Fischs zu beschäftigen. Zuerst haben wir uns darum gekümmert eine Methode zu schreiben, die aus jedem einzelnen Faktor, der den Fisch beeinflusst eine Richtung errechnet. Sie nutzt die Wertrückgaben der Methoden, die Hunger, Müdigkeit etc errechnen, und bestimmt im zusammenspiel aller Faktoren die neue Bewegungsrichtung des Fischs.
Danach kamen über die Zeit immer mehr Methoden dazu. Jede dieser Methoden beschreibt eines der Faktoren, die ein Individuum in ihrer Bewegungsrichtung beeinflussen.Nähere Erläuterungen zum Programmcode werdet ihr aber noch präsentiert bekommen.
Über die Zeit haben sich nicht nur die Methoden erweitert, sondern auch die Attribute des Fisches. Wir haben alle wichtigen Konstanten zu Attributen des Fisches gemacht, um, wie schon vorhin erwähnt, ganz einfach nur einen wert ändern zu müssen, und nicht den ganzen Programmcode. Damit wird es für uns und auch euch verständlicher, da wir nicht nur mit zahlen arbeiten, sondern mit Worten.
Allgemein war der Ablauf des Programmschreibens sehr leicht zu organisieren. Wir haben erstmal die Grundlagen geschafft, durch das Erschaffen der Welt und der Fische, sowie der Visualisierung. Damit konnten wir Schritt für Schritt immer mehr Faktoren hereinbringen, immer nachvollziehen was die von uns jetzt neu geschriebenen Methode für Auswirkungen auf die Bewegung hatte, und Fehler schnell korrigieren.
Auch, wenn wir das hier gerade in Vergangenheit schreiben, ist Der Ablauf des Programmierens eigentlich noch garnicht fertig. Wir, und jeder andere auch, kann weiter arbeiten, weitere Funktionen hinzufügen, und noch nicht perfekt ausgebaute Methoden verbessern. Das ist das schöne an diesem Projekt: Jetzt wo die Grundlagen geschaffen sind, haben wir einen sich bewegenden Schwarm, den man immer näher an die Realität bringen kann. Damit beschreibt dieser Text wie wir den Ablauf des Programmierens organisiert haben, er soll aber keinen Schlussstrich ziehen, sondern eher die Richtung zeigen, wie das Programm am besten weiter geschrieben wird.

Erste Ideen und erstes Konzept

Unsere ersten Idee war es eine Fischschwarmsimulation zu entwickeln, bei dem man – ähnlich wie bei Computerspielen – selber einen Hai, also einen Angreifer steuern kann, um hinterehre die Bewegung eines jeden Fisches und auch des Schwarms im Ganzen analysieren zu können. Schon schnell haben wir uns überlegt, dass dieses Ziel vielleicht doch ein bisschen hoch gegriffen ist, bzw, dass die Zeit eines Semesters nicht genug sein würde dafür. Wir beschlossen also klein anzufangen und erst einmal einen Fischschwarm zu kreieren und Hindernisse in die Welt zu setzen.
Wir wussten schon früh, dass wir ein sehr flexibles Programm schreiben wollen. Wir wollten erstmal die Grundsteine legen und ein sich bewegenden Schwarm erschaffen, den wir dann immer weiter ausbauen und verbessern, bzw Realitätsnaher gestalten können. Bei unserem ersten Brainstorming kamen dann doch noch viele Vorschläge, für die wir einfach zu wenig Zeit hatten, die unrealistisch zu schaffen waren. Beispielsweise, wollten wir die Fische altern lassen & sterben, ihnen einen Sexualtrieb geben und neue Fische gebehren lassen. Die Trägheit sollte im Alter zunehmen, die Geschwindigkeit sich verringern. Nachdem uns Stefan dazu geraten hat doch noch ein bisschen einfacher anzufangen, kamen wir auf unser erstes Konzept.
erstes Konzept

Python ist eine objektorientierte Sprache, weshalb es für unser Projekt perfekt geeignet ist! Wir kamen daher auch schnell auf die Idee ein Objekt der Welt und eins der Fische zu erzeugen. Jedes Objekt in Python (oder auch in anderen objektorientierten Programmiersprachen) haben Attribute und Methoden. Dies von uns sehr von Vorteil, weil man sich sehr gut vorstellen kann was die Attribute und die Funktionen eines Fisches wie auch der Welt ist. Es wird also nicht sehr abstrakt programmiert. Außerdem sind die Attribute allgemein festgelegt für das Objekt und kann dann weiter in den Methoden verwendet werden. Was für uns den Vorteil hat, dass wir die einzelnen Werte wie Müdigkeit oder die Anzahl an Nachbarn an denen sich ein Fisch orientiert einmal festlegen, und diese dann in den Methoden benutzt werden. Und wenn wir uns nun an die Realität annähern wollen, müssen wir nur den einen Wert des Attributs ändern, ohne eine ganze Methode umzuschreiben.
Die allgemein Struktur unseres ersten Konzepts mit den zwei Objekten der Welt un des Fischs hat sich zum Großteil komplett durchgesetzt. Nur einzelne Details, wie beispielsweise die Attribute des Fisches haben sich geändert. Diese Liste wurde deutlich länger, da wir anfangs noch nicht an wichtige Konstanten wie den Fischradius, der den Raum um den Fisch beschreibt, in den ein anderer nicht eindringen kann (im Endeffekt der Körper, sozusagen), gedacht haben. Wir haben uns während des Programmierens die ganze Zeit an unser Konzept gehalten; dass es leichte Veränderungen gibt, ist aber wohl bei jedem Projekt so: erst während der Arbeit kommen die Details hinzu.
Zur Visualisierung haben wir von Anfang an den Tipp von Stefan bekommen „Vpython“ zu benutzen, ein Programm, durch dass sich die Visualisierung unglaublich einfach machen lässt. Man braucht nur eine Zeile um einen Punkt bzw unseren Fisch erscheinen zu lassen, und weitere 4 Zeilen um die Hindernisse zu zeigen. Es wäre wohl blöd gewesen nicht dieses Programm zur Visualisierung zu benutzen.

Informationen sammeln

Angefangen hat unser Projekt – wie wohl jedes andere auch – mit der Sammlung von Informationen. Wir hatten beide ein grobes Bild davon wodurch ein Fisch besonders beeinflusst werden könnte; durch den Biologieunterricht in der Schule hatten wir schon von wichtigen biotischen und abiotischen Faktoren gehört, wie beispielsweise Nahrung oder auch lebende Angreifer. Haben uns vorher aber noch nicht speziell mit Schwärmen beschäftigt.
Um uns eine Überblick zu verschaffen, nutzten wir zuerst das Medium des Internets um uns Schwarmdokumentationen anzusehen. Besonders interessant war dabei der Film “Schwärme – Die Intelligenz der Massen”. ()
Die Dokumentation war sehr hilfreich für uns um grundlegende wichtige Informationen über Schwärme zu erlangen. Der Film behandelt alle möglichen Tierarten, die in Schwärmen leben. Damit haben wir zwar keine detailgetreuen Informationen besonders auf Fischarten bezogen bekommen, jedoch wurden die wichtigsten Faktoren, die ein Individuum beeinflussen, erwähnt: Hunger, Müdigkeit, Angst vor Angreifern, die Bewegung der Nachbarn etc. Was wir vorallem besonders Wichtiges gelernt haben, ist der Fakt, dass sich jedes einzelne Tier an eine bestimmte Anzahl an Nachbarn orientiert. Dass sich ein Schwarmmitglied mit daran orientieren muss wie sich die Nachbarn bewegen, haben wir uns schon gedacht; sonst wärs eher schwer gemeinsam so flüssig zu fliegen/schwimmen/laufen. Interessant dabei ist jedoch, dass die einzelnen Individuen nicht danach gehen wie die Nachbarn in einem bestimmten Radius um sie herum schwimmen (wir beziehen das jetzt mal auf Fische, ist aber bei allen Schwarmarten so), sondern sie orientieren sich immer an den nahsten 5/6 Nachbarn, egal in welcher Entfernung diese zueinander sind. Dies macht Sinn, da sich ein Schwarm sehr dicht, aber auch sehr weitläufig verteilen kann, dies passiert oft in sekundenschnelle. Würde ein Fisch auf die Nachbarn in einem bestimmten Radius gucken, und die Fische müssen sich durch einen Angriff verteilen, gibt es die Möglichkeit, dass plötzlich in dem Radius auf den sich ein Fisch konzentriert kein Nachbar mehr zu finden ist.Damit verliert der Fisch den Kontakt zum Fischschwarm. Dies würde wohl sehr oft passieren, daher ist es sehr schlau sich an den nächsten Nachbarn zu orientieren.
Weiterhin haben wir aus Zweck der Informationssuche einen Text von Stefan bekommen: ‘Flocks, Herds, and Schools: A Distributed Behavioural Model’. Dieser Text wurde geschrieben von Craig W. Reynolds, und beschreibt wie man ein Programm zur Schwarmsimulation aufbauen kann. Es war also nicht nur ein fachlicher Text zum Schwarmverhalten, sondern hat auch vorallem die mögliche Umsetzung beschrieben. Wir haben uns den Text im Labor durchgelesen und miteinander besprochen. Jedoch, haben wir uns bei der Arbeit eigentlich so gut wie gar nicht auf diesen Text gestützt, wir haben eher selber überlegt wie man bestimmte Sachen umsetzen kann.
Im Endeffekt war die wohl wichtigste Quelle die Dokumentation. Wir haben schon ziemlich früh beschlossen nicht all zu viel Wert auf die exakte biologische Richtigkeit zu legen, sondern lieber die Zeit zum Programmieren zu nutzen und dann zum Ende durch ausprobieren an die Realität heranzukommen. Unser Programm ist doch sehr flexibel geworden, das heißt die genauen biologischen Daten kann man noch herausfinden und hinzufügen, sofern wir das weiterführen bzw jemand anderes das weiterführt. Daher, waren aber die für uns wichtigsten Informationen welche Faktoren das Individuum beeinflussen, was in der Dokumentation alles erwähnt wurde. Zusätzlich hat uns der Film noch weiter motiviert und fasziniert, durch die unglaublichen Bilder, die es von den verschiedenen Schwärmen gezeigt hat. Und weiter auch durch die Information darüber, dass die Schwarmforschung noch sehr jung ist, und es noch vieles zu entdecken und bestaunen gibt.

Themenfindung

Unsere Themenfindung fing damit an, dass wir zuerst einmal Beispielthemen von Steffan, unserem Labor-Leiter, präsentiert bekommen haben. Dies war auf jeden Fall sehr hilfreich! Da wir, wie schon erwähnt, thematisch keine Eimschränkungen hatten, konnten wir uns davon ein bild machen woru, genau es geht – es ist doch eher schwer sich vorzustellen was ein mathematisch-naturwissenschaftliche labor für projekt hervorbringen würde. Auf der anderen Seite brachte es uns einen überblick über die interessanten Themenbereiche in denen man arbeiten kann. Beispiele für Themenbereiche wären: …..
Uns war sehr schnell klar, dass wir uns mit der datenverarbeitung auseinandersetzen wollen. Dies war bei eimigen Mathesis-Laboranten so, jedoch haben wir beide uns auch für die biologische mathematik interessiert. Wir waren beide begeistert von der Idee der Simulation einer Population, daher haben wir uns zu einer Gruppe zusammengefunden.
Unsere erste Idee war es die Populationsgenetik zu untersuchen. Geplant war es ein Programm zu schreiben, mit dem man die Veränderung einer Population durch verschiedene Faktoren vorhersagen kann, zumindest näherungsweise. Man sagt dem Programm beispielsweise wann eine mögliche Naturkatastrophe auftritt und wie sich diese auf eine Population auswirkt.
Dieses Thema klang für uns schnell sehr komplex und abstrakt. Es gibt so unglaublicn viele Faktoren, die eine Population beeinflussen, dass es sehr schwer ist auf solch eine Art und Weise in die Zukunft zu gucken. Wir sind aber in unseren Diskussionen über Populationen und Tiere auf ein – für uns – viel interessanteres Thema gekommen: Schwärme.
Vorallem faszinierend an diesem Thema war für uns der Fakt, dass ein Schwarm keinen Anführer hat. Jeder einzelne Fisch wird von einzelnen Faktoren beeinflusst und bestimmt seine Richtung ganz alleine. Und trotzdem bewegt sich ein Schwarm als Einheit. Es ist unglaublich zu sehen wie sich eine so große Masse an Individuen ganz ohne Leitung so flüssig bewegen kann.
Daher ist das Thema für unser Laborprojekt auch so interessant für uns. Es ist dadurch möglich einen Algorithmus zu schreiben der jeden einzelnen Fisch beschreibt. Man kann die Richtung eines jeden Fisches errechnen und vorbestimmen, da jedes Individuum auf die gleiche Situation gleich reagiert. Sind die Faktoren, die ein Fisch, Vogel oder andere Schwarm-Tiere bei ihren Bewegungen beeinflussen, bei zwei Individuen exakt gleich, werden diese auch die gleiche Richtung einschlagen. (Wobei es in der Realität sehr unwahrscheinlich ist; allein durch die verschiedenen Positionen der einzelnen Mitglieder bilden sich Unterschiede der beeinflussenden Faktoren, zum Beispiel die physikalischen Eigenschaften der Luft oder auch die Position und Richtung der Nachbarn)

Einführung

In unserem MINT Orientierungsstudium an der TU Berlin haben wir die Möglichkeit ein Labor zu belegen. Es gibt die verschiedensten Labore zu wählen, alle aus den diversen Fachbereichen der TU Berlin, beispielsweise Robotik oder das Umweltlabor.
Wir,Niels und Carla, haben uns das Mathesis-Labor gewählt, das wohl interessanteste von allen 😉 In diesem Labor geht es grundlegend darum durch Mathematik und die Anwendung der Informatik naturwissenschaftliche Prozesse zu begreifen und erklären.
Einführend haben wir die Programmiersprache Python gelernt. Dies ist eine objektorientierte Programmiersprache, die einfach aufgebaut ist und damit leicht zu erlernen. Das war sehr wichtig, weil wir doch so schnell wie möglich mit dem Hauptteil des Labors anfangen wollten: Unseren Projekten.
In Gruppen von je zwei bis vier Personen haben wir ein Semester lang an den unterschiedlichsten Projekten gearbeitet. Thematische Vorgaben gab es keine, außer natürlich, dass es unter das Thema des Labor fällt.
Wir möchten mit diesem Blog unser Mathesis-Projekt vorstellen. Zum einen wollen wir euch unseren Projektablauf, zum anderen aber auch das Programm präsentieren, und möglicherweise auch zur Weiterarbeit motivieren… 🙂