情報地球科学演習 (2024年前学期) 第12回

今回のテーマ: 常微分方程式の初期値問題の数値解法

演習の後半戦では、物理現象の簡単な数値シミュレーションの入口にあたる実習を行っている。 その主旨は、 手計算でやるのが大変な問題を、コンピュータに代わりにやってもらう ことであるともいえる。 これまで、非線形方程式の数値解法、及び関数の定積分の計算を扱ってきたが、今回は 常微分方程式の初期値問題を、コンピュータに代わりに解いてもらうことを考える。

例題として、

解くことを考える。 なおこの問題は、重力のある中で投げ上げられた物体の軌跡 を求める問題である。

これは2階の常微分方程式であり、講義で紹介した方法をそのまま使うことはできない。 しかし \(v\equiv\dfrac{d{x}}{d{t}}\) という新たな変数を導入してやると、

という2つの問題に分割することができる。 なお、ここで導入した \(v\) はもちろん物体の速度を表している。 また、これらの方程式の解はもちろん \(v=1-t\)、\(x=t-\dfrac{1}{2}t^2\) となる。

オイラー法による解法 (その1)

まず最初は、速度 v に関する1階の常微分方程式 (\(\dfrac{dv}{dt}=-1\) かつ \(v(t=0)=1\)) だけを、オイラー法により解くことを考える。

必要な手順 (の要点) を以下に示す。 第11回 に扱った、定積分を計算する手順とよく似ていることに注意。

program enshu13a                              
implicitnone
integer,parameter::kosuu=16
real,dimension(0:kosuu)::t,v
real::dt
real,parameter::t_kaishi=0.0,t_shuryo=2.0
integer::i
dt=(t_shuryo-t_kaishi)/real(kosuu)
doi=0,kosuu
t(i)=t_kaishi+dt*real(i)
enddo
v(0)=1.0
doi=0,kosuu-1
v(i+1)=
enddo
doi=0,kosuu
write(*,*)t(i),v(i)
enddo
endprogramenshu13a

これを基にして、オイラー法により上記の常微分方程式を解くプログラムを作成せよ [みほん]。 このプログラムを (例えば) enshu13a.f90 という名前で保存し、例の如く gfortran enshu13a.f90 とした後に、

$ ./a.out
と実行せよ。 また期待通りの答が得られているかを、以下の手順により確認せよ。

オイラー法による解法 (その2)

次は、上で作ったプログラムを改良し、速度 v に加えて位置 x も解く機能を追加 してみよう。 それには \(x\) に関する常微分方程式 \(\dfrac{d{x}}{d{t}}=v(t)\) かつ \(x(t=0)=0\) も解くようにすればよいのだが、そのために新たに追加すべき手順 (の要点) を以下に示す。

これらを参考にして、先に作ったプログラム enshu13a.f90 に、x を解く機能を追加したプログラムを作成せよ [みほん]。 そのプログラムを用いて (例の如く gfortran enshu13b.f90 などとして a.out を新たに作った後に)

$ ./a.out
と実行し、期待通りの答が得られているかどうかを確認せよ。 プログラムが正しく作られていれば、出力の先頭3行は以下のようになっているはずである。
   0.00000000       1.00000000       0.00000000    
  0.125000000      0.875000000      0.125000000    
  0.250000000      0.750000000      0.234375000    
正しく動いていることが確認できたら、本日の演習の出席確認のため、このプログラムを 末尾のフォーム 経由で提出せよ。

正しい出力が得られていることが確認できたら、

$ ./a.out > tvx.txt
と実行することにより、出力を tvx.txt という名前のファイルに書き出させておくこと。

オイラー法による解法 (その3)

上で求めた数値的な答がどれだけ正確なものかを、Gnuplotでグラフを描くことにより調べてみよう。

Gnuplot を起動し、まずは以下のように入力してみよ。

gnuplot> plot "tvx.txt" using 1:2
とすると、横軸に t、縦軸に v をとったグラフが表示される。 さらに
gnuplot> plot "tvx.txt" using 1:2,1-x
とすることで、v の真の答と合わせたグラフが表示される。 両者の比較により、数値的に求めた v がどの程度正確であるかを確かめよ。

同様に

gnuplot> plot "tvx.txt" using 1:3
とすると、横軸に t、縦軸に x をとったグラフが表示される。 また
gnuplot> plot "tvx.txt" using 1:3,x-x**2/2
とすることで、x の真の答と合わせたグラフが表示される。 両者の比較により、数値的に求めた x がどの程度正確であるかを確かめよ。

オイラー法による解法 (その4)

上で作ったプログラムで得られた x の計算結果は、真の答にさほど近いものではなかったはずだ。 実際、t=2 における真の答は x=0 であるのに対し、数値的な答では x は 0 から大きく外れていた。 当然予想されるように、「小区間」の幅を小さくすれば、言い変えれば 「小区間」の数を多くすれば、真の答により近い答が出てくる はずである。 そこで、「小区間」の数と、計算値の正確さの間の関係 を確かめてみよう。

「小区間」の数 kosuu を 2 から 4096 あるいは 8192 程度まで2倍ずつ増やしながら同じ計算 を行い、数値的に求めた x(t=2) と真の答からのずれがどう変化しているか を調べてみよ [みほん]。 なおそのためには、

$ ./a.out | tail -n 1
のようにプログラムを実行し、出力の最後の1行のみを表示させてやると便利である。 さらに kosuu と真の答からのずれの間にはどのような関係があるか。 必要に応じて両対数グラフにプロットしてみるなどして、その傾向を確認せよ。

ここで見たように、オイラー法では、「小区間」の数を増やしても、なかなか計算の精度が上がってくれない。 このことは、オイラー法で精度よく計算するためには、「小区間」を非常に細かくとる必要がある ことを意味している。 という訳でオイラー法は (「常微分方程式の解法の入門」という意味はあるものの) 実用的とはいえない。 実際の問題では、オイラー法よりも数段「高精度な」方法、例えば ルンゲ-クッタ法 と呼ばれる一連の方法を用いることがほとんどである。

余力のある人向けのおまけ: オイラー法による解法 (その5)

次回の演習では、オイラー法とその他の高精度な方法との間で、得られる答の正確さがどれくらい違うかを検討していく予定にしている。 そのための (ちょっと複雑な) プログラムを作る上では、微分方程式の右辺の式を、自前の関数として定義しておく のが便利である。 そこで (来週の課題を一部先取りするつもりで) 余力のある人は以下のプログラム例を参考にして、(その2) で作ったプログラムを修正し、自前の関数を定義・使用する仕様で書き直してみよう。 ただし (例によって) 肝心なところは (わざと) 抜いているので、各自で考えて埋めてほしい。

なお、このプログラムのミソは以下の通り。

また、このような書き方をすることで、オイラー法の前提である以下の近似的な関係式 \[ \dfrac{d{v}}{d{t}}\simeq\dfrac{v_{(i+1)}-v_{(i)}}{dt} ,\quad \dfrac{d{x}}{d{t}}\simeq\dfrac{x_{(i+1)}-x_{(i)}}{dt} \] がより明確に意識できるようになるだろう (と思う)。

program enshu13bf                             
implicitnone
integer,parameter::kosuu=16
real,dimension(0:kosuu)::t,v,x
real::dt
real,parameter::t_kaishi=0.0,t_shuryo=2.0
integer::i
dt=(t_shuryo-t_kaishi)/real(kosuu)
doi=0,kosuu
t(i)=t_kaishi+dt*real(i)
enddo
v(0)=1.0
x(0)=0.0
doi=0,kosuu-1
v(i+1)=v(i)+dt*dvdt(x(i))
x(i+1)=x(i)+dt*dxdt(v(i))
enddo
doi=0,kosuu
write(*,*)t(i),v(i),x(i)
enddo
contains
functiondvdt(x)
real,intent(in)::x
real::dvdt
dvdt=
endfunctiondvdt
functiondxdt(v)
real,intent(in)::v
real::dxdt
dxdt=v
endfunctiondxdt
endprogramenshu13bf

出席確認用プログラム提出フォーム

Moodle のコースページ 以下の 課題ファイル提出 により、各自で作成した (enshu13b.f90 に相当する) オイラー法によって本日の課題の常微分方程式を解く Fortran 90 プログラムの最終版を提出せよ。