はじめに
二次元非定常熱伝導方程式
\frac{\partial T}{\partial t}= \frac{k}{c\rho}\left( \frac{\partial^2 T}{\partial x^2}+\frac{\partial^2 T}{\partial y^2}\right)+\frac{q}{c\rho}\tag{1}
\end{align}
を差分法により離散化して、matlabで数値解を求めてみる。ちなみにこの偏微分方程式は放物型で拡散方程式と一緒である。
離散化
左辺をオイラー陽解法(前進差分法)で離散化すると以下のように書ける。
(左辺)= \frac{\partial T}{\partial t}=\frac{T(t+\Delta t)-T(t)}{\Delta t}\tag{2}
\end{align}
右辺は二階微分を中心差分法で離散化すると
(右辺) &\scriptsize= \frac{k}{c\rho}\left( \frac{\partial^2 T}{\partial x^2}+\frac{\partial^2 T}{\partial y^2}\right)+\frac{q}{c\rho}\\\\
\scriptsize&\scriptsize=\frac{k}{c\rho}\left( \frac{T(x+h,y)-2T(x,y)+T(x-h,y)}{h^2}+\frac{T(x,y+h)-2T(x,y)+T(x,y-h)}{h^2}\right)+\frac{q(x,y)}{c\rho}\\\\
&\scriptsize=\frac{4k}{c\rho h^2}\left[ \frac{1}{4}\left \{ T(x+h,y)+T(x-h,y) +T(x,y+h)+T(x,y-h)\right \}-T(x,y) \right ]+\frac{q(x,y)}{c\rho}\tag{3}
\end{align}
ここで正方格子を想定し、\(h=Δx=Δy\)とする。以上、式\((2)\)、式\((3)\)より、式全体は
\frac{T(t+\Delta t)-T(t)}{\Delta t}=\frac{4k}{c\rho h^2}\left[ \frac{1}{4}\left\{ T(x+h,y)+T(x-h,y) +T(x,y+h)+T(x,y-h)\right\}-T(x,y) \right ]+\frac{q(x,y)}{c\rho}\tag{4}
\end{align}
\(T(t+\Delta t)\)のみ左辺に残すと、
T(t+\Delta t)=T(t)+\frac{4k \Delta t}{c\rho h^2}\left[ \frac{1}{4}\left \{ T(x+h,y)+T(x-h,y) +T(x,y+h)+T(x,y-h)\right \}-T(x,y) \right ]+\frac{q(x,y)\Delta t}{c\rho}\tag{5}
\end{align}
となる。これが離散化された非定常熱伝導方程式である。式\((5)\)より次ステップの温度は「周囲隣接節点の平均温度」と「中心節点の温度」の差分に比例して増加していくことが分かる。
行列形式
離散化された非定常熱伝導方程式(式\((5)\))は温度に関して線形となっており、行列を用いるとよりシンプルに記述できる。
T(t+\Delta t)&\scriptsize=T(t)+\frac{k\Delta t}{c\rho h^2}\left( T(x+h,y)+T(x-h,y) +T(x,y+h)+T(x,y-h)\right)+\left( 1-\frac{4k\Delta t}{c\rho h^2} \right)T(x,y)+\frac{q(x,y)\Delta t}{c\rho}\\\\
&\scriptsize=
\left(\begin{array}{ccccc}
\frac{k\Delta t}{c\rho h^2} &
\frac{k\Delta t}{c\rho h^2} &
1-\frac{4k\Delta t}{c\rho h^2} &
\frac{k\Delta t}{c\rho h^2}&
\frac{k\Delta t}{c\rho h^2}
\end{array} \right)
\left( \begin{array}{c} T(x-h,y)\\T(x,y-h)\\T(x,y)\\T(x+h,y)\\T(x,y+h) \end{array} \right)+\frac{q(x,y)\Delta t}{c\rho}\tag{6}
\end{align}
このように行列で表した場合、その時間発展行列は中心節点要素が\(1-\frac{4k\Delta t}{c\rho h}\)、周囲隣接節点要素が\(\frac{k\Delta t}{c\rho h}\)となる。 例えば、これを3*3の2次元格子(下図)に拡張すると、
\left( \begin{array}{c}
T_1(t+\Delta t)\\
T_2(t+\Delta t)\\
T_3(t+\Delta t)\\
T_4(t+\Delta t)\\
T_5(t+\Delta t)
\end{array} \right)=
\left(\begin{array}{ccccccccc}
1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\
0 & \frac{k\Delta t}{c\rho h^2} & 0 & \frac{k\Delta t}{c\rho h^2} & 1- \frac{4k\Delta t}{c\rho h^2} & \frac{k\Delta t}{c\rho h^2} & 0 & \frac{k\Delta t}{c\rho h^2} & 0 \\
0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\
\end{array} \right)
\left( \begin{array}{c}
T_1\\
T_2\\
T_3\\
T_4\\
T_5(t)\\
T_6\\
T_7\\
T_8\\
T_9\\
\end{array} \right)
+
\frac{\Delta t}{c\rho}
\left( \begin{array}{c}
0\\
0\\
0\\
0\\
q_5\\
0\\
0\\
0\\
0\\
\end{array} \right)
\tag{7}
\end{align}
と記述できる。ここで境界節点は温度固定で与えるものとし、その節点部分のみ1と置くようにしている。これは3*3の単純な例だが、実際にはこれをn*nの格子へ拡張することで、温度場を解くことができる。
境界条件の設定
上辺が100[℃]、その他の辺が0[℃]の境界を持ち、内部温度が\(t=0[s]\)で0[℃]の二次元領域の非定常解を求める。なお内部で発熱はないものとする。(\(q=0\))
Matlabソースコード
ソースコードはこちらにアップしています。
% 初期化
clc; clear all;
% グローバル変数宣言
global dt n ita L x y
% パラメーター
L = 10;% 計算領域
n = 30;% 要素数
dL = L / n;% 要素サイズ
c = 1;% 比熱
rho = 1;% 密度
k = 1;% 熱伝導率
alpha = k / (c * rho);% 熱拡散率
t_total = 10;% SIM計算時間
dt = 0.01;% タイムステップ
ita = t_total / dt;% 反復数
% 座標の生成
x = 0 : L / n : L;
y = L : - L / n : 0;
[X, Y] = meshgrid(x, y);
% 配列確保
T2d = zeros(n, n, ita);
wall_2d = zeros(n, n);
% 熱境界条件
T1 = 100;% 北側
T2 = 0;% 東側
T3 = 0;% 南側
T4 = 0;% 西側
% 境界条件を設定と行列の作成
[T2d, wall_2d] = DefineWall(T2d, wall_2d, T1, T2, T3, T4);
% 温度ベクトルの構築
T1d = zeros(n * n, ita);
for i = 1 : ita
T1d(:, i) = reshape(T2d(:, :, i).', [n * n, 1]);% リシェイプの前に転置しておく
end
wall_1d = reshape(wall_2d.', [n * n, 1]);
% 時間発展行列の構築
A = TransitionMatrix(wall_1d, alpha, dL);
% 時間発展
for i = 2 : ita
% 時間発展
T1d(:, i) = A * T1d(:, i - 1);
T2d(:, :, i) = (reshape(T1d(:, i), [n, n])).';
% コマンドウィンドウへの出力
txt = ['ita = ',num2str(i),' / ',num2str(ita)];
disp(txt);
% 可視化
vis_contour('temp.gif', i, T2d(:, :, i), 0, 100, 1);
end
%% 以下関数
function[T2d, wall_2d] = DefineWall(T2d, wall_2d, T1, T2, T3, T4)
% グローバル変数呼び出し
global n
% 壁行列
% 1|2|3
% 8|0|4
% 7|6|5
for j = 1 : n
for i = 1 : n
if i == 1 && j == 1% 左上
T2d(i, j, :) = T1;
wall_2d(i, j) = 1;
elseif i == 1 && j == n% 右上
T2d(i, j, :) = T1;
wall_2d(i, j) = 3;
elseif i == n && j == n% 右下
T2d(i, j, :) = T3;
wall_2d(i, j) = 5;
elseif i == n && j == 1% 左下
T2d(i, j, :) = T3;
wall_2d(i, j) = 7;
elseif i == 1
T2d(i, j, :) = T1;
wall_2d(i, j) = 2;
elseif j == n
T2d(i, j, :) = T3;
wall_2d(i, j) = 4;
elseif i == n
T2d(i, j, :) = T2;
wall_2d(i, j) = 6;
elseif j == 1
T2d(i, j, :) = T4;
wall_2d(i, j) = 8;
end
end
end
end
function[A] = TransitionMatrix(wall_1d, alpha, dL)
% グローバル変数呼び出し
global n dt
% 壁行列
% 1|2|3
% 8|0|4
% 7|6|5
A = zeros(n * n, n * n);
for i = 1 : n * n
if wall_1d(i, 1) == 1% 角は二つの境界条件の平均をとる。
A(i, i + 1) = 1 / 2;
A(i, i + n) = 1 / 2;
elseif wall_1d(i, 1) == 2% 北側壁
A(i, i) = 1;
elseif wall_1d(i, 1) == 3% 角は二つの境界条件の平均をとる。
A(i, i - 1) = 1 / 2;
A(i, i + n) = 1 / 2;
elseif wall_1d(i, 1) == 4% 東側壁
A(i, i) = 1;
elseif wall_1d(i, 1) == 5% 角は二つの境界条件の平均をとる。
A(i, i - 1) = 1 / 2;
A(i, i - n) = 1 / 2;
elseif wall_1d(i, 1) == 6% 南側壁
A(i, i) = 1;
elseif wall_1d(i, 1) == 7% 角は二つの境界条件の平均をとる
A(i, i + 1) = 1 / 2;
A(i, i - n) = 1 / 2;
elseif wall_1d(i, 1) == 8% 西側壁
A(i, i) = 1;
elseif wall_1d(i, 1) == 0% 壁でないならば
A(i, i) = 1 - 4 * dt * alpha / dL^2;
A(i, i - 1) = dt * alpha / dL^2;
A(i, i + 1) = dt * alpha / dL^2;
A(i, i - n) = dt * alpha / dL^2;
A(i, i + n) = dt * alpha / dL^2;
end
end
end
function[] = vis_contour(filename, timestep, u, maxrange, minrange, fignum)
% グローバル変数呼び出し
global dt L x y
figure(fignum);
h = imagesc(x, y, u);
h.AlphaData = isfinite(u); % NaNやInfを透明にする
title(['time = ', num2str(timestep * dt, '%.3f')]);
set(gca, 'FontName', 'Times New Roman', 'FontSize', 16);
axis equal; axis tight; axis on;
xlabel('x')
ylabel('y')
view(0, 270); % 視点の設定
xticks(0 : round(L / 5) : L);
yticks(0 : round(L / 5) : L);
fig=gcf;
fig.Color='white';
colorbar;
caxis([maxrange minrange])
frame = getframe(fignum);
im = frame2im(frame);
[imind, cm] = rgb2ind(im, 256);
if timestep == 2
imwrite(imind, cm, filename, 'gif', 'DelayTime', 0.001, 'Loopcount', inf);
elseif rem(timestep, 10) == 0
imwrite(imind, cm, filename, 'gif', 'DelayTime', 0.001, 'WriteMode', 'append');
end
end
計算結果
おわりに
今回は2次元非定常熱伝導方程式の数値解を求めました。非定常熱伝導方程式(放物型偏微分方程式)は離散化すると線形マトリクスになるため計算は容易でした。 今後は解の安定性(適切なタイムステップやメッシュ解像度の決め方など)について調べてみたいと思います。