1313import FrictionEnergy
1414import SpringEnergy
1515
16- def step_forward (x , e , v , m , l2 , k , n , o , contact_area , mu , is_DBC , h , tol ):
16+ def step_forward (x , e , v , m , l2 , k , n , o , contact_area , mu , is_DBC , DBC , DBC_v , DBC_limit , h , tol ):
1717 x_tilde = x + v * h # implicit Euler predictive position
1818 x_n = copy .deepcopy (x )
1919 mu_lambda = BarrierEnergy .compute_mu_lambda (x , n , o , contact_area , mu ) # compute mu * lambda for each node using x^n
20+ DBC_target = [] # target position of each DBC in the current time step
21+ for i in range (0 , len (DBC )):
22+ if (DBC_limit [i ] - x_n [DBC [i ]]).dot (DBC_v [i ]) > 0 :
23+ DBC_target .append (x_n [DBC [i ]] + h * DBC_v [i ])
24+ else :
25+ DBC_target .append (x_n [DBC [i ]])
26+ DBC_stiff = 10 # initialize stiffness for DBC springs
2027
2128 # Newton loop
2229 iter = 0
23- E_last = IP_val (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , h )
24- p = search_dir (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , is_DBC , h )
25- while LA .norm (p , inf ) / h > tol :
30+ E_last = IP_val (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , DBC , DBC_target , DBC_stiff , h )
31+ [ p , DBC_satisfied ] = search_dir (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , is_DBC , DBC , DBC_target , DBC_stiff , tol , h )
32+ while ( LA .norm (p , inf ) / h > tol ) | ( sum ( DBC_satisfied ) != len ( DBC )): # also check whether all DBCs are satisfied
2633 print ('Iteration' , iter , ':' )
2734 print ('residual =' , LA .norm (p , inf ) / h )
2835
36+ if (LA .norm (p , inf ) / h <= tol ) & (sum (DBC_satisfied ) != len (DBC )):
37+ # increase DBC stiffness and recompute energy value record
38+ DBC_stiff *= 2
39+ E_last = IP_val (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , DBC , DBC_target , DBC_stiff , h )
40+
2941 # filter line search
3042 alpha = BarrierEnergy .init_step_size (x , n , o , p ) # avoid interpenetration and tunneling
31- while IP_val (x + alpha * p , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , h ) > E_last :
43+ while IP_val (x + alpha * p , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , DBC , DBC_target , DBC_stiff , h ) > E_last :
3244 alpha /= 2
3345 print ('step size =' , alpha )
3446
3547 x += alpha * p
36- E_last = IP_val (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , h )
37- p = search_dir (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , is_DBC , h )
48+ E_last = IP_val (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , DBC , DBC_target , DBC_stiff , h )
49+ [ p , DBC_satisfied ] = search_dir (x , e , x_tilde , m , l2 , k , n , o , contact_area , (x - x_n ) / h , mu_lambda , is_DBC , DBC , DBC_target , DBC_stiff , tol , h )
3850 iter += 1
3951
4052 v = (x - x_n ) / h # implicit Euler velocity update
4153 return [x , v ]
4254
43- def IP_val (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , h ):
55+ def IP_val (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , DBC , DBC_target , DBC_stiff , h ):
4456 return InertiaEnergy .val (x , x_tilde , m ) + h * h * ( # implicit Euler
4557 MassSpringEnergy .val (x , e , l2 , k ) +
4658 GravityEnergy .val (x , m ) +
4759 BarrierEnergy .val (x , n , o , contact_area ) +
4860 FrictionEnergy .val (v , mu_lambda , h , n )
49- ) + SpringEnergy .val (x , m , [ len ( x ) - 1 ], [ np . array ([ 0.0 , 0.6 ])] )
61+ ) + SpringEnergy .val (x , m , DBC , DBC_target , DBC_stiff )
5062
51- def IP_grad (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , h ):
63+ def IP_grad (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , DBC , DBC_target , DBC_stiff , h ):
5264 return InertiaEnergy .grad (x , x_tilde , m ) + h * h * ( # implicit Euler
5365 MassSpringEnergy .grad (x , e , l2 , k ) +
5466 GravityEnergy .grad (x , m ) +
5567 BarrierEnergy .grad (x , n , o , contact_area ) +
5668 FrictionEnergy .grad (v , mu_lambda , h , n )
57- ) + SpringEnergy .grad (x , m , [ len ( x ) - 1 ], [ np . array ([ 0.0 , 0.6 ])] )
69+ ) + SpringEnergy .grad (x , m , DBC , DBC_target , DBC_stiff )
5870
59- def IP_hess (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , h ):
71+ def IP_hess (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , DBC , DBC_target , DBC_stiff , h ):
6072 IJV_In = InertiaEnergy .hess (x , x_tilde , m )
6173 IJV_MS = MassSpringEnergy .hess (x , e , l2 , k )
6274 IJV_B = BarrierEnergy .hess (x , n , o , contact_area )
6375 IJV_F = FrictionEnergy .hess (v , mu_lambda , h , n )
64- IJV_S = SpringEnergy .hess (x , m , [ len ( x ) - 1 ], [ np . array ([ 0.0 , 0.6 ])] )
76+ IJV_S = SpringEnergy .hess (x , m , DBC , DBC_target , DBC_stiff )
6577 IJV_MS [2 ] *= h * h # implicit Euler
6678 IJV_B [2 ] *= h * h # implicit Euler
6779 IJV_F [2 ] *= h * h # implicit Euler
@@ -72,14 +84,19 @@ def IP_hess(x, e, x_tilde, m, l2, k, n, o, contact_area, v, mu_lambda, h):
7284 H = sparse .coo_matrix ((IJV [2 ], (IJV [0 ], IJV [1 ])), shape = (len (x ) * 2 , len (x ) * 2 )).tocsr ()
7385 return H
7486
75- def search_dir (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , is_DBC , h ):
76- projected_hess = IP_hess (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , h )
77- reshaped_grad = IP_grad (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , h ).reshape (len (x ) * 2 , 1 )
78- # eliminate DOF by modifying gradient and Hessian for DBC:
87+ def search_dir (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , is_DBC , DBC , DBC_target , DBC_stiff , tol , h ):
88+ projected_hess = IP_hess (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , DBC , DBC_target , DBC_stiff , h )
89+ reshaped_grad = IP_grad (x , e , x_tilde , m , l2 , k , n , o , contact_area , v , mu_lambda , DBC , DBC_target , DBC_stiff , h ).reshape (len (x ) * 2 , 1 )
90+ # check whether each DBC is satisfied
91+ DBC_satisfied = [False ] * len (x )
92+ for i in range (0 , len (DBC )):
93+ if LA .norm (x [DBC [i ]] - DBC_target [i ]) / h < tol :
94+ DBC_satisfied [DBC [i ]] = True
95+ # eliminate DOF if it's a satisfied DBC by modifying gradient and Hessian for DBC:
7996 for i , j in zip (* projected_hess .nonzero ()):
80- if is_DBC [int (i / 2 )] | is_DBC [int (j / 2 )]:
97+ if ( is_DBC [int (i / 2 )] & DBC_satisfied [ int ( i / 2 )]) | ( is_DBC [int (j / 2 )] & DBC_satisfied [ int ( i / 2 )]) :
8198 projected_hess [i , j ] = (i == j )
8299 for i in range (0 , len (x )):
83- if is_DBC [i ]:
100+ if is_DBC [i ] & DBC_satisfied [ i ] :
84101 reshaped_grad [i * 2 ] = reshaped_grad [i * 2 + 1 ] = 0.0
85- return spsolve (projected_hess , - reshaped_grad ).reshape (len (x ), 2 )
102+ return [ spsolve (projected_hess , - reshaped_grad ).reshape (len (x ), 2 ), DBC_satisfied ]
0 commit comments