// Dieses Programm integriert die Diffusionsgleichung mittels // ADI(Alternativ Direction Implicit)-Methode 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 #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 = 1.0; // Raumbereich [x_0,x_1]x[y_0,y_1] double x_0 = 0.0; double x_1 = 1.0; double y_0 = 0.0; double y_1 = 1.0; // Raum- und Zeitschritt. Aus diesen Größen wird weiter unten die // Anzahl der Schritte berechnet. double dx = 0.02; double dy = 0.02; double dt = 0.001; // Diffusionskonstante double Diff = 0.1; // fps ist die Anzahl der Bilder, die pro simulierter Sekunde ausgegeben werden sollen int fps = 200; // Die Funktionen startwert und startableitung werden zu Beginn des // Programms verwendet, um die Anfangsbedingung festzulegen. double startwert(int i, int j) { double y = i * dx; double x = j * dy; return exp(-20.0*pow(x-0.5,2)-20.0*pow(y-0.5,2)); } 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 y_steps = round( (y_1 - y_0) / dy); int t_steps = round( (t_1 - t_0) / dt); printf("\nx_steps=%d y_steps=%d t_steps=%d\n",x_steps, y_steps, t_steps); // 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. int vektorlaenge = (x_steps + 1)*(y_steps + 1); gsl_vector *u = gsl_vector_alloc(vektorlaenge); gsl_vector *u_halb = gsl_vector_alloc(vektorlaenge); gsl_vector *u_temp = gsl_vector_alloc(vektorlaenge); gsl_vector *gamma = gsl_vector_alloc(vektorlaenge); gsl_matrix *A = gsl_matrix_alloc(vektorlaenge, vektorlaenge); gsl_matrix *B = gsl_matrix_alloc(vektorlaenge, vektorlaenge); gsl_matrix *C = gsl_matrix_alloc(vektorlaenge, vektorlaenge); gsl_matrix *D = gsl_matrix_alloc(vektorlaenge, vektorlaenge); // Die folgenden drei Größen werden gsl-intern für die LU-Zerlegung // benötigt. gsl_permutation *p_A = gsl_permutation_alloc(vektorlaenge); gsl_permutation *p_C = gsl_permutation_alloc(vektorlaenge); int sign = 0; int i = 0; // i ist der x-Index int j = 0; // j ist der y-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 = Diff * dt / 2.0 / dx / dx; double beta = Diff * dt / 2.0 / dy / dy; // Das Feld wird entsprechend der Anfangsbedingung mit startwert() // initialisiert. for (i = 0; i < vektorlaenge; i++) { gsl_vector_set(u, i, startwert(i / (x_steps+1), i % (x_steps+1))); } // Erstelle die Matrix A for ( i=0; i x_steps ) && (i < vektorlaenge - (x_steps + 1)) ) { gsl_matrix_set(B, i, i+x_steps+1, beta); gsl_matrix_set(B, i, i-x_steps-1, beta); } else if ( i <= x_steps ) { gsl_matrix_set(B, i, i+x_steps+1, 2.0*beta); } else { gsl_matrix_set(B, i, i-x_steps-1, 2.0*beta); } } // Erstelle die Matrix C for ( i=0; i x_steps ) && (i < vektorlaenge - (x_steps + 1)) ) { gsl_matrix_set(C, i, i+x_steps+1, -beta); gsl_matrix_set(C, i, i-x_steps-1, -beta); } else if ( i <= x_steps ) { gsl_matrix_set(C, i, i+x_steps+1, -2.0*beta); } else { gsl_matrix_set(C, i, i-x_steps-1, -2.0*beta); } } // Erstelle die Matrix D for ( i=0; i