libMesh
cell_pyramid18.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 
19 // Local includes
20 #include "libmesh/cell_pyramid18.h"
21 #include "libmesh/edge_edge3.h"
22 #include "libmesh/face_tri7.h"
23 #include "libmesh/face_quad9.h"
24 #include "libmesh/enum_io_package.h"
25 #include "libmesh/enum_order.h"
26 
27 namespace libMesh
28 {
29 
30 
31 
32 
33 // ------------------------------------------------------------
34 // Pyramid18 class static member initializations
35 const int Pyramid18::num_nodes;
38 
40  {
41  {0, 1, 4, 5, 10, 9, 14, 99, 99}, // Side 0 (front)
42  {1, 2, 4, 6, 11, 10, 15, 99, 99}, // Side 1 (right)
43  {2, 3, 4, 7, 12, 11, 16, 99, 99}, // Side 2 (back)
44  {3, 0, 4, 8, 9, 12, 17, 99, 99}, // Side 3 (left)
45  {0, 3, 2, 1, 8, 7, 6, 5, 13} // Side 4 (base)
46  };
47 
49  {
50  {0, 1, 5}, // Edge 0
51  {1, 2, 6}, // Edge 1
52  {2, 3, 7}, // Edge 2
53  {0, 3, 8}, // Edge 3
54  {0, 4, 9}, // Edge 4
55  {1, 4, 10}, // Edge 5
56  {2, 4, 11}, // Edge 6
57  {3, 4, 12} // Edge 7
58  };
59 
60 // ------------------------------------------------------------
61 // Pyramid18 class member functions
62 
63 bool Pyramid18::is_vertex(const unsigned int i) const
64 {
65  if (i < 5)
66  return true;
67  return false;
68 }
69 
70 
71 
72 bool Pyramid18::is_edge(const unsigned int i) const
73 {
74  if (i < 5)
75  return false;
76  if (i > 12)
77  return false;
78  return true;
79 }
80 
81 
82 
83 bool Pyramid18::is_face(const unsigned int i) const
84 {
85  if (i > 12)
86  return true;
87  return false;
88 }
89 
90 
91 
92 bool Pyramid18::is_node_on_side(const unsigned int n,
93  const unsigned int s) const
94 {
95  libmesh_assert_less (s, n_sides());
96  return std::find(std::begin(side_nodes_map[s]),
97  std::end(side_nodes_map[s]),
98  n) != std::end(side_nodes_map[s]);
99 }
100 
101 std::vector<unsigned>
102 Pyramid18::nodes_on_side(const unsigned int s) const
103 {
104  libmesh_assert_less(s, n_sides());
105  auto trim = (s == 4) ? 0 : 2;
106  return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s]) - trim};
107 }
108 
109 std::vector<unsigned>
110 Pyramid18::nodes_on_edge(const unsigned int e) const
111 {
112  libmesh_assert_less(e, n_edges());
113  return {std::begin(edge_nodes_map[e]), std::end(edge_nodes_map[e])};
114 }
115 
116 bool Pyramid18::is_node_on_edge(const unsigned int n,
117  const unsigned int e) const
118 {
119  libmesh_assert_less (e, n_edges());
120  return std::find(std::begin(edge_nodes_map[e]),
121  std::end(edge_nodes_map[e]),
122  n) != std::end(edge_nodes_map[e]);
123 }
124 
125 
126 
128 {
129  // TODO: If the base is a parallelogram and all the triangular faces are planar,
130  // the map should be linear, but I need to test this theory...
131  return false;
132 }
133 
134 
135 
137 {
138  return THIRD;
139 }
140 
141 
142 
143 dof_id_type Pyramid18::key (const unsigned int s) const
144 {
145  libmesh_assert_less (s, this->n_sides());
146 
147  switch (s)
148  {
149  case 0: // triangular face 1
150  case 1: // triangular face 2
151  case 2: // triangular face 3
152  case 3: // triangular face 4
153  return this->compute_key (this->node_id(s+14));
154 
155  case 4: // the quad face at z=0
156  return this->compute_key (this->node_id(13));
157 
158  default:
159  libmesh_error_msg("Invalid side s = " << s);
160  }
161 }
162 
163 
164 
165 unsigned int Pyramid18::local_side_node(unsigned int side,
166  unsigned int side_node) const
167 {
168  libmesh_assert_less (side, this->n_sides());
169 
170  // Never more than 9 nodes per side.
171  libmesh_assert_less(side_node, Pyramid18::nodes_per_side);
172 
173  // Some sides have 7 nodes.
174  libmesh_assert(side == 4 || side_node < 7);
175 
176  return Pyramid18::side_nodes_map[side][side_node];
177 }
178 
179 
180 
181 unsigned int Pyramid18::local_edge_node(unsigned int edge,
182  unsigned int edge_node) const
183 {
184  libmesh_assert_less(edge, this->n_edges());
185  libmesh_assert_less(edge_node, Pyramid18::nodes_per_edge);
186 
187  return Pyramid18::edge_nodes_map[edge][edge_node];
188 }
189 
190 
191 
192 std::unique_ptr<Elem> Pyramid18::build_side_ptr (const unsigned int i)
193 {
194  libmesh_assert_less (i, this->n_sides());
195 
196  std::unique_ptr<Elem> face;
197 
198  switch (i)
199  {
200  case 0: // triangular face 1
201  case 1: // triangular face 2
202  case 2: // triangular face 3
203  case 3: // triangular face 4
204  {
205  face = std::make_unique<Tri7>();
206  break;
207  }
208  case 4: // the quad face at z=0
209  {
210  face = std::make_unique<Quad9>();
211  break;
212  }
213  default:
214  libmesh_error_msg("Invalid side i = " << i);
215  }
216 
217  // Set the nodes
218  for (auto n : face->node_index_range())
219  face->set_node(n, this->node_ptr(Pyramid18::side_nodes_map[i][n]));
220 
221  face->set_interior_parent(this);
222  face->inherit_data_from(*this);
223 
224  return face;
225 }
226 
227 
228 
229 void Pyramid18::build_side_ptr (std::unique_ptr<Elem> & side,
230  const unsigned int i)
231 {
232  libmesh_assert_less (i, this->n_sides());
233 
234  switch (i)
235  {
236  case 0: // triangular face 1
237  case 1: // triangular face 2
238  case 2: // triangular face 3
239  case 3: // triangular face 4
240  {
241  if (!side.get() || side->type() != TRI7)
242  {
243  side = this->build_side_ptr(i);
244  return;
245  }
246  break;
247  }
248  case 4: // the quad face at z=0
249  {
250  if (!side.get() || side->type() != QUAD9)
251  {
252  side = this->build_side_ptr(i);
253  return;
254  }
255  break;
256  }
257  default:
258  libmesh_error_msg("Invalid side i = " << i);
259  }
260 
261  side->inherit_data_from(*this);
262 
263  // Set the nodes
264  for (auto n : side->node_index_range())
265  side->set_node(n, this->node_ptr(Pyramid18::side_nodes_map[i][n]));
266 }
267 
268 
269 
270 std::unique_ptr<Elem> Pyramid18::build_edge_ptr (const unsigned int i)
271 {
272  return this->simple_build_edge_ptr<Edge3,Pyramid18>(i);
273 }
274 
275 
276 
277 void Pyramid18::build_edge_ptr (std::unique_ptr<Elem> & edge, const unsigned int i)
278 {
279  this->simple_build_edge_ptr<Pyramid18>(edge, i, EDGE3);
280 }
281 
282 
283 
284 void Pyramid18::connectivity(const unsigned int libmesh_dbg_var(sc),
285  const IOPackage iop,
286  std::vector<dof_id_type> & /*conn*/) const
287 {
289  libmesh_assert_less (sc, this->n_sub_elem());
290  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
291 
292  switch (iop)
293  {
294  case TECPLOT:
295  {
296  // TODO
297  libmesh_not_implemented();
298  }
299 
300  case VTK:
301  {
302  // TODO
303  libmesh_not_implemented();
304  }
305 
306  default:
307  libmesh_error_msg("Unsupported IO package " << iop);
308  }
309 }
310 
311 
312 
313 unsigned int Pyramid18::n_second_order_adjacent_vertices (const unsigned int n) const
314 {
315  switch (n)
316  {
317  case 5:
318  case 6:
319  case 7:
320  case 8:
321  case 9:
322  case 10:
323  case 11:
324  case 12:
325  return 2;
326 
327  case 13:
328  return 4;
329 
330  case 14:
331  case 15:
332  case 16:
333  case 17:
334  return 3;
335 
336  default:
337  libmesh_error_msg("Invalid node n = " << n);
338  }
339 }
340 
341 
342 unsigned short int Pyramid18::second_order_adjacent_vertex (const unsigned int n,
343  const unsigned int v) const
344 {
345  libmesh_assert_greater_equal (n, this->n_vertices());
346  libmesh_assert_less (n, this->n_nodes());
347 
348  switch (n)
349  {
350  case 5:
351  case 6:
352  case 7:
353  case 8:
354  case 9:
355  case 10:
356  case 11:
357  case 12:
358  {
359  libmesh_assert_less (v, 2);
360 
361  // This is the analog of the static, const arrays
362  // {Hex,Prism,Tet10}::_second_order_adjacent_vertices
363  // defined in the respective source files... possibly treat
364  // this similarly once the Pyramid13 has been added?
365  constexpr unsigned short node_list[8][2] =
366  {
367  {0,1},
368  {1,2},
369  {2,3},
370  {0,3},
371  {0,4},
372  {1,4},
373  {2,4},
374  {3,4}
375  };
376 
377  return node_list[n-5][v];
378  }
379 
380  // mid-face node on bottom
381  case 13:
382  {
383  libmesh_assert_less (v, 4);
384 
385  // The vertex nodes surrounding node 13 are 0, 1, 2, and 3.
386  // Thus, the v'th node is simply = v.
387  return cast_int<unsigned short>(v);
388  }
389 
390  // mid-face nodes on triangles
391  case 14:
392  case 15:
393  case 16:
394  case 17:
395  {
396  libmesh_assert_less (v, 3);
397 
398  constexpr unsigned short node_list[4][3] =
399  {
400  {0,1,4},
401  {1,2,4},
402  {2,3,4},
403  {0,3,4}
404  };
405 
406  return node_list[n-14][v];
407  }
408 
409  default:
410  libmesh_error_msg("Invalid n = " << n);
411 
412  }
413 }
414 
415 
416 
417 void Pyramid18::permute(unsigned int perm_num)
418 {
419  libmesh_assert_less (perm_num, 4);
420 
421  for (unsigned int i = 0; i != perm_num; ++i)
422  {
423  swap4nodes(0,1,2,3);
424  swap4nodes(5,6,7,8);
425  swap4nodes(9,10,11,12);
426  swap4nodes(14,15,16,17);
427  swap4neighbors(0,1,2,3);
428  }
429 }
430 
431 
432 void Pyramid18::flip(BoundaryInfo * boundary_info)
433 {
434  libmesh_assert(boundary_info);
435 
436  swap2nodes(0,1);
437  swap2nodes(2,3);
438  swap2nodes(6,8);
439  swap2nodes(9,10);
440  swap2nodes(11,12);
441  swap2nodes(15,17);
442  swap2neighbors(1,3);
443  swap2boundarysides(1,3,boundary_info);
444  swap2boundaryedges(1,3,boundary_info);
445  swap2boundaryedges(4,5,boundary_info);
446  swap2boundaryedges(6,7,boundary_info);
447 }
448 
449 
450 unsigned int Pyramid18::center_node_on_side(const unsigned short side) const
451 {
452  libmesh_assert_less (side, Pyramid18::num_sides);
453  return side == 4 ? 13 : side+14;
454 }
455 
456 
457 ElemType Pyramid18::side_type (const unsigned int s) const
458 {
459  libmesh_assert_less (s, 5);
460  if (s < 4)
461  return TRI7;
462  return QUAD9;
463 }
464 
465 
466 } // namespace libMesh
ElemType
Defines an enum for geometric element types.
void swap2boundaryedges(unsigned short e1, unsigned short e2, BoundaryInfo *boundary_info) const
Swaps two edges in boundary_info, if it is non-null.
Definition: elem.C:3550
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
Node ** _nodes
Pointers to the nodes we are connected to.
Definition: elem.h:2245
static const int num_edges
Definition: cell_pyramid.h:78
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the node of the side to element node numbers.
virtual dof_id_type key() const
Definition: elem.C:753
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
unsigned int center_node_on_side(const unsigned short side) const override final
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the node of the edge to element node numbers.
IOPackage
libMesh interfaces with several different software packages for the purposes of creating, reading, and writing mesh files.
virtual void flip(BoundaryInfo *) override final
Flips the element (by swapping node and neighbor pointers) to have a mapping Jacobian of opposite sig...
virtual unsigned int n_second_order_adjacent_vertices(const unsigned int n) const override
virtual bool is_edge(const unsigned int i) const override
static const int nodes_per_side
virtual unsigned int n_sub_elem() const override
FIXME: we don&#39;t yet have a refinement pattern for pyramids...
void swap2boundarysides(unsigned short s1, unsigned short s2, BoundaryInfo *boundary_info) const
Swaps two sides in boundary_info, if it is non-null.
Definition: elem.C:3534
virtual unsigned int n_sides() const override
Definition: cell_pyramid.h:90
The libMesh namespace provides an interface to certain functionality in the library.
static const int num_nodes
Geometric constants for Pyramid18.
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const override
virtual unsigned int n_nodes() const override
virtual unsigned int n_vertices() const override
Definition: cell_pyramid.h:95
virtual void permute(unsigned int perm_num) override final
Permutes the element (by swapping node and neighbor pointers) according to the specified index...
void swap4nodes(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four node_ptrs, "rotating" them.
Definition: elem.h:2143
void swap2nodes(unsigned int n1, unsigned int n2)
Swaps two node_ptrs.
Definition: elem.h:2092
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
virtual bool has_affine_map() const override
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
libmesh_assert(ctx)
virtual bool is_face(const unsigned int i) const override
static const int num_sides
Geometric constants for all Pyramids.
Definition: cell_pyramid.h:77
void swap2neighbors(unsigned int n1, unsigned int n2)
Swaps two neighbor_ptrs.
Definition: elem.h:2102
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i) override
Builds a EDGE3 coincident with edge i.
virtual void connectivity(const unsigned int sc, const IOPackage iop, std::vector< dof_id_type > &conn) const override
virtual unsigned int n_edges() const override
Definition: cell_pyramid.h:100
static const int nodes_per_edge
void swap4neighbors(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four neighbor_ptrs, "rotating" them.
Definition: elem.h:2153
ElemType side_type(const unsigned int s) const override final
static dof_id_type compute_key(dof_id_type n0)
Definition: elem.h:3294
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
virtual Order default_order() const override
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Builds a QUAD9 or TRI7 coincident with face i.
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:2475
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const override
virtual bool is_vertex(const unsigned int i) const override
uint8_t dof_id_type
Definition: id_types.h:67