def foo(): ti.block_dim(512) ti.block_local(a) for i, j in a: for k in range(stencil_length): b[i, j] += a[i + k, j] b[i, j] += a[i, j + k]
def g2p(self, dt: ti.f32): ti.block_dim(256) ti.block_local(*self.grid_v.entries) ti.no_activate(self.particle) for I in ti.grouped(self.pid): p = self.pid[I] base = ti.floor(self.x[p] * self.inv_dx - 0.5).cast(int) for D in ti.static(range(self.dim)): base[D] = ti.assume_in_range(base[D], I[D], 0, 1) fx = self.x[p] * self.inv_dx - base.cast(float) w = [ 0.5 * (1.5 - fx)**2, 0.75 - (fx - 1.0)**2, 0.5 * (fx - 0.5)**2 ] new_v = ti.Vector.zero(ti.f32, self.dim) new_C = ti.Matrix.zero(ti.f32, self.dim, self.dim) # loop over 3x3 grid node neighborhood for offset in ti.static(ti.grouped(self.stencil_range())): dpos = offset.cast(float) - fx g_v = self.grid_v[base + offset] weight = 1.0 for d in ti.static(range(self.dim)): weight *= w[offset[d]][d] new_v += weight * g_v new_C += 4 * self.inv_dx * weight * g_v.outer_product(dpos) self.v[p], self.C[p] = new_v, new_C self.x[p] += dt * self.v[p] # advection
def copy(bls: ti.template(), w: ti.template()): if ti.static(bls): ti.block_local(x, y, z) for i, j in x: w[i, j] = x[i, j - 2] + y[i + 2, j - 1] + y[i - 1, j] + z[i - 1, j] + z[i + 1, j]
def update_Q(rk_step: ti.template()): ti.block_dim(256) ti.block_local(F_x, F_y) for i, j in Q: if is_interior_cell(i, j): if ti.static(rk_step == 0): Q[i, j] = Q[i, j] + dt[None] * (F_x[i, j] - F_x[i + 1, j] + F_y[i, j] - F_y[i, j + 1]) / h if ti.static(rk_step == 1): Q[i, j] = (Q[i, j] + Q_old[i, j]) / 2.0 + dt[None] * ( F_x[i, j] - F_x[i + 1, j] + F_y[i, j] - F_y[i, j + 1]) / h
def triple_for(): ti.block_local(a) ti.block_local(b) for i in range(N - M): for k in range(N): weight = 1.0 for j in range(M): weight *= a[i + j] s = 0.0 for j in range(2 * M): s += weight + b[2 * i + j] f[i, k] = s
def p2g(use_shared: ti.template(), m: ti.template()): ti.block_dim(256) if ti.static(use_shared): ti.block_local(m) for I in ti.grouped(pid): p = pid[I] u_ = ti.floor(x[p] * N).cast(ti.i32) Im = ti.rescale_index(pid, m, I) u0 = ti.assume_in_range(u_[0], Im[0], 0, 1) u1 = ti.assume_in_range(u_[1], Im[1], 0, 1) u = ti.Vector([u0, u1]) for offset in ti.static(ti.grouped(ti.ndrange(extend, extend))): m[u + offset] += scatter_weight
def apply(use_bls: ti.template(), y: ti.template()): if ti.static(use_bls and not scatter): ti.block_local(x) if ti.static(use_bls and scatter): ti.block_local(y) ti.block_dim(block_dim) for I in ti.grouped(x): if ti.static(scatter): for offset in ti.static(stencil): y[I + ti.Vector(offset)] += x[I] else: # gather s = 0 for offset in ti.static(stencil): s = s + x[I + ti.Vector(offset)] y[I] = s
def stencil_2d(y: ti.template(), x: ti.template()): #reference: tests/python/bls_test_template.py if ti.static(bls and not scatter): ti.block_local(x) if ti.static(bls and scatter): ti.block_local(y) ti.block_dim(64) # 8*8=64 for I in ti.grouped(x): if ti.static(scatter): for offset in ti.static(stencil_common): y[I + ti.Vector(offset)] += x[I] else: # gather s = ti.cast(0.0, dtype) for offset in ti.static(stencil_common): s = s + x[I + ti.Vector(offset)] y[I] = s
def compute_F(): ti.block_dim(256) ti.block_local(W) for i, j in Q: if is_interior_x_face(i, j): # muscl reconstrucion of left and right states with HLLC flux wL = ti.Vector([0.0, 0.0, 0.0, 0.0]) wR = ti.Vector([0.0, 0.0, 0.0, 0.0]) for f in ti.static(range(4)): ratio_l = (W[i, j][f] - W[i - 1, j][f]) / (W[i - 1, j][f] - W[i - 2, j][f]) ratio_r = (W[i, j][f] - W[i - 1, j][f]) / (W[i + 1, j][f] - W[i, j][f]) wL[f] = W[i - 1, j][f] + 0.5 * mc_lim(ratio_l) * ( W[i - 1, j][f] - W[i - 2, j][f]) wR[f] = W[i, j][f] - 0.5 * mc_lim(ratio_r) * (W[i + 1, j][f] - W[i, j][f]) F_x[i, j] = HLLC_flux(w_to_u(wL), w_to_u(wR), ti.Vector([1.0, 0.0])) elif is_boundary_x_face(i, j): F_x[i, j] = HLLC_flux(Q[i - 1, j], Q[i, j], ti.Vector([1.0, 0.0])) if is_interior_y_face(i, j): # muscl reconstrucion of left and right states with HLLC flux wL = ti.Vector([0.0, 0.0, 0.0, 0.0]) wR = ti.Vector([0.0, 0.0, 0.0, 0.0]) for f in ti.static(range(4)): ratio_l = (W[i, j][f] - W[i, j - 1][f]) / (W[i, j - 1][f] - W[i, j - 2][f]) ratio_r = (W[i, j][f] - W[i, j - 1][f]) / (W[i, j + 1][f] - W[i, j][f]) wL[f] = W[i, j - 1][f] + 0.5 * mc_lim(ratio_l) * ( W[i, j - 1][f] - W[i, j - 2][f]) wR[f] = W[i, j][f] - 0.5 * mc_lim(ratio_r) * (W[i, j + 1][f] - W[i, j][f]) F_y[i, j] = HLLC_flux(w_to_u(wL), w_to_u(wR), ti.Vector([0.0, 1.0])) elif is_boundary_y_face(i, j): F_y[i, j] = HLLC_flux(Q[i, j - 1], Q[i, j], ti.Vector([0.0, 1.0]))
def g2p(use_shared: ti.template(), s: ti.template()): ti.block_dim(256) if ti.static(use_shared): ti.block_local(m1) for I in ti.grouped(pid): p = pid[I] u_ = ti.floor(x[p] * N).cast(ti.i32) Im = ti.rescale_index(pid, m1, I) u0 = ti.assume_in_range(u_[0], Im[0], 0, 1) u1 = ti.assume_in_range(u_[1], Im[1], 0, 1) u = ti.Vector([u0, u1]) tot = 0.0 for offset in ti.static(ti.grouped(ti.ndrange(extend, extend))): tot += m1[u + offset] s[p] = tot
def copy(): ti.block_local(x) for i, j in x: y[i, j] = x[i, j]
def copy(): ti.block_local(x) for i in x: y[i] = x[i]
def p2g(self, dt: ti.f32): ti.no_activate(self.particle) ti.block_dim(256) ti.block_local(*self.grid_v.entries) ti.block_local(self.grid_m) for I in ti.grouped(self.pid): p = self.pid[I] base = ti.floor(self.x[p] * self.inv_dx - 0.5).cast(int) for D in ti.static(range(self.dim)): base[D] = ti.assume_in_range(base[D], I[D], 0, 1) fx = self.x[p] * self.inv_dx - base.cast(float) # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] w = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2] # deformation gradient update self.F[p] = (ti.Matrix.identity(ti.f32, self.dim) + dt * self.C[p]) @ self.F[p] # Hardening coefficient: snow gets harder when compressed h = ti.exp(10 * (1.0 - self.Jp[p])) if self.material[ p] == self.material_elastic: # jelly, make it softer h = 0.3 mu, la = self.mu_0 * h, self.lambda_0 * h if self.material[p] == self.material_water: # liquid mu = 0.0 U, sig, V = ti.svd(self.F[p]) J = 1.0 if self.material[p] != self.material_sand: for d in ti.static(range(self.dim)): new_sig = sig[d, d] if self.material[p] == self.material_snow: # Snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity self.Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if self.material[p] == self.material_water: # Reset deformation gradient to avoid numerical instability new_F = ti.Matrix.identity(ti.f32, self.dim) new_F[0, 0] = J self.F[p] = new_F elif self.material[p] == self.material_snow: # Reconstruct elastic deformation gradient after plasticity self.F[p] = U @ sig @ V.transpose() stress = ti.Matrix.zero(ti.f32, self.dim, self.dim) if self.material[p] != self.material_sand: stress = 2 * mu * ( self.F[p] - U @ V.transpose()) @ self.F[p].transpose( ) + ti.Matrix.identity(ti.f32, self.dim) * la * J * (J - 1) else: sig = self.sand_projection(sig, p) self.F[p] = U @ sig @ V.transpose() log_sig_sum = 0.0 center = ti.Matrix.zero(ti.f32, self.dim, self.dim) for i in ti.static(range(self.dim)): log_sig_sum += ti.log(sig[i, i]) center[i, i] = 2.0 * self.mu_0 * ti.log( sig[i, i]) * (1 / sig[i, i]) for i in ti.static(range(self.dim)): center[i, i] += self.lambda_0 * log_sig_sum * (1 / sig[i, i]) stress = U @ center @ V.transpose() @ self.F[p].transpose() stress = (-dt * self.p_vol * 4 * self.inv_dx**2) * stress affine = stress + self.p_mass * self.C[p] # Loop over 3x3 grid node neighborhood for offset in ti.static(ti.grouped(self.stencil_range())): dpos = (offset.cast(float) - fx) * self.dx weight = 1.0 for d in ti.static(range(self.dim)): weight *= w[offset[d]][d] self.grid_v[base + offset] += weight * (self.p_mass * self.v[p] + affine @ dpos) self.grid_m[base + offset] += weight * self.p_mass
def p2g(self, dt: ti.f32): ti.no_activate(self.particle) ti.block_dim(256) if ti.static(self.use_bls): for d in ti.static(range(self.dim)): ti.block_local(self.grid_v.get_scalar_field(d)) ti.block_local(self.grid_m) for I in ti.grouped(self.pid): p = self.pid[I] base = ti.floor(self.x[p] * self.inv_dx - 0.5).cast(int) Im = ti.rescale_index(self.pid, self.grid_m, I) for D in ti.static(range(self.dim)): # For block shared memory: hint compiler that there is a connection between `base` and loop index `I` base[D] = ti.assume_in_range(base[D], Im[D], 0, 1) fx = self.x[p] * self.inv_dx - base.cast(float) # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] w = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2] # Deformation gradient update F = self.F[p] if self.material[p] == self.material_water: # liquid F = ti.Matrix.identity(ti.f32, self.dim) if ti.static(self.support_plasticity): F[0, 0] = self.Jp[p] F = (ti.Matrix.identity(ti.f32, self.dim) + dt * self.C[p]) @ F # Hardening coefficient: snow gets harder when compressed h = 1.0 if ti.static(self.support_plasticity): if self.material[p] != self.material_water: h = ti.exp(10 * (1.0 - self.Jp[p])) if self.material[ p] == self.material_elastic: # jelly, make it softer h = 0.3 mu, la = self.mu_0 * h, self.lambda_0 * h if self.material[p] == self.material_water: # liquid mu = 0.0 U, sig, V = ti.svd(F) J = 1.0 if self.material[p] != self.material_sand: for d in ti.static(range(self.dim)): new_sig = sig[d, d] if self.material[p] == self.material_snow: # Snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity if ti.static(self.support_plasticity): self.Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if self.material[p] == self.material_water: # Reset deformation gradient to avoid numerical instability F = ti.Matrix.identity(ti.f32, self.dim) F[0, 0] = J if ti.static(self.support_plasticity): self.Jp[p] = J elif self.material[p] == self.material_snow: # Reconstruct elastic deformation gradient after plasticity F = U @ sig @ V.transpose() stress = ti.Matrix.zero(ti.f32, self.dim, self.dim) if self.material[p] != self.material_sand: stress = 2 * mu * (F - U @ V.transpose()) @ F.transpose( ) + ti.Matrix.identity(ti.f32, self.dim) * la * J * (J - 1) else: if ti.static(self.support_plasticity): sig = self.sand_projection(sig, p) F = U @ sig @ V.transpose() log_sig_sum = 0.0 center = ti.Matrix.zero(ti.f32, self.dim, self.dim) for i in ti.static(range(self.dim)): log_sig_sum += ti.log(sig[i, i]) center[i, i] = 2.0 * self.mu_0 * ti.log( sig[i, i]) * (1 / sig[i, i]) for i in ti.static(range(self.dim)): center[i, i] += self.lambda_0 * log_sig_sum * (1 / sig[i, i]) stress = U @ center @ V.transpose() @ F.transpose() self.F[p] = F stress = (-dt * self.p_vol * 4 * self.inv_dx**2) * stress # TODO: implement g2p2g pmass mass = self.p_mass if self.material[p] == self.material_water: mass *= self.water_density affine = stress + mass * self.C[p] # Loop over 3x3 grid node neighborhood for offset in ti.static(ti.grouped(self.stencil_range())): dpos = (offset.cast(float) - fx) * self.dx weight = 1.0 for d in ti.static(range(self.dim)): weight *= w[offset[d]][d] self.grid_v[base + offset] += weight * (mass * self.v[p] + affine @ dpos) self.grid_m[base + offset] += weight * mass
def g2p2g(self, dt: ti.f32, pid: ti.template(), grid_v_in: ti.template(), grid_v_out: ti.template(), grid_m_out: ti.template()): ti.block_dim(256) ti.no_activate(self.particle) if ti.static(self.use_bls): ti.block_local(grid_m_out) for d in ti.static(range(self.dim)): ti.block_local(grid_v_in.get_scalar_field(d)) ti.block_local(grid_v_out.get_scalar_field(d)) for I in ti.grouped(pid): p = pid[I] # G2P base = ti.floor(self.x[p] * self.inv_dx - 0.5).cast(int) Im = ti.rescale_index(pid, grid_m_out, I) for D in ti.static(range(self.dim)): base[D] = ti.assume_in_range(base[D], Im[D], 0, 1) fx = self.x[p] * self.inv_dx - base.cast(float) w = [ 0.5 * (1.5 - fx)**2, 0.75 - (fx - 1.0)**2, 0.5 * (fx - 0.5)**2 ] new_v = ti.Vector.zero(ti.f32, self.dim) C = ti.Matrix.zero(ti.f32, self.dim, self.dim) # Loop over 3x3 grid node neighborhood for offset in ti.static(ti.grouped(self.stencil_range())): dpos = offset.cast(float) - fx g_v = grid_v_in[base + offset] weight = 1.0 for d in ti.static(range(self.dim)): weight *= w[offset[d]][d] new_v += weight * g_v C += 4 * self.inv_dx * weight * g_v.outer_product(dpos) if p >= self.last_time_final_particles[None]: # New particles. No G2P. new_v = self.v[p] C = ti.Matrix.zero(ti.f32, self.dim, self.dim) if self.material[p] != self.material_stationary: self.v[p] = new_v self.x[p] += dt * self.v[p] # advection # P2G base = ti.floor(self.x[p] * self.inv_dx - 0.5).cast(int) for D in ti.static(range(self.dim)): base[D] = ti.assume_in_range(base[D], Im[D], -1, 2) fx = self.x[p] * self.inv_dx - base.cast(float) # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] w2 = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2] # Deformation gradient update new_F = (ti.Matrix.identity(ti.f32, self.dim) + dt * C) @ self.F[p] if ti.static(self.quant): new_F = max(-self.F_bound, min(self.F_bound, new_F)) self.F[p] = new_F # Hardening coefficient: snow gets harder when compressed h = 1.0 if ti.static(self.support_plasticity): h = ti.exp(10 * (1.0 - self.Jp[p])) if self.material[ p] == self.material_elastic: # Jelly, make it softer h = 0.3 mu, la = self.mu_0 * h, self.lambda_0 * h if self.material[p] == self.material_water: # Liquid mu = 0.0 U, sig, V = ti.svd(self.F[p]) J = 1.0 if self.material[p] != self.material_sand: for d in ti.static(range(self.dim)): new_sig = sig[d, d] if self.material[p] == self.material_snow: # Snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity if ti.static(self.support_plasticity): self.Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if self.material[p] == self.material_water: # Reset deformation gradient to avoid numerical instability new_F = ti.Matrix.identity(ti.f32, self.dim) new_F[0, 0] = J self.F[p] = new_F elif self.material[p] == self.material_snow: # Reconstruct elastic deformation gradient after plasticity self.F[p] = U @ sig @ V.transpose() stress = ti.Matrix.zero(ti.f32, self.dim, self.dim) if self.material[p] != self.material_sand: stress = 2 * mu * ( self.F[p] - U @ V.transpose()) @ self.F[p].transpose( ) + ti.Matrix.identity(ti.f32, self.dim) * la * J * (J - 1) else: if ti.static(self.support_plasticity): sig = self.sand_projection(sig, p) self.F[p] = U @ sig @ V.transpose() log_sig_sum = 0.0 center = ti.Matrix.zero(ti.f32, self.dim, self.dim) for i in ti.static(range(self.dim)): log_sig_sum += ti.log(sig[i, i]) center[i, i] = 2.0 * self.mu_0 * ti.log( sig[i, i]) * (1 / sig[i, i]) for i in ti.static(range(self.dim)): center[i, i] += self.lambda_0 * log_sig_sum * (1 / sig[i, i]) stress = U @ center @ V.transpose() @ self.F[p].transpose() stress = (-dt * self.p_vol * 4 * self.inv_dx**2) * stress affine = stress + self.p_mass * C # Loop over 3x3 grid node neighborhood for offset in ti.static(ti.grouped(self.stencil_range())): dpos = (offset.cast(float) - fx) * self.dx weight = 1.0 for d in ti.static(range(self.dim)): weight *= w2[offset[d]][d] grid_v_out[base + offset] += weight * (self.p_mass * self.v[p] + affine @ dpos) grid_m_out[base + offset] += weight * self.p_mass self.last_time_final_particles[None] = self.n_particles[None]
def call_block_local(): ti.block_local(x)