PolyFEM
Loading...
Searching...
No Matches
Mesh.cpp
Go to the documentation of this file.
1
7
10
11#include <Eigen/Geometry>
12
13#include <igl/boundary_facets.h>
14#include <igl/oriented_facets.h>
15#include <igl/edges.h>
16
17#include <unordered_set>
18#include <set>
19#include <type_traits>
20
22namespace polyfem::mesh
23{
24 using namespace polyfem::utils;
25
26 std::vector<MeshWithID> Mesh::split() const
27 {
28 std::set<int> ids;
29 for (int e = 0; e < n_elements(); ++e)
30 ids.insert(get_geometry_id(e));
31
32 std::vector<MeshWithID> result;
33 result.reserve(ids.size());
34 for (const int id : ids)
35 {
36 auto child = copy();
37 std::vector<bool> keep(n_elements(), false);
38 for (int e = 0; e < n_elements(); ++e)
39 keep[e] = get_geometry_id(e) == id;
40 child->remove_elements(keep);
41 result.push_back({id, std::move(child)});
42 }
43 return result;
44 }
45
46 void Mesh::filter_element_data(const std::vector<bool> &keep)
47 {
48 const int kept = std::count(keep.begin(), keep.end(), true);
49
50 auto filter_vector = [&keep, kept](auto &values) {
51 if (values.empty())
52 return;
53 assert(values.size() == keep.size());
54 using Value = typename std::decay_t<decltype(values)>::value_type;
55 std::vector<Value> filtered;
56 filtered.reserve(kept);
57 for (int i = 0; i < keep.size(); ++i)
58 if (keep[i])
59 filtered.push_back(values[i]);
60 values = std::move(filtered);
61 };
62
63 filter_vector(elements_tag_);
64 filter_vector(body_ids_);
65 filter_vector(geometry_ids_);
66 filter_vector(cell_weights_);
67 filter_vector(higher_order_connectivity_);
68
69 if (orders_.size() > 0)
70 {
71 assert(orders_.rows() == keep.size());
72 Eigen::MatrixXi filtered(kept, orders_.cols());
73 for (int i = 0, j = 0; i < keep.size(); ++i)
74 if (keep[i])
75 filtered.row(j++) = orders_.row(i);
76 orders_ = std::move(filtered);
77 }
78 }
79
80 std::unique_ptr<Mesh> Mesh::create(MeshData data, const bool non_conforming)
81 {
82 data.validate();
83 const int dim = data.dimension();
84 assert(dim == 2 || dim == 3);
85
86 std::unique_ptr<Mesh> mesh;
87 if (dim == 2 && non_conforming)
88 mesh = std::make_unique<NCMesh2D>();
89 else if (dim == 2 && !non_conforming)
90 mesh = std::make_unique<CMesh2D>();
91 else if (dim == 3 && non_conforming)
92 mesh = std::make_unique<NCMesh3D>();
93 else if (dim == 3 && !non_conforming)
94 mesh = std::make_unique<CMesh3D>();
95 if (!mesh || !mesh->build_from_data(data))
96 log_and_throw_error("Unable to construct runtime mesh from MeshData.");
97 return mesh;
98 }
99
101 {
102 if (n_vertices() == 0 || n_elements() == 0)
103 log_and_throw_error("Cannot convert an empty runtime mesh to MeshData.");
104
105 Eigen::MatrixXd vertices(n_vertices(), dimension());
106 for (int i = 0; i < n_vertices(); ++i)
107 vertices.row(i) = point(i);
108
109 int element_width = 0;
110 for (int e = 0; e < n_elements(); ++e)
111 element_width = std::max(element_width, n_cell_vertices(e));
112 Eigen::MatrixXi elements = Eigen::MatrixXi::Constant(n_elements(), element_width, -1);
113 for (int e = 0; e < n_elements(); ++e)
114 {
115 for (int j = 0; j < n_cell_vertices(e); ++j)
116 elements(e, j) = element_vertex(e, j);
117
118 // Runtime navigation may reorder refined simplex corners. MeshData is a
119 // decoder-facing representation, so restore the canonical positive
120 // orientation before it is serialized or used to construct another mesh.
121 if (is_simplex(e))
122 {
123 if (dimension() == 2)
124 {
125 const Eigen::Vector2d a = vertices.row(elements(e, 1)) - vertices.row(elements(e, 0));
126 const Eigen::Vector2d b = vertices.row(elements(e, 2)) - vertices.row(elements(e, 0));
127 if (a.x() * b.y() - a.y() * b.x() < 0)
128 std::swap(elements(e, 1), elements(e, 2));
129 }
130 else
131 {
132 Eigen::Matrix3d jacobian;
133 jacobian.col(0) = vertices.row(elements(e, 1)) - vertices.row(elements(e, 0));
134 jacobian.col(1) = vertices.row(elements(e, 2)) - vertices.row(elements(e, 0));
135 jacobian.col(2) = vertices.row(elements(e, 3)) - vertices.row(elements(e, 0));
136 if (jacobian.determinant() < 0)
137 std::swap(elements(e, 1), elements(e, 2));
138 }
139 }
140 }
141
142 MeshData data(std::move(vertices), std::move(elements));
143 if (has_body_ids())
144 data.body_ids = body_ids_;
145 if (has_geometry_ids())
147 if (has_node_ids())
148 data.node_ids = node_ids_;
149 if (has_boundary_ids())
150 {
153 for (int i = 0; i < n_boundary_elements(); ++i)
154 for (int j = 0; j < (is_volume() ? n_face_vertices(i) : 2); ++j)
155 data.boundary_elements[i].push_back(boundary_element_vertex(i, j));
156 }
157
158 if (!higher_order_connectivity_.empty())
159 {
160 if (higher_order_connectivity_.size() != size_t(n_elements())
161 || higher_order_nodes_.rows() < n_vertices())
162 log_and_throw_error("Runtime mesh has inconsistent higher-order data.");
164 data.higher_order_nodes.topRows(n_vertices()) = data.vertices;
166 }
167 if (std::any_of(cell_weights_.begin(), cell_weights_.end(), [](const auto &weights) { return !weights.empty(); }))
168 {
169 if (cell_weights_.size() != size_t(n_elements()))
170 log_and_throw_error("Runtime mesh has inconsistent rational weights.");
172 }
173
175 {
176 const auto *mesh3d = dynamic_cast<const Mesh3D *>(this);
177 if (mesh3d == nullptr)
178 log_and_throw_error("Polyhedral topology is only supported for 3D meshes.");
179 data.faces.resize(n_faces());
180 for (int f = 0; f < n_faces(); ++f)
181 for (int j = 0; j < n_face_vertices(f); ++j)
182 data.faces[f].push_back(face_vertex(f, j));
183 data.cell_faces.resize(n_elements());
184 data.cell_face_orientations.resize(n_elements());
185 data.cell_is_hex.resize(n_elements());
186 data.cell_kernel_points.resize(n_elements(), 3);
187 for (int c = 0; c < n_elements(); ++c)
188 {
189 for (int j = 0; j < mesh3d->n_cell_faces(c); ++j)
190 {
191 data.cell_faces[c].push_back(mesh3d->cell_face(c, j));
192 data.cell_face_orientations[c].push_back(mesh3d->cell_face_orientation(c, j));
193 }
194 data.cell_is_hex[c] = is_cube(c);
195 data.cell_kernel_points.row(c) = mesh3d->kernel(c);
196 }
197 }
198
199 data.validate();
200 return data;
201 }
202
204 {
205 if (!build_topology(data))
206 return false;
208
209 std::vector<int> tmp(data.elements.data(), data.elements.data() + data.elements.size());
210 std::sort(tmp.begin(), tmp.end());
211 tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
212 if (!tmp.empty() && tmp.front() == -1)
213 tmp.erase(tmp.begin());
214
215 in_ordered_vertices_ = Eigen::Map<Eigen::VectorXi, Eigen::Unaligned>(tmp.data(), tmp.size());
216
217 in_ordered_edges_.resize(n_edges(), 2);
218 for (int e = 0; e < n_edges(); ++e)
219 in_ordered_edges_.row(e) << edge_vertex(e, 0), edge_vertex(e, 1);
220 if (dimension() == 2)
221 in_ordered_faces_.resize(0, 0);
222 else
223 {
224 int width = 0;
225 for (int f = 0; f < n_faces(); ++f)
226 width = std::max(width, n_face_vertices(f));
227 in_ordered_faces_.setConstant(n_faces(), width, -1);
228 for (int f = 0; f < n_faces(); ++f)
229 for (int lv = 0; lv < n_face_vertices(f); ++lv)
230 in_ordered_faces_(f, lv) = face_vertex(f, lv);
231 }
232
233 if (!data.higher_order_connectivity.empty())
234 {
238 }
239 if (!data.higher_order_weights.empty())
240 {
242 set_is_rational(std::any_of(
243 data.higher_order_weights.begin(), data.higher_order_weights.end(),
244 [](const auto &weights) { return !weights.empty(); }));
245 }
246 if (!data.body_ids.empty())
248 if (!data.geometry_ids.empty())
250 if (!data.node_ids.empty())
251 node_ids_ = data.node_ids;
252
253 if (!data.boundary_ids.empty())
254 {
255 std::unordered_map<std::vector<int>, int, HashVector> labels;
256 for (int i = 0; i < data.boundary_elements.size(); ++i)
257 {
258 std::vector<int> side = data.boundary_elements[i];
259 std::sort(side.begin(), side.end());
260 const auto [it, inserted] = labels.emplace(std::move(side), data.boundary_ids[i]);
261 if (!inserted && it->second != data.boundary_ids[i])
262 logger().warn("Mesh side has multiple labels; using {}.", it->second);
263 }
264 compute_boundary_ids([&](const size_t primitive, const std::vector<int> &vertices, const RowVectorNd &, const bool) {
265 std::vector<int> side = vertices;
266 std::sort(side.begin(), side.end());
267 const auto it = labels.find(side);
268 return it == labels.end() ? get_default_boundary_id(primitive) : it->second;
269 });
270 }
271
272 return true;
273 }
274
276
277 void Mesh::edge_barycenters(Eigen::MatrixXd &barycenters) const
278 {
279 barycenters.resize(n_edges(), dimension());
280 for (int e = 0; e < n_edges(); ++e)
281 {
282 barycenters.row(e) = edge_barycenter(e);
283 }
284 }
285
286 void Mesh::face_barycenters(Eigen::MatrixXd &barycenters) const
287 {
288 barycenters.resize(n_faces(), dimension());
289 for (int f = 0; f < n_faces(); ++f)
290 {
291 barycenters.row(f) = face_barycenter(f);
292 }
293 }
294
295 void Mesh::cell_barycenters(Eigen::MatrixXd &barycenters) const
296 {
297 barycenters.resize(n_cells(), dimension());
298 for (int c = 0; c < n_cells(); ++c)
299 {
300 barycenters.row(c) = cell_barycenter(c);
301 }
302 }
303
305
306 // Queries on the tags
307 bool Mesh::is_spline_compatible(const int el_id) const
308 {
309 if (is_volume())
310 {
313 // || elements_tag_[el_id] == ElementType::SIMPLE_SINGULAR_INTERIOR_CUBE
314 // || elements_tag_[el_id] == ElementType::SIMPLE_SINGULAR_BOUNDARY_CUBE;
315 }
316 else
317 {
320 // || elements_tag_[el_id] == ElementType::INTERFACE_CUBE
321 // || elements_tag_[el_id] == ElementType::SIMPLE_SINGULAR_INTERIOR_CUBE;
322 }
323 }
324
325 // -----------------------------------------------------------------------------
326
337
338 // -----------------------------------------------------------------------------
339
340 bool Mesh::is_polytope(const int el_id) const
341 {
344 }
345
346 void Mesh::update_nodes(const Eigen::VectorXi &in_node_to_node)
347 {
348 if (in_node_to_node.size() <= 0 || node_ids_.empty())
349 {
350 node_ids_.clear();
351 return;
352 }
353
354 const auto tmp = node_ids_;
355
356 for (int n = 0; n < n_vertices(); ++n)
357 {
358 node_ids_[in_node_to_node[n]] = tmp[n];
359 }
360 }
361
362 void Mesh::compute_node_ids(const std::function<int(const size_t, const RowVectorNd &, bool)> &marker)
363 {
364 node_ids_.resize(n_vertices());
365
366 for (int n = 0; n < n_vertices(); ++n)
367 {
368 bool is_boundary = is_boundary_vertex(n);
369 const auto p = point(n);
370 node_ids_[n] = marker(n, p, is_boundary);
371 }
372 }
373
374 bool Mesh::is_simplex(const int el_id) const
375 {
376 return elements_tag_[el_id] == ElementType::SIMPLEX;
377 }
378
379 bool Mesh::is_prism(const int el_id) const
380 {
381 return elements_tag_[el_id] == ElementType::PRISM;
382 }
383
384 bool Mesh::is_pyramid(const int el_id) const
385 {
386 return elements_tag_[el_id] == ElementType::PYRAMID;
387 }
388
389 std::vector<std::pair<int, int>> Mesh::edges() const
390 {
391 std::vector<std::pair<int, int>> res;
392 res.reserve(n_edges());
393
394 for (int e_id = 0; e_id < n_edges(); ++e_id)
395 {
396 const int e0 = edge_vertex(e_id, 0);
397 const int e1 = edge_vertex(e_id, 1);
398
399 res.emplace_back(std::min(e0, e1), std::max(e0, e1));
400 }
401
402 return res;
403 }
404
405 std::vector<std::vector<int>> Mesh::faces() const
406 {
407 std::vector<std::vector<int>> res(n_faces());
408
409 for (int f_id = 0; f_id < n_faces(); ++f_id)
410 {
411 auto &tmp = res[f_id];
412 for (int lv_id = 0; lv_id < n_face_vertices(f_id); ++lv_id)
413 tmp.push_back(face_vertex(f_id, lv_id));
414
415 std::sort(tmp.begin(), tmp.end());
416 }
417
418 return res;
419 }
420
421 std::unordered_map<std::pair<int, int>, size_t, HashPair> Mesh::edges_to_ids() const
422 {
423 std::unordered_map<std::pair<int, int>, size_t, HashPair> res;
424 res.reserve(n_edges());
425
426 for (int e_id = 0; e_id < n_edges(); ++e_id)
427 {
428 const int e0 = edge_vertex(e_id, 0);
429 const int e1 = edge_vertex(e_id, 1);
430
431 res[std::pair<int, int>(std::min(e0, e1), std::max(e0, e1))] = e_id;
432 }
433
434 return res;
435 }
436
437 std::unordered_map<std::vector<int>, size_t, HashVector> Mesh::faces_to_ids() const
438 {
439 std::unordered_map<std::vector<int>, size_t, HashVector> res;
440 res.reserve(n_faces());
441
442 for (int f_id = 0; f_id < n_faces(); ++f_id)
443 {
444 std::vector<int> f;
445 f.reserve(n_face_vertices(f_id));
446 for (int lv_id = 0; lv_id < n_face_vertices(f_id); ++lv_id)
447 f.push_back(face_vertex(f_id, lv_id));
448 std::sort(f.begin(), f.end());
449
450 res[f] = f_id;
451 }
452
453 return res;
454 }
455
456 void Mesh::append(const Mesh &mesh)
457 {
458 const int n_vertices = this->n_vertices();
459 const int other_vertices = mesh.n_vertices();
462 if (!higher_order_connectivity_.empty() || !mesh.higher_order_connectivity_.empty())
463 {
464 auto complete_higher_order = [](const Mesh &source) {
465 std::pair<Eigen::MatrixXd, std::vector<std::vector<int>>> result;
466 if (!source.higher_order_connectivity_.empty())
467 {
468 result.first = source.higher_order_nodes_;
469 result.second = source.higher_order_connectivity_;
470 }
471 else
472 {
473 result.first.resize(source.n_vertices(), source.dimension());
474 result.second.resize(source.n_elements());
475 for (int v = 0; v < source.n_vertices(); ++v)
476 result.first.row(v) = source.point(v);
477 for (int e = 0; e < source.n_elements(); ++e)
478 for (int j = 0; j < source.n_cell_vertices(e); ++j)
479 result.second[e].push_back(source.element_vertex(e, j));
480 }
481 if (result.first.rows() < source.n_vertices()
482 || result.second.size() != size_t(source.n_elements()))
483 log_and_throw_error("Cannot append inconsistent higher-order mesh data.");
484 for (int v = 0; v < source.n_vertices(); ++v)
485 result.first.row(v) = source.point(v);
486 return result;
487 };
488
489 auto left = complete_higher_order(*this);
490 auto right = complete_higher_order(mesh);
491 const int left_extra = left.first.rows() - n_vertices;
492 const int right_extra = right.first.rows() - other_vertices;
493 Eigen::MatrixXd nodes(n_vertices + other_vertices + left_extra + right_extra, dimension());
494 nodes.topRows(n_vertices) = left.first.topRows(n_vertices);
495 nodes.middleRows(n_vertices, other_vertices) = right.first.topRows(other_vertices);
496 if (left_extra)
497 nodes.middleRows(n_vertices + other_vertices, left_extra) = left.first.bottomRows(left_extra);
498 if (right_extra)
499 nodes.bottomRows(right_extra) = right.first.bottomRows(right_extra);
500
501 for (auto &element : left.second)
502 for (int &node : element)
503 if (node >= n_vertices)
504 node += other_vertices;
505 for (auto &element : right.second)
506 for (int &node : element)
507 node = node < other_vertices
508 ? node + n_vertices
509 : node + n_vertices + left_extra;
510 higher_order_nodes_ = std::move(nodes);
511 higher_order_connectivity_ = std::move(left.second);
513 higher_order_connectivity_.end(), right.second.begin(), right.second.end());
514 }
515
516 elements_tag_.insert(elements_tag_.end(), mesh.elements_tag_.begin(), mesh.elements_tag_.end());
517
518 // --------------------------------------------------------------------
519
520 // Initialize node_ids_ if it is not initialized yet.
521 if (!has_node_ids() && mesh.has_node_ids())
522 {
523 node_ids_.resize(n_vertices);
524 for (int i = 0; i < node_ids_.size(); ++i)
525 node_ids_[i] = get_node_id(i); // results in default if node_ids_ is empty
526 }
527
528 if (mesh.has_node_ids())
529 {
530 node_ids_.insert(node_ids_.end(), mesh.node_ids_.begin(), mesh.node_ids_.end());
531 }
532 else if (has_node_ids()) // && !mesh.has_node_ids()
533 {
534 node_ids_.resize(n_vertices + mesh.n_vertices());
535 for (int i = 0; i < mesh.n_vertices(); ++i)
536 node_ids_[n_vertices + i] = mesh.get_node_id(i); // results in default if node_ids_ is empty
537 }
538
539 assert(node_ids_.empty() || node_ids_.size() == n_vertices + mesh.n_vertices());
540
541 // --------------------------------------------------------------------
542
543 // Initialize boundary_ids_ if it is not initialized yet.
544 if (!has_boundary_ids() && mesh.has_boundary_ids())
545 {
547 for (int i = 0; i < boundary_ids_.size(); ++i)
549 }
550
551 if (mesh.has_boundary_ids())
552 {
553 boundary_ids_.insert(boundary_ids_.end(), mesh.boundary_ids_.begin(), mesh.boundary_ids_.end());
554 }
555 else if (has_boundary_ids()) // && !mesh.has_boundary_ids()
556 {
558 for (int i = 0; i < mesh.n_boundary_elements(); ++i)
559 boundary_ids_[n_boundary_elements() + i] = mesh.get_boundary_id(i); // results in default if mesh.boundary_ids_ is empty
560 }
561
562 // --------------------------------------------------------------------
563
564 // Initialize body_ids_ if it is not initialized yet.
565 if (!has_body_ids() && mesh.has_body_ids())
566 body_ids_ = std::vector<int>(n_elements(), 0); // 0 is the default body_id
567
568 if (mesh.has_body_ids())
569 body_ids_.insert(body_ids_.end(), mesh.body_ids_.begin(), mesh.body_ids_.end());
570 else if (has_body_ids()) // && !mesh.has_body_ids()
571 body_ids_.resize(n_elements() + mesh.n_elements(), 0); // 0 is the default body_id
572
573 // --------------------------------------------------------------------
574 // Initialize geometry_ids_ if it is not initialized yet.
575 if (!has_geometry_ids() && mesh.has_geometry_ids())
576 geometry_ids_ = std::vector<int>(n_elements(), 0);
577
578 if (mesh.has_geometry_ids())
579 geometry_ids_.insert(geometry_ids_.end(), mesh.geometry_ids_.begin(), mesh.geometry_ids_.end());
580 else if (has_geometry_ids())
581 geometry_ids_.resize(n_elements() + mesh.n_elements(), 0);
582
583 // --------------------------------------------------------------------
584
585 if (orders_.size() == 0)
586 orders_.setOnes(n_elements(), 1);
587 Eigen::MatrixXi mesh_orders = mesh.orders_;
588 if (mesh_orders.size() == 0)
589 mesh_orders.setOnes(mesh.n_elements(), 1);
590 assert(orders_.cols() == mesh_orders.cols());
591 orders_.conservativeResize(orders_.rows() + mesh_orders.rows(), orders_.cols());
592 orders_.bottomRows(mesh_orders.rows()) = mesh_orders;
593
595
596 // --------------------------------------------------------------------
597 for (const auto &n : mesh.edge_nodes_)
598 {
599 auto tmp = n;
600 tmp.v1 += n_vertices;
601 tmp.v2 += n_vertices;
602 edge_nodes_.push_back(tmp);
603 }
604 for (const auto &n : mesh.face_nodes_)
605 {
606 auto tmp = n;
607 tmp.v1 += n_vertices;
608 tmp.v2 += n_vertices;
609 tmp.v3 += n_vertices;
610 face_nodes_.push_back(tmp);
611 }
612 for (const auto &n : mesh.cell_nodes_)
613 {
614 auto tmp = n;
615 tmp.v1 += n_vertices;
616 tmp.v2 += n_vertices;
617 tmp.v3 += n_vertices;
618 tmp.v4 += n_vertices;
619 cell_nodes_.push_back(tmp);
620 }
621 cell_weights_.insert(cell_weights_.end(), mesh.cell_weights_.begin(), mesh.cell_weights_.end());
622 // --------------------------------------------------------------------
623
624 assert(in_ordered_vertices_.cols() == mesh.in_ordered_vertices_.cols());
625 in_ordered_vertices_.conservativeResize(in_ordered_vertices_.rows() + mesh.in_ordered_vertices_.rows(), in_ordered_vertices_.cols());
626 in_ordered_vertices_.bottomRows(mesh.in_ordered_vertices_.rows()) = mesh.in_ordered_vertices_.array() + n_vertices;
627
628 if (in_ordered_edges_.size() == 0 || mesh.in_ordered_edges_.size() == 0)
629 in_ordered_edges_.resize(0, 0);
630 else
631 {
632 assert(in_ordered_edges_.cols() == mesh.in_ordered_edges_.cols());
634 }
635
636 if (in_ordered_faces_.size() == 0 || mesh.in_ordered_faces_.size() == 0)
637 in_ordered_faces_.resize(0, 0);
638 else
639 {
640 Eigen::MatrixXi incoming_faces = mesh.in_ordered_faces_;
641 for (int i = 0; i < incoming_faces.size(); ++i)
642 if (incoming_faces(i) >= 0)
643 incoming_faces(i) += n_vertices;
644
645 const int old_rows = in_ordered_faces_.rows();
646 const int width = std::max(in_ordered_faces_.cols(), incoming_faces.cols());
647 Eigen::MatrixXi combined = Eigen::MatrixXi::Constant(
648 old_rows + incoming_faces.rows(), width, -1);
649 combined.topLeftCorner(old_rows, in_ordered_faces_.cols()) = in_ordered_faces_;
650 combined.bottomLeftCorner(incoming_faces.rows(), incoming_faces.cols()) = incoming_faces;
651 in_ordered_faces_ = std::move(combined);
652 }
653 }
654
655 namespace
656 {
657 template <typename T>
658 void transform_high_order_nodes(std::vector<T> &nodes, const MatrixNd &A, const VectorNd &b)
659 {
660 for (T &n : nodes)
661 {
662 if (n.nodes.size())
663 {
664 n.nodes = (n.nodes * A.transpose()).rowwise() + b.transpose();
665 }
666 }
667 }
668 } // namespace
669
671 {
672 for (int i = 0; i < n_vertices(); ++i)
673 {
674 VectorNd p = point(i).transpose();
675 p = A * p + b;
676 set_point(i, p.transpose());
677 }
678
679 transform_high_order_nodes(edge_nodes_, A, b);
680 transform_high_order_nodes(face_nodes_, A, b);
681 transform_high_order_nodes(cell_nodes_, A, b);
683 }
684
686 {
687 higher_order_nodes_.resize(0, 0);
689 cell_weights_.clear();
690 is_rational_ = false;
691 }
692
694 {
695 if (higher_order_nodes_.rows() > n_vertices())
696 {
697 auto nodes = higher_order_nodes_.bottomRows(higher_order_nodes_.rows() - n_vertices());
698 nodes = (nodes * A.transpose()).rowwise() + b.transpose();
699 }
700 }
701} // namespace polyfem::mesh
Eigen::RowVectorXd point
StiffnessMatrix source
std::vector< std::pair< int, double > > weights
Format-independent input used to construct a runtime Mesh.
Definition MeshData.hpp:12
Eigen::MatrixXd vertices
Definition MeshData.hpp:21
bool has_polyhedral_topology() const
Definition MeshData.hpp:19
Eigen::MatrixXd higher_order_nodes
Definition MeshData.hpp:33
std::vector< std::vector< int > > higher_order_connectivity
Definition MeshData.hpp:34
std::vector< int > node_ids
Definition MeshData.hpp:29
std::vector< int > geometry_ids
Definition MeshData.hpp:28
std::vector< std::vector< int > > boundary_elements
Definition MeshData.hpp:30
std::vector< std::vector< int > > faces
Optional topology for arbitrary polyhedral cells.
Definition MeshData.hpp:38
std::vector< int > body_ids
Definition MeshData.hpp:27
std::vector< int > boundary_ids
Definition MeshData.hpp:31
Eigen::MatrixXi elements
Definition MeshData.hpp:22
void validate() const
Definition MeshData.cpp:7
Eigen::MatrixXd cell_kernel_points
Definition MeshData.hpp:42
std::vector< std::vector< int > > cell_faces
Definition MeshData.hpp:39
std::vector< std::vector< int > > cell_face_orientations
Definition MeshData.hpp:40
std::vector< std::vector< double > > higher_order_weights
Definition MeshData.hpp:35
std::vector< bool > cell_is_hex
Definition MeshData.hpp:41
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:50
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:148
virtual int n_vertices() const =0
number of vertices
void set_cell_weights(const std::vector< std::vector< double > > &in_cell_weights)
Set the cell weights for rational polynomial meshes.
Definition Mesh.hpp:561
bool is_polytope(const int el_id) const
checks if element is polygon compatible
Definition Mesh.cpp:340
Eigen::MatrixXi orders_
list of geometry orders, one per cell
Definition Mesh.hpp:696
std::unordered_map< std::pair< int, int >, size_t, polyfem::utils::HashPair > edges_to_ids() const
map from edge (pair of v id) to the id of the edge
Definition Mesh.cpp:421
std::vector< ElementType > elements_tag_
list of element types
Definition Mesh.hpp:686
virtual RowVectorNd edge_barycenter(const int e) const =0
edge barycenter
int element_vertex(const int el_id, const int lv_id) const
id of the vertex of a element
Definition Mesh.hpp:207
bool is_rational_
stores if the mesh is rational
Definition Mesh.hpp:698
bool has_boundary_ids() const
checks if surface selections are available
Definition Mesh.hpp:528
virtual void compute_boundary_ids(const std::function< int(const size_t, const std::vector< int > &, const RowVectorNd &, bool)> &marker)=0
computes boundary selections based on a function
void cell_barycenters(Eigen::MatrixXd &barycenters) const
all cells barycenters
Definition Mesh.cpp:295
std::vector< std::vector< int > > higher_order_connectivity_
Definition Mesh.hpp:715
virtual RowVectorNd face_barycenter(const int f) const =0
face barycenter
int get_geometry_id(const int element) const
Get the geometry ID of an element. The default geometry is 0.
Definition Mesh.hpp:514
virtual void set_point(const int global_index, const RowVectorNd &p)=0
Set the point.
bool is_cube(const int el_id) const
checks if element is cube compatible
Definition Mesh.cpp:327
bool has_node_ids() const
checks if points selections are available
Definition Mesh.hpp:524
virtual void set_body_ids(const std::vector< int > &body_ids)
Set the volume sections.
Definition Mesh.hpp:444
Eigen::MatrixXi in_ordered_faces_
Order of the input faces, TODO: change to std::vector of Eigen::Vector.
Definition Mesh.hpp:722
void compute_node_ids(const std::function< int(const size_t, const RowVectorNd &, bool)> &marker)
computes boundary selections based on a function
Definition Mesh.cpp:362
virtual int get_boundary_id(const int primitive) const
Get the boundary selection of an element (face in 3d, edge in 2d)
Definition Mesh.hpp:466
virtual bool is_boundary_vertex(const int vertex_global_id) const =0
is vertex boundary
bool is_simplex(const int el_id) const
checks if element is simplex
Definition Mesh.cpp:374
void face_barycenters(Eigen::MatrixXd &barycenters) const
all face barycenters
Definition Mesh.cpp:286
virtual bool has_body_ids() const
checks if volumes selections are available
Definition Mesh.hpp:532
bool is_spline_compatible(const int el_id) const
checks if element is spline compatible
Definition Mesh.cpp:307
std::vector< int > geometry_ids_
list of geometry labels, one per top-dimensional element
Definition Mesh.hpp:694
void set_is_rational(const bool in_is_rational)
Set the is rational object.
Definition Mesh.hpp:276
std::vector< int > boundary_ids_
list of surface labels
Definition Mesh.hpp:690
bool is_prism(const int el_id) const
checks if element is a prism
Definition Mesh.cpp:379
void clear_higher_order_data()
Definition Mesh.cpp:685
void apply_affine_transformation(const MatrixNd &A, const VectorNd &b)
Apply an affine transformation to the vertex positions .
Definition Mesh.cpp:670
std::vector< int > node_ids_
list of node labels
Definition Mesh.hpp:688
std::unordered_map< std::vector< int >, size_t, polyfem::utils::HashVector > faces_to_ids() const
map from face (tuple of v id) to the id of the face
Definition Mesh.cpp:437
std::vector< CellNodes > cell_nodes_
high-order nodes associates to cells
Definition Mesh.hpp:705
MeshData to_mesh_data() const
Capture the complete runtime mesh in the canonical, format-independent representation.
Definition Mesh.cpp:100
virtual bool build_topology(const MeshData &data)=0
Construct only the dimension-specific topology.
std::vector< std::vector< double > > cell_weights_
weights associates to cells for rational polynomail meshes
Definition Mesh.hpp:707
virtual bool is_volume() const =0
checks if mesh is volume
std::vector< std::pair< int, int > > edges() const
list of sorted edges.
Definition Mesh.cpp:389
void update_nodes(const Eigen::VectorXi &in_node_to_node)
Update the node ids to reorder them.
Definition Mesh.cpp:346
virtual int edge_vertex(const int e_id, const int lv_id) const =0
id of the edge vertex
virtual std::unique_ptr< Mesh > copy() const =0
Create a copy of the mesh.
void set_geometry_ids(const std::vector< int > &geometry_ids)
Set the geometry selection, one ID per element.
Definition Mesh.hpp:507
std::vector< MeshWithID > split() const
Split the mesh according to its per-element geometry IDs.
Definition Mesh.cpp:26
bool has_poly() const
checks if the mesh has polytopes
Definition Mesh.hpp:570
Eigen::MatrixXd higher_order_nodes_
Canonical connectivity is retained because the runtime edge/face caches do not preserve the original ...
Definition Mesh.hpp:714
std::vector< int > body_ids_
list of volume labels
Definition Mesh.hpp:692
virtual int get_default_boundary_id(const int primitive) const
Get the default boundary selection of an element (face in 3d, edge in 2d)
Definition Mesh.hpp:454
int dimension() const
utily for dimension
Definition Mesh.hpp:138
virtual int n_cells() const =0
number of cells
void transform_higher_order_data(const MatrixNd &A, const VectorNd &b)
Definition Mesh.cpp:693
static std::unique_ptr< Mesh > create(MeshData data, bool non_conforming=false)
Construct a runtime mesh from format-independent decoded data.
Definition Mesh.cpp:80
std::vector< FaceNodes > face_nodes_
high-order nodes associates to faces
Definition Mesh.hpp:703
virtual int n_faces() const =0
number of faces
bool build_from_data(const MeshData &data)
Import all topology and metadata from MeshData.
Definition Mesh.cpp:203
std::vector< EdgeNodes > edge_nodes_
high-order nodes associates to edges
Definition Mesh.hpp:701
std::vector< std::vector< int > > faces() const
list of sorted faces.
Definition Mesh.cpp:405
virtual void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes)=0
attach high order nodes
int n_boundary_elements() const
utitlity to return the number of boundary elements, faces or edges in 3d and 2d
Definition Mesh.hpp:153
void filter_element_data(const std::vector< bool > &keep)
Definition Mesh.cpp:46
Eigen::MatrixXi in_ordered_edges_
Order of the input edges.
Definition Mesh.hpp:720
virtual void append(const Mesh &mesh)
appends a new mesh to the end of this
Definition Mesh.cpp:456
bool is_pyramid(const int el_id) const
checks if element is a pyramid
Definition Mesh.cpp:384
virtual RowVectorNd cell_barycenter(const int c) const =0
cell barycenter
virtual int n_edges() const =0
number of edges
void edge_barycenters(Eigen::MatrixXd &barycenters) const
all edges barycenters
Definition Mesh.cpp:277
virtual int n_face_vertices(const int f_id) const =0
number of vertices of a face
bool has_explicit_polyhedral_topology_
Whether the source MeshData supplied explicit face/cell incidence.
Definition Mesh.hpp:711
Eigen::VectorXi in_ordered_vertices_
Order of the input vertices.
Definition Mesh.hpp:718
bool has_geometry_ids() const
Definition Mesh.hpp:520
virtual int n_cell_vertices(const int c_id) const =0
number of vertices of a cell
virtual int get_node_id(const int node_id) const
Get the boundary selection of a node.
Definition Mesh.hpp:475
virtual int face_vertex(const int f_id, const int lv_id) const =0
id of the face vertex
int boundary_element_vertex(const int primitive_id, const int lv_id) const
Definition Mesh.hpp:225
@ REGULAR_INTERIOR_CUBE
Triangle/tet element.
@ REGULAR_BOUNDARY_CUBE
Quad/Hex incident to more than 1 singular vertices (should not happen in 2D)
@ MULTI_SINGULAR_BOUNDARY_CUBE
Quad incident to exactly 1 singular vertex (in 2D); hex incident to exactly 1 singular interior edge,...
@ PRISM
Boundary polytope.
@ MULTI_SINGULAR_INTERIOR_CUBE
Quad/hex incident to exactly 1 singular vertex (in 2D) or edge (in 3D)
@ SIMPLE_SINGULAR_INTERIOR_CUBE
Regular quad/hex inside a 3^n patch.
@ INTERFACE_CUBE
Boundary hex that is not regular nor SimpleSingularBoundaryCube.
@ INTERIOR_POLYTOPE
Quad/hex that is at the interface with a polytope (if a cube has both external boundary and and inter...
@ SIMPLE_SINGULAR_BOUNDARY_CUBE
Boundary quad/hex, where all boundary vertices/edges are incident to at most 2 quads/hexes.
@ BOUNDARY_POLYTOPE
Interior polytope.
void append_rows(DstMat &dst, const SrcMat &src)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, 3, 1 > VectorNd
Definition Types.hpp:11
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor, 3, 3 > MatrixNd
Definition Types.hpp:14
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73