// Dieses Programm integriert die FKPP-Gleichung und gibt die Ergebnisse // in Form von PNG-Grafiken aus, aus denen sich z.B. mit Programmen wie ffmpeg // kleine Filme erzeugen lassen. Die Anzahl der ausgegebenen Bilder läßt sich // über die Variable "fps" steuern (siehe unten). Für die lineare Algebra wird // dabei die Bibliothek GLS (Gnu Scientific-Library) verwendet, weswegen mit // "-ldislin -lgsl -lgslcblas" gelinkt werden muss. #include #include // Die folgende Zeile muss evtl. an Eure lokale Dislin-Installation // angepasst werden. #include "/usr/local/dislin/dislin.h" // Eine nützliche Definition zum Runden #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) // Zeitintervall [t_0,t_0] double t_0 = 0.0; double t_1 = 40.0; // Raumbereich [x_0,x_1]x[y_0,y_1] double x_0 = -50.0; double x_1 = 50.0; // Raum- und Zeitschritt. Aus diesen Größen wird weiter unten die // Anzahl der Schritte berechnet. double dx = 0.1; double dt = 0.001; // Diffusionskonstante double D = 1.0; // fps ist die Anzahl der Bilder, die pro simulierter Sekunde ausgegeben // werden sollen int fps = 20; // Die Funktion startwert wird zu Beginn des Programms verwendet, um die // Anfangsbedingung festzulegen. double startwert(int i) { double x = x_0 + i * dx; return 0.05 * exp(-5.0*x*x); } double R(double u) { return u*(1.0-u); } int main () { // Die Anzahl der räumlichen und zeitlichen Iterationsschritte wird // aus der Größe der entsprechenden Intervalle und den Schrittweiten // berechnet. int x_steps = round( (x_1 - x_0) / dx); int t_steps = round( (t_1 - t_0) / dt); // Die Variablen fname und titel werden für die Ausgabe mit Dislin // benötigt (siehe unten). char fname[80]; char titel[80]; // Je nach Wahl der globalen Variablen fps und dt wird die Zahl der // zeitlichen Iterationen berechnet, die zwischen zwei Ausgaben // durchgeführt werden sollen. int steps_pro_frame = round(1.0 / fps / dt); if ( !steps_pro_frame ) { steps_pro_frame = 1; } // Die Zeitintegration erfolgt durch Lösung eines linearen // Gleichungssystems. Im Folgenden werden die dafür benötigten Vektoren und // eine Matrix definiert. gsl_vector *u = gsl_vector_alloc(x_steps + 1); gsl_vector *gamma = gsl_vector_alloc(x_steps + 1); gsl_matrix *A = gsl_matrix_alloc(x_steps + 1, x_steps + 1); // Die folgenden beiden Variablen werden für die LU-Zerlegung // der Matrix A benötigt gsl_permutation *p = gsl_permutation_alloc(x_steps + 1); int signum = 0; int i = 0; // i ist der x-Index int k = 0; // k ist der Zeitindex // Division und Potenzierung ist relativ teuer, sollte deshalb nicht // öfter als nötig berechnet werden! double alpha = D * dt / dx / dx; // Das Feld wird entsprechend der Anfangsbedingung mit startwert() // initialisiert. for (i = 0; i <= x_steps; i++) { gsl_vector_set(u, i, startwert(i)); gsl_vector_set(gamma, i, R(gsl_vector_get(u ,i))); } // Erstelle die Matrix A for ( i=0; i<=x_steps; i++ ) { gsl_matrix_set(A, i, i, 1.0+2.0*alpha); if ( (i != 0) && (i != x_steps) ) { gsl_matrix_set(A, i, i-1, -alpha); gsl_matrix_set(A, i, i+1, -alpha); } else if ( i == 0 ) { gsl_matrix_set(A, i, i+1, -2.0*alpha); } else { gsl_matrix_set(A, i, i-1, -2.0*alpha); } } // Führe die LU-Zerlegung der Matrix A durch. Dies ermöglicht ein // schnelles Lösen der Gleichung A x = b mit verschiedenen Vektoren b. gsl_linalg_LU_decomp(A, p, &signum); for ( k = 1; k <= t_steps; k++ ) { //---{ Ausgabe mit Dislin }----------------------------------------- if ( k % steps_pro_frame == 0) { scrmod("REVERSE"); metafl("PNG"); filmod("DELETE"); sprintf(fname, "FKPP%d.png", round(k / steps_pro_frame) ); setfil(fname); disini(); texmod("ON"); sprintf(titel, "%d Stuetzstellen, $t=%f$",x_steps + 1, t_0 + (k + 1) * dt); titlin(titel, 4); // Graph für Darstellung graf(x_0, x_1, x_0, (x_1 - x_0)/10.0, -0.2, 1.2, -0.2, 0.2); title(); // Zeichne die Extrema des Potenzials ein color("RED"); rline(x_0, 1, x_1, 1); rline(x_0, 0, x_1, 0); // Zeichne zum Vergleich zwei Linien ein, die sich mit der // analytisch berechneten Ausbreitungsgeschwindigkeit der Fronten // c=2*sqrt(D) bewegen. color("GREEN"); rline(-9.0+k*dt*2.0*sqrt(D),-0.5,-9.0+k*dt*2.0*sqrt(D),1.2); rline(9.0-+k*dt*2.0*sqrt(D),-0.5,9.0-k*dt*2.0*sqrt(D),1.2); // Plotte das Feld u hsymbl(6); color("WHITE"); for (i=0; i