(有限要素法を出したので、差分法もやっておくべきか、 どうして気づかなかったのか?)
正方形領域
( , ) | ||
( , ) | ||
( ) |
ここで は の境界 ((正方形の4つの辺の合併)、 は時刻 での初期温度分布である。
時間発展する系なので、 各時刻 での差分解 のグラフの鳥瞰図を描くことにする。
プログラムは http://nalab.mind.meiji.ac.jp/~mk/misc/20191229/heat2d-gnuplot.cに置いておく。
Mac のターミナルの場合: プログラムの入手、コンパイル、実行 |
curl -O http://nalab.mind.meiji.ac.jp/~mk/misc/20191229/heat2d-gnuplot.c cc heat2d-gnuplot.c ./a.out(Xcode の cc, GNU の gcc で動作確認済み) |
/* * heat2d-gnuplot.c --- 2次元領域の熱伝導方程式 * u_t=u_{xx}+u_{yy}, 同次Dirichlet境界条件 */ #include <stdio.h> #include <math.h> // rint() #include <stdlib.h> // malloc() #include <unistd.h> // sleep() typedef double *vector; typedef vector *matrix; matrix newmatrix(int m, int n) { int i; vector ap; matrix a; if ((a = malloc(m * sizeof(vector))) == NULL) return NULL; if ((ap = malloc(m * n * sizeof(double))) == NULL) { free(a); return NULL; } for (i = 0; i < m; i++) a[i] = ap + (i * n); return a; } // 初期条件 double u0(double x, double y) { return x * (1 - x) * y * (1 - y); } int main(void) { int nx, ny, i, j, n, nMax, nskip; double Tmax, tau, hx, hy, t, lambdax, lambday, lambda, c, dt, ztop; double *x, *y; matrix u, newu; FILE *gp; Tmax = 0.5; dt = 0.001; // 描画間隔 // 分割 nx = 50; ny = 50; hx = 1.0 / nx; hy = 1.0 / ny; tau = 0.25 * (hx*hx*hy*hy)/(hx*hx+hy*hy); // λ=0.25 nskip = rint(dt / tau); if (nskip <= 0) nskip = 1; lambdax = tau / (hx * hx); lambday = tau / (hy * hy); c = 1 - 2.0 * (lambdax + lambday); nMax = Tmax / tau; printf("hx=%g, hy=%g, tau=%g, nskip=%d\n", hx, hy, tau, nskip); // メモリー確保 x = malloc(sizeof(double) * (nx+1)); y = malloc(sizeof(double) * (ny+1)); u = newmatrix(nx+1,ny+1); newu = newmatrix(nx+1,ny+1); if (x == NULL || y == NULL || u == NULL || newu == NULL) { fprintf(stderr, "メモリー不足です。"); exit(1); } // gnuplot を呼び出す if ((gp = popen("gnuplot -persist", "w")) == NULL) { exit(1); } // 次の2行の注釈を外すとアニメーション GIF ファイルを作る // fprintf(gp, "set term gif animate\n"); // fprintf(gp, "set output \"heat2d.gif\"\n"); fprintf(gp, "set xlabel \"x\"\n"); fprintf(gp, "set ylabel \"y\"\n"); fprintf(gp, "set label \"2D heat equation\" at screen 0.4,0.95\n"); fprintf(gp, "set xrange [0:1]\n"); fprintf(gp, "set yrange [0:1]\n"); // 初期値 t = 0; for (i = 0; i <= nx; i++) x[i] = i * hx; for (j = 0; j <= ny; j++) y[j] = j * hy; for (i = 0; i <= nx; i++) for (j = 0; j <= ny; j++) u[i][j] = u0(x[i], y[j]); // 初期値を描く ztop = pow(10.0, ceil(log10(fabs(u[nx/2][ny/2])))); fprintf(gp, "set zrange [0:%f]\n", ztop); fprintf(gp, "splot '-' with lines title \"t=0\"\n"); for (i = 0; i <= nx; i++) { for (j = 0; j <= ny; j++) fprintf(gp, "%f %f %f\n", x[i], y[j], u[i][j]); fprintf(gp, "\n"); } fprintf(gp, "e\n"); fflush(gp); sleep(3); // 時間を進める for (n = 1; n <= nMax; n++) { t = n * tau; for (i = 1; i < nx; i++) for (j = 1; j < ny; j++) { newu[i][j] = c * u[i][j] + lambdax * (u[i+1][j]+u[i-1][j]) + lambday * (u[i][j+1]+u[i][j-1]); } for (i = 0; i <= nx; i++) newu[i][0] = newu[i][ny] = 0.0; for (j = 0; j <= ny; j++) newu[0][j] = newu[nx][j] = 0.0; for (i = 0; i <= nx; i++) for (j = 0; j <= ny; j++) u[i][j] = newu[i][j]; if (n % nskip == 0) { ztop = pow(10.0, ceil(log10(fabs(u[nx/2][ny/2])))); fprintf(gp, "set zrange [0:%f]\n", ztop); fprintf(gp, "splot '-' with lines title \"t=%g\"\n", t); for (i = 0; i <= nx; i++) { for (j = 0; j <= ny; j++) fprintf(gp, "%f %f %f\n", x[i], y[j], u[i][j]); fprintf(gp, "\n"); } fprintf(gp, "e\n"); fflush(gp); } } pclose(gp); return 0; }