libMesh
cell_tet10.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2024 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/side.h"
21 #include "libmesh/cell_tet10.h"
22 #include "libmesh/edge_edge3.h"
23 #include "libmesh/face_tri6.h"
24 #include "libmesh/enum_io_package.h"
25 #include "libmesh/enum_order.h"
26 
27 namespace libMesh
28 {
29 
30 
31 
32 // ------------------------------------------------------------
33 // Tet10 class static member initializations
34 const int Tet10::num_nodes;
35 const int Tet10::num_sides;
36 const int Tet10::num_edges;
37 const int Tet10::num_children;
38 const int Tet10::nodes_per_side;
39 const int Tet10::nodes_per_edge;
40 
42  {
43  {0, 2, 1, 6, 5, 4}, // Side 0
44  {0, 1, 3, 4, 8, 7}, // Side 1
45  {1, 2, 3, 5, 9, 8}, // Side 2
46  {2, 0, 3, 6, 7, 9} // Side 3
47  };
48 
50  {
51  {0, 1, 4}, // Edge 0
52  {1, 2, 5}, // Edge 1
53  {0, 2, 6}, // Edge 2
54  {0, 3, 7}, // Edge 3
55  {1, 3, 8}, // Edge 4
56  {2, 3, 9} // Edge 5
57  };
58 
59 // ------------------------------------------------------------
60 // Tet10 class member functions
61 
62 bool Tet10::is_vertex(const unsigned int i) const
63 {
64  if (i < 4)
65  return true;
66  return false;
67 }
68 
69 bool Tet10::is_edge(const unsigned int i) const
70 {
71  if (i < 4)
72  return false;
73  return true;
74 }
75 
76 bool Tet10::is_face(const unsigned int) const
77 {
78  return false;
79 }
80 
81 bool Tet10::is_node_on_side(const unsigned int n,
82  const unsigned int s) const
83 {
84  libmesh_assert_less (s, n_sides());
85  return std::find(std::begin(side_nodes_map[s]),
86  std::end(side_nodes_map[s]),
87  n) != std::end(side_nodes_map[s]);
88 }
89 
90 std::vector<unsigned>
91 Tet10::nodes_on_side(const unsigned int s) const
92 {
93  libmesh_assert_less(s, n_sides());
94  return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s])};
95 }
96 
97 std::vector<unsigned>
98 Tet10::nodes_on_edge(const unsigned int e) const
99 {
100  libmesh_assert_less(e, n_edges());
101  return {std::begin(edge_nodes_map[e]), std::end(edge_nodes_map[e])};
102 }
103 
104 bool Tet10::is_node_on_edge(const unsigned int n,
105  const unsigned int e) const
106 {
107  libmesh_assert_less (e, n_edges());
108  return std::find(std::begin(edge_nodes_map[e]),
109  std::end(edge_nodes_map[e]),
110  n) != std::end(edge_nodes_map[e]);
111 }
112 
113 
114 #ifdef LIBMESH_ENABLE_AMR
115 
116 // This function only works if LIBMESH_ENABLE_AMR...
117 bool Tet10::is_child_on_side(const unsigned int c,
118  const unsigned int s) const
119 {
120  // Table of local IDs for the midege nodes on the side opposite a given node.
121  // See the ASCII art in the header file for this class to confirm this.
122  const unsigned int midedge_nodes_opposite[4][3] =
123  {
124  {5,8,9}, // midedge nodes opposite node 0
125  {6,7,9}, // midedge nodes opposite node 1
126  {4,7,8}, // midedge nodes opposite node 2
127  {4,5,6} // midedge nodes opposite node 3
128  };
129 
130  // Call the base class helper function
131  return Tet::is_child_on_side_helper(c, s, midedge_nodes_opposite);
132 }
133 
134 #else
135 
136 bool Tet10::is_child_on_side(const unsigned int /*c*/,
137  const unsigned int /*s*/) const
138 {
139  libmesh_not_implemented();
140  return false;
141 }
142 
143 #endif //LIBMESH_ENABLE_AMR
144 
145 
146 
148 {
149  // Make sure edges are straight
150  Point v = this->point(1) - this->point(0);
151  if (!v.relative_fuzzy_equals
152  ((this->point(4) - this->point(0))*2, affine_tol))
153  return false;
154  v = this->point(2) - this->point(1);
155  if (!v.relative_fuzzy_equals
156  ((this->point(5) - this->point(1))*2, affine_tol))
157  return false;
158  v = this->point(2) - this->point(0);
159  if (!v.relative_fuzzy_equals
160  ((this->point(6) - this->point(0))*2, affine_tol))
161  return false;
162  v = this->point(3) - this->point(0);
163  if (!v.relative_fuzzy_equals
164  ((this->point(7) - this->point(0))*2, affine_tol))
165  return false;
166  v = this->point(3) - this->point(1);
167  if (!v.relative_fuzzy_equals
168  ((this->point(8) - this->point(1))*2, affine_tol))
169  return false;
170  v = this->point(3) - this->point(2);
171  if (!v.relative_fuzzy_equals
172  ((this->point(9) - this->point(2))*2, affine_tol))
173  return false;
174  return true;
175 }
176 
177 
178 
180 {
181  return SECOND;
182 }
183 
184 
185 
186 unsigned int Tet10::local_side_node(unsigned int side,
187  unsigned int side_node) const
188 {
189  libmesh_assert_less (side, this->n_sides());
190  libmesh_assert_less (side_node, Tet10::nodes_per_side);
191 
192  return Tet10::side_nodes_map[side][side_node];
193 }
194 
195 
196 
197 unsigned int Tet10::local_edge_node(unsigned int edge,
198  unsigned int edge_node) const
199 {
200  libmesh_assert_less (edge, this->n_edges());
201  libmesh_assert_less (edge_node, Tet10::nodes_per_edge);
202 
203  return Tet10::edge_nodes_map[edge][edge_node];
204 }
205 
206 
207 
208 std::unique_ptr<Elem> Tet10::build_side_ptr (const unsigned int i,
209  bool proxy)
210 {
211  return this->simple_build_side_ptr<Tri6, Tet10>(i, proxy);
212 }
213 
214 
215 
216 void Tet10::build_side_ptr (std::unique_ptr<Elem> & side,
217  const unsigned int i)
218 {
219  this->simple_build_side_ptr<Tet10>(side, i, TRI6);
220 }
221 
222 
223 
224 std::unique_ptr<Elem> Tet10::build_edge_ptr (const unsigned int i)
225 {
226  return this->simple_build_edge_ptr<Edge3,Tet10>(i);
227 }
228 
229 
230 
231 void Tet10::build_edge_ptr (std::unique_ptr<Elem> & edge, const unsigned int i)
232 {
233  this->simple_build_edge_ptr<Tet10>(edge, i, EDGE3);
234 }
235 
236 
237 
238 void Tet10::connectivity(const unsigned int sc,
239  const IOPackage iop,
240  std::vector<dof_id_type> & conn) const
241 {
243  libmesh_assert_less (sc, this->n_sub_elem());
244  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
245 
246  switch (iop)
247  {
248  case TECPLOT:
249  {
250  conn.resize(8);
251  switch (sc)
252  {
253 
254 
255  // Linear sub-tet 0
256  case 0:
257 
258  conn[0] = this->node_id(0)+1;
259  conn[1] = this->node_id(4)+1;
260  conn[2] = this->node_id(6)+1;
261  conn[3] = this->node_id(6)+1;
262  conn[4] = this->node_id(7)+1;
263  conn[5] = this->node_id(7)+1;
264  conn[6] = this->node_id(7)+1;
265  conn[7] = this->node_id(7)+1;
266 
267  return;
268 
269  // Linear sub-tet 1
270  case 1:
271 
272  conn[0] = this->node_id(4)+1;
273  conn[1] = this->node_id(1)+1;
274  conn[2] = this->node_id(5)+1;
275  conn[3] = this->node_id(5)+1;
276  conn[4] = this->node_id(8)+1;
277  conn[5] = this->node_id(8)+1;
278  conn[6] = this->node_id(8)+1;
279  conn[7] = this->node_id(8)+1;
280 
281  return;
282 
283  // Linear sub-tet 2
284  case 2:
285 
286  conn[0] = this->node_id(5)+1;
287  conn[1] = this->node_id(2)+1;
288  conn[2] = this->node_id(6)+1;
289  conn[3] = this->node_id(6)+1;
290  conn[4] = this->node_id(9)+1;
291  conn[5] = this->node_id(9)+1;
292  conn[6] = this->node_id(9)+1;
293  conn[7] = this->node_id(9)+1;
294 
295  return;
296 
297  // Linear sub-tet 3
298  case 3:
299 
300  conn[0] = this->node_id(7)+1;
301  conn[1] = this->node_id(8)+1;
302  conn[2] = this->node_id(9)+1;
303  conn[3] = this->node_id(9)+1;
304  conn[4] = this->node_id(3)+1;
305  conn[5] = this->node_id(3)+1;
306  conn[6] = this->node_id(3)+1;
307  conn[7] = this->node_id(3)+1;
308 
309  return;
310 
311  // Linear sub-tet 4
312  case 4:
313 
314  conn[0] = this->node_id(4)+1;
315  conn[1] = this->node_id(8)+1;
316  conn[2] = this->node_id(6)+1;
317  conn[3] = this->node_id(6)+1;
318  conn[4] = this->node_id(7)+1;
319  conn[5] = this->node_id(7)+1;
320  conn[6] = this->node_id(7)+1;
321  conn[7] = this->node_id(7)+1;
322 
323  return;
324 
325  // Linear sub-tet 5
326  case 5:
327 
328  conn[0] = this->node_id(4)+1;
329  conn[1] = this->node_id(5)+1;
330  conn[2] = this->node_id(6)+1;
331  conn[3] = this->node_id(6)+1;
332  conn[4] = this->node_id(8)+1;
333  conn[5] = this->node_id(8)+1;
334  conn[6] = this->node_id(8)+1;
335  conn[7] = this->node_id(8)+1;
336 
337  return;
338 
339  // Linear sub-tet 6
340  case 6:
341 
342  conn[0] = this->node_id(5)+1;
343  conn[1] = this->node_id(9)+1;
344  conn[2] = this->node_id(6)+1;
345  conn[3] = this->node_id(6)+1;
346  conn[4] = this->node_id(8)+1;
347  conn[5] = this->node_id(8)+1;
348  conn[6] = this->node_id(8)+1;
349  conn[7] = this->node_id(8)+1;
350 
351  return;
352 
353  // Linear sub-tet 7
354  case 7:
355 
356  conn[0] = this->node_id(7)+1;
357  conn[1] = this->node_id(6)+1;
358  conn[2] = this->node_id(9)+1;
359  conn[3] = this->node_id(9)+1;
360  conn[4] = this->node_id(8)+1;
361  conn[5] = this->node_id(8)+1;
362  conn[6] = this->node_id(8)+1;
363  conn[7] = this->node_id(8)+1;
364 
365  return;
366 
367 
368  default:
369  libmesh_error_msg("Invalid sc = " << sc);
370  }
371  }
372 
373  case VTK:
374  {
375  // VTK connectivity for VTK_QUADRATIC_TETRA matches libMesh's own.
376  conn.resize(Tet10::num_nodes);
377  for (auto i : index_range(conn))
378  conn[i] = this->node_id(i);
379  return;
380  }
381 
382  default:
383  libmesh_error_msg("Unsupported IO package " << iop);
384  }
385 }
386 
387 
388 
389 const unsigned short int Tet10::_second_order_vertex_child_number[10] =
390  {
391  99,99,99,99, // Vertices
392  0,1,0,0,1,2 // Edges
393  };
394 
395 
396 
397 const unsigned short int Tet10::_second_order_vertex_child_index[10] =
398  {
399  99,99,99,99, // Vertices
400  1,2,2,3,3,3 // Edges
401  };
402 
403 
404 
405 std::pair<unsigned short int, unsigned short int>
406 Tet10::second_order_child_vertex (const unsigned int n) const
407 {
408  libmesh_assert_greater_equal (n, this->n_vertices());
409  libmesh_assert_less (n, this->n_nodes());
410  return std::pair<unsigned short int, unsigned short int>
413 }
414 
415 
416 
417 unsigned short int Tet10::second_order_adjacent_vertex (const unsigned int n,
418  const unsigned int v) const
419 {
420  libmesh_assert_greater_equal (n, this->n_vertices());
421  libmesh_assert_less (n, this->n_nodes());
422  libmesh_assert_less (v, 2);
423  return _second_order_adjacent_vertices[n-this->n_vertices()][v];
424 }
425 
426 
427 
428 const unsigned short int Tet10::_second_order_adjacent_vertices[6][2] =
429  {
430  {0, 1}, // vertices adjacent to node 4
431  {1, 2}, // vertices adjacent to node 5
432  {0, 2}, // vertices adjacent to node 6
433  {0, 3}, // vertices adjacent to node 7
434  {1, 3}, // vertices adjacent to node 8
435  {2, 3} // vertices adjacent to node 9
436  };
437 
438 
439 
440 
441 
442 #ifdef LIBMESH_ENABLE_AMR
443 
445  {
446  // embedding matrix for child 0
447  {
448  // 0 1 2 3 4 5 6 7 8 9
449  { 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.}, // 0
450  { 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.}, // 1
451  { 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.}, // 2
452  { 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.}, // 3
453  { 0.375,-0.125, 0., 0., 0.75, 0., 0., 0., 0., 0.}, // 4
454  { 0.,-0.125,-0.125, 0., 0.5, 0.25, 0.5, 0., 0., 0.}, // 5
455  { 0.375, 0.,-0.125, 0., 0., 0., 0.75, 0., 0., 0.}, // 6
456  { 0.375, 0., 0.,-0.125, 0., 0., 0., 0.75, 0., 0.}, // 7
457  { 0.,-0.125, 0.,-0.125, 0.5, 0., 0., 0.5, 0.25, 0.}, // 8
458  { 0., 0.,-0.125,-0.125, 0., 0., 0.5, 0.5, 0., 0.25} // 9
459  },
460 
461  // embedding matrix for child 1
462  {
463  // 0 1 2 3 4 5 6 7 8 9
464  { 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.}, // 0
465  { 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.}, // 1
466  { 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.}, // 2
467  { 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.}, // 3
468  {-0.125, 0.375, 0., 0., 0.75, 0., 0., 0., 0., 0.}, // 4
469  { 0., 0.375,-0.125, 0., 0., 0.75, 0., 0., 0., 0.}, // 5
470  {-0.125, 0.,-0.125, 0., 0.5, 0.5, 0.25, 0., 0., 0.}, // 6
471  {-0.125, 0., 0.,-0.125, 0.5, 0., 0., 0.25, 0.5, 0.}, // 7
472  { 0., 0.375, 0.,-0.125, 0., 0., 0., 0., 0.75, 0.}, // 8
473  { 0., 0.,-0.125,-0.125, 0., 0.5, 0., 0., 0.5, 0.25} // 9
474  },
475 
476  // embedding matrix for child 2
477  {
478  // 0 1 2 3 4 5 6 7 8 9
479  { 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.}, // 0
480  { 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.}, // 1
481  { 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.}, // 2
482  { 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.}, // 3
483  {-0.125,-0.125, 0., 0., 0.25, 0.5, 0.5, 0., 0., 0.}, // 4
484  { 0.,-0.125, 0.375, 0., 0., 0.75, 0., 0., 0., 0.}, // 5
485  {-0.125, 0., 0.375, 0., 0., 0., 0.75, 0., 0., 0.}, // 6
486  {-0.125, 0., 0.,-0.125, 0., 0., 0.5, 0.25, 0., 0.5}, // 7
487  { 0.,-0.125, 0.,-0.125, 0., 0.5, 0., 0., 0.25, 0.5}, // 8
488  { 0., 0., 0.375,-0.125, 0., 0., 0., 0., 0., 0.75} // 9
489  },
490 
491  // embedding matrix for child 3
492  {
493  // 0 1 2 3 4 5 6 7 8 9
494  { 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.}, // 0
495  { 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.}, // 1
496  { 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.}, // 2
497  { 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.}, // 3
498  {-0.125,-0.125, 0., 0., 0.25, 0., 0., 0.5, 0.5, 0.}, // 4
499  { 0.,-0.125,-0.125, 0., 0., 0.25, 0., 0., 0.5, 0.5}, // 5
500  {-0.125, 0.,-0.125, 0., 0., 0., 0.25, 0.5, 0., 0.5}, // 6
501  {-0.125, 0., 0., 0.375, 0., 0., 0., 0.75, 0., 0.}, // 7
502  { 0.,-0.125, 0., 0.375, 0., 0., 0., 0., 0.75, 0.}, // 8
503  { 0., 0.,-0.125, 0.375, 0., 0., 0., 0., 0., 0.75} // 9
504  },
505 
506  // embedding matrix for child 4
507  {
508  // 0 1 2 3 4 5 6 7 8 9
509  { 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.}, // 0
510  { 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.}, // 1
511  { 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.}, // 2
512  { 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.}, // 3
513  {-0.125, 0., 0.,-0.125, 0.5, 0., 0., 0.25, 0.5, 0.}, // 4
514  {-0.125,-0.125,-0.125,-0.125, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25}, // 5
515  { 0.,-0.125,-0.125, 0., 0.5, 0.25, 0.5, 0., 0., 0.}, // 6
516  { 0.,-0.125, 0.,-0.125, 0.5, 0., 0., 0.5, 0.25, 0.}, // 7
517  {-0.125,-0.125, 0., 0., 0.25, 0., 0., 0.5, 0.5, 0.}, // 8
518  { 0., 0.,-0.125,-0.125, 0., 0., 0.5, 0.5, 0., 0.25} // 9
519  },
520 
521  // embedding matrix for child 5
522  {
523  // 0 1 2 3 4 5 6 7 8 9
524  { 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.}, // 0
525  { 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.}, // 1
526  { 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.}, // 2
527  { 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.}, // 3
528  {-0.125, 0.,-0.125, 0., 0.5, 0.5, 0.25, 0., 0., 0.}, // 4
529  {-0.125,-0.125, 0., 0., 0.25, 0.5, 0.5, 0., 0., 0.}, // 5
530  { 0.,-0.125,-0.125, 0., 0.5, 0.25, 0.5, 0., 0., 0.}, // 6
531  {-0.125, 0., 0.,-0.125, 0.5, 0., 0., 0.25, 0.5, 0.}, // 7
532  { 0., 0.,-0.125,-0.125, 0., 0.5, 0., 0., 0.5, 0.25}, // 8
533  {-0.125,-0.125,-0.125,-0.125, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25} // 9
534  },
535 
536  // embedding matrix for child 6
537  {
538  // 0 1 2 3 4 5 6 7 8 9
539  { 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.}, // 0
540  { 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.}, // 1
541  { 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.}, // 2
542  { 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.}, // 3
543  {-0.125,-0.125, 0., 0., 0.25, 0.5, 0.5, 0., 0., 0.}, // 4
544  { 0.,-0.125, 0.,-0.125, 0., 0.5, 0., 0., 0.25, 0.5}, // 5
545  {-0.125, 0., 0.,-0.125, 0., 0., 0.5, 0.25, 0., 0.5}, // 6
546  {-0.125,-0.125,-0.125,-0.125, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25}, // 7
547  { 0., 0.,-0.125,-0.125, 0., 0.5, 0., 0., 0.5, 0.25}, // 8
548  { 0.,-0.125,-0.125, 0., 0., 0.25, 0., 0., 0.5, 0.5} // 9
549  },
550 
551  // embedding matrix for child 7
552  {
553  // 0 1 2 3 4 5 6 7 8 9
554  { 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.}, // 0
555  { 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.}, // 1
556  { 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.}, // 2
557  { 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.}, // 3
558  {-0.125,-0.125,-0.125,-0.125, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25}, // 4
559  { 0.,-0.125,-0.125, 0., 0., 0.25, 0., 0., 0.5, 0.5}, // 5
560  {-0.125, 0., 0.,-0.125, 0., 0., 0.5, 0.25, 0., 0.5}, // 6
561  { 0., 0.,-0.125,-0.125, 0., 0., 0.5, 0.5, 0., 0.25}, // 7
562  {-0.125,-0.125, 0., 0., 0.25, 0., 0., 0.5, 0.5, 0.}, // 8
563  {-0.125, 0.,-0.125, 0., 0., 0., 0.25, 0.5, 0., 0.5} // 9
564  }
565  };
566 
567 
568 
569 Real Tet10::embedding_matrix (const unsigned int i,
570  const unsigned int j,
571  const unsigned int k) const
572 {
573  // Choose an optimal diagonal, if one has not already been selected
574  this->choose_diagonal();
575 
576  // Permuted j and k indices
577  unsigned int
578  jp=j,
579  kp=k;
580 
581  if ((i>3) && (this->_diagonal_selection!=DIAG_02_13))
582  {
583  // Just the enum value cast to an unsigned int...
584  const unsigned ds = static_cast<unsigned int>(this->_diagonal_selection); // == 1 or 2
585 
586  // Instead of doing a lot of arithmetic, use these
587  // straightforward arrays for the permutations. Note that 3 ->
588  // 3, and the first array consists of "forward" permutations of
589  // the sets {0,1,2}, {4,5,6}, and {7,8,9} while the second array
590  // consists of "reverse" permutations of the same sets.
591  const unsigned int perms[2][10] =
592  {
593  {1, 2, 0, 3, 5, 6, 4, 8, 9, 7},
594  {2, 0, 1, 3, 6, 4, 5, 9, 7, 8}
595  };
596 
597  // Permute j
598  jp = perms[ds-1][j];
599  // if (jp<3)
600  // jp = (jp+ds)%3;
601  // else if (jp>3)
602  // jp = (jp-1+ds)%3 + 1 + 3*((jp-1)/3);
603 
604  // Permute k
605  kp = perms[ds-1][k];
606  // if (kp<3)
607  // kp = (kp+ds)%3;
608  // else if (kp>3)
609  // kp = (kp-1+ds)%3 + 1 + 3*((kp-1)/3);
610  }
611 
612  // Debugging:
613  // libMesh::err << "Selected diagonal " << _diagonal_selection << std::endl;
614  // libMesh::err << "j=" << j << std::endl;
615  // libMesh::err << "k=" << k << std::endl;
616  // libMesh::err << "jp=" << jp << std::endl;
617  // libMesh::err << "kp=" << kp << std::endl;
618 
619  // Call embedding matrix with permuted indices
620  return this->_embedding_matrix[i][jp][kp];
621 }
622 
623 #endif // #ifdef LIBMESH_ENABLE_AMR
624 
625 
626 
628 {
629  // This specialization is good for Lagrange mappings only
630  if (this->mapping_type() != LAGRANGE_MAP)
631  return this->Elem::volume();
632 
633  // Make copies of our points. It makes the subsequent calculations a bit
634  // shorter and avoids dereferencing the same pointer multiple times.
635  Point
636  x0 = point(0), x1 = point(1), x2 = point(2), x3 = point(3), x4 = point(4),
637  x5 = point(5), x6 = point(6), x7 = point(7), x8 = point(8), x9 = point(9);
638 
639  // The constant components of the dx/dxi vector, linear in xi, eta, zeta.
640  // These were copied directly from the output of a Python script.
641  Point dx_dxi[4] =
642  {
643  -3*x0 - x1 + 4*x4, // constant
644  4*x0 - 4*x4 - 4*x7 + 4*x8, // zeta
645  4*x0 - 4*x4 + 4*x5 - 4*x6, // eta
646  4*x0 + 4*x1 - 8*x4 // xi
647  };
648 
649  // The constant components of the dx/deta vector, linear in xi, eta, zeta.
650  // These were copied directly from the output of a Python script.
651  Point dx_deta[4] =
652  {
653  -3*x0 - x2 + 4*x6, // constant
654  4*x0 - 4*x6 - 4*x7 + 4*x9, // zeta
655  4*x0 + 4*x2 - 8*x6, // eta
656  4*x0 - 4*x4 + 4*x5 - 4*x6 // xi
657  };
658 
659  // The constant components of the dx/dzeta vector, linear in xi, eta, zeta.
660  // These were copied directly from the output of a Python script.
661  Point dx_dzeta[4] =
662  {
663  -3*x0 - x3 + 4*x7, // constant
664  4*x0 + 4*x3 - 8*x7, // zeta
665  4*x0 - 4*x6 - 4*x7 + 4*x9, // eta
666  4*x0 - 4*x4 - 4*x7 + 4*x8 // xi
667  };
668 
669  // 2x2x2 conical quadrature rule. Note: there is also a five point
670  // rule for tets with a negative weight which would be cheaper, but
671  // we'll use this one to preclude any possible issues with
672  // cancellation error.
673  const int N = 8;
674  static const Real w[N] =
675  {
676  Real(3.6979856358852914509238091810505e-02L),
677  Real(1.6027040598476613723156741868689e-02L),
678  Real(2.1157006454524061178256145400082e-02L),
679  Real(9.1694299214797439226823542540576e-03L),
680  Real(3.6979856358852914509238091810505e-02L),
681  Real(1.6027040598476613723156741868689e-02L),
682  Real(2.1157006454524061178256145400082e-02L),
683  Real(9.1694299214797439226823542540576e-03L)
684  };
685 
686  static const Real xi[N] =
687  {
688  Real(1.2251482265544137786674043037115e-01L),
689  Real(5.4415184401122528879992623629551e-01L),
690  Real(1.2251482265544137786674043037115e-01L),
691  Real(5.4415184401122528879992623629551e-01L),
692  Real(1.2251482265544137786674043037115e-01L),
693  Real(5.4415184401122528879992623629551e-01L),
694  Real(1.2251482265544137786674043037115e-01L),
695  Real(5.4415184401122528879992623629551e-01L)
696  };
697 
698  static const Real eta[N] =
699  {
700  Real(1.3605497680284601717109468420738e-01L),
701  Real(7.0679724159396903069267439165167e-02L),
702  Real(5.6593316507280088053551297149570e-01L),
703  Real(2.9399880063162286589079157179842e-01L),
704  Real(1.3605497680284601717109468420738e-01L),
705  Real(7.0679724159396903069267439165167e-02L),
706  Real(5.6593316507280088053551297149570e-01L),
707  Real(2.9399880063162286589079157179842e-01L)
708  };
709 
710  static const Real zeta[N] =
711  {
712  Real(1.5668263733681830907933725249176e-01L),
713  Real(8.1395667014670255076709592007207e-02L),
714  Real(6.5838687060044409936029672711329e-02L),
715  Real(3.4202793236766414300604458388142e-02L),
716  Real(5.8474756320489429588282763292971e-01L),
717  Real(3.0377276481470755305409673253211e-01L),
718  Real(2.4571332521171333166171692542182e-01L),
719  Real(1.2764656212038543100867773351792e-01L)
720  };
721 
722  Real vol = 0.;
723  for (int q=0; q<N; ++q)
724  {
725  // Compute dx_dxi, dx_deta, dx_dzeta at the current quadrature point.
726  Point
727  dx_dxi_q = dx_dxi[0] + zeta[q]*dx_dxi[1] + eta[q]*dx_dxi[2] + xi[q]*dx_dxi[3],
728  dx_deta_q = dx_deta[0] + zeta[q]*dx_deta[1] + eta[q]*dx_deta[2] + xi[q]*dx_deta[3],
729  dx_dzeta_q = dx_dzeta[0] + zeta[q]*dx_dzeta[1] + eta[q]*dx_dzeta[2] + xi[q]*dx_dzeta[3];
730 
731  // Compute scalar triple product, multiply by weight, and accumulate volume.
732  vol += w[q] * triple_product(dx_dxi_q, dx_deta_q, dx_dzeta_q);
733  }
734 
735  return vol;
736 }
737 
738 
739 void Tet10::permute(unsigned int perm_num)
740 {
741  libmesh_assert_less (perm_num, 12);
742 
743  const unsigned int side = perm_num % 4;
744  const unsigned int rotate = perm_num / 4;
745 
746  for (unsigned int i = 0; i != rotate; ++i)
747  {
748  swap3nodes(0,1,2);
749  swap3nodes(4,5,6);
750  swap3nodes(7,8,9);
751  swap3neighbors(1,2,3);
752  }
753 
754  switch (side) {
755  case 0:
756  break;
757  case 1:
758  swap3nodes(0,2,3);
759  swap3nodes(4,5,8);
760  swap3nodes(6,9,7);
761  swap3neighbors(0,2,1);
762  break;
763  case 2:
764  swap3nodes(2,0,3);
765  swap3nodes(5,4,8);
766  swap3nodes(6,7,9);
767  swap3neighbors(0,1,2);
768  break;
769  case 3:
770  swap3nodes(2,1,3);
771  swap3nodes(5,8,9);
772  swap3nodes(6,4,7);
773  swap3neighbors(0,1,3);
774  break;
775  default:
776  libmesh_error();
777  }
778 }
779 
780 
781 void Tet10::flip(BoundaryInfo * boundary_info)
782 {
783  swap2nodes(0,2);
784  swap2nodes(4,5);
785  swap2nodes(7,9);
786  swap2neighbors(1,2);
787  swap2boundarysides(1,2,boundary_info);
788  swap2boundaryedges(0,1,boundary_info);
789  swap2boundaryedges(3,5,boundary_info);
790 }
791 
792 
793 ElemType Tet10::side_type (const unsigned int libmesh_dbg_var(s)) const
794 {
795  libmesh_assert_less (s, 4);
796  return TRI6;
797 }
798 
799 
800 } // 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:3171
virtual Order default_order() const override
Definition: cell_tet10.C:179
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:2087
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i) override
Builds a EDGE3 built coincident with edge i.
Definition: cell_tet10.C:224
virtual unsigned int n_nodes() const override
Definition: cell_tet10.h:90
virtual bool has_affine_map() const override
Definition: cell_tet10.C:147
virtual unsigned int n_sides() const override final
Definition: cell_tet.h:74
static const unsigned short int _second_order_adjacent_vertices[6][2]
Matrix that tells which vertices define the location of mid-side (or second-order) nodes...
Definition: cell_tet10.h:278
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the node of the edge to element node numbers.
Definition: cell_tet10.h:231
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const override
Definition: cell_tet10.C:417
IOPackage
libMesh interfaces with several different software packages for the purposes of creating, reading, and writing mesh files.
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:3155
Diagonal _diagonal_selection
The currently-selected diagonal used during refinement.
Definition: cell_tet.h:237
The libMesh namespace provides an interface to certain functionality in the library.
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
Definition: cell_tet10.C:91
virtual void connectivity(const unsigned int sc, const IOPackage iop, std::vector< dof_id_type > &conn) const override
Definition: cell_tet10.C:238
virtual void permute(unsigned int perm_num) override final
Permutes the element (by swapping node and neighbor pointers) according to the specified index...
Definition: cell_tet10.C:739
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
Definition: cell_tet10.C:81
static const Real _embedding_matrix[num_children][num_nodes][num_nodes]
Matrix that computes new nodal locations/solution values from current nodes/solution.
Definition: cell_tet10.h:266
virtual unsigned int n_sub_elem() const override
Definition: cell_tet10.h:95
void swap3neighbors(unsigned int n1, unsigned int n2, unsigned int n3)
Swaps three neighbor_ptrs, "rotating" them.
Definition: elem.h:1974
virtual unsigned int n_vertices() const override final
Definition: cell_tet.h:79
static const int num_children
Definition: cell_tet10.h:217
void swap3nodes(unsigned int n1, unsigned int n2, unsigned int n3)
Swaps three node_ptrs, "rotating" them.
Definition: elem.h:1965
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
Definition: type_vector.h:1068
static const unsigned short int _second_order_vertex_child_number[10]
Vector that names a child sharing each second order node.
Definition: cell_tet10.h:283
ElemMappingType mapping_type() const
Definition: elem.h:2957
void swap2nodes(unsigned int n1, unsigned int n2)
Swaps two node_ptrs.
Definition: elem.h:1933
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override
Definition: cell_tet10.C:117
virtual Real volume() const override
A specialization for computing the volume of a Tet10.
Definition: cell_tet10.C:627
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const override
Definition: cell_tet10.C:104
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
libmesh_assert(ctx)
virtual unsigned int n_edges() const override final
Definition: cell_tet.h:84
virtual Real embedding_matrix(const unsigned int i, const unsigned int j, const unsigned int k) const override
Matrix used to create the elements children.
Definition: cell_tet10.C:569
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
Definition: cell_tet10.C:186
virtual void flip(BoundaryInfo *) override final
Flips the element (by swapping node and neighbor pointers) to have a mapping Jacobian of opposite sig...
Definition: cell_tet10.C:781
static constexpr Real affine_tol
Default tolerance to use in has_affine_map().
Definition: elem.h:1902
static const int num_sides
Definition: cell_tet10.h:215
static const int nodes_per_edge
Definition: cell_tet10.h:219
RealTensorValue rotate(MeshBase &mesh, const Real phi, const Real theta=0., const Real psi=0.)
Rotates the mesh in the xy plane.
void swap2neighbors(unsigned int n1, unsigned int n2)
Swaps two neighbor_ptrs.
Definition: elem.h:1943
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
Definition: cell_tet10.C:98
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
ElemType side_type(const unsigned int s) const override final
Definition: cell_tet10.C:793
virtual bool is_vertex(const unsigned int i) const override
Definition: cell_tet10.C:62
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy=false) override
Builds a TRI6 built coincident with face i.
Definition: cell_tet10.C:208
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the node of the side to element node numbers.
Definition: cell_tet10.h:225
virtual Real volume() const
Definition: elem.C:3050
void choose_diagonal() const
Derived classes use this function to select an initial diagonal during refinement.
Definition: cell_tet.C:194
virtual bool is_face(const unsigned int i) const override
Definition: cell_tet10.C:76
virtual std::pair< unsigned short int, unsigned short int > second_order_child_vertex(const unsigned int n) const override
Definition: cell_tet10.C:406
static const unsigned short int _second_order_vertex_child_index[10]
Vector that names the child vertex index for each second order node.
Definition: cell_tet10.h:288
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
Definition: cell_tet10.C:197
virtual bool is_edge(const unsigned int i) const override
Definition: cell_tet10.C:69
static const int num_nodes
Geometric constants for Tet10.
Definition: cell_tet10.h:214
static const int num_edges
Definition: cell_tet10.h:216
bool is_child_on_side_helper(const unsigned int c, const unsigned int s, const unsigned int checked_nodes[][3]) const
Called by descendant classes with appropriate data to determine if child c is on side s...
Definition: cell_tet.C:142
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:2299
const Point & point(const unsigned int i) const
Definition: elem.h:2277
bool relative_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
Definition: type_vector.h:1004
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:111
static const int nodes_per_side
Definition: cell_tet10.h:218