从变分原理到变分方程之FEniCS求解

FEniCS系列第四讲

【仅是视频中Markdown文件内容,不包括讲解】

从变分原理到变分方程之FEniCS求解

FEniCS系列讲座

  • 第1讲 有限元法求解偏微分方程之FEniCS入门讲解
  • 第2讲 混合形式泊松方程之FEniCS求解
  • 第3讲 非线性变分问题之FEniCS求解【上一讲】

本讲要点

  • 从变分原理到变分方程
  • 计算雅可比函数
  • 另一种求非线性变分问题的方式
  • 超弹性介质问题的求解

从变分原理到变分方程

所谓变分原理,就是可化为求泛函极值(或驻值)的问题。

对超弹性介质边界问题而言,对应的变分原理就是:总势能的最小化

寻求超弹性介质的一个应变场\(u:\Omega\to\mathbb{R}^3\),满足最小总势能\(\Pi\)

\[ \min_{u\in V}\ \Pi \]

其中,\(V\)是一个适合的满足边界条件的函数空间。这个总是势能的一般表达式:

\[ \Pi = \int_\Omega \psi(u)dx - \int_\Omega B\cdot u dx - \int_{\textcolor{red}{\partial \Omega}} \textcolor{red}{T}\cdot u ds \]

其中,\(\psi\)是弹性蓄能密度,\(B\)是体元力,\(T\)是面元牵引力。

在总势能\(\Pi\)极小点,沿任意方向\(v\)的微扰\(\epsilon\),导致的总势能变化为0,就是:

\[ F(u;v)=\left.\frac{d\Pi(u+\epsilon v)}{d\epsilon}\right|_{\epsilon=0}=0 \]

换句话说,寻求\(u\in V\),满足

\[ F(u;v)=0\qquad \forall v\in \hat{V} \]

这就是上一讲,非线性变分问题的一般表述。

上一讲提到,对非线性问题而言,要用牛顿法来结果,进而就需要计算\(F\)的雅可比(矩阵或函数),其实就是对\(F(\cdot;\cdot)\)分号前的变量求导:

\[ J(u;du,u)=\left.\frac{dF(u+\epsilon du;v)}{d\epsilon}\right|_{\epsilon=0} \]

但是上一讲的代码实现中,没有用到这个雅可比(矩阵或函数),因为上一讲是通过选择“牛顿法求解器“进行求解的,而这个求解器内部就自动会计算雅可比(矩阵)。

本讲采用,主动算出雅可比(函数)的方式,作为参数提交给solve来求解非线性变分问题。

弹性蓄能密度

考虑变形梯度\(F\)

\[ F=I+\nabla u \]

右Cauchy-Green张量\(C\)

\[ C = F^T F \]

以及标量\(J\)\(I_C\)

\[ J=\det(F)\\ I_C=\mathrm{tr}(C) \]

考虑普通的neo-Hookean蓄能模型 ,我们有:

\[ \psi=\frac{\mu}{2}(I_C-3)-\mu\ln(J)+\frac{\lambda}{2}\ln(J)^2 \]

其中,\(\mu\)\(\lambda\)是Lame参数。他们可以表示成杨氏模量\(E\)泊松比\(\nu\)

\[ \lambda=\frac{E\nu}{(1+\nu)(1-2\nu)},\qquad \mu=\frac{E}{2(1+\nu)} \]

域,边界,输入函数,参数设定

  • \(\Omega=(0,1)\times(0,1)\times(0,1)\)【单位立方体】
  • \(\Gamma_{D_0}=0\times(0,1)\times(0,1)\) 【第一类边界0】
  • \(\Gamma_{D_1}=1\times(0,1)\times(0,1)\) 【第一类边界1】
  • \(\Gamma_N=\partial\Omega-\Gamma_{D_0}-\Gamma_{D_1}\) 【第二类边界】
  • \(u=(0,0,0)\qquad \text{on } \Gamma_{D_0}\) 【第一类边界0的值】
  • \(\begin{aligned}u=(&0,\\ &(0.5+(y-0.5)\cos(\pi/3)-(z-0.5)\sin(\pi/3)-y)/2,\\ &(0.5+(y-0.5)\sin(\pi/3)+(z-0.5)\cos(\pi/3)-z)/2)\end{aligned} \quad \text{on }\Gamma_{D_1}\) 【第一类边界1的值】
  • \(T=(0.1,0,0) \qquad \text{on }\Gamma_N\)【第二类边界值】
  • \(B=(0,-0.5,0)\)【体元力】
  • \(E=10.0\)【杨氏模量】
  • \(\nu=0.3\)【泊松比】

FEniCS代码

为形式编译器的优化选项

1
2
3
4
from dolfin import *
parameters["form_compiler"]["cpp_optimize"] = True
parameters["form_compiler"]["representation"] = "uflacs"

第一步:创建网格定义函数空间

1
2
3
mesh = UnitCubeMesh(24, 16, 16)
V = VectorFunctionSpace(mesh, "Lagrange", 1)

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

1
2
3
4
5
6
7
c = Constant((0.0, 0.0, 0.0))
r = Expression(("scale*0.0",
"scale*(y0 + (x[1] - y0)*cos(theta) - (x[2] - z0)*sin(theta) - x[1])",
"scale*(z0 + (x[1] - y0)*sin(theta) + (x[2] - z0)*cos(theta) - x[2])"),
scale = 0.5, y0 = 0.5, z0 = 0.5, theta = pi/3, degree=2)
B = Constant((0.0, -0.5, 0.0)) # 体元力
T = Constant((0.1, 0.0, 0.0))

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

1
2
3
4
5
6
7
8
9
10
11
12
# 标记边界子域
# def left(x, on_boundary):
# return on_boundary and near(x[0], 0.0)
#def right(x, on_boundary):
# return on_boundary and near(x[0], 1.0)
left = CompiledSubDomain("on_boundary && near(x[0], side)", side = 0.0)
right = CompiledSubDomain("on_boundary && near(x[0], side)", side = 1.0)
# 定义基本边界条件 (x = 0 or x = 1)
bcl = DirichletBC(V, c, left)
bcr = DirichletBC(V, r, right)
bcs = [bcl, bcr]

第四步:定义变分问题

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
# 定义形式函数
du = TrialFunction(V)
v = TestFunction(V)
u = Function(V)

# 变形梯度 和 右Cauchy-Green张量
d = len(u)
I = Identity(d)
F = I + grad(u)
C = F.T*F
# 变形张量的不变量
Ic = tr(C)
J = det(F)
# 弹性参数
E, nu = 10.0, 0.3
mu, lmbda = Constant(E/(2*(1 + nu))), Constant(E*nu/((1 + nu)*(1 - 2*nu)))

# 应变储能密度(可压缩的neo-Hookean模型)
psi = (mu/2)*(Ic - 3) - mu*ln(J) + (lmbda/2)*(ln(J))**2

# 总势能Pi
Pi = psi*dx - dot(B, u)*dx - dot(T, u)*ds
# 计算总势能Pi的一阶变分(关于u沿v的方向导数)
F = derivative(Pi, u, v)
# 计算F的雅可比
J = derivative(F, u, du)

第五步:求解并绘图

1
2
3
4
5
6
# 求解变分问题
solve(F == 0, u, bcs, J=J)
# 将解保存为VTK格式
file = File("displacement.pvd");
file << u;

END