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+
13+ def step_forward (x , e , v , m , l2 , k , is_DBC , h , tol ):
14+ x_tilde = x + v * h # implicit Euler predictive position
15+ x_n = copy .deepcopy (x )
16+
17+ # Newton loop
18+ 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 )
21+ while LA .norm (p , inf ) / h > tol :
22+ print ('Iteration' , iter , ':' )
23+ print ('residual =' , LA .norm (p , inf ) / h )
24+
25+ # line search
26+ alpha = 1
27+ while IP_val (x + alpha * p , e , x_tilde , m , l2 , k , h ) > E_last :
28+ alpha /= 2
29+ print ('step size =' , alpha )
30+
31+ 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 )
34+ iter += 1
35+
36+ v = (x - x_n ) / h # implicit Euler velocity update
37+ return [x , v ]
38+
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
41+
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
44+
45+ def IP_hess (x , e , x_tilde , m , l2 , k , h ):
46+ IJV_In = InertiaEnergy .hess (x , x_tilde , m )
47+ IJV_MS = MassSpringEnergy .hess (x , e , l2 , k )
48+ IJV_MS [2 ] *= h * h # implicit Euler
49+ IJV = np .append (IJV_In , IJV_MS , axis = 1 )
50+ H = sparse .coo_matrix ((IJV [2 ], (IJV [0 ], IJV [1 ])), shape = (len (x ) * 2 , len (x ) * 2 )).tocsr ()
51+ return H
52+
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 )
56+ # eliminate DOF by modifying gradient and Hessian for DBC:
57+ for i , j in zip (* projected_hess .nonzero ()):
58+ if is_DBC [int (i / 2 )] | is_DBC [int (j / 2 )]:
59+ projected_hess [i , j ] = (i == j )
60+ for i in range (0 , len (x )):
61+ if is_DBC [i ]:
62+ reshaped_grad [i * 2 ] = reshaped_grad [i * 2 + 1 ] = 0.0
63+ return spsolve (projected_hess , - reshaped_grad ).reshape (len (x ), 2 )
0 commit comments