PolyFEM
Loading...
Searching...
No Matches
Parametrizations.cpp
Go to the documentation of this file.
5#include <polyfem/Common.hpp>
7
8namespace polyfem::solver
9{
10 std::vector<std::shared_ptr<Parametrization>> ParametrizationFactory::build(const json &params, const int full_size)
11 {
12 return std::vector<std::shared_ptr<Parametrization>>();
13 }
14
15 ExponentialMap::ExponentialMap(const int from, const int to)
16 : from_(from), to_(to)
17 {
18 assert(from_ < to_ || from_ < 0);
19 }
20
21 Eigen::VectorXd ExponentialMap::inverse_eval(const Eigen::VectorXd &y)
22 {
23 if (from_ >= 0)
24 {
25 Eigen::VectorXd res = y;
26 res.segment(from_, to_ - from_) = y.segment(from_, to_ - from_).array().log();
27 return res;
28 }
29 else
30 return y.array().log();
31 }
32
33 Eigen::VectorXd ExponentialMap::eval(const Eigen::VectorXd &x) const
34 {
35 if (from_ >= 0)
36 {
37 Eigen::VectorXd y = x;
38 y.segment(from_, to_ - from_) = x.segment(from_, to_ - from_).array().exp();
39 return y;
40 }
41 else
42 return x.array().exp();
43 }
44
45 Eigen::VectorXd ExponentialMap::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
46 {
47 if (from_ >= 0)
48 {
49 Eigen::VectorXd res = grad.array();
50 res.segment(from_, to_ - from_) = x.segment(from_, to_ - from_).array().exp() * grad.segment(from_, to_ - from_).array();
51 return res;
52 }
53 else
54 return x.array().exp() * grad.array();
55 }
56
57 Scaling::Scaling(const double scale, const int from, const int to)
58 : from_(from), to_(to), scale_(scale)
59 {
60 assert(from_ < to_ || from_ < 0);
61 assert(scale_ != 0);
62 }
63
64 Eigen::VectorXd Scaling::inverse_eval(const Eigen::VectorXd &y)
65 {
66 if (from_ >= 0)
67 {
68 Eigen::VectorXd res = y;
69 res.segment(from_, to_ - from_) = y.segment(from_, to_ - from_).array() / scale_;
70 return res;
71 }
72 else
73 return y.array() / scale_;
74 }
75
76 Eigen::VectorXd Scaling::eval(const Eigen::VectorXd &x) const
77 {
78 if (from_ >= 0)
79 {
80 Eigen::VectorXd y = x;
81 y.segment(from_, to_ - from_) = x.segment(from_, to_ - from_).array() * scale_;
82 return y;
83 }
84 else
85 return x.array() * scale_;
86 }
87
88 Eigen::VectorXd Scaling::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
89 {
90 if (from_ >= 0)
91 {
92 Eigen::VectorXd res = grad.array();
93 res.segment(from_, to_ - from_) = scale_ * grad.segment(from_, to_ - from_).array();
94 return res;
95 }
96 else
97 return scale_ * grad.array();
98 }
99
100 Eigen::VectorXd PowerMap::inverse_eval(const Eigen::VectorXd &y)
101 {
102 if (from_ >= 0)
103 {
104 Eigen::VectorXd res = y;
105 res.segment(from_, to_ - from_) = y.segment(from_, to_ - from_).array().pow(1. / power_);
106 return res;
107 }
108 else
109 return y.array().pow(1. / power_);
110 }
111
112 Eigen::VectorXd PowerMap::eval(const Eigen::VectorXd &x) const
113 {
114 if (from_ >= 0)
115 {
116 Eigen::VectorXd y = x;
117 y.segment(from_, to_ - from_) = x.segment(from_, to_ - from_).array().pow(power_);
118 return y;
119 }
120 else
121 return x.array().pow(power_);
122 }
123
124 Eigen::VectorXd PowerMap::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
125 {
126 if (from_ >= 0)
127 {
128 Eigen::VectorXd res = grad;
129 res.segment(from_, to_ - from_) = grad.segment(from_, to_ - from_).array() * x.segment(from_, to_ - from_).array().pow(power_ - 1) * power_;
130 return res;
131 }
132 else
133 return grad.array() * x.array().pow(power_ - 1) * power_;
134 }
135
136 ENu2LambdaMu::ENu2LambdaMu(const bool is_volume)
137 : is_volume_(is_volume)
138 {
139 }
140
141 Eigen::VectorXd ENu2LambdaMu::inverse_eval(const Eigen::VectorXd &y)
142 {
143 const int size = y.size() / 2;
144 assert(size * 2 == y.size());
145
146 Eigen::VectorXd x(y.size());
147 for (int i = 0; i < size; i++)
148 {
149 x(i) = convert_to_E(is_volume_, y(i), y(i + size));
150 x(i + size) = convert_to_nu(is_volume_, y(i), y(i + size));
151 }
152
153 return x;
154 }
155
156 Eigen::VectorXd ENu2LambdaMu::eval(const Eigen::VectorXd &x) const
157 {
158 const int size = x.size() / 2;
159 assert(size * 2 == x.size());
160
161 Eigen::VectorXd y;
162 y.setZero(x.size());
163 for (int i = 0; i < size; i++)
164 {
165 y(i) = convert_to_lambda(is_volume_, x(i), x(i + size));
166 y(i + size) = convert_to_mu(x(i), x(i + size));
167 }
168
169 return y;
170 }
171
172 Eigen::VectorXd ENu2LambdaMu::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
173 {
174 const int size = grad.size() / 2;
175 assert(size * 2 == grad.size());
176 assert(size * 2 == x.size());
177
178 Eigen::VectorXd grad_E_nu;
179 grad_E_nu.setZero(grad.size());
180 for (int i = 0; i < size; i++)
181 {
182 const Eigen::Matrix2d jacobian = d_lambda_mu_d_E_nu(is_volume_, x(i), x(i + size));
183 grad_E_nu(i) = grad(i) * jacobian(0, 0) + grad(i + size) * jacobian(1, 0);
184 grad_E_nu(i + size) = grad(i) * jacobian(0, 1) + grad(i + size) * jacobian(1, 1);
185 }
186
187 return grad_E_nu;
188 }
189
190 PerBody2PerNode::PerBody2PerNode(const mesh::Mesh &mesh, const std::vector<basis::ElementBases> &bases, const int n_bases) : mesh_(mesh), bases_(bases), full_size_(n_bases)
191 {
192 reduced_size_ = 0;
193 std::map<int, int> body_id_map;
194 for (int e = 0; e < mesh.n_elements(); e++)
195 {
196 const int body_id = mesh.get_body_id(e);
197 if (!body_id_map.count(body_id))
198 {
199 body_id_map[body_id] = reduced_size_;
201 }
202 }
203 logger().info("{} objects found!", reduced_size_);
204
206 node_id_to_body_id_.setConstant(-1);
207 for (int e = 0; e < bases.size(); e++)
208 {
209 const int body_id = mesh_.get_body_id(e);
210 const int id = body_id_map.at(body_id);
211 for (const auto &bs : bases[e].bases)
212 {
213 for (const auto &g : bs.global())
214 {
215 if (node_id_to_body_id_(g.index) < 0)
216 node_id_to_body_id_(g.index) = id;
217 else if (node_id_to_body_id_(g.index) != id)
218 log_and_throw_adjoint_error("Same node on different bodies!");
219 }
220 }
221 }
222 }
223
224 Eigen::VectorXd PerBody2PerNode::eval(const Eigen::VectorXd &x) const
225 {
226 Eigen::VectorXd y;
227 y.setZero(size(x.size()));
228 const int dim = x.size() / reduced_size_;
229
230 for (int i = 0; i < full_size_; i++)
231 {
232 for (int d = 0; d < dim; d++)
233 {
234 y(i * dim + d) = x(node_id_to_body_id_(i) * dim + d);
235 }
236 }
237
238 return y;
239 }
240
241 int PerBody2PerNode::size(const int x_size) const
242 {
243 assert(x_size % reduced_size_ == 0);
244 return (x_size / reduced_size_) * full_size_;
245 }
246
247 Eigen::VectorXd PerBody2PerNode::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
248 {
249 assert(grad.size() == size(x.size()));
250 Eigen::VectorXd grad_body;
251 grad_body.setZero(x.size());
252 const int dim = x.size() / reduced_size_;
253
254 for (int i = 0; i < full_size_; i++)
255 {
256 for (int d = 0; d < dim; d++)
257 {
258 grad_body(node_id_to_body_id_(i) * dim + d) += grad(i * dim + d);
259 }
260 }
261
262 return grad_body;
263 }
264
265 PerBody2PerElem::PerBody2PerElem(const mesh::Mesh &mesh) : mesh_(mesh), full_size_(mesh_.n_elements())
266 {
267 reduced_size_ = 0;
268 for (int e = 0; e < mesh.n_elements(); e++)
269 {
270 const int body_id = mesh.get_body_id(e);
271 if (!body_id_map_.count(body_id))
272 {
273 body_id_map_[body_id] = {{e, reduced_size_}};
275 }
276 }
277 logger().info("{} objects found!", reduced_size_);
278 }
279
280 Eigen::VectorXd PerBody2PerElem::eval(const Eigen::VectorXd &x) const
281 {
282 Eigen::VectorXd y;
283 y.setZero(size(x.size()));
284
285 for (int e = 0; e < mesh_.n_elements(); e++)
286 {
287 const int body_id = mesh_.get_body_id(e);
288 const auto &entry = body_id_map_.at(body_id);
289 // y(e) = x(entry[1]);
290 y(Eigen::seq(e, y.size() - 1, full_size_)) = x(Eigen::seq(entry[1], x.size() - 1, reduced_size_));
291 }
292
293 return y;
294 }
295
296 int PerBody2PerElem::size(const int x_size) const
297 {
298 assert(x_size % reduced_size_ == 0);
299 return (x_size / reduced_size_) * full_size_;
300 }
301
302 Eigen::VectorXd PerBody2PerElem::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
303 {
304 assert(grad.size() == size(x.size()));
305 Eigen::VectorXd grad_body;
306 grad_body.setZero(x.size());
307
308 for (int e = 0; e < mesh_.n_elements(); e++)
309 {
310 const int body_id = mesh_.get_body_id(e);
311 const auto &entry = body_id_map_.at(body_id);
312 // grad_body(entry[1]) += grad(e);
313 grad_body(Eigen::seq(entry[1], x.size() - 1, reduced_size_)) += grad(Eigen::seq(e, grad.size() - 1, full_size_));
314 }
315
316 return grad_body;
317 }
318
319 SliceMap::SliceMap(const int from, const int to, const int total) : from_(from), to_(to), total_(total)
320 {
321 if (to_ - from_ < 0)
322 log_and_throw_adjoint_error("Invalid Slice Map input!");
323 }
324
325 Eigen::VectorXd SliceMap::inverse_eval(const Eigen::VectorXd &y)
326 {
327 if (total_ == -1)
328 return y;
329 else
330 {
331 if (y.size() != size(0))
332 log_and_throw_adjoint_error("Inverse eval on SliceMap is inconsistent in size!");
333 Eigen::VectorXd y_;
334 y_.setZero(total_);
335 y_.segment(from_, to_ - from_) = y;
336 return y_;
337 }
338 }
339
340 Eigen::VectorXd SliceMap::eval(const Eigen::VectorXd &x) const
341 {
342 return x.segment(from_, to_ - from_);
343 }
344 Eigen::VectorXd SliceMap::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
345 {
346 Eigen::VectorXd grad_full;
347 grad_full.setZero(x.size());
348 grad_full.segment(from_, to_ - from_) = grad;
349 return grad_full;
350 }
351
352 InsertConstantMap::InsertConstantMap(const int size, const double val, const int start_index) : start_index_(start_index)
353 {
354 if (size <= 0)
355 log_and_throw_adjoint_error("Invalid InsertConstantMap input!");
356 values_.setConstant(size, val);
357 }
358
359 InsertConstantMap::InsertConstantMap(const Eigen::VectorXd &values, const int start_index) : start_index_(start_index), values_(values)
360 {
361 }
362
363 int InsertConstantMap::size(const int x_size) const
364 {
365 return x_size + values_.size();
366 }
367
368 Eigen::VectorXd InsertConstantMap::inverse_eval(const Eigen::VectorXd &y)
369 {
370 if (start_index_ >= 0)
371 {
372 Eigen::VectorXd x(y.size() - values_.size());
373 if (start_index_ > 0)
374 x.head(start_index_) = y.head(start_index_);
375 x.tail(x.size() - start_index_) = y.tail(y.size() - start_index_ - values_.size());
376 return x;
377 }
378 else
379 return y.head(y.size() - values_.size());
380 }
381
382 Eigen::VectorXd InsertConstantMap::eval(const Eigen::VectorXd &x) const
383 {
384 Eigen::VectorXd y;
385 y.setZero(size(x.size()));
386 if (start_index_ >= 0)
387 {
388 if (start_index_ > 0)
389 y.head(start_index_) = x.head(start_index_);
390 y.segment(start_index_, values_.size()) = values_;
391 y.tail(y.size() - start_index_ - values_.size()) = x.tail(x.size() - start_index_);
392 }
393 else
394 y << x, values_;
395
396 return y;
397 }
398 Eigen::VectorXd InsertConstantMap::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
399 {
400 assert(x.size() == grad.size() - values_.size());
401 Eigen::VectorXd reduced_grad(grad.size() - values_.size());
402 if (start_index_ >= 0)
403 {
404 if (start_index_ > 0)
405 reduced_grad.head(start_index_) = grad.head(start_index_);
406 reduced_grad.tail(reduced_grad.size() - start_index_) = grad.tail(grad.size() - start_index_ - values_.size());
407 }
408 else
409 reduced_grad = grad.head(grad.size() - values_.size());
410
411 return reduced_grad;
412 }
413
414 LinearFilter::LinearFilter(const mesh::Mesh &mesh, const double radius)
415 {
416 std::vector<Eigen::Triplet<double>> tt_adjacency_list;
417
418 Eigen::MatrixXd barycenters;
419 if (mesh.is_volume())
420 mesh.cell_barycenters(barycenters);
421 else
422 mesh.face_barycenters(barycenters);
423
424 RowVectorNd min, max;
425 mesh.bounding_box(min, max);
426 // TODO: more efficient way
427 for (int i = 0; i < barycenters.rows(); i++)
428 {
429 auto center_i = barycenters.row(i);
430 for (int j = 0; j <= i; j++)
431 {
432 auto center_j = barycenters.row(j);
433 double dist = 0;
434 dist = (center_i - center_j).norm();
435 if (dist < radius)
436 {
437 tt_adjacency_list.emplace_back(i, j, radius - dist);
438 if (i != j)
439 tt_adjacency_list.emplace_back(j, i, radius - dist);
440 }
441 }
442 }
443 tt_radius_adjacency.resize(barycenters.rows(), barycenters.rows());
444 tt_radius_adjacency.setFromTriplets(tt_adjacency_list.begin(), tt_adjacency_list.end());
445
447 for (int i = 0; i < tt_radius_adjacency.rows(); i++)
449 }
450
451 Eigen::VectorXd LinearFilter::eval(const Eigen::VectorXd &x) const
452 {
453 assert(x.size() == tt_radius_adjacency.rows());
454 return (tt_radius_adjacency * x).array() / tt_radius_adjacency_row_sum.array();
455 }
456
457 Eigen::VectorXd LinearFilter::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
458 {
459 assert(x.size() == tt_radius_adjacency.rows());
460 return (tt_radius_adjacency * grad).array() / tt_radius_adjacency_row_sum.array();
461 }
462
463 Eigen::VectorXd ScalarVelocityParametrization::inverse_eval(const Eigen::VectorXd &y)
464 {
465 Eigen::VectorXd x;
466 x.setZero(size(y.size()));
467 x(0) = (y(0) - start_val_) / dt_;
468 for (int i = 1; i < x.size(); ++i)
469 x(i) = (y(i) - y(i - 1)) / dt_;
470 return x;
471 }
472
473 Eigen::VectorXd ScalarVelocityParametrization::eval(const Eigen::VectorXd &x) const
474 {
475 Eigen::VectorXd y;
476 y.setZero(size(x.size()));
477 y(0) = start_val_ + dt_ * x(0);
478 for (int i = 1; i < x.size(); ++i)
479 y(i) = y(i - 1) + dt_ * x(i);
480 return y;
481 }
482
483 Eigen::VectorXd ScalarVelocityParametrization::apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const
484 {
485 assert(x.size() == grad.size());
486
487 Eigen::MatrixXd hess;
488 hess.setZero(x.size(), size(x.size()));
489 for (int i = 0; i < hess.rows(); ++i)
490 for (int j = 0; j <= i; ++j)
491 hess(i, j) = dt_;
492
493 return hess.transpose() * grad;
494 }
495
496} // namespace polyfem::solver
double val
Definition Assembler.cpp:86
int y
int x
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:39
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:161
virtual int get_body_id(const int primitive) const
Get the volume selection of an element (cell in 3d, face in 2d)
Definition Mesh.hpp:501
void cell_barycenters(Eigen::MatrixXd &barycenters) const
all cells barycenters
Definition Mesh.cpp:320
virtual void bounding_box(RowVectorNd &min, RowVectorNd &max) const =0
computes the bbox of the mesh
void face_barycenters(Eigen::MatrixXd &barycenters) const
all face barycenters
Definition Mesh.cpp:311
virtual bool is_volume() const =0
checks if mesh is volume
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
int size(const int x_size) const override
ENu2LambdaMu(const bool is_volume)
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
ExponentialMap(const int from=-1, const int to=-1)
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
int size(const int x_size) const override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
InsertConstantMap(const int size=-1, const double val=0, const int start_index=-1)
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
Eigen::SparseMatrix< double > tt_radius_adjacency
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
LinearFilter(const mesh::Mesh &mesh, const double radius)
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
static std::vector< std::shared_ptr< Parametrization > > build(const json &params, const int full_size)
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
PerBody2PerElem(const mesh::Mesh &mesh)
int size(const int x_size) const override
std::map< int, std::array< int, 2 > > body_id_map_
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
int size(const int x_size) const override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
PerBody2PerNode(const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &bases, const int n_bases)
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
int size(const int x_size) const override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Scaling(const double scale, const int from=-1, const int to=-1)
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad, const Eigen::VectorXd &x) const override
SliceMap(const int from=-1, const int to=-1, const int total=-1)
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
int size(const int x_size) const override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
double convert_to_E(const bool is_volume, const double lambda, const double mu)
nlohmann::json json
Definition Common.hpp:9
double convert_to_mu(const double E, const double nu)
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:77
double convert_to_nu(const bool is_volume, const double lambda, const double mu)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
double convert_to_lambda(const bool is_volume, const double E, const double nu)
Eigen::Matrix2d d_lambda_mu_d_E_nu(const bool is_volume, const double E, const double nu)