PolyFEM
Loading...
Searching...
No Matches
ElasticForm.cpp
Go to the documentation of this file.
1#include "ElasticForm.hpp"
2
12
13using namespace polyfem::assembler;
14using namespace polyfem::utils;
15using namespace polyfem::quadrature;
16
17namespace polyfem::solver
18{
19 namespace
20 {
21 class LocalThreadVecStorage
22 {
23 public:
24 Eigen::MatrixXd vec;
27
28 LocalThreadVecStorage(const int size)
29 {
30 vec.resize(size, 1);
31 vec.setZero();
32 }
33 };
34
35 Eigen::MatrixXd refined_nodes(const int dim, const int i)
36 {
37 Eigen::MatrixXd A(dim + 1, dim);
38 if (dim == 2)
39 {
40 A << 0., 0.,
41 1., 0.,
42 0., 1.;
43 switch (i)
44 {
45 case 0:
46 break;
47 case 1:
48 A.col(0).array() += 1;
49 break;
50 case 2:
51 A.col(1).array() += 1;
52 break;
53 case 3:
54 A.array() -= 1;
55 A *= -1;
56 break;
57 default:
58 throw std::runtime_error("Invalid node index");
59 }
60 }
61 else
62 {
63 A << 0, 0, 0,
64 1, 0, 0,
65 0, 1, 0,
66 0, 0, 1;
67 switch (i)
68 {
69 case 0:
70 break;
71 case 1:
72 A.col(0).array() += 1;
73 break;
74 case 2:
75 A.col(1).array() += 1;
76 break;
77 case 3:
78 A.col(2).array() += 1;
79 break;
80 case 4:
81 {
82 Eigen::VectorXd tmp = 1 - A.col(1).array() - A.col(2).array();
83 A.col(2) += A.col(0) + A.col(1);
84 A.col(0) = tmp;
85 break;
86 }
87 case 5:
88 {
89 Eigen::VectorXd tmp = 1. - A.col(1).array();
90 A.col(2) += A.col(1);
91 A.col(1) += A.col(0);
92 A.col(0) = tmp;
93 break;
94 }
95 case 6:
96 {
97 Eigen::VectorXd tmp = A.col(0) + A.col(1);
98 A.col(1) = 1. - A.col(0).array();
99 A.col(0) = tmp;
100 break;
101 }
102 case 7:
103 {
104 Eigen::VectorXd tmp = 1. - A.col(0).array() - A.col(1).array();
105 A.col(1) += A.col(2);
106 A.col(2) = tmp;
107 break;
108 }
109 default:
110 throw std::runtime_error("Invalid node index");
111 }
112 }
113 return A / 2;
114 }
115
120 std::tuple<Eigen::MatrixXd, std::vector<int>> extract_subelement(const Eigen::MatrixXd &pts, const Tree &tree)
121 {
122 if (!tree.has_children())
123 return {pts, std::vector<int>{0}};
124
125 const int dim = pts.cols();
126 Eigen::MatrixXd out;
127 std::vector<int> levels;
128 for (int i = 0; i < tree.n_children(); i++)
129 {
130 Eigen::MatrixXd uv;
131 uv.setZero(dim+1, dim+1);
132 uv.rightCols(dim) = refined_nodes(dim, i);
133 if (dim == 2)
134 uv.col(0) = 1. - uv.col(2).array() - uv.col(1).array();
135 else
136 uv.col(0) = 1. - uv.col(3).array() - uv.col(1).array() - uv.col(2).array();
137
138 Eigen::MatrixXd pts_ = uv * pts;
139
140 auto [tmp, L] = extract_subelement(pts_, tree.child(i));
141 if (out.size() == 0)
142 out = tmp;
143 else
144 {
145 out.conservativeResize(out.rows() + tmp.rows(), Eigen::NoChange);
146 out.bottomRows(tmp.rows()) = tmp;
147 }
148 for (int &i : L)
149 ++i;
150 levels.insert(levels.end(), L.begin(), L.end());
151 }
152 return {out, levels};
153 }
154
155 quadrature::Quadrature refine_quadrature(const Tree &tree, const int dim, const int order)
156 {
157 Eigen::MatrixXd pts(dim + 1, dim);
158 if (dim == 2)
159 pts << 0., 0.,
160 1., 0.,
161 0., 1.;
162 else
163 pts << 0, 0, 0,
164 1, 0, 0,
165 0, 1, 0,
166 0, 0, 1;
167 auto [quad_points, levels] = extract_subelement(pts, tree);
168
169 Quadrature tmp, quad;
170 if (dim == 2)
171 {
172 TriQuadrature tri_quadrature(true);
173 tri_quadrature.get_quadrature(order, tmp);
174 tmp.points.conservativeResize(tmp.points.rows(), dim + 1);
175 tmp.points.col(dim) = 1. - tmp.points.col(0).array() - tmp.points.col(1).array();
176 }
177 else
178 {
179 TetQuadrature tet_quadrature(true);
180 tet_quadrature.get_quadrature(order, tmp);
181 tmp.points.conservativeResize(tmp.points.rows(), dim + 1);
182 tmp.points.col(dim) = 1. - tmp.points.col(0).array() - tmp.points.col(1).array() - tmp.points.col(2).array();
183 }
184
185 quad.points.resize(tmp.size() * levels.size(), dim);
186 quad.weights.resize(tmp.size() * levels.size());
187
188 for (int i = 0; i < levels.size(); i++)
189 {
190 quad.points.middleRows(i * tmp.size(), tmp.size()) = tmp.points * quad_points.middleRows(i * (dim + 1), dim + 1);
191 quad.weights.segment(i * tmp.size(), tmp.size()) = tmp.weights / pow(2, dim * levels[i]);
192 }
193 assert (fabs(quad.weights.sum() - tmp.weights.sum()) < 1e-8);
194
195 return quad;
196 }
197
198 // Eigen::MatrixXd evaluate_jacobian(const basis::ElementBases &bs, const basis::ElementBases &gbs, const Eigen::MatrixXd &uv, const Eigen::VectorXd &disp)
199 // {
200 // assembler::ElementAssemblyValues vals;
201 // vals.compute(0, uv.cols() == 3, uv, bs, gbs);
202
203 // Eigen::MatrixXd out(uv.rows(), 2);
204 // for (long p = 0; p < uv.rows(); ++p)
205 // {
206 // Eigen::MatrixXd disp_grad;
207 // disp_grad.setZero(uv.cols(), uv.cols());
208
209 // for (std::size_t j = 0; j < vals.basis_values.size(); ++j)
210 // {
211 // const auto &loc_val = vals.basis_values[j];
212
213 // for (int d = 0; d < uv.cols(); ++d)
214 // {
215 // for (std::size_t ii = 0; ii < loc_val.global.size(); ++ii)
216 // {
217 // disp_grad.row(d) += loc_val.global[ii].val * loc_val.grad.row(p) * disp(loc_val.global[ii].index * uv.cols() + d);
218 // }
219 // }
220 // }
221
222 // disp_grad = disp_grad * vals.jac_it[p] + Eigen::MatrixXd::Identity(uv.cols(), uv.cols());
223 // out.row(p) << disp_grad.determinant(), disp_grad.determinant() / vals.jac_it[p].determinant();
224 // }
225 // return out;
226 // }
227
228 void update_quadrature(const int invalidID, const int dim, Tree &tree, const int quad_order, basis::ElementBases &bs, const basis::ElementBases &gbs, assembler::AssemblyValsCache &ass_vals_cache)
229 {
230 // update quadrature to capture the point with negative jacobian
231 const Quadrature quad = refine_quadrature(tree, dim, quad_order);
232
233 // capture the flipped point by refining the quadrature
234 bs.set_quadrature([quad](Quadrature &quad_) {
235 quad_ = quad;
236 });
237 logger().debug("New number of quadrature points: {}, level: {}", quad.size(), tree.depth());
238
239 if (ass_vals_cache.is_initialized())
240 ass_vals_cache.update(invalidID, dim == 3, bs, gbs);
241 }
242 } // namespace
243
244 ElasticForm::ElasticForm(const int n_bases,
245 std::vector<basis::ElementBases> &bases,
246 const std::vector<basis::ElementBases> &geom_bases,
247 const assembler::Assembler &assembler,
248 assembler::AssemblyValsCache &ass_vals_cache,
249 const double t, const double dt,
250 const bool is_volume,
251 const double jacobian_threshold,
252 const ElementInversionCheck check_inversion)
253 : n_bases_(n_bases),
254 bases_(bases),
255 geom_bases_(geom_bases),
256 assembler_(assembler),
257 ass_vals_cache_(ass_vals_cache),
258 t_(t),
259 jacobian_threshold_(jacobian_threshold),
260 check_inversion_(check_inversion),
261 dt_(dt),
262 is_volume_(is_volume)
263 {
264 if (assembler_.is_linear())
265 compute_cached_stiffness();
266 // mat_cache_ = std::make_unique<utils::DenseMatrixCache>();
267 mat_cache_ = std::make_unique<utils::SparseMatrixCache>();
268 quadrature_hierarchy_.resize(bases_.size());
269
270 quadrature_order_ = AssemblerUtils::quadrature_order(assembler_.name(), bases_[0].bases[0].order(), AssemblerUtils::BasisType::SIMPLEX_LAGRANGE, is_volume_ ? 3 : 2);
271
272 if (check_inversion_ != ElementInversionCheck::Discrete)
273 {
274 Eigen::VectorXd x0;
275 x0.setZero(n_bases_ * (is_volume_ ? 3 : 2));
276 if (!is_step_collision_free(x0, x0))
277 log_and_throw_error("Initial state has inverted elements!");
278
279 int basis_order = 0;
280 int gbasis_order = 0;
281 for (int e = 0; e < bases_.size(); e++)
282 {
283 if (basis_order == 0)
284 basis_order = bases_[e].bases.front().order();
285 else if (basis_order != bases_[e].bases.front().order())
286 log_and_throw_error("Non-uniform basis order not supported for conservative Jacobian check!!");
287 if (gbasis_order == 0)
288 gbasis_order = geom_bases_[e].bases.front().order();
289 else if (gbasis_order != geom_bases_[e].bases.front().order())
290 log_and_throw_error("Non-uniform gbasis order not supported for conservative Jacobian check!!");
291 }
292 }
293 }
294
295 double ElasticForm::value_unweighted(const Eigen::VectorXd &x) const
296 {
297 return assembler_.assemble_energy(
298 is_volume_,
299 bases_, geom_bases_, ass_vals_cache_, t_, dt_, x, x_prev_);
300 }
301
302 Eigen::VectorXd ElasticForm::value_per_element_unweighted(const Eigen::VectorXd &x) const
303 {
304 const Eigen::VectorXd out = assembler_.assemble_energy_per_element(
305 is_volume_, bases_, geom_bases_, ass_vals_cache_, t_, dt_, x, x_prev_);
306 assert(abs(out.sum() - value_unweighted(x)) < std::max(1e-10 * out.sum(), 1e-10));
307 return out;
308 }
309
310 void ElasticForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
311 {
312 Eigen::MatrixXd grad;
313 assembler_.assemble_gradient(is_volume_, n_bases_, bases_, geom_bases_,
314 ass_vals_cache_, t_, dt_, x, x_prev_, grad);
315 gradv = grad;
316 }
317
318 void ElasticForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
319 {
320 POLYFEM_SCOPED_TIMER("elastic hessian");
321
322 hessian.resize(x.size(), x.size());
323
324 if (assembler_.is_linear())
325 {
326 assert(cached_stiffness_.rows() == x.size() && cached_stiffness_.cols() == x.size());
327 hessian = cached_stiffness_;
328 }
329 else
330 {
331 // NOTE: mat_cache_ is marked as mutable so we can modify it here
332 assembler_.assemble_hessian(
333 is_volume_, n_bases_, project_to_psd_, bases_,
334 geom_bases_, ass_vals_cache_, t_, dt_, x, x_prev_, *mat_cache_, hessian);
335 }
336 }
337
338 void ElasticForm::finish()
339 {
340 for (auto &t : quadrature_hierarchy_)
341 t = Tree();
342 }
343
344 double ElasticForm::max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
345 {
346 if (check_inversion_ == ElementInversionCheck::Discrete)
347 return 1.;
348
349 const int dim = is_volume_ ? 3 : 2;
350 double step, invalidStep;
351 int invalidID;
352
353 Tree subdivision_tree;
354 {
355 double transient_check_time = 0;
356 {
357 POLYFEM_SCOPED_TIMER("Transient Jacobian Check", transient_check_time);
358 std::tie(step, invalidID, invalidStep, subdivision_tree) = max_time_step(dim, bases_, geom_bases_, x0, x1);
359 }
360
361 logger().log(step == 0 ? spdlog::level::warn : (step == 1. ? spdlog::level::trace : spdlog::level::debug),
362 "Jacobian max step size: {} at element {}, invalid step size: {}, tree depth {}, runtime {} sec", step, invalidID, invalidStep, subdivision_tree.depth(), transient_check_time);
363 }
364
365 if (invalidID >= 0 && step <= 0.5)
366 {
367 auto& bs = bases_[invalidID];
368 auto& gbs = geom_bases_[invalidID];
369 if (quadrature_hierarchy_[invalidID].merge(subdivision_tree)) // if the tree is refined
370 update_quadrature(invalidID, dim, quadrature_hierarchy_[invalidID], quadrature_order_, bs, gbs, ass_vals_cache_);
371
372 // verify that new quadrature points don't make x0 invalid
373 // {
374 // Quadrature quad;
375 // bs.compute_quadrature(quad);
376 // const Eigen::MatrixXd jacs0 = evaluate_jacobian(bs, gbs, quad.points, x0);
377 // const Eigen::MatrixXd jacs1 = evaluate_jacobian(bs, gbs, quad.points, x0 + (x1 - x0) * step);
378 // const Eigen::VectorXd min_jac0 = jacs0.colwise().minCoeff();
379 // const Eigen::VectorXd min_jac1 = jacs1.colwise().minCoeff();
380 // logger().debug("Min jacobian on quadrature points: before step {}, {}; after step {}, {}", min_jac0(0), min_jac0(1), min_jac1(0), min_jac1(1));
381 // }
382 }
383
384 return step;
385 }
386
387 bool ElasticForm::is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
388 {
389 if (check_inversion_ == ElementInversionCheck::Discrete)
390 return true;
391
392 const auto [isvalid, id, tree] = is_valid(is_volume_ ? 3 : 2, bases_, geom_bases_, x1);
393 return isvalid;
394 }
395
396 bool ElasticForm::is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
397 {
398 // check inversion on quadrature points
399 Eigen::VectorXd grad;
400 first_derivative(x1, grad);
401 if (grad.array().isNaN().any())
402 return false;
403
404 return true;
405
406 // Check the scalar field in the output does not contain NANs.
407 // WARNING: Does not work because the energy is not evaluated at the same quadrature points.
408 // This causes small step lengths in the LS.
409 // TVector x1_full;
410 // reduced_to_full(x1, x1_full);
411 // return state_.check_scalar_value(x1_full, true, false);
412 // return true;
413 }
414
415 void ElasticForm::solution_changed(const Eigen::VectorXd &new_x)
416 {
417 }
418
419 void ElasticForm::compute_cached_stiffness()
420 {
421 if (assembler_.is_linear() && cached_stiffness_.size() == 0)
422 {
423 assembler_.assemble(is_volume_, n_bases_, bases_, geom_bases_,
424 ass_vals_cache_, t_, cached_stiffness_);
425 }
426 }
427
428 void ElasticForm::force_material_derivative(const double t, const Eigen::MatrixXd &x, const Eigen::MatrixXd &x_prev, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &term)
429 {
430 const int dim = is_volume_ ? 3 : 2;
431
432 const int n_elements = int(bases_.size());
433
434 if (assembler_.name() == "ViscousDamping")
435 {
436 term.setZero(2);
437
438 auto storage = utils::create_thread_storage(LocalThreadVecStorage(term.size()));
439
440 utils::maybe_parallel_for(n_elements, [&](int start, int end, int thread_id) {
441 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
442
443 for (int e = start; e < end; ++e)
444 {
445 assembler::ElementAssemblyValues &vals = local_storage.vals;
446 ass_vals_cache_.compute(e, is_volume_, bases_[e], geom_bases_[e], vals);
447
448 const quadrature::Quadrature &quadrature = vals.quadrature;
449 local_storage.da = vals.det.array() * quadrature.weights.array();
450
451 Eigen::MatrixXd u, grad_u, prev_u, prev_grad_u, p, grad_p;
452 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, x, u, grad_u);
453 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, x_prev, prev_u, prev_grad_u);
454 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, adjoint, p, grad_p);
455
456 for (int q = 0; q < local_storage.da.size(); ++q)
457 {
458 Eigen::MatrixXd grad_p_i, grad_u_i, prev_grad_u_i;
459 vector2matrix(grad_p.row(q), grad_p_i);
460 vector2matrix(grad_u.row(q), grad_u_i);
461 vector2matrix(prev_grad_u.row(q), prev_grad_u_i);
462
463 Eigen::MatrixXd f_prime_dpsi, f_prime_dphi;
464 assembler::ViscousDamping::compute_dstress_dpsi_dphi(OptAssemblerData(t, dt_, e, quadrature.points.row(q), vals.val.row(q), grad_u_i), prev_grad_u_i, f_prime_dpsi, f_prime_dphi);
465
466 // This needs to be a sum over material parameter basis.
467 local_storage.vec(0) += -matrix_inner_product<double>(f_prime_dpsi, grad_p_i) * local_storage.da(q);
468 local_storage.vec(1) += -matrix_inner_product<double>(f_prime_dphi, grad_p_i) * local_storage.da(q);
469 }
470 }
471 });
472
473 for (const LocalThreadVecStorage &local_storage : storage)
474 term += local_storage.vec;
475 }
476 else
477 {
478 term.setZero(n_elements * 2, 1);
479
480 auto storage = utils::create_thread_storage(LocalThreadVecStorage(term.size()));
481
482 utils::maybe_parallel_for(n_elements, [&](int start, int end, int thread_id) {
483 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
484
485 for (int e = start; e < end; ++e)
486 {
487 assembler::ElementAssemblyValues &vals = local_storage.vals;
488 ass_vals_cache_.compute(e, is_volume_, bases_[e], geom_bases_[e], vals);
489
490 const quadrature::Quadrature &quadrature = vals.quadrature;
491 local_storage.da = vals.det.array() * quadrature.weights.array();
492
493 Eigen::MatrixXd u, grad_u, p, grad_p;
494 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, x, u, grad_u);
495 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, adjoint, p, grad_p);
496
497 for (int q = 0; q < local_storage.da.size(); ++q)
498 {
499 Eigen::MatrixXd grad_p_i, grad_u_i;
500 vector2matrix(grad_p.row(q), grad_p_i);
501 vector2matrix(grad_u.row(q), grad_u_i);
502
503 Eigen::MatrixXd f_prime_dmu, f_prime_dlambda;
504 assembler_.compute_dstress_dmu_dlambda(OptAssemblerData(t, dt_, e, quadrature.points.row(q), vals.val.row(q), grad_u_i), f_prime_dmu, f_prime_dlambda);
505
506 // This needs to be a sum over material parameter basis.
507 local_storage.vec(e + n_elements) += -matrix_inner_product<double>(f_prime_dmu, grad_p_i) * local_storage.da(q);
508 local_storage.vec(e) += -matrix_inner_product<double>(f_prime_dlambda, grad_p_i) * local_storage.da(q);
509 }
510 }
511 });
512
513 for (const LocalThreadVecStorage &local_storage : storage)
514 term += local_storage.vec;
515 }
516 }
517
518 void ElasticForm::force_shape_derivative(const double t, const int n_verts, const Eigen::MatrixXd &x, const Eigen::MatrixXd &x_prev, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &term)
519 {
520 const int dim = is_volume_ ? 3 : 2;
521 const int actual_dim = (assembler_.name() == "Laplacian") ? 1 : dim;
522
523 const int n_elements = int(bases_.size());
524 term.setZero(n_verts * dim, 1);
525
526 auto storage = utils::create_thread_storage(LocalThreadVecStorage(term.size()));
527
528 if (assembler_.name() == "ViscousDamping")
529 {
530 utils::maybe_parallel_for(n_elements, [&](int start, int end, int thread_id) {
531 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
532
533 for (int e = start; e < end; ++e)
534 {
535 assembler::ElementAssemblyValues &vals = local_storage.vals;
536 ass_vals_cache_.compute(e, is_volume_, bases_[e], geom_bases_[e], vals);
538 gvals.compute(e, is_volume_, vals.quadrature.points, geom_bases_[e], geom_bases_[e]);
539
540 const quadrature::Quadrature &quadrature = vals.quadrature;
541 local_storage.da = vals.det.array() * quadrature.weights.array();
542
543 Eigen::MatrixXd u, grad_u, prev_u, prev_grad_u, p, grad_p;
544 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, x, u, grad_u);
545 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, x_prev, prev_u, prev_grad_u);
546 io::Evaluator::interpolate_at_local_vals(e, dim, dim, vals, adjoint, p, grad_p);
547
548 Eigen::MatrixXd grad_u_i, grad_p_i, prev_grad_u_i;
549 Eigen::MatrixXd grad_v_i;
550 Eigen::MatrixXd stress_tensor, f_prime_gradu_gradv;
551 Eigen::MatrixXd f_prev_prime_prev_gradu_gradv;
552
553 for (int q = 0; q < local_storage.da.size(); ++q)
554 {
555 vector2matrix(grad_u.row(q), grad_u_i);
556 vector2matrix(grad_p.row(q), grad_p_i);
557 vector2matrix(prev_grad_u.row(q), prev_grad_u_i);
558
559 for (auto &v : gvals.basis_values)
560 {
561 Eigen::MatrixXd stress_grad, stress_prev_grad;
562 assembler_.compute_stress_grad(OptAssemblerData(t, dt_, e, quadrature.points.row(q), vals.val.row(q), grad_u_i), prev_grad_u_i, stress_tensor, stress_grad);
563 assembler_.compute_stress_prev_grad(OptAssemblerData(t, dt_, e, quadrature.points.row(q), vals.val.row(q), grad_u_i), prev_grad_u_i, stress_prev_grad);
564 for (int d = 0; d < dim; d++)
565 {
566 grad_v_i.setZero(dim, dim);
567 grad_v_i.row(d) = v.grad_t_m.row(q);
568
569 f_prime_gradu_gradv.setZero(dim, dim);
570 Eigen::MatrixXd tmp = grad_u_i * grad_v_i;
571 for (int i = 0; i < f_prime_gradu_gradv.rows(); i++)
572 for (int j = 0; j < f_prime_gradu_gradv.cols(); j++)
573 for (int k = 0; k < tmp.rows(); k++)
574 for (int l = 0; l < tmp.cols(); l++)
575 f_prime_gradu_gradv(i, j) += stress_grad(i * dim + j, k * dim + l) * tmp(k, l);
576
577 f_prev_prime_prev_gradu_gradv.setZero(dim, dim);
578 tmp = prev_grad_u_i * grad_v_i;
579 for (int i = 0; i < f_prev_prime_prev_gradu_gradv.rows(); i++)
580 for (int j = 0; j < f_prev_prime_prev_gradu_gradv.cols(); j++)
581 for (int k = 0; k < tmp.rows(); k++)
582 for (int l = 0; l < tmp.cols(); l++)
583 f_prev_prime_prev_gradu_gradv(i, j) += stress_prev_grad(i * dim + j, k * dim + l) * tmp(k, l);
584
585 tmp = grad_v_i - grad_v_i.trace() * Eigen::MatrixXd::Identity(dim, dim);
586 local_storage.vec(v.global[0].index * dim + d) -= matrix_inner_product<double>(f_prime_gradu_gradv + f_prev_prime_prev_gradu_gradv + stress_tensor * tmp.transpose(), grad_p_i) * local_storage.da(q);
587 }
588 }
589 }
590 }
591 });
592 }
593 else
594 {
595 utils::maybe_parallel_for(n_elements, [&](int start, int end, int thread_id) {
596 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
597
598 for (int e = start; e < end; ++e)
599 {
600 assembler::ElementAssemblyValues &vals = local_storage.vals;
601 ass_vals_cache_.compute(e, is_volume_, bases_[e], geom_bases_[e], vals);
603 gvals.compute(e, is_volume_, vals.quadrature.points, geom_bases_[e], geom_bases_[e]);
604
605 const quadrature::Quadrature &quadrature = vals.quadrature;
606 local_storage.da = vals.det.array() * quadrature.weights.array();
607
608 Eigen::MatrixXd u, grad_u, p, grad_p; //, stiffnesses;
609 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, x, u, grad_u);
610 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, adjoint, p, grad_p);
611 // assembler_.compute_stiffness_value(formulation_, vals, quadrature.points, x, stiffnesses);
612
613 for (int q = 0; q < local_storage.da.size(); ++q)
614 {
615 Eigen::MatrixXd grad_u_i, grad_p_i, stiffness_i;
616 if (actual_dim == 1)
617 {
618 grad_u_i = grad_u.row(q);
619 grad_p_i = grad_p.row(q);
620 }
621 else
622 {
623 vector2matrix(grad_u.row(q), grad_u_i);
624 vector2matrix(grad_p.row(q), grad_p_i);
625 }
626
627 // stiffness_i = utils::unflatten(stiffnesses.row(q).transpose(), actual_dim * dim);
628
629 for (auto &v : gvals.basis_values)
630 {
631 for (int d = 0; d < dim; d++)
632 {
633 Eigen::MatrixXd grad_v_i;
634 grad_v_i.setZero(dim, dim);
635 grad_v_i.row(d) = v.grad_t_m.row(q);
636
637 Eigen::MatrixXd stress_tensor, f_prime_gradu_gradv;
638 assembler_.compute_stress_grad_multiply_mat(OptAssemblerData(t, dt_, e, quadrature.points.row(q), vals.val.row(q), grad_u_i), grad_u_i * grad_v_i, stress_tensor, f_prime_gradu_gradv);
639 // f_prime_gradu_gradv = utils::unflatten(stiffness_i * utils::flatten(grad_u_i * grad_v_i), dim);
640
641 Eigen::MatrixXd tmp = grad_v_i - grad_v_i.trace() * Eigen::MatrixXd::Identity(dim, dim);
642 local_storage.vec(v.global[0].index * dim + d) -= matrix_inner_product<double>(f_prime_gradu_gradv + stress_tensor * tmp.transpose(), grad_p_i) * local_storage.da(q);
643 }
644 }
645 }
646 }
647 });
648 }
649
650 for (const LocalThreadVecStorage &local_storage : storage)
651 term += local_storage.vec;
652 }
653} // namespace polyfem::solver
Eigen::MatrixXd vec
Definition Assembler.cpp:72
QuadratureVector da
Definition Assembler.cpp:23
ElementAssemblyValues vals
Definition Assembler.cpp:22
assembler::ElementAssemblyValues gvals
Definition BodyForm.cpp:25
Eigen::MatrixXd vec
assembler::ElementAssemblyValues vals
Quadrature quadrature
int x
#define POLYFEM_SCOPED_TIMER(...)
Definition Timer.hpp:10
static int quadrature_order(const std::string &assembler, const int basis_degree, const BasisType &b_type, const int dim)
utility for retrieving the needed quadrature order to precisely integrate the given form on the given...
Caches basis evaluation and geometric mapping at every element.
void update(const int el_index, const bool is_volume, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
stores per element basis values at given quadrature points and geometric mapping
void compute(const int el_index, const bool is_volume, const Eigen::MatrixXd &pts, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
computes the per element values at the local (ref el) points (pts) sets basis_values,...
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
void set_quadrature(const QuadratureFunction &fun)
int depth() const
Definition Jacobian.hpp:61
int n_children() const
Definition Jacobian.hpp:60
bool has_children() const
Definition Jacobian.hpp:59
Tree & child(int i)
Definition Jacobian.hpp:77
list tmp
Definition p_bases.py:339
Used for test only.
std::tuple< bool, int, Tree > is_valid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const double threshold)
Definition Jacobian.cpp:241
void vector2matrix(const Eigen::VectorXd &vec, Eigen::MatrixXd &mat)
std::tuple< double, int, double, Tree > max_time_step(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u1, const Eigen::VectorXd &u2, double precision)
Definition Jacobian.cpp:345
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, MAX_QUAD_POINTS, 1 > QuadratureVector
Definition Types.hpp:17
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:22