Problem 7.5#
The domain contains \(n+1\) nodes. However, final node (\(n+1\)) has its temperature fixed at \(\theta_1\) due to the boundary condition. As such, we do not need to ever solve for the temperature at this point.
Diffusivity matrix#
The diffusivity matrix, \(\mathbf{K}\), is therefore \((n \times n)\) and for constant grid spacing \(\Delta x\) has the following components:
or in matrix format
Forcing matrix#
The forcing matrix components are defined as follows:
Point \(x_1\)#
in the case that \(h=0\) this is simply
In the case that \(h = 1\) this is
Internal points (A = 2, … n)#
For all points except the last (\(2, ... n-1\)), the forcing is given by
When \(h=0\) this produces \(F_A = 0\). When \(h=1\) this produces
which for a constant \(\Delta x\) is simply equal to \(\Delta x\) .
The \(n\)’th node contains contributions from the last element and \(\theta_1\), given in 7.54 as
For the case that \(h=0\) this reduces to
where as for \(h(x) = 1\) it is
Case 1: h = 0#
For 10 elements (\(n=10\)) the equations then becomes
since \(H_0\) = 1
The solution is then:
import numpy as np
import matplotlib.pyplot as plt
L = 1 # Domain 0 to L
n = 10 # Number of elements
# Boundary conditions
theta_1 = 1
H0 = 1
x = np.linspace(0, L, n+1)
dx = x[1:] - x[:-1] # Delta x in each element
# Create matrix K
diag = 2 * np.ones(n) # Main diagonal
off_diag = -1 * np.ones(n-1) # Off-diagonals
K = np.diag(diag) + np.diag(off_diag, k=1) + np.diag(off_diag, k=-1)
# Edit the first diagonal element
K[0,0] = 1
# Remember division by dx for K matrix
K = K/dx
# Create vector f:
F = np.zeros(n)
F[0] = H0
F[-1] = theta_1 / dx[-1]
# Compute inverse matrix K^-1
Kinv = np.linalg.inv(K)
# Compute theta
theta = np.matmul(Kinv, F)
# Theta array for whole domain contains the n+1 point also:
total_theta = np.zeros(n+1)
total_theta[:n] = theta
total_theta[-1] = theta_1
# Plot for comparison
fig, ax = plt.subplots()
# Plot FEM
ax.plot(x, total_theta, 'k')
# Plot analytical
analytical = 1 + (1-x)*H0
ax.plot(x, analytical, '--', color='orange')
ax.legend(['FEM', 'Analytical']);
Case 2: h = 0#
Now lets look at the case when \(h = 1\). Remember that \(h\) doesn’t affect the diffusivity matrix so all we need to do is compute the new \(\mathbf{F}\) vector
# Create a new F vector
F = np.zeros(n)
for inode in range(n):
if inode == 0:
F[inode] = H0 + dx[0]/2
else:
F[inode] = 0.5 * (dx[inode-1] + dx[inode])
# The last node (n) also gets an extra contribution
# note the python indexing from 0 here means its 'n-1'
if inode == n-1:
F[inode] += theta_1/dx[inode]
# Now we can compute the temperature field:
# Compute theta
theta = np.matmul(Kinv, F)
# Theta array for whole domain contains the n+1 point also:
total_theta = np.zeros(n+1)
total_theta[:n] = theta
total_theta[-1] = theta_1
Let us compare against an analytical solution (7.19) for \(h(x)=1\) which ends up being
Note how the internal heating contributes an extra quadratic term compared to the case when \(h=0\).
# Plot for comparison
fig, ax = plt.subplots()
# Plot FEM
ax.plot(x, total_theta, 'k')
# Plot analytical
analytical = theta_1 + (1-x)*H0 + 0.5*(1 - x**2)
ax.plot(x, analytical, '--', color='orange')
ax.legend(['FEM', 'Analytical']);