拡散方程式の差分解法から数値解析の扉を開く

CFD

はじめに:シミュレーションとその重要性

こんにちは、読者の皆さん。カフェの片隅でひと息つきながら、数値解析と特に「差分法」の話を少ししようと思います。数値解析って、ちょっと堅苦しい響きがありますよね。でも、考えてみてください。この世界には、解明されていない多くの謎や、解決できない多くの問題がある。そんなとき、数値解析はまるでジャズミュージシャンのように登場し、その不確かなリズムやメロディを数学の言葉で紐解いてくれるんです。

差分法、この言葉を聞いて何を思い浮かべますか?実は、これが数値解析の中でも一つのキーテクニックなんです。熱がどのように物体を流れるのか、水がどう動いていくのか、そういった自然現象を理解する際に非常に役立ちます。

じゃあ、具体的に何ができるのかと言いますと、例えば気候変動の予測。あるいは、新しい薬の効果をシミュレーションで試してみることもできます。要するに、この方法は私たちのリアルな世界を、数学の魔法で少しだけ理解しやすくしてくれるのです。

今日はその中でも、特に「差分法」という手法に焦点を当ててみたいと思います。この差分法、名前だけ聞くと何だかよくわからないものですが、実はとても身近な存在。熱がどう広がっていくのか、あるいは水流はどう動いていくのか。そういったことを計算する際によく使われます。

だから、ここで少しだけ数値解析の世界に足を踏み入れてみませんか?おそらく、新しい何かが見えてくるでしょう。そしてその何かが、きっと皆さんの日常や未来に役立つヒントを教えてくれるはずです。

1次元非定常熱伝導方程式:棒の物語とその数学

ある日、一本の棒がありました。この棒は、夏も冬も、昼も夜も、温度が変わることがあります。太陽が出ていれば暖かくなり、夜になれば冷え込む。どうしてもこの棒の中の温度を知りたい。そう思うところからすべては始まります。次の図1のような棒を考えます。

図1 熱が伝わる棒

この棒の中の熱の移動を知るために数学の言葉で表します。どう表すかというと、1次元非定常熱伝導方程式(もしくは熱方程式)という方程式*\(^1\)が使われます。

$$\frac{\partial T}{\partial t} = a \frac{\partial^2 T}{\partial x^2}\quad (1)$$

この方程式は、ある棒(長さを\(x\)軸で表現)の温度\(T\)が時間\(t\)とともにどのように変化するかを表しています。ここで\(a\)は熱拡散率と呼ばれ、この数値が大きいほど熱は素早く拡散します。

この方程式には偏微分記号が出てきますが、これは「多変数関数の一方の変数に対する微分」を意味します。熱伝導方程式では、時間\(t\)と位置 \(x\)、この2つの変数が重要な役割を果たします。

この方程式の左側、\(\frac{\partial T}{\partial t}\)は「時間に対する温度の変化率」を表しています。つまり、この項が正であれば温度は上がるし、負であれば温度は下がるというわけです。

一方で、右側の\(\frac{\partial^2 T}{\partial x^2}\)は「位置に対する温度の二次微分」、つまり「温度の曲率」を示しています。これが正であれば、その位置は近くよりも低温で、負であればその位置は近くよりも高温です。

そして、この2つの項が等しいというのがこの方程式の核心です。つまり、時間によって温度が上がる(または下がる)スピードは、その位置での温度の曲率に比例する、ということです。

これだけ聞くと「なんだ、そんなものか」と思うかもしれませんが、この方程式一つで、たとえば地球の気候や、エンジンの冷却、さらには人体の熱伝導まで、多くの現象が説明できるのです。

離散化:時間と空間のスナップショット

人生とは、一連の瞬間を紡いでいくものです。そう考えると、棒の温度も、一連の「瞬間」によって変化していくわけです。この「瞬間」を捉えるために、数学では「離散化」という技術が使われます。棒の各部分と、それが時間とともにどう変化するかを見ていくために、棒を「スライス」に分け、時間を「刻む」わけです。

具体的には、棒の位置を\(x_0, x_1, \ldots, x_N\)として、時間を\(t_0, t_1, \ldots, t_M\)とします。そして、各\( x_i \)と\( t_j \)での温度を \( T(x_i, t_j) \)と表現します。そうすると、連続的な方程式を一連の離散的な値で近似することができます。

離散化するにはいくつかの方法がありますが、今回は時間に対して「前進差分法」、空間に対しては「中心差分法」を用います。これらは非常に基本的な離散化の手法です。

前進差分法では、時間の変化を以下のように近似します。

$$\frac{\partial T}{\partial t} \approx \frac{T(x_i, t_{j+1}) – T(x_i, t_j)}{\Delta t}\quad (2)$$

ここで、\(\Delta t = t_{j+1} – t_j\) です。

一方、中心差分法*\(^2\)では、空間における温度の変化を以下のように近似します。

$$\frac{\partial^2 T}{\partial x^2} \approx \frac{T(x_{i+1}, t_j) – 2T(x_i, t_j) + T(x_{i-1}, t_j)}{\Delta x^2}\quad (3)$$

ここで、\(\Delta x = x_{i+1} – x_i\) です。

これらを使って、元の熱方程式を離散化すると、次のような形になります。

$$\frac{T(x_i, t{j+1}) – T(x_i, t_j)}{\Delta t} = a \frac{T(x{i+1}, t_j) – 2T(x_i, t_j) + T(x_{i-1}, t_j)}{\Delta x^2}\quad (4)$$

この方程式を解くことで、任意の時間\( t_{j+1} \)と位置\( x_i \)での温度\( T \)を計算することができます。

離散化とは、つまり、このようにして現実世界の連続的な現象を、コンピュータが理解できる「スナップショット」に変換する方法なのです。

境界条件:棒の両端の物語

棒の物語が続きますが、今度はその「両端」にスポットを当てたいと思います。なぜなら、棒の両端はその熱の運命を大きく左右するからです。例えば、一方の端が炎に触れている場合、その端は常に高温になるでしょう。また、もう一方の端が氷に触れているなら、その端は低温に保たれます。

このような状況を数学的に表すのが「境界条件」です。境界条件にはいくつかの種類がありますが、主に以下の二つがよく用いられます。

  1. ディリクレ条件(Dirichlet condition): これは、棒の端の温度が一定であるという条件です。数学的には \( T(x_0, t) = T_0 \) または \( T(x_N, t) = T_N \) と表されます。
  2. ノイマン条件(Neumann condition): これは、棒の端での熱の流れが一定であるという条件です。数学的には \( \frac{\partial T}{\partial x}(x_0, t) = q_0 \) または \( \frac{\partial T}{\partial x}(x_N, t) = q_N \) と表されます。

ディリクレ条件は、例えば棒の一端が火に触れている場合や、冷蔵庫の中に入っている場合などに適用されます。ノイマン条件は、棒の一端が断熱されている場合や、一定の熱流が供給されている場合などに適用されます。

これらの境界条件は、先程の離散化された方程式と一緒に用いることで、棒の全体の温度分布を計算する際の「ルール」を決定します。それがないと、棒の端で何が起こるのか、計算上では解明できないからです。

短い棒かもしれませんが、その端には多くの物語が詰まっています。境界条件は、その物語がどう展開するかを決める重要な要素なのです。

計算安定性と拡散数:棒の安定な未来

私たちが数値解析で何かを計算するとき、その計算が「安定」であるかどうかは非常に重要です。安定とは、計算が進むにつれて誤差が積み重ならず、正確な答えに近づく状態を指します。ちょっと考えてみてください。もし計算が不安定だと、小さな誤差がどんどん大きくなってしまい、最終的には全く意味のない結果になってしまいます。

この計算の安定性を数学的に評価する方法がいくつかありますが、今回は「拡散数」を紹介します。拡散数は以下のように定義されます。

$$\text{拡散数} = a \frac{\Delta t}{\Delta x^2}\quad (5)$$

この拡散数が一定の値以下でないと、計算が不安定になる可能性があります。具体的には、拡散数が 1/2 以下であれば、計算は一般に安定とされます。

$$a \frac{\Delta t}{\Delta x^2} \leq \frac{1}{2}\quad (6)$$

この条件は、計算する前に選ぶ時間間隔\(\Delta t\)と空間間隔\(\Delta x\)に依存します。もしこの条件を満たさないと、計算結果は信頼できないものになってしまいます。

計算安定性は、ちょうど棒が安定な状態で温度分布が行われるように、計算もまた安定な状態で進められるべきです。棒の未来が不確定であるように、計算の未来もまた不確定です。しかし、拡散数という指標を使うことで、その不確定性を一定の範囲に抑えることができるのです。


サンプルコード:C++とPythonで棒の未来を覗く

さて、ここまで理論的な話が多かったので、いよいよ実践的な部分に入ります。私たちはコードを書いて、棒の未来を覗いてみましょう。コードはC++とPythonの両方でご紹介します。

C++のサンプルコード

 #include <iostream>
 #include <vector>
 #include <fstream>
 ​
 int main() {
     const int N = 100;  // 空間の分割数
     const int M = 200;  // 時間の分割数
     const double a = 0.01;  // 熱拡散率
     const double dx = 1.0 / N;  // 空間の刻み幅
     const double dt = 0.01;  // 時間の刻み幅
     const double diffusion_number = a * dt / (dx * dx);  // 拡散数
 ​
     std::vector<double> T(N, 0.0);  // 初期温度を0とする
     T[0] = 100.0;  // 左端の温度を100に設定(Dirichlet条件)
 ​
     std::ofstream output("output.txt");
 ​
     // 時間による進行
     for (int m = 0; m < M; ++m) {
         std::vector<double> new_T(N, 0.0);
         // 空間に対する計算
         for (int i = 1; i < N - 1; ++i) {
             new_T[i] = T[i] + diffusion_number * (T[i + 1] - 2 * T[i] + T[i - 1]);
        }
         T = new_T;
         output << T[50] << std::endl;  // 中央の温度を出力
    }
 }

Pythonのサンプルコード

import numpy as np
import matplotlib.pyplot as plt
 ​
N = 100  # 空間の分割数
M = 200  # 時間の分割数
a = 0.01  # 熱拡散率
dx = 1.0 / N  # 空間の刻み幅
dt = 0.01  # 時間の刻み幅
diffusion_number = a * dt / dx**2  # 拡散数
 ​
T = np.zeros(N)  # 初期温度を0とする
T[0] = 100  # 左端の温度を100に設定(Dirichlet条件)
 ​
# 時間による進行
for m in range(M):
    new_T = np.zeros(N)
    for i in range(1, N - 1):
        new_T[i] = T[i] + diffusion_number * (T[i + 1] - 2 * T[i] + T[i - 1])
    T = new_T
    if m % 20 == 0:  # 20ステップごとにプロット
        plt.plot(T)
 ​
plt.show()

以上のコードで、棒の温度分布がどのように変化するかを観察できます。C++のコードはファイルに出力し、Pythonのコードはグラフで表示しています。

おわりに:読者への感謝と棒の未来

こんなにも細かい数字と式で棒の温度変化を追いかけるのは、ちょっとやりすぎなようにも思えますよね。でも、このように微細な現象を丁寧に観察することで、私たちは大きな問題に対する新しい視点を得ることができるのです。棒がただの棒でなく、一つの宇宙であるように、数値解析もまた、単なる数学でなく、私たちが住むこの世界を理解するための「言葉」なのです。

私がジャズを聞きながらこの文章を書いているように、数値解析もまた一種の音楽です。不確かな要素を含みつつ、美しいハーモニーを生む。それが数値解析の、そして、この世界の魅力です。

このようなテクニカルな話を最後まで読んでいただき、心から感謝します。もしこの内容が皆さんの何かの役に立つ、または新しい視点を提供できたことを祈って、今日は筆を置きたいと思います。


*1 :1次元非定常熱伝導方程式の導出

図1の[\( x \)と\( x+ \Delta x\)]に着目します。まず、この領域の内部の総熱量の変化は密度\( \rho [kg/m^3]\)と比熱\( c [J/(kg \cdot K)]\)と断面積\(A [m^2]\)を用いて次のように表します。
$$\frac{d}{dt} \int_{x}^{x+\Delta x} \rho cAT(t,s)ds\quad (A1)$$
次に境界面[\( x \)と境界面\( x+ \Delta x\)]を横切る熱量は熱伝導率をkとしてフーリエの法則法則\( q=k\frac{dT(x)}{dx}\)より
$$q_x=kA\frac{\partial T(t,x)}{\partial x}\quad(A3)$$
$$q_{x+\Delta x}=kA\frac{\partial T(t,x+\Delta x)}{\partial x}\quad(A4)$$
工事中

*2 :中心差分法とテーラー展開

中心差分法では、ある点\( x_i \)における関数(この場合、温度\( T \))の二次微分を、その点の近傍における関数の値から近似的に計算します。
テーラー展開を使って、\( x_i \)を中心とした近傍の点\( x_{i+1} \)と\( x_{i-1} \)における\( T \)の値を展開すると、次のようになります。
$$T(x_{i+1}) \approx T(x_i) + (x_{i+1} – x_i) T'(x_i) + \frac{(x_{i+1} – x_i)^2}{2!} T”(x_i) \quad (A2)$$
$$T(x_{i-1}) \approx T(x_i) + (x_{i-1} – x_i) T'(x_i) + \frac{(x_{i-1} – x_i)^2}{2!} T”(x_i)\quad (A3) $$
これを整理して、\( T”(x_i) \)について解くと、
$$T(x_{i+1}) – 2T(x_i) + T(x_{i-1}) \approx (x_{i+1} – x_i)^2 T”(x_i) + (x_{i-1} – x_i)^2 T”(x_i) $$
$$ T”(x_i) \approx \frac{T(x_{i+1}) – 2T(x_i) + T(x_{i-1})}{(x_{i+1} – x_i)^2} \quad (A4)$$
となります。ここで、\( \Delta x = x_{i+1} – x_i = x_i – x_{i-1} \)とした場合、この式はさらに簡単になり、
$$T”(x_i) \approx \frac{T(x_{i+1}) – 2T(x_i) + T(x_{i-1})}{\Delta x^2} \quad (A5)$$
となります。これが中心差分法による二次微分の近似です。

このようにして、テーラー展開を用いることで、中心差分法の近似式は導出されます。これは非常に基本的ながらも強力な手法で、多くの数値計算で用いられています。

コメント

タイトルとURLをコピーしました