libMesh
which_node_am_i_test.C
Go to the documentation of this file.
1 #include <libmesh/elem.h>
2 #include <libmesh/reference_elem.h>
3 
4 // Unit test headers
5 #include "stream_redirector.h"
6 #include "libmesh_cppunit.h"
7 
8 using namespace libMesh;
9 
10 class WhichNodeAmITest : public CppUnit::TestCase
11 {
12 
13 public:
14  LIBMESH_CPPUNIT_TEST_SUITE( WhichNodeAmITest );
15 #if LIBMESH_DIM > 2
16  CPPUNIT_TEST( testPyramids );
17  CPPUNIT_TEST( testPrisms );
18  CPPUNIT_TEST( testTets );
19  CPPUNIT_TEST( testHexes );
20 #endif
21  CPPUNIT_TEST_SUITE_END();
22 
23 public:
24 
25  void testPyramids()
26  {
27  LOG_UNIT_TEST;
28 
29  const Elem & pyr5 = ReferenceElem::get(PYRAMID5);
30  // The last node on the right side (1) should be node 4 (apex node).
31  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4), pyr5.local_side_node(/*side=*/1, /*node=*/2));
32  // (Edge 0, Node 0) -> Local node 0
33  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), pyr5.local_edge_node(/*edge=*/0, /*node=*/0));
34  // Second node of edges 4-7 is the apex node (4).
35  for (unsigned int edge=4; edge<8; ++edge)
36  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4),
37  pyr5.local_edge_node(edge, /*node=*/1));
38 
39  // Test the libmesh_asserts when they are enabled and exceptions
40  // are available. If exceptions aren't available, libmesh_assert
41  // simply aborts, so we can't unit test in that case.
42 #if !defined(NDEBUG) && defined(LIBMESH_ENABLE_EXCEPTIONS)
43  try
44  {
45  // Avoid sending confusing error messages to the console.
46  StreamRedirector stream_redirector;
47 
48  // Asking for the 4th node on a triangular face should throw.
49  unsigned int n = pyr5.local_side_node(1, 3);
50 
51  // We shouldn't get here if the line above throws. If we do
52  // get here, there's no way this assert will pass.
53  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), n);
54  }
55  catch (...) {}
56 #endif
57 
58 #ifdef NDEBUG
59  // In optimized mode, we expect to get the "dummy" value 99.
60  unsigned int n = pyr5.local_side_node(1, 3);
61  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(99), n);
62 #endif
63 
64  const Elem & pyr13 = ReferenceElem::get(PYRAMID13);
65  // The last node on the right side (1) should be node 10.
66  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(10), pyr13.local_side_node(/*side=*/1, /*node=*/5));
67  // Second node of edges 4-7 is the apex node (4).
68  for (unsigned int edge=4; edge<8; ++edge)
69  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4),
70  pyr13.local_edge_node(edge, /*node=*/1));
71 
72  const Elem & pyr14 = ReferenceElem::get(PYRAMID14);
73  // The central node of the base should be node 13
74  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(13), pyr14.local_side_node(/*side=*/4, /*node=*/8));
75  // Second node of edges 4-7 is the apex node (4).
76  for (unsigned int edge=4; edge<8; ++edge)
77  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4),
78  pyr14.local_edge_node(edge, /*node=*/1));
79 
80  const Elem & pyr18 = ReferenceElem::get(PYRAMID18);
81  // The central node of the base should be node 13
82  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(13), pyr18.local_side_node(/*side=*/4, /*node=*/8));
83  // The central node of the sides should be nodes 14-17
84  for (unsigned int side=0; side<4; ++side)
85  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(14+side), pyr18.local_side_node(side, /*node=*/6));
86  // Second node of edges 4-7 is the apex node (4).
87  for (unsigned int edge=4; edge<8; ++edge)
88  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4),
89  pyr18.local_edge_node(edge, /*node=*/1));
90  }
91 
92 
93 
94  void testPrisms()
95  {
96  LOG_UNIT_TEST;
97 
98  // A PRISM6 has four nodes on some sides and three nodes on others
99  for (ElemType elem_type : {PRISM6, PRISM15, PRISM18, PRISM20, PRISM21})
100  {
101  const Elem & prism = ReferenceElem::get(elem_type);
102  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4),
103  prism.local_side_node(/*side=*/4, /*node=*/1));
104  // Edges 3, 4, 5 are the "vertical" Prism edges.
105  // Edges 0-2 and 6-8 are the "triangle" Prism edges.
106  // We orient edges by volume-node order for some reason, which
107  // makes some cases here weird.
108  for (unsigned int i=0; i!=3; ++i)
109  {
110  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i%2),
111  prism.local_edge_node(/*edge=*/i, /*node=*/0));
112  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1+(i>0)),
113  prism.local_edge_node(/*edge=*/i, /*node=*/1));
114  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i),
115  prism.local_edge_node(/*edge=*/i+3, /*node=*/0));
116  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+3),
117  prism.local_edge_node(/*edge=*/i+3, /*node=*/1));
118  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i%2+3),
119  prism.local_edge_node(/*edge=*/i+6, /*node=*/0));
120  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4+(i>0)),
121  prism.local_edge_node(/*edge=*/i+6, /*node=*/1));
122  }
123  }
124 
125  // Test the libmesh_asserts when they are enabled and exceptions
126  // are available. If exceptions aren't available, libmesh_assert
127  // simply aborts, so we can't unit test in that case.
128 #if !defined(NDEBUG) && defined(LIBMESH_ENABLE_EXCEPTIONS)
129  try
130  {
131  const Elem & prism6 = ReferenceElem::get(PRISM6);
132  // Avoid sending confusing error messages to the console.
133  StreamRedirector stream_redirector;
134 
135  // Asks for the 3rd node on a Tri face which only has
136  // indices 0, 1, and 2. Should throw an exception
137  // (libmesh_assert throws an exception) when NDEBUG is not
138  // defined.
139  unsigned int n = prism6.local_side_node(0, 3);
140 
141  // We shouldn't get here if the line above throws. If we do
142  // get here, there's no way this assert will pass.
143  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), n);
144  }
145  catch (...) {}
146 #endif
147 
148 #ifdef NDEBUG
149  // In optimized mode, we expect to get the "dummy" value 99.
150  {
151  const Elem & prism6 = ReferenceElem::get(PRISM6);
152  unsigned int n = prism6.local_side_node(0, 3);
153  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(99), n);
154  }
155 #endif
156 
157  // Test the Prism15 midedge nodes.
158  for (ElemType elem_type : {PRISM15, PRISM18, PRISM20, PRISM21})
159  {
160  const Elem & prism = ReferenceElem::get(elem_type);
161  for (unsigned int i=0; i!=3; ++i)
162  {
163  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+6),
164  prism.local_edge_node(/*edge=*/i, /*node=*/2));
165  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+6),
166  prism.local_side_node(/*side=*/i+1, /*node=*/4));
167  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(8-i), // "flipped" side
168  prism.local_side_node(/*side=*/0, /*node=*/i+3));
169  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+9),
170  prism.local_edge_node(/*edge=*/i+3, /*node=*/2));
171  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+9),
172  prism.local_side_node(/*side=*/i+1, /*node=*/7));
173  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+9),
174  prism.local_side_node(/*side=*/(i+2)%3+1, /*node=*/5));
175  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+12),
176  prism.local_edge_node(/*edge=*/i+6, /*node=*/2));
177  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+12),
178  prism.local_side_node(/*side=*/i+1, /*node=*/6));
179  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(i+12),
180  prism.local_side_node(/*side=*/4, /*node=*/i+3));
181  }
182  }
183 
184  // Test the Prism18 face nodes.
185  for (ElemType elem_type : {PRISM18, PRISM20, PRISM21})
186  {
187  const Elem & prism = ReferenceElem::get(elem_type);
188  // Faces 1, 2, 3 are the "vertical" Prism sides
189  for (unsigned int side=1; side<4; ++side)
190  {
191  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(side+14),
192  prism.local_side_node(/*side=*/side, /*node=*/8));
193  }
194  }
195 
196  // Test the Prism20 face nodes.
197  for (ElemType elem_type : {PRISM20, PRISM21})
198  {
199  const Elem & prism = ReferenceElem::get(elem_type);
200  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(18),
201  prism.local_side_node(/*side=*/0, /*node=*/6));
202  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(19),
203  prism.local_side_node(/*side=*/4, /*node=*/6));
204  }
205 
206  }
207 
208 
209 
210  void testTets()
211  {
212  LOG_UNIT_TEST;
213 
214  const Elem & tet4 = ReferenceElem::get(TET4);
215  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), tet4.local_side_node(/*side=*/0, /*node=*/0));
216 
217  // Edges 3, 4, 5 all connect to the "apex" node 3
218  for (unsigned int edge=3; edge<6; ++edge)
219  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3),
220  tet4.local_edge_node(edge, /*node=*/1));
221 
222  const Elem & tet10 = ReferenceElem::get(TET10);
223  // Node 4 is a mid-edge node on side 1.
224  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4), tet10.local_side_node(/*side=*/1, /*node=*/3));
225  // Nodes 4, 5, 6 are mid-edge nodes of the first three edges
226  for (unsigned int edge=0; edge<3; ++edge)
227  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(edge + 4),
228  tet10.local_edge_node(edge, /*node=*/2));
229  }
230 
231 
232 
233  void testHexes()
234  {
235  LOG_UNIT_TEST;
236 
237  // Top left node on back side.
238  const Elem & hex8 = ReferenceElem::get(HEX8);
239  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(7), hex8.local_side_node(/*side=*/3, /*node=*/2));
240 
241  const Elem & hex20 = ReferenceElem::get(HEX20);
242  const Elem & hex27 = ReferenceElem::get(HEX27);
243 
244  // The vertices (i.e. the first 4 nodes on each side should match for all of the Hex types.
245  for (unsigned int side=0; side<hex8.n_sides(); ++side)
246  for (unsigned int node=0; node<4; ++node)
247  {
248  // Make sure the Hex8 and Hex20 implementations agree.
249  CPPUNIT_ASSERT_EQUAL(hex8.local_side_node(side, node),
250  hex20.local_side_node(side, node));
251 
252  // Make sure the Hex20 and Hex27 implementations agree.
253  CPPUNIT_ASSERT_EQUAL(hex20.local_side_node(side, node),
254  hex27.local_side_node(side, node));
255  }
256 
257  for (unsigned int edge=0; edge<hex8.n_edges(); ++edge)
258  for (unsigned int node=0; node<2; ++node)
259  {
260  // Make sure the Hex8 and Hex20 implementations agree.
261  CPPUNIT_ASSERT_EQUAL(hex8.local_edge_node(edge, node),
262  hex20.local_edge_node(edge, node));
263 
264  // Make sure the Hex20 and Hex27 implementations agree.
265  CPPUNIT_ASSERT_EQUAL(hex20.local_edge_node(edge, node),
266  hex27.local_edge_node(edge, node));
267  }
268  }
269 };
270 
ElemType
Defines an enum for geometric element types.
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
This class uses RAII to control redirecting the libMesh::err stream to NULL and restoring it around s...
CPPUNIT_TEST_SUITE_REGISTRATION(WhichNodeAmITest)
The libMesh namespace provides an interface to certain functionality in the library.
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const =0
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const =0
Similar to Elem::local_side_node(), but instead of a side id, takes an edge id and a node id on that ...
virtual unsigned int n_edges() const =0
virtual unsigned int n_sides() const =0
const Elem & get(const ElemType type_in)