流体模拟的边界和优点

Fluid simulation boundaries and advect

本文关键字:边界 模拟      更新时间:2023-10-16

此流体模拟基于Stam的一篇论文。在第7页,他描述了平流背后的基本思想:

从两个网格开始:一个包含上一个时间步长的密度值,另一个将包含新值。对于后者的每个网格单元,我们追踪单元的中心通过速度场向后定位。然后,我们从以前的密度值,并将该值指定给当前网格单元。

降临节代码。两个密度网格是dd0uv是速度分量,dt是时间步长,N(全局)是网格大小,b可以忽略:

void advect(int b, vfloat &d, const vfloat &d0, const vfloat &u, const vfloat &v, float dt, std::vector<bool> &bound)
{
    float dt0 = dt*N;
    for (int i=1; i<=N; i++)
    {
        for (int j=1; j<=N; j++)
        {
            float x = i - dt0*u[IX(i,j)];
            float y = j - dt0*v[IX(i,j)];
            if (x<0.5) x=0.5; if (x>N+0.5) x=N+0.5;
            int i0=(int)x; int i1=i0+1;
            if (y<0.5) y=0.5; if (y>N+0.5) y=N+0.5;
            int j0=(int)y; int j1=j0+1;
            float s1 = x-i0; float s0 = 1-s1; float t1 = y-j0; float t0 = 1-t1;
            d[IX(i,j)] = s0*(t0*d0[IX(i0,j0)] + t1*d0[IX(i0,j1)]) +
                         s1*(t0*d0[IX(i1,j0)] + t1*d0[IX(i1,j1)]);
        }
    }
    set_bnd(b, d, bound);
}

这种方法很简洁,效果也很好,但实现对象边界对我来说很难弄清楚,因为值是向后追溯和插值的。我目前的解决方案是,如果旁边有一个或多个空白空间,只需将密度推出边界,但这是不准确的,会导致密度增加,尤其是在具有对角速度的角落和区域仅在视觉上准确。我现在正在寻找"正确性"。

我的边界代码的相关部分:

void set_bnd(const int b, vfloat &x, std::vector<bool> &bound)
{
    //...
    for (int i=1; i<=N; i++)
    {
        for (int j=1; j<=N; j++)
        {
            if (bound[IX(i,j)])
            {
                //...
                else if (b==0)
                {
                    // Distribute density from bound to surrounding cells
                    int nearby_count = !bound[IX(i+1,j)] + !bound[IX(i-1,j)] + !bound[IX(i,j+1)] + !bound[IX(i,j-1)];
                    if (!nearby_count) x[IX(i,j)] = 0;
                    else
                        x[IX(i,j)] = ((bound[IX(i+1,j)] ? 0 : x[IX(i+1,j)]) +
                                      (bound[IX(i-1,j)] ? 0 : x[IX(i-1,j)]) +
                                      (bound[IX(i,j+1)] ? 0 : x[IX(i,j+1)]) +
                                      (bound[IX(i,j-1)] ? 0 : x[IX(i,j-1)])) / surround;
                }
            }
        }
    }
}

bound是具有行和列0N+1的布尔的向量。通过在bound1中设置单元坐标,在主循环之前设置边界对象。

该文件含糊地指出:"然后我们只需添加一些代码到set_bnd()例程,以根据他们的直接邻居",这就是我正在做的。我正在寻找一种更准确地实现边界的方法,即具有非流体-固体边界,并可能最终支持多种流体的边界。视觉质量比物理正确性重要得多。

您的答案来自物理而非模拟。既然你在处理边界,你的速度场需要满足普朗特无滑移边界条件,它简单地说,边界处的速度必须为零。看见https://en.wikipedia.org/wiki/Boundary_layer获取更多信息。如果你的速度场不符合这个标准,你就会遇到你所描述的困难,包括将质量平流回到边界,这是对模型的基本违反。

你还应该意识到,这个平流代码(通过设计)并没有守恒密度,守恒定律在最后是固定的。您需要注意这一步,因为向量场的Hodge分解也有适用的边界条件。

您可能对Jos Stam的《流体动画艺术》(2015年9月)感兴趣。在第69页左右,他详细讨论了边界条件。。

也许还有兴趣:https://software.intel.com/en-us/articles/fluid-simulation-for-video-games-part-1/.

"完美风暴"是不久前的事了,所以现在你的流体模拟必须非常大、非常快或非常详细。最好是全部三个。如果用例允许,有些人可能会使用GPU。

也许这有帮助。。