libMesh
Loading...
Searching...
No Matches
cell_polyhedron.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18#include "libmesh/cell_polyhedron.h"
19
20// Local includes
21#include "libmesh/face_polygon.h"
22#include "libmesh/enum_elem_quality.h"
23#include "libmesh/hashword.h"
24
25// C++ includes
26#include <algorithm>
27#include <array>
28#include <unordered_map>
29#include <unordered_set>
30
31
32namespace libMesh
33{
34
35// ------------------------------------------------------------
36// Polyhedron class static member initializations
38
39// ------------------------------------------------------------
40// Polyhedron class member functions
41
42
43Polyhedron::Polyhedron (const std::vector<std::shared_ptr<Polygon>> & sides,
44 Elem * p) :
45 Cell(/* unused here */ 0, sides.size(), p, nullptr, nullptr),
46 _elemlinks_data(sides.size()+2), // neighbors + parent + interior_parent
47 _nodelinks_data(0), // We'll have to resize *this* later too!
48 _sidelinks_data(sides.size())
49 {
50 // Set our sides, and while we're at it figure out our node maps
51 // and side normal directions and edge lookup table, and count our
52 // sides' nodes. If we have internal nodes too then the subclass
53 // will append those afterward.
54 unsigned int nn = 0;
55 std::unordered_map<Node *, unsigned int> local_node_number;
56 std::unordered_set<std::pair<const Node *, const Node *>,
57 libMesh::hash> edges_seen;
58 std::unique_ptr<const Elem> edge;
59 for (unsigned int s : index_range(sides))
60 {
61 libmesh_assert(sides[s].get());
62 auto & side_tuple = _sidelinks_data[s];
63 std::get<0>(side_tuple) = sides[s];
64
65 Polygon & side = *sides[s]; // not const, for writeable nodes
66 for (auto n : make_range(side.n_nodes()))
67 {
68 Node * node = side.node_ptr(n);
69 if (auto it = local_node_number.find(node);
70 it != local_node_number.end())
71 {
72 std::get<2>(side_tuple).push_back(it->second);
73 }
74 else
75 {
76 std::get<2>(side_tuple).push_back(nn);
77 local_node_number[node] = nn++;
78 _nodelinks_data.push_back(node);
79 }
80 }
81
82 for (unsigned int e : make_range(side.n_edges()))
83 {
84 side.build_edge_ptr(edge, e);
85 auto edge_vertices = std::make_pair(edge->node_ptr(0), edge->node_ptr(1));
86 if (edge_vertices.first > edge_vertices.second)
87 std::swap(edge_vertices.first, edge_vertices.second);
88
89 if (!edges_seen.count(edge_vertices))
90 {
91 edges_seen.insert(edge_vertices);
92 _edge_lookup.emplace_back(s, e);
93 }
94 }
95 }
96
97 // Plan room for an extra node so we don't invalidate this->_nodes when we add to
98 // nodelinks_data in the derived class
99 _nodelinks_data.reserve(_nodelinks_data.size() + 1);
100
101 // Do the manual initialization that Elem::Elem and Cell::Cell
102 // couldn't, now that we've resized both our vectors. No need to
103 // manually set nullptr, though, since std::vector does that.
104 this->_elemlinks = _elemlinks_data.data();
105 this->_nodes = _nodelinks_data.data();
106 this->_elemlinks[0] = p;
107
108 libmesh_assert_equal_to(nn, this->n_nodes());
109
110 // Figure out the orientation of our sides, now that we've got our
111 // nodes organized enough to find our center. The algorithm below
112 // only works for convex polyhedra, but that's all we're
113 // supporting for now.
114 Point center;
115 for (auto n : make_range(nn))
116 center.add (this->point(n));
117 center /= static_cast<Real>(nn);
118
119 for (unsigned int s : index_range(sides))
120 {
121 const Polygon & side = *sides[s];
122 const Point x_i = side.point(0);
123 const Point n_i =
124 (side.point(1) - side.point(0)).cross
125 (side.point(0) - side.point(side.n_sides()-1)).unit();
126
127 bool & inward_normal = std::get<1>(_sidelinks_data[s]);
128 inward_normal = (n_i * (center - x_i) > TOLERANCE);
129 }
130
131 // We're betting a lot on "our polyhedra are all convex", so let's
132 // check that if we have time.
133#ifdef DEBUG
134 for (unsigned int s : index_range(sides))
135 {
136 const Polygon & side = *sides[s];
137 const Point x_i = side.point(0);
138 const bool inward_normal = std::get<1>(this->_sidelinks_data[s]);
139
140 const Point n_i =
141 (side.point(1) - side.point(0)).cross
142 (side.point(0) - side.point(side.n_sides()-1)).unit() *
143 (inward_normal ? -1 : 1);
144
145 for (const Point & node : this->node_ref_range())
146 {
147 const Point d_n = node - x_i;
148 if (d_n * n_i > TOLERANCE * d_n.norm())
149 libmesh_not_implemented_msg
150 ("Cannot create a non-convex polyhedron");
151 }
152 }
153#endif
154
155 // Is this likely to ever be used? We may do refinement with
156 // polyhedra but it's probably not going to have a hierarchy...
157 if (p)
158 {
159 this->subdomain_id() = p->subdomain_id();
160 this->processor_id() = p->processor_id();
161 _map_type = p->mapping_type();
162 _map_data = p->mapping_data();
163
164#ifdef LIBMESH_ENABLE_AMR
165 this->set_p_level(p->p_level());
166#endif
167 }
168
169 // Make sure the interior parent isn't undefined
170 this->set_interior_parent(nullptr);
171 }
172
173
174
175Point Polyhedron::master_point (const unsigned int i) const
176{
177 return this->point(i);
178}
179
180
181
183{
184 for (unsigned int s : make_range(this->n_sides()))
185 {
186 const Polygon & side = *std::get<0>(this->_sidelinks_data[s]);
187 const Point x_i = side.point(0);
188 const bool inward_normal = std::get<1>(this->_sidelinks_data[s]);
189
190 const Point n_i =
191 (side.point(1) - side.point(0)).cross
192 (side.point(0) - side.point(side.n_sides()-1)).unit() *
193 (inward_normal ? -1 : 1);
194
195 for (const Point & node : this->node_ref_range())
196 {
197 const Point d_n = node - x_i;
198 if (d_n * n_i > TOLERANCE * d_n.norm())
199 return false;
200 }
201 }
202 return true;
203}
204
205
206
208 const Real eps) const
209{
210 const unsigned int ns = this->n_sides();
211
212 // Check that the point is on the same side of all the faces by
213 // testing whether:
214 //
215 // n_i.(p - x_i) <= 0
216 //
217 // for each i, where:
218 // n_i is the outward normal of face i,
219 // x_i is a point on face i.
220
221 for (auto i : make_range(ns))
222 {
223 const Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
224 const bool inward_normal = std::get<1>(this->_sidelinks_data[i]);
225
226 const Point x_i = face.point(0);
227
228 const Point n_i =
229 (face.point(1) - face.point(0)).cross
230 (face.point(0) - face.point(face.n_sides()-1)).unit() *
231 (inward_normal ? -1 : 1);
232
233 // This only works for polyhedra with flat sides.
234#ifdef DEBUG
235 for (auto j : make_range(face.n_sides()-1))
236 {
237 const Point x_j = face.point(j+1);
238 const Point d_j = x_j - x_i;
239 if (std::abs(d_j * n_i) > eps * d_j.norm())
240 libmesh_not_implemented_msg
241 ("Polyhedra with non-flat sides are not fully supported.");
242 }
243#endif
244
245 if (n_i * (p - x_i) > eps)
246 return false;
247 }
248
249 return true;
250}
251
252
253
254dof_id_type Polyhedron::key (const unsigned int s) const
255{
256 libmesh_assert_less (s, this->n_sides());
257
258 const Polygon & face = *std::get<0>(this->_sidelinks_data[s]);
259
260 return face.key();
261}
262
263
264
265dof_id_type Polyhedron::low_order_key (const unsigned int s) const
266{
267 libmesh_assert_less (s, this->n_sides());
268
269 const Polygon & face = *std::get<0>(this->_sidelinks_data[s]);
270
271 const unsigned int nv = face.n_vertices();
272 std::vector<dof_id_type> vertex_ids(nv);
273 for (unsigned int v : make_range(nv))
274 vertex_ids[v] = face.node_id(v);
275
276 // Sort the vertex ids before hashing so the key is independent of the
277 // order in which the face's vertices are stored, just like
278 // Elem::compute_key() does for every other element type. This is
279 // essential for find_neighbors(): two polyhedra sharing a face
280 // generally wind that face in opposite orders (each orienting it
281 // outward from its own cell), so without sorting the two sides would
282 // hash to different keys, never get compared, and never be linked as
283 // neighbors.
284 std::sort(vertex_ids.begin(), vertex_ids.end());
285
286 return Utility::hashword(vertex_ids);
287}
288
289
290
291unsigned int Polyhedron::local_side_node(unsigned int side,
292 unsigned int side_node) const
293{
294 libmesh_assert_less (side, this->n_sides());
295
296 const std::vector<unsigned int> & node_map =
297 std::get<2>(this->_sidelinks_data[side]);
298 libmesh_assert_less (side_node, node_map.size());
299
300 return node_map[side_node];
301}
302
303
304
305unsigned int Polyhedron::local_edge_node(unsigned int edge,
306 unsigned int edge_node) const
307{
308 libmesh_assert_less (edge, this->n_edges());
309 libmesh_assert_less (edge, _edge_lookup.size());
310
311 auto [side, edge_of_side] = _edge_lookup[edge];
312
313 const Polygon & face = *std::get<0>(this->_sidelinks_data[side]);
314
315 const std::vector<unsigned int> & node_map =
316 std::get<2>(this->_sidelinks_data[side]);
317
318 return node_map[face.local_edge_node(edge_of_side, edge_node)];
319}
320
321
322
324{
325 std::vector<dof_id_type> node_ids;
326 for (const auto & n : this->node_ref_range())
327 node_ids.push_back(n.id());
328
329 return Utility::hashword(node_ids);
330}
331
332
333
334std::unique_ptr<Elem> Polyhedron::side_ptr (const unsigned int i)
335{
336 return const_cast<const Polyhedron *>(this)->side_ptr(i);
337}
338
339
340
341std::unique_ptr<Elem> Polyhedron::side_ptr (const unsigned int i) const
342{
343 libmesh_assert_less (i, this->n_sides());
344
345 Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
346 std::unique_ptr<Elem> face_copy = face.disconnected_clone();
347 for (auto n : face.node_index_range())
348 face_copy->set_node(n, face.node_ptr(n));
349
350 return face_copy;
351}
352
353
354
355void Polyhedron::side_ptr (std::unique_ptr<Elem> & side,
356 const unsigned int i)
357{
358 libmesh_assert_less (i, this->n_sides());
359
360 // Polyhedra are irregular enough that we're not even going to try
361 // and bother optimizing heap access here.
362 side = this->side_ptr(i);
363}
364
365
366
367std::unique_ptr<Elem> Polyhedron::build_side_ptr (const unsigned int i)
368{
369 auto returnval = this->side_ptr(i);
370 returnval->set_interior_parent(this);
371 returnval->inherit_data_from(*this);
372 return returnval;
373}
374
375
376
377void Polyhedron::build_side_ptr (std::unique_ptr<Elem> & side,
378 const unsigned int i)
379{
380 this->side_ptr(side, i);
381 side->set_interior_parent(this);
382 side->inherit_data_from(*this);
383}
384
385
386
387std::unique_ptr<Elem> Polyhedron::build_edge_ptr (const unsigned int i)
388{
389 auto [s, se] = _edge_lookup[i];
390 Polygon & face = *std::get<0>(_sidelinks_data[s]);
391 return face.build_edge_ptr(se);
392}
393
394
395
396void Polyhedron::build_edge_ptr (std::unique_ptr<Elem> & elem,
397 const unsigned int i)
398{
399 auto [s, se] = _edge_lookup[i];
400 Polygon & face = *std::get<0>(_sidelinks_data[s]);
401 face.build_edge_ptr(elem, se);
402}
403
404
405
406bool Polyhedron::is_child_on_side(const unsigned int /*c*/,
407 const unsigned int /*s*/) const
408{
409 libmesh_not_implemented();
410 return false;
411}
412
413
414
415unsigned int Polyhedron::opposite_side(const unsigned int /* side_in */) const
416{
417 // This is too ambiguous in general.
418 libmesh_not_implemented();
420}
421
422
423
424unsigned int Polyhedron::opposite_node(const unsigned int /* n */,
425 const unsigned int /* s */) const
426{
427 // This is too ambiguous in general.
428 libmesh_not_implemented();
430}
431
432
433
435{
436 if (this->_triangulation.empty())
437 return false;
438
439 auto & tet = this->_triangulation[0];
440
441 const Point v01 = this->point(tet[1]) - this->point(tet[0]);
442 const Point v02 = this->point(tet[2]) - this->point(tet[0]);
443 const Point v03 = this->point(tet[3]) - this->point(tet[0]);
444
445 return (triple_product(v01, v02, v03) < 0);
446}
447
448
449std::vector<unsigned int>
450Polyhedron::edges_adjacent_to_node(const unsigned int n) const
451{
452 libmesh_assert_less(n, this->n_nodes());
453
454 // For mid-edge or mid-face nodes, the subclass had better have
455 // overridden this.
456 libmesh_assert_less(n, this->n_vertices());
457
458 libmesh_assert_equal_to(this->n_edges(), _edge_lookup.size());
459
460 std::vector<unsigned int> adjacent_edges;
461
462 for (const auto edge : index_range(_edge_lookup))
463 {
464 const auto [side, side_edge] = _edge_lookup[edge];
465 const Polygon & face = *std::get<0>(_sidelinks_data[side]);
466 const std::vector<unsigned int> & node_map =
467 std::get<2>(_sidelinks_data[side]);
468
469 const unsigned int fnv = face.n_vertices();
470 libmesh_assert_equal_to(fnv, face.n_edges());
471 libmesh_assert_equal_to(fnv, face.n_sides());
472 libmesh_assert_less_equal(fnv, node_map.size());
473 libmesh_assert_less(side_edge, fnv);
474
475 const unsigned int vn = node_map[side_edge];
476 const unsigned int vnp = node_map[(side_edge + 1) % fnv];
477 libmesh_assert_less(vn, this->n_vertices());
478 libmesh_assert_less(vnp, this->n_vertices());
479 if (vn == n || vnp == n)
480 adjacent_edges.push_back(edge);
481 }
482
483 return adjacent_edges;
484}
485
486
487std::pair<Real, Real> Polyhedron::qual_bounds (const ElemQuality q) const
488{
489 std::pair<Real, Real> bounds;
490
491 switch (q)
492 {
494 bounds.first = 1.;
495 bounds.second = 4.;
496 break;
497
498 case MIN_ANGLE:
499 bounds.first = 30.;
500 bounds.second = 180.;
501 break;
502
503 case MAX_ANGLE:
504 bounds.first = 60.;
505 bounds.second = 180.;
506 break;
507
508 // The generic dihedral metrics measure the unoriented angle
509 // between adjacent face planes, so their values are in [0, 90].
510 // Use the same recommended lower bounds as MIN,MAX_ANGLE.
512 bounds.first = 30.;
513 bounds.second = 90.;
514 break;
515
517 bounds.first = 60.;
518 bounds.second = 90.;
519 break;
520
521 case JACOBIAN:
522 case SCALED_JACOBIAN:
523 bounds.first = 0.5;
524 bounds.second = 1.;
525 break;
526
527 default:
528 libmesh_warning("Invalid quality measure chosen.");
529 bounds.first = -1;
530 bounds.second = -1;
531 }
532
533 return bounds;
534}
535
536
537
538std::vector<std::shared_ptr<Polygon>>
540{
541 const auto ns = this->n_sides();
542
543 libmesh_assert_equal_to(ns, _sidelinks_data.size());
544
545 std::vector<std::shared_ptr<Polygon>> cloned_sides(ns);
546
547 for (auto i : make_range(ns))
548 {
549 const Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
550
551 Elem * clone = face.disconnected_clone().release();
552 Polygon * polygon_clone = cast_ptr<Polygon *>(clone);
553 cloned_sides[i] = std::shared_ptr<Polygon>(polygon_clone);
554
555 // We can't actually use a *disconnected* clone to reconstruct
556 // links between sides, so we'll temporarily give the clone our
557 // own nodes; user code that typically replaces the usual
558 // nullptr with permanent nodes will then instead place our
559 // nodes with permanent nodes.
560 for (auto n : make_range(face.n_nodes()))
561 cloned_sides[i]->set_node
562 (n, const_cast<Node *>(face.node_ptr(n)));
563 }
564
565 return cloned_sides;
566}
567
568
569
571 unsigned int min_node,
572 unsigned int max_node) const
573{
574 const Polygon & face = *std::get<0>(_sidelinks_data[s]);
575 const std::vector<unsigned int> & node_map =
576 std::get<2>(this->_sidelinks_data[s]);
577
578 for (unsigned int e : make_range(face.n_sides()))
579 {
580 std::vector<unsigned int> nodes_on_edge =
581 face.nodes_on_side(e);
582 libmesh_assert_equal_to(nodes_on_edge.size(), 2);
583 nodes_on_edge[0] = node_map[nodes_on_edge[0]];
584 nodes_on_edge[1] = node_map[nodes_on_edge[1]];
585 if ((nodes_on_edge[0] == min_node) &&
586 (nodes_on_edge[1] == max_node))
587 return true;
588 if ((nodes_on_edge[1] == min_node) &&
589 (nodes_on_edge[0] == max_node))
590 return true;
591 }
592
593 return false;
594}
595
596
597
598std::vector<unsigned int>
599Polyhedron::sides_on_edge(const unsigned int e) const
600{
601 std::vector<unsigned int> returnval(2);
602 auto [s1, s1e] = _edge_lookup[e];
603 returnval[0] = s1;
604
605 const Polygon & face1 = *std::get<0>(_sidelinks_data[s1]);
606 const std::vector<unsigned int> & node_map =
607 std::get<2>(this->_sidelinks_data[s1]);
608
609 std::vector<unsigned int> nodes_on_edge =
610 face1.nodes_on_side(s1e);
611 libmesh_assert_equal_to(nodes_on_edge.size(), 2);
612 nodes_on_edge[0] = node_map[nodes_on_edge[0]];
613 nodes_on_edge[1] = node_map[nodes_on_edge[1]];
614
615 if (nodes_on_edge[0] > nodes_on_edge[1])
616 std::swap(nodes_on_edge[0], nodes_on_edge[1]);
617
618 for (unsigned int s2 : make_range(this->n_sides()))
619 {
620 if (s2 == s1)
621 continue;
622
623 if (this->side_has_edge_nodes(s2, nodes_on_edge[0],
624 nodes_on_edge[1]))
625 {
626 returnval[1] = s2;
627 return returnval;
628 }
629 }
630
631 libmesh_error();
632
633 return returnval;
634}
635
636
637
638bool Polyhedron::is_edge_on_side(const unsigned int e,
639 const unsigned int s) const
640{
641 auto [s1, s1e] = _edge_lookup[e];
642
643 // Did we get lucky with our cache?
644 if (s1 == s)
645 return true;
646
647 const Polygon & face1 = *std::get<0>(_sidelinks_data[s1]);
648 const std::vector<unsigned int> & node_map =
649 std::get<2>(this->_sidelinks_data[s1]);
650 std::vector<unsigned int> nodes_on_edge1 =
651 face1.nodes_on_side(s1e);
652 libmesh_assert_equal_to(nodes_on_edge1.size(), 2);
653
654 nodes_on_edge1[0] = node_map[nodes_on_edge1[0]];
655 nodes_on_edge1[1] = node_map[nodes_on_edge1[1]];
656 if (nodes_on_edge1[0] > nodes_on_edge1[1])
657 std::swap(nodes_on_edge1[0], nodes_on_edge1[1]);
658
659 return this->side_has_edge_nodes(s,
660 nodes_on_edge1[0],
661 nodes_on_edge1[1]);
662}
663
664
665
666std::array<Point, 4> Polyhedron::master_subelement (unsigned int i) const
667{
668 libmesh_assert_less(i, this->_triangulation.size());
669
670 const auto & tet = this->_triangulation[i];
671
672 return { this->master_point(tet[0]),
673 this->master_point(tet[1]),
674 this->master_point(tet[2]),
675 this->master_point(tet[3]) };
676}
677
678
679
680std::tuple<unsigned int, Real, Real, Real>
682{
683 std::tuple<unsigned int, Real, Real, Real> returnval =
684 {libMesh::invalid_uint, -1, -1, -1};
685
686 Real best_bad_coord = -1;
687
688 for (auto s : make_range(this->n_subelements()))
689 {
690 const std::array<Point, 4> subtet =
691 this->master_subelement(s);
692
693 // Find barycentric coordinates in subelem
694 const Point v0 = p - subtet[0];
695 // const Point v1 = p - subtet[1];
696
697 const Point v01 = subtet[1] - subtet[0];
698 const Point v02 = subtet[2] - subtet[0];
699 const Point v03 = subtet[3] - subtet[0];
700
701 // const Point v12 = subtet[2] - subtet[1];
702 // const Point v13 = subtet[3] - subtet[1];
703
704 // const Real tp0 = triple_product(v1, v13, v12);
705 const Real tp1 = triple_product(v0, v02, v03);
706 const Real tp2 = triple_product(v0, v03, v01);
707 const Real tp3 = triple_product(v0, v01, v02);
708
709 const Real six_vol = triple_product(v01, v02, v03);
710
711 const Real xi = tp1 / six_vol;
712 const Real eta = tp2 / six_vol;
713 const Real zeta = tp3 / six_vol;
714
715 if (xi>=0 && eta>=0 && zeta>=0 && xi+eta+zeta<=1)
716 return { s, xi, eta, zeta };
717
718 const Real my_best_bad_coord =
719 std::min(std::min(std::min(xi, eta), zeta), 1-xi-eta-zeta);
720
721 if (my_best_bad_coord > best_bad_coord)
722 {
723 best_bad_coord = my_best_bad_coord;
724 returnval = { s, xi, eta, zeta };
725 }
726 }
727
728 if (best_bad_coord > -tol)
729 return returnval;
730
731 return {libMesh::invalid_uint, -1, -1, -1};
732}
733
734
735} // namespace libMesh
The Cell is an abstract element type that lives in three dimensions.
Definition cell.h:39
processor_id_type processor_id() const
Definition dof_object.h:895
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual std::unique_ptr< Elem > disconnected_clone() const
Definition elem.C:350
virtual Node *& set_node(const unsigned int i)
Definition elem.h:2688
unsigned char mapping_data() const
Definition elem.h:3274
virtual unsigned int n_vertices() const =0
const Point & point(const unsigned int i) const
Definition elem.h:2583
SimpleRange< NodeRefIter > node_ref_range()
Returns a range with all nodes of an element, usable in range-based for loops.
Definition elem.h:2803
Node ** _nodes
Pointers to the nodes we are connected to.
Definition elem.h:2375
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
void set_interior_parent(Elem *p)
Sets the pointer to the element's interior_parent.
Definition elem.C:1162
unsigned char _map_data
Mapping function data; currently used when needed to store the RATIONAL_BERNSTEIN nodal weight data i...
Definition elem.h:2433
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int) const =0
subdomain_id_type subdomain_id() const
Definition elem.h:2712
Elem ** _elemlinks
Pointers to this element's parent and neighbors, and for lower-dimensional elements' interior_parent.
Definition elem.h:2381
unsigned char _map_type
Mapping function type; currently either 0 (LAGRANGE) or 1 (RATIONAL_BERNSTEIN).
Definition elem.h:2427
ElemMappingType mapping_type() const
Definition elem.h:3258
const Node * node_ptr(const unsigned int i) const
Definition elem.h:2637
IntRange< unsigned short > node_index_range() const
Definition elem.h:2821
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2605
unsigned int p_level() const
Definition elem.h:3246
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i) override final
build_side and build_edge are identical for faces.
Definition face.h:72
A Node is like a Point, but with more information.
Definition node.h:55
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
The Polygon is an element in 2D with an arbitrary (but fixed) number of sides.
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
Calls local_side_node(edge, edge_node).
virtual dof_id_type key() const override
virtual unsigned int n_edges() const override final
virtual unsigned int n_nodes() const override
virtual unsigned int n_sides() const override final
virtual unsigned int n_vertices() const override final
The Polyhedron is an element in 3D with an arbitrary number of polygonal faces.
virtual std::array< Point, 4 > master_subelement(unsigned int i) const
virtual unsigned int n_edges() const override final
virtual Point master_point(const unsigned int i) const override
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Copies the Polygon side coincident with side i.
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
virtual std::vector< unsigned int > sides_on_edge(const unsigned int e) const override final
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
virtual unsigned int opposite_side(const unsigned int s) const override final
Throws an error.
virtual dof_id_type low_order_key(const unsigned int s) const override
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
virtual bool is_flipped() const override final
virtual unsigned int n_nodes() const override
unsigned int n_subelements() const
Polyhedron(const std::vector< std::shared_ptr< Polygon > > &sides, Elem *p)
Arbitrary polyhedral element, takes a vector of shared pointers to sides (which should already be con...
virtual unsigned int opposite_node(const unsigned int n, const unsigned int s) const override final
Throws an error - opposite_side(s) is too hard to define in general on polyhedra.
static const int num_children
std::vector< Elem * > _elemlinks_data
Data for links to parent/neighbor/interior_parent elements.
virtual unsigned int n_sides() const override final
virtual dof_id_type key() const override
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const override final
std::tuple< unsigned int, Real, Real, Real > subelement_coordinates(const Point &p, Real tol=TOLERANCE *TOLERANCE) const
std::vector< std::shared_ptr< Polygon > > side_clones() const
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i) override final
std::vector< std::pair< unsigned int, unsigned int > > _edge_lookup
One entry for each polyhedron edge, a pair indicating the side number and the edge-of-side number whi...
std::vector< Node * > _nodelinks_data
Data for links to nodes.
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
Similar to Elem::local_side_node(), but instead of a side id, takes an edge id and a node id on that ...
virtual std::pair< Real, Real > qual_bounds(const ElemQuality q) const override
std::vector< std::tuple< std::shared_ptr< Polygon >, bool, std::vector< unsigned int > > > _sidelinks_data
Data for links to sides.
std::vector< std::array< int, 4 > > _triangulation
Data for a triangulation (tetrahedralization) of the polyhedron.
bool side_has_edge_nodes(unsigned int side, unsigned int min_node, unsigned int max_node) const
Helper method for finding the non-cached side that shares an edge, by examining the local node ids th...
LIBMESH_DEVICE_INLINE TypeVector< T > unit() const
auto norm() const
void add(const TypeVector< T2 > &)
Add to this vector without creating a temporary.
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval=0)
The hashword function takes an array of uint32_t's of length 'length' and computes a single key from ...
Definition hashword.h:158
The libMesh namespace provides an interface to certain functionality in the library.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
LIBMESH_DEVICE_INLINE T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
libmesh_assert(ctx)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition libmesh.h:303
ElemQuality
Defines an enum for element quality metrics.
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176