PolyFEM
Loading...
Searching...
No Matches
diff_elastic_energy.py
Go to the documentation of this file.
1import sympy as sp
2from sympy.printing import ccode
3import pretty_print
4import argparse
5import os
6import numpy as np
7from pathlib import Path
8
9
11 def __init__(self, use_rest_pose, dim):
12 self.use_rest_pose = use_rest_pose
13 self.dim = dim
14
15 def parameters(self):
16 return []
17
18 def get_standard(self):
19 if self.use_rest_pose:
20 return sp.eye(self.dim)
21
22 if self.dim == 2:
23 standard = sp.Matrix([
24 [1, 0],
25 [sp.Rational(1, 2), sp.sqrt(3) / 2]
26 ])
27 else:
28 standard = sp.Matrix([
29 [1, 0, 0],
30 [sp.Rational(1, 2), sp.sqrt(3) / 2, 0],
31 [sp.Rational(1, 2),
32 sp.Rational(1, 2) / sp.sqrt(3), sp.sqrt(3) / 2]
33 ])
34 standard = standard.inv().T
35
36 return standard
37
38 def eval(self, p, t, el_id, def_grad):
39 if self.use_rest_pose:
40 power = 1 if self.dim == 2 else sp.Rational(2, 3)
41 else:
42 power = 2 if self.dim == 2 else sp.Rational(5, 3)
43
44 standard = self.get_standard()
45
46 if not self.use_rest_pose:
47 def_grad = def_grad @ standard
48
49 det = def_grad.det()
50
51 # if det <= 0:
52 # return sp.nan
53
54 powJ = det**power
55 return (def_grad.T @ def_grad).trace() / powJ
56
57
59 def __init__(self, dim):
60 self.dim = dim
61 self.k_ = sp.Symbol('k')
62
63 def parameters(self):
64 return ["k"]
65
66 def eval(self, p, t, el_id, def_grad):
67 k = self.k_
68
69 J = def_grad.det()
70 log_J = sp.log(J)
71
72 val = k / 2.0 * ((J * J - 1) / 2.0 - log_J)
73
74 return val
75
76
77def compute_energy(energy):
78 dim = energy.dim
79 F = sp.Matrix(dim, dim, lambda i, j: sp.Symbol(f"F{i}{j}"))
80 p = sp.MatrixSymbol('p', dim, 1)
81 t = sp.Symbol('t')
82 el_id = sp.Symbol('el_id')
83
84 E = energy.eval(p, t, el_id, F)
85 E = sp.simplify(E)
86
87 x = sp.Matrix([F[i, j] for i in range(dim) for j in range(dim)])
88 grad = sp.Matrix([sp.diff(E, v) for v in x])
89 hess = grad.jacobian(x)
90
91 return E, grad, hess
92
93
94energies = {
95 "VolumePenalty2d": VolumePenaltyEnergy(dim=2),
96 "VolumePenalty3d": VolumePenaltyEnergy(dim=3),
97 "AMIPS2d": AMIPSEnergy(use_rest_pose=False, dim=2),
98 "AMIPS2drest": AMIPSEnergy(use_rest_pose=True, dim=2),
99 "AMIPS3d": AMIPSEnergy(use_rest_pose=False, dim=3),
100 "AMIPS3drest": AMIPSEnergy(use_rest_pose=True, dim=3),
101}
102
103
105 parser = argparse.ArgumentParser(
106 description=__doc__,
107 formatter_class=argparse.RawDescriptionHelpFormatter)
108 parser.add_argument("output", type=str, help="path to the output folder")
109 return parser.parse_args()
110
111
112if __name__ == "__main__":
113 args = parse_args()
114 path = Path(os.path.abspath(args.output))
115
116 for name, energy in energies.items():
117 E, grad, hess = compute_energy(energy)
118 dim = energy.dim
119
120 file = path / f"{name}.hpp"
121
122 fparams = "(const RowVectorNd &p, const double t, const int el_id, const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3>& F"
123 for param in energy.parameters():
124 fparams += f", const double {param}"
125 fparams += ")"
126
127 with open(file, "w") as f:
128 f.write(f"// Auto-generated code for {name} energy\n")
129 f.write(f"#pragma once\n")
130 f.write("#include <Eigen/Dense>\n\n")
131 f.write("namespace polyfem {\n")
132 f.write(f" namespace autogen {{\n")
133
134 # f.write(f" inline double {name}_energy{fparams} {{\n")
135 # for i in range(dim):
136 # for j in range(dim):
137 # f.write(f" const double F{i*dim + j} = F({i}, {j});\n")
138 # f.write(f" const double {pretty_print.C99_print(sp.sympify(E))}\n")
139 # f.write(f" return result_0;\n")
140 # f.write(" }\n\n")
141
142 f.write(
143 f" Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> {name}_gradient{fparams} {{\n")
144 f.write(
145 f" Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> grad({dim},{dim});\n")
146 for i in range(dim):
147 for j in range(dim):
148 f.write(
149 f" const double F{i}{j} = F({i}, {j});\n")
150 f.write(f" std::array<double, {dim*dim}> result_0;\n")
151 f.write(
152 f" {pretty_print.C99_print(sp.sympify(grad))};\n")
153 for i in range(dim):
154 for j in range(dim):
155 idx = i * dim + j
156 f.write(f" grad({i}, {j}) = result_0[{idx}];\n")
157 f.write(" return grad;\n")
158 f.write(" }\n\n")
159
160 f.write(
161 f" inline Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, 9, 9> {name}_hessian{fparams} {{\n")
162 f.write(
163 f" Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, 9, 9> hess({dim*dim},{dim*dim});\n")
164 f.write(f" std::array<double, {dim**4}> result_0;\n")
165 for i in range(dim):
166 for j in range(dim):
167 f.write(
168 f" const double F{i}{j} = F({i}, {j});\n")
169 f.write(
170 f" {pretty_print.C99_print(sp.sympify(hess))};\n")
171 for i in range(dim*dim):
172 for j in range(dim*dim):
173 f.write(
174 f" hess({i}, {j}) = result_0[{i*dim*dim+j}];\n")
175 f.write(" return hess;\n")
176 f.write(" }\n")
177 f.write(" }\n")
178 f.write("}\n")
__init__(self, use_rest_pose, dim)
eval(self, p, t, el_id, def_grad)