有限元法求解偏微分方程之FEniCS入门讲解

FEniCS入门讲解(求解泊松方程)

FEniCS是一个有限元法求解偏微分方程的开源计算平台。

  • 泊松方程
  • 将泊松方程转化成(弱)变分形式
  • 求解微分方程边值问题(1维泊松方程)
  • 求解2维泊松方程
  • ParaView中查看解

泊松方程

第一个例子自然是求解著名的泊松方程。

Δu=f in Ωu|ΓD=u0 on ΓDun|ΓN=g on ΓN=ΩΓD

将泊松方程转化成(弱)变分形式

首先:对泊松方程两边都乘上测试函数v,然后对全域Ω积分。

ΩΔuvdx=Ωfvdx

这里需要说明一下试探函数测试函数的概念。

测试函数,定义为: V^={vH1(Ω):v=0 on ΓD}

试探函数,定义为: V={uH1(Ω):u=u0 on ΓD}

然后,对上面这个变分方程进行变换

Δuv=(xixiu)v=xi(uxiv)uxiuxi=(uv)uv

Ωuvdx=Ωfvdx+Ω(uv)dx

Ω(uv)dx=Ωnuvds=Ωunvds=ΓNgvds

Ωuvdx=Ωfvdx+ΓNgvds

左边是双线性形式a(u,v),右边是线性形式L(v):

a(u,v)=ΩuvdxL(v)=Ωfvdx+ΓNgvds

于是得到标准的变分问题:寻求uV,满足

a(u,v)=L(v)vV^

这就是和前面的泊松问题等价的变分问题。

求解微分方程边值问题(1维泊松方程)

u=fu(0)=0, u(1)=g

有了前面的准备,现在可以写代码求解了。

第一步:为求解域创建网格,并定义函数空间

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from dolfin import *

# 单元个数
nel = 20
# 左右端点
xmin = 0
xmax = 1
# 试探/测试函数的多项式阶数
p = 2

# 创建网格
mesh = IntervalMesh(nel,xmin,xmax)
# 使用连续Galerkin定义函数空间
# 每个单元上的p阶(拉格朗日)函数
V = FunctionSpace(mesh,"CG",p)

第二步:定义已提供的表达式

python
1
2
3
u0 = Constant(0)
f = Constant(-1)
g = Constant(1)

第三步:创建和应用Dirichlet边界条件

python
1
2
3
4
5
# 定义Dirichlet边界(x = 0)
def dirichlet_boundary(x, on_boundary):
return on_boundary and abs(x[0]) < DOLFIN_EPS
# 在点x=0施加一个Dirichlet条件
bc = DirichletBC(V,u0,dirichlet_boundary)

第四步:定义变分问题

python
1
2
3
4
5
u = TrialFunction(V)
v = TestFunction(V)

a = inner(grad(u),grad(v))*dx
L = f*v*dx+g*v*ds

第五步:求解并绘图

python
1
2
3
4
5
6
# 求解
u = Function(V)
solve(a == L, u, bc)

# 绘图
plot(u)

求解2维泊松方程

  • Ω=[0,1]×[0,1] (一个单位矩阵)
  • ΓD={(0,y)(1,y)Ω}(Dirichlet边界)
  • ΓN={(x,0)(x,1)Ω} (Neumann边界)
  • g=sin(5x) (法向导数)
  • f=10exp{(x0.5)2+(y0.5)20.02} (源项)

类似地,也分五步求解

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from dolfin import *

# 第一步:为求解域创建网格,并定义函数空间
mesh = UnitSquareMesh(32, 32)
V = FunctionSpace(mesh, "Lagrange", 1)

# 第二步:定义已提供的表达式
u0 = Constant(0.0)
f = Expression("10*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)", degree=2)
g = Expression("sin(5*x[0])", degree=2)

# 第三步:创建和应用`Dirichlet`边界条件
def boundary(x):
return x[0] < DOLFIN_EPS or x[0] > 1.0 - DOLFIN_EPS
bc = DirichletBC(V, u0, boundary)

# 第四步:定义变分问题
u = TrialFunction(V)
v = TestFunction(V)
a = inner(grad(u), grad(v))*dx
L = f*v*dx + g*v*ds

# 第五步:求解并绘图

u = Function(V)
solve(a == L, u, bc)
plot(u)

ParaView中查看解

python
1
2
3
# 将解保存为VTK格式
file = File("poisson.pvd")
file << u

【结束】