Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
ss17:protokolle_muster [2017/06/15 17:10] fmbk25 |
ss17:protokolle_muster [2017/07/13 17:57] (aktuell) fmbk25 |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
**Protokoll 1.6.17:**\\ | **Protokoll 1.6.17:**\\ | ||
Diffusionscode: \\ | Diffusionscode: \\ | ||
- | <code> | + | <code python> |
import matplotlib.pyplot as plt | import matplotlib.pyplot as plt | ||
import numpy as np | import numpy as np | ||
Zeile 51: | Zeile 51: | ||
Lotta Volterra Pfeilmodell im iPython notebook : | Lotta Volterra Pfeilmodell im iPython notebook : | ||
- | <code> | + | <code python> |
import matplotlib.pyplot as plt | import matplotlib.pyplot as plt | ||
import numpy as np | import numpy as np | ||
Zeile 75: | Zeile 75: | ||
Fitz-Hugh-Nagumo Modell (auch mit Pfeilen): | Fitz-Hugh-Nagumo Modell (auch mit Pfeilen): | ||
- | <code> | + | <code python> |
import matplotlib.pyplot as plt | import matplotlib.pyplot as plt | ||
import numpy as np | import numpy as np | ||
Zeile 99: | Zeile 99: | ||
Lotka-Volterra mit Populationen-Zeit-Graph: | Lotka-Volterra mit Populationen-Zeit-Graph: | ||
- | <code> | + | <code python> |
import matplotlib.pyplot as plt | import matplotlib.pyplot as plt | ||
import numpy as np | import numpy as np | ||
Zeile 132: | Zeile 132: | ||
Fitz-Hugh-Nagumo Konzentrations-Zeit-Diagramm: | Fitz-Hugh-Nagumo Konzentrations-Zeit-Diagramm: | ||
- | <code> | + | <code python> |
#!/usr/bin/env python | #!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||
Zeile 166: | Zeile 166: | ||
**Protokoll 15.6.17** | **Protokoll 15.6.17** | ||
Wir haben die zwei Teile der Diffusion-Reaktionsgleichung zusammengefügt. | Wir haben die zwei Teile der Diffusion-Reaktionsgleichung zusammengefügt. | ||
- | Dazu mussten wir den Diffusionsteil etwas abändern. Zuvor haben wir immer direkt den neuen Wert von a erhalten, aber wir brauchen die Differenz zwischen zwei Werten (also zwischen a und a +1 Zeitschritt). (umbenannt und verkürzt zu laplacian) Auch den Reaktionsteil haben wir verändert (s. code) | + | Dazu mussten wir den Diffusionsteil etwas abändern. Zuvor haben wir immer direkt den neuen Wert von a erhalten, aber wir brauchen die Differenz zwischen zwei Werten (also zwischen a und a +1 Zeitschritt, außerdem umbenannt und verkürzt zu laplacian) Auch den Reaktionsteil haben wir verändert (s. code) |
- | <code> | + | <code python> |
import matplotlib.pyplot as plt | import matplotlib.pyplot as plt | ||
import numpy as np | import numpy as np | ||
Zeile 217: | Zeile 217: | ||
a,b = NextStep(a,b) | a,b = NextStep(a,b) | ||
</code> | </code> | ||
+ | https://www.mpg.de/613597/pressemitteilung20100510 \\ | ||
+ | (simulation von Arik, geht an unseren Computern nicht) | ||
+ | |||
+ | **22.06.17** | ||
+ | Game of life: | ||
+ | im Tutorium haben wir schon angefangen die Klasse Welt zu programmieren und heute weitergemacht (Array mit lauter Nullen erzeugen, dann zufällig Positionen im Array auswählen und dort Einsen einfügen. Die Nullen sind tote Zellen, die Einsen die lebenden. Außerdem haben wir das Umfeld definiert:für jede Zelle soll das Programm zählen wie viele der 8 umliegenden Zellen leben oder tot sind. In der nächsten Funktion wird dann nach den Regeln des Spiels (s. u.) der nächste Schritt definiert. | ||
+ | Wir haben folgende Regeln vorausgesetzt: | ||
+ | * für lebende Zellen: | ||
+ | *von genau zwei oder drei lebenden Zellen umgeben: lebt weiter | ||
+ | *sonst stirbt sie | ||
+ | *für tote Zellen: | ||
+ | *von genau 3 lebenden Zellen umgeben: Zustand wird geändert zu lebend | ||
+ | *sonst: weiter tot | ||
+ | Dann haben wir mit etwas Hilfe aus unseren einzelnen Funktion eine große übergeordnete Klasse Welt erzeugt: | ||
+ | |||
+ | <code python> | ||
+ | import numpy as np | ||
+ | import random | ||
+ | |||
+ | class Feld(object): | ||
+ | |||
+ | def __init__(self, lebend): | ||
+ | self.lebend = lebend | ||
+ | |||
+ | |||
+ | class Welt(object): | ||
+ | |||
+ | def __init__(self, umfeld, lebend_oder_tot): | ||
+ | |||
+ | self.v=np.zeros((10,10),dtype=int) | ||
+ | |||
+ | def anfang(v): | ||
+ | def lebewesen(): | ||
+ | a = random.randint(0,9) | ||
+ | b = random.randint(0,9) | ||
+ | |||
+ | v[a,b] = 1 | ||
+ | |||
+ | for i in range (20): | ||
+ | lebewesen() | ||
+ | #print v | ||
+ | #return v | ||
+ | |||
+ | anfang(self.v) | ||
+ | |||
+ | def schleife(self,x,y): | ||
+ | a = 0 | ||
+ | while a<10: | ||
+ | for i in range (9): | ||
+ | umfeld(self.v[a,i]) | ||
+ | a +=1 | ||
+ | |||
+ | #self.umfeld=umfeld | ||
+ | |||
+ | #if v[x,y] == 1: | ||
+ | # self.lebend_oder_tot = lebend | ||
+ | #if v[x,y] == 0: | ||
+ | # self.lebend_oder_tot = tot | ||
+ | |||
+ | |||
+ | |||
+ | def umfeld(self,x,y): | ||
+ | | ||
+ | l = 0 | ||
+ | | ||
+ | if self.v[x, y+1] ==1: | ||
+ | l = l+1 | ||
+ | if self.v[x, y-1] ==1: | ||
+ | l = l+1 | ||
+ | | ||
+ | if self.v[x+1,y] ==1: | ||
+ | l = l+1 | ||
+ | if self.v[x+1, y+1] ==1: | ||
+ | l=l+1 | ||
+ | if self.v[x+1,y-1]==1: | ||
+ | l=l+1 | ||
+ | | ||
+ | if self.v[x-1,y] == 1: | ||
+ | l= l+1 | ||
+ | if self.v [x-1,y+1]==1: | ||
+ | l=l+1 | ||
+ | if self.v[x-1,y-1] ==1: | ||
+ | l=l+1 | ||
+ | return l | ||
+ | |||
+ | def schritt(self,x,y): | ||
+ | l = self.Umfeld(x,y) | ||
+ | |||
+ | if v[x,y]==1: | ||
+ | if l !=2 or l!=3: | ||
+ | self.v[x,y] == 0 | ||
+ | | ||
+ | else: | ||
+ | if l == 3: | ||
+ | self.v[x,y] = 1 | ||
+ | |||
+ | |||
+ | |||
+ | #print Umfeld(3,3) | ||
+ | #'print schritt(v) | ||
+ | |||
+ | </code> | ||
+ | |||
+ | **Protokoll 29.6.17:**\\ | ||
+ | Diesmal haben wir mit TKinter gearbeitet. Letztes Mal haben wir zufällig Einsen in den Array eingefügt, aber eigentlich soll der Benutzer selbst per Klick Zellen auswählen können die leben. Bei der zufälligen Erzeugung der Einsen gab es wenig "überlappende" Zellen, also sind relativ viele gestorben weil in ihrem Umfeld sonst keine lebenden Zellen waren. | ||
+ | TKinter erzeugt ein Gitter mit Zellen. Diese Zellen sind Buttons und wenn man sie anklickt, werden Funktionen aufgerufen und der Zustand der Zelle ändert sich. Den Teil des Codes haben wir bekommen. Selbst programmiert haben wir dann den Teil, wo aus der Liste der Buttons mit den neuen Zuständen wieder ein Array mit Einsen und Nullen erzeugt wird, um mit unserem Programm vom letzten Mal das Umfeld und den nächsten Schritt zu definieren. | ||
+ | Den Rest haben wir auch ein bisschen umgeschrieben und angepasst (vgl. Code letzte Woche), jetzt haben wir keine Klassenstruktur mehr, die haben wir nicht so richtig verstanden gehabt. | ||
+ | <code python> | ||
+ | from Tkinter import * | ||
+ | |||
+ | |||
+ | LIVE = "red" | ||
+ | DEAD = "black" | ||
+ | N=40 | ||
+ | |||
+ | import time | ||
+ | from scipy.signal import convolve2d | ||
+ | import numpy as np | ||
+ | |||
+ | def make_callback(i,j): | ||
+ | def callback(): | ||
+ | print "click" | ||
+ | if buttons[i][j]['background']==DEAD: | ||
+ | buttons[i][j].config(background=LIVE,activebackground=LIVE) | ||
+ | else: | ||
+ | buttons[i][j].config(background=DEAD,activebackground=DEAD) | ||
+ | return callback | ||
+ | |||
+ | |||
+ | |||
+ | def simulate(buttons): | ||
+ | | ||
+ | def buttons_2_array(buttons): | ||
+ | v=np.zeros((40,40)) | ||
+ | for j in range(40): | ||
+ | for i in range (40): | ||
+ | if buttons[i][j]["background"]==LIVE: | ||
+ | v[i,j] = 1 | ||
+ | return v | ||
+ | |||
+ | def array_2_buttons(v): | ||
+ | for j in range(40): | ||
+ | for i in range (40): | ||
+ | if v[i,j] ==1: | ||
+ | buttons[i][j].config(background=LIVE,activebackground=LIVE) | ||
+ | else: | ||
+ | buttons[i][j].config(background=DEAD,activebackground=DEAD) | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | def umfeld(v): | ||
+ | a =np.zeros((40,40)) | ||
+ | for y in range(2,39): | ||
+ | for x in range (2,39): | ||
+ | l = 0 | ||
+ | if v[x, y+1] ==1: | ||
+ | l = l+1 | ||
+ | if v[x, y-1] ==1: | ||
+ | l = l+1 | ||
+ | |||
+ | if v[x+1,y] ==1: | ||
+ | l = l+1 | ||
+ | if v[x+1, y+1] ==1: | ||
+ | l=l+1 | ||
+ | if v[x+1,y-1]==1: | ||
+ | l=l+1 | ||
+ | |||
+ | if v[x-1,y] == 1: | ||
+ | l= l+1 | ||
+ | if v [x-1,y+1]==1: | ||
+ | l=l+1 | ||
+ | if v[x-1,y-1] ==1: | ||
+ | l=l+1 | ||
+ | |||
+ | if v[x,y]==1: | ||
+ | if l ==2 or l==3: | ||
+ | a[x,y] = 1 | ||
+ | else: | ||
+ | a[x,y] = 0 | ||
+ | |||
+ | if v[x,y]==0: | ||
+ | if l == 3: | ||
+ | a[x,y] = 1 | ||
+ | |||
+ | return a | ||
+ | |||
+ | |||
+ | v = buttons_2_array(buttons) | ||
+ | while True: | ||
+ | print "awdwa" | ||
+ | v = umfeld(v) | ||
+ | array_2_buttons(v) | ||
+ | master.update() | ||
+ | | ||
+ | def get_board(buttons): | ||
+ | | ||
+ | | ||
+ | def unbind_all_and_start_simulation(ev): | ||
+ | master.unbind("q") | ||
+ | | ||
+ | for row in buttons: | ||
+ | for b in row: | ||
+ | b['command'] = lambda: 1 | ||
+ | |||
+ | simulate(buttons) | ||
+ | | ||
+ | | ||
+ | | ||
+ | STOP = [] | ||
+ | |||
+ | for i in range(N): | ||
+ | buttons.append([]) | ||
+ | for j in range(N): | ||
+ | buttons[-1].append(Button(master,text="",command = make_callback(i,j))) | ||
+ | buttons[-1][-1].grid(row=i,column=j) | ||
+ | buttons[-1][-1].config(background=DEAD, activebackground=DEAD) | ||
+ | | ||
+ | master.bind("q", unbind_all_and_start_simulation) | ||
+ | return | ||
+ | | ||
+ | |||
+ | |||
+ | master = Tk() | ||
+ | buttons = [] | ||
+ | get_board(buttons) | ||
+ | mainloop() | ||
+ | |||
+ | #buttons[i][j]["background"]==LIVE: | ||
+ | |||
+ | |||
+ | </code> | ||
+ | |||
+ | **6.07.17:**\\ | ||
+ | Zuerst haben wir das Game of Life fertig gemacht (mit Pygame statt tkinter). Es läuft jetzt ziemlich schnell ab mit einem gegebenen Anfangszustand (nicht mehr selbst wählbar). Am Anfang gibt es viel mehr lebende als tote Zellen, aber mit der Zeit bilden sich Formen, die auch Conway beobachtet hat. | ||
+ | |||
+ | Wir haben außerdem versucht, den zusammengefügten Diffusions- und Reaktionsteil in 2d zu simulieren. Dafür musste man in den Laplaceteil eine weitere Dimension hinzufügen. Arik hat uns geholfen und am Ende hatten wir einen zweidimensionalen Graphen, der mit verschiedenen Farben unterschiedliche Konzentrationen zeigt. Durch Klicken wird der nächste Zeitschritt angezeigt. | ||
+ | <code python > | ||
+ | import pygame | ||
+ | import numpy as np | ||
+ | import random | ||
+ | from scipy.signal import convolve2d | ||
+ | import matplotlib.pyplot as plt | ||
+ | W = 750 | ||
+ | |||
+ | grid_size = 5 | ||
+ | N=int(W/grid_size) | ||
+ | |||
+ | grid = np.zeros((N,N)) | ||
+ | |||
+ | x0 = 10 | ||
+ | x1 = 10 | ||
+ | dx = 1 #abstand der diskreten punkte | ||
+ | dt = 0.001 | ||
+ | #D = 10.0 | ||
+ | dy = 1 | ||
+ | |||
+ | |||
+ | def init(): | ||
+ | grid = np.zeros((N,N)) | ||
+ | for y in range(N): | ||
+ | for x in range(N): | ||
+ | grid[x,y]=random.random() | ||
+ | | ||
+ | return grid | ||
+ | | ||
+ | |||
+ | def laplacian(U): | ||
+ | dx = 1 | ||
+ | return ( - 4 * U + np.roll(U,1,axis=0) + np.roll(U,-1,axis = 0) + np.roll(U,1,axis=1) + np.roll(U,-1,axis=1) ) * 1/dx**2 | ||
+ | def RU(a,b): | ||
+ | alpha = -0.005 | ||
+ | return a-a**3-b+alpha | ||
+ | |||
+ | def RV(a,b): | ||
+ | beta =10 | ||
+ | return (a-b)*beta | ||
+ | |||
+ | def NextStep(U,V): | ||
+ | delta_U =dt * ( laplacian(U) + RU(U,V)) | ||
+ | delta_V =dt* ( laplacian(V) + RV(U,V)) | ||
+ | U += delta_U | ||
+ | V += delta_V | ||
+ | return np.array(U),np.array(V) | ||
+ | |||
+ | |||
+ | |||
+ | U = init() | ||
+ | V = init() | ||
+ | N = 15000 #Zeitschritte | ||
+ | print "HAllo" | ||
+ | k=0 | ||
+ | plt.imshow(U) | ||
+ | plt.show() | ||
+ | for i in range(N): | ||
+ | k+=1 | ||
+ | print k | ||
+ | if k% 100==0: | ||
+ | plt.imshow(U) | ||
+ | plt.show() | ||
+ | U,V = NextStep(U,V) | ||
+ | |||
+ | </code> | ||
+ | |||
+ | **13.7.17**\\ | ||
+ | Heute haben wir das Labor von Herrn Engel besucht. Er beschäftigt sich mit nichtlinearer Dynamik und Strukturbildung, also u.a. mit der Belousov-Zhabotinsky-Reaktion und hatte einige Beispiele aufgebaut. | ||
+ | |||
+ | Wir haben uns einen Versuchsaufbau angeschaut, bei dem Licht wie ein Skalpell wirkte und so verschiedene Bedingungen konstruiert werden konnten. Licht löscht die Spiralwellen aus, so können z.B. Wellen abgeschnitten werden, wenn diese sich einrollen entstehen Spiralen. Es wurde auch probiert wie sich die Wellen verhalten, wenn sie durch das Licht in eine Schablone gezwungen werden, in diesem Fall war es ein Herz. Die Welle lief immer durch/um das Herz. | ||
+ | |||
+ | Außerdem konnten wir einige Musterbildungen am Computer, am Mikroskop und in der Petrischale beobachtet. | ||
+ | |||
+ | Herr Engel hat uns sehr viel erzählt und erklärt, das meiste war mit unseren Chemie-, Physik- und Mathekenntnissen schwer zu verstehen, aber die Grundaussagen konnten wir nachvollziehen, weil er viele Beispiele, z.B. aus der Biologie, eingebracht hat. Eines war über Bienen, die eine Art Laolawelle (indem sie ihren Hintern hoch- oder runter bewegen) in der Gruppe entstehen lassen. Die Welle sieht aus wie eine sich drehende Spiralwelle. Dadurch wird Feinden vorgetäuscht, dass sich an der Stelle, an der sich der Bienenschwarm befindet, ein großes Tier aufhält. | ||
+ | |||
+ | Zusätzlich hat er uns über die 3D-Struktur der Wellen erzählt. Von oben sieht man nicht, dass auch die Tiefe eine Rolle spielt. Mithilfe eines Computers wurde diese Tiefe durch eine 3. Achse definiert. Vielleicht schaffen wir das auch. | ||
+ | |||
+ | Interessant war auch, was er über die Entstehung von Herzrasen erzählt hat. Der Sinusknoten gibt sonst die Impulse für den regelmäßigen Herzschlag. Kommt ein Impuls/eine andere Welle, so löschen sich die Wellen wieder gegenseitig aus bzw. der stärkere Impuls gewinnt gegen den vom Sinusknoten. Das Herz schlägt im aggressiveren Rhythmus des Impulses, das führt zu Herzrasen oder zu schlimmerem. | ||
+ |