|
9 | 9 | import InertiaEnergy |
10 | 10 | import MassSpringEnergy |
11 | 11 | import GravityEnergy |
| 12 | +import BarrierEnergy |
12 | 13 |
|
13 | | -def step_forward(x, e, v, m, l2, k, is_DBC, h, tol): |
| 14 | +def step_forward(x, e, v, m, l2, k, contact_area, is_DBC, h, tol): |
14 | 15 | x_tilde = x + v * h # implicit Euler predictive position |
15 | 16 | x_n = copy.deepcopy(x) |
16 | 17 |
|
17 | 18 | # Newton loop |
18 | 19 | iter = 0 |
19 | | - E_last = IP_val(x, e, x_tilde, m, l2, k, h) |
20 | | - p = search_dir(x, e, x_tilde, m, l2, k, is_DBC, h) |
| 20 | + E_last = IP_val(x, e, x_tilde, m, l2, k, contact_area, h) |
| 21 | + p = search_dir(x, e, x_tilde, m, l2, k, contact_area, is_DBC, h) |
21 | 22 | while LA.norm(p, inf) / h > tol: |
22 | 23 | print('Iteration', iter, ':') |
23 | 24 | print('residual =', LA.norm(p, inf) / h) |
24 | 25 |
|
25 | 26 | # line search |
26 | | - alpha = 1 |
27 | | - while IP_val(x + alpha * p, e, x_tilde, m, l2, k, h) > E_last: |
| 27 | + alpha = BarrierEnergy.init_step_size(x, p) # filter line search to avoid interpenetration and tunneling |
| 28 | + while IP_val(x + alpha * p, e, x_tilde, m, l2, k, contact_area, h) > E_last: |
28 | 29 | alpha /= 2 |
29 | 30 | print('step size =', alpha) |
30 | 31 |
|
31 | 32 | x += alpha * p |
32 | | - E_last = IP_val(x, e, x_tilde, m, l2, k, h) |
33 | | - p = search_dir(x, e, x_tilde, m, l2, k, is_DBC, h) |
| 33 | + E_last = IP_val(x, e, x_tilde, m, l2, k, contact_area, h) |
| 34 | + p = search_dir(x, e, x_tilde, m, l2, k, contact_area, is_DBC, h) |
34 | 35 | iter += 1 |
35 | 36 |
|
36 | 37 | v = (x - x_n) / h # implicit Euler velocity update |
37 | 38 | return [x, v] |
38 | 39 |
|
39 | | -def IP_val(x, e, x_tilde, m, l2, k, h): |
40 | | - return InertiaEnergy.val(x, x_tilde, m) + h * h * (MassSpringEnergy.val(x, e, l2, k) + GravityEnergy.val(x, m)) # implicit Euler |
| 40 | +def IP_val(x, e, x_tilde, m, l2, k, contact_area, h): |
| 41 | + return InertiaEnergy.val(x, x_tilde, m) + h * h * (MassSpringEnergy.val(x, e, l2, k) + GravityEnergy.val(x, m) + BarrierEnergy.val(x, contact_area)) # implicit Euler |
41 | 42 |
|
42 | | -def IP_grad(x, e, x_tilde, m, l2, k, h): |
43 | | - return InertiaEnergy.grad(x, x_tilde, m) + h * h * (MassSpringEnergy.grad(x, e, l2, k) + GravityEnergy.grad(x, m)) # implicit Euler |
| 43 | +def IP_grad(x, e, x_tilde, m, l2, k, contact_area, h): |
| 44 | + return InertiaEnergy.grad(x, x_tilde, m) + h * h * (MassSpringEnergy.grad(x, e, l2, k) + GravityEnergy.grad(x, m) + BarrierEnergy.grad(x, contact_area)) # implicit Euler |
44 | 45 |
|
45 | | -def IP_hess(x, e, x_tilde, m, l2, k, h): |
| 46 | +def IP_hess(x, e, x_tilde, m, l2, k, contact_area, h): |
46 | 47 | IJV_In = InertiaEnergy.hess(x, x_tilde, m) |
47 | 48 | IJV_MS = MassSpringEnergy.hess(x, e, l2, k) |
| 49 | + IJV_B = BarrierEnergy.hess(x, contact_area) |
48 | 50 | IJV_MS[2] *= h * h # implicit Euler |
49 | | - IJV = np.append(IJV_In, IJV_MS, axis=1) |
| 51 | + IJV_B[2] *= h * h # implicit Euler |
| 52 | + IJV_In_MS = np.append(IJV_In, IJV_MS, axis=1) |
| 53 | + IJV = np.append(IJV_In_MS, IJV_B, axis=1) |
50 | 54 | H = sparse.coo_matrix((IJV[2], (IJV[0], IJV[1])), shape=(len(x) * 2, len(x) * 2)).tocsr() |
51 | 55 | return H |
52 | 56 |
|
53 | | -def search_dir(x, e, x_tilde, m, l2, k, is_DBC, h): |
54 | | - projected_hess = IP_hess(x, e, x_tilde, m, l2, k, h) |
55 | | - reshaped_grad = IP_grad(x, e, x_tilde, m, l2, k, h).reshape(len(x) * 2, 1) |
| 57 | +def search_dir(x, e, x_tilde, m, l2, k, contact_area, is_DBC, h): |
| 58 | + projected_hess = IP_hess(x, e, x_tilde, m, l2, k, contact_area, h) |
| 59 | + reshaped_grad = IP_grad(x, e, x_tilde, m, l2, k, contact_area, h).reshape(len(x) * 2, 1) |
56 | 60 | # eliminate DOF by modifying gradient and Hessian for DBC: |
57 | 61 | for i, j in zip(*projected_hess.nonzero()): |
58 | 62 | if is_DBC[int(i / 2)] | is_DBC[int(j / 2)]: |
|
0 commit comments