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