1+ import utils
2+ import numpy as np
3+ import math
4+
5+ def polar_svd (F ):
6+ [U , s , VT ] = np .linalg .svd (F )
7+ if np .linalg .det (U ) < 0 :
8+ U [:, 1 ] = - U [:, 1 ]
9+ s [1 ] = - s [1 ]
10+ if np .linalg .det (VT ) < 0 :
11+ VT [1 , :] = - VT [1 , :]
12+ s [1 ] = - s [1 ]
13+ return [U , s , VT ]
14+
15+ def dPsi_div_dsigma (s , mu , lam ):
16+ ln_sigma_prod = math .log (s [0 ] * s [1 ])
17+ inv0 = 1.0 / s [0 ]
18+ dPsi_dsigma_0 = mu * (s [0 ] - inv0 ) + lam * inv0 * ln_sigma_prod
19+ inv1 = 1.0 / s [1 ]
20+ dPsi_dsigma_1 = mu * (s [1 ] - inv1 ) + lam * inv1 * ln_sigma_prod
21+ return [dPsi_dsigma_0 , dPsi_dsigma_1 ]
22+
23+ def d2Psi_div_dsigma2 (s , mu , lam ):
24+ ln_sigma_prod = math .log (s [0 ] * s [1 ])
25+ inv2_0 = 1 / (s [0 ] * s [0 ])
26+ d2Psi_dsigma2_00 = mu * (1 + inv2_0 ) - lam * inv2_0 * (ln_sigma_prod - 1 )
27+ inv2_1 = 1 / (s [1 ] * s [1 ])
28+ d2Psi_dsigma2_11 = mu * (1 + inv2_1 ) - lam * inv2_1 * (ln_sigma_prod - 1 )
29+ d2Psi_dsigma2_01 = lam / (s [0 ] * s [1 ])
30+ return [[d2Psi_dsigma2_00 , d2Psi_dsigma2_01 ], [d2Psi_dsigma2_01 , d2Psi_dsigma2_11 ]]
31+
32+ def B_left_coef (s , mu , lam ):
33+ sigma_prod = s [0 ] * s [1 ]
34+ return (mu + (mu - lam * math .log (sigma_prod )) / sigma_prod ) / 2
35+
36+ def Psi (F , mu , lam ):
37+ J = np .linalg .det (F )
38+ lnJ = math .log (J )
39+ return mu / 2 * (np .trace (np .transpose (F ).dot (F )) - 2 ) - mu * lnJ + lam / 2 * lnJ * lnJ
40+
41+ def dPsi_div_dF (F , mu , lam ):
42+ FinvT = np .transpose (np .linalg .inv (F ))
43+ return mu * (F - FinvT ) + lam * math .log (np .linalg .det (F )) * FinvT
44+
45+ def d2Psi_div_dF2 (F , mu , lam ):
46+ [U , sigma , VT ] = polar_svd (F )
47+
48+ Psi_sigma_sigma = utils .make_PD (d2Psi_div_dsigma2 (sigma , mu , lam ))
49+
50+ B_left = B_left_coef (sigma , mu , lam )
51+ Psi_sigma = dPsi_div_dsigma (sigma , mu , lam )
52+ B_right = (Psi_sigma [0 ] + Psi_sigma [1 ]) / (2 * max (sigma [0 ] + sigma [1 ], 1e-6 ))
53+ B = utils .make_PD ([[B_left + B_right , B_left - B_right ], [B_left - B_right , B_left + B_right ]])
54+
55+ M = np .array ([[0 , 0 , 0 , 0 ]] * 4 )
56+ M [0 , 0 ] = Psi_sigma_sigma [0 , 0 ]
57+ M [0 , 3 ] = Psi_sigma_sigma [0 , 1 ]
58+ M [1 , 1 ] = B [0 , 0 ]
59+ M [1 , 2 ] = B [0 , 1 ]
60+ M [2 , 1 ] = B [1 , 0 ]
61+ M [2 , 2 ] = B [1 , 1 ]
62+ M [3 , 0 ] = Psi_sigma_sigma [1 , 0 ]
63+ M [3 , 3 ] = Psi_sigma_sigma [1 , 1 ]
64+
65+ dP_div_dF = np .array ([[0 , 0 , 0 , 0 ]] * 4 )
66+ for j in range (0 , 2 ):
67+ for i in range (0 , 2 ):
68+ ij = j * 2 + i
69+ for s in range (0 , 2 ):
70+ for r in range (0 , 2 ):
71+ rs = s * 2 + r
72+ dP_div_dF [ij , rs ] = M [0 , 0 ] * U [i , 0 ] * VT [0 , j ] * U [r , 0 ] * VT [0 , s ] \
73+ + M [0 , 3 ] * U [i , 0 ] * VT [0 , j ] * U [r , 1 ] * VT [1 , s ] \
74+ + M [1 , 1 ] * U [i , 0 ] * VT [1 , j ] * U [r , 0 ] * VT [1 , s ] \
75+ + M [1 , 2 ] * U [i , 0 ] * VT [1 , j ] * U [r , 1 ] * VT [0 , s ] \
76+ + M [2 , 1 ] * U [i , 1 ] * VT [0 , j ] * U [r , 0 ] * VT [1 , s ] \
77+ + M [2 , 2 ] * U [i , 1 ] * VT [0 , j ] * U [r , 1 ] * VT [0 , s ] \
78+ + M [3 , 0 ] * U [i , 1 ] * VT [1 , j ] * U [r , 0 ] * VT [0 , s ] \
79+ + M [3 , 3 ] * U [i , 1 ] * VT [1 , j ] * U [r , 1 ] * VT [1 , s ]
80+ return dP_div_dF
81+
82+ def deformation_grad (x , elemVInd , IB ):
83+ F = [x [elemVInd [1 ]] - x [elemVInd [0 ]], x [elemVInd [2 ]] - x [elemVInd [0 ]]]
84+ return np .transpose (F ).dot (IB )
85+
86+ def dPsi_div_dx (P , IB ): # applying chain-rule, dPsi_div_dx = dPsi_div_dF * dF_div_dx
87+ dPsi_dx_2 = P [0 , 0 ] * IB [0 , 0 ] + P [0 , 1 ] * IB [0 , 1 ]
88+ dPsi_dx_3 = P [1 , 0 ] * IB [0 , 0 ] + P [1 , 1 ] * IB [0 , 1 ]
89+ dPsi_dx_4 = P [0 , 0 ] * IB [1 , 0 ] + P [0 , 1 ] * IB [1 , 1 ]
90+ dPsi_dx_5 = P [1 , 0 ] * IB [1 , 0 ] + P [1 , 1 ] * IB [1 , 1 ]
91+ return [np .array ([- dPsi_dx_2 - dPsi_dx_4 , - dPsi_dx_3 - dPsi_dx_5 ]), np .array ([dPsi_dx_2 , dPsi_dx_3 ]), np .array ([dPsi_dx_4 , dPsi_dx_5 ])]
92+
93+ def d2Psi_div_dx2 (dP_div_dF , IB ): # applying chain-rule, d2Psi_div_dx2 = dF_div_dx^T * d2Psi_div_dF2 * dF_div_dx (note that d2F_div_dx2 = 0)
94+ intermediate = np .array ([[0.0 , 0.0 , 0.0 , 0.0 ]] * 6 )
95+ for colI in range (0 , 4 ):
96+ _000 = dP_div_dF [0 , colI ] * IB [0 , 0 ]
97+ _010 = dP_div_dF [0 , colI ] * IB [1 , 0 ]
98+ _101 = dP_div_dF [2 , colI ] * IB [0 , 1 ]
99+ _111 = dP_div_dF [2 , colI ] * IB [1 , 1 ]
100+ _200 = dP_div_dF [1 , colI ] * IB [0 , 0 ]
101+ _210 = dP_div_dF [1 , colI ] * IB [1 , 0 ]
102+ _301 = dP_div_dF [3 , colI ] * IB [0 , 1 ]
103+ _311 = dP_div_dF [3 , colI ] * IB [1 , 1 ]
104+ intermediate [2 , colI ] = _000 + _101
105+ intermediate [3 , colI ] = _200 + _301
106+ intermediate [4 , colI ] = _010 + _111
107+ intermediate [5 , colI ] = _210 + _311
108+ intermediate [0 , colI ] = - intermediate [2 , colI ] - intermediate [4 , colI ]
109+ intermediate [1 , colI ] = - intermediate [3 , colI ] - intermediate [5 , colI ]
110+ result = np .array ([[0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ]] * 6 )
111+ for colI in range (0 , 6 ):
112+ _000 = intermediate [colI , 0 ] * IB [0 , 0 ]
113+ _010 = intermediate [colI , 0 ] * IB [1 , 0 ]
114+ _101 = intermediate [colI , 2 ] * IB [0 , 1 ]
115+ _111 = intermediate [colI , 2 ] * IB [1 , 1 ]
116+ _200 = intermediate [colI , 1 ] * IB [0 , 0 ]
117+ _210 = intermediate [colI , 1 ] * IB [1 , 0 ]
118+ _301 = intermediate [colI , 3 ] * IB [0 , 1 ]
119+ _311 = intermediate [colI , 3 ] * IB [1 , 1 ]
120+ result [2 , colI ] = _000 + _101
121+ result [3 , colI ] = _200 + _301
122+ result [4 , colI ] = _010 + _111
123+ result [5 , colI ] = _210 + _311
124+ result [0 , colI ] = - _000 - _101 - _010 - _111
125+ result [1 , colI ] = - _200 - _301 - _210 - _311
126+ return result
127+
128+ def val (x , e , vol , IB , mu , lam ):
129+ sum = 0.0
130+ for i in range (0 , len (e )):
131+ F = deformation_grad (x , e [i ], IB [i ])
132+ sum += vol [i ] * Psi (F , mu [i ], lam [i ])
133+ return sum
134+
135+ def grad (x , e , vol , IB , mu , lam ):
136+ g = np .array ([[0.0 , 0.0 ]] * len (x ))
137+ for i in range (0 , len (e )):
138+ F = deformation_grad (x , e [i ], IB [i ])
139+ P = vol [i ] * dPsi_div_dF (F , mu [i ], lam [i ])
140+ g_local = dPsi_div_dx (P , IB [i ])
141+ for j in range (0 , 3 ):
142+ g [e [i ][j ]] += g_local [j ]
143+ return g
144+
145+ def hess (x , e , vol , IB , mu , lam ):
146+ IJV = [[0 ] * (len (e ) * 36 ), [0 ] * (len (e ) * 36 ), np .array ([0.0 ] * (len (e ) * 36 ))]
147+ for i in range (0 , len (e )):
148+ F = deformation_grad (x , e [i ], IB [i ])
149+ dP_div_dF = vol [i ] * d2Psi_div_dF2 (F , mu [i ], lam [i ])
150+ local_hess = d2Psi_div_dx2 (dP_div_dF , IB [i ])
151+ for xI in range (0 , 3 ):
152+ for xJ in range (0 , 3 ):
153+ for dI in range (0 , 2 ):
154+ for dJ in range (0 , 2 ):
155+ ind = i * 36 + (xI * 3 + xJ ) * 4 + dI * 2 + dJ
156+ IJV [0 ][ind ] = e [i ][xI ] * 2 + dI
157+ IJV [1 ][ind ] = e [i ][xJ ] * 2 + dJ
158+ IJV [2 ][ind ] = local_hess [xI * 2 + dI , xJ * 2 + dJ ]
159+ return IJV
160+
161+ def init_step_size (x , e , p ):
162+ alpha = 1
163+ for i in range (0 , len (e )):
164+ x21 = x [e [i ][1 ]] - x [e [i ][0 ]]
165+ x31 = x [e [i ][2 ]] - x [e [i ][0 ]]
166+ p21 = p [e [i ][1 ]] - p [e [i ][0 ]]
167+ p31 = p [e [i ][2 ]] - p [e [i ][0 ]]
168+ detT = np .linalg .det (np .transpose ([x21 , x31 ]))
169+ a = np .linalg .det (np .transpose ([p21 , p31 ])) / detT
170+ b = (np .linalg .det (np .transpose ([x21 , p31 ])) + np .linalg .det (np .transpose ([p21 , x31 ]))) / detT
171+ c = 0.9 # solve for alpha that first brings the new volume to 0.1x the old volume for slackness
172+ critical_alpha = utils .smallest_positive_real_root_quad (a , b , c )
173+ if critical_alpha > 0 :
174+ alpha = min (alpha , critical_alpha )
175+ return alpha
0 commit comments