PolyFEM
Loading...
Searching...
No Matches
MeshNodes.cpp
Go to the documentation of this file.
1
7
10
11namespace polyfem::mesh
12{
13 namespace
14 {
15
16 std::vector<bool> interface_edges(const Mesh2D &mesh)
17 {
18 std::vector<bool> is_interface(mesh.n_edges(), false);
19 for (int f = 0; f < mesh.n_faces(); ++f)
20 {
21 if (mesh.is_cube(f))
22 {
23 continue;
24 } // Skip quads
25
26 auto index = mesh.get_index_from_face(f, 0);
27 for (int lv = 0; lv < mesh.n_face_vertices(f); ++lv)
28 {
29 auto index2 = mesh.switch_face(index);
30 if (index2.face >= 0)
31 {
32 is_interface[index.edge] = true;
33 }
34 index = mesh.next_around_face(index);
35 }
36 }
37 return is_interface;
38 }
39
40 std::vector<bool> interface_faces(const Mesh3D &mesh)
41 {
42 std::vector<bool> is_interface(mesh.n_faces(), false);
43 for (int c = 0; c < mesh.n_cells(); ++c)
44 {
45 if (mesh.is_cube(c))
46 {
47 continue;
48 } // Skip hexes
49
50 for (int lf = 0; lf < mesh.n_cell_faces(c); ++lf)
51 {
52 auto index = mesh.get_index_from_element(c, lf, 0);
53 auto index2 = mesh.switch_element(index);
54 if (index2.element >= 0)
55 {
56 is_interface[index.face] = true;
57 }
58 }
59 }
60 return is_interface;
61 }
62
63 } // anonymous namespace
64
65 // -----------------------------------------------------------------------------
66
67 MeshNodes::MeshNodes(const Mesh &mesh, const bool has_poly, const bool connect_nodes, const int max_nodes_per_edge, const int max_nodes_per_face, const int max_nodes_per_cell)
68 : mesh_(mesh), connect_nodes_(connect_nodes), edge_offset_(mesh.n_vertices()), face_offset_(edge_offset_ + mesh.n_edges() * max_nodes_per_edge), cell_offset_(face_offset_ + mesh.n_faces() * max_nodes_per_face)
69
70 ,
71 max_nodes_per_edge_(max_nodes_per_edge), max_nodes_per_face_(max_nodes_per_face), max_nodes_per_cell_(max_nodes_per_cell)
72 {
73 // Initialization
74 int n_nodes = cell_offset_ + mesh.n_cells() * max_nodes_per_cell;
75 primitive_to_node_.assign(n_nodes, -1); // #v + #e + #f + #c
76 nodes_.resize(n_nodes, mesh.dimension());
77 is_boundary_.assign(n_nodes, false);
78
79 if (has_poly)
80 is_interface_.assign(n_nodes, false);
81
82 // Vertex nodes
83 for (int v = 0; v < mesh.n_vertices(); ++v)
84 {
85 // nodes_.row(v) = mesh.point(v);
87 }
88 // if (!vertices_only) {
89 // Eigen::MatrixXd bary;
90 // Edge nodes
91 // mesh.edge_barycenters(bary);
92
93 for (int e = 0; e < mesh.n_edges(); ++e)
94 {
95 // nodes_.row(edge_offset_ + e) = bary.row(e);
96 const bool is_boundary = mesh.is_boundary_edge(e);
97 for (int tmp = 0; tmp < max_nodes_per_edge; ++tmp)
98 is_boundary_[edge_offset_ + max_nodes_per_edge * e + tmp] = is_boundary;
99 }
100 // Face nodes
101 // mesh.face_barycenters(bary);
102 for (int f = 0; f < mesh.n_faces(); ++f)
103 {
104 // nodes_.row(face_offset_ + f) = bary.row(f);
105 for (int tmp = 0; tmp < max_nodes_per_face; ++tmp)
106 {
107 if (mesh.is_volume())
108 {
109 is_boundary_[face_offset_ + max_nodes_per_face * f + tmp] = mesh.is_boundary_face(f);
110 }
111 else
112 {
113 is_boundary_[face_offset_ + max_nodes_per_face * f + tmp] = false;
114 }
115 }
116 }
117 // Cell nodes
118 // mesh.cell_barycenters(bary);
119 for (int c = 0; c < mesh.n_cells(); ++c)
120 {
121 for (int tmp = 0; tmp < max_nodes_per_cell; ++tmp)
122 is_boundary_[cell_offset_ + max_nodes_per_cell * c + tmp] = false;
123 }
124 // }
125
126 // Vertices only, no need to compute interface marker
127 // if (vertices_only) { return; }
128
129 // Compute edges/faces that are at interface with a polytope
130 if (has_poly)
131 {
132 if (mesh.is_volume())
133 {
134 const Mesh3D *mesh3d = dynamic_cast<const Mesh3D *>(&mesh);
135 assert(mesh3d);
136 auto is_interface_face = interface_faces(*mesh3d);
137 for (int f = 0; f < mesh.n_faces(); ++f)
138 {
139 for (int tmp = 0; tmp < max_nodes_per_face; ++tmp)
140 is_interface_[face_offset_ + max_nodes_per_face * f + tmp] = is_interface_face[f];
141 }
142 }
143 else
144 {
145 const Mesh2D *mesh2d = dynamic_cast<const Mesh2D *>(&mesh);
146 assert(mesh2d);
147 auto is_interface_edge = interface_edges(*mesh2d);
148 for (int e = 0; e < mesh.n_edges(); ++e)
149 {
150 for (int tmp = 0; tmp < max_nodes_per_edge; ++tmp)
151 is_interface_[edge_offset_ + max_nodes_per_edge * e + tmp] = is_interface_edge[e];
152 }
153 }
154 }
155 }
156
158
160 {
161 if (primitive_to_node_[primitive_id] < 0 || !connect_nodes_)
162 {
163 primitive_to_node_[primitive_id] = n_nodes();
164
165 in_ordered_vertices_.push_back(primitive_id);
166 node_to_primitive_.push_back(primitive_id);
167 node_to_primitive_gid_.push_back(primitive_id);
168 assert(in_ordered_vertices_.size() == n_nodes());
169
170 if (primitive_id < edge_offset_)
171 nodes_.row(primitive_id) = mesh_.point(primitive_id);
172 else if (primitive_id < face_offset_)
173 nodes_.row(primitive_id) = mesh_.edge_barycenter(primitive_id - edge_offset_);
174 else if (primitive_id < cell_offset_)
175 nodes_.row(primitive_id) = mesh_.face_barycenter(primitive_id - face_offset_);
176 else
177 nodes_.row(primitive_id) = mesh_.cell_barycenter(primitive_id - cell_offset_);
178 }
179 return primitive_to_node_[primitive_id];
180 }
181
182 std::vector<int> MeshNodes::node_ids_from_edge(const Navigation::Index &index, const int n_new_nodes)
183 {
184 std::vector<int> res;
185 if (n_new_nodes <= 0)
186 return res;
187
188 const Mesh2D *mesh2d = dynamic_cast<const Mesh2D *>(&mesh_);
189 int start;
190
191 if (connect_nodes_)
192 start = edge_offset_ + index.edge * max_nodes_per_edge_;
193 else
194 {
195 if (mesh2d->is_boundary_edge(index.edge) || mesh2d->switch_face(index).face > index.face)
196 start = edge_offset_ + index.edge * max_nodes_per_edge_;
197 else
199 }
200
201 // const auto v1 = mesh2d->point(index.vertex);
202 // const auto v2 = mesh2d->point(mesh2d->switch_vertex(index).vertex);
203 assert(start < primitive_to_node_.size());
204 const int start_node_id = primitive_to_node_[start];
205#ifndef NDEBUG
206 if (!connect_nodes_)
207 {
208 assert(start_node_id < 0);
209 }
210#endif
211 if (start_node_id < 0 || !connect_nodes_)
212 {
213 for (int i = 1; i <= n_new_nodes; ++i)
214 {
215 // const double t = i/(n_new_nodes + 1.0);
216
217 const int primitive_id = start + i - 1;
218 assert(primitive_id < primitive_to_node_.size());
219
220 const auto [node, node_id] = mesh2d->edge_node(index, n_new_nodes, i);
221
222 primitive_to_node_[primitive_id] = n_nodes();
223
224 in_ordered_vertices_.push_back(node_id);
225 node_to_primitive_.push_back(primitive_id);
226 node_to_primitive_gid_.push_back(index.edge);
227
228 nodes_.row(primitive_id) = node;
229
230 res.push_back(primitive_to_node_[primitive_id]);
231 assert(in_ordered_vertices_.size() == n_nodes());
232 }
233 }
234 else
235 {
236 const auto [v, _] = mesh2d->edge_node(index, n_new_nodes, 1);
237
238 if ((node_position(start_node_id) - v).norm() < 1e-10)
239 {
240 for (int i = 0; i < n_new_nodes; ++i)
241 {
242 const int primitive_id = start + i;
243 res.push_back(primitive_to_node_[primitive_id]);
244 }
245 }
246 else
247 {
248 for (int i = n_new_nodes - 1; i >= 0; --i)
249 {
250 const int primitive_id = start + i;
251 res.push_back(primitive_to_node_[primitive_id]);
252 }
253 }
254 }
255
256 assert(res.size() == size_t(n_new_nodes));
257 return res;
258 }
259
260 std::vector<int> MeshNodes::node_ids_from_edge(const Navigation3D::Index &index, const int n_new_nodes)
261 {
262 std::vector<int> res;
263 if (n_new_nodes <= 0)
264 return res;
265
266 const int start = edge_offset_ + index.edge * max_nodes_per_edge_;
267
268 const Mesh3D *mesh3d = dynamic_cast<const Mesh3D *>(&mesh_);
269
270 const int start_node_id = primitive_to_node_[start];
271 if (start_node_id < 0)
272 {
273 for (int i = 1; i <= n_new_nodes; ++i)
274 {
275 const auto [node, node_id] = mesh3d->edge_node(index, n_new_nodes, i);
276
277 const int primitive_id = start + i - 1;
278 primitive_to_node_[primitive_id] = n_nodes();
279
280 in_ordered_vertices_.push_back(node_id);
281 node_to_primitive_.push_back(primitive_id);
282 node_to_primitive_gid_.push_back(index.edge);
283
284 nodes_.row(primitive_id) = node;
285
286 res.push_back(primitive_to_node_[primitive_id]);
287 assert(in_ordered_vertices_.size() == n_nodes());
288 }
289 }
290 else
291 {
292 const auto [v, _] = mesh3d->edge_node(index, n_new_nodes, 1);
293 if ((node_position(start_node_id) - v).norm() < 1e-10)
294 {
295 for (int i = 0; i < n_new_nodes; ++i)
296 {
297 const int primitive_id = start + i;
298 res.push_back(primitive_to_node_[primitive_id]);
299 }
300 }
301 else
302 {
303 for (int i = n_new_nodes - 1; i >= 0; --i)
304 {
305 const int primitive_id = start + i;
306 res.push_back(primitive_to_node_[primitive_id]);
307 }
308 }
309 }
310
311 assert(res.size() == size_t(n_new_nodes));
312 return res;
313 }
314
315 std::vector<int> MeshNodes::node_ids_from_face(const Navigation::Index &index, const int n_new_nodes)
316 {
317 std::vector<int> res;
318 if (n_new_nodes <= 0)
319 return res;
320
321 const int start = face_offset_ + index.face * max_nodes_per_face_;
322 const int start_node_id = primitive_to_node_[start];
323
324 const Mesh2D *mesh2d = dynamic_cast<const Mesh2D *>(&mesh_);
325
326 if (start_node_id < 0 || !connect_nodes_)
327 {
328 int loc_index = 0;
329 for (int i = 1; i <= n_new_nodes; ++i)
330 {
331 const int end = mesh2d->is_simplex(index.face) ? (n_new_nodes - i + 1) : n_new_nodes;
332 for (int j = 1; j <= end; ++j)
333 {
334 const auto [node, node_id] = mesh2d->face_node(index, n_new_nodes, i, j);
335
336 const int primitive_id = start + loc_index;
337 primitive_to_node_[primitive_id] = n_nodes();
338
339 in_ordered_vertices_.push_back(node_id);
340 node_to_primitive_.push_back(primitive_id);
341 node_to_primitive_gid_.push_back(index.face);
342
343 nodes_.row(primitive_id) = node;
344
345 res.push_back(primitive_to_node_[primitive_id]);
346
347 assert(in_ordered_vertices_.size() == n_nodes());
348
349 ++loc_index;
350 }
351 }
352 }
353 else
354 {
355 assert(false);
356 }
357
358#ifndef NDEBUG
359 if (mesh2d->is_simplex(index.face))
360 assert(res.size() == size_t(n_new_nodes * (n_new_nodes + 1) / 2));
361 else
362 assert(res.size() == size_t(n_new_nodes * n_new_nodes));
363#endif
364 return res;
365 }
366
367 std::vector<int> MeshNodes::node_ids_from_face(const Navigation3D::Index &index, const int n_new_nodes)
368 {
369 std::vector<int> res;
370 if (n_new_nodes <= 0)
371 return res;
372
373 const Mesh3D *mesh3d = dynamic_cast<const Mesh3D *>(&mesh_);
374 int start;
375 const bool is_tri = mesh3d->is_simplex(index.element) || (mesh3d->is_prism(index.element) && mesh3d->n_face_vertices(index.face) == 3);
376
377 if (connect_nodes_)
378 start = face_offset_ + index.face * max_nodes_per_face_;
379 else
380 {
381 if (mesh3d->is_boundary_face(index.face) || mesh3d->switch_element(index).element > index.element)
382 start = face_offset_ + index.face * max_nodes_per_face_;
383 else
385 }
386
387 const int start_node_id = primitive_to_node_[start];
388
389#ifndef NDEBUG
390 if (!connect_nodes_)
391 {
392 assert(start_node_id < 0);
393 }
394#endif
395
396 if (start_node_id < 0 || !connect_nodes_)
397 {
398 int loc_index = 0;
399 for (int i = 1; i <= n_new_nodes; ++i)
400 {
401 const int end = is_tri ? (n_new_nodes - i + 1) : n_new_nodes;
402 for (int j = 1; j <= end; ++j)
403 {
404 const int primitive_id = start + loc_index;
405 const auto [node, node_id] = mesh3d->face_node(index, n_new_nodes, i, j);
406
407 primitive_to_node_[primitive_id] = n_nodes();
408
409 in_ordered_vertices_.push_back(node_id);
410 node_to_primitive_.push_back(primitive_id);
411 node_to_primitive_gid_.push_back(index.face);
412
413 nodes_.row(primitive_id) = node;
414
415 res.push_back(primitive_to_node_[primitive_id]);
416 assert(in_ordered_vertices_.size() == n_nodes());
417
418 ++loc_index;
419 }
420 }
421 }
422 else
423 {
424 if (n_new_nodes == 1)
425 {
426 res.push_back(start_node_id);
427 }
428 else
429 {
430 const int total_nodes = is_tri ? (n_new_nodes * (n_new_nodes + 1) / 2) : (n_new_nodes * n_new_nodes);
431 for (int i = 1; i <= n_new_nodes; ++i)
432 {
433 const int end = is_tri ? (n_new_nodes - i + 1) : n_new_nodes;
434 for (int j = 1; j <= end; ++j)
435 {
436 const auto [p, _] = mesh3d->face_node(index, n_new_nodes, i, j);
437
438 bool found = false;
439 for (int k = start; k < start + total_nodes; ++k)
440 {
441 const double dist = (nodes_.row(k) - p).norm();
442 if (dist < 1e-10)
443 {
444 res.push_back(primitive_to_node_[k]);
445 found = true;
446 break;
447 }
448 }
449
450 assert(found);
451 }
452 }
453 }
454 }
455
456#ifndef NDEBUG
457 if (is_tri)
458 assert(res.size() == size_t(n_new_nodes * (n_new_nodes + 1) / 2));
459 else
460 assert(res.size() == size_t(n_new_nodes * n_new_nodes));
461#endif
462 return res;
463 }
464
465 std::vector<int> MeshNodes::node_ids_from_cell(const Navigation3D::Index &index, const int n_new_nodes)
466 {
467 std::vector<int> res;
468 const int start = cell_offset_ + index.element * max_nodes_per_cell_;
469 const Mesh3D *mesh3d = dynamic_cast<const Mesh3D *>(&mesh_);
470
471 if (mesh3d->is_simplex(index.element))
472 {
473 int loc_index = 0;
474 for (int i = 1; i <= n_new_nodes; ++i)
475 {
476 const int endj = (n_new_nodes - i + 1);
477 for (int j = 1; j <= endj; ++j)
478 {
479 const int endk = (n_new_nodes - i - j + 2);
480 for (int k = 1; k <= endk; ++k)
481 {
482 const int primitive_id = start + loc_index;
483
484 auto [node, node_id] = mesh3d->cell_node(index, n_new_nodes, i, j, k);
485
486 primitive_to_node_[primitive_id] = n_nodes();
487
488 in_ordered_vertices_.push_back(node_id);
489 node_to_primitive_.push_back(primitive_id);
490 node_to_primitive_gid_.push_back(index.element);
491
492 nodes_.row(primitive_id) = node;
493 res.push_back(primitive_to_node_[primitive_id]);
494 assert(in_ordered_vertices_.size() == n_nodes());
495
496 ++loc_index;
497 }
498 }
499 }
500 }
501 else if (mesh3d->is_cube(index.element))
502 {
503 int loc_index = 0;
504 for (int i = 1; i <= n_new_nodes; ++i)
505 {
506 for (int j = 1; j <= n_new_nodes; ++j)
507 {
508 for (int k = 1; k <= n_new_nodes; ++k)
509 {
510 const int primitive_id = start + loc_index;
511
512 const auto [node, node_id] = mesh3d->cell_node(index, n_new_nodes, i, j, k);
513 primitive_to_node_[primitive_id] = n_nodes();
514
515 in_ordered_vertices_.push_back(node_id);
516 node_to_primitive_.push_back(primitive_id);
517 node_to_primitive_gid_.push_back(index.element);
518
519 nodes_.row(primitive_id) = node;
520 res.push_back(primitive_to_node_[primitive_id]);
521 assert(in_ordered_vertices_.size() == n_nodes());
522
523 ++loc_index;
524 }
525 }
526 }
527 }
528 else if (mesh3d->is_prism(index.element))
529 {
530 // TODO: implement me internal prism nodes
531 log_and_throw_error("Prism internal nodes not implemented yet");
532 assert(false);
533 }
534
535#ifndef NDEBUG
536 if (res.size() == 1 && connect_nodes_)
537 {
538 const int idx = node_id_from_cell(index.element);
539 assert(idx == res.front());
540 }
541#endif
542
543#ifndef NDEBUG
544 if (mesh3d->is_simplex(index.element))
545 {
546 int n_cell_nodes = 0;
547 for (int pp = 0; pp <= n_new_nodes; ++pp)
548 n_cell_nodes += (pp * (pp + 1) / 2);
549 assert(res.size() == size_t(n_cell_nodes));
550 }
551 else if (mesh3d->is_cube(index.element))
552 assert(res.size() == size_t(n_new_nodes * n_new_nodes * n_new_nodes));
553#endif
554
555 return res;
556 }
557
559 {
560 return node_id_from_primitive(v);
561 }
562
567
572
577
579
580 int MeshNodes::vertex_from_node_id(int node_id) const
581 {
582 const int res = node_to_primitive_[node_id];
583 assert(res >= 0 && res < edge_offset_);
584 return res;
585 }
586
587 int MeshNodes::edge_from_node_id(int node_id) const
588 {
589 const int res = node_to_primitive_[node_id];
590 assert(res >= edge_offset_ && res < face_offset_);
591 return res - edge_offset_;
592 }
593
594 int MeshNodes::face_from_node_id(int node_id) const
595 {
596 const int res = node_to_primitive_[node_id];
597 assert(res >= face_offset_ && res < cell_offset_);
598 return res - face_offset_;
599 }
600
601 int MeshNodes::cell_from_node_id(int node_id) const
602 {
603 const int res = node_to_primitive_[node_id];
604 assert(res >= cell_offset_ && res < n_nodes());
605 return res - cell_offset_;
606 }
607
609
610 std::vector<int> MeshNodes::boundary_nodes() const
611 {
612 std::vector<int> res;
613 res.reserve(n_nodes());
614 for (size_t prim_id = 0; prim_id < primitive_to_node_.size(); ++prim_id)
615 {
616 int node_id = primitive_to_node_[prim_id];
617 if (node_id >= 0 && is_boundary_[prim_id])
618 {
619 res.push_back(node_id);
620 }
621 }
622 return res;
623 }
624
625 int MeshNodes::count_nonnegative_nodes(int start_i, int end_i) const
626 {
627 int count = 0;
628 for (int i = start_i; i < end_i; i++)
629 count += primitive_to_node_[i] >= 0;
630 return count;
631 }
632
633} // namespace polyfem::mesh
virtual std::pair< RowVectorNd, int > edge_node(const Navigation::Index &index, const int n_new_nodes, const int i) const =0
virtual std::pair< RowVectorNd, int > face_node(const Navigation::Index &index, const int n_new_nodes, const int i, const int j) const =0
virtual Navigation::Index switch_face(Navigation::Index idx) const =0
virtual Navigation3D::Index switch_element(Navigation3D::Index idx) const =0
std::pair< RowVectorNd, int > cell_node(const Navigation3D::Index &index, const int n_new_nodes, const int i, const int j, const int k) const
Definition Mesh3D.cpp:203
std::pair< RowVectorNd, int > face_node(const Navigation3D::Index &index, const int n_new_nodes, const int i, const int j) const
Definition Mesh3D.cpp:99
std::pair< RowVectorNd, int > edge_node(const Navigation3D::Index &index, const int n_new_nodes, const int i) const
Definition Mesh3D.cpp:80
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:40
virtual int n_vertices() const =0
number of vertices
virtual RowVectorNd edge_barycenter(const int e) const =0
edge barycenter
virtual RowVectorNd face_barycenter(const int f) const =0
face barycenter
bool is_cube(const int el_id) const
checks if element is cube compatible
Definition Mesh.cpp:352
virtual RowVectorNd point(const int global_index) const =0
point coordinates
virtual bool is_boundary_face(const int face_global_id) const =0
is face boundary
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:422
bool is_prism(const int el_id) const
checks if element is a prism
Definition Mesh.cpp:427
virtual bool is_volume() const =0
checks if mesh is volume
virtual bool is_boundary_edge(const int edge_global_id) const =0
is edge boundary
int dimension() const
utily for dimension
Definition Mesh.hpp:152
virtual int n_cells() const =0
number of cells
virtual int n_faces() const =0
number of faces
virtual RowVectorNd cell_barycenter(const int c) const =0
cell barycenter
virtual int n_edges() const =0
number of edges
virtual int n_face_vertices(const int f_id) const =0
number of vertices of a face
bool is_boundary(int node_id) const
Definition MeshNodes.hpp:70
int node_id_from_primitive(int primitive_id)
std::vector< int > primitive_to_node_
Definition MeshNodes.hpp:98
std::vector< int > node_ids_from_face(const Navigation::Index &index, const int n_new_nodes)
std::vector< int > node_ids_from_cell(const Navigation3D::Index &index, const int n_new_nodes)
int cell_from_node_id(int node_id) const
RowVectorNd node_position(int node_id) const
Definition MeshNodes.hpp:67
MeshNodes(const Mesh &mesh, const bool has_poly, const bool connect_nodes, const int max_nodes_per_edge, const int max_nodes_per_face, const int max_nodes_per_cell=0)
Definition MeshNodes.cpp:67
std::vector< int > node_to_primitive_gid_
Eigen::MatrixXd nodes_
std::vector< int > in_ordered_vertices_
int face_from_node_id(int node_id) const
int vertex_from_node_id(int node_id) const
int count_nonnegative_nodes(int start_i, int end_i) const
std::vector< int > boundary_nodes() const
int edge_from_node_id(int node_id) const
std::vector< int > node_to_primitive_
Definition MeshNodes.hpp:99
std::vector< int > node_ids_from_edge(const Navigation::Index &index, const int n_new_nodes)
std::vector< bool > is_boundary_
std::vector< bool > is_interface_
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73