libMesh
mesh_generation_test.C
Go to the documentation of this file.
1 #include <libmesh/libmesh.h>
2 #include <libmesh/distributed_mesh.h>
3 #include <libmesh/elem.h>
4 #include <libmesh/mesh_generation.h>
5 #include <libmesh/mesh_tools.h>
6 #include <libmesh/replicated_mesh.h>
7 
8 #include "test_comm.h"
9 #include "libmesh_cppunit.h"
10 
11 
12 using namespace libMesh;
13 
14 class MeshGenerationTest : public CppUnit::TestCase
15 {
21 public:
22  LIBMESH_CPPUNIT_TEST_SUITE( MeshGenerationTest );
23 
24  CPPUNIT_TEST( buildLineEdge2 );
25  CPPUNIT_TEST( buildLineEdge3 );
26  CPPUNIT_TEST( buildLineEdge4 );
27 # ifdef LIBMESH_ENABLE_AMR
28  CPPUNIT_TEST( buildSphereEdge2 );
29  CPPUNIT_TEST( buildSphereEdge3 );
30 // CPPUNIT_TEST( buildSphereEdge4 ); Doesn't work with AMR yet
31 # endif
32 
33 #if LIBMESH_DIM > 1
34  CPPUNIT_TEST( buildSquareTri3 );
35  CPPUNIT_TEST( buildSquareTri6 );
36  CPPUNIT_TEST( buildSquareTri7 );
37  CPPUNIT_TEST( buildSquareQuad4 );
38  CPPUNIT_TEST( buildSquareQuad8 );
39  CPPUNIT_TEST( buildSquareQuad9 );
40  CPPUNIT_TEST( buildSquareC0PolygonEven );
41  CPPUNIT_TEST( buildSquareC0PolygonOdd );
42 # ifdef LIBMESH_ENABLE_AMR
43  CPPUNIT_TEST( buildSphereTri3 );
44  CPPUNIT_TEST( buildSphereQuad4 );
45 # endif
46 #endif
47 #if LIBMESH_DIM > 2
48  CPPUNIT_TEST( buildCubeTet4 );
49  CPPUNIT_TEST( buildCubeTet10 );
50  CPPUNIT_TEST( buildCubeTet14 );
51  CPPUNIT_TEST( buildCubeHex8 );
52  CPPUNIT_TEST( buildCubeHex20 );
53  CPPUNIT_TEST( buildCubeHex27 );
54  CPPUNIT_TEST( buildCubePrism6 );
55  CPPUNIT_TEST( buildCubePrism15 );
56  CPPUNIT_TEST( buildCubePrism18 );
57  CPPUNIT_TEST( buildCubePrism20 );
58  CPPUNIT_TEST( buildCubePrism21 );
59 
60  // These tests throw an exception from contains_point() calls, and
61  // this simply aborts() when exceptions are not enabled.
62 #ifdef LIBMESH_ENABLE_EXCEPTIONS
63  CPPUNIT_TEST( buildCubePyramid5 );
64  CPPUNIT_TEST( buildCubePyramid13 );
65  CPPUNIT_TEST( buildCubePyramid14 );
66 
67 #ifdef LIBMESH_ENABLE_AMR
68  CPPUNIT_TEST( buildSphereHex27 );
69 #endif
70 #endif
71 
72 # ifdef LIBMESH_ENABLE_AMR
73  CPPUNIT_TEST( buildSphereHex8 );
74 # endif
75 #endif
76 
77  CPPUNIT_TEST_SUITE_END();
78 
79 protected:
80  std::unique_ptr<UnstructuredMesh> new_mesh (bool is_replicated)
81  {
82  if (is_replicated)
83  return std::make_unique<ReplicatedMesh>(*TestCommWorld);
84  return std::make_unique<DistributedMesh>(*TestCommWorld);
85  }
86 
87 public:
88  void setUp() {}
89 
90  void tearDown() {}
91 
92  void testBuildLine(UnstructuredMesh & mesh, unsigned int n, ElemType type)
93  {
94  MeshTools::Generation::build_line (mesh, n, -1.0, 2.0, type);
95  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n));
96  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
97  cast_int<dof_id_type>((Elem::type_to_n_nodes_map[type]-1)*n + 1));
98 
100  CPPUNIT_ASSERT_EQUAL(bbox.min()(0), Real(-1.0));
101  CPPUNIT_ASSERT_EQUAL(bbox.max()(0), Real(2.0));
102 
103  // Do serial assertions *after* all parallel assertions, so we
104  // stay in sync after failure on only some processor(s)
105  for (auto & elem : mesh.element_ptr_range())
106  CPPUNIT_ASSERT(elem->has_affine_map());
107  }
108 
109  void testBuildSquare(UnstructuredMesh & mesh, unsigned int n, ElemType type)
110  {
111  MeshTools::Generation::build_square (mesh, n, n, -2.0, 3.0, -4.0, 5.0, type);
112  if (type == C0POLYGON)
113  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n*n + 4 + 2 * (n - 1) + ((n - 1) / 2)));
114  else if (Elem::type_to_n_sides_map[type] == 4)
115  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n*n));
116  else
117  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n*n*2));
118 
119  switch (type)
120  {
121  case TRI3: // First-order elements
122  case QUAD4:
123  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
124  cast_int<dof_id_type>((n+1)*(n+1)));
125  break;
126  case TRI6: // Second-order elements
127  case QUAD9:
128  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
129  cast_int<dof_id_type>((2*n+1)*(2*n+1)));
130  break;
131  case QUAD8: // Not-really-second-order element missing center nodes
132  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
133  cast_int<dof_id_type>((2*n+1)*(2*n+1) - n*n));
134  break;
135  case TRI7: // Not-really-second-order element with extra center nodes
136  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
137  cast_int<dof_id_type>((2*n+1)*(2*n+1) + 2*n*n));
138  break;
139  case C0POLYGON:
140  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
141  cast_int<dof_id_type>(4 + 2*n*n + (n - 1) + 2*n + 2 * (n%2)));
142  break;
143  default: // Wait, what did we try to build?
144  CPPUNIT_ASSERT(false);
145  }
146 
147  // Our bounding boxes can be loose on higher order elements, but
148  // we can at least assert that they're not too tight
150  CPPUNIT_ASSERT(bbox.min()(0) <= Real(-2.0));
151  CPPUNIT_ASSERT(bbox.max()(0) >= Real(3.0));
152  CPPUNIT_ASSERT(bbox.min()(1) <= Real(-4.0));
153  CPPUNIT_ASSERT(bbox.max()(1) >= Real(5.0));
154 
155  // Do serial assertions *after* all parallel assertions, so we
156  // stay in sync after failure on only some processor(s)
157  if (type != C0POLYGON)
158  for (auto & elem : mesh.element_ptr_range())
159  CPPUNIT_ASSERT(elem->has_affine_map());
160  }
161 
162  void testBuildCube(UnstructuredMesh & mesh, unsigned int n, ElemType type)
163  {
164  MeshTools::Generation::build_cube (mesh, n, n, n, -2.0, 3.0, -4.0, 5.0, -6.0, 7.0, type);
165  switch (Elem::type_to_n_sides_map[type])
166  {
167  case 4: // tets
168  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n*n*n*24));
169  break;
170  case 5: // prisms, pyramids
171  if (type == PRISM6 || type == PRISM15 || type == PRISM18 ||
172  type == PRISM20 || type == PRISM21)
173  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n*n*n*2));
174  else
175  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n*n*n*6));
176  break;
177  case 6: // hexes
178  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), cast_int<dof_id_type>(n*n*n));
179  break;
180  default:
181  libmesh_error();
182  }
183 
184 
185  switch (Elem::type_to_n_nodes_map[type])
186  {
187  case 4: // First-order tets
188  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
189  cast_int<dof_id_type>((n+1)*(n+1)*(n+1) + n*n*n + 3*(n+1)*n*n));
190  break;
191  case 6: // First-order prisms and hexes use the same nodes
192  case 8:
193  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
194  cast_int<dof_id_type>((n+1)*(n+1)*(n+1)));
195  break;
196  case 10: // Second-order tets
197  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
198  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) + 14*n*n*n + 4*3*(n+1)*n*n));
199  break;
200  case 18:
201  case 27: // Second-order prisms and hexes use the same nodes
202  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
203  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1)));
204  break;
205  case 20:
206  if (type == HEX20)
207  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
208  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) - n*n*n - 3*(n+1)*n*n));
209  if (type == PRISM20)
210  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
211  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) + 2*(n+1)*n*n));
212  break;
213  case 21: // Prisms based on full Tri7 cross sections
214  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
215  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) + 2*(2*n+1)*n*n));
216  break;
217  case 15: // weird partial order prism
218  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
219  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) - n*n*n - 2*(n+1)*n*n));
220  break;
221  case 5: // pyramids
222  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
223  cast_int<dof_id_type>((n+1)*(n+1)*(n+1) + n*n*n));
224  break;
225  case 13:
226  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
227  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) + 8*n*n*n - 3*(n+1)*n*n));
228  break;
229  case 14: // pyramids, tets
230  if (type == PYRAMID14)
231  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
232  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) + 8*n*n*n));
233  else // TET14
234  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(),
235  cast_int<dof_id_type>((2*n+1)*(2*n+1)*(2*n+1) + 14*n*n*n + 4*3*(n+1)*n*n +
236  36*n*n*n + 4*3*(n+1)*n*n));
237  break;
238  default:
239  libmesh_error();
240  }
241 
242  // Our bounding boxes can be loose on higher order elements, but
243  // we can at least assert that they're not too tight
245  CPPUNIT_ASSERT(bbox.min()(0) <= Real(-2.0));
246  CPPUNIT_ASSERT(bbox.max()(0) >= Real(3.0));
247  CPPUNIT_ASSERT(bbox.min()(1) <= Real(-4.0));
248  CPPUNIT_ASSERT(bbox.max()(1) >= Real(5.0));
249  CPPUNIT_ASSERT(bbox.min()(2) <= Real(-6.0));
250  CPPUNIT_ASSERT(bbox.max()(2) >= Real(7.0));
251 
252  // We don't yet try to do affine map optimizations on pyramids
253  if (type == PYRAMID5 ||
254  type == PYRAMID13 ||
255  type == PYRAMID14)
256  return;
257 
258  // Do serial assertions *after* all parallel assertions, so we
259  // stay in sync after failure on only some processor(s)
260  for (auto & elem : mesh.element_ptr_range())
261  CPPUNIT_ASSERT(elem->has_affine_map());
262  }
263 
264  void testBuildSphere(unsigned int n_ref, ElemType type)
265  {
267  MeshTools::Generation::build_sphere (rmesh, 2.0, n_ref, type);
268 
270  dmesh.allow_renumbering(false);
271  MeshTools::Generation::build_sphere (dmesh, 2.0, n_ref, type);
272  }
273 
274 
275  typedef void (MeshGenerationTest::*Builder)(UnstructuredMesh&, unsigned int, ElemType);
276 
277  void tester(Builder f, unsigned int n, ElemType type)
278  {
279  for (int is_replicated = 0; is_replicated != 2; ++is_replicated)
280  {
281  for (int skip_renumber = 0 ; skip_renumber != 2; ++skip_renumber)
282  {
283  std::unique_ptr<UnstructuredMesh> mesh =
284  new_mesh(is_replicated);
285  mesh->allow_renumbering(!skip_renumber);
286  (this->*f)(*mesh, n, type);
287  }
288  }
289  }
290 
294 
295  void buildSphereEdge2 () { LOG_UNIT_TEST; testBuildSphere(2, EDGE2); }
296  void buildSphereEdge3 () { LOG_UNIT_TEST; testBuildSphere(2, EDGE3); }
297  void buildSphereEdge4 () { LOG_UNIT_TEST; testBuildSphere(2, EDGE4); }
298 
307 
308  void buildSphereTri3 () { LOG_UNIT_TEST; testBuildSphere(2, TRI3); }
309  void buildSphereQuad4 () { LOG_UNIT_TEST; testBuildSphere(2, QUAD4); }
310 
311  void buildCubeTet4 () { LOG_UNIT_TEST; tester(&MeshGenerationTest::testBuildCube, 2, TET4); }
314  void buildCubeHex8 () { LOG_UNIT_TEST; tester(&MeshGenerationTest::testBuildCube, 2, HEX8); }
322 
323  // These tests throw an exception from contains_point() calls, and
324  // this simply aborts() when exceptions are not enabled.
325 #ifdef LIBMESH_ENABLE_EXCEPTIONS
329 #endif
330 
331  void buildSphereHex8 () { LOG_UNIT_TEST; testBuildSphere(2, HEX8); }
332  void buildSphereHex27 () { LOG_UNIT_TEST; testBuildSphere(2, HEX27); }
333 };
334 
335 
ElemType
Defines an enum for geometric element types.
void testBuildLine(UnstructuredMesh &mesh, unsigned int n, ElemType type)
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
void testBuildCube(UnstructuredMesh &mesh, unsigned int n, ElemType type)
static const unsigned int type_to_n_sides_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of sides on the element...
Definition: elem.h:678
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use...
Definition: mesh_base.h:1345
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:566
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
The libMesh namespace provides an interface to certain functionality in the library.
static const unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
Definition: elem.h:643
std::unique_ptr< UnstructuredMesh > new_mesh(bool is_replicated)
void testBuildSquare(UnstructuredMesh &mesh, unsigned int n, ElemType type)
The UnstructuredMesh class is derived from the MeshBase class.
const Point & min() const
Definition: bounding_box.h:77
CPPUNIT_TEST_SUITE_REGISTRATION(MeshGenerationTest)
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
Defines a Cartesian bounding box by the two corner extremum.
Definition: bounding_box.h:40
void tester(Builder f, unsigned int n, ElemType type)
void build_sphere(UnstructuredMesh &mesh, const Real radius=1, const unsigned int n_refinements=2, const ElemType type=INVALID_ELEM, const unsigned int n_smooth=2, const bool flat=true)
Meshes a spherical or mapped-spherical domain.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void tester(const std::set< int > &s, int i)
void build_line(UnstructuredMesh &mesh, const unsigned int nx, const Real xmin=0., const Real xmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 1D meshes.
const Point & max() const
Definition: bounding_box.h:86
virtual dof_id_type n_elem() const =0
void ErrorVector unsigned int
Definition: adjoints_ex3.C:360
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
virtual dof_id_type n_nodes() const =0
void testBuildSphere(unsigned int n_ref, ElemType type)