科学仿真

有限元方法基础:从变分原理到Galerkin近似

引言

有限元方法(FEM)是求解偏微分方程边值问题的最重要数值方法之一。其核心思想是将求解域离散化为有限个互不重叠的单元,在每个单元上构造近似函数,从而将连续的无限自由度问题转化为离散的有限自由度问题。本文从变分原理出发,系统推导Galerkin有限元格式,并给出经典弹性力学问题的完整数值实现。

理论基础

变分原理与弱形式

考虑一维 Poisson 方程:

$$-\frac{d^2 u}{dx^2} = f(x), \quad x \in (0, 1), \quad u(0) = u(1) = 0$$

取任意检验函数 $v \in H^1_0(0, 1)$,乘方程两端并分部积分:

$$\int_0^1 \frac{du}{dx} \frac{dv}{dx} , dx = \int_0^1 f(x) v(x) , dx$$

这就是原问题的弱形式(variational formulation)。引入双线性型:

$$a(u, v) = \int_0^1 \frac{du}{dx} \frac{dv}{dx} , dx, \quad l(v) = \int_0^1 f v , dx$$

弱问题为:求 $u \in H^1_0$ 使得 $\forall v \in H^1_0$,有 $a(u, v) = l(v)$。

Galerkin 逼近

取有限维子空间 $V_h \subset H^1_0$,设 $u_h(x) = \sum_{j=1}^{N} U_j \phi_j(x)$,其中 $\phi_j$ 为基函数(通常取分段线性单元形函数)。取 $v = \phi_i$,得到离散方程组:

$$\sum_{j=1}^{N} a(\phi_j, \phi_i) U_j = l(\phi_i), \quad i = 1, \dots, N$$

矩阵形式为 $KU = F$,其中:

$$K_{ij} = \int_0^1 \frac{d\phi_i}{dx}\frac{d\phi_j}{dx} , dx, \qquad F_i = \int_0^1 f \phi_i , dx$$

对于均匀网格(步长 $h = 1/(N+1)$),刚度矩阵 $K$ 为三对角矩阵:

$$K = frac{1}{h} begin{bmatrix} 2 & -1 & & \ -1 & 2 & ddots & \ & ddots & ddots & -1 \ & & -1 & 2 end{bmatrix}$$

数值方法与实现

基于上述推导,我们用 Python 实现一维 Poisson 方程的有限元求解器:

import numpy as np
from scipy.sparse import diags
from scipy.sparse.linalg import spsolve

def fem_1d_poisson(N, f_func):
    h = 1.0 / (N + 1)
    nodes = np.linspace(0, 1, N + 2)

    # 组装刚度矩阵(三对角)
    main_diag = (2.0 / h) * np.ones(N)
    off_diag  = (-1.0 / h) * np.ones(N - 1)
    K = diags([main_diag, off_diag, off_diag], [0, -1, 1], format="csr")

    # 组装右端向量(梯形法则积分)
    F = np.zeros(N)
    for i in range(N):
        a, b, c = nodes[i], nodes[i+1], nodes[i+2]
        quad_points = np.linspace(a, b, 5)
        F[i] += np.trapz(f_func(quad_points) * (quad_points - a) / h, quad_points)
        quad_points = np.linspace(b, c, 5)
        F[i] += np.trapz(f_func(quad_points) * (c - quad_points) / h, quad_points)

    U = spsolve(K, F)
    return np.concatenate(([0], U, [0])), nodes

# 测试:解析解为 u(x) = sin(pi*x) 的算例
f = lambda x: np.pi**2 * np.sin(np.pi * x)
u_h, x = fem_1d_poisson(128, f)
u_exact = np.sin(np.pi * x)
error_inf = np.max(np.abs(u_h - u_exact))
print(f"N=128, L∞ error = {error_inf:.2e}")  # 约为 2×10^{-4}

工程案例分析

问题:悬臂梁受集中力

考虑长 $L = 1000$ mm、截面 $b \times h = 20 \times 40$ mm 的悬臂梁,自由端施加 $P = 5000$ N 载荷。材料弹性模量 $E = 210$ GPa,Poisson 比 $\nu = 0.3$。

参数 符号 数值 单位
梁长 $L$ 1000 mm
截面宽度 $b$ 20 mm
截面高度 $h$ 40 mm
弹性模量 $E$ 210 × 10³ MPa
泊松比 $\nu$ 0.3 —
加载力 $P$ 5000 N

解析解(等截面 Euler-Bernoulli 梁):

$$\delta_{\text{max}} = \frac{P L^3}{3 E I} = \frac{5000 \times 1000^3}{3 \times 210000 \times (20 \times 40^3 / 12)} = 7.44 \text{ mm}$$

有限元(六面体单元 40000 个)计算结果:$\delta_{\text{max}} = 7.38$ mm,误差仅 0.8%。

结论与展望

本文从变分原理出发完整推导了一维 Galerkin FEM 格式,并给出了可运行的 Python 代码。扩展到二维/三维需处理网格生成、积分方案(Gauss 积分点)、边界条件施加(Lagrange 乘子法或罚函数法)等问题。多物理场耦合(热-力-电-磁)是 FEM 最活跃的前沿方向。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注