libMesh
boundary_mesh.C
Go to the documentation of this file.
1 #include <libmesh/distributed_mesh.h>
2 #include <libmesh/mesh.h>
3 #include <libmesh/mesh_generation.h>
4 #include <libmesh/mesh_refinement.h>
5 #include <libmesh/mesh_serializer.h>
6 #include <libmesh/remote_elem.h>
7 #include <libmesh/replicated_mesh.h>
8 #include <libmesh/boundary_info.h>
9 
10 #include "test_comm.h"
11 #include "libmesh_cppunit.h"
12 
13 #include <memory>
14 
15 namespace {
16 
17  using namespace libMesh;
18 
19  // Check that the interior_parent side indices that we set on a
20  // BoundaryMesh as extra integers agree with the side returned by
21  // which_side_am_i().
22  void check_parent_side_index_tag(UnstructuredMesh & boundary_mesh)
23  {
24  const unsigned int parent_side_index_tag =
25  boundary_mesh.get_elem_integer_index("parent_side_index");
26 
27  for (const auto & belem : boundary_mesh.element_ptr_range())
28  {
29  const dof_id_type parent_side_index =
30  belem->get_extra_integer(parent_side_index_tag);
31 
32  if (belem->interior_parent() != remote_elem)
33  CPPUNIT_ASSERT_EQUAL
34  (static_cast<dof_id_type>(belem->interior_parent()->which_side_am_i(belem)),
35  parent_side_index);
36  }
37  }
38 
39  void sanity_check_mesh(const UnstructuredMesh & mesh,
40  ElemType boundary_type,
41  ElemType interior_type,
42  bool is_mixed)
43  {
44  const unsigned int interior_dim = Elem::type_to_dim_map[interior_type];
45 
46  for (const auto & elem : mesh.active_element_ptr_range())
47  {
48  const Elem * pip = elem->dim() < interior_dim ?
49  elem->interior_parent() : nullptr;
50 
51  // On a DistributedMesh we might not be able to see the
52  // interior_parent of a non-local element
53  if (pip == remote_elem)
54  {
55  CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
56  continue;
57  }
58 
59  // The boundary elements should have interior parents of the
60  // specified type; interior element shouldn't have any
61  // interior parents.
62  if (pip)
63  {
64  CPPUNIT_ASSERT_EQUAL(elem->type(), boundary_type);
65  CPPUNIT_ASSERT_EQUAL(pip->type(), interior_type);
66  CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
67  }
68  else
69  {
70  // We should only see interior elements if we expected
71  // them
72  CPPUNIT_ASSERT(is_mixed);
73  CPPUNIT_ASSERT_EQUAL(elem->type(), interior_type);
74  }
75  }
76  }
77 }
78 
79 using namespace libMesh;
80 
81 class BoundaryMesh0DTest : public CppUnit::TestCase {
86 public:
87  LIBMESH_CPPUNIT_TEST_SUITE( BoundaryMesh0DTest );
88 
89 #if LIBMESH_DIM > 1
90  CPPUNIT_TEST( testMesh );
91 #endif
92 
93  CPPUNIT_TEST_SUITE_END();
94 
95 protected:
96 
97  std::unique_ptr<UnstructuredMesh> _mesh;
98  std::unique_ptr<UnstructuredMesh> _replicated_boundary_mesh;
99  std::unique_ptr<UnstructuredMesh> _distributed_boundary_mesh;
100  std::unique_ptr<UnstructuredMesh> _interior_node_mesh;
101 
102  void build_mesh()
103  {
104  _mesh = std::make_unique<Mesh>(*TestCommWorld);
105  _replicated_boundary_mesh = std::make_unique<ReplicatedMesh>(*TestCommWorld);
106  _distributed_boundary_mesh = std::make_unique<DistributedMesh>(*TestCommWorld);
107  _interior_node_mesh = std::make_unique<Mesh>(*TestCommWorld);
108 
110  0.2, 0.8, EDGE3);
111 
112  static constexpr boundary_id_type bid_int = 2;
113 
114  // Add an interior boundary too
115  BoundaryInfo & bi = _mesh->get_boundary_info();
116  for (auto & elem : _mesh->active_element_ptr_range())
117  {
118  const Point c = elem->vertex_average();
119  if (c(0) > 0.6)
120  bi.add_side(elem, 0, bid_int);
121  }
122 
123  // We'll need to skip most repartitioning with DistributedMesh for
124  // now; otherwise the boundary meshes' interior parents might get
125  // shuffled off to different processors.
126  if (!_mesh->is_serial())
127  {
128  _mesh->skip_noncritical_partitioning(true);
129  _replicated_boundary_mesh->skip_noncritical_partitioning(true);
130  _distributed_boundary_mesh->skip_noncritical_partitioning(true);
131  }
132  }
133 
135  {
136  // Get the border of the line
137  const std::set<boundary_id_type> exterior_boundaries {0, 1};
138 
139  _mesh->get_boundary_info().sync(exterior_boundaries,
140  *_replicated_boundary_mesh);
141  check_parent_side_index_tag(*_replicated_boundary_mesh);
142 
143  _mesh->get_boundary_info().sync(exterior_boundaries,
144  *_distributed_boundary_mesh);
145  check_parent_side_index_tag(*_distributed_boundary_mesh);
146 
147  const std::set<boundary_id_type> interior_boundaries {2};
148  _mesh->get_boundary_info().sync(interior_boundaries,
149  *_interior_node_mesh);
150  check_parent_side_index_tag(*_interior_node_mesh);
151 
152  // Add the right side of the square to the square; this should
153  // make it a mixed dimension mesh. We skip storing the parent
154  // side ids (which is the default) since they are not needed
155  // in this particular test.
156  std::set<boundary_id_type> right_id;
157  right_id.insert(1);
158 
159  _mesh->get_boundary_info().add_elements
160  (right_id, *_mesh, /*store_parent_side_ids=*/false);
161  _mesh->prepare_for_use();
162  }
163 
164 public:
165  void setUp()
166  {
167 #if LIBMESH_DIM > 1
168  this->build_mesh();
169  this->sync_and_test_meshes();
170 #endif
171  }
172 
173  void testMesh()
174  {
175  LOG_UNIT_TEST;
176 
177  // There'd better be 3 + 1 elements in the interior plus right
178  // boundary
179  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4),
180  _mesh->n_elem());
181 
182  // There'd better be 7 nodes in the interior
183  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(7),
184  _mesh->n_nodes());
185 
186  // There'd better be 2 elements on the exterior boundary
187  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
188  _replicated_boundary_mesh->n_elem());
189  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
190  _distributed_boundary_mesh->n_elem());
191 
192  // There'd better be 2 nodes on the exterior boundary
193  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
194  _replicated_boundary_mesh->n_nodes());
195  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
196  _distributed_boundary_mesh->n_nodes());
197 
198  // There'd better be 1 nodeelem on the interior boundary
199  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(1),
200  _interior_node_mesh->n_elem());
201  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(1),
202  _interior_node_mesh->n_nodes());
203 
204  this->sanityCheck();
205  }
206 
208  {
209  LOG_UNIT_TEST;
210 
211  MeshSerializer internal_serializer(*_distributed_boundary_mesh);
212 
213  // There'd better be 2 elements on the exterior boundary
214  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
215  _replicated_boundary_mesh->n_elem());
216  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
217  _distributed_boundary_mesh->n_elem());
218 
219  // There'd better be 2 nodes on the exterior boundary
220  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
221  _replicated_boundary_mesh->n_nodes());
222  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
223  _distributed_boundary_mesh->n_nodes());
224 
225  this->sanityCheck();
226  }
227 
228  void sanityCheck()
229  {
230  sanity_check_mesh(*_mesh, NODEELEM, EDGE3, true);
231 
232  sanity_check_mesh(*_replicated_boundary_mesh, NODEELEM, EDGE3, false);
233  sanity_check_mesh(*_distributed_boundary_mesh, NODEELEM, EDGE3, false);
234  sanity_check_mesh(*_interior_node_mesh, NODEELEM, EDGE3, false);
235  }
236 };
237 
239 
240 
241 class BoundaryMeshTest : public CppUnit::TestCase {
246 public:
247  LIBMESH_CPPUNIT_TEST_SUITE( BoundaryMeshTest );
248 
249 #if LIBMESH_DIM > 1
250  CPPUNIT_TEST( testMesh );
251  CPPUNIT_TEST( testBoundarySerialization );
252 #endif
253 
254  CPPUNIT_TEST_SUITE_END();
255 
256 protected:
257 
258  std::unique_ptr<UnstructuredMesh> _mesh;
259  std::unique_ptr<UnstructuredMesh> _multi_boundary_mesh;
260  std::unique_ptr<UnstructuredMesh> _exterior_boundary_mesh;
261  std::unique_ptr<UnstructuredMesh> _left_boundary_mesh;
262  std::unique_ptr<UnstructuredMesh> _internal_boundary_mesh;
263 
264  // We create internal sideset IDs that do not conflict with
265  // sidesets 0-3 that get created by build_square().
266  static constexpr boundary_id_type bid1 = 5;
267  static constexpr boundary_id_type bid2 = 6;
268 
269  void build_mesh()
270  {
271  _mesh = std::make_unique<Mesh>(*TestCommWorld);
272  _multi_boundary_mesh = std::make_unique<Mesh>(*TestCommWorld);
273  _exterior_boundary_mesh = std::make_unique<Mesh>(*TestCommWorld);
274 
275  // We want to test Distributed->Replicated sync; this does that in
276  // some builds
277  _left_boundary_mesh = std::make_unique<ReplicatedMesh>(*TestCommWorld);
278 
279  // We want to test Replicated->Distributed sync; this does that in
280  // other builds
281  _internal_boundary_mesh = std::make_unique<DistributedMesh>(*TestCommWorld);
282 
284  0.2, 0.8, 0.2, 0.7, QUAD9);
285 
286  // We'll need to skip most repartitioning with DistributedMesh for
287  // now; otherwise the boundary meshes' interior parents might get
288  // shuffled off to different processors.
289  if (!_mesh->is_serial())
290  {
291  _mesh->skip_noncritical_partitioning(true);
292  _left_boundary_mesh->skip_noncritical_partitioning(true);
293  _multi_boundary_mesh->skip_noncritical_partitioning(true);
294  _exterior_boundary_mesh->skip_noncritical_partitioning(true);
295  _internal_boundary_mesh->skip_noncritical_partitioning(true);
296  }
297 
298  // Set subdomain ids for specific elements. This allows us to later
299  // build an internal sideset with respect to a given
300  // subdomain. The element subdomains look like:
301  // ___________________
302  // | 2 | 2 | 2 |
303  // |_____|_____|_____|
304  // | 2 | 2 | 2 |
305  // |_____|_____|_____|
306  // | 2 | 2 | 2 |
307  // |_____|_____|_____|
308  // | 1 | 1 | 2 |
309  // |_____|_____|_____|
310  // | 1 | 1 | 2 |
311  // |_____|_____|_____|
312  //
313  // and we will create an internal sideset along the border between
314  // subdomains 1 and 2.
315 
316  for (auto & elem : _mesh->active_element_ptr_range())
317  {
318  const Point c = elem->vertex_average();
319  if (c(0) < 0.6 && c(1) < 0.4)
320  elem->subdomain_id() = 1;
321  else
322  elem->subdomain_id() = 2;
323  }
324 
325  // To test the "relative to" feature, we add the same sides to the
326  // same sideset twice, from elements in subdomain 2 the second
327  // time. These should not show up in the BoundaryMesh, i.e. there
328  // should not be overlapped elems in the BoundaryMesh.
329  BoundaryInfo & bi = _mesh->get_boundary_info();
330 
331  for (auto & elem : _mesh->active_element_ptr_range())
332  {
333  const Point c = elem->vertex_average();
334  if (c(0) < 0.6 && c(1) < 0.4)
335  {
336  if (c(0) > 0.4)
337  bi.add_side(elem, 1, bid1);
338  if (c(1) > 0.3)
339  bi.add_side(elem, 2, bid1);
340  }
341  else
342  {
343  if (c(0) < 0.75 && c(1) < 0.4)
344  bi.add_side(elem, 3, bid2);
345  if (c(0) < 0.6 && c(1) < 0.5)
346  bi.add_side(elem, 0, bid2);
347  }
348  }
349  }
350 
352  {
353  // Get the border of the square
354  const std::set<boundary_id_type> exterior_boundaries {0, 1, 2, 3};
355  _mesh->get_boundary_info().sync(exterior_boundaries,
356  *_exterior_boundary_mesh);
357  check_parent_side_index_tag(*_exterior_boundary_mesh);
358 
359  // The mesh of all boundaries is, because of the two nodes each
360  // joining three edges where the internal boundary meets the
361  // external boundary, not a manifold mesh. We still have work to
362  // do to properly support non-manifold meshes, and
363  // find_neighbors() when preparing such a mesh is likely to fail,
364  // so we'll just do the best test we can here, requesting a set of
365  // three different boundaries. We drop the left and bottom
366  // boundaries because they have any T intersections with the
367  // interior boundaries, and we drop one of the interior boundaries
368  // because with both together we'd have 4 edges meeting at every
369  // interior boundary vertex.
370  const std::set<boundary_id_type> multi_boundaries {1, 2, 5};
371  _mesh->get_boundary_info().sync(multi_boundaries,
372  *_multi_boundary_mesh);
373  check_parent_side_index_tag(*_multi_boundary_mesh);
374 
375  std::set<boundary_id_type> left_id, right_id;
376  left_id.insert(3);
377  right_id.insert(1);
378 
379  // Add the right side of the square to the square; this should
380  // make it a mixed dimension mesh. We skip storing the parent
381  // side ids (which is the default) since they are not needed
382  // in this particular test.
383  _mesh->get_boundary_info().add_elements
384  (right_id, *_mesh, /*store_parent_side_ids=*/false);
385  _mesh->prepare_for_use();
386 
387  // Add the left side of the square to its own boundary mesh.
388  _mesh->get_boundary_info().sync(left_id, *_left_boundary_mesh);
389  check_parent_side_index_tag(*_left_boundary_mesh);
390 
391  // Create a BoundaryMesh from the internal sidesets relative to subdomain 1.
392  {
393  std::set<boundary_id_type> requested_boundary_ids {bid1, bid2};
394  std::set<subdomain_id_type> subdomains_relative_to;
395  subdomains_relative_to.insert(1);
396  _mesh->get_boundary_info().sync(requested_boundary_ids,
397  *_internal_boundary_mesh,
398  subdomains_relative_to);
399  check_parent_side_index_tag(*_internal_boundary_mesh);
400  }
401  }
402 
403 public:
404  void setUp()
405  {
406 #if LIBMESH_DIM > 1
407  this->build_mesh();
408  this->sync_and_test_meshes();
409 #endif
410  }
411 
412  void testMesh()
413  {
414  LOG_UNIT_TEST;
415 
416  // There'd better be 3*5 + 5 elements in the interior plus right
417  // boundary
418  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(20),
419  _mesh->n_elem());
420 
421  // There'd better be 7*11 nodes in the interior
422  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(77),
423  _mesh->n_nodes());
424 
425  // There'd better be 2*(3+5) elements on the exterior boundary
426  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(16),
427  _exterior_boundary_mesh->n_elem());
428 
429  // There'd better be 2*2*(3+5) nodes on the exterior boundary
430  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
431  _exterior_boundary_mesh->n_nodes());
432 
433  // There'd better be 5 elements on the left boundary
434  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(5),
435  _left_boundary_mesh->n_elem());
436 
437  // There'd better be 2*5+1 nodes on the left boundary
438  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(11),
439  _left_boundary_mesh->n_nodes());
440 
441  // There are four elements in the one-sided internal sideset mesh.
442  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4),
443  _internal_boundary_mesh->n_elem());
444 
445  // There are 2*n_elem + 1 nodes in the one-sided internal sideset mesh.
446  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(9),
447  _internal_boundary_mesh->n_nodes());
448 
449  // There'd better be 3+5 + 4 elements on the multi-boundary
450  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
451  _multi_boundary_mesh->n_elem());
452 
453  // There'd better be (3+5)*2+1 + 4*2+1 nodes on the multi-boundary
454  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(26),
455  _multi_boundary_mesh->n_nodes());
456 
457  this->sanityCheck();
458  }
459 
461  {
462  LOG_UNIT_TEST;
463 
464  MeshSerializer internal_serializer(*_internal_boundary_mesh);
465 
466  // There are four elements in the internal sideset mesh.
467  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4),
468  _internal_boundary_mesh->n_elem());
469 
470  // There are 2*n_elem + 1 nodes in the internal sideset mesh.
471  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(9),
472  _internal_boundary_mesh->n_nodes());
473 
474  this->sanityCheck();
475  }
476 
477  void sanityCheck()
478  {
479  sanity_check_mesh(*_mesh, EDGE3, QUAD9, true);
480  sanity_check_mesh(*_multi_boundary_mesh, EDGE3, QUAD9, false);
481  sanity_check_mesh(*_exterior_boundary_mesh, EDGE3, QUAD9, false);
482  sanity_check_mesh(*_left_boundary_mesh, EDGE3, QUAD9, false);
483  sanity_check_mesh(*_internal_boundary_mesh, EDGE3, QUAD9, false);
484 
485  for (const auto & elem : _left_boundary_mesh->active_element_ptr_range())
486  {
487  // We only added left edges here
488  LIBMESH_ASSERT_FP_EQUAL(0.2, elem->vertex_average()(0),
490  }
491 
492  // Sanity check for the internal sideset mesh.
493  for (const auto & elem : _internal_boundary_mesh->active_element_ptr_range())
494  {
495  // All of the elements in the internal sideset mesh should
496  // have the same subdomain id as the parent Elems (i.e. 1)
497  // they came from.
498  CPPUNIT_ASSERT_EQUAL(static_cast<subdomain_id_type>(1),
499  elem->subdomain_id());
500  }
501  }
502 
503 };
504 
506 
507 #ifdef LIBMESH_ENABLE_AMR
508 
516 public:
517  LIBMESH_CPPUNIT_TEST_SUITE( BoundaryRefinedMeshTest );
518 
519 #if LIBMESH_DIM > 1
520  CPPUNIT_TEST( testMesh );
521  CPPUNIT_TEST( testBoundarySerialization );
522 #endif
523 
524  CPPUNIT_TEST_SUITE_END();
525 
526  // Yes, this is necessary. Somewhere in those macros is a protected/private
527 public:
528 
529  void setUp()
530  {
531 #if LIBMESH_DIM > 1
532  this->build_mesh();
533  this->sync_and_test_meshes();
534 
535  // Need to refine interior mesh before separate boundary meshes,
536  // if we want to get interior_parent links right.
537  MeshRefinement(*_mesh).uniformly_refine(1);
538 
539  MeshRefinement(*_multi_boundary_mesh).uniformly_refine(1);
540  MeshRefinement(*_exterior_boundary_mesh).uniformly_refine(1);
541  MeshRefinement(*_left_boundary_mesh).uniformly_refine(1);
542  MeshRefinement(*_internal_boundary_mesh).uniformly_refine(1);
543 #endif
544  }
545 
546  void testMesh()
547  {
548  LOG_UNIT_TEST;
549 
550  // There'd better be 3*5*4 + 5*2 active elements in the interior
551  // plus right boundary
552  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(70),
553  _mesh->n_active_elem());
554 
555  // Plus the original 20 now-inactive elements
556  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(90),
557  _mesh->n_elem());
558 
559  // There'd better be 13*21 nodes in the interior
560  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(273),
561  _mesh->n_nodes());
562 
563  // There'd better be 2*2*(3+5) active elements on the exterior boundary
564  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
565  _exterior_boundary_mesh->n_active_elem());
566 
567  // Plus the original 16 now-inactive elements
568  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(48),
569  _exterior_boundary_mesh->n_elem());
570 
571  // There'd better be 2*2*2*(3+5) nodes on the exterior boundary
572  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(64),
573  _exterior_boundary_mesh->n_nodes());
574 
575  // There'd better be 2*5 active elements on the left boundary
576  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(10),
577  _left_boundary_mesh->n_active_elem());
578 
579  // Plus the original 5 now-inactive elements
580  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(15),
581  _left_boundary_mesh->n_elem());
582 
583  // There'd better be 2*2*5+1 nodes on the left boundary
584  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(21),
585  _left_boundary_mesh->n_nodes());
586 
587  // There'd better be 2*4 active elements on the one-sided internal
588  // sideset mesh
589  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
590  _internal_boundary_mesh->n_active_elem());
591 
592  // Plus the original 4 now-inactive elements
593  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
594  _internal_boundary_mesh->n_elem());
595 
596  // There'd better be 2*2*4+1 nodes on the internal boundary
597  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
598  _internal_boundary_mesh->n_nodes());
599 
600  // There'd better be 2*(3+5) + 2*4 active elements on the
601  // multi-boundary
602  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(24),
603  _multi_boundary_mesh->n_active_elem());
604 
605  // Plus the original 12 now-inactive elements
606  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(36),
607  _multi_boundary_mesh->n_elem());
608 
609  // There'd better be 2*2*(3+5)+1 + 2*2*4+1 nodes on the
610  // multi-boundary
611  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(50),
612  _multi_boundary_mesh->n_nodes());
613 
614 
615  this->sanityCheck();
616  }
617 
618 
620  {
621  LOG_UNIT_TEST;
622 
623  MeshSerializer internal_serializer(*_internal_boundary_mesh);
624 
625  // There'd better be 2*4 active elements on the internal
626  // sideset mesh
627  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
628  _internal_boundary_mesh->n_active_elem());
629 
630  // Plus the original 4 now-inactive elements
631  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
632  _internal_boundary_mesh->n_elem());
633 
634  // There'd better be 2*2*4+1 nodes on the internal boundary
635  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
636  _internal_boundary_mesh->n_nodes());
637 
638  this->sanityCheck();
639  }
640 
641 };
642 
644 
645 
652 public:
653  LIBMESH_CPPUNIT_TEST_SUITE( BoundaryOfRefinedMeshTest );
654 
655 #if LIBMESH_DIM > 1
656  CPPUNIT_TEST( testMesh );
657  CPPUNIT_TEST( testBoundarySerialization );
658 #endif
659 
660  CPPUNIT_TEST_SUITE_END();
661 
662  // Yes, this is necessary. Somewhere in those macros is a protected/private
663 public:
664 
665  void setUp()
666  {
667 #if LIBMESH_DIM > 1
668  this->build_mesh();
669 
670  // Refine interior mesh before creating boundary meshes
671  MeshRefinement(*_mesh).uniformly_refine(1);
672 
673  this->sync_and_test_meshes();
674 #endif
675  }
676 
677  void testMesh()
678  {
679  LOG_UNIT_TEST;
680 
681  // There'd better be 3*5*4 + 5*2 active elements in the interior
682  // plus right boundary
683  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(70),
684  _mesh->n_active_elem());
685 
686  // Plus the original 20 now-inactive elements
687  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(90),
688  _mesh->n_elem());
689 
690  // There'd better be 13*21 nodes in the interior
691  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(273),
692  _mesh->n_nodes());
693 
694  // There'd better be 2*2*(3+5) active elements on the exterior boundary
695  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
696  _exterior_boundary_mesh->n_active_elem());
697 
698  // Plus the original 16 now-inactive elements
699  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(48),
700  _exterior_boundary_mesh->n_elem());
701 
702  // There'd better be 2*2*2*(3+5) nodes on the exterior boundary
703  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(64),
704  _exterior_boundary_mesh->n_nodes());
705 
706  // There'd better be 2*5 active elements on the left boundary
707  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(10),
708  _left_boundary_mesh->n_active_elem());
709 
710  // Plus the original 5 now-inactive elements
711  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(15),
712  _left_boundary_mesh->n_elem());
713 
714  // There'd better be 2*2*5+1 nodes on the left boundary
715  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(21),
716  _left_boundary_mesh->n_nodes());
717 
718  // There'd better be 2*4 active elements on the internal
719  // sideset mesh
720  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
721  _internal_boundary_mesh->n_active_elem());
722 
723  // Plus the original 4 now-inactive elements
724  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
725  _internal_boundary_mesh->n_elem());
726 
727  // There'd better be 2*2*4+1 nodes on the one-sided internal boundary
728  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
729  _internal_boundary_mesh->n_nodes());
730 
731  // There'd better be 2*(3+5) + 2*4 active elements on the
732  // multi-boundary
733  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(24),
734  _multi_boundary_mesh->n_active_elem());
735 
736  // Plus the original 12 now-inactive elements
737  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(36),
738  _multi_boundary_mesh->n_elem());
739 
740  // There'd better be 2*2*2*(3+5) + 2*2*4-1 nodes on the total boundary
741  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(50),
742  _multi_boundary_mesh->n_nodes());
743 
744  this->sanityCheck();
745  }
746 
748  {
749  LOG_UNIT_TEST;
750 
751  MeshSerializer internal_serializer(*_internal_boundary_mesh);
752 
753  // There'd better be 2*4 active elements on the internal
754  // sideset mesh
755  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
756  _internal_boundary_mesh->n_active_elem());
757 
758  // Plus the original 4 now-inactive elements
759  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
760  _internal_boundary_mesh->n_elem());
761 
762  // There'd better be 2*2*4+1 nodes on the internal boundary
763  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
764  _internal_boundary_mesh->n_nodes());
765 
766  this->sanityCheck();
767  }
768 
769 };
770 
772 
773 #endif
ElemType
Defines an enum for geometric element types.
std::unique_ptr< UnstructuredMesh > _internal_boundary_mesh
void sync_and_test_meshes()
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
static constexpr Real TOLERANCE
std::unique_ptr< UnstructuredMesh > _replicated_boundary_mesh
Definition: boundary_mesh.C:98
static const unsigned int type_to_dim_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the geometric dimension of the ele...
Definition: elem.h:635
std::unique_ptr< UnstructuredMesh > _exterior_boundary_mesh
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
std::unique_ptr< UnstructuredMesh > _distributed_boundary_mesh
Definition: boundary_mesh.C:99
processor_id_type rank() const
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.
std::unique_ptr< UnstructuredMesh > _mesh
void testBoundarySerialization()
unsigned int get_elem_integer_index(std::string_view name) const
Definition: mesh_base.C:626
Implements (adaptive) mesh refinement algorithms for a MeshBase.
int8_t boundary_id_type
Definition: id_types.h:51
The UnstructuredMesh class is derived from the MeshBase class.
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
CPPUNIT_TEST_SUITE_REGISTRATION(BoundaryMesh0DTest)
std::unique_ptr< UnstructuredMesh > _left_boundary_mesh
std::unique_ptr< UnstructuredMesh > _interior_node_mesh
unsigned int level() const
Definition: elem.h:3074
std::unique_ptr< UnstructuredMesh > _multi_boundary_mesh
virtual unsigned short dim() const =0
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure...
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.
std::unique_ptr< UnstructuredMesh > _mesh
Definition: boundary_mesh.C:97
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
void testBoundarySerialization()
uint8_t dof_id_type
Definition: id_types.h:67
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.
const RemoteElem * remote_elem
Definition: remote_elem.C:57