2. 变分形式与弱形式推导基础
有限元方法求解偏微分方程,并不是直接在强形式上做离散,而是先把方程“放松”为一个积分等式,再在这个积分等式上选取有限维子空间做逼近。这一步转换就是弱形式推导,也是 FEniCS 中一切求解代码的数学起点。本节以泊松方程为例,完整走一遍从强形式到弱形式的过程,并说明试探函数、测试函数以及它们所在空间的含义。
强形式及其对解的要求
考虑定义在有界区域 Ω 上的泊松方程,边界分为 Dirichlet 边界 ΓD 与 Neumann 边界 ΓN:
-Δu = f 在 Ω 内
u = g 在 Γ_D 上
∂u/∂n = h 在 Γ_N 上
强形式要求 u 二阶可导,且方程在区域内每一点逐点成立。这对解的光滑性要求较高:一旦系数不连续、区域有角点,或右端项 f 只是平方可积,经典意义下的二阶导数可能根本不存在。弱形式的核心思路是:把方程乘以一个“任意”的函数再积分,通过分部积分把二阶导数转移一个到测试函数上,从而把对 u 的要求从二阶降到一阶。
分部积分:把导数“搬”过去
取测试函数 v,在 Ω 上乘以方程两端并积分:
∫_Ω (-Δu) v dx = ∫_Ω f v dx
对左端使用格林公式(分部积分的高维形式),得到:
∫_Ω ∇u · ∇v dx - ∫_∂Ω (∂u/∂n) v ds = ∫_Ω f v dx
整理后:
∫_Ω ∇u · ∇v dx = ∫_Ω f v dx + ∫_∂Ω (∂u/∂n) v ds
这一步是弱形式推导的关键。原本作用在 u 上的二阶算子 Δ 被拆成两个一阶梯度 ∇u 与 ∇v 的内积,u 与 v 的地位变得对称,对 u 的光滑性要求降为一阶弱可导。边界上的法向导数项则被保留下来,成为自然边界条件的入口。
边界条件的处理:本质与自然
Dirichlet 条件 u = g 无法直接代入边界积分,因为它约束的是 u 的取值而非导数。标准做法是把试探函数与测试函数的空间都限制为在 ΓD 上取零(对测试函数)或取给定值(对试探函数)。这样在 ΓD 上 v = 0,边界积分中对应部分自动消失。这类必须写进函数空间的条件称为本质边界条件。
Neumann 条件 ∂u/∂n = h 则直接代入剩余的边界积分,得到:
∫_Ω ∇u · ∇v dx = ∫_Ω f v dx + ∫_{Γ_N} h v ds
它不需要对函数空间做任何限制,而是通过弱形式右端项“自然”地进入方程,因此称为自然边界条件。这也是有限元方法的一个显著优点:复杂边界上的通量条件只需在右端加一项线积分,无需特殊处理。
试探函数空间与测试函数空间
弱形式要求 ∇u 与 ∇v 都平方可积,因此自然的函数空间是 Sobolev 空间 H¹(Ω)。具体地:
- 试探空间 Vg = { u ∈ H¹(Ω) : u = g 在 ΓD 上 },即满足非齐次 Dirichlet 条件的函数集合;
- 测试空间 V0 = { v ∈ H¹(Ω) : v = 0 在 ΓD 上 },即在 Dirichlet 边界上取零的函数集合。
注意 Vg 一般不是线性空间(两个满足 u = g 的函数相加后边界值为 2g),而 V0 是线性空间。实际计算中常把解写成 u = u0 + g̃,其中 g̃ 是某个满足边界条件的已知提升函数,u0 ∈ V0,从而把问题转化为在同一个线性空间 V0 中求解。FEniCS 的 DirichletBC 正是这一思想的程序化实现。
抽象变分问题
把弱形式写成抽象形式:求 u ∈ Vg,使得对任意 v ∈ V0 有
a(u, v) = L(v)
其中双线性形式 a(u,v) = ∫Ω ∇u·∇v dx,线性泛函 L(v) = ∫Ω f v dx + ∫Γ_N h v ds。这个“对任意测试函数成立”的表述,正是 FEniCS 中 solve(a == L, u, bc) 的数学原型:a 与 L 分别对应 UFL 中的双线性形式和线性形式,bc 对应本质边界条件。
一个可手算的示例
设 Ω = (0,1),f = 1,两端 Dirichlet 条件 u(0) = u(1) = 0。弱形式为:求 u ∈ V0,使对任意 v ∈ V0 有 ∫01 u′v′ dx = ∫01 v dx。若取有限元空间为分片线性函数,把区间等分为 N 段,节点值 ui 为未知量,测试函数取各节点对应的“帽函数” φi,则得到线性方程组 K u = b,其中刚度矩阵 Kij = ∫ φi′φj′ dx,载荷向量 bi = ∫ φi dx。以 N = 4、步长 h = 0.25 为例,内部节点刚度矩阵为三对角形式 (1/h)·tridiag(-1, 2, -1),右端项每个内部节点约为 h/2 = 0.125(端点帽函数积分折半)。解出内部节点值约为 0.09375、0.125、0.09375,与精确解 u(x) = x(1-x)/2 在节点处的值 0.09375、0.125、0.09375 完全一致——这是因为一维泊松方程的分片线性有限元解在节点上恰好精确。这个例子说明:弱形式并没有改变问题的解,只是换了一种对解的光滑性要求更低、更适合离散的表述方式。
为 FEniCS 实现做准备
在 FEniCS 中,弱形式直接用 UFL 语言书写,几乎与数学表达式一一对应:
from fenics import *
mesh = UnitSquareMesh(32, 32)
V = FunctionSpace(mesh, 'P', 1)
u = TrialFunction(V) # 试探函数
v = TestFunction(V) # 测试函数
f = Constant(1.0)
g = Constant(0.0)
a = dot(grad(u), grad(v)) * dx
L = f * v * dx
bc = DirichletBC(V, g, 'on_boundary')
u_sol = Function(V)
solve(a == L, u_sol, bc)
这里 TrialFunction 对应试探空间中的未知 u,TestFunction 对应测试空间中的 v,dx 表示区域积分,ds 表示边界积分。若存在 Neumann 条件 ∂u/∂n = h,只需在 L 中追加 h * v * ds 一项,无需改动 a 或函数空间。理解这一点,就能明白为什么弱形式推导中“哪些项进 a、哪些项进 L、哪些条件进 bc”是写对 FEniCS 代码的前提。
总结来看,弱形式推导完成了三件事:降低了对解的光滑性要求,把边界条件按本质与自然两类分别处理,并把微分方程转化为“对任意测试函数成立的积分等式”。这三件事共同构成了有限元离散与 FEniCS 实现的数学基础。