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