======Flip Solver======
//Ver.18.0// \\
**//Evolves an object as a FLIP fluid object.//**
----
====Basics====
//Flip Solver// 的用处是将指定对象“发展”为 particle fluid。\\ \\
//Flip Solver// 在结构上是一种混合的结构。其结构由两部分组成:particle based 流体和 volume based 流体(Grid / voxel)。由于所有的流体数据都将存储在粒子中,因此我们只需要保留粒子的所有数据就可以继续解算(Particle 与 Grid based Fluid 的主要区别)。这种存储的形式也可以确保流体的信息不会被混淆或者丢失。\\ \\ 但是,在 Particle Based 流体模拟中,要想确保 //Divergent-Free// 是非常困难的(计算量太大),因此在 //Flip Solver// 中这一部分交由 Volume Based 模拟完成(non-divergent projection)。简单的来说,FLIP fluid 首先会以 particle 的形式进行速度场的计算,然后将计算完毕得到的,基于 particle 的速度场传递到基于 grid 的模拟中,由 gird based 模拟来完成 fluid projection。这样做也会避免粒子因为相互重叠而往同一方向运动的趋势。
FLIP fluid 由粒子及其本身属性 //pscale// 组成,因此可以使用 POP / DOP 的外部力进行推动。
\\
\\
===FLIP V.S. SPH===
* 在不需要 substep 的情况下,相较于 SPH,FLIP fluid 的速度更快。 当由于某种情况(比如模拟快速移动的流体)需要 substep 的时候,SPH 可能会更快。
* 因为粒子可以堆叠,因此 FLIP 可以做到大量的粒子堆叠而不影响模拟的稳定性。SPH 在粒子太近的时候会 “爆炸”。
* FLIP 对 substep 的要求非常低。而为了稳定模拟,SPH 需要全程的 //7-20// 倍的 substep,甚至更多。正是由于FLIP 在模拟过程使用了 volume fields 来处理 divergence, 因此 FLIP 的模拟过程消除了由于某些潜在的 “脉冲 / 爆炸” 带来的整个流体模拟的上升。这样的处理方法同时带来了其他的好处:
* 使用更少的 substep & 更少的点就可以保证模拟的稳定性
* 粒子的间距也可以非常随机
* 随时添加新的粒子到模拟中也不会破坏整个模拟。
* FLIP Solver 中内嵌了 POP solver,因此使用第二个输入端 //Particle Velocity// 就可以加入指定的外部力。任何可以修改 ''v'',''tergetv'', 或 ''force'' 属性的节点都可以使用;同时被 POP solver 支持的粒子属性和行为(color, age & aging, reaping等)也可以使用。
===Splashy vs Swirly Kernel===
在 **Volume Motion** Tab 下的 **Velocity Transfer** 选项中,我们可以选择两种不同的计算内核:**Splashy Kernel** 和 **Swirly Kernel**。Splashy Kernel 多用于高能的、noise 比较强的、大型的流体模拟(比如河流、海洋等表面都是 noise 的流体);而 Swirly Kernel 用于**高涡流**(//Vorticity//)模拟。在这种模拟中,我们需要在尽可能减少 surface 中的 noise 的同时保留模拟中存在的自然涡旋。比如岩浆,如果表面的 noise 过多,就会非常影响整体的效果。
Splashy Kernel 对应的速度转移算法是 **FLIP / PIC**;Swirly Kernel 对应的算法是 **APIC**。所有的 viscous shelf tool 都使用 Swirly Kernel。
===Tips===
* 如果需要发射大量的粒子, **Volume Source** 比 ''Particle Fluid Emitter'' 快很多(后者似乎已经不见了,新的 shelf tool 也是用的 volume source)。
* 如果场景的单位不是**米**, **Spatial Scale** 参数需要被正确设置。否则 FLIP Solver 会更精确自动调整粒子的位置,而这往往是超出场景原本的需求的。这样做会导致模拟性能下降(主要是 ''Reseeding'' 和 ''Move Outside Collision'' 的碰撞检测)。
* 多核 CPU 的机器可以关闭 ''Use Preconditioner'' 提高性能。
* 使用 //Performance Monitor// 监控整个模拟的瓶颈。总的来说,FLIP 模拟的绝大部分时间都会花费在 FLIP Solver 上。有一种可能性是粒子发射的时间占用了大量的时间,这种情况下可以考虑使用 ''Volume source''。
* 如果使用 ''DOP I/O'' 将大型的 FLIP 模拟写入硬盘,启用 **Save In Background** 可以在写入的同时继续进行模拟。在该节点中的 ''Compression'' Tab 中也可以通过删除不必要的属性来节约硬盘空间和写入时间。
* ''Reseeding'' 对保留流体表面的细节有帮助。可以考虑增加 ''Surface Oversampling'' 到 ''2'' 或更高。
* Velocity Field 针对速度的大变化做了模糊和限制,保证了流体解算在有趋势呈现 “爆炸” 的情况下可控。Pressure Field 则用于监控高 / 低压力区域,并利用该信息补偿 Velocity field。该补偿的主要体现在粒子被推动;因此这也是控制 [[https://practical.engineering/blog/2018/8/13/what-is-fluid-cavitation|cavitation]], entrapped air(此处应指流体中的气泡),fluid escape 等现象的主要方式。
* substep 通常情况下默认就好,但对快速碰撞流体的场景和慢速的高粘度流体模拟很有帮助。Surface tension 是个例外。
* 我们可以通过自建 “粘性场(sticky field)” 来对不同的对象添加不同的粘性。具体的说,首先我们可以通过在 SOP层级使用 ''sticky'' **点属性** 用于初始化粘性,再通过 Coliision 中的 **Stick On Collision ** 选项来建立控制场。
* Debugging 的准则:当看到异常的碰撞现象,首先在 FLIP 对象中打开 Collision 的可视化,查看 Solver 是如何理解碰撞的过程。
* 不推荐关闭 ''Reseed Particles'' 和将 ''jitter Scale'' 设置为 ''0'',因为这样会获得特别均匀的,呈网格分布的粒子。这样的设置会导致我们最终不能像开启以上选项一样有效的填充 voxel;而因为精度的问题,最终我们也不会得到均匀的粒子分布。
==Collision Tips==
* 精确的速度对 FLIP 模拟来说**极其的重要**。不准确的碰撞速度会导致流体的溅射或流体从碰撞几何体中泄露。为了精确的计算运动或者变形几何体的碰撞速度,**Cache Simulation** 是一定要打开的。不过,当处理大型的流体模拟的时候,我们的缓存可能会不够用。在这种情况下,我们需要关闭 Flip Object 中的 ''Allow Caching'' 选项中将 FLIP 的数据出去,也就是**仅**保留碰撞对象的缓存。
* 大部分 FLIP 模拟使用 ''2'' 或着更高的 substeps. 对于变形的碰撞对象,我们需要确认输入的几何体有**与 substep 匹配的插值**。''Collision Source'' 有插值和创建 VDB SDF 的功能,因此可以用于 FLIP。流程可以参考 Deforming Object shelf tool。
如果使用 Volume Source 作为碰撞体,那么我们需要选择 **Move Outside Collision** 的碰撞方式。因为 **Particle** 方法只在碰撞几何体为实际几何体的情况下生效。
默认的作为碰撞的 Volume Source 中,velocity scale 是 1.5。移动的容器应该设置为 1。
* 某些情况下(特别是很薄的碰撞对象),FLIP Solver 并不能在一个相对精度较低的情况下很好的模拟碰撞。这种情况下我们可以将 Flip Object 中的 ''Collision Separation'' 设置为一个比 ''Particle Separation'' 更小的值。如果碰撞对象特别的薄,我们可能还需要将碰撞几何体转化为较厚的 SDF。
* **Move Outside Collision** 是最快的碰撞处理方法。该方法可以提供最平滑的溅射,但在有快速移动的碰撞几何体场景中,该方法并不够精确。同时,该方法是**唯一**可以处理来源于 Volume Source 的碰撞体的方法。
====Parameters====
===Substeps===
关于 Min /Max Substeps(个人理解): 总的来说, Min /Max Substeps 是与 CFL condition 协同合作的。CFL condition 是一个阈值,决定解算中需要多少 substep。当该阈值被超过的时候,那么 substep 就会自动的增加,直到达到 Max。
|Min Substeps|substep 的下限,基本上不用改。|
|Max Substeps|substep 的上限。|
|CFL Condition|CFL Condition 用于检测当前模拟需要多**长**的 substep。其判断的依据是:单位substep 中,单个 particle 在流体中移动的距离。\\ \\ 举个例子,当该参数设置为 ''0.5'' 的时候,解算器将指定 substep 的长度,使得在每个 substep 之间,所有粒子的移动距离不会超过 //Particle separation// 值的 ''50%''。|
|Particle Advection CFL|为 Particle advection 设置的 CFL Condition。该值只会影响在速度场中的 particle advection 的精度,可以设置的比全局的 CFL Condition 小一些。 |
|Quantize to Max Substeps|强制指定单位 substep 的长度为 ''1 / Max Substeps'' 的倍数。比如 CFL Condition 需要 3 个 substeps, 那么三次 Substep 的长度会分别为:''.25'',''.5'',''.25''。 |
===Particle Motion===
|Apply External Forces|允许对粒子应用外力(标准的 DOP force)。\\ \\ 该选项只会在 FLIP Solver 作为大型模拟的一部分的时候关闭。|
|Force Override|默认情况下,该参数是添加 ''ballistic'' 属性的开关。''ballistic'' 属性存储在 particle 上,其作用是混合//POP// 和 //FLIP// 产生的力。该值为 ''0'' 意味着粒子只受 FLIP 的影响,为 ''1'' 则意味着只受 //POP// 力的影响,也就是粒子只由 //POP// 驱动。|
|Under-Resolved Particles|(个人理解)
Houdini 使用 finite element method 来解 N-S 方程,也就是把整个流体分成有限的小区域来解。当解算的精度不足的时候,两个太靠近的单元会因为精度的关系无法计算梯度。这种区域就被称为 Under-Resolved Region,而本参数就是指定如何处理这个区域里的粒子或者 Voxel 的方法。取决于 ''Particle Radius Scale'' 和 ''Grid Scale'' 的值(在 FLIP Object 力设置),处于 Under-Resolved 区域的粒子会不参与压力的解算。本参数控制如何处理这些粒子:\\ \\ **No Detection**\\ 不会尝试检测这些粒子\\ \\ **Detect Only**\\ 添加属性 ''underresolved'' 到每个粒子,并使用该属性统计 Under-Resolved Particles 的总数。\\ \\ **Treat as Ballistic** 使用 ''underresolved'' 属性与 Force Override 建立的属性来决定这些粒子应该以 POP 的方式或者 FLIP 的方式来处理。\\ \\ **Use Extrapolated Velocity** \\ 如果粒子的值没有超出 ''Max Cells to Extrapolate'' 的范围,则对粒子应用基于外推产生的速度(Extrapolation 也是估算的一种),否则就按 //Treat as Ballistic// 的处理方式来计算。\\ \\ **Kill** \\ 除掉所有 under-resolved particles. \\
当 **Particle Radius Scale / Grid Scale >= sqrt(3) / 2** 的时候,不会有任何 under-resolved particle 存在。 |
|Collision Detection|该参数负责处理粒子与其他对象的碰撞行为。\\ \\ **None**\\ 不做粒子的碰撞检测。只有在需要解算 pressure 的情况下粒子才会避免碰撞;但因为计算精度的问题,粒子并不能完全避免所有碰撞;这将造成某些粒子进入几何体内部。\\ \\ **Particle**\\ 执行粒子的碰撞检测。检测包括粒子与其他模拟对象之间的反馈。该碰撞检测还支持摩擦力和弹力的检测,是最精确的,也是最慢的碰撞检测方式。\\ \\ **Move Outside Collision** \\ 通过将粒子移出碰撞对象内部来完成碰撞检测。该种方式较快,但对薄的或者快速移动的碰撞对象的模拟中精度偏低。|
|Kill Unmoveable Particles|**Move Outside Collision** 模式下使用,将卡在 SDF 里的粒子清除掉。|
==Behavior==
|Collide with Volume Limits|启用 ''Volume Limits'' 中的边界,限制流体在边界之内。|
|Use Friction and Bounce|(只在碰撞检测为 //Particle// 的时候有效)使用 FLIP Object 中,Physical Tab下的摩擦力和弹力参数影响粒子。|
|Age Particles|随时间计算粒子的 ''age''。|
|Reap Particles|将 ''age'' 大于 ''life'' 的所有粒子移除。|
|Delete Attributes|删除不需要输出的属性。|
==Reseeding==
|Reseed Particles|开启该功能后,FLIP Solver 会动态的管理粒子的数量,也就是:当粒子数量不足以正确的表现流体表面时创建新的粒子,而在粒子太拥挤的时候删除粒子。使用 //Reseeding// 可以一定程度上避免碰撞附近的流体出现空气洞,同时也能为 meshing 提供更光滑的表面。|
|Particles Per Voxel|单位 voxel 产生的粒子数量。|
|Surface Oversampling|与 **Oversampling Bandwidth** 配合使用,对 **Oversampling Bandwidth** 指定采样范围内生成的粒子做**乘法(scale)**。|
|Oversampling Bandwidth|需要重复采样的 voxel 的数量。这些 voxel 来自于 surface 或者 任何surface volume 的边界(如果** Oversample at Boundaries** 开启的话)|
|Oversample At Boundaries|对 volume 的边界部分进行重复采样。也受 **Oversampling Bandwidth** 的限制。|
|Birth Threshold|如果当前粒子数量小于该参数与目标粒子数的乘积,那么粒子将会被添加到 voxel 中。|
|Death Threshold|如果当前粒子数量大于于该参数与目标粒子数的乘积,那么粒子将会被从 voxel 中移除。|
|Random Seed|该 seed 控制一个随时间而变化的随机函数。该函数用于生成新的粒子。因为高频率的 splash 对粒子位置的影响非常大,因此对于其他参数相同的模拟来说,改变此参数对模拟的 bulk motion 影响不大,但对 splash 的行为影响会非常明显。\\ \\
//Bulk motion// 是一个物理术语,大致描述了粒子群在受力时会往力的方向整体运动,但单个粒子在跟随力运动的时候会在整体的范围内随机运动。比如沙尘整体按风的方向移动,但移动的同时沙粒在沙尘内随机运动。|
|Interpolate Attributes|所有在本参数列表中的属性都会参与到插值计算中。插值发生在新加入的粒子与其周围粒子之间。相对于拷贝相邻粒子的属性,该方法更加的消耗资源,但对于某些属性的采样来说(比如 velocity),会得到更加平滑的采样效果。比如利用本参数对 viscosity 做插值,就可以得到在流体冻结和融化之间平滑转换的效果。|
过高的 **Reseeding** 会导致流体在溅射较强烈的模拟中迅速增加体积,这是因为过于拥挤的 voxel 造成的。通过降低 ** Particle Radius Scale** 和 **Death Threshold** 可以帮助缓解该问题;同时降低oversampling 的数量或者 bandwidth 也有助于解决该问题。
==Separation==
三个属性都来自 **Gas Particle separate**。\\ \\
|Apply Particle Separation|(可能是因为误差的原因?)velocity projection 并不能保证所有粒子之间的距离都与 pscale 相同。如果某些粒子直接的距离小于 pscale ,那么粒子之间的力会因为 velocity projection 而被去掉;这将导致粒子之间的距离小于正常设定,从而导致流体的收缩。|
|Separation Iterations|relaxation 的迭代次数。通常设为 1|
|Separation Rate|该参数决定将粒子向理想状态下粒子所处的位置移动多少距离。|
|Separation Scale|Sphere packing 可能会导致流体本身不能按 pscale 的值来进行堆叠。本参数可用于“解决”该问题(需要通过测试)m(|
==Droplets==