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+ # filter line search
27+ alpha = BarrierEnergy .init_step_size (x , y_ground , p ) # avoid interpenetration and tunneling
28+ while IP_val (x + alpha * p , e , x_tilde , m , l2 , k , y_ground , contact_area , h ) > E_last :
29+ alpha /= 2
30+ print ('step size =' , alpha )
31+
32+ x += alpha * p
33+ E_last = IP_val (x , e , x_tilde , m , l2 , k , y_ground , contact_area , h )
34+ p = search_dir (x , e , x_tilde , m , l2 , k , y_ground , contact_area , is_DBC , h )
35+ iter += 1
36+
37+ v = (x - x_n ) / h # implicit Euler velocity update
38+ return [x , v ]
39+
40+ def IP_val (x , e , x_tilde , m , l2 , k , y_ground , 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 , y_ground , contact_area )) # implicit Euler
42+
43+ def IP_grad (x , e , x_tilde , m , l2 , k , y_ground , 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 , y_ground , contact_area )) # implicit Euler
45+
46+ def IP_hess (x , e , x_tilde , m , l2 , k , y_ground , contact_area , h ):
47+ IJV_In = InertiaEnergy .hess (x , x_tilde , m )
48+ IJV_MS = MassSpringEnergy .hess (x , e , l2 , k )
49+ IJV_B = BarrierEnergy .hess (x , y_ground , contact_area )
50+ IJV_MS [2 ] *= h * h # implicit Euler
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 )
54+ H = sparse .coo_matrix ((IJV [2 ], (IJV [0 ], IJV [1 ])), shape = (len (x ) * 2 , len (x ) * 2 )).tocsr ()
55+ return H
56+
57+ def search_dir (x , e , x_tilde , m , l2 , k , y_ground , contact_area , is_DBC , h ):
58+ projected_hess = IP_hess (x , e , x_tilde , m , l2 , k , y_ground , contact_area , h )
59+ reshaped_grad = IP_grad (x , e , x_tilde , m , l2 , k , y_ground , contact_area , h ).reshape (len (x ) * 2 , 1 )
60+ # eliminate DOF by modifying gradient and Hessian for DBC:
61+ for i , j in zip (* projected_hess .nonzero ()):
62+ if is_DBC [int (i / 2 )] | is_DBC [int (j / 2 )]:
63+ projected_hess [i , j ] = (i == j )
64+ for i in range (0 , len (x )):
65+ if is_DBC [i ]:
66+ reshaped_grad [i * 2 ] = reshaped_grad [i * 2 + 1 ] = 0.0
67+ return spsolve (projected_hess , - reshaped_grad ).reshape (len (x ), 2 )
0 commit comments