1. 拉格朗日视角 vs 欧拉视角
拉格朗日视角:其中的元素跟随一起移动。
欧拉视角 :其中的元素固定在对应的地方,网格的点对应的速度。

2. 弹簧质点系统
胡克定律
fijfi=−k(∥xi−xj∥2lij)xij^=j∑j=ifij
牛顿第二定律
∂t∂vi∂t∂xi=mi1fi=vi
2.1 时间积分
前欧拉(显式)积分器 :根据现有状态推测以后的状态
vt+1xt+1=vt+Δtmft=xt+Δtvt
半隐式欧拉积分器 :根据现有状态推测以后的状态,速度根据推测出的速度计算
vt+1xt+1=vt+Δtmft=xt+Δtvt+1
2.2 代码
- 计算速度:vt+1=vt+Δtmft
- 与地面碰撞(防止计算位移之后陷入地下)
- 计算位移:xt+1=xt+Δtvt+1
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
| @ti.kernel def substep(): n = num_particles[None] for i in range(n):
v[i] *= ti.exp(-dt * damping[None]) total_force = ti.Vector(gravity) * particle_mass for j in range(n): if rest_length[i, j] != 0: x_ij = x[i] - x[j] total_force += -spring_stiffness[None] * (x_ij.norm() - rest_length[i, j]) * x_ij.normalized() v[i] += dt * total_force / particle_mass for i in range(n): if x[i].y < bottom_y: x[i].y = bottom_y v[i].y = 0
for i in range(num_particles[None]): x[i] += v[i] * dt
|
NOTE :
2.3 质点系统
隐式时间积分 :
xt+1vt+1=xt+Δtvt+1=vt+ΔtM−1f(xt+1)
NOTE :其中 $ \bold{M} $ 是质量矩阵。
消除 xt+1 :
vt+1=vt+ΔtM−1f(xt+Δtvt+1)
线性化(牛顿法的一步):
vt+1=vt+ΔtM−1[f(xt)+∂x∂f(xt)Δtvt+1]
3. 形变
形变映射 ϕ :静止材料位置 ↦ 形变材料位置
xdeformed=ϕ(xrest)
形变梯度 F :
F:=∂xrest∂xdeformed
Note :
- 平移过程中形变梯度保持不变:ϕ1=ϕ(xrest) 和 ϕ1=ϕ(xrest)+c 有相同的形变梯度
变形/静止体积比 J :
J=det(F)
Note :
4. 弹性体
4.1 超弹性体(Hyperelasticity)
超弹性材料:应力 – 应变关系 由 应变能密度函数 定义 :
Ψ=Ψ(F)
直观理解:Ψ 是惩罚形变的势函数。
应力 :材料的内部弹性力。
应变 :现在用 形变梯度 F 代替。
Note :
- Ψ 是应变能量密度函数
- ϕ 是形变映射
4.2 应力张量
应力:代表材料微元施加在其周围为材料微元的内力。
4.2.1 三种常用的应力张量
- Piola - Kirchhoff 应力张量 (PK1):
P(F)=∂F∂Ψ(F)
(计算简单,是在静止空间计算,需要变换到形变空间)
- 基尔霍夫应力(Kirchhoff stress) :τ
- 柯西应力张量(Cauchy stress tensor) :σ
(对称,因为角动量守恒)
4.2.2 关系式
- τ=Jσ=PFT
- P=JσF−T
Note:
- F−T :补偿材料变形
- 用 F−T 替代 F−1 :因为变换的是法向量 n 而不是 x
4.2.3 牵引力
- t=σTn
直观来说,将法向量乘以应力张量即可获得材料向周围微元施加的力。
4.3 弹性模量(各向同性材料)
E=ϵσ
K=−VdVdP
ν∈[0.0,0.5)
Note :
- 辅助项具有负泊松比;
- 泊松比为 0 时,拉长物体时,截面积不会发生变化;
- 泊松比较大时,物体会尽量保持体积不变,例如在拉长物体时,物体会变细。
拉梅常数(Lamé parameters) :
- Lamé 第一参数: λ
表示材料的压缩性,等价与体弹性模量或者杨氏模量
- Lamé 第二参数: μ
表示材料的剪切模量,用 G 表示
换算公式 :
- K=3(1−2ν)E (常用于可压缩液体)
- λ=(1+ν)(1−2ν)Eν
- μ=2(1+ν)E
广义胡克定律 :均匀和各向同性的材料
σ=2μϵ+λtr(ϵ)
5. 常见的超弹性模型
- 经典的 MPM 方法将每个粒子看做材料的一个微元,材料的本构模型会有一个能量密度函数 Ψ ;
- 对能量密度函数 Ψ 关于整个模型求积分,得到整个材料的势能;
- 势能对材料点的形变梯度进行求导:P(F)=∂F∂Ψ ;
- 物理意义上来说,势能对位置求导的结果就是力,P(F) 可以看做材料点的受力。
6.1 Neo-Hookean 模型
适用于各向同性材料
- Ψ(F)=2μ∑i[(FTF)ii−1]−μlog(J)+2λlog2(J)
- P(F)=∂F∂Ψ=μ(F−FT)+λlog(J)F−T
因为 Neo-Hookean 模型容易造成能量流失,这时可以考虑 Corotated 模型。
FEM 中应用 Neo-Hookean 模型的示例代码 :
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 28 29 30 31 32 33 34 35 36 37
| dim = 2
E, nu = 1000, 0.3 la = E * nu / ((1 + nu) * (1 - 2 * nu)) mu = E / (2 * (1 + nu))
element_V = 0.01
x = ti.Vector(dim, dt=real, shape=n_nodes, needs_grad=True) v = ti.Vector(dim, dt=real, shape=n_nodes)
total_energy = ti.var(dt=real, shape=(), needs_grad=True)
@ti.kernel def compute_total_energy(): for i in range(n_elements): ...... I1 = (F @ F.transpose()).trace() J = max(0.2, F.determinant()) element_energy_density = 0.5 * mu * (I1 - dim) - mu * ti.log(J) + 0.5 * la * ti.log(J)**2 total_energy[None] += element_energy_density * element_V
while True: for s in range(30): with ti.Tape(total_energy): compute_total_energy() ......
|
Note :
U(e)=∫eΨ(F(x))dx=VeΨ(Fe)
6.2 (Fixed)Corotated 模型
- Ψ(F)=μ∑i(σi−1)2+2λ(J−1)2
- P(F)=∂F∂Ψ=2μ(F−R)+λ(J−1)JF−T
Note :
- σi 是 F 的奇异值。
6.3 MPM 教程
《The Material Point Method for Simulating Continuum Materials》
6. 有限元基础
有限元法 :建立离散模型的 Galerkin 离散格式。
6.1 线性四面体(三角形)有限元法
线性四面体有限元(用于弹性)假设 形变映射 phi 是一个仿射变换,因此 形变梯度 F 在单个四面体单元内是恒定的,对单个元素来说:
xdeformed=Fxrest+p
对于每个元素 e ,对能量密度函数求体积的积分,可以计算其弹性势能:
U(e)=∫eΨ(F(x))dx=VeΨ(Fe)
- 其中 形变梯度 F 在元素 e 上是个常数 Fe ,即 Ψ(Fe) 也为常数,因此可以直接得到积分结果。
6.2 计算形变梯度
xdeformed=Fxrest+p
在 2D 三角形元素(三维空间中是四面体元素)中,设:
- 静止时的顶点位置: arest ,brest ,crest ;
- 变形后的顶点位置:adeformed ,bdeformed ,cdeformed 。
因为在线性三角形元素中 F 是常数,则有:
adeformedbdeformedcdeformed=Farest+p=Fbrest+p=Fcrest+p
消除 p :
(adeformed−cdeformed)(bdeformed−cdeformed)=F(arest−crest)=F(brest−crest)
现在 F2×2 有四个线性约束:
BDF=[arest−crest∣brest−crest]−1=[adeformed−cdeformed∣bdeformed−cdeformed]=DB
其中 B 在整个物理过程中是常数。因此可进行预计算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| B = ti.Matrix(dim, dim, dt=real, shape=n_elements) vertices = ti.var(dt=ti.i32, shape=(n_elements, 3))
@ti.func def compute_D(i): a = vertices[i, 0] b = vertices[i, 1] c = vertices[i, 2] return ti.Matrix.cols([x[b] - x[a], x[c] - x[a]])
@ti.kernel def compute_B(): for i in range(n_elements): B[i] = compute_D(i).inverse()
@ti.kernel def compute_total_energy(): for i in range(n_elements): D = compute_D(i) F = D @ B[i] ......
|
6.3 显式时间积分
vt+1,ixt+1,i=vt,i+Δtmift,i=xt,i+Δtvt+1,i
- vt,i 和 xt,i 存储在顶点中。
弹性势能对位置求导,结果的相反值即为顶点的受力:
ft,i=−∂xi∂U=−e∑∂xi∂U(e)=−e∑Ve∂Fe∂Ψ(Fe)∂xi∂Fe=−e∑VeP(Fe)∂xi∂Fe
1 2 3 4 5 6 7
| @ti.kernel def integrate(): for p in x: ...... v[p] = (v[p] + ((-x.grad[p] / node_mass) + ti.Vector([0, -10])) * dt) * math.exp(dt * -6) x[p] += dt * v[p]
|
vt+1,i=(vt,i+mift,i+migΔt)e−6Δt
6.4 隐式时间积分
[I−Δt2M−1∂x∂f(xt)]vt+1=vt+ΔtM−1f(xt)
力的微分计算:
∂x∂f=−∂x2∂2Ψ