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
Given boundary conditions
Analytic expression#
Solution. We have the heat transport governing equation
where
Based on the problem statement, we have the assumptions:
No heat source/generation
No fluid or heat movement
Steady-state system
no time dependenceThin metal slab
2D heat transfer (no heat transfer in direction)Constant thermal conductivity
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
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
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
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()
