泊松方程试探法,混合形式泊松方程之FEniCS求解
泊松方程试探法,混合形式泊松方程之FEniCS求解稳态情况下,根据能量守恒,通过任意闭合曲面流出的能量(这里指热量) 必须等于 曲面内热源发出的能量:而泊松方程实际就是傅里叶定律+能量守恒的结果。如图:现在我们要将其改成一阶方程组,引入一个叫热通量(或简称 通量)的辅助矢量,不难得到:这个通量是有物理意义的,那就是所谓的傅里叶定律:热通量 与温度 的负梯度成比例。这里我们取而已。
【我已经发了同名西瓜视频,本文仅是视频中Markdown文件内容,不包括视频中讲解】
如果你希望和我一样Win10上安装FEniCS,建议采用Win10 WSL2 Ubuntu。
FEniCS讲座系列第1讲:有限元法求解偏微分方程之FEniCS入门讲解【上一讲】
第2讲要点
- 将高阶偏微分方程 变换成 1阶偏微分方程组
- 1阶偏微分方程组 变换成 1个变分方程
- 自然边界 和 基本边界
- 如何定义混合空间
- 如何自定义表达式
- FEniCS快捷可视化
以泊松方程为例,这是一个二阶方程:
现在我们要将其改成一阶方程组,引入一个叫热通量(或简称 通量)的辅助矢量,不难得到:
这个通量是有物理意义的,那就是所谓的傅里叶定律:热通量 与温度 的负梯度成比例。
这里我们取而已。
而泊松方程实际就是傅里叶定律+能量守恒的结果。如图:
稳态情况下,根据能量守恒,通过任意闭合曲面流出的能量(这里指热量) 必须等于 曲面内热源发出的能量:
进而
由于闭合区域的任意选择性,所以在整个,下式成立
对应的边界条件则需要改成:
转换成变分形式第一个方程是标量方程,选择标量测试函数;第二个方程是矢量方程,选择矢量测试函数。
方程1× 方程2· ,然后对全域积分,得到:
参考这个关系,可以具体地定义测试函数和试探函数。
将所有测试函数元组的集合记作;类似地,将所有试探函数元组的集合记作:
请注意,这里和上一讲的不同之处在于, 上的第一类边界条件 进入了变分公式(现在是自然边界条件),而第二类边界条件条件则在上进入试探空间的定义(现在是基本边界条件)。
将上面的结果整理得到最终的变分方程:
改成标准变分问题表述:寻求 满足
求解这个混合形式泊松方程- (一个单位矩阵)
- (Dirichlet边界)
- (Neumann边界)
- (法向导数)
- (源项)
from dolfin import *
# 创建单位矩形网格
mesh = UnitSquareMesh(32 32)
# 定义有限元空间和混合空间
BDM = FiniteElement("BDM" mesh.ufl_cell() 1)
DG = FiniteElement("DG" mesh.ufl_cell() 0)
W = FunctionSpace(mesh BDM * DG)
第二步:定义已提供的表达式
# 第一类界值
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·n = -g的函数G(实际对应公式中的σ)
# g = sin(5x)
class BoundarySource(UserExpression):
def __init__(self mesh **kwargs):
self.mesh = mesh
super().__init__(**kwargs)
def eval_cell(self values x ufc_cell):
cell = Cell(self.mesh ufc_cell.index)
n = cell.normal(ufc_cell.local_facet)
g = sin(5*x[0])
values[0] = -g*n[0]
values[1] = -g*n[1]
def value_shape(self):
return (2 )
G = BoundarySource(mesh degree=2)
第三步:创建和应用基本边界条件
# 定义基本边界条件
def boundary(x):
return x[1] < DOLFIN_EPS or x[1] > 1.0 - DOLFIN_EPS
bc = DirichletBC(W.sub(0) G boundary)
第四步:定义变分问题
# 定义试探函数和测试函数
(sigma u) = TrialFunctions(W)
(tau v) = TestFunctions(W)
# 定义变分形式
n = FacetNormal(mesh)
a = (div(sigma)*v dot(sigma tau) - div(tau)*u)*dx
L = f*v*dx - u0*dot(n tau)*ds
第五步:求解并绘图
# 求解
w = Function(W)
solve(a == L w bc)
(sigma u) = w.split()
# 绘图
plot(sigma)
plot(u)
ParaView可视化
# 将解保存为VTK格式
vtkFile = File("mixed_poisson/sigma.pvd")
vtkfile << sigma
vtkfile = File("mixed_poisson/u.pvd")
vtkfile << u
FEniCS快捷可视化
# 绘制矢量场图(如果是矢量场的话)
# plot(sigma mode="glyphs")
plot(sigma)
# 绘制位移图(如果是矢量场的话)
plot(sigma mode="displacement")
# 等高色图(如果是标量场的话)
# plot(u mode = "contourf" levels = 40)
# plot(u mode = "color" shading = "gouraud")
plot(u)
# 标量场3d图(曲面)
plot(u mode="warp" linewidths=0)
# 等高线(如果是标量场的话)
plot(u mode="contour")
END