next up previous contents
Next: A..2 2001年1月の作業 Up: A..1 1998年秋の挑戦 Previous: A..1.1 Heat1d_e_3.java

A..1.2 Heat1d_e_5.java

次の Heat1d_e_5.java (実行は http://nalab.mind.meiji.ac.jp/~mk/labo/java/sample/Heat1d_e_5.html) は Canvas を使うように書き直したプログラムである。


   1 /*
   2  * Heat1d_e_5.java -- Canvas を利用したバージョン
   3  * 1998年11月20日
   4  *
   5  * コンパイル: javac Heat1d_e_5.java
   6  * 実行:       appletviewer Heat1d_e_5.java
   7  *
   8  * <APPLET code="Heat1d_e_5.class" width=500 height=500></APPLET>
   9  *
  10  * 注意
  11  *   何と言っても古いので JDK1.1 以降では警告される。
  12  *  (1) reshape() よりも setBounds() を使えと言われる (置き換えれば OK)。
  13  *  (2) action() もよせ、と言われる。
  14  */
  15 
  16 import java.applet.*;
  17 import java.awt.*;
  18 
  19 public class Heat1d_e_5 extends Applet {
  20 
  21   private int N = 20;
  22   private double lambda = 0.5;
  23   private double Tmax = 0.5;
  24   // ユーザーとのインターフェイス (パラメーターの入力)
  25   private Label labelLambda, labelN, labelTmax;
  26   private TextField inputLambda, inputN, inputTmax;
  27   private Button startB;
  28   // 差分法による熱方程式シミュレーション
  29   private HeatCanvas c1;
  30 
  31   // 準備 (変数の用意と座標系の初期化など)
  32   public void init() {
  33     //
  34     setLayout(null);
  35     // λ=(τ/h^2) を入力するためのテキスト・フィールド
  36     labelLambda = new Label("lambda (should be <= 1/2)");
  37     add(labelLambda);
  38     labelLambda.reshape(100, 10, 200, 30);
  39     inputLambda = new TextField("" + lambda);
  40     add(inputLambda);
  41     inputLambda.reshape(300, 10, 100, 30);
  42     // N (区間の分割数) を入力するためのテキスト・フィールド
  43     labelN = new Label("N");
  44     add(labelN);
  45     labelN.reshape(100, 45, 200, 30);
  46     inputN = new TextField("" + N);
  47     add(inputN);
  48     inputN.reshape(300, 45, 100, 30);
  49     // Tmax (計算時間) を入力するためのテキスト・フィールド
  50     labelTmax = new Label("Tmax");
  51     add(labelTmax);
  52     labelTmax.reshape(100, 80, 200, 30);
  53     inputTmax = new TextField("" + Tmax);
  54     add(inputTmax);
  55     inputTmax.reshape(300, 80, 100, 30);
  56     // 再計算ボタン
  57     startB = new Button("Restart");
  58     add(startB);
  59     startB.reshape(420, 60, 50, 30);
  60     // 紙芝居「熱方程式」キャンバス
  61     c1 = new HeatCanvas();
  62     add(c1);
  63     c1.reshape(50, 100, 400, 400);
  64     c1.compute(lambda, N, Tmax);
  65   }
  66 
  67   // ボタンを押されたら、テキスト・フィールドの内容を読み取って、再描画
  68   public boolean action(Event evt, Object what) {
  69     if (evt.target == startB) {
  70       String str1 = inputLambda.getText();
  71       String str2 = inputN.getText();
  72       String str3 = inputTmax.getText();
  73       lambda = Double.valueOf(str1).doubleValue();
  74       N = Integer.parseInt(str2);
  75       Tmax = Double.valueOf(str3).doubleValue();
  76       c1.compute(lambda, N, Tmax);
  77     }
  78     return true;
  79   }
  80 
  81 }
  82 
  83 // HeatCanvas.java
  84 // 1998年11月20日
  85 
  86 class HeatCanvas extends Canvas {
  87 
  88   static final boolean DEBUG = false; // true;
  89   private static final boolean Debug = false;
  90   private static final String message = "1D Heat Equation";
  91   // 問題に取って基本的なパラメーター
  92   //   N:      区間の分割数
  93   //   Tmax:   最終時刻
  94   //   lambda: λ=τ/h^2
  95   private int N;
  96   private double Tmax, lambda;
  97   // 座標系の変換のためのパラメーター
  98   private int CanvasX = 400, CanvasY = 400;
  99   private double ratiox, ratioy, X0, Y0;
 100   //
 101   private HeatCanvas c1;
 102 
 103   // コンストラクター
 104   public HeatCanvas() {
 105     super();
 106     space(-0.1, -0.1, 1.1, 1.1);
 107   }
 108   public HeatCanvas(int cx, int cy) {
 109     super();
 110     CanvasX = cx; CanvasY = cy;
 111     space(-0.1, -0.1, 1.1, 1.1);
 112   }
 113 
 114   public void compute(double lambda, int N, double Tmax) {
 115     this.lambda = lambda;
 116     this.N = N;
 117     this.Tmax = Tmax;
 118     repaint();
 119   }
 120 
 121   // 初期条件
 122   private double f(double x) {
 123     if (x <= 0.5)
 124       return x;
 125     else
 126       return 1.0 - x;
 127   }
 128   // 座標変換の準備
 129   private void space(double x0, double y0, double x1, double y1) {
 130     X0 = x0; Y0 = y0;
 131     ratiox = CanvasX / (x1 - x0);
 132     ratioy = CanvasY / (y1 - y0);
 133   }
 134   // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系)
 135   private int wx(double x) {
 136     return (int)(ratiox * (x - X0));
 137   }
 138   // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系)
 139   private int wy(double y) {
 140     return CanvasY - (int)(ratioy * (y - Y0));
 141   }
 142   // x[], y[] の内容をグラフにする
 143   private void drawGaph(Graphics g, double x[], double u[]) {
 144     for (int i= 0; i < N; i++)
 145       g.drawLine(wx(x[i]), wy(u[i]), wx(x[i + 1]), wy(u[i + 1]));
 146   }
 147 
 148   public void paint(Graphics g) {
 149 
 150     double h = 1.0 / N;
 151     double tau = lambda * h * h;
 152     double dt = 0.01;
 153     int Jmax = (int) (Tmax / tau);
 154     int skip = (int) (dt / tau + 0.5);
 155     double [] u, unext, x;
 156 
 157     // ベクトルを確保する
 158     x = new double[N+1];
 159     u = new double[N+1];
 160     unext = new double[N+1];
 161     for (int i = 0; i <= N; i++)
 162       x[i] = i * h;
 163 
 164     if (Debug) {
 165         // これはあんまり意味がない。
 166         g.setColor(Color.pink);
 167         g.fillOval(10, 10, 330, 60);
 168         g.setColor(Color.red);
 169         for (int i=0; i<4;i++) 
 170           g.drawOval(10-i, 10-i, 330+2*i, 60+2*i);
 171 
 172         // タイトルを表示する
 173         g.setColor(Color.black);
 174         g.setFont(new Font("Helvetica", Font.BOLD, 24));
 175         g.drawString(message, 40, 50);
 176     }
 177 
 178     // 初期値を計算する
 179     for (int i = 0; i <= N; i++)
 180       u[i] = f(i * h);
 181 
 182     // 初期値のグラフを描く
 183     drawGaph(g, x, u);
 184 
 185     // 時間に関するループ
 186     for (int j = 1; j <= Jmax; j++) {
 187       int i;
 188       for (i = 1; i < N; i++)
 189         unext[i] = (1 - 2 * lambda) * u[i]
 190                 + lambda * (u[i-1] + u[i+1]);
 191       for (i = 1; i < N; i++)
 192         u[i] = unext[i];
 193       u[0] = 0; u[N] = 0;
 194 
 195       if (DEBUG)
 196         for (i = 0; i <= N; i++)
 197           System.out.println("u[" + i + "]=" + u[i]);
 198       // 適当な間隔 (dt=0.01) でグラフを描く
 199       if (j % skip == 0)
 200         drawGaph(g, x, u);
 201     }
 202   }
 203 }


next up previous contents
Next: A..2 2001年1月の作業 Up: A..1 1998年秋の挑戦 Previous: A..1.1 Heat1d_e_3.java
Masashi Katsurada
平成20年2月28日