91 const Eigen::MatrixXd &displacement,
92 const std::vector<mesh::LocalBoundary> &local_boundary,
95 const bool multiply_pressure)
const
102 LocalThreadScalarStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
104 Eigen::MatrixXd pressure_vals, g_3;
105 ElementAssemblyValues vals;
106 Eigen::MatrixXd points, uv, normals, deform_mat, trafo;
107 Eigen::VectorXd weights;
108 Eigen::VectorXi global_primitive_ids;
109 for (int lb_id = start; lb_id < end; ++lb_id)
111 const auto &lb = local_boundary[lb_id];
112 const int e = lb.element_id();
113 const basis::ElementBases &gbs = gbases_[e];
114 const basis::ElementBases &bs = bases_[e];
116 for (int i = 0; i < lb.size(); ++i)
118 const int primitive_global_id = lb.global_primitive_id(i);
119 const auto nodes = bs.local_nodes_for_primitive(primitive_global_id, mesh_);
121 bool has_samples = utils::BoundarySampler::boundary_quadrature(lb, resolution, mesh_, i, false, uv, points, normals, weights);
122 if (mesh_.is_volume())
123 weights /= 2 * mesh_.tri_area(primitive_global_id);
125 weights /= mesh_.edge_length(primitive_global_id);
126 g_3.setZero(normals.rows(), normals.cols());
131 global_primitive_ids.setConstant(weights.size(), primitive_global_id);
133 vals.compute(e, mesh_.is_volume(), points, bs, gbs);
135 for (int n = 0; n < vals.jac_it.size(); ++n)
137 trafo = vals.jac_it[n].inverse();
139 if (displacement.size() > 0)
141 assert(size_ == 2 || size_ == 3);
142 deform_mat.resize(size_, size_);
143 deform_mat.setZero();
144 for (const auto &b : vals.basis_values)
146 for (const auto &g : b.global)
148 for (int d = 0; d < size_; ++d)
150 deform_mat.row(d) += displacement(g.index * size_ + d) * b.grad.row(n);
158 normals.row(n) = normals.row(n) * trafo.inverse();
159 normals.row(n).normalize();
161 if (mesh_.is_volume())
163 Eigen::Vector3d g1, g2, g3;
164 auto endpoints = utils::BoundarySampler::tet_local_node_coordinates_from_face(lb[i]);
165 g1 = trafo * (endpoints.row(0) - endpoints.row(1)).transpose();
166 g2 = trafo * (endpoints.row(0) - endpoints.row(2)).transpose();
170 g_3.row(n) = g3.transpose();
174 Eigen::Vector2d g1, g3;
175 auto endpoints = utils::BoundarySampler::tri_local_node_coordinates_from_edge(lb[i]);
176 g1 = trafo * (endpoints.row(0) - endpoints.row(1)).transpose();
179 g_3.row(n) = g3.transpose();
183 if (multiply_pressure)
184 problem_.pressure_bc(mesh_, global_primitive_ids, uv, vals.val, normals, t, pressure_vals);
186 pressure_vals = Eigen::MatrixXd::Ones(weights.size(), 1);
188 Eigen::MatrixXd u, grad_u;
189 if (displacement.size() > 0)
190 io::Evaluator::interpolate_at_local_vals(mesh_, problem_.is_scalar(), bases_, gbases_, e, points, displacement, u, grad_u);
192 u.setZero(weights.size(), size_);
195 for (long p = 0; p < weights.size(); ++p)
196 for (int d = 0; d < size_; ++d)
197 local_storage.val += pressure_vals(p) * g_3(p, d) * u(p, d) * weights(p);
202 for (
const LocalThreadScalarStorage &local_storage : storage)
203 res += local_storage.
val;
211 const Eigen::MatrixXd &displacement,
212 const std::vector<mesh::LocalBoundary> &local_boundary,
213 const std::vector<int> &dirichlet_nodes,
214 const int resolution,
215 Eigen::VectorXd &grad,
217 const bool multiply_pressure)
const
224 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
226 Eigen::MatrixXd pressure_vals, g_3;
227 ElementAssemblyValues vals;
228 Eigen::MatrixXd points, uv, normals, deform_mat, trafo;
229 Eigen::VectorXd weights;
230 Eigen::VectorXi global_primitive_ids;
231 for (int lb_id = start; lb_id < end; ++lb_id)
233 const auto &lb = local_boundary[lb_id];
234 const int e = lb.element_id();
235 const basis::ElementBases &gbs = gbases_[e];
236 const basis::ElementBases &bs = bases_[e];
238 for (int i = 0; i < lb.size(); ++i)
240 const int primitive_global_id = lb.global_primitive_id(i);
241 const auto nodes = bs.local_nodes_for_primitive(primitive_global_id, mesh_);
243 bool has_samples = utils::BoundarySampler::boundary_quadrature(lb, resolution, mesh_, i, false, uv, points, normals, weights);
244 if (mesh_.is_volume())
245 weights /= 2 * mesh_.tri_area(primitive_global_id);
247 weights /= mesh_.edge_length(primitive_global_id);
248 g_3.setZero(normals.rows(), normals.cols());
253 global_primitive_ids.setConstant(weights.size(), primitive_global_id);
255 vals.compute(e, mesh_.is_volume(), points, bs, gbs);
256 for (int n = 0; n < vals.jac_it.size(); ++n)
258 trafo = vals.jac_it[n].inverse();
260 if (displacement.size() > 0)
262 assert(size_ == 2 || size_ == 3);
263 deform_mat.resize(size_, size_);
264 deform_mat.setZero();
265 for (const auto &b : vals.basis_values)
267 for (const auto &g : b.global)
269 for (int d = 0; d < size_; ++d)
271 deform_mat.row(d) += displacement(g.index * size_ + d) * b.grad.row(n);
279 normals.row(n) = normals.row(n) * trafo.inverse();
280 normals.row(n).normalize();
282 if (mesh_.is_volume())
284 Eigen::Vector3d g1, g2, g3;
285 auto endpoints = utils::BoundarySampler::tet_local_node_coordinates_from_face(lb[i]);
286 g1 = trafo * (endpoints.row(0) - endpoints.row(1)).transpose();
287 g2 = trafo * (endpoints.row(0) - endpoints.row(2)).transpose();
291 g_3.row(n) = g3.transpose();
295 Eigen::Vector2d g1, g3;
296 auto endpoints = utils::BoundarySampler::tri_local_node_coordinates_from_edge(lb[i]);
297 g1 = trafo * (endpoints.row(0) - endpoints.row(1)).transpose();
300 g_3.row(n) = g3.transpose();
304 if (multiply_pressure)
305 problem_.pressure_bc(mesh_, global_primitive_ids, uv, vals.val, normals, t, pressure_vals);
307 pressure_vals = Eigen::MatrixXd::Ones(weights.size(), 1);
309 for (long n = 0; n < nodes.size(); ++n)
311 const AssemblyValues &v = vals.basis_values[nodes(n)];
312 for (int d = 0; d < size_; ++d)
314 for (size_t g = 0; g < v.global.size(); ++g)
316 const int g_index = v.global[g].index * size_ + d;
317 const bool is_dof_dirichlet = std::find(dirichlet_nodes.begin(), dirichlet_nodes.end(), g_index) != dirichlet_nodes.end();
318 if (is_dof_dirichlet)
321 for (long p = 0; p < weights.size(); ++p)
323 local_storage.vec(g_index) += pressure_vals(p) * g_3(p, d) * v.val(p) * weights(p);
331 for (
const LocalThreadVecStorage &local_storage : storage)
332 grad += local_storage.
vec;
336 const Eigen::MatrixXd &displacement,
337 const std::vector<mesh::LocalBoundary> &local_boundary,
338 const std::vector<int> &dirichlet_nodes,
339 const int resolution,
342 const bool multiply_pressure)
const
349 LocalThreadMatStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
351 Eigen::MatrixXd pressure_vals, g_1, g_2, g_3, local_hessian;
352 ElementAssemblyValues vals;
353 Eigen::MatrixXd points, uv, normals, deform_mat, trafo;
354 Eigen::VectorXd weights;
355 Eigen::VectorXi global_primitive_ids;
356 for (int lb_id = start; lb_id < end; ++lb_id)
358 const auto &lb = local_boundary[lb_id];
359 const int e = lb.element_id();
360 const basis::ElementBases &gbs = gbases_[e];
361 const basis::ElementBases &bs = bases_[e];
363 for (int i = 0; i < lb.size(); ++i)
365 const int primitive_global_id = lb.global_primitive_id(i);
366 const auto nodes = bs.local_nodes_for_primitive(primitive_global_id, mesh_);
368 bool has_samples = utils::BoundarySampler::boundary_quadrature(lb, resolution, mesh_, i, false, uv, points, normals, weights);
369 std::vector<Eigen::VectorXd> param_chain_rule;
370 if (mesh_.is_volume())
372 weights /= 2 * mesh_.tri_area(primitive_global_id);
373 g_1.setZero(normals.rows(), normals.cols());
374 g_2.setZero(normals.rows(), normals.cols());
375 g_3.setZero(normals.rows(), normals.cols());
377 auto endpoints = utils::BoundarySampler::tet_local_node_coordinates_from_face(lb[i]);
378 param_chain_rule = {(endpoints.row(0) - endpoints.row(1)).transpose(), (endpoints.row(0) - endpoints.row(2)).transpose()};
380 param_chain_rule[0] *= -1;
388 global_primitive_ids.setConstant(weights.size(), primitive_global_id);
390 vals.compute(e, mesh_.is_volume(), points, bs, gbs);
391 for (int n = 0; n < vals.jac_it.size(); ++n)
393 trafo = vals.jac_it[n].inverse();
395 if (displacement.size() > 0)
398 deform_mat.resize(size_, size_);
399 deform_mat.setZero();
400 for (const auto &b : vals.basis_values)
402 for (const auto &g : b.global)
404 for (int d = 0; d < size_; ++d)
406 deform_mat.row(d) += displacement(g.index * size_ + d) * b.grad.row(n);
414 normals.row(n) = normals.row(n) * trafo.inverse();
415 normals.row(n).normalize();
417 if (mesh_.is_volume())
419 Eigen::Vector3d g1, g2, g3;
420 auto endpoints = utils::BoundarySampler::tet_local_node_coordinates_from_face(lb[i]);
421 g1 = trafo * (endpoints.row(0) - endpoints.row(1)).transpose();
422 g2 = trafo * (endpoints.row(0) - endpoints.row(2)).transpose();
427 g_1.row(n) = g1.transpose();
428 g_2.row(n) = g2.transpose();
429 g_3.row(n) = g3.transpose();
435 if (multiply_pressure)
436 problem_.pressure_bc(mesh_, global_primitive_ids, uv, vals.val, normals, t, pressure_vals);
438 pressure_vals = Eigen::MatrixXd::Ones(weights.size(), 1);
440 local_hessian.setZero(vals.basis_values.size() * size_, vals.basis_values.size() * size_);
442 for (long p = 0; p < weights.size(); ++p)
444 Eigen::Vector3d g_up_1, g_up_2;
445 g_dual(g_1.row(p).transpose(), g_2.row(p).transpose(), g_up_1, g_up_2);
446 std::vector<Eigen::MatrixXd> g_3_wedge_g_up = {wedge_product(g_3.row(p), g_up_1), wedge_product(g_3.row(p), g_up_2)};
448 for (long ni = 0; ni < nodes.size(); ++ni)
450 const AssemblyValues &vi = vals.basis_values[nodes(ni)];
451 for (int di = 0; di < size_; ++di)
453 const int gi_index = vi.global[0].index * size_ + di;
454 const bool is_dof_i_dirichlet = std::find(dirichlet_nodes.begin(), dirichlet_nodes.end(), gi_index) != dirichlet_nodes.end();
455 if (is_dof_i_dirichlet)
458 Eigen::MatrixXd grad_phi_i;
459 grad_phi_i.setZero(3, 3);
460 grad_phi_i.row(di) = vi.grad.row(p);
462 for (long nj = 0; nj < nodes.size(); ++nj)
464 const AssemblyValues &vj = vals.basis_values[nodes(nj)];
465 for (int dj = 0; dj < size_; ++dj)
467 const int gj_index = vj.global[0].index * size_ + dj;
468 const bool is_dof_j_dirichlet = std::find(dirichlet_nodes.begin(), dirichlet_nodes.end(), gj_index) != dirichlet_nodes.end();
469 if (is_dof_j_dirichlet)
472 Eigen::MatrixXd grad_phi_j;
473 grad_phi_j.setZero(3, 3);
474 grad_phi_j.row(dj) = vj.grad.row(p);
477 for (int alpha = 0; alpha < size_ - 1; ++alpha)
479 auto a = vj.val(p) * g_3_wedge_g_up[alpha].row(di) * (grad_phi_i * param_chain_rule[alpha]);
480 auto b = (g_3_wedge_g_up[alpha] * (grad_phi_j * param_chain_rule[alpha])).row(di) * vi.val(p);
481 value += pressure_vals(p) * (a(0) + b(0)) * weights(p);
483 local_hessian(nodes(ni) * size_ + di, nodes(nj) * size_ + dj) += value;
490 for (long ni = 0; ni < nodes.size(); ++ni)
492 const AssemblyValues &vi = vals.basis_values[nodes(ni)];
493 for (int di = 0; di < size_; ++di)
495 const int gi_index = vi.global[0].index * size_ + di;
496 for (long nj = 0; nj < nodes.size(); ++nj)
498 const AssemblyValues &vj = vals.basis_values[nodes(nj)];
499 for (int dj = 0; dj < size_; ++dj)
501 const int gj_index = vj.global[0].index * size_ + dj;
503 local_storage.entries.push_back(Eigen::Triplet<double>(gi_index, gj_index, local_hessian(nodes(ni) * size_ + di, nodes(nj) * size_ + dj)));
512 std::vector<Eigen::Triplet<double>> all_entries;
514 for (LocalThreadMatStorage &local_storage : storage)
516 all_entries.insert(all_entries.end(), local_storage.entries.begin(), local_storage.entries.end());
519 hess.setFromTriplets(all_entries.begin(), all_entries.end());
523 const Eigen::MatrixXd &displacement,
524 const std::vector<mesh::LocalBoundary> &local_boundary,
525 const std::vector<int> &dirichlet_nodes,
526 const int resolution,
529 const bool multiply_pressure)
const
536 LocalThreadMatStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
538 Eigen::MatrixXd pressure_vals, g_3_grad, local_hessian;
539 ElementAssemblyValues vals;
540 Eigen::MatrixXd points, uv, normals, deform_mat, trafo;
541 Eigen::VectorXd weights;
542 Eigen::VectorXi global_primitive_ids;
543 for (int lb_id = start; lb_id < end; ++lb_id)
545 const auto &lb = local_boundary[lb_id];
546 const int e = lb.element_id();
547 const basis::ElementBases &gbs = gbases_[e];
548 const basis::ElementBases &bs = bases_[e];
550 for (int i = 0; i < lb.size(); ++i)
552 const int primitive_global_id = lb.global_primitive_id(i);
553 const auto nodes = bs.local_nodes_for_primitive(primitive_global_id, mesh_);
555 bool has_samples = utils::BoundarySampler::boundary_quadrature(lb, resolution, mesh_, i, false, uv, points, normals, weights);
556 std::vector<Eigen::VectorXd> param_chain_rule;
561 if (mesh_.is_volume())
564 weights /= mesh_.edge_length(primitive_global_id);
566 global_primitive_ids.setConstant(weights.size(), primitive_global_id);
568 vals.compute(e, mesh_.is_volume(), points, bs, gbs);
569 g_3_grad.setZero(normals.rows(), size_ * vals.basis_values.size() * size_);
571 for (int n = 0; n < vals.jac_it.size(); ++n)
573 trafo = vals.jac_it[n].inverse();
575 if (displacement.size() > 0)
578 deform_mat.resize(size_, size_);
579 deform_mat.setZero();
580 for (const auto &b : vals.basis_values)
582 for (const auto &g : b.global)
584 for (int d = 0; d < size_; ++d)
586 deform_mat.row(d) += displacement(g.index * size_ + d) * b.grad.row(n);
594 normals.row(n) = normals.row(n) * trafo.inverse();
595 normals.row(n).normalize();
597 if (mesh_.is_volume())
601 Eigen::MatrixXd g_3_grad_local(size_, vals.basis_values.size() * size_);
602 g_3_grad_local.setZero();
603 auto endpoints = utils::BoundarySampler::tri_local_node_coordinates_from_edge(lb[i]);
604 Eigen::VectorXd reference_normal = (endpoints.row(0) - endpoints.row(1)).transpose();
606 for (const auto &b : vals.basis_values)
608 for (const auto &g : b.global)
609 for (int d = 0; d < size_; ++d)
610 for (int k = 0; k < size_; ++k)
611 g_3_grad_local(1 - d, b_count * size_ + d) += b.grad(n, k) * reference_normal(k);
614 g_3_grad_local.row(0) *= -1;
616 for (int k = 0; k < size_; ++k)
617 for (int l = 0; l < vals.basis_values.size() * size_; ++l)
618 g_3_grad(n, k * (vals.basis_values.size() * size_) + l) = g_3_grad_local(k, l);
622 if (multiply_pressure)
623 problem_.pressure_bc(mesh_, global_primitive_ids, uv, vals.val, normals, t, pressure_vals);
625 pressure_vals = Eigen::MatrixXd::Ones(weights.size(), 1);
627 local_hessian.setZero(vals.basis_values.size() * size_, vals.basis_values.size() * size_);
629 for (long p = 0; p < weights.size(); ++p)
631 for (long ni = 0; ni < nodes.size(); ++ni)
633 const AssemblyValues &vi = vals.basis_values[nodes(ni)];
634 for (int di = 0; di < size_; ++di)
636 const int gi_index = vi.global[0].index * size_ + di;
637 const bool is_dof_i_dirichlet = std::find(dirichlet_nodes.begin(), dirichlet_nodes.end(), gi_index) != dirichlet_nodes.end();
638 if (is_dof_i_dirichlet)
641 for (long nj = 0; nj < nodes.size(); ++nj)
643 const AssemblyValues &vj = vals.basis_values[nodes(nj)];
644 for (int dj = 0; dj < size_; ++dj)
646 const int gj_index = vj.global[0].index * size_ + dj;
647 const bool is_dof_j_dirichlet = std::find(dirichlet_nodes.begin(), dirichlet_nodes.end(), gj_index) != dirichlet_nodes.end();
648 if (is_dof_j_dirichlet)
651 double value = pressure_vals(p) * g_3_grad(p, (di * vals.basis_values.size() * size_) + nodes(nj) * size_ + dj) * vi.val(p) * weights(p);
652 local_hessian(nodes(ni) * size_ + di, nodes(nj) * size_ + dj) += value;
659 for (long ni = 0; ni < nodes.size(); ++ni)
661 const AssemblyValues &vi = vals.basis_values[nodes(ni)];
662 for (int di = 0; di < size_; ++di)
664 const int gi_index = vi.global[0].index * size_ + di;
665 for (long nj = 0; nj < nodes.size(); ++nj)
667 const AssemblyValues &vj = vals.basis_values[nodes(nj)];
668 for (int dj = 0; dj < size_; ++dj)
670 const int gj_index = vj.global[0].index * size_ + dj;
672 local_storage.entries.push_back(Eigen::Triplet<double>(gi_index, gj_index, local_hessian(nodes(ni) * size_ + di, nodes(nj) * size_ + dj)));
681 std::vector<Eigen::Triplet<double>> all_entries;
683 for (LocalThreadMatStorage &local_storage : storage)
685 all_entries.insert(all_entries.end(), local_storage.entries.begin(), local_storage.entries.end());
688 hess.setFromTriplets(all_entries.begin(), all_entries.end());
692 const std::vector<mesh::LocalBoundary> &local_boundary,
693 const std::vector<int> &dirichlet_nodes)
const
695 if (local_boundary.size() == 0)
701 LocalThreadPrimitiveStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
703 ElementAssemblyValues vals;
704 Eigen::MatrixXd points, uv, normals, deform_mat, trafo;
705 Eigen::VectorXd weights;
706 Eigen::VectorXi global_primitive_ids;
707 for (int lb_id = start; lb_id < end; ++lb_id)
709 const auto &lb = local_boundary[lb_id];
710 const int e = lb.element_id();
711 const basis::ElementBases &bs = bases_[e];
712 const basis::ElementBases &gbs = gbases_[e];
714 for (int i = 0; i < lb.size(); ++i)
716 const int primitive_global_id = lb.global_primitive_id(i);
717 const auto nodes = bs.local_nodes_for_primitive(primitive_global_id, mesh_);
719 points.resize(0, size_);
720 vals.compute(e, mesh_.is_volume(), points, bs, gbs);
722 if (!((lb.type() == BoundaryType::TRI_LINE) || (lb.type() == BoundaryType::TRI)))
724 logger().warn(
"Detected element not triangle or tet, cannot check if pressure boundary is closed");
728 Eigen::VectorXi face(size_);
730 for (int n = 0; n < size_; ++n)
732 const AssemblyValues &v = vals.basis_values[nodes(n)];
733 assert(v.global.size() == 1);
734 face(n) = v.global[0].index;
736 local_storage.faces.push_back(face);
741 Eigen::MatrixXi
F(0, size_);
743 for (
const LocalThreadPrimitiveStorage &local_storage : storage)
745 for (
int i = 0; i < local_storage.faces.size(); ++i)
747 F.conservativeResize(count + 1, size_);
748 F.row(count) = local_storage.faces[i];
755 boundary_loop_2d(
F, L);
757 igl::boundary_loop(
F, L);
759 for (
const int &l : L)
760 if (std::
find(dirichlet_nodes.begin(), dirichlet_nodes.end(), l * size_) == dirichlet_nodes.end())
844 const Eigen::MatrixXd &displacement,
845 const std::unordered_map<
int, std::vector<mesh::LocalBoundary>> &local_pressure_cavity,
846 const std::vector<int> &dirichlet_nodes,
847 const int resolution,
849 const bool project_to_psd,
852 if (project_to_psd && local_pressure_cavity.size() > 0)
857 hess.resize(displacement.size(), displacement.size());
858 for (
const auto &v : local_pressure_cavity)
862 double curr_volume =
compute_volume(displacement, v.second, resolution, t,
false);
873 -start_pressure, -start_volume, -curr_volume);
875 -start_pressure, -start_volume, -curr_volume);
878 hess += dp_dv * (g * g.transpose()).sparseView();