libMesh
cell_polyhedron.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 <array>
27 #include <unordered_map>
28 #include <unordered_set>
29 
30 
31 namespace libMesh
32 {
33 
34 // ------------------------------------------------------------
35 // Polyhedron class static member initializations
36 const int Polyhedron::num_children;
37 
38 // ------------------------------------------------------------
39 // Polyhedron class member functions
40 
41 
42 Polyhedron::Polyhedron (const std::vector<std::shared_ptr<Polygon>> & sides,
43  Elem * p) :
44  Cell(/* unused here */ 0, sides.size(), p, nullptr, nullptr),
45  _elemlinks_data(sides.size()+2), // neighbors + parent + interior_parent
46  _nodelinks_data(0), // We'll have to resize *this* later too!
47  _sidelinks_data(sides.size())
48  {
49  // Set our sides, and while we're at it figure out our node maps
50  // and side normal directions and edge lookup table, and count our
51  // sides' nodes. If we have internal nodes too then the subclass
52  // will append those afterward.
53  unsigned int nn = 0;
54  std::unordered_map<Node *, unsigned int> local_node_number;
55  std::unordered_set<std::pair<const Node *, const Node *>,
56  libMesh::hash> edges_seen;
57  std::unique_ptr<const Elem> edge;
58  for (unsigned int s : index_range(sides))
59  {
60  libmesh_assert(sides[s].get());
61  auto & side_tuple = _sidelinks_data[s];
62  std::get<0>(side_tuple) = sides[s];
63 
64  Polygon & side = *sides[s]; // not const, for writeable nodes
65  for (auto n : make_range(side.n_nodes()))
66  {
67  Node * node = side.node_ptr(n);
68  if (auto it = local_node_number.find(node);
69  it != local_node_number.end())
70  {
71  std::get<2>(side_tuple).push_back(it->second);
72  }
73  else
74  {
75  std::get<2>(side_tuple).push_back(nn);
76  local_node_number[node] = nn++;
77  _nodelinks_data.push_back(node);
78  }
79  }
80 
81  for (unsigned int e : make_range(side.n_edges()))
82  {
83  side.build_edge_ptr(edge, e);
84  auto edge_vertices = std::make_pair(edge->node_ptr(0), edge->node_ptr(1));
85  if (edge_vertices.first > edge_vertices.second)
86  std::swap(edge_vertices.first, edge_vertices.second);
87 
88  if (!edges_seen.count(edge_vertices))
89  {
90  edges_seen.insert(edge_vertices);
91  _edge_lookup.emplace_back(s, e);
92  }
93  }
94  }
95 
96  // Do the manual initialization that Elem::Elem and Cell::Cell
97  // couldn't, now that we've resized both our vectors. No need to
98  // manually set nullptr, though, since std::vector does that.
99  this->_elemlinks = _elemlinks_data.data();
100  this->_nodes = _nodelinks_data.data();
101  this->_elemlinks[0] = p;
102 
103  libmesh_assert_equal_to(nn, this->n_nodes());
104 
105  // Figure out the orientation of our sides, now that we've got our
106  // nodes organized enough to find our center. The algorithm below
107  // only works for convex polyhedra, but that's all we're
108  // supporting for now.
109  Point center;
110  for (auto n : make_range(nn))
111  center.add (this->point(n));
112  center /= static_cast<Real>(nn);
113 
114  for (unsigned int s : index_range(sides))
115  {
116  const Polygon & side = *sides[s];
117  const Point x_i = side.point(0);
118  const Point n_i =
119  (side.point(1) - side.point(0)).cross
120  (side.point(0) - side.point(side.n_sides()-1)).unit();
121 
122  bool & inward_normal = std::get<1>(_sidelinks_data[s]);
123  inward_normal = (n_i * (center - x_i) > TOLERANCE);
124  }
125 
126  // We're betting a lot on "our polyhedra are all convex", so let's
127  // check that if we have time.
128 #ifdef DEBUG
129  for (unsigned int s : index_range(sides))
130  {
131  const Polygon & side = *sides[s];
132  const Point x_i = side.point(0);
133  const bool inward_normal = std::get<1>(this->_sidelinks_data[s]);
134 
135  const Point n_i =
136  (side.point(1) - side.point(0)).cross
137  (side.point(0) - side.point(side.n_sides()-1)).unit() *
138  (inward_normal ? -1 : 1);
139 
140  for (const Point & node : this->node_ref_range())
141  {
142  const Point d_n = node - x_i;
143  if (d_n * n_i > TOLERANCE * d_n.norm())
144  libmesh_not_implemented_msg
145  ("Cannot create a non-convex polyhedron");
146  }
147  }
148 #endif
149 
150  // Is this likely to ever be used? We may do refinement with
151  // polyhedra but it's probably not going to have a hierarchy...
152  if (p)
153  {
154  this->subdomain_id() = p->subdomain_id();
155  this->processor_id() = p->processor_id();
156  _map_type = p->mapping_type();
157  _map_data = p->mapping_data();
158 
159 #ifdef LIBMESH_ENABLE_AMR
160  this->set_p_level(p->p_level());
161 #endif
162  }
163 
164  // Make sure the interior parent isn't undefined
165  this->set_interior_parent(nullptr);
166  }
167 
168 
169 
170 Point Polyhedron::master_point (const unsigned int i) const
171 {
172  return this->point(i);
173 }
174 
175 
176 
178 {
179  for (unsigned int s : make_range(this->n_sides()))
180  {
181  const Polygon & side = *std::get<0>(this->_sidelinks_data[s]);
182  const Point x_i = side.point(0);
183  const bool inward_normal = std::get<1>(this->_sidelinks_data[s]);
184 
185  const Point n_i =
186  (side.point(1) - side.point(0)).cross
187  (side.point(0) - side.point(side.n_sides()-1)).unit() *
188  (inward_normal ? -1 : 1);
189 
190  for (const Point & node : this->node_ref_range())
191  {
192  const Point d_n = node - x_i;
193  if (d_n * n_i > TOLERANCE * d_n.norm())
194  return false;
195  }
196  }
197  return true;
198 }
199 
200 
201 
203  const Real eps) const
204 {
205  const unsigned int ns = this->n_sides();
206 
207  // Check that the point is on the same side of all the faces by
208  // testing whether:
209  //
210  // n_i.(p - x_i) <= 0
211  //
212  // for each i, where:
213  // n_i is the outward normal of face i,
214  // x_i is a point on face i.
215 
216  for (auto i : make_range(ns))
217  {
218  const Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
219  const bool inward_normal = std::get<1>(this->_sidelinks_data[i]);
220 
221  const Point x_i = face.point(0);
222 
223  const Point n_i =
224  (face.point(1) - face.point(0)).cross
225  (face.point(0) - face.point(face.n_sides()-1)).unit() *
226  (inward_normal ? -1 : 1);
227 
228  // This only works for polyhedra with flat sides.
229 #ifdef DEBUG
230  for (auto j : make_range(face.n_sides()-1))
231  {
232  const Point x_j = face.point(j+1);
233  const Point d_j = x_j - x_i;
234  if (std::abs(d_j * n_i) > eps * d_j.norm())
235  libmesh_not_implemented_msg
236  ("Polyhedra with non-flat sides are not fully supported.");
237  }
238 #endif
239 
240  if (n_i * (p - x_i) > eps)
241  return false;
242  }
243 
244  return true;
245 }
246 
247 
248 
249 dof_id_type Polyhedron::key (const unsigned int s) const
250 {
251  libmesh_assert_less (s, this->n_sides());
252 
253  const Polygon & face = *std::get<0>(this->_sidelinks_data[s]);
254 
255  return face.key();
256 }
257 
258 
259 
260 dof_id_type Polyhedron::low_order_key (const unsigned int s) const
261 {
262  libmesh_assert_less (s, this->n_sides());
263 
264  const Polygon & face = *std::get<0>(this->_sidelinks_data[s]);
265 
266  const unsigned int nv = face.n_vertices();
267  std::vector<dof_id_type> vertex_ids(nv);
268  for (unsigned int v : make_range(nv))
269  vertex_ids[v] = face.node_id(v);
270 
271  return Utility::hashword(vertex_ids);
272 }
273 
274 
275 
276 unsigned int Polyhedron::local_side_node(unsigned int side,
277  unsigned int side_node) const
278 {
279  libmesh_assert_less (side, this->n_sides());
280 
281  const std::vector<unsigned int> & node_map =
282  std::get<2>(this->_sidelinks_data[side]);
283  libmesh_assert_less (side_node, node_map.size());
284 
285  return node_map[side_node];
286 }
287 
288 
289 
290 unsigned int Polyhedron::local_edge_node(unsigned int edge,
291  unsigned int edge_node) const
292 {
293  libmesh_assert_less (edge, this->n_edges());
294  libmesh_assert_less (edge, _edge_lookup.size());
295 
296  auto [side, edge_of_side] = _edge_lookup[edge];
297 
298  const Polygon & face = *std::get<0>(this->_sidelinks_data[side]);
299 
300  const std::vector<unsigned int> & node_map =
301  std::get<2>(this->_sidelinks_data[side]);
302 
303  return node_map[face.local_edge_node(edge_of_side, edge_node)];
304 }
305 
306 
307 
309 {
310  std::vector<dof_id_type> node_ids;
311  for (const auto & n : this->node_ref_range())
312  node_ids.push_back(n.id());
313 
314  return Utility::hashword(node_ids);
315 }
316 
317 
318 
319 std::unique_ptr<Elem> Polyhedron::side_ptr (const unsigned int i)
320 {
321  libmesh_assert_less (i, this->n_sides());
322 
323  Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
324  std::unique_ptr<Elem> face_copy = face.disconnected_clone();
325  for (auto n : face.node_index_range())
326  face_copy->set_node(n, face.node_ptr(n));
327 
328  return face_copy;
329 }
330 
331 
332 
333 void Polyhedron::side_ptr (std::unique_ptr<Elem> & side,
334  const unsigned int i)
335 {
336  libmesh_assert_less (i, this->n_sides());
337 
338  // Polyhedra are irregular enough that we're not even going to try
339  // and bother optimizing heap access here.
340  side = this->side_ptr(i);
341 }
342 
343 
344 
345 std::unique_ptr<Elem> Polyhedron::build_side_ptr (const unsigned int i)
346 {
347  auto returnval = this->side_ptr(i);
348  returnval->set_interior_parent(this);
349  returnval->inherit_data_from(*this);
350  return returnval;
351 }
352 
353 
354 
355 void Polyhedron::build_side_ptr (std::unique_ptr<Elem> & side,
356  const unsigned int i)
357 {
358  this->side_ptr(side, i);
359  side->set_interior_parent(this);
360  side->inherit_data_from(*this);
361 }
362 
363 
364 
365 std::unique_ptr<Elem> Polyhedron::build_edge_ptr (const unsigned int i)
366 {
367  auto [s, se] = _edge_lookup[i];
368  Polygon & face = *std::get<0>(_sidelinks_data[s]);
369  return face.build_edge_ptr(se);
370 }
371 
372 
373 
374 void Polyhedron::build_edge_ptr (std::unique_ptr<Elem> & elem,
375  const unsigned int i)
376 {
377  auto [s, se] = _edge_lookup[i];
378  Polygon & face = *std::get<0>(_sidelinks_data[s]);
379  face.build_edge_ptr(elem, se);
380 }
381 
382 
383 
384 bool Polyhedron::is_child_on_side(const unsigned int /*c*/,
385  const unsigned int /*s*/) const
386 {
387  libmesh_not_implemented();
388  return false;
389 }
390 
391 
392 
393 unsigned int Polyhedron::opposite_side(const unsigned int /* side_in */) const
394 {
395  // This is too ambiguous in general.
396  libmesh_not_implemented();
397  return libMesh::invalid_uint;
398 }
399 
400 
401 
402 unsigned int Polyhedron::opposite_node(const unsigned int /* n */,
403  const unsigned int /* s */) const
404 {
405  // This is too ambiguous in general.
406  libmesh_not_implemented();
407  return libMesh::invalid_uint;
408 }
409 
410 
411 
413 {
414  if (this->_triangulation.empty())
415  return false;
416 
417  auto & tet = this->_triangulation[0];
418 
419  const Point v01 = this->point(tet[1]) - this->point(tet[0]);
420  const Point v02 = this->point(tet[2]) - this->point(tet[0]);
421  const Point v03 = this->point(tet[3]) - this->point(tet[0]);
422 
423  return (triple_product(v01, v02, v03) < 0);
424 }
425 
426 
427 std::vector<unsigned int>
428 Polyhedron::edges_adjacent_to_node(const unsigned int n) const
429 {
430  libmesh_assert_less(n, this->n_nodes());
431 
432  // For mid-edge or mid-face nodes, the subclass had better have
433  // overridden this.
434  libmesh_assert_less(n, this->n_vertices());
435 
436  const unsigned int ne = this->n_edges();
437  libmesh_assert_equal_to(ne, _edge_lookup.size());
438 
439  std::vector<unsigned int> adjacent_edges;
440 
441  unsigned int next_edge = 0;
442 
443  // Look for any adjacent edges on each side. Make use of the fact
444  // that we number our edges in order as we encounter them from each
445  // side.
446  for (auto t : index_range(_sidelinks_data))
447  {
448  const Polygon & face = *std::get<0>(_sidelinks_data[t]);
449  const std::vector<unsigned int> & node_map =
450  std::get<2>(_sidelinks_data[t]);
451 
452  while (_edge_lookup[next_edge].first < t)
453  {
454  ++next_edge;
455  if (next_edge == ne)
456  return adjacent_edges;
457  }
458 
459  // If we haven't seen the next edge on this or an earlier side
460  // then we might as well go on to the next.
461  if (_edge_lookup[next_edge].first > t)
462  continue;
463 
464  const unsigned int fnv = face.n_vertices();
465  libmesh_assert_equal_to(fnv, face.n_edges());
466  libmesh_assert_equal_to(fnv, face.n_sides());
467  libmesh_assert_less_equal(fnv, node_map.size());
468 
469  // Polygon faces have one edge per vertex
470  for (auto v : make_range(fnv))
471  {
472  libmesh_assert_equal_to (_edge_lookup[next_edge].first, t);
473 
474  if (_edge_lookup[next_edge].second > v)
475  continue;
476 
477  while (_edge_lookup[next_edge].first == t &&
478  _edge_lookup[next_edge].second < v)
479  {
480  ++next_edge;
481  if (next_edge == ne)
482  return adjacent_edges;
483  }
484 
485  if (_edge_lookup[next_edge].first > t)
486  break;
487 
488  const unsigned int vn = node_map[v];
489  const unsigned int vnp = node_map[(v+1)%fnv];
490  libmesh_assert_less(vn, this->n_vertices());
491  libmesh_assert_less(vnp, this->n_vertices());
492  if (vn == n || vnp == n)
493  adjacent_edges.push_back(next_edge);
494  }
495  }
496 
497  return adjacent_edges;
498 }
499 
500 
501 std::pair<Real, Real> Polyhedron::qual_bounds (const ElemQuality q) const
502 {
503  std::pair<Real, Real> bounds;
504 
505  switch (q)
506  {
507  case EDGE_LENGTH_RATIO:
508  bounds.first = 1.;
509  bounds.second = 4.;
510  break;
511 
512  case MIN_ANGLE:
513  bounds.first = 30.;
514  bounds.second = 180.;
515  break;
516 
517  case MAX_ANGLE:
518  bounds.first = 60.;
519  bounds.second = 180.;
520  break;
521 
522  case JACOBIAN:
523  case SCALED_JACOBIAN:
524  bounds.first = 0.5;
525  bounds.second = 1.;
526  break;
527 
528  default:
529  libMesh::out << "Warning: Invalid quality measure chosen." << std::endl;
530  bounds.first = -1;
531  bounds.second = -1;
532  }
533 
534  return bounds;
535 }
536 
537 
538 
539 std::vector<std::shared_ptr<Polygon>>
541 {
542  const auto ns = this->n_sides();
543 
544  libmesh_assert_equal_to(ns, _sidelinks_data.size());
545 
546  std::vector<std::shared_ptr<Polygon>> cloned_sides(ns);
547 
548  for (auto i : make_range(ns))
549  {
550  const Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
551 
552  Elem * clone = face.disconnected_clone().release();
553  Polygon * polygon_clone = cast_ptr<Polygon *>(clone);
554  cloned_sides[i] = std::shared_ptr<Polygon>(polygon_clone);
555 
556  // We can't actually use a *disconnected* clone to reconstruct
557  // links between sides, so we'll temporarily give the clone our
558  // own nodes; user code that typically replaces the usual
559  // nullptr with permanent nodes will then instead place our
560  // nodes with permanent nodes.
561  for (auto n : make_range(face.n_nodes()))
562  cloned_sides[i]->set_node
563  (n, const_cast<Node *>(face.node_ptr(n)));
564  }
565 
566  return cloned_sides;
567 }
568 
569 
570 
572  unsigned int min_node,
573  unsigned int max_node) const
574 {
575  const Polygon & face = *std::get<0>(_sidelinks_data[s]);
576  const std::vector<unsigned int> & node_map =
577  std::get<2>(this->_sidelinks_data[s]);
578 
579  for (unsigned int e : make_range(face.n_sides()))
580  {
581  std::vector<unsigned int> nodes_on_edge =
582  face.nodes_on_side(e);
583  libmesh_assert_equal_to(nodes_on_edge.size(), 2);
584  nodes_on_edge[0] = node_map[nodes_on_edge[0]];
585  nodes_on_edge[1] = node_map[nodes_on_edge[1]];
586  if ((nodes_on_edge[0] == min_node) &&
587  (nodes_on_edge[1] == max_node))
588  return true;
589  if ((nodes_on_edge[1] == min_node) &&
590  (nodes_on_edge[0] == max_node))
591  return true;
592  }
593 
594  return false;
595 }
596 
597 
598 
599 std::vector<unsigned int>
600 Polyhedron::sides_on_edge(const unsigned int e) const
601 {
602  std::vector<unsigned int> returnval(2);
603  auto [s1, s1e] = _edge_lookup[e];
604  returnval[0] = s1;
605 
606  const Polygon & face1 = *std::get<0>(_sidelinks_data[s1]);
607  const std::vector<unsigned int> & node_map =
608  std::get<2>(this->_sidelinks_data[s1]);
609 
610  std::vector<unsigned int> nodes_on_edge =
611  face1.nodes_on_side(s1e);
612  libmesh_assert_equal_to(nodes_on_edge.size(), 2);
613  nodes_on_edge[0] = node_map[nodes_on_edge[0]];
614  nodes_on_edge[1] = node_map[nodes_on_edge[1]];
615 
616  if (nodes_on_edge[0] > nodes_on_edge[1])
617  std::swap(nodes_on_edge[0], nodes_on_edge[1]);
618 
619  for (unsigned int s2 : make_range(this->n_sides()))
620  {
621  if (s2 == s1)
622  continue;
623 
624  if (this->side_has_edge_nodes(s2, nodes_on_edge[0],
625  nodes_on_edge[1]))
626  {
627  returnval[1] = s2;
628  return returnval;
629  }
630  }
631 
632  libmesh_error();
633 
634  return returnval;
635 }
636 
637 
638 
639 bool Polyhedron::is_edge_on_side(const unsigned int e,
640  const unsigned int s) const
641 {
642  auto [s1, s1e] = _edge_lookup[e];
643 
644  // Did we get lucky with our cache?
645  if (s1 == s)
646  return true;
647 
648  const Polygon & face1 = *std::get<0>(_sidelinks_data[s1]);
649  const std::vector<unsigned int> & node_map =
650  std::get<2>(this->_sidelinks_data[s1]);
651  std::vector<unsigned int> nodes_on_edge1 =
652  face1.nodes_on_side(s1e);
653  libmesh_assert_equal_to(nodes_on_edge1.size(), 2);
654 
655  nodes_on_edge1[0] = node_map[nodes_on_edge1[0]];
656  nodes_on_edge1[1] = node_map[nodes_on_edge1[1]];
657  if (nodes_on_edge1[0] > nodes_on_edge1[1])
658  std::swap(nodes_on_edge1[0], nodes_on_edge1[1]);
659 
660  return this->side_has_edge_nodes(s,
661  nodes_on_edge1[0],
662  nodes_on_edge1[1]);
663 }
664 
665 
666 
667 std::array<Point, 4> Polyhedron::master_subelement (unsigned int i) const
668 {
669  libmesh_assert_less(i, this->_triangulation.size());
670 
671  const auto & tet = this->_triangulation[i];
672 
673  return { this->master_point(tet[0]),
674  this->master_point(tet[1]),
675  this->master_point(tet[2]),
676  this->master_point(tet[3]) };
677 }
678 
679 
680 std::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
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
unsigned char mapping_data() const
Definition: elem.h:3136
virtual unsigned int n_nodes() const override
virtual unsigned int n_nodes() const override
Definition: face_polygon.h:78
unsigned char _map_type
Mapping function type; currently either 0 (LAGRANGE) or 1 (RATIONAL_BERNSTEIN).
Definition: elem.h:2297
unsigned char _map_data
Mapping function data; currently used when needed to store the RATIONAL_BERNSTEIN nodal weight data i...
Definition: elem.h:2303
std::vector< Elem * > _elemlinks_data
Data for links to parent/neighbor/interior_parent elements.
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2558
A Node is like a Point, but with more information.
Definition: node.h:52
Node ** _nodes
Pointers to the nodes we are connected to.
Definition: elem.h:2245
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:907
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:310
std::vector< Node * > _nodelinks_data
Data for links to nodes.
virtual unsigned int opposite_side(const unsigned int s) const override final
Throws an error.
virtual dof_id_type key() const override
Definition: face_polygon.C:200
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 ...
static constexpr Real TOLERANCE
virtual std::array< Point, 4 > master_subelement(unsigned int i) const
std::vector< std::tuple< std::shared_ptr< Polygon >, bool, std::vector< unsigned int > > > _sidelinks_data
Data for links to sides.
virtual std::pair< Real, Real > qual_bounds(const ElemQuality q) const override
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const override final
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
static const int num_children
unsigned int p_level() const
Definition: elem.h:3108
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...
The libMesh namespace provides an interface to certain functionality in the library.
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
Calls local_side_node(edge, edge_node).
Definition: face_polygon.C:192
virtual unsigned int n_sides() const override final
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i) override final
void set_interior_parent(Elem *p)
Sets the pointer to the element&#39;s interior_parent.
Definition: elem.C:1248
void add(const TypeVector< T2 > &)
Add to this vector without creating a temporary.
Definition: type_vector.h:605
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...
virtual unsigned int n_edges() const override final
Definition: face_polygon.h:94
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval=0)
The hashword function takes an array of uint32_t&#39;s of length &#39;length&#39; and computes a single key from ...
Definition: hashword.h:158
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...
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
Definition: type_vector.h:1029
TypeVector< T > unit() const
Definition: type_vector.h:1104
std::tuple< unsigned int, Real, Real, Real > subelement_coordinates(const Point &p, Real tol=TOLERANCE *TOLERANCE) const
ElemMappingType mapping_type() const
Definition: elem.h:3120
virtual bool is_flipped() const override final
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
unsigned int n_subelements() const
virtual dof_id_type low_order_key(const unsigned int s) const override
The Polygon is an element in 2D with an arbitrary (but fixed) number of sides.
Definition: face_polygon.h:39
Elem ** _elemlinks
Pointers to this element&#39;s parent and neighbors, and for lower-dimensional elements&#39; interior_parent...
Definition: elem.h:2251
The Cell is an abstract element type that lives in three dimensions.
Definition: cell.h:38
libmesh_assert(ctx)
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. ...
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Copies the Polygon side coincident with side i.
ElemQuality
Defines an enum for element quality metrics.
virtual std::unique_ptr< Elem > disconnected_clone() const
Definition: elem.C:412
virtual dof_id_type key() const override
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int) const =0
SimpleRange< NodeRefIter > node_ref_range()
Returns a range with all nodes of an element, usable in range-based for loops.
Definition: elem.h:2665
std::vector< std::shared_ptr< Polygon > > side_clones() const
virtual Point master_point(const unsigned int i) const override
virtual unsigned int n_edges() const override final
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
virtual unsigned int n_vertices() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual unsigned int n_vertices() const override final
Definition: face_polygon.h:89
subdomain_id_type subdomain_id() const
Definition: elem.h:2582
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2507
OStreamProxy out
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:140
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2683
virtual unsigned int n_sides() const override final
Definition: face_polygon.h:84
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
std::vector< std::array< int, 4 > > _triangulation
Data for a triangulation (tetrahedralization) of the polyhedron.
processor_id_type processor_id() const
Definition: dof_object.h:905
virtual std::vector< unsigned int > sides_on_edge(const unsigned int e) const override final
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:2475
const Point & point(const unsigned int i) const
Definition: elem.h:2453
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:117
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
uint8_t dof_id_type
Definition: id_types.h:67
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