Skip to content

Commit 9149060

Browse files
committed
separate self frictional/less contact
1 parent 4a25d75 commit 9149060

15 files changed

Lines changed: 1023 additions & 0 deletions

self_friction/BarrierEnergy.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import math
2+
import numpy as np
3+
4+
import distance.PointEdgeDistance as PE
5+
import distance.CCD as CCD
6+
7+
import utils
8+
9+
dhat = 0.01
10+
kappa = 1e5
11+
12+
def val(x, n, o, bp, be, contact_area):
13+
sum = 0.0
14+
# floor:
15+
for i in range(0, len(x)):
16+
d = n.dot(x[i] - o)
17+
if d < dhat:
18+
s = d / dhat
19+
sum += contact_area[i] * dhat * kappa / 2 * (s - 1) * math.log(s)
20+
# ceil:
21+
n = np.array([0.0, -1.0])
22+
for i in range(0, len(x) - 1):
23+
d = n.dot(x[i] - x[-1])
24+
if d < dhat:
25+
s = d / dhat
26+
sum += contact_area[i] * dhat * kappa / 2 * (s - 1) * math.log(s)
27+
# self-contact
28+
dhat_sqr = dhat * dhat
29+
for xI in bp:
30+
for eI in be:
31+
if xI != eI[0] and xI != eI[1]: # do not consider a point and its incident edge
32+
d_sqr = PE.val(x[xI], x[eI[0]], x[eI[1]])
33+
if d_sqr < dhat_sqr:
34+
s = d_sqr / dhat_sqr
35+
# since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity:
36+
sum += contact_area[xI] * dhat * kappa / 8 * (s - 1) * math.log(s)
37+
return sum
38+
39+
def grad(x, n, o, bp, be, contact_area):
40+
g = np.array([[0.0, 0.0]] * len(x))
41+
# floor:
42+
for i in range(0, len(x)):
43+
d = n.dot(x[i] - o)
44+
if d < dhat:
45+
s = d / dhat
46+
g[i] = contact_area[i] * dhat * (kappa / 2 * (math.log(s) / dhat + (s - 1) / d)) * n
47+
# ceil:
48+
n = np.array([0.0, -1.0])
49+
for i in range(0, len(x) - 1):
50+
d = n.dot(x[i] - x[-1])
51+
if d < dhat:
52+
s = d / dhat
53+
local_grad = contact_area[i] * dhat * (kappa / 2 * (math.log(s) / dhat + (s - 1) / d)) * n
54+
g[i] += local_grad
55+
g[-1] -= local_grad
56+
# self-contact
57+
dhat_sqr = dhat * dhat
58+
for xI in bp:
59+
for eI in be:
60+
if xI != eI[0] and xI != eI[1]: # do not consider a point and its incident edge
61+
d_sqr = PE.val(x[xI], x[eI[0]], x[eI[1]])
62+
if d_sqr < dhat_sqr:
63+
s = d_sqr / dhat_sqr
64+
# since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity:
65+
local_grad = contact_area[xI] * dhat * (kappa / 8 * (math.log(s) / dhat_sqr + (s - 1) / d_sqr)) * PE.grad(x[xI], x[eI[0]], x[eI[1]])
66+
g[xI] += local_grad[0:2]
67+
g[eI[0]] += local_grad[2:4]
68+
g[eI[1]] += local_grad[4:6]
69+
return g
70+
71+
def hess(x, n, o, bp, be, contact_area):
72+
IJV = [[0] * 0, [0] * 0, np.array([0.0] * 0)]
73+
# floor:
74+
for i in range(0, len(x)):
75+
d = n.dot(x[i] - o)
76+
if d < dhat:
77+
local_hess = contact_area[i] * dhat * kappa / (2 * d * d * dhat) * (d + dhat) * np.outer(n, n)
78+
for c in range(0, 2):
79+
for r in range(0, 2):
80+
IJV[0].append(i * 2 + r)
81+
IJV[1].append(i * 2 + c)
82+
IJV[2] = np.append(IJV[2], local_hess[r, c])
83+
# ceil:
84+
n = np.array([0.0, -1.0])
85+
for i in range(0, len(x) - 1):
86+
d = n.dot(x[i] - x[-1])
87+
if d < dhat:
88+
local_hess = contact_area[i] * dhat * kappa / (2 * d * d * dhat) * (d + dhat) * np.outer(n, n)
89+
index = [i, len(x) - 1]
90+
for nI in range(0, 2):
91+
for nJ in range(0, 2):
92+
for c in range(0, 2):
93+
for r in range(0, 2):
94+
IJV[0].append(index[nI] * 2 + r)
95+
IJV[1].append(index[nJ] * 2 + c)
96+
IJV[2] = np.append(IJV[2], ((-1) ** (nI != nJ)) * local_hess[r, c])
97+
# self-contact
98+
dhat_sqr = dhat * dhat
99+
for xI in bp:
100+
for eI in be:
101+
if xI != eI[0] and xI != eI[1]: # do not consider a point and its incident edge
102+
d_sqr = PE.val(x[xI], x[eI[0]], x[eI[1]])
103+
if d_sqr < dhat_sqr:
104+
d_sqr_grad = PE.grad(x[xI], x[eI[0]], x[eI[1]])
105+
s = d_sqr / dhat_sqr
106+
# since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity:
107+
local_hess = contact_area[xI] * dhat * utils.make_PD(kappa / (8 * d_sqr * d_sqr * dhat_sqr) * (d_sqr + dhat_sqr) * np.outer(d_sqr_grad, d_sqr_grad) \
108+
+ (kappa / 8 * (math.log(s) / dhat_sqr + (s - 1) / d_sqr)) * PE.hess(x[xI], x[eI[0]], x[eI[1]]))
109+
index = [xI, eI[0], eI[1]]
110+
for nI in range(0, 3):
111+
for nJ in range(0, 3):
112+
for c in range(0, 2):
113+
for r in range(0, 2):
114+
IJV[0].append(index[nI] * 2 + r)
115+
IJV[1].append(index[nJ] * 2 + c)
116+
IJV[2] = np.append(IJV[2], local_hess[nI * 2 + r, nJ * 2 + c])
117+
return IJV
118+
119+
def init_step_size(x, n, o, bp, be, p):
120+
alpha = 1
121+
# floor:
122+
for i in range(0, len(x)):
123+
p_n = p[i].dot(n)
124+
if p_n < 0:
125+
alpha = min(alpha, 0.9 * n.dot(x[i] - o) / -p_n)
126+
# ceil:
127+
n = np.array([0.0, -1.0])
128+
for i in range(0, len(x) - 1):
129+
p_n = (p[i] - p[-1]).dot(n)
130+
if p_n < 0:
131+
alpha = min(alpha, 0.9 * n.dot(x[i] - x[-1]) / -p_n)
132+
# self-contact
133+
for xI in bp:
134+
for eI in be:
135+
if xI != eI[0] and xI != eI[1]: # do not consider a point and its incident edge
136+
if CCD.bbox_overlap(x[xI], x[eI[0]], x[eI[1]], p[xI], p[eI[0]], p[eI[1]], alpha):
137+
toc = CCD.narrow_phase_CCD(x[xI], x[eI[0]], x[eI[1]], p[xI], p[eI[0]], p[eI[1]], alpha)
138+
if alpha > toc:
139+
alpha = toc
140+
return alpha
141+
142+
def compute_mu_lambda(x, n, o, bp, be, contact_area, mu):
143+
# floor:
144+
mu_lambda = np.array([0.0] * len(x))
145+
for i in range(0, len(x)):
146+
d = n.dot(x[i] - o)
147+
if d < dhat:
148+
s = d / dhat
149+
mu_lambda[i] = mu * -contact_area[i] * dhat * (kappa / 2 * (math.log(s) / dhat + (s - 1) / d))
150+
# self-contact
151+
mu_lambda_self = []
152+
dhat_sqr = dhat * dhat
153+
for xI in bp:
154+
for eI in be:
155+
if xI != eI[0] and xI != eI[1]: # do not consider a point and its incident edge
156+
d_sqr = PE.val(x[xI], x[eI[0]], x[eI[1]])
157+
if d_sqr < dhat_sqr:
158+
s = d_sqr / dhat_sqr
159+
# since d_sqr is used, need to divide by 8 not 2 here for consistency to linear elasticity
160+
# also, lambda = -\partial b / \partial d = -(\partial b / \partial d^2) * (\partial d^2 / \partial d)
161+
mu_lam = mu * -contact_area[xI] * dhat * (kappa / 8 * (math.log(s) / dhat_sqr + (s - 1) / d_sqr)) * 2 * math.sqrt(d_sqr)
162+
[n, r] = PE.tangent(x[xI], x[eI[0]], x[eI[1]]) # normal and closest point parameterization on the edge
163+
mu_lambda_self.append([xI, eI[0], eI[1], mu_lam, n, r])
164+
return [mu_lambda, mu_lambda_self]

self_friction/FrictionEnergy.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import numpy as np
2+
import utils
3+
4+
epsv = 1e-3
5+
6+
def f0(vbarnorm, epsv, hhat):
7+
if vbarnorm >= epsv:
8+
return vbarnorm * hhat
9+
else:
10+
vbarnormhhat = vbarnorm * hhat
11+
epsvhhat = epsv * hhat
12+
return vbarnormhhat * vbarnormhhat * (-vbarnormhhat / 3.0 + epsvhhat) / (epsvhhat * epsvhhat) + epsvhhat / 3.0
13+
14+
def f1_div_vbarnorm(vbarnorm, epsv):
15+
if vbarnorm >= epsv:
16+
return 1.0 / vbarnorm
17+
else:
18+
return (-vbarnorm + 2.0 * epsv) / (epsv * epsv)
19+
20+
def f_hess_term(vbarnorm, epsv):
21+
if vbarnorm >= epsv:
22+
return -1.0 / (vbarnorm * vbarnorm)
23+
else:
24+
return -1.0 / (epsv * epsv)
25+
26+
def val(v, mu_lambda, mu_lambda_self, hhat, n):
27+
sum = 0.0
28+
# floor:
29+
T = np.identity(2) - np.outer(n, n) # tangent of slope is constant
30+
for i in range(0, len(v)):
31+
if mu_lambda[i] > 0:
32+
vbar = np.transpose(T).dot(v[i])
33+
sum += mu_lambda[i] * f0(np.linalg.norm(vbar), epsv, hhat)
34+
# self-contact:
35+
for i in range(0, len(mu_lambda_self)):
36+
[xI, eI0, eI1, mu_lam, n, r] = mu_lambda_self[i]
37+
T = np.identity(2) - np.outer(n, n)
38+
rel_v = v[xI] - ((1 - r) * v[eI0] + r * v[eI1])
39+
vbar = np.transpose(T).dot(rel_v)
40+
sum += mu_lam * f0(np.linalg.norm(vbar), epsv, hhat)
41+
return sum
42+
43+
def grad(v, mu_lambda, mu_lambda_self, hhat, n):
44+
g = np.array([[0.0, 0.0]] * len(v))
45+
# floor:
46+
T = np.identity(2) - np.outer(n, n) # tangent of slope is constant
47+
for i in range(0, len(v)):
48+
if mu_lambda[i] > 0:
49+
vbar = np.transpose(T).dot(v[i])
50+
g[i] = mu_lambda[i] * f1_div_vbarnorm(np.linalg.norm(vbar), epsv) * T.dot(vbar)
51+
# self-contact:
52+
for i in range(0, len(mu_lambda_self)):
53+
[xI, eI0, eI1, mu_lam, n, r] = mu_lambda_self[i]
54+
T = np.identity(2) - np.outer(n, n)
55+
rel_v = v[xI] - ((1 - r) * v[eI0] + r * v[eI1])
56+
vbar = np.transpose(T).dot(rel_v)
57+
g_rel_v = mu_lam * f1_div_vbarnorm(np.linalg.norm(vbar), epsv) * T.dot(vbar)
58+
g[xI] += g_rel_v
59+
g[eI0] += g_rel_v * -(1 - r)
60+
g[eI1] += g_rel_v * -r
61+
return g
62+
63+
def hess(v, mu_lambda, mu_lambda_self, hhat, n):
64+
IJV = [[0] * 0, [0] * 0, np.array([0.0] * 0)]
65+
# floor:
66+
T = np.identity(2) - np.outer(n, n) # tangent of slope is constant
67+
for i in range(0, len(v)):
68+
if mu_lambda[i] > 0:
69+
vbar = np.transpose(T).dot(v[i])
70+
vbarnorm = np.linalg.norm(vbar)
71+
inner_term = f1_div_vbarnorm(vbarnorm, epsv) * np.identity(2)
72+
if vbarnorm != 0:
73+
inner_term += f_hess_term(vbarnorm, epsv) / vbarnorm * np.outer(vbar, vbar)
74+
local_hess = mu_lambda[i] * T.dot(utils.make_PD(inner_term)).dot(np.transpose(T)) / hhat
75+
for c in range(0, 2):
76+
for r in range(0, 2):
77+
IJV[0].append(i * 2 + r)
78+
IJV[1].append(i * 2 + c)
79+
IJV[2] = np.append(IJV[2], local_hess[r, c])
80+
# self-contact:
81+
for i in range(0, len(mu_lambda_self)):
82+
[xI, eI0, eI1, mu_lam, n, r] = mu_lambda_self[i]
83+
T = np.identity(2) - np.outer(n, n)
84+
rel_v = v[xI] - ((1 - r) * v[eI0] + r * v[eI1])
85+
vbar = np.transpose(T).dot(rel_v)
86+
vbarnorm = np.linalg.norm(vbar)
87+
inner_term = f1_div_vbarnorm(vbarnorm, epsv) * np.identity(2)
88+
if vbarnorm != 0:
89+
inner_term += f_hess_term(vbarnorm, epsv) / vbarnorm * np.outer(vbar, vbar)
90+
hess_rel_v = mu_lam * T.dot(utils.make_PD(inner_term)).dot(np.transpose(T)) / hhat
91+
index = [xI, eI0, eI1]
92+
d_rel_v_dv = [1, -(1 - r), -r]
93+
for nI in range(0, 3):
94+
for nJ in range(0, 3):
95+
for c in range(0, 2):
96+
for r in range(0, 2):
97+
IJV[0].append(index[nI] * 2 + r)
98+
IJV[1].append(index[nJ] * 2 + c)
99+
IJV[2] = np.append(IJV[2], d_rel_v_dv[nI] * d_rel_v_dv[nJ] * hess_rel_v[r, c])
100+
return IJV

self_friction/GravityEnergy.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import numpy as np
2+
3+
gravity = [0.0, -9.81]
4+
5+
def val(x, m):
6+
sum = 0.0
7+
for i in range(0, len(x)):
8+
sum += -m[i] * x[i].dot(gravity)
9+
return sum
10+
11+
def grad(x, m):
12+
g = np.array([gravity] * len(x))
13+
for i in range(0, len(x)):
14+
g[i] *= -m[i]
15+
return g
16+
17+
# Hessian is 0

self_friction/InertiaEnergy.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import numpy as np
2+
3+
def val(x, x_tilde, m):
4+
sum = 0.0
5+
for i in range(0, len(x)):
6+
diff = x[i] - x_tilde[i]
7+
sum += 0.5 * m[i] * diff.dot(diff)
8+
return sum
9+
10+
def grad(x, x_tilde, m):
11+
g = np.array([[0.0, 0.0]] * len(x))
12+
for i in range(0, len(x)):
13+
g[i] = m[i] * (x[i] - x_tilde[i])
14+
return g
15+
16+
def hess(x, x_tilde, m):
17+
IJV = [[0] * (len(x) * 2), [0] * (len(x) * 2), np.array([0.0] * (len(x) * 2))]
18+
for i in range(0, len(x)):
19+
for d in range(0, 2):
20+
IJV[0][i * 2 + d] = i * 2 + d
21+
IJV[1][i * 2 + d] = i * 2 + d
22+
IJV[2][i * 2 + d] = m[i]
23+
return IJV

0 commit comments

Comments
 (0)