taichi-dev / taichi

Productive, portable, and performant GPU programming in Python.
https://taichi-lang.org
Apache License 2.0
25.52k stars 2.29k forks source link

Taichi vector field values being changed randomly by kernel after explicit assignment #4756

Closed YuxinPan closed 2 years ago

YuxinPan commented 2 years ago

Describe the bug Taichi vector field values being changed randomly by kernel after explicit assignment of values inside a function. This happens without a certain pattern.

To Reproduce Please see the code below to reproduce. The dev environment is: [Taichi] version 0.8.9, latest version 0.9.2, llvm 10.0.0, commit 8a0942ba, linux, python 3.9.7

import taichi as ti
import numpy as np

real = ti.f32
ti.init(default_fp=real, arch=ti.cpu)

quality = 1 # Use a larger value for higher-res simulations
n_particles, n_grid = 18000, 64 * quality
n_width, n_length, density = 36, 88, 3
dx = 0.5 / n_grid

x = ti.Vector.field(2, dtype=real, shape=n_particles) # position(x, y)
material = ti.field(dtype=ti.i32, shape=n_particles) # material id
kk = ti.field(ti.i32,shape=())
kk[None] = 0

@ti.kernel
def apply_grid()  -> ti.i32:
    for i in range(n_width): # ti.static(range(36))
        for j in range(n_length):
            x[kk[None]] = [ i* dx, j * dx]
            material[kk[None]] = 1 # 0: fluid 1: jelly 2: snow
            kk[None] += 1
    return 0

rtn_flag = apply_grid()

material_np = material.to_numpy()
x_np = x.to_numpy()
print("Wrong index: ",np.where(material_np[:n_width*n_length]==0))
print("Value randomly reset to 0: ",x_np[np.where(material_np[:n_width*n_length]==0)])

Log/Screenshots There is no error message as the program can finish execution, but wrong value is shown below after manual filtering.

[Taichi] version 0.8.9, latest version 0.9.2, llvm 10.0.0, commit 8a0942ba, linux, python 3.9.7
[Taichi] Starting on arch=x64
Wrong index:  (array([ 439,  456,  807, 1015, 1037, 1061, 1168, 1207, 1250, 1279, 1296]),)
Value randomly reset to 0:  [[0. 0.]
erizmr commented 2 years ago

Hi @YuxinPan , the outermost loop of a Taichi kernel is paralleled executed, thus the order of the kk[None] loaded of material[kk[None]] = 1 is not guaranteed. Some simple modifications can help address this issue, such as the example below:

@ti.kernel
def apply_grid()  -> ti.i32:
    for i in range(n_width): # ti.static(range(36))
        for j in range(n_length):
            x[i * n_length + j] = [ i* dx, j * dx]
            material[i * n_length + j] = 1 # 0: fluid 1: jelly 2: snow
    return 0
YuxinPan commented 2 years ago

Hi @YuxinPan , the outermost loop of a Taichi kernel is paralleled executed, thus the order of the kk[None] loaded of material[kk[None]] = 1 is not guaranteed. Some simple modifications can help address this issue, such as the example below:

@ti.kernel
def apply_grid()  -> ti.i32:
    for i in range(n_width): # ti.static(range(36))
        for j in range(n_length):
            x[i * n_length + j] = [ i* dx, j * dx]
            material[i * n_length + j] = 1 # 0: fluid 1: jelly 2: snow
    return 0

Thanks, that indeed fixed this issue!