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