【GAMES201学习笔记】物质点法入门

2023-10-20 21:50

本文主要是介绍【GAMES201学习笔记】物质点法入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 流体力学中的两种描述

1.1 拉格朗日描述

1.1.1 什么是拉格朗日描述

拉格朗日描述 的观察对象是组成物体的 质点粒子(particle) ,或者说 流体微元

  • 随着物体变化,对应 “粒子” 的位置也会随之变化,跟踪的观察对象是单个 “粒子” 的属性变化;
  • 拉格朗日描述最显著的特征就是观察对象会发生位置或者形状的变换。

1.1.2 常见的使用拉格朗日描述的方法

  • 弹簧质点模型(观察质点的变换)
  • 有限元法(观察有限微元的变换)

1.1.3 拉格朗日描述擅长的地方

  • 拉格朗日描述擅长对独立粒子的操作;
  • 物体的变换操作:这时对粒子施加相应的变换即可;
  • 粒子的质量和动量守恒是简单的;
  • 定义物体的材质:定义单个粒子相关参数。

1.1.4 拉格朗日描述不擅长的地方

由于粒子经过变换之后,对应的位置和形变都是不确定的,因此虽然可以查询之前已经建立了 邻接信息 的粒子之间的关系(当然,在拉格朗日中找邻接粒子本身是一个困难的问题);但查询未确立 邻接信息 的粒子之间的关系(例如任意两个粒子之间的距离),会异常困难。

这导致当有查询 未邻接的两个粒子 之间关系的需求时,会遇到一定的麻烦:例如在使用有限元进行仿真时,如果没有合理处理自相交问题,会发生模型穿透的情况。

弹性方块的 FEM 模拟

FEM_Cube.gif

弹性平面的 FEM 模拟

  • 由于仅做了邻接粒子之间、粒子与球之间的碰撞检测,所以在平面折叠时发生了穿透。

FEM_Plane.gif

不过目前在有限元领域,对于碰撞问题,也已经有了对应的解决方案:

  • [SIGGRAPH 2020] Incremental Potential Contact (IPC)

1.2 欧拉描述

1.2.1 什么是欧拉描述

欧拉描述 的观察对象是物体所在 空间的场网格(Grid) ,或者说 流体元胞(Cell)

  • 网格是在空间中的绝对参照系的微元,随着物体变化,网格的位置和形状不会随之变化,仅物体映射到网格上的信息发生改变;
  • 欧拉描述最显著的特征就是观察对象不会发生位置或者形状的变换。

1.2.2 欧拉描述擅长的地方

  • 拉格朗日描述擅长处理粒子之间的相对关系;
  • 物体性质的变化:质量密度、速度、温度、熵、焓,甚至单位流体中的磁通量;
  • 物体内部的压力压强计算,可以很快的获得能量密度函数;
  • 边界碰撞检测:欧拉描述可以很快的获得任意粒子之间的相对关系信息,或者说在欧拉视角下物体自然而然地在进行着碰撞检测。

1.2.3 欧拉描述不擅长的地方

  • 物体的变换:显然,拉格朗日描述擅长的地方就是欧拉描述不擅长的地方,在物体发生变换的过程中,需要更新网格和相邻网格的信息,这个过程是较为繁琐的。

2. Particle-In-Cell methods(PIC)

Note

  • 在混合拉格朗日 - 欧拉方法中,“粒子”是一等公民,“网格”是用来计算场信息的中间量。

2.1 粒子信息映射到网格(P2G)

2.1.1 思路

将粒子信息映射到网格上,或者说从一组粒子重建整个场的信息,这里采用了一个 SPH 中处理类似问题的方法:

  • 使用一个径向对称的 核函数 (有时称为 基函数 ),来确定一个粒子对周边空间的 “影响(贡献)”,即一种加权计算 ;
  • 其中粒子的影响是局部化的,核函数通常选择 有限支撑 ,即存在一个最大支撑距离;
  • 核函数是归一化的: ∮ R N ^ ( r ) d r = 1 \oint_{R} \hat{N}(\bold{r})d\bold{r} = 1 RN^(r)dr=1 ,其中 R R R 是整个支撑集。

B 样条核函数

screenShot.png

在二维空间下,仅考虑粒子周围的九个网格节点。

screenShot.png

2.1.2 代码实现

mpm88.py Line 30,42 (除去了 APIC 的部分):

for p in x:Xp = x[p] / dxbase = int(Xp - 0.5)fx = Xp - base# Quadratic B-splinew = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2]for i, j in ti.static(ti.ndrange(3, 3)):offset = ti.Vector([i, j])weight = w[i].x * w[j].ygrid_v[base + offset] += weight * (p_mass * v[p])grid_m[base + offset] += weight * p_mass

Note

  • 粒子在中间网格里;
  • base :粒子所在周边网格的网格点 p [ 0 , 0 ] \bold{p}_{[0,0]} p[0,0] ,坐标 (0.5 * dx, 0.5 * dx)
  • fx :粒子距离网格点 p [ 0 , 0 ] \bold{p}_{[0,0]} p[0,0] 的距离;
     
  • 距离中间的网格点: ω = 3 4 − ∣ ( x p − x b a s e ) − 1 ∣ 2 \omega = \frac{3}{4} - \vert (\bold{x}_p - \bold{x}_{base}) - 1 \vert^2 ω=43(xpxbase)12
     
  • 距离靠左下的网格点: ω = 1 2 ( 3 2 − ∣ x p − x b a s e ∣ ) 2 \omega = \frac{1}{2}(\frac{3}{2} - \vert \bold{x}_p - \bold{x}_{base} \vert)^2 ω=21(23xpxbase)2
     
  • 距离靠右上的网格点: ω = 1 2 ( 2 − ( 3 2 − ∣ x p − x b a s e ∣ ) ) 2 = 1 2 ( ∣ x p − x b a s e ∣ − 1 2 ) 2 \omega = \frac{1}{2}(2 - (\frac{3}{2} - \vert \bold{x}_p - \bold{x}_{base} \vert))^2 = \frac{1}{2}(\vert \bold{x}_p - \bold{x}_{base} \vert - \frac{1}{2})^2 ω=21(2(23xpxbase))2=21(xpxbase21)2

screenShot.png

mpm88.py Line 43,46:

# 对速度做一个网格质量的加权平均
for i, j in grid_m:if grid_m[i, j] > 0:grid_v[i, j] /= grid_m[i, j]grid_v[i, j].y -= dt * gravity

2.2 网格信息叠加到粒子(G2P)

2.1.1 思路

在计算完网格上各种场的对应信息之后,将周围网格的信息叠加到原粒子上。

2.2.2 代码实现

mpm88.py Line 55,68 (除去了 APIC 的部分):

for p in x:Xp = x[p] / dxbase = int(Xp - 0.5)fx = Xp - base# Quadratic B-spline w = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2]new_v = ti.Vector.zero(float, 2)for i, j in ti.static(ti.ndrange(3, 3)):offset = ti.Vector([i, j])weight = w[i].x * w[j].ynew_v += weight * g_vv[p] = new_vx[p] += dt * v[p]

2.3 PIC 的局限性

主要是在 G2P 的过程中,粒子信息是由网格信息叠加而成的,存在大量的信息缺失,直观来说就是出现了能量损耗,主要在旋转和切变的过程(主要是角动量损耗及其严重)。

  • 以速度场为例,粒子拥有 2 个自由度,而一个 3×3 的网格点有 18 个自由度:

screenShot.png

3. Affine Particle-In-Cell(APIC)

3.1 APIC 简介

screenShot.png

通过 2.3 可知,PIC 在场信息到粒子信息的过程中存在信息缺失的情况,这时不妨在这个过程中存储更多的场的信息:

符 号含 义
v 0 \bold{v}_0 v0 v 1 \bold{v}_1 v1均匀常量速度场,描述粒子原本的 2 个自由度的速度信息,不会随着 x p \bold{x}_p xp 位置的变化而变化。
C 00 \bold{C}_{00} C00随着粒子在 x 分量的变化,在 x 分量上线性变化的速度场,场的分量 C[0] 随着 x[p][0] 变化的情况。
C 10 \bold{C}_{10} C10随着粒子在 x 分量的变化,在 y 方向上线性变化的速度场,场的分量 C[1] 随着 x[p][0] 变化的情况。
C 01 \bold{C}_{01} C01随着粒子在 y 分量的变化,在 x 方向上线性变化的速度场,场的分量 C[0] 随着 x[p][1] 变化的情况。
C 11 \bold{C}_{11} C11随着粒子在 y 分量的变化,在 y 方向上线性变化的速度场,场的分量 C[1] 随着 x[p][1] 变化的情况。

3.2 APIC 的角动量是守恒的

数学证明见:

  • Tech report: the affine Particle-in-Cell method <5.3.1> <5.3.2>

3.3 代码实现

3.3.1 P2G

mpm88.py Line 30,42(除去压力计算部分):

x = ti.Vector.field(2, float, n_particles)
v = ti.Vector.field(2, float, n_particles)
C = ti.Matrix.field(2, 2, float, n_particles)for p in x:Xp = x[p] / dxbase = int(Xp - 0.5)fx = Xp - base# Quadratic B-splinew = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2]affine = C[p]for i, j in ti.static(ti.ndrange(3, 3)):offset = ti.Vector([i, j])# 网格点位置和粒子位置的偏差值dpos = (offset - fx) * dxweight = w[i].x * w[j].ygrid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos)grid_m[base + offset] += weight * p_mass

g v = [ g v . x g v . y ] = [ C 00 C 01 C 10 C 11 ] [ d p o s . x d p o s . y ] = [ C 00 ⋅ d p o s . x + C 01 ⋅ d p o s . y C 10 ⋅ d p o s . x + C 11 ⋅ d p o s . y ] \begin{aligned} \bold{g}_v &= \begin{bmatrix} \bold{g}_v.x \\ \bold{g}_v.y \end{bmatrix} \\[3ex] &= \begin{bmatrix} \bold{C}_{00} & \bold{C}_{01} \\ \bold{C}_{10} & \bold{C}_{11} \end{bmatrix} \begin{bmatrix} \bold{d}_{pos}.x \\ \bold{d}_{pos}.y \end{bmatrix} \\[3ex] &= \begin{bmatrix} \bold{C}_{00} \cdot \bold{d}_{pos}.x + \bold{C}_{01} \cdot \bold{d}_{pos}.y\\ \bold{C}_{10} \cdot \bold{d}_{pos}.x + \bold{C}_{11} \cdot \bold{d}_{pos}.y \end{bmatrix} \end{aligned} gv=[gv.xgv.y]=[C00C10C01C11][dpos.xdpos.y]=[C00dpos.x+C01dpos.yC10dpos.x+C11dpos.y]

Note

  • 其中网格点速度 g_v 、粒子位移的差分值 dpos ,与速度场 C 之间的关系,见 3.1 中的表格。

3.3.2 G2P

mpm88.py Line 30,42(除去压力计算部分):

for p in x:Xp = x[p] / dxbase = int(Xp - 0.5)fx = Xp - basew = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2]new_v = ti.Vector.zero(float, 2)new_C = ti.Matrix.zero(float, 2, 2)for i, j in ti.static(ti.ndrange(3, 3)):offset = ti.Vector([i, j])# 网格点位置和粒子位置的偏差值dpos = (offset - fx) * dxweight = w[i].x * w[j].y# 网格点的速度g_v = grid_v[base + offset]new_v += weight * g_vnew_C += 4 * weight * g_v.outer_product(dpos) / dx**2v[p] = new_vx[p] += dt * v[p]C[p] = new_C

C n e w = [ C 00 C 01 C 10 C 11 ] = 4 w Δ x 2 g v ⊗ d p o s = 4 w Δ x 2 [ g v . x g v . y ] [ d p o s . x d p o s . y ] = 4 w Δ x 2 [ g v . x ⋅ d p o s . x g v . x ⋅ d p o s . y g v . y ⋅ d p o s . x g v . y ⋅ d p o s . y ] \begin{aligned} \bold{C}_{new} &= \begin{bmatrix} \bold{C}_{00} & \bold{C}_{01} \\ \bold{C}_{10} & \bold{C}_{11} \end{bmatrix} \\[3ex] &= \cfrac{4w}{{\Delta x}^2} \space \bold{g}_v \otimes \bold{d}_{pos} \\[3ex] &= \cfrac{4w}{{\Delta x}^2} \begin{bmatrix} \bold{g}_v.x \\ \bold{g}_v.y \end{bmatrix} \begin{bmatrix} \bold{d}_{pos}.x & \bold{d}_{pos}.y \end{bmatrix} \\[3ex] &= \cfrac{4w}{{\Delta x}^2} \begin{bmatrix} \bold{g}_v.x \cdot \bold{d}_{pos}.x & \bold{g}_v.x \cdot \bold{d}_{pos}.y \\ \bold{g}_v.y \cdot \bold{d}_{pos}.x & \bold{g}_v.y \cdot \bold{d}_{pos}.y \end{bmatrix} \end{aligned} Cnew=[C00C10C01C11]=Δx24w gvdpos=Δx24w[gv.xgv.y][dpos.xdpos.y]=Δx24w[gv.xdpos.xgv.ydpos.xgv.xdpos.ygv.ydpos.y]

Note

  • 其中网格点速度 g_v 、粒子位移的差分值 dpos ,与速度场 C 之间的关系,见 3.1 中的表格。

3.4 如果需要更精确的解

APIC 可以类比于泰勒一级展开,如果有追求更高精度的需要(二级展开等),则可以使用 ployPIC

  • [SIGGRAPH Asia 2017] A polynomial particle-in-cell method

4. Material Point Method(MPM)

4.1 物质点法简介

在解决了欧拉-拉格朗日之间的信息传递问题之后(APIC),就需要真正开始进行模拟,这时需要额外增加一些信息(形变梯度 F \bold{F} F ,体积应变比 J \bold{J} J ,杨氏模量 E E E 等)

最早的一篇关于 MPM 论文:

  • [SIGGRAPH 2013] A material point method for snow simulation

距 2018 年,MPM 的相关论文:

screenShot.png

4.2 MLS-MPM

screenShot.png

P2G

  • 使用(仿射 Affine)速度更新粒子;
  • 将质量和动量分散到附近的 3×3×3 个节点。

对于每个网格点

  • 用动量除以质量得到速度;
  • 应用重力和边界条件

G2P

  • 从 3×3×3 个节点收集 速度/仿射速度(Affine)。

4.3 代码实现

4.3.1 相关参数

mpm88.py Line 2, 23:

import taichi as ti
ti.init(arch=ti.gpu)n_particles = 8192
n_grid = 128
dx = 1 / n_grid
dt = 2e-4p_rho = 1
p_vol = (dx * 0.5)**2
p_mass = p_vol * p_rho
gravity = 9.8
bound = 3
E = 400x = ti.Vector.field(2, float, n_particles)
v = ti.Vector.field(2, float, n_particles)
C = ti.Matrix.field(2, 2, float, n_particles)
# 体积比(当前体积/初始体积):
# J < 1 :粒子压缩
# J > 1 :粒子膨胀
J = ti.field(float, n_particles)grid_v = ti.Vector.field(2, float, (n_grid, n_grid))
grid_m = ti.field(float, (n_grid, n_grid))

4.3.2 P2G

mpm88.py Line 30, 42:

@ti.kernel
def substep():# init grid...... # P2Gfor p in x:Xp = x[p] / dxbase = int(Xp - 0.5)fx = Xp - basew = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2]stress = -dt * 4 * E * p_vol * (J[p] - 1) / dx**2# 动量的仿射信息affine = ti.Matrix([[stress, 0], [0, stress]]) + p_mass * C[p]for i, j in ti.static(ti.ndrange(3, 3)):offset = ti.Vector([i, j])dpos = (offset - fx) * dxweight = w[i].x * w[j].ygrid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos)grid_m[base + offset] += weight * p_mass

MPM 中,添加了一项 stress ,表示粒子受到压缩之后推开周围粒子的力(实际上是在网格层面操作):

( m v ) s t r e s s = − 4 Δ x 2 Δ t E p v o l ( J p − 1 ) (mv)_{stress} = - \cfrac{4}{\Delta x^2} \Delta t E \bold{p}_{vol}(J_\bold{p} - 1) (mv)stress=Δx24ΔtEpvol(Jp1)

4.3.3 边界条件

mpm88.py Line 43, 54:

    for i, j in grid_m:if grid_m[i, j] > 0:grid_v[i, j] /= grid_m[i, j]grid_v[i, j].y -= dt * gravityif i < bound and grid_v[i, j].x < 0:grid_v[i, j].x = 0if i > n_grid - bound and grid_v[i, j].x > 0:grid_v[i, j].x = 0if j < bound and grid_v[i, j].y < 0:grid_v[i, j].y = 0if j > n_grid - bound and grid_v[i, j].y > 0:grid_v[i, j].y = 0

4.3.4 G2P

mpm88.py Line 55, 72:

    for p in x:Xp = x[p] / dxbase = int(Xp - 0.5)fx = Xp - basew = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2]new_v = ti.Vector.zero(float, 2)new_C = ti.Matrix.zero(float, 2, 2)for i, j in ti.static(ti.ndrange(3, 3)):offset = ti.Vector([i, j])dpos = (offset - fx) * dxweight = w[i].x * w[j].yg_v = grid_v[base + offset]new_v += weight * g_vnew_C += 4 * weight * g_v.outer_product(dpos) / dx**2v[p] = new_vx[p] += dt * v[p]J[p] *= 1 + dt * new_C.trace()C[p] = new_C

J p − n e w = J p ( 1 + ( C 00 + C 11 ) Δ t ) J_{\bold{p}-new} = J_{\bold{p}}(1 + (\bold{C}_{00} + \bold{C}_{11})\Delta t) Jpnew=Jp(1+(C00+C11)Δt)

Note

  • C 00 \bold{C}_{00} C00 C 11 \bold{C}_{11} C11 同样可以用来表示粒子的膨胀(正值)和收缩(负值)。

screenShot.png

参考课程

文中相关资源来自课程:

  • [Chinagraph 2020] 用太极编写物理引擎 (5) 物质点法

这篇关于【GAMES201学习笔记】物质点法入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/249953

相关文章

从入门到精通详解Python虚拟环境完全指南

《从入门到精通详解Python虚拟环境完全指南》Python虚拟环境是一个独立的Python运行环境,它允许你为不同的项目创建隔离的Python环境,下面小编就来和大家详细介绍一下吧... 目录什么是python虚拟环境一、使用venv创建和管理虚拟环境1.1 创建虚拟环境1.2 激活虚拟环境1.3 验证虚

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Java List 使用举例(从入门到精通)

《JavaList使用举例(从入门到精通)》本文系统讲解JavaList,涵盖基础概念、核心特性、常用实现(如ArrayList、LinkedList)及性能对比,介绍创建、操作、遍历方法,结合实... 目录一、List 基础概念1.1 什么是 List?1.2 List 的核心特性1.3 List 家族成

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

史上最全MybatisPlus从入门到精通

《史上最全MybatisPlus从入门到精通》MyBatis-Plus是MyBatis增强工具,简化开发并提升效率,支持自动映射表名/字段与实体类,提供条件构造器、多种查询方式(等值/范围/模糊/分页... 目录1.简介2.基础篇2.1.通用mapper接口操作2.2.通用service接口操作3.进阶篇3

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

Python实现Word转PDF全攻略(从入门到实战)

《Python实现Word转PDF全攻略(从入门到实战)》在数字化办公场景中,Word文档的跨平台兼容性始终是个难题,而PDF格式凭借所见即所得的特性,已成为文档分发和归档的标准格式,下面小编就来和大... 目录一、为什么需要python处理Word转PDF?二、主流转换方案对比三、五套实战方案详解方案1:

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三