PolyFEM
Loading...
Searching...
No Matches
elasticity_rhs.py
Go to the documentation of this file.
1import os
2import argparse
3
4from sympy import *
5from sympy.matrices import *
6import re
7
8# local
9import pretty_print
10
11
12
13def Det(mat):
14 assert(mat.rows == mat.cols)
15
16 if(mat.rows == 1):
17 return mat[0]
18 elif(mat.rows == 2):
19 return mat[0, 0] * mat[1, 1] - mat[0, 1] * mat[1, 0]
20 elif(mat.rows == 3):
21 return mat[0,0]*(mat[1,1]*mat[2,2]-mat[1,2]*mat[2,1])-mat[0,1]*(mat[1,0]*mat[2,2]-mat[1,2]*mat[2,0])+mat[0,2]*(mat[1,0]*mat[2,1]-mat[1,1]*mat[2,0])
22
23 assert(False)
24 return 0
25
26
27def sigma_fun(j, ee, C, dim):
28 res = 0
29
30 for k in range(dim):
31 res += C(j, k) * ee[k]
32 return res
33
34
35# sigma = 2 * mu * eps + lambda * strain.trace() * Id;
36def linear_elasticity(disp_grad, def_grad):
37 l_dim = def_grad.rows
38 mu = Symbol('mu')
39 llambda = Symbol('lambda')
40
41 eps = 1 / 2 * (disp_grad + Transpose(disp_grad))
42 t_eps = eps[0, 0]
43
44 for i in range(1,l_dim):
45 t_eps += eps[i, i]
46
47 sigma = 2*mu*eps + llambda * t_eps * eye(l_dim)
48
49 return sigma
50
51
52# sigma = (C:strain)
53def hooke(disp_grad, def_grad):
54 l_dim = def_grad.rows
55
56 C = Function('C')
57
58 eps = 1 / 2 * (disp_grad + Transpose(disp_grad))
59
60 if l_dim == 2:
61 ee = [eps[0, 0], eps[1, 1], 2 * eps[0, 1]]
62
63 sigma = Matrix([
64 [sigma_fun(0, ee, C, 3), sigma_fun(2, ee, C, 3)],
65 [sigma_fun(2, ee, C, 3), sigma_fun(1, ee, C, 3)]
66 ])
67 else:
68 ee = [eps[0, 0], eps[1, 1], eps[2, 2], 2 * eps[1, 2], 2 * eps[0, 2], 2 * eps[0, 1]]
69
70 sigma = Matrix([
71 [sigma_fun(0, ee, C, 6), sigma_fun(5, ee, C, 6), sigma_fun(4, ee, C, 6)],
72 [sigma_fun(5, ee, C, 6), sigma_fun(1, ee, C, 6), sigma_fun(3, ee, C, 6)],
73 [sigma_fun(4, ee, C, 6), sigma_fun(3, ee, C, 6), sigma_fun(2, ee, C, 6)]
74 ])
75
76 return sigma
77
78
79# sigma = (C:strain)
80def saint_venant(disp_grad, def_grad):
81 l_dim = def_grad.rows
82
83 C = Function('C')
84
85 eps = 1 / 2 * (Transpose(disp_grad) * disp_grad + disp_grad + Transpose(disp_grad))
86
87 if l_dim == 2:
88 ee = [eps[0, 0], eps[1, 1], 2 * eps[0, 1]]
89
90 sigma = Matrix([
91 [sigma_fun(0, ee, C, 3), sigma_fun(2, ee, C, 3)],
92 [sigma_fun(2, ee, C, 3), sigma_fun(1, ee, C, 3)]
93 ])
94 else:
95 ee = [eps[0, 0], eps[1, 1], eps[2, 2], 2 * eps[1, 2], 2 * eps[0, 2], 2 * eps[0, 1]]
96
97 sigma = Matrix([
98 [sigma_fun(0, ee, C, 6), sigma_fun(5, ee, C, 6), sigma_fun(4, ee, C, 6)],
99 [sigma_fun(5, ee, C, 6), sigma_fun(1, ee, C, 6), sigma_fun(3, ee, C, 6)],
100 [sigma_fun(4, ee, C, 6), sigma_fun(3, ee, C, 6), sigma_fun(2, ee, C, 6)]
101 ])
102
103 sigma = def_grad * sigma
104
105 return sigma
106
107
108# sigma = mu * (def_grad - def_grad^{-T}) + lambda ln (det def_grad) def_grad^{-T}
109def neo_hookean(disp_grad, def_grad):
110 mu = Symbol('mu')
111 llambda = Symbol('lambda')
112
113 FmT = Inverse(Transpose(def_grad))
114
115 return mu * (def_grad - FmT) + llambda * log(Determinant(def_grad)) * FmT
116
117
118# sigma = (mu disp_grad + lambda ln(det def_grad) I)/det def_grad
119# def neo_hookean(disp_grad, def_grad):
120# l_dim = def_grad.rows
121
122# mu = Symbol('mu')
123# llambda = Symbol('lambda')
124
125# J = Det(def_grad)
126
127# return (mu * disp_grad + llambda * log(J) * eye(l_dim)) / J
128
129
130def divergence(sigma):
131 if dim == 2:
132 div = Matrix([
133 sigma[0, 0].diff(x) + sigma[0, 1].diff(y),
134 sigma[1, 0].diff(x) + sigma[1, 1].diff(y)
135 ])
136 else:
137 div = Matrix([
138 sigma[0, 0].diff(x) + sigma[0, 1].diff(y) + sigma[0, 2].diff(z),
139 sigma[1, 0].diff(x) + sigma[1, 1].diff(y) + sigma[1, 2].diff(z),
140 sigma[2, 0].diff(x) + sigma[2, 1].diff(y) + sigma[2, 2].diff(z)
141 ])
142
143 return div
144
145
147 parser = argparse.ArgumentParser(
148 description=__doc__,
149 formatter_class=argparse.RawDescriptionHelpFormatter)
150 parser.add_argument("output", type=str, help="path to the output folder")
151 return parser.parse_args()
152
153
154if __name__ == "__main__":
155 args = parse_args()
156 dims = [2, 3]
157 names = ["linear_elasticity", "hooke", "saint_venant", "neo_hookean"]
158 cpp = "#include <polyfem/autogen/auto_elasticity_rhs.hpp>\n\n\n"
159 hpp = "#pragma once\n\n#include <polyfem/utils/ElasticityUtils.hpp>\n#include <polyfem/utils/AutodiffTypes.hpp>\n#include <Eigen/Dense>\n\n"
160 cpp = cpp + "namespace polyfem {\nnamespace autogen " + "{\n"
161 hpp = hpp + "namespace polyfem {\nnamespace autogen " + "{\n"
162
163 x = Symbol('x')
164 y = Symbol('y')
165 z = Symbol('z')
166
167 for name in names:
168 for dim in dims:
169 print("processing " + name + " in " + str(dim) + "D")
170
171 if dim == 2:
172 X = Matrix([x, y])
173 f = Matrix([Function('f0')(x, y), Function('f1')(x, y)])
174 else:
175 X = Matrix([x, y, z])
176 f = Matrix([Function('f0')(x, y, z), Function('f1')(x, y, z), Function('f2')(x, y, z)])
177
178 disp_grad = f.jacobian(X)
179 def_grad = (eye(dim) + disp_grad)
180
181 if name == "hooke":
182 sigma = hooke(disp_grad, def_grad)
183 elif name == "saint_venant":
184 sigma = saint_venant(disp_grad, def_grad)
185 elif name == "neo_hookean":
186 sigma = neo_hookean(disp_grad, def_grad)
187 elif name == "linear_elasticity":
188 sigma = linear_elasticity(disp_grad, def_grad)
189
190 div = divergence(sigma)
191 # div = simplify(div)
193
194 c99 = re.sub(r"f0\‍(x, y(, z)?\‍)", "pt(0)", c99)
195 c99 = re.sub(r"f1\‍(x, y(, z)?\‍)", "pt(1)", c99)
196 c99 = re.sub(r"f2\‍(x, y(, z)?\‍)", "pt(2)", c99)
197
198 c99 = re.sub(r", x, x\‍)", ".getHessian()(0,0)", c99)
199 c99 = re.sub(r", x, y\‍)", ".getHessian()(0,1)", c99)
200 c99 = re.sub(r", x, z\‍)", ".getHessian()(0,2)", c99)
201
202 c99 = re.sub(r", y, y\‍)", ".getHessian()(1,1)", c99)
203 c99 = re.sub(r", y, z\‍)", ".getHessian()(1,2)", c99)
204
205 c99 = re.sub(r", z, z\‍)", ".getHessian()(2,2)", c99)
206
207 c99 = re.sub(r", x\‍)", ".getGradient()(0)", c99)
208 c99 = re.sub(r", y\‍)", ".getGradient()(1)", c99)
209 c99 = re.sub(r", z\‍)", ".getGradient()(2)", c99)
210
211 c99 = re.sub(r"Derivative\‍(*", "", c99)
212
213 c99 = re.sub(r", \‍(x, 2\‍)\‍)", ".getHessian()(0,0)", c99)
214 c99 = re.sub(r", \‍(y, 2\‍)\‍)", ".getHessian()(1,1)", c99)
215 c99 = re.sub(r", \‍(z, 2\‍)\‍)", ".getHessian()(2,2)", c99)
216
217 c99 = c99.replace("result_0[0]", "res(0)")
218 c99 = c99.replace("result_0[1]", "res(1)")
219 c99 = c99.replace("result_0[2]", "res(2)")
220
221 # c99 = re.sub("// ", "", c99)
222
223 signature = "void " + name + "_" + str(dim) + "d_function(const AutodiffHessianPt &pt"
224 if name == "hooke" or name == "saint_venant":
225 signature = signature + ", const ElasticityTensor &C"
226 elif name == "linear_elasticity" or name == "neo_hookean":
227 signature = signature + ", const double lambda, const double mu"
228
229 signature = signature + ", Eigen::Matrix<double, Eigen::Dynamic, 1, 0, 3, 1> &res)"
230
231 cpp = cpp + signature + " {\nres.resize(" + str(dim) + ");\n" + c99 + "\n}\n\n"
232 hpp = hpp + signature + ";\n"
233
234 cpp = cpp + "\n"
235 hpp = hpp + "\n"
236
237 cpp = cpp + "\n}}\n"
238 hpp = hpp + "\n}}\n"
239 path = os.path.abspath(args.output)
240
241 print("saving...")
242 with open(os.path.join(path, "auto_elasticity_rhs.cpp"), "w") as file:
243 file.write(cpp)
244
245 with open(os.path.join(path, "auto_elasticity_rhs.hpp"), "w") as file:
246 file.write(hpp)
247
248 print("done!")
hooke(disp_grad, def_grad)
sigma_fun(j, ee, C, dim)
saint_venant(disp_grad, def_grad)
linear_elasticity(disp_grad, def_grad)
neo_hookean(disp_grad, def_grad)
C99_print(expr)