Leftmost dambreak运行效果如下所示:
看到好多PIC的代码都和MAC掺在一起,用了marker和速度网格上的advection(backtrace particle)啥的。我自己写的时候还是比较喜欢mpm focus在粒子上的逻辑(staggered grid还是要用的),代码的逻辑大概是:
init_particle()
while running:
init_grid()
p2g() # particle to grid transfer
add_force(dt)
pressure_projection()
g2p(dt) # grid to particle transfer
其中particle位置的更新在g2p里面:
def g2p(dt):
for x in p:
...
x[p] += v * dt
感觉这样做的好处是,在下一个循环的时候,自然而然particle transfer出来的grid就已经是advection过的了。
不过现在我不确定自己写的对不对。找了好多网上的代码,基本运行结果都不尽相同,好像没有一个统一测试样例的ground truth。我自己把参数设置到和yuanming老师几年前写的webgl fluid相同,跑出来的结果也有区别。
在对比其他人代码的过程中,我主要有三个疑惑:
-
速度场的外插(extrapolate velocity)是必要的吗?如果更新粒子位置的时候,不用midpoint(x[p] + v0.5dt)的速度,是不是就不需要了呢?我发现速度场的外插也非常容易引起一些边界上的问题(2中所说)。
-
好多参考代码的boundary condition似乎有问题?举个例子,citadel佬写的FLIP demo里面,可以看到边界上会粘着某些粒子掉不下来。我自己写的时候也有遇到过这个问题,似乎是强制边界里面的速度为0,再加上最后插值速度的时候插到了这些0值引起的。因此我没太敢用enforce_bc。取而代之的,我在算divergence的时候用了边界条件。
-
一个step里面标准的写法应该是怎么来的?有些写法里面,既要advect速度网格(向后backtrace),又要向前移动粒子(move marker),而mpm的逻辑里似乎没有advect网格这一步。
提前感谢诸位老师和大佬解答困惑!!!