Stable_fluid改写共轭梯度出现问题

taichi example里的stable_fluid.py,只改了压力求解器。但改完之后爆炸了,不知道什么原因,希望大佬指教

爆炸效果gif:

2022-08-10-17-11-08

共轭梯度求解器部分的代码如下:

import taichi as ti
ti.init(arch=ti.cpu)
@ti.data_oriented
class CG:
    def __init__(self, velocity_divs: ti.template()):
        self.velocity_divs = velocity_divs
        self.x = ti.field(dtype=ti.f32, shape=velocity_divs.shape)
        self.r = ti.field(dtype=ti.f32, shape=velocity_divs.shape)
        self.d = ti.field(dtype=ti.f32, shape=velocity_divs.shape)
        self.Ad = ti.field(dtype=ti.f32, shape=velocity_divs.shape)
        self.alpha = ti.field(dtype=ti.f32, shape=())
        self.sum = ti.field(dtype=ti.f32, shape=())
        self.beta = ti.field(dtype=ti.f32, shape=())
        self.delta_old = ti.field(dtype=ti.f32, shape=())
        self.delta_new = ti.field(dtype=ti.f32, shape=())

    @ti.func
    def sample(self, c, u, v):
        I = ti.Vector([int(u), int(v)])
        I = max(0, min(512 - 1, I))  # 网格大小512*512
        return c[I]

    @ti.func
    def sum_neighbor(self, c, I):
        sum = self.sample(c, I.x - 1, I.y) + self.sample(c, I.x + 1, I.y) + self.sample(c, I.x, I.y - 1) + self.sample(
            c, I.x, I.y + 1)
        return sum

    @ti.kernel
    def compute_Ad(self):
        for I in ti.grouped(self.velocity_divs):
            self.Ad[I] = -2 * 2 * self.d[I] + self.sum_neighbor(self.d, I)

    @ti.kernel
    def compute_rTr(self) -> ti.f32:
        self.sum[None] = 0.0
        for I in ti.grouped(self.r):
            self.sum[None] += self.r[I] * self.r[I]
        return self.sum[None]

    @ti.kernel
    def update_delta(self):
        self.delta_old[None] = self.delta_new[None]

    @ti.kernel
    def update_alpha(self, eps: ti.template()):
        self.sum[None] = 0.0
        for I in ti.grouped(self.d):
            self.sum[None] += self.d[I] * self.Ad[I]
        self.alpha[None] = self.delta_new[None] / ti.max(self.sum[None], eps)

    @ti.kernel
    def update_beta(self, eps: ti.template()):
        self.beta[None] = self.delta_new[None] / ti.max(self.delta_old[None], eps)

    @ti.kernel
    def update_x(self):
        for I in ti.grouped(self.x):
            self.x[I] += (self.alpha[None] * self.d[I])

    @ti.kernel
    def update_r(self):
        for I in ti.grouped(self.r):
            self.r[I] -= (self.alpha[None] * self.Ad[I])

    @ti.kernel
    def update_d(self):
        for I in ti.grouped(self.d):
            self.d[I] = self.r[I] + (self.beta[None] * self.d[I])

    @ti.kernel
    def init(self):
        for I in ti.grouped(self.x):
            self.x[I] = 0.0
            self.r[I] = self.velocity_divs[I]
            self.d[I] = self.r[I]

    def solve(self, maxiters=100):
        self.init()
        self.delta_new[None] = self.compute_rTr()
        for i in ti.static(range(maxiters)):
            self.compute_Ad()  # q=Ad
            self.update_alpha(1e-12)  # alpha=rTr/dTAd
            self.update_x()  # x=x+alpha*d
            self.update_r()  # r=r-alpha*Ad
            self.update_delta()  # delta_old=delta_new
            self.delta_new[None] = self.compute_rTr()  # delta_new=rTr
            if self.delta_new[None] < 1e-12:
                # print('迭代次数:', i, '误差:', self.delta_new)
                break
            self.update_beta(1e-12)  # beta=delta_new/delta_old
            self.update_d()  # d=r+beta*d

    @ti.kernel
    def update_result(self, pf_cur: ti.template()):
        for I in ti.grouped(self.x):
            pf_cur[I] = self.x[I]
            
def solve_pressure_CG():
    cg_solver.solve(maxiters=cg_iters)
    cg_solver.update_result(pressures_pair.cur)
    
cg_solver = CG(velocity_divs)
3 个赞

找到原因了,我在差分拉普拉斯算子的时候直接用的(pl+pr+pt+pb-4p)/Δx²,导致要解的矩阵不正定,所以用共轭梯度爆炸了。我想两边同时加上负号应该就可以解决了,因此修改了两个kernal函数,看起来好像成功了!

解决方案:

@ti.kernel
def compute_Ad(self):
    for I in ti.grouped(self.velocity_divs):
        self.Ad[I] = 2 * 2 * self.d[I] - self.sum_neighbor(self.d, I)

@ti.kernel
def init(self):
    for I in ti.grouped(self.x):
        self.x[I] = 0.0
        self.r[I] = -self.velocity_divs[I]
        self.d[I] = self.r[I]

修改后效果:
2022-08-11-22-33-07

只迭代了10次所以效果不是很好,准备之后继续学习MGPCG方法!

3 个赞

欢迎加入 Taichi 社区~ 自己找到解决方案了很棒 :star_struck:

1 个赞