Solving Time-Indepdendent PDEs#
Teng-Jui Lin
Content adapted from UW CHEME 375, Chemical Engineering Computer Skills, in Spring 2021.
Python skills and numerical methods
Finite difference method for PDEs
ChemE applications
Time-independent 2D heat transfer
Time-independent 2D heat transfer#
Problem Statement. We have a thin metal slab at steady-state, having different temperatures on its four sides. Determine the equilibrium temperature of the slab of points in the interval \([1, 3]\times[1, 3]\) with equal spacing of 1.
Given boundary conditions \(T(0, y) = 75 \mathrm{^\circ C}, T(4, y) = 50 \mathrm{^\circ C}, T(x, 0) = 0 \mathrm{^\circ C}, T(x, 4) = 100 \mathrm{^\circ C}\).
Analytic expression#
Solution. We have the heat transport governing equation
where \(\nabla^2 = \frac{\partial^2}{\partial x^2} + \frac{\partial^2}{\partial y^2} + \frac{\partial^2}{\partial z^2}\).
Based on the problem statement, we have the assumptions:
No heat source/generation
\(\dot{q} = 0\)
No fluid or heat movement
\(\Phi = 0\)
Steady-state system \(\implies\) no time dependence
\(\frac{\partial T}{\partial t} = 0\)
Thin metal slab \(\implies\) 2D heat transfer (no heat transfer in \(z\) direction)
\(\frac{\partial^2 T}{\partial z^2} = 0\)
Constant thermal conductivity \(\implies k \not= f(x, y, z, t)\)
\(k\) can be simplified
Therefore, we can simplify the governing equation:
Numerical approximations#
By central finite difference, we approximate the derivatives by
Assume that the spacing in \(x\) and \(y\) directions are the same \(\Delta x = \Delta y = 1\), we have from the original equation:
For each point in the slab, we write out the expression from the above equation. We also replace the boundary conditions with numerical values. For example, at point \((i, j) = (1, 1)\), we have
From PDE to linear algebra#
We can repeat the process for all the points. In this case, we have 9 points, therefore 9 equations and 9 unknowns:
so we have the system \(\mathbf{A}\mathbf{x} = \mathbf{b}\), where
We can then solve the system of linear equations.
Implementation#
In this approach, we use numpy.linalg.solve()
to solve the linear system obtained from simplifying the PDE.
import numpy as np
import matplotlib.pyplot as plt
# create the (sparse) matrix
A_size = 9
A = np.zeros((A_size, A_size))
for i in range(A_size):
A[i, i] = 4
band_num = 4-1
for i in range(A_size-band_num):
A[3+i, i] = -1
for i in range(A_size-band_num):
A[i, 3+i] = -1
band_num = 2-1
for i in range(A_size-band_num):
A[band_num+i, i] = -1
for i in range(A_size-band_num):
A[i, band_num+i] = -1
for i in range(2, A_size-band_num, 3):
A[band_num+i, i] = 0
for i in range(2, A_size-band_num, 3):
A[i, band_num+i] = 0
A
array([[ 4., -1., 0., -1., 0., 0., 0., 0., 0.],
[-1., 4., -1., 0., -1., 0., 0., 0., 0.],
[ 0., -1., 4., 0., 0., -1., 0., 0., 0.],
[-1., 0., 0., 4., -1., 0., -1., 0., 0.],
[ 0., -1., 0., -1., 4., -1., 0., -1., 0.],
[ 0., 0., -1., 0., -1., 4., 0., 0., -1.],
[ 0., 0., 0., -1., 0., 0., 4., -1., 0.],
[ 0., 0., 0., 0., -1., 0., -1., 4., -1.],
[ 0., 0., 0., 0., 0., -1., 0., -1., 4.]])
b = np.array([75, 0, 50, 75, 0, 50, 175, 100, 150])
temperatures = np.linalg.solve(A, b)
temperatures
array([42.85714286, 33.25892857, 33.92857143, 63.16964286, 56.25 ,
52.45535714, 78.57142857, 76.11607143, 69.64285714])
row = 3
col = 3
T_profile = temperatures.reshape(row, col)
for i in np.arange(6, -1, -3):
print('{:.2f} | {:.2f} | {:.2f}'.format(*temperatures[i:i+3]))
78.57 | 76.12 | 69.64
63.17 | 56.25 | 52.46
42.86 | 33.26 | 33.93
Plotting annotated heatmap#
# plot settings
%config InlineBackend.figure_format = 'retina'
%matplotlib inline
plt.rcParams.update({
'font.family': 'Arial', # Times New Roman, Calibri
'font.weight': 'normal',
'mathtext.fontset': 'cm',
'font.size': 18,
'lines.linewidth': 2,
'axes.linewidth': 2,
'axes.spines.top': False,
'axes.spines.right': False,
'axes.titleweight': 'bold',
'axes.titlesize': 18,
'axes.labelweight': 'bold',
'xtick.major.size': 8,
'xtick.major.width': 2,
'ytick.major.size': 8,
'ytick.major.width': 2,
'figure.dpi': 80,
'legend.framealpha': 1,
'legend.edgecolor': 'black',
'legend.fancybox': False,
'legend.fontsize': 14
})
import seaborn as sns
T_heatmap = sns.heatmap(T_profile, square=True, cbar=True,
annot=True, fmt=".1f", cmap='Reds',
cbar_kws={'label': '$T \ [^\circ C]$',
'format': '%i',
'ticks': np.linspace(temperatures.min(), temperatures.max(), 5)})
T_heatmap.set_title('Temperature of thin slab')
T_heatmap.invert_yaxis()