// HeatCanvas_all.java
import java.awt.*;
import java.awt.event.*;
public class HeatCanvas_all extends Canvas {
static final boolean DEBUG = false; // true;
private static final String message = "1D Heat Equation";
// 問題にとって基本的なパラメーター
// N: 区間の分割数
// Tmax: 最終時刻
// lambda: λ=τ/h^2
// A,B: 境界条件
// theta θ法
// erabuBC 境界条件のチョイスに用いた変数
// erabuF f(x)のチョイスに用いた変数
private int N, erabuBC, erabuF, anime;
private double Tmax, lambda, theta, A, B;
// 座標系の変換のためのパラメーター
private int CanvasX = 400, CanvasY = 400;
private double ratiox, ratioy, X0, Y0;
//キャンバス
private HeatCanvas_all c1;
private Thread th;
// コンストラクター
public HeatCanvas_all() {
super();
space(-0.1, -0.1, 1.1, 1.1);
}
public HeatCanvas_all(int cx, int cy) {
super();
CanvasX = cx; CanvasY = cy;
space(-0.1, -0.1, 1.1, 1.1);
}
public void compute(double lambda, int N,
double Tmax, double theta, double A, double B) {
this.lambda = lambda;
this.N = N;
this.Tmax = Tmax;
this.theta = theta;
this.A = A;
this.B = B;
repaint();
}
public void compute(double lambda, int N,
double Tmax, double theta,
double A, double B, int erabuBC) {
this.lambda = lambda;
this.N = N;
this.Tmax = Tmax;
this.theta = theta;
this.A = A;
this.B = B;
this.erabuBC = erabuBC;
repaint();
}
public void compute(double lambda, int N,
double Tmax, double theta,
double A, double B, int erabuBC, int erabuF) {
this.lambda = lambda;
this.N = N;
this.Tmax = Tmax;
this.theta = theta;
this.A = A;
this.B = B;
this.erabuBC = erabuBC;
this.erabuF = erabuF;
repaint();
}
public void compute(double lambda, int N,
double Tmax, double theta,
double A, double B, int erabuBC, int erabuF, int anime)
{
this.lambda = lambda;
this.N = N;
this.Tmax = Tmax;
this.theta = theta;
this.A = A;
this.B = B;
this.erabuBC = erabuBC;
this.erabuF = erabuF;
this.anime = anime;
repaint();
}
// 初期条件
private double f(double x, int erabuF) {
if (erabuF == 0) {
if (x <= 0.5)
return x;
else
return 1.0 - x;
}
else if (erabuF == 1) {
return 1.0;
}
else if (erabuF == 2){
return Math.sin(2 * x * Math.PI);
}
else
return x;
}
// 座標変換の準備
private void space(double x0, double y0, double x1, double y1) {
X0 = x0; Y0 = y0;
ratiox = CanvasX / (x1 - x0);
ratioy = CanvasY / (y1 - y0);
}
// ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系)
private int wx(double x) {
return (int)(ratiox * (x - X0));
}
// ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系)
private int wy(double y) {
return CanvasY - (int)(ratioy * (y - Y0));
}
// x[], y[] の内容をグラフにする
private void drawGraph(Graphics g, double x[], double u[]) {
for (int i = 0; i < N; i++)
g.drawLine(wx(x[i]), wy(u[i]), wx(x[i + 1]), wy(u[i + 1]));
}
// 三重対角行列のLU分解
private void trilu(int N, double [] AL, double [] AD, double [] AU) {
for (int i = 1; i < N; i++) {
AL[i+1] /= AD[i];
AD[i+1] -= AU[i] * AL[i+1];
}
}
// 三項方程式を解く
private void trisol(int N, double [] AL, double [] AD,
double [] AU, double [] F) {
int i;
for (i = 1; i < N; i++)
F[i+1] -= F[i] * AL[i+1];
F[N] /= AD[N];
for (i = N - 1; i >= 1; i--)
F[i] = (F[i] - AU[i] * F[i+1]) / AD[i];
}
public void paint(Graphics g) {
int i;
double h = 1.0 / N;
double tau = lambda * h * h;
double dt = 0.01;
int Jmax = (int) (Tmax / tau);
int skip = (int) (dt / tau + 0.5);
double c1 = -theta * lambda;
double c2 = 1.0 + 2.0 * theta * lambda;
double c3 = 1.0 - 2.0 * (1.0 - theta) * lambda;
double c4 = (1.0 - theta) * lambda;
double AL[] = new double[N+1];
double AD[] = new double[N+1];
double AU[] = new double[N+1];
double ff[] = new double[N+1];
double u[] = new double[N+1];
double x[] = new double[N+1];
for (i = 1; i < N; i++) {
AL[i] = c1; AD[i] = c2; AU[i] = c1;
}
// BC (Boundary Condition) を選択した時に変更
if (erabuBC == 1) {
AD[1] = 1.0 + theta * lambda;
AD[N-1] = 1.0 + theta * lambda;
}
else if(erabuBC == 2) {
AD[1] = 1.0 + theta * lambda;
}
else if(erabuBC == 3) {
AD[N-1] = 1.0 + theta * lambda;
}
for (i = 0; i <= N; i++)
x[i] = i * h;
// タイトルを表示する
g.setColor(Color.red);
g.setFont(new Font("Helvetica", Font.BOLD, 24));
g.drawString(message, 40, 50);
// 初期値を計算する
for (i = 0; i <= N; i++)
u[i] = f(i * h, erabuF);
// 初期値のグラフを描く
g.setColor(Color.black);
drawGraph(g, x, u);
trilu(N - 1, AL, AD, AU);
// 時間に関するループ
for (int j = 1; j <= Jmax; j++) {
ff[1] = c3 * u[1] + c4 * (u[0] + u[2])+ A * theta * lambda;
ff[N-1] = c3 * u[N-1] + c4 * (u[N-2] + u[N]) + B * theta * lambda;
// BC (Boundary Condition) を選択した時に変更
if (erabuBC == 1) {
ff[1] = c3 * u[1] + c4 * (u[0] + u[2])- A * theta * lambda * h;
ff[N-1] = c3 * u[N-1] + c4 * (u[N-2] + u[N]) + B * theta * lambda * h;
}
else if (erabuBC == 2) {
ff[1] = c3 * u[1] + c4 * (u[0] + u[2])- A * theta * lambda * h;
}
else if (erabuBC == 3) {
ff[N-1] = c3 * u[N-1] + c4 * (u[N-2] + u[N]) + B * theta * lambda * h;
}
for (i = 2; i < N - 1; i++)
ff[i] = c3 * u[i] + c4 * (u[i-1] + u[i+1]);
trisol(N - 1, AL, AD, AU, ff);
for (i = 1; i < N; i++)
u[i] = ff[i];
u[0] = A; u[N] = B;
// BC (Boundary Condition) を選択した時に変更
if (erabuBC == 1) {
u[0] = u[1] - A * h; u[N] = u[N-1] + B * h;
}
else if (erabuBC == 2) {
u[0] = u[1] - A * h;
}
else if (erabuBC == 3) {
u[N] = u[N-1] + B * h;
}
if (DEBUG)
for (i = 0; i <= N; i++)
System.out.println("u[" + i + "]=" + u[i]);
// 適当な間隔 (dt=0.01) でグラフを描く
if (j % skip == 0)
drawGraph(g, x, u);
try {
th.sleep(10 * anime);
} catch(InterruptedException e){}
}
}
}