import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def fem_1d_poisson(n_elements, L=1.0, f=-4.0):
"""Solve u'' = f with u(0)=u(L)=0 using linear FEM."""
n_nodes = n_elements + 1
x = np.linspace(0, L, n_nodes)
h = L / n_elements
# Assembly (simplified)
K = np.zeros((n_nodes, n_nodes))
F = np.zeros(n_nodes)
for e in range(n_elements):
Ke = (1/h) * np.array([[1, -1], [-1, 1]])
Fe = (f * h / 2) * np.array([1, 1])
K[e:e+2, e:e+2] += Ke
F[e:e+2] += Fe
# Apply BCs and solve
u = np.zeros(n_nodes)
u[1:-1] = np.linalg.solve(K[1:-1, 1:-1], F[1:-1])
return x, u
# Analytical solution: u = 0.5*f*x^2 - 0.5*f*L*x
x_exact = np.linspace(0, 1, 100)
u_exact = -2*x_exact**2 + 2*x_exact
# Create animation showing convergence
fig, ax = plt.subplots()
for n in [2, 3, 5, 10, 20]:
x, u = fem_1d_poisson(n)
ax.plot(x, u, 'o-', label=f'{n} elements')
ax.plot(x_exact, u_exact, 'k--', label='Exact')
ax.legend()
plt.show()
When to Stop Refining
Scenario
Stop When
Global quantities (displacement)
<2% change with refinement
Local stress
<5% change at hotspots
Fatigue life
Life prediction changes <10%
Comparison study
Both models converged similarly
Automotive Application: Bolt Hole Stress
Stress concentration at a bolt hole in a suspension arm: