libMesh
Loading...
Searching...
No Matches
cell_prism20.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_prism20.h"
21#include "libmesh/edge_edge3.h"
22#include "libmesh/face_quad9.h"
23#include "libmesh/face_tri7.h"
24#include "libmesh/enum_io_package.h"
25#include "libmesh/enum_order.h"
26#include "libmesh/int_range.h"
27
28namespace libMesh
29{
30
31
32
33// ------------------------------------------------------------
34// Prism20 class static member initializations
35const int Prism20::num_nodes;
38
39// ------------------------------------------------------------
40// Prism20 class member functions
41
42bool Prism20::is_vertex(const unsigned int i) const
43{
44 if (i < 6)
45 return true;
46 return false;
47}
48
49bool Prism20::is_edge(const unsigned int i) const
50{
51 if (i < 6)
52 return false;
53 if (i > 14)
54 return false;
55 return true;
56}
57
58bool Prism20::is_face(const unsigned int i) const
59{
60 if (i > 14)
61 return true;
62 return false;
63}
64
65bool Prism20::is_node_on_side(const unsigned int n,
66 const unsigned int s) const
67{
68 libmesh_assert_less (s, n_sides());
69 return std::find(std::begin(side_nodes_map[s]),
70 std::end(side_nodes_map[s]),
71 n) != std::end(side_nodes_map[s]);
72}
73
74std::vector<unsigned>
75Prism20::nodes_on_side(const unsigned int s) const
76{
77 libmesh_assert_less(s, n_sides());
78 auto trim = (s > 0 && s < 4) ? 0 : 2;
79 return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s]) - trim};
80}
81
82std::vector<unsigned>
83Prism20::nodes_on_edge(const unsigned int e) const
84{
85 libmesh_assert_less(e, n_edges());
86 return {std::begin(edge_nodes_map[e]), std::end(edge_nodes_map[e])};
87}
88
89bool Prism20::is_node_on_edge(const unsigned int n,
90 const unsigned int e) const
91{
92 libmesh_assert_less (e, n_edges());
93 return std::find(std::begin(edge_nodes_map[e]),
94 std::end(edge_nodes_map[e]),
95 n) != std::end(edge_nodes_map[e]);
96}
97
98
99
101{
102 // Make sure z edges are affine
103 Point v = this->point(3) - this->point(0);
104 if (!v.relative_fuzzy_equals(this->point(4) - this->point(1), affine_tol) ||
105 !v.relative_fuzzy_equals(this->point(5) - this->point(2), affine_tol))
106 return false;
107
108 // Make sure edges are straight
109 v /= 2;
110 if (!v.relative_fuzzy_equals(this->point(9) - this->point(0), affine_tol) ||
111 !v.relative_fuzzy_equals(this->point(10) - this->point(1), affine_tol) ||
112 !v.relative_fuzzy_equals(this->point(11) - this->point(2), affine_tol) ||
113 !v.relative_fuzzy_equals(this->point(15) - this->point(6), affine_tol) ||
114 !v.relative_fuzzy_equals(this->point(16) - this->point(7), affine_tol) ||
115 !v.relative_fuzzy_equals(this->point(17) - this->point(8), affine_tol))
116 return false;
117 v = (this->point(1) - this->point(0))/2;
118 if (!v.relative_fuzzy_equals(this->point(6) - this->point(0), affine_tol) ||
119 !v.relative_fuzzy_equals(this->point(12) - this->point(3), affine_tol))
120 return false;
121 v = (this->point(2) - this->point(0))/2;
122 if (!v.relative_fuzzy_equals(this->point(8) - this->point(0), affine_tol) ||
123 !v.relative_fuzzy_equals(this->point(14) - this->point(3), affine_tol))
124 return false;
125 v = (this->point(2) - this->point(1))/2;
126 if (!v.relative_fuzzy_equals(this->point(7) - this->point(1), affine_tol) ||
127 !v.relative_fuzzy_equals(this->point(13) - this->point(4), affine_tol))
128 return false;
129
130 // Make sure triangle face midpoints are centered
131 v = this->point(2) + this->point(1) - 2*this->point(0);
132 if (!v.relative_fuzzy_equals((this->point(18)-this->point(0))*3))
133 return false;
134 v = this->point(5) + this->point(4) - 2*this->point(3);
135 if (!v.relative_fuzzy_equals((this->point(19)-this->point(3))*3))
136 return false;
137
138 return true;
139}
140
141
142
144{
145 return THIRD;
146}
147
148dof_id_type Prism20::key (const unsigned int s) const
149{
150 libmesh_assert_less (s, this->n_sides());
151
152 switch (s)
153 {
154 case 0: // the triangular face at z=0
155 {
156 return Elem::compute_key (this->node_id(18));
157 }
158 case 1: // the quad face at y=0
159 {
160 return Elem::compute_key (this->node_id(15));
161 }
162 case 2: // the other quad face
163 {
164 return Elem::compute_key (this->node_id(16));
165 }
166 case 3: // the quad face at x=0
167 {
168 return Elem::compute_key (this->node_id(17));
169 }
170 case 4: // the triangular face at z=1
171 {
172 return Elem::compute_key (this->node_id(19));
173 }
174 default:
175 libmesh_error_msg("Invalid side " << s);
176 }
177}
178
179
180
181unsigned int Prism20::local_side_node(unsigned int side,
182 unsigned int side_node) const
183{
184 libmesh_assert_less (side, this->n_sides());
185
186 // Never more than 9 nodes per side.
187 libmesh_assert_less(side_node, Prism20::nodes_per_side);
188
189 // Some sides have 7 nodes.
190 libmesh_assert(!(side==0 || side==4) || side_node < 7);
191
192 return Prism20::side_nodes_map[side][side_node];
193}
194
195
196
197unsigned int Prism20::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, Prism20::nodes_per_edge);
202
203 return Prism20::edge_nodes_map[edge][edge_node];
204}
205
206
207
208std::unique_ptr<Elem> Prism20::build_side_ptr (const unsigned int i)
209{
210 libmesh_assert_less (i, this->n_sides());
211
212 std::unique_ptr<Elem> face;
213
214 switch (i)
215 {
216 case 0: // the triangular face at z=-1
217 case 4: // the triangular face at z=1
218 {
219 face = std::make_unique<Tri7>();
220 break;
221 }
222 case 1: // the quad face at y=0
223 case 2: // the other quad face
224 case 3: // the quad face at x=0
225 {
226 face = std::make_unique<Quad9>();
227 break;
228 }
229 default:
230 libmesh_error_msg("Invalid side i = " << i);
231 }
232
233 // Set the nodes
234 for (auto n : face->node_index_range())
235 face->set_node(n, this->node_ptr(Prism20::side_nodes_map[i][n]));
236
237 face->set_interior_parent(this);
238 face->inherit_data_from(*this);
239
240 return face;
241}
242
243
244
245void Prism20::build_side_ptr (std::unique_ptr<Elem> & side,
246 const unsigned int i)
247{
248 libmesh_assert_less (i, this->n_sides());
249
250 switch (i)
251 {
252 case 0: // the triangular face at z=-1
253 case 4: // the triangular face at z=1
254 {
255 if (!side.get() || side->type() != TRI7)
256 {
257 side = this->build_side_ptr(i);
258 return;
259 }
260 break;
261 }
262
263 case 1: // the quad face at y=0
264 case 2: // the other quad face
265 case 3: // the quad face at x=0
266 {
267 if (!side.get() || side->type() != QUAD9)
268 {
269 side = this->build_side_ptr(i);
270 return;
271 }
272 break;
273 }
274
275 default:
276 libmesh_error_msg("Invalid side i = " << i);
277 }
278
279 side->inherit_data_from(*this);
280
281 // Set the nodes
282 for (auto n : side->node_index_range())
283 side->set_node(n, this->node_ptr(Prism20::side_nodes_map[i][n]));
284}
285
286
287
288std::unique_ptr<Elem> Prism20::build_edge_ptr (const unsigned int i)
289{
290 return this->simple_build_edge_ptr<Edge3,Prism20>(i);
291}
292
293
294
295void Prism20::build_edge_ptr (std::unique_ptr<Elem> & edge, const unsigned int i)
296{
297 this->simple_build_edge_ptr<Prism20>(edge, i, EDGE3);
298}
299
300
301
302void Prism20::connectivity(const unsigned int /*sc*/,
303 const IOPackage /*iop*/,
304 std::vector<dof_id_type> & /*conn*/) const
305{
306 libmesh_not_implemented(); // FIXME RHS
307
308/*
309 libmesh_assert(_nodes);
310 libmesh_assert_less (sc, this->n_sub_elem());
311 libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
312
313 switch (iop)
314 {
315 case TECPLOT:
316 {
317 conn.resize(8);
318 switch (sc)
319 {
320
321 case 0:
322 {
323 conn[0] = this->node_id(0)+1;
324 conn[1] = this->node_id(6)+1;
325 conn[2] = this->node_id(8)+1;
326 conn[3] = this->node_id(8)+1;
327 conn[4] = this->node_id(9)+1;
328 conn[5] = this->node_id(15)+1;
329 conn[6] = this->node_id(17)+1;
330 conn[7] = this->node_id(17)+1;
331
332 return;
333 }
334
335 case 1:
336 {
337 conn[0] = this->node_id(6)+1;
338 conn[1] = this->node_id(1)+1;
339 conn[2] = this->node_id(7)+1;
340 conn[3] = this->node_id(7)+1;
341 conn[4] = this->node_id(15)+1;
342 conn[5] = this->node_id(10)+1;
343 conn[6] = this->node_id(16)+1;
344 conn[7] = this->node_id(16)+1;
345
346 return;
347 }
348
349 case 2:
350 {
351 conn[0] = this->node_id(8)+1;
352 conn[1] = this->node_id(7)+1;
353 conn[2] = this->node_id(2)+1;
354 conn[3] = this->node_id(2)+1;
355 conn[4] = this->node_id(17)+1;
356 conn[5] = this->node_id(16)+1;
357 conn[6] = this->node_id(11)+1;
358 conn[7] = this->node_id(11)+1;
359
360 return;
361 }
362
363 case 3:
364 {
365 conn[0] = this->node_id(6)+1;
366 conn[1] = this->node_id(7)+1;
367 conn[2] = this->node_id(8)+1;
368 conn[3] = this->node_id(8)+1;
369 conn[4] = this->node_id(15)+1;
370 conn[5] = this->node_id(16)+1;
371 conn[6] = this->node_id(17)+1;
372 conn[7] = this->node_id(17)+1;
373
374 return;
375 }
376
377 case 4:
378 {
379 conn[0] = this->node_id(9)+1;
380 conn[1] = this->node_id(15)+1;
381 conn[2] = this->node_id(17)+1;
382 conn[3] = this->node_id(17)+1;
383 conn[4] = this->node_id(3)+1;
384 conn[5] = this->node_id(12)+1;
385 conn[6] = this->node_id(14)+1;
386 conn[7] = this->node_id(14)+1;
387
388 return;
389 }
390
391 case 5:
392 {
393 conn[0] = this->node_id(15)+1;
394 conn[1] = this->node_id(10)+1;
395 conn[2] = this->node_id(16)+1;
396 conn[3] = this->node_id(16)+1;
397 conn[4] = this->node_id(12)+1;
398 conn[5] = this->node_id(4)+1;
399 conn[6] = this->node_id(13)+1;
400 conn[7] = this->node_id(13)+1;
401
402 return;
403 }
404
405 case 6:
406 {
407 conn[0] = this->node_id(17)+1;
408 conn[1] = this->node_id(16)+1;
409 conn[2] = this->node_id(11)+1;
410 conn[3] = this->node_id(11)+1;
411 conn[4] = this->node_id(14)+1;
412 conn[5] = this->node_id(13)+1;
413 conn[6] = this->node_id(5)+1;
414 conn[7] = this->node_id(5)+1;
415
416 return;
417 }
418
419 case 7:
420 {
421 conn[0] = this->node_id(15)+1;
422 conn[1] = this->node_id(16)+1;
423 conn[2] = this->node_id(17)+1;
424 conn[3] = this->node_id(17)+1;
425 conn[4] = this->node_id(12)+1;
426 conn[5] = this->node_id(13)+1;
427 conn[6] = this->node_id(14)+1;
428 conn[7] = this->node_id(14)+1;
429
430 return;
431 }
432
433 default:
434 libmesh_error_msg("Invalid sc = " << sc);
435 }
436
437 }
438
439 case VTK:
440 {
441 // VTK now supports VTK_BIQUADRATIC_QUADRATIC_WEDGE directly
442 const unsigned int conn_size = 18;
443 conn.resize(conn_size);
444
445 // VTK's VTK_BIQUADRATIC_QUADRATIC_WEDGE first 9 (vertex) and
446 // last 3 (mid-face) nodes match. The middle and top layers
447 // of mid-edge nodes are reversed from LibMesh's.
448 for (auto i : index_range(conn))
449 conn[i] = this->node_id(i);
450
451 // top "ring" of mid-edge nodes
452 conn[9] = this->node_id(12);
453 conn[10] = this->node_id(13);
454 conn[11] = this->node_id(14);
455
456 // middle "ring" of mid-edge nodes
457 conn[12] = this->node_id(9);
458 conn[13] = this->node_id(10);
459 conn[14] = this->node_id(11);
460
461 return;
462 }
463
464 default:
465 libmesh_error_msg("Unsupported IO package " << iop);
466 }
467*/
468}
469
470
471
472
473unsigned int Prism20::n_second_order_adjacent_vertices (const unsigned int n) const
474{
475 switch (n)
476 {
477 case 6:
478 case 7:
479 case 8:
480 case 9:
481 case 10:
482 case 11:
483 case 12:
484 case 13:
485 case 14:
486 return 2;
487
488 case 15:
489 case 16:
490 case 17:
491 return 4;
492
493 case 18:
494 case 19:
495 return 3;
496
497 default:
498 libmesh_error_msg("Invalid node n = " << n);
499 }
500}
501
502
503
504
505
506unsigned short int Prism20::second_order_adjacent_vertex (const unsigned int n,
507 const unsigned int v) const
508{
509 libmesh_assert_greater_equal (n, this->n_vertices());
510 libmesh_assert_less (n, this->n_nodes());
511
512 switch (n)
513 {
514 /*
515 * These nodes are unique to \p Prism20,
516 * let our _remaining_... matrix handle
517 * this.
518 */
519 case 15:
520 case 16:
521 case 17:
522 case 18:
523 case 19:
524 {
525 libmesh_assert_less (v, 4);
527 }
528
529 /*
530 * All other second-order nodes (6,...,14) are
531 * identical with Prism15 and are therefore
532 * delegated to the _second_order matrix of
533 * \p Prism
534 */
535 default:
536 {
537 libmesh_assert_less (v, 2);
538 return _second_order_adjacent_vertices[n-this->n_vertices()][v];
539 }
540
541 }
542
543 return static_cast<unsigned short int>(-1);
544}
545
546
547
548const unsigned short int Prism20::_remaining_second_order_adjacent_vertices[5][4] =
549 {
550 { 0, 1, 3, 4}, // vertices adjacent to node 15
551 { 1, 2, 4, 5}, // vertices adjacent to node 16
552 { 0, 2, 3, 5}, // vertices adjacent to node 17
553 { 0, 1, 2, 99}, // vertices adjacent to node 18
554 { 3, 4, 5, 99} // vertices adjacent to node 19
555 };
556
557
558
559std::pair<unsigned short int, unsigned short int>
560Prism20::second_order_child_vertex (const unsigned int n) const
561{
562 libmesh_assert_greater_equal (n, this->n_vertices());
563 libmesh_assert_less (n, this->n_nodes());
564
565 return std::pair<unsigned short int, unsigned short int>
568}
569
570
571
572void
573Prism20::permute(unsigned int perm_num)
574{
575 libmesh_assert_less (perm_num, 6);
576 const unsigned int side = perm_num % 2;
577 const unsigned int rotate = perm_num / 2;
578
579 for (unsigned int i = 0; i != rotate; ++i)
580 {
581 swap3nodes(0,1,2);
582 swap3nodes(3,4,5);
583 swap3nodes(6,7,8);
584 swap3nodes(9,10,11);
585 swap3nodes(12,13,14);
586 swap3nodes(15,16,17);
587 swap3neighbors(1,2,3);
588 }
589
590 switch (side) {
591 case 0:
592 break;
593 case 1:
594 swap2nodes(1,3);
595 swap2nodes(0,4);
596 swap2nodes(2,5);
597 swap2nodes(6,12);
598 swap2nodes(9,10);
599 swap2nodes(7,14);
600 swap2nodes(8,13);
601 swap2nodes(16,17);
602 swap2nodes(18,19);
603 swap2neighbors(0,4);
604 swap2neighbors(2,3);
605 break;
606 default:
607 libmesh_error();
608 }
609}
610
611
612void
614{
615 libmesh_assert(boundary_info);
616
617 swap2nodes(0,1);
618 swap2nodes(3,4);
619 swap2nodes(7,8);
620 swap2nodes(9,10);
621 swap2nodes(13,14);
622 swap2nodes(16,17);
623 swap2neighbors(2,3);
624 swap2boundarysides(2,3,boundary_info);
625 swap2boundaryedges(0,1,boundary_info);
626 swap2boundaryedges(3,4,boundary_info);
627 swap2boundaryedges(7,8,boundary_info);
628}
629
630
631unsigned int Prism20::center_node_on_side(const unsigned short side) const
632{
633 libmesh_assert_less (side, Prism20::num_sides);
634 if (side >= 1 && side <= 3)
635 return side + 14;
636 if (side == 4)
637 return 19;
638 return 18;
639}
640
641
643Prism20::side_type (const unsigned int s) const
644{
645 libmesh_assert_less (s, 5);
646 if (s == 0 || s == 4)
647 return TRI7;
648 return QUAD9;
649}
650
651
652} // 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
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
static dof_id_type compute_key(dof_id_type n0)
Definition elem.h:3432
void swap3nodes(unsigned int n1, unsigned int n2, unsigned int n3)
Swaps three node_ptrs, "rotating" them.
Definition elem.h:2254
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 std::pair< unsigned short int, unsigned short int > second_order_child_vertex(const unsigned int n) const override
virtual bool is_face(const unsigned int i) const override
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i) override
Builds a EDGE3 or INFEDGE2 built coincident with edge i.
virtual Order default_order() const override
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
static const int nodes_per_side
static constexpr const unsigned int(& edge_nodes_map)[num_edges][nodes_per_edge]
virtual bool is_edge(const unsigned int i) const override
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
static constexpr const unsigned int(& side_nodes_map)[num_sides][nodes_per_side]
unsigned int center_node_on_side(const unsigned short side) const override final
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const override
virtual unsigned int n_nodes() const override
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 local_edge_node(unsigned int edge, unsigned int edge_node) const override
virtual dof_id_type key() const
Don't hide Elem::key() defined in the base class.
Definition elem.C:678
virtual bool is_vertex(const unsigned int i) const override
static const int nodes_per_edge
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Builds a QUAD9 or TRI6 built coincident with face i.
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
ElemType side_type(const unsigned int s) const override final
virtual bool has_affine_map() const override
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
virtual void permute(unsigned int perm_num) override final
Permutes the element (by swapping node and neighbor pointers) according to the specified index.
static const int num_nodes
Geometric constants for Prism20.
virtual void connectivity(const unsigned int sc, const IOPackage iop, std::vector< dof_id_type > &conn) const override
virtual unsigned int n_second_order_adjacent_vertices(const unsigned int) const override
static const unsigned short int _remaining_second_order_adjacent_vertices[5][4]
Matrix that tells which vertices define the location of mid-side (or second-order) nodes.
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const override
virtual unsigned int n_vertices() const override final
Definition cell_prism.h:91
virtual unsigned int n_edges() const override final
Definition cell_prism.h:96
virtual unsigned int n_sides() const override final
Definition cell_prism.h:86
static const unsigned short int _second_order_vertex_child_number[18]
Vector that names a child sharing each second order node.
Definition cell_prism.h:213
static const int num_sides
Geometric constants for all Prisms.
Definition cell_prism.h:73
static const unsigned short int _second_order_adjacent_vertices[9][2]
Matrix that tells which vertices define the location of mid-side (or second-order) nodes.
Definition cell_prism.h:208
static const unsigned short int _second_order_vertex_child_index[18]
Vector that names the child vertex index for each second order node.
Definition cell_prism.h:218
bool relative_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
The libMesh namespace provides an interface to certain functionality in the library.
IOPackage
libMesh interfaces with several different software packages for the purposes of creating,...
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
uint8_t dof_id_type
Definition id_types.h:67