def dp(i, res=ti.Vector([0.0, 0.0])): for j in range(N): if j != i: res += mass[j] * (pressure[i] / ti.pow(density[i], 2) + pressure[j] / ti.pow(density[j], 2)) * dw(i, j) return density[i] * res
def compute_loss(): dist = (x_avg[None] - ti.Vector(target))**2 loss[None] = 0.5 * (dist(0) + dist(1))
import taichi as ti ti.init(arch=ti.gpu) N = 32 dt = 1e-4 dx = 1 / N rho = 4e1 NF = 2 * N**2 # number of faces NV = (N + 1)**2 # number of vertices E, nu = 4e4, 0.2 # Young's modulus and Poisson's ratio mu, lam = E / 2 / (1 + nu), E * nu / (1 + nu) / (1 - 2 * nu) # Lame parameters ball_pos, ball_radius = ti.Vector([0.5, 0.0]), 0.32 gravity = ti.Vector([0, -40]) damping = 12.5 pos = ti.Vector.field(2, float, NV, needs_grad=True) vel = ti.Vector.field(2, float, NV) f2v = ti.Vector.field(3, int, NF) # ids of three vertices of each face B = ti.Matrix.field(2, 2, float, NF) F = ti.Matrix.field(2, 2, float, NF, needs_grad=True) V = ti.field(float, NF) phi = ti.field(float, NF) # potential energy of each face (Neo-Hookean) U = ti.field(float, (), needs_grad=True) # total potential energy @ti.kernel def update_U(): for i in range(NF): ia, ib, ic = f2v[i] a, b, c = pos[ia], pos[ib], pos[ic]
density[i] += mass[j] * w(i, j) for i in range(N): pressure[i] = compute_pressure(density[i]) for i in range(N): f_pressure[i] = -mass[i] / density[i] * dp(i) for i in range(N): g = ti.Vector([0, -9.8]) v[i] = v[i] + 0.01 * (f_pressure[i] + g) / mass[i] x[i] = x[i] + 0.01 * v[i] if __name__ == "__main__": for i in range(N): x[i] = ti.Vector([i % 10, i / 10]) # print(i % 10, i / 10) mass[i] = 2.0 density[i] = 3.0 pressure[i] = 4.0 while True: if gui.get_event(ti.GUI.ESCAPE): break simulation_loop() for i in range(N): pos = x[i] gui.circle(pos=(pos[0] / 10, pos[1] / 10), color=0xFF0000, radius=5) gui.show()
def sample(qf, u, v): I = ti.Vector([int(u), int(v)]) I = max(0, min(res - 1, I)) #element-wise comparison return qf[I]
def advect_semilag(vf: ti.template(), qf: ti.template(), new_qf: ti.template(), intermedia_qf: ti.template()): for i, j in vf: #extract every sensor in the given resolution p = ti.Vector([i, j]) + 0.5 p = backtrace(vf, p, dt) new_qf[i, j] = bilerp(qf, p)
def complex_sqr(z): return ti.Vector([z[0]**2 - z[1]**2, z[1] * z[0] * 2])
def set_attachments(): for i in range(attach_num): attach_pos[i] = ti.Vector(list(bm.verts[attach[i]].co))
import os from imageio import imread, imwrite real = ti.f32 ti.set_default_fp(real) num_iterations = 150 n_grid = 110 dx = 1.0 / n_grid num_iterations_gauss_seidel = 6 p_dims = num_iterations_gauss_seidel + 1 steps = 100 learning_rate = 100 scalar = lambda: ti.var(dt=real) vector = lambda: ti.Vector(2, dt=real) v = vector() div = scalar() p = scalar() v_updated = vector() target = scalar() smoke = scalar() loss = scalar() ti.cfg.arch = ti.cuda # ti.cfg.enable_profiler = True @ti.layout def place():
def substep(): for i, j in grid_m: grid_v[i, j] = [0, 0] grid_m[i, j] = 0 for p in x: # Particle state update and scatter to grid (P2G) base = (x[p] * inv_dx - 0.5).cast(int) fx = x[p] * 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] F[p] = (ti.Matrix.identity(float, 2) + dt * C[p]) @ F[p] # deformation gradient update h = ti.exp( 10 * (1.0 - Jp[p])) # Hardening coefficient: snow gets harder when compressed if material[p] == 1: # jelly, make it softer h = 0.3 mu, la = mu_0 * h, lambda_0 * h if material[p] == 0: # liquid mu = 0.0 U, sig, V = ti.svd(F[p]) J = 1.0 for d in ti.static(range(2)): new_sig = sig[d, d] if material[p] == 2: # Snow new_sig = min(max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if material[ p] == 0: # Reset deformation gradient to avoid numerical instability F[p] = ti.Matrix.identity(float, 2) * ti.sqrt(J) elif material[p] == 2: F[p] = U @ sig @ V.transpose( ) # Reconstruct elastic deformation gradient after plasticity stress = 2 * mu * (F[p] - U @ V.transpose()) @ F[p].transpose( ) + ti.Matrix.identity(float, 2) * la * J * (J - 1) stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress affine = stress + p_mass * C[p] for i, j in ti.static(ti.ndrange( 3, 3)): # Loop over 3x3 grid node neighborhood offset = ti.Vector([i, j]) dpos = (offset.cast(float) - fx) * dx weight = w[i][0] * w[j][1] grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) grid_m[base + offset] += weight * p_mass for i, j in grid_m: if grid_m[i, j] > 0: # No need for epsilon here grid_v[i, j] = (1 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity grid_v[i, j][1] -= dt * 50 # gravity if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 # Boundary conditions if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 for p in x: # grid to particle (G2P) base = (x[p] * inv_dx - 0.5).cast(int) fx = x[p] * 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(float, 2) new_C = ti.Matrix.zero(float, 2, 2) for i, j in ti.static(ti.ndrange( 3, 3)): # loop over 3x3 grid node neighborhood dpos = ti.Vector([i, j]).cast(float) - fx g_v = grid_v[base + ti.Vector([i, j])] weight = w[i][0] * w[j][1] new_v += weight * g_v new_C += 4 * inv_dx * weight * g_v.outer_product(dpos) v[p], C[p] = new_v, new_C x[p] += dt * v[p] # advection
def foo1() -> ti.types.vector(3, dtype=ti.i32): c = ti.Vector([0, 1, 2, 3, 4, 5, 6]) return c[:5:2]