PolyFEM
Loading...
Searching...
No Matches
LazyCubicInterpolator.cpp
Go to the documentation of this file.
2#include <mutex>
3
4namespace polyfem
5{
6 void LazyCubicInterpolator::bicubic_interpolation(const Eigen::MatrixXd &corner_point, const std::vector<std::string> &keys, const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad) const
7 {
8 Eigen::MatrixXd corner_val(4, 1);
9 Eigen::MatrixXd corner_grad(4, 2);
10 Eigen::MatrixXd corner_grad_grad(4, 1);
11 for (int i = 0; i < 4; ++i)
12 {
13 {
14 std::shared_lock distance_lock(distance_mutex_);
15 corner_val(i) = implicit_function_distance.at(keys[i]);
16 }
17 {
18 std::shared_lock grad_lock(grad_mutex_);
19 auto mixed_grads = implicit_function_grads.at(keys[i]);
20 corner_grad(i, 0) = mixed_grads(0);
21 corner_grad(i, 1) = mixed_grads(1);
22 corner_grad_grad(i, 0) = mixed_grads(2);
23 }
24 }
25
26 Eigen::MatrixXd x(16, 1);
27 x << corner_val(0), corner_val(1), corner_val(2), corner_val(3),
28 delta_ * corner_grad(0, 0), delta_ * corner_grad(1, 0), delta_ * corner_grad(2, 0), delta_ * corner_grad(3, 0),
29 delta_ * corner_grad(0, 1), delta_ * corner_grad(1, 1), delta_ * corner_grad(2, 1), delta_ * corner_grad(3, 1),
30 delta_ * delta_ * corner_grad_grad(0, 0), delta_ * delta_ * corner_grad_grad(1, 0), delta_ * delta_ * corner_grad_grad(2, 0), delta_ * delta_ * corner_grad_grad(3, 0);
31
32 Eigen::MatrixXd coeffs = cubic_mat * x;
33
34 auto bar_x = [&corner_point](double x_) { return (x_ - corner_point(0, 0)) / (corner_point(1, 0) - corner_point(0, 0)); };
35 auto bar_y = [&corner_point](double y_) { return (y_ - corner_point(0, 1)) / (corner_point(2, 1) - corner_point(0, 1)); };
36
37 val = 0;
38 grad.setZero(2, 1);
39 for (int i = 0; i < 4; ++i)
40 for (int j = 0; j < 4; ++j)
41 {
42 val += coeffs(i + j * 4) * pow(bar_x(point(0)), i) * pow(bar_y(point(1)), j);
43 grad(0) += i == 0 ? 0 : (coeffs(i + j * 4) * i * pow(bar_x(point(0)), i - 1) * pow(bar_y(point(1)), j));
44 grad(1) += j == 0 ? 0 : coeffs(i + j * 4) * pow(bar_x(point(0)), i) * j * pow(bar_y(point(1)), j - 1);
45 }
46
47 grad(0) /= (corner_point(1, 0) - corner_point(0, 0));
48 grad(1) /= (corner_point(2, 1) - corner_point(0, 1));
49
50 assert(!std::isnan(grad(0)) && !std::isnan(grad(1)));
51 }
52
53 void LazyCubicInterpolator::tricubic_interpolation(const Eigen::MatrixXd &corner_point, const std::vector<std::string> &keys, const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad) const
54 {
55 Eigen::MatrixXd corner_val(8, 1);
56 Eigen::MatrixXd corner_grad(8, 3);
57 Eigen::MatrixXd corner_grad_grad(8, 3);
58 Eigen::MatrixXd corner_grad_grad_grad(8, 1);
59 for (int i = 0; i < 8; ++i)
60 {
61 {
62 std::shared_lock distance_lock(distance_mutex_);
63 corner_val(i) = implicit_function_distance.at(keys[i]);
64 }
65 {
66 std::shared_lock grad_lock(grad_mutex_);
67 auto mixed_grads = implicit_function_grads.at(keys[i]);
68 corner_grad(i, 0) = mixed_grads(0);
69 corner_grad(i, 1) = mixed_grads(1);
70 corner_grad(i, 2) = mixed_grads(2);
71 corner_grad_grad(i, 0) = mixed_grads(3);
72 corner_grad_grad(i, 1) = mixed_grads(4);
73 corner_grad_grad(i, 2) = mixed_grads(5);
74 corner_grad_grad_grad(i, 0) = mixed_grads(6);
75 }
76 }
77 Eigen::MatrixXd x(64, 1);
78 x << corner_val(0), corner_val(1), corner_val(2), corner_val(3), corner_val(4), corner_val(5), corner_val(6), corner_val(7),
79 delta_ * corner_grad(0, 0), delta_ * corner_grad(1, 0), delta_ * corner_grad(2, 0), delta_ * corner_grad(3, 0), delta_ * corner_grad(4, 0), delta_ * corner_grad(5, 0), delta_ * corner_grad(6, 0), delta_ * corner_grad(7, 0),
80 delta_ * corner_grad(0, 1), delta_ * corner_grad(1, 1), delta_ * corner_grad(2, 1), delta_ * corner_grad(3, 1), delta_ * corner_grad(4, 1), delta_ * corner_grad(5, 1), delta_ * corner_grad(6, 1), delta_ * corner_grad(7, 1),
81 delta_ * corner_grad(0, 2), delta_ * corner_grad(1, 2), delta_ * corner_grad(2, 2), delta_ * corner_grad(3, 2), delta_ * corner_grad(4, 2), delta_ * corner_grad(5, 2), delta_ * corner_grad(6, 2), delta_ * corner_grad(7, 2),
82 delta_ * delta_ * corner_grad_grad(0, 0), delta_ * delta_ * corner_grad_grad(1, 0), delta_ * delta_ * corner_grad_grad(2, 0), delta_ * delta_ * corner_grad_grad(3, 0), delta_ * delta_ * corner_grad_grad(4, 0), delta_ * delta_ * corner_grad_grad(5, 0), delta_ * delta_ * corner_grad_grad(6, 0), delta_ * delta_ * corner_grad_grad(7, 0),
83 delta_ * delta_ * corner_grad_grad(0, 1), delta_ * delta_ * corner_grad_grad(1, 1), delta_ * delta_ * corner_grad_grad(2, 1), delta_ * delta_ * corner_grad_grad(3, 1), delta_ * delta_ * corner_grad_grad(4, 1), delta_ * delta_ * corner_grad_grad(5, 1), delta_ * delta_ * corner_grad_grad(6, 1), delta_ * delta_ * corner_grad_grad(7, 1),
84 delta_ * delta_ * corner_grad_grad(0, 2), delta_ * delta_ * corner_grad_grad(1, 2), delta_ * delta_ * corner_grad_grad(2, 2), delta_ * delta_ * corner_grad_grad(3, 2), delta_ * delta_ * corner_grad_grad(4, 2), delta_ * delta_ * corner_grad_grad(5, 2), delta_ * delta_ * corner_grad_grad(6, 2), delta_ * delta_ * corner_grad_grad(7, 2),
85 delta_ * delta_ * delta_ * corner_grad_grad_grad(0, 0), delta_ * delta_ * delta_ * corner_grad_grad_grad(1, 0), delta_ * delta_ * delta_ * corner_grad_grad_grad(2, 0), delta_ * delta_ * delta_ * corner_grad_grad_grad(3, 0), delta_ * delta_ * delta_ * corner_grad_grad_grad(4, 0), delta_ * delta_ * delta_ * corner_grad_grad_grad(5, 0), delta_ * delta_ * delta_ * corner_grad_grad_grad(6, 0), delta_ * delta_ * delta_ * corner_grad_grad_grad(7, 0);
86
87 Eigen::MatrixXd coeffs = cubic_mat * x;
88
89 auto bar_x = [&corner_point](double x_) { return (x_ - corner_point(0, 0)) / (corner_point(1, 0) - corner_point(0, 0)); };
90 auto bar_y = [&corner_point](double y_) { return (y_ - corner_point(0, 1)) / (corner_point(2, 1) - corner_point(0, 1)); };
91 auto bar_z = [&corner_point](double z_) { return (z_ - corner_point(0, 2)) / (corner_point(4, 2) - corner_point(0, 2)); };
92
93 val = 0;
94 grad.setZero(3, 1);
95 for (int i = 0; i < 4; ++i)
96 for (int j = 0; j < 4; ++j)
97 for (int l = 0; l < 4; ++l)
98 {
99 val += coeffs(i + j * 4 + l * 16) * pow(bar_x(point(0)), i) * pow(bar_y(point(1)), j) * pow(bar_z(point(2)), l);
100 grad(0) += i == 0 ? 0 : (coeffs(i + j * 4 + l * 16) * i * pow(bar_x(point(0)), i - 1) * pow(bar_y(point(1)), j)) * pow(bar_z(point(2)), l);
101 grad(1) += j == 0 ? 0 : coeffs(i + j * 4 + l * 16) * pow(bar_x(point(0)), i) * j * pow(bar_y(point(1)), j - 1) * pow(bar_z(point(2)), l);
102 grad(2) += l == 0 ? 0 : coeffs(i + j * 4 + l * 16) * pow(bar_x(point(0)), i) * pow(bar_y(point(1)), j) * l * pow(bar_z(point(2)), l - 1);
103 }
104
105 grad(0) /= (corner_point(1, 0) - corner_point(0, 0));
106 grad(1) /= (corner_point(2, 1) - corner_point(0, 1));
107 grad(2) /= (corner_point(4, 2) - corner_point(0, 2));
108
109 assert(!std::isnan(grad(0)) && !std::isnan(grad(1)) && !std::isnan(grad(2)));
110 }
111
112 void LazyCubicInterpolator::cache_grid(std::function<void(const Eigen::MatrixXd &, double &)> compute_distance, const Eigen::MatrixXd &point)
113 {
114 Eigen::MatrixXi keys;
115 build_corner_keys(point, keys);
116 std::vector<std::string> keys_string;
117
118 auto safe_compute_distance = [this, compute_distance](const Eigen::MatrixXd &clamped_point, const std::string &key_string) {
119 std::unique_lock lock(distance_mutex_);
120 if (implicit_function_distance.count(key_string) == 0)
121 compute_distance(clamped_point, implicit_function_distance[key_string]);
122 };
123 auto safe_distance = [this, safe_compute_distance](const Eigen::VectorXi &key) {
124 Eigen::MatrixXd point;
125 std::string key_string;
126 double distance;
127 setup_key(key, key_string, point);
128 safe_compute_distance(point, key_string);
129 {
130 std::shared_lock lock(distance_mutex_);
131 distance = implicit_function_distance[key_string];
132 }
133 return distance;
134 };
135 auto centered_fd = [this, safe_distance](const Eigen::VectorXi &key, const int k) {
136 Eigen::MatrixXi key_plus, key_minus;
137 double distance_plus, distance_minus;
138 key_plus = key;
139 key_plus(k) += 1;
140 distance_plus = safe_distance(key_plus);
141 key_minus = key;
142 key_minus(k) -= 1;
143 distance_minus = safe_distance(key_minus);
144 return (1. / 2. / delta_) * (distance_plus - distance_minus);
145 };
146 auto centered_mixed_fd = [this, centered_fd](const Eigen::VectorXi &key, const int k1, const int k2) {
147 Eigen::VectorXi key_plus, key_minus;
148 key_plus = key;
149 key_plus(k1) += 1;
150 key_minus = key;
151 key_minus(k1) -= 1;
152 return (1. / 2. / delta_) * (centered_fd(key_plus, k2) - centered_fd(key_minus, k2));
153 };
154 auto centered_mixed_fd_3d = [this, centered_mixed_fd](const Eigen::VectorXi &key) {
155 Eigen::VectorXi key_plus, key_minus;
156 key_plus = key;
157 key_plus(0) += 1;
158 key_minus = key;
159 key_minus(0) -= 1;
160 return (1. / 2. / delta_) * (centered_mixed_fd(key_plus, 1, 2) - centered_mixed_fd(key_minus, 1, 2));
161 };
162 auto compute_grad = [this, centered_fd, centered_mixed_fd, centered_mixed_fd_3d](const Eigen::VectorXi &key) {
163 Eigen::VectorXd mixed_grads(dim_ == 2 ? 3 : 7);
164 if (dim_ == 2)
165 {
166 mixed_grads(0) = centered_fd(key, 0);
167 mixed_grads(1) = centered_fd(key, 1);
168 mixed_grads(2) = centered_mixed_fd(key, 0, 1);
169 }
170 else if (dim_ == 3)
171 {
172 mixed_grads(0) = centered_fd(key, 0);
173 mixed_grads(1) = centered_fd(key, 1);
174 mixed_grads(2) = centered_fd(key, 2);
175 mixed_grads(3) = centered_mixed_fd(key, 0, 1);
176 mixed_grads(4) = centered_mixed_fd(key, 0, 2);
177 mixed_grads(5) = centered_mixed_fd(key, 1, 2);
178 mixed_grads(6) = centered_mixed_fd_3d(key);
179 }
180 return mixed_grads;
181 };
182 auto safe_compute_grad = [this, compute_grad](const Eigen::VectorXi &key) {
183 std::string key_string;
184 Eigen::MatrixXd point;
185 setup_key(key, key_string, point);
186 {
187 std::unique_lock lock(grad_mutex_);
188 if (implicit_function_grads.count(key_string) == 0)
189 {
190 Eigen::MatrixXd grad = compute_grad(key);
191 implicit_function_grads[key_string] = grad;
192 }
193 }
194 };
195 Eigen::MatrixXd corner_point(keys.rows(), dim_);
196 for (int i = 0; i < keys.rows(); ++i)
197 {
198 std::string key_string;
199 Eigen::MatrixXd clamped_point;
200 setup_key(keys.row(i), key_string, clamped_point);
201 safe_compute_distance(clamped_point, key_string);
202 keys_string.push_back(key_string);
203 corner_point.row(i) = clamped_point.transpose();
204 safe_compute_grad(keys.row(i));
205 }
206 }
207
208 void LazyCubicInterpolator::evaluate(const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad) const
209 {
210 Eigen::MatrixXi keys;
211 build_corner_keys(point, keys);
212
213 std::vector<std::string> keys_string;
214 Eigen::MatrixXd corner_point(keys.rows(), dim_);
215 for (int i = 0; i < keys.rows(); ++i)
216 {
217 std::string key_string;
218 Eigen::MatrixXd clamped_point;
219 setup_key(keys.row(i), key_string, clamped_point);
220 keys_string.push_back(key_string);
221 corner_point.row(i) = clamped_point.transpose();
222 }
223
224 grad.setZero(dim_, 1);
225 if (dim_ == 2)
226 bicubic_interpolation(corner_point, keys_string, point, val, grad);
227 else if (dim_ == 3)
228 tricubic_interpolation(corner_point, keys_string, point, val, grad);
229
230 for (int i = 0; i < dim_; ++i)
231 if (std::isnan(grad(i)))
232 throw std::runtime_error("Nan found in gradient computation.");
233 }
234
235 void LazyCubicInterpolator::lazy_evaluate(std::function<void(const Eigen::MatrixXd &, double &)> compute_distance, const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad)
236 {
237 cache_grid(compute_distance, point);
238
239 evaluate(point, val, grad);
240 }
241
242} // namespace polyfem
double val
Definition Assembler.cpp:86
int x
void setup_key(const Eigen::VectorXi &key, std::string &key_string, Eigen::MatrixXd &clamped_point) const
void tricubic_interpolation(const Eigen::MatrixXd &corner_point, const std::vector< std::string > &keys, const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad) const
std::unordered_map< std::string, Eigen::VectorXd > implicit_function_grads
void build_corner_keys(const Eigen::MatrixXd &point, Eigen::MatrixXi &keys) const
void cache_grid(std::function< void(const Eigen::MatrixXd &, double &)> compute_distance, const Eigen::MatrixXd &point)
std::unordered_map< std::string, double > implicit_function_distance
void bicubic_interpolation(const Eigen::MatrixXd &corner_point, const std::vector< std::string > &keys, const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad) const
void lazy_evaluate(std::function< void(const Eigen::MatrixXd &, double &)> compute_distance, const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad)
void evaluate(const Eigen::MatrixXd &point, double &val, Eigen::MatrixXd &grad) const