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