libMesh
boundary_info.C
Go to the documentation of this file.
1 #include <libmesh/mesh.h>
2 #include <libmesh/mesh_generation.h>
3 #include <libmesh/boundary_info.h>
4 #include <libmesh/elem.h>
5 #include <libmesh/face_quad4_shell.h>
6 #include <libmesh/equation_systems.h>
7 #include <libmesh/zero_function.h>
8 #include <libmesh/dirichlet_boundaries.h>
9 #include <libmesh/dof_map.h>
10 #include <libmesh/parallel.h>
11 #include <libmesh/mesh_refinement.h>
12 
13 #include "test_comm.h"
14 #include "libmesh_cppunit.h"
15 
16 #include <regex>
17 
18 using namespace libMesh;
19 
20 class BoundaryInfoTest : public CppUnit::TestCase {
24 public:
25  LIBMESH_CPPUNIT_TEST_SUITE( BoundaryInfoTest );
26 
27  CPPUNIT_TEST( testNameCopying );
28 
29 #if LIBMESH_DIM > 1
30  CPPUNIT_TEST( testMesh );
31  CPPUNIT_TEST( testRenumber );
32  CPPUNIT_TEST( testInternalBoundary );
33 # if LIBMESH_DIM > 2
34  CPPUNIT_TEST( testSelectiveRenumber );
35 # endif
36 # ifdef LIBMESH_ENABLE_AMR
37 # ifdef LIBMESH_ENABLE_EXCEPTIONS
38  CPPUNIT_TEST( testBoundaryOnChildrenErrors );
39 # endif
40  CPPUNIT_TEST( testBoundaryIDs );
41  CPPUNIT_TEST( testBoundaryOnChildrenElementsRefineCoarsen );
42  CPPUNIT_TEST( testBoundaryOnChildrenBoundaryIDs );
43  CPPUNIT_TEST( testBoundaryOnChildrenBoundarySides );
44 # endif
45  CPPUNIT_TEST( testBuildNodeListFromSideList );
46  CPPUNIT_TEST( testBuildSideListFromNodeList );
47 # ifdef LIBMESH_ENABLE_DIRICHLET
48  CPPUNIT_TEST( testShellFaceConstraints );
49 # endif
50 #endif
51 #if LIBMESH_DIM > 2
52  CPPUNIT_TEST( testEdgeBoundaryConditions );
53 #endif
54 
55  CPPUNIT_TEST_SUITE_END();
56 
57 protected:
58 
59 public:
60  void setUp()
61  {
62  }
63 
64  void tearDown()
65  {
66  }
67 
68  void testMesh()
69  {
70  LOG_UNIT_TEST;
71 
73 
75  2, 2,
76  0., 1.,
77  0., 1.,
78  QUAD4);
79 
81 
82  // build_square adds boundary_ids 0,1,2,3 for the bottom, right,
83  // top, and left sides, respectively.
84 
85  // On a ReplicatedMesh, we should see all 4 ids on each processor
86  if (mesh.is_serial())
87  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), bi.n_boundary_ids());
88 
89  // On any mesh, we should see each id on *some* processor
90  {
91  const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
92  for (boundary_id_type i = 0 ; i != 4; ++i)
93  {
94  bool has_bcid = bc_ids.count(i);
95  mesh.comm().max(has_bcid);
96  CPPUNIT_ASSERT(has_bcid);
97  }
98  }
99 
100  // Check that there are exactly 8 sides in the BoundaryInfo for a
101  // replicated mesh
102  auto bc_triples = bi.build_side_list();
103  if (mesh.is_serial())
104  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), bc_triples.size());
105 
106  // Let's test that they are preserved (in a relative sense) when
107  // we clone a mesh.
108  std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
109  CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
111 
112  // Let's test that we can remove them successfully.
113  bi.remove_id(0);
114 
115  CPPUNIT_ASSERT(mesh_clone->get_boundary_info() !=
117 
118  // Check that there are now only 3 boundary ids total on the Mesh.
119  if (mesh.is_serial())
120  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
121 
122  {
123  const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
124  CPPUNIT_ASSERT(!bc_ids.count(0));
125  for (boundary_id_type i = 1 ; i != 4; ++i)
126  {
127  bool has_bcid = bc_ids.count(i);
128  mesh.comm().max(has_bcid);
129  CPPUNIT_ASSERT(has_bcid);
130  }
131  }
132 
133  // Build the side list again
134  bc_triples = bi.build_side_list();
135 
136  // Check that there are now exactly 6 sides left in the
137  // BoundaryInfo on a replicated mesh
138  if (mesh.is_serial())
139  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), bc_triples.size());
140 
141  // Check that the removed ID is really removed
142  CPPUNIT_ASSERT(std::find_if(bc_triples.begin(), bc_triples.end(),
143  [](const auto & t) { return std::get<2>(t) == 0; }) == bc_triples.end());
144 
145  // Remove the same id again, make sure nothing changes.
146  bi.remove_id(0);
147  if (mesh.is_serial())
148  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
149 
150  // Remove the remaining IDs, verify that we have no sides left and
151  // that we can safely reuse the same vectors in the
152  // build_side_list() call.
153  bi.remove_id(1);
154  bi.remove_id(2);
155  bi.remove_id(3);
156  bc_triples = bi.build_side_list();
157 
158  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_boundary_ids());
159  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bc_triples.size());
160  }
161 
162 
164  {
165  LOG_UNIT_TEST;
166 
168 
170  2, 2,
171  0., 1.,
172  0., 1.,
173  QUAD4);
174 
176 
177  // build_square adds boundary_ids 0,1,2,3 for the bottom, right,
178  // top, and left sides, respectively. Let's remap those, not 1-1.
179  bi.renumber_id(0, 4);
180  bi.renumber_id(1, 5);
181  bi.renumber_id(2, 6);
182  bi.renumber_id(3, 6);
183 
184  const std::map<boundary_id_type, std::string> expected_names =
185  {{4,"bottom"}, {5,"right"}, {6,"left"}};
186 
187  // On a ReplicatedMesh, we should see ids 4,5,6 on each processor
188  if (mesh.is_serial())
189  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
190 
191  // On any mesh, we should see each new id on *some* processor, and
192  // shouldn't see old ids on *any* processor
193  {
194  const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
195  for (boundary_id_type i = 0 ; i != 4; ++i)
196  {
197  bool has_bcid = bc_ids.count(i);
198  mesh.comm().max(has_bcid);
199  CPPUNIT_ASSERT(!has_bcid);
200  }
201  for (boundary_id_type i = 4 ; i != 7; ++i)
202  {
203  bool has_bcid = bc_ids.count(i);
204 
205  bool bad_name = false;
206  if (has_bcid)
207  {
208  const std::string & current_name = bi.sideset_name(i);
209 
210  bad_name = (current_name != libmesh_map_find(expected_names, i));
211  }
212 
213  // At least one proc should have each of these BCs
214  mesh.comm().max(has_bcid);
215  CPPUNIT_ASSERT(has_bcid);
216 
217  // No proc should have the wrong name for a BC it has
218  mesh.comm().max(bad_name);
219  CPPUNIT_ASSERT(!bad_name);
220  }
221  }
222 
223  // Check that there are still exactly 8 sides in the BoundaryInfo
224  // for a replicated mesh
225  auto bc_triples = bi.build_side_list();
226 
227  if (mesh.is_serial())
228  {
229  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), bc_triples.size());
230  }
231 
232  // Remove the new IDs, verify that we have no sides left
233  bi.remove_id(4);
234  bi.remove_id(5);
235  bi.remove_id(6);
236  bc_triples = bi.build_side_list();
237 
238  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_boundary_ids());
239  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bc_triples.size());
240  }
241 
242 
244  {
245  LOG_UNIT_TEST;
246 
248 
250  2, 2, 2,
251  0., 1.,
252  0., 1.,
253  0., 1.,
254  HEX8);
255 
257 
258  // build_cube adds boundary_ids 0-5 for "back", "bottom", "right",
259  // "top", "left", and "front" (as viewed facing the usual XY plane
260  // with the Z axis pointing toward the viewer) respectively.
261  // Let's scramble those, and scramble them differently on nodes vs
262  // sides.
263  bi.renumber_side_id(0, 6);
264  bi.renumber_side_id(5, 7);
265  bi.renumber_node_id(0, 7);
266  bi.renumber_node_id(5, 6);
267 
268  Elem * elem = mesh.query_elem_ptr(0);
269 
270  if (elem)
271  {
272  // Let's add a couple edges
273  bi.add_edge(elem, 2, 1);
274  bi.add_edge(elem, 3, 2);
275  bi.edgeset_name(1) = "firstedge";
276  bi.edgeset_name(2) = "secondedge";
277  // And scramble them
278  bi.renumber_edge_id(1, 3);
279  bi.renumber_edge_id(2, 4);
280  }
281 
282  // We should get global ids squared away
284 
285  const std::map<boundary_id_type, std::string> expected_basic_names =
286  {{1,"bottom"}, {2,"right"}, {3,"top"}, {4,"left"}};
287 
288  std::map<boundary_id_type, std::string> expected_side_names =
289  expected_basic_names;
290  expected_side_names.insert({{6,"back"}, {7,"front"}});
291 
292  std::map<boundary_id_type, std::string> expected_node_names =
293  expected_basic_names;
294  expected_node_names.insert({{6,"front"}, {7,"back"}});
295 
296  const std::map<boundary_id_type, std::string> expected_edge_names =
297  {{3,"firstedge"}, {4,"secondedge"}};
298 
299  // On a ReplicatedMesh, we should see ids 1-4,6,7 on each processor
300  if (mesh.is_serial())
301  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), bi.n_boundary_ids());
302 
303  // On any mesh, we should see each new id on *some* processor, and
304  // shouldn't see old ids on *any* processor
305  {
306  auto & bc_ids = bi.get_boundary_ids();
307  auto & side_bc_ids = bi.get_side_boundary_ids();
308  auto & edge_bc_ids = bi.get_edge_boundary_ids();
309  auto & node_bc_ids = bi.get_node_boundary_ids();
310 
311  for (boundary_id_type noid : {0, 5})
312  {
313  bool has_bcid = bc_ids.count(noid) ||
314  side_bc_ids.count(noid) ||
315  edge_bc_ids.count(noid) ||
316  node_bc_ids.count(noid);
317  mesh.comm().max(has_bcid);
318  CPPUNIT_ASSERT(!has_bcid);
319  }
320 
321  for (boundary_id_type id : {1, 2, 3, 4, 6, 7})
322  {
323  bool has_bcid = bc_ids.count(id),
324  has_side_id = side_bc_ids.count(id),
325  has_edge_id = edge_bc_ids.count(id),
326  has_node_id = node_bc_ids.count(id);
327 
328  bool bad_name = false;
329  if (has_side_id)
330  {
331  const std::string & side_name = bi.sideset_name(id);
332  bad_name = bad_name || (side_name != libmesh_map_find(expected_side_names, id));
333  }
334 
335  if (has_edge_id)
336  {
337  const std::string & edge_name = bi.edgeset_name(id);
338  bad_name = bad_name || (edge_name != libmesh_map_find(expected_edge_names, id));
339  }
340 
341  if (has_node_id)
342  {
343  const std::string & node_name = bi.nodeset_name(id);
344  bad_name = bad_name || (node_name != libmesh_map_find(expected_node_names, id));
345  }
346 
347  // At least one proc should have each the BCs we expect
348  mesh.comm().max(has_bcid);
349  CPPUNIT_ASSERT(has_bcid);
350 
351  mesh.comm().max(has_side_id);
352  CPPUNIT_ASSERT(has_side_id);
353 
354  mesh.comm().max(has_edge_id);
355  if (id == 3 || id == 4)
356  CPPUNIT_ASSERT(has_edge_id);
357  else
358  CPPUNIT_ASSERT(!has_edge_id);
359 
360  mesh.comm().max(has_node_id);
361  CPPUNIT_ASSERT(has_node_id);
362 
363  // No proc should have the wrong name for a BC it has
364  mesh.comm().max(bad_name);
365  CPPUNIT_ASSERT(!bad_name);
366  }
367  }
368  }
369 
370 
372  {
373  LOG_UNIT_TEST;
374 
375  const unsigned int n_elem = 5;
376  const std::string mesh_filename = "cube_mesh.xda";
377 
378  {
381  n_elem, n_elem, n_elem,
382  0., 1.,
383  0., 1.,
384  0., 1.,
385  HEX8);
386 
388 
389  // build_cube does not add any edge boundary IDs
390  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_edge_conds());
391 
392  // Let's now add some edge boundary IDs.
393  // We loop over all elements (not just local elements) so that
394  // all processors know about the boundary IDs
395  const boundary_id_type BOUNDARY_ID_MAX_X = 2;
396  const boundary_id_type BOUNDARY_ID_MIN_Y = 1;
397  const boundary_id_type EDGE_BOUNDARY_ID = 20;
398 
399  for (const auto & elem : mesh.element_ptr_range())
400  {
401  unsigned short side_max_x = 0, side_min_y = 0;
402  bool found_side_max_x = false, found_side_min_y = false;
403 
404  for (unsigned short side=0; side<elem->n_sides(); side++)
405  {
406  if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MAX_X))
407  {
408  side_max_x = side;
409  found_side_max_x = true;
410  }
411 
412  if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MIN_Y))
413  {
414  side_min_y = side;
415  found_side_min_y = true;
416  }
417  }
418 
419  // If elem has sides on boundaries
420  // BOUNDARY_ID_MAX_X and BOUNDARY_ID_MIN_Y
421  // then let's set an edge boundary condition
422  if (found_side_max_x && found_side_min_y)
423  for (unsigned short e=0; e<elem->n_edges(); e++)
424  if (elem->is_edge_on_side(e, side_max_x) &&
425  elem->is_edge_on_side(e, side_min_y))
426  bi.add_edge(elem, e, EDGE_BOUNDARY_ID);
427  }
428 
429  // Check that we have the expected number of edge boundary IDs after
430  // updating bi
431  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
432 
433  // Let's test that edge BCIDs are preserved (in a relative
434  // sense) when we clone a mesh.
435  std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
436  CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
438 
439  mesh.write(mesh_filename);
440  }
441 
442  // Make sure all processors are done writing before we try to
443  // start reading
445 
447  mesh.read(mesh_filename);
448 
449  // Check that writing and reading preserves the edge boundary IDs
451  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
452  }
453 
455  {
456  LOG_UNIT_TEST;
457 
460  8,
461  0., 1.,
462  EDGE2);
463 
464  Mesh mesh2(mesh);
465 
467  bi.sideset_name(0) = "zero";
468  bi.sideset_name(1) = "one";
469  bi.sideset_name(2) = "two";
470  bi.sideset_name(3) = "three";
471  bi.nodeset_name(0) = "ZERO";
472  bi.nodeset_name(1) = "ONE";
473 
474  BoundaryInfo bi2 {bi};
475  CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(0), std::string("zero"));
476  CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(1), std::string("one"));
477  CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(2), std::string("two"));
478  CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(3), std::string("three"));
479  CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(0), std::string("ZERO"));
480  CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(1), std::string("ONE"));
481 
482  BoundaryInfo & bi3 = mesh2.get_boundary_info();
483  bi3 = bi;
484  CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(0), std::string("zero"));
485  CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(1), std::string("one"));
486  CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(2), std::string("two"));
487  CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(3), std::string("three"));
488  CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(0), std::string("ZERO"));
489  CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(1), std::string("ONE"));
490  }
491 
492 #ifdef LIBMESH_ENABLE_DIRICHLET
494  {
495  LOG_UNIT_TEST;
496 
497  // Make a simple two element mesh that we can use to test constraints
499 
500  // (0,1) (1,1)
501  // x---------------x
502  // | |
503  // | |
504  // | |
505  // | |
506  // | |
507  // x---------------x
508  // (0,0) (1,0)
509  // | |
510  // | |
511  // | |
512  // | |
513  // x---------------x
514  // (0,-1) (1,-1)
515 
516  mesh.add_point( Point(0.0,-1.0), 4 );
517  mesh.add_point( Point(1.0,-1.0), 5 );
518  mesh.add_point( Point(1.0, 0.0), 1 );
519  mesh.add_point( Point(1.0, 1.0), 2 );
520  mesh.add_point( Point(0.0, 1.0), 3 );
521  mesh.add_point( Point(0.0, 0.0), 0 );
522 
523  Elem * elem_top = mesh.add_elem(Elem::build(QUADSHELL4));
524  elem_top->set_node(0, mesh.node_ptr(0));
525  elem_top->set_node(1, mesh.node_ptr(1));
526  elem_top->set_node(2, mesh.node_ptr(2));
527  elem_top->set_node(3, mesh.node_ptr(3));
528 
529  Elem * elem_bottom = mesh.add_elem(Elem::build(QUADSHELL4));
530  elem_bottom->set_node(0, mesh.node_ptr(4));
531  elem_bottom->set_node(1, mesh.node_ptr(5));
532  elem_bottom->set_node(2, mesh.node_ptr(1));
533  elem_bottom->set_node(3, mesh.node_ptr(0));
534 
536  bi.add_shellface(elem_top, 0, 10);
537  bi.add_shellface(elem_bottom, 1, 20);
538 
539  mesh.allow_renumbering(true);
541 
542  // Let's test that shellface BCIDs are preserved (in a relative
543  // sense) when we clone a mesh.
544  std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
545  CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
547 
548  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), bi.n_shellface_conds());
549 
550  EquationSystems es(mesh);
551  System & system = es.add_system<System> ("SimpleSystem");
552  system.add_variable("u", FIRST);
553 
554  // Add a Dirichlet constraint to check that we impose constraints
555  // correctly on shell faces.
556  std::vector<unsigned int> variables;
557  variables.push_back(0);
558  std::set<boundary_id_type> shellface_ids;
559  shellface_ids.insert(20);
560  ZeroFunction<> zf;
561  DirichletBoundary dirichlet_bc(shellface_ids,
562  variables,
563  &zf);
564  system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
565  es.init();
566 
567  // Find elem_bottom again if we have it (it may have been deleted
568  // in a DistributedMesh or renumbered in theory)
569  elem_bottom = nullptr;
570  for (unsigned int e = 0; e != mesh.max_elem_id(); ++e)
571  {
572  Elem *elem = mesh.query_elem_ptr(e);
573  if (elem && elem->point(3) == Point(0,0))
574  elem_bottom = elem;
575  }
576 
577  // We expect to have a dof constraint on all four dofs of
578  // elem_bottom
579  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), static_cast<std::size_t>(system.n_constrained_dofs()));
580 
581  // But we may only know the details of that
582  // constraint on the processor which owns elem_bottom.
583  if (elem_bottom &&
584  elem_bottom->processor_id() == mesh.processor_id())
585  {
586  std::vector<dof_id_type> dof_indices;
587  system.get_dof_map().dof_indices(elem_bottom, dof_indices);
588  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), dof_indices.size());
589 
590  for(unsigned int i=0; i<dof_indices.size(); i++)
591  {
592  dof_id_type dof_id = dof_indices[i];
593  CPPUNIT_ASSERT( system.get_dof_map().is_constrained_dof(dof_id) );
594  }
595  }
596  }
597 #endif // LIBMESH_ENABLE_DIRICHLET
598 
599 #if LIBMESH_ENABLE_AMR
600 # if LIBMESH_ENABLE_EXCEPTIONS
602  {
603  LOG_UNIT_TEST;
604 
605  // We create one cell only. The default boundaries of the cell are below.
606  // ___2___
607  // 3 | | 1
608  // |_____|
609  // 0
610 
611  auto mesh = std::make_unique<Mesh>(*TestCommWorld);
613  1, 1,
614  0., 1.,
615  0., 1.,
616  QUAD4);
617 
619 
620  // We only have one element, but for easy access we use the iterator
621  for (auto & elem : mesh->active_element_ptr_range())
622  elem->set_refinement_flag(Elem::REFINE);
624 
627 
628  // Now we try to add boundary id 3 to a child on side 3. This should
629  // result in a "not implemented" error message
630  bool threw_desired_exception = false;
631  try {
632  for (auto & elem : mesh->active_element_ptr_range())
633  {
634  const Point c = elem->vertex_average();
635  if (c(0) < 0.5 && c(1) > 0.5)
636  bi.add_side(elem, 3, 3);
637  }
638  }
639  catch (libMesh::NotImplemented & e) {
640  std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
641  CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
642  threw_desired_exception = true;
643  }
644  // If we have more than 4 processors, or a poor partitioner, we
645  // might not get an exception on every processor
646  mesh->comm().max(threw_desired_exception);
647 
648  CPPUNIT_ASSERT(threw_desired_exception);
649 
650  threw_desired_exception = false;
651  try {
652  for (auto & elem : mesh->active_element_ptr_range())
653  {
654  const Point c = elem->vertex_average();
655  if (c(0) < 0.5 && c(1) > 0.5)
656  bi.add_side(elem, 3, {3,4});
657  }
658  }
659  catch (libMesh::NotImplemented & e) {
660  std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
661  CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
662  threw_desired_exception = true;
663  }
664 
665  // If we have more than 4 processors, or a poor partitioner, we
666  // might not get an exception on every processor
667  mesh->comm().max(threw_desired_exception);
668 
669  CPPUNIT_ASSERT(threw_desired_exception);
670 
671  // We tested the side addition errors, now we move to the removal parts.
672  // We will attempt the removal of boundary 3 through the child
673  threw_desired_exception = false;
675  try {
676  for (auto & elem : mesh->active_element_ptr_range())
677  {
678  const Point c = elem->vertex_average();
679  if (c(0) < 0.5 && c(1) > 0.5)
680  bi.remove_side(elem, 3, 3);
681  }
682  }
683  catch (libMesh::NotImplemented & e) {
684  std::regex msg_regex("We cannot delete boundary ID 3 using a child because it is inherited from an ancestor");
685  CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
686  threw_desired_exception = true;
687  }
688 
689  // If we have more than 4 processors, or a poor partitioner, we
690  // might not get an exception on every processor
691  mesh->comm().max(threw_desired_exception);
692 
693  CPPUNIT_ASSERT(threw_desired_exception);
694  }
695 # endif // LIBMESH_ENABLE_EXCEPTIONS
696 
697 
699  {
700  LOG_UNIT_TEST;
701 
702  // We create one cell only. The default boundaries of the cell are below.
703  // ___2___
704  // 3 | | 1
705  // |_____|
706  // 0
707 
708  auto mesh = std::make_unique<Mesh>(*TestCommWorld);
710  1, 1,
711  0., 1.,
712  0., 1.,
713  QUAD4);
714 
716 
717  // Now we add the extra boundary ID (5) to the element on side 3
718  auto elem = mesh->query_elem_ptr(0);
719  if (elem)
720  bi.add_side(elem, 3, 5);
722 
723  // Check the element now
724  if (elem && elem->processor_id() == mesh->processor_id())
725  {
726  std::vector<boundary_id_type> container;
727  bi.boundary_ids(elem, 3, container);
728 
729  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
730  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[0]);
731  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[1]);
732 
733  std::vector<std::vector<boundary_id_type>> all_bids_container;
734  bi.side_boundary_ids(elem, all_bids_container);
735  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
736  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
737  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
738  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][1]);
739  // Check other sides
740  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[0].size());
741  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(0), all_bids_container[0][0]);
742  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
743  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(1), all_bids_container[1][0]);
744  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
745  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
746  }
747  }
748 
750  {
751  LOG_UNIT_TEST;
752 
753  // Set subdomain ids for specific elements, we will refine/coarsen
754  // the cell on subdomain 1
755  // _____________
756  // | 1 | 2 |
757  // |_____|_____|
758 
759  auto mesh = std::make_unique<Mesh>(*TestCommWorld);
761  2, 1,
762  0., 2.,
763  0., 1.,
764  QUAD4);
765 
767 
768  for (auto & elem : mesh->active_element_ptr_range())
769  {
770  const Point c = elem->vertex_average();
771  if (c(0) < 1)
772  {
773  elem->subdomain_id() = 1;
774  elem->set_refinement_flag(Elem::REFINE);
775  }
776  else
777  elem->subdomain_id() = 2;
778  }
780 
781  // Refine the elements once in subdomain 1, and
782  // add the right side subdomain 1 as boundary 5
785 
786  for (auto & elem : mesh->active_element_ptr_range())
787  {
788  const Point c = elem->vertex_average();
789  if (c(0) < 1 && c(0) > 0.5)
790  bi.add_side(elem, 1, 5);
791  }
793 
794  // Check the middle boundary, we expect to have two sides in boundary 5
795  unsigned int count = 0;
796  for (auto & elem : mesh->active_element_ptr_range())
797  if (bi.has_boundary_id(elem, 1, 5))
798  count++;
799 
800  if (mesh->n_active_local_elem())
801  {
802  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(2), count);
803  CPPUNIT_ASSERT(bi.is_children_on_boundary_side());
804  }
805 
806  // First, we will coarsen the the elements on subdomain 1. This
807  // is to check if the boundary information propagates upward upon
808  // coarsening.
809  for (auto & elem : mesh->active_element_ptr_range())
810  {
811  const Point c = elem->vertex_average();
812  if (c(0) < 1)
813  elem->set_refinement_flag(Elem::COARSEN);
814  }
816 
817  // The coarsened element should have its side on boundary 5
818  // This is boundary info transferred from this child element
821 
822  for (auto & elem : mesh->active_element_ptr_range())
823  {
824  const Point c = elem->vertex_average();
825  if (c(0) < 1)
826  {
827  CPPUNIT_ASSERT(bi.has_boundary_id(elem, 1, 5));
828  // We clean up this boundary ID for the next round of tests
829  bi.remove_side(elem, 1, 5);
830  // we will refine this element again
831  elem->set_refinement_flag(Elem::REFINE);
832  }
833  }
834 
837 
838  // This time we remove boundary 5 from one of the children. We expect
839  // the boundary not to propagate to the next level. Furthermore we
840  // expect boundary 5 to be deleted from the parent's boundaries
841  for (auto & elem : mesh->active_element_ptr_range())
842  {
843  const Point c = elem->vertex_average();
844  if (c(0) < 1)
845  elem->set_refinement_flag(Elem::COARSEN);
846  if (c(0) > 0.5 && c(0) < 1 && c(1) < 0.5)
847  bi.add_side(elem, 1, 5);
848  }
850 
852 
854 
855  // The parent element should not have any side associated with boundary 5
856  for (auto & elem : mesh->active_element_ptr_range())
857  {
858  const Point c = elem->vertex_average();
859  if (c(0) < 1)
860  CPPUNIT_ASSERT(!bi.has_boundary_id(elem, 1, 5));
861  }
862  }
863 
865  {
866  LOG_UNIT_TEST;
867 
868  // We create one cell only. The default boundaries of the cell are below.
869  // We will refine the mesh and add a new boundary id to the left side (side 3).
870  // Then will query the available boundary ids on the added side. It should return
871  // both the parent's and the child's boundaries.
872  // ___2___
873  // 3 | | 1
874  // |_____|
875  // 0
876 
877  auto mesh = std::make_unique<Mesh>(*TestCommWorld);
879  1, 1,
880  0., 1.,
881  0., 1.,
882  QUAD4);
883 
885 
886  // We only have one element, but for easy access we use the iterator
887  for (auto & elem : mesh->active_element_ptr_range())
888  elem->set_refinement_flag(Elem::REFINE);
890 
892 
893  // Now we add the extra boundary ID (5) to the element in the top
894  // left corner
895  for (auto & elem : mesh->active_element_ptr_range())
896  {
897  const Point c = elem->vertex_average();
898  if (c(0) < 0.5 && c(1) > 0.5)
899  bi.add_side(elem, 3, 5);
900  }
902 
903  // Okay, now we query the boundary ids on side 3 of the child and check if it has
904  // the right elements
905  for (auto & elem : mesh->active_element_ptr_range())
906  {
907  const Point c = elem->vertex_average();
908  if (c(0) < 0.5 && c(1) > 0.5)
909  {
910  std::vector<boundary_id_type> container;
911  bi.boundary_ids(elem, 3, container);
912 
913  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
914  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[0]);
915  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[1]);
916 
917  std::vector<std::vector<boundary_id_type>> all_bids_container;
918  bi.side_boundary_ids(elem, all_bids_container);
919  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
920  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
921  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][0]);
922  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][1]);
923  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
924  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
925  // Check other sides
926  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[0].size());
927  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[1].size());
928 
929  // This is against the spirit of the test, and undefined behavior which
930  // may be changed later. Setting allow_children_on_boundary_side(false) could
931  // be actively doing a transfer_boundary_ids_from_children() and then deleting the
932  // children's data, not leaving the children's data there-but-ignored.
934  bi.side_boundary_ids(elem, all_bids_container);
935  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
936  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[3].size());
937  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
938  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
939  CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
940  }
941  }
942  }
943 
945  {
946  LOG_UNIT_TEST;
947 
948  // We create one cell only. The default boundaries of the cell are below.
949  // We will refine mesh and see if we can get back the correct sides
950  // for a given boundary id on an internal boundary.
951  // ___2___
952  // 3 | | 1
953  // |_____|
954  // 0
955 
956  auto mesh = std::make_unique<Mesh>(*TestCommWorld);
958  1, 1,
959  0., 1.,
960  0., 1.,
961  QUAD4);
962 
964 
965 
966  // We only have one element, but for easy access we use the iterator
967  for (auto & elem : mesh->active_element_ptr_range())
968  elem->set_refinement_flag(Elem::REFINE);
971 
972  // Now we add the extra boundary ID (5) to two sides of
973  // the element in the bottom left corner. then we refine again
974  for (auto & elem : mesh->active_element_ptr_range())
975  {
976  const Point c = elem->vertex_average();
977  if (c(0) < 0.5 && c(1) < 0.5)
978  {
979  bi.add_side(elem, 1, 5);
980  bi.add_side(elem, 2, 5);
981  elem->set_refinement_flag(Elem::REFINE);
982  }
983  }
986 
987  // Okay, now we add another boundary id (6) to the cell which is in the bottom
988  // right corner of the refined element
989  for (auto & elem : mesh->active_element_ptr_range())
990  {
991  const Point c = elem->vertex_average();
992  if (c(0) < 0.5 && c(0) > 0.25 && c(1) < 0.25)
993  bi.add_side(elem, 1, 6);
994  }
995 
996  // Time to test if we can get back the boundary sides, first we
997  // check if we can get back boundary from the ancestors of (5) on
998  // the cell which only has boundary (6) registered. We also check
999  // if we can get boundary (6) back.
1000 
1001  for (auto & elem : mesh->active_element_ptr_range())
1002  {
1003  const Point c = elem->vertex_average();
1004  if (c(0) < 0.5 && c(0) > 0.25 && c(1) < 0.25)
1005  {
1006  const auto side_5 = bi.side_with_boundary_id(elem, 5);
1007  const auto side_6 = bi.side_with_boundary_id(elem, 6);
1008  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), side_5);
1009  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), side_6);
1010  }
1011  }
1012 
1013  // Now we go and try to query the sides with boundary id (5) using
1014  // the element which is at the top right corner of the bottom
1015  // right parent.
1016  for (auto & elem : mesh->active_element_ptr_range())
1017  {
1018  const Point c = elem->vertex_average();
1019  if (c(0) < 0.5 && c(0) > 0.25 && c(1) > 0.25 && c(1) < 0.5)
1020  {
1021  const auto sides = bi.sides_with_boundary_id(elem, 5);
1022  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned long>(2), sides.size());
1023  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), sides[0]);
1024  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(2), sides[1]);
1025  }
1026  }
1027  }
1028 #endif //LIBMESH_ENABLE_AMR
1029 
1030 
1032  {
1033  LOG_UNIT_TEST;
1034 
1036 
1038  2, 2,
1039  0., 1.,
1040  0., 1.,
1041  QUAD4);
1042 
1044 
1045  // build_square gave us ids 0-3 as both side sets and node sets
1046  bi.remove_node_id(0);
1047  bi.remove_node_id(1);
1048  bi.remove_node_id(2);
1049  bi.remove_node_id(3);
1050 
1051  CPPUNIT_ASSERT(bi.build_node_list().empty());
1052 
1054 
1055  for (const auto & elem : mesh.element_ptr_range())
1056  {
1057  for (auto n : elem->node_index_range())
1058  {
1059  const Node * node = elem->node_ptr(n);
1060  for (auto s : {0,2})
1061  if (elem->is_node_on_side(n, s) && !elem->neighbor_ptr(s))
1062  CPPUNIT_ASSERT(bi.has_boundary_id(node, s));
1063  for (auto s : {1,3})
1064  CPPUNIT_ASSERT(!bi.has_boundary_id(node, s));
1065  }
1066  }
1067  }
1068 
1069 
1071  {
1072  LOG_UNIT_TEST;
1073 
1075 
1077  2, 2,
1078  0., 1.,
1079  0., 1.,
1080  QUAD4);
1081 
1083 
1084  // build_square gave us ids 0-3 as both side sets and node sets
1085  bi.remove_side_id(0);
1086  bi.remove_side_id(1);
1087  bi.remove_side_id(2);
1088  bi.remove_side_id(3);
1089 
1090  CPPUNIT_ASSERT(bi.build_side_list().empty());
1091 
1093 
1094  for (const auto & elem : mesh.element_ptr_range())
1095  {
1096  for (auto s : {0,2})
1097  {
1098  if (!elem->neighbor_ptr(s))
1099  {
1100  CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, s));
1101  CPPUNIT_ASSERT_EQUAL(bi.n_boundary_ids(elem, s), 1u);
1102  }
1103  else
1104  CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1105  }
1106  for (auto s : {1,3})
1107  {
1108  CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, s));
1109  CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1110  }
1111  }
1112  }
1113 
1114 
1116  {
1117  LOG_UNIT_TEST;
1118 
1120 
1121  // Build a 2x2 QUAD4 structured mesh on [0,1]x[0,1].
1123  2, 2,
1124  0., 1.,
1125  0., 1.,
1126  QUAD4);
1127 
1129 
1130  const unsigned int internal_side = 1; // east side for left elems
1131  const boundary_id_type BID = 7;
1132 
1134 
1135  Elem * left_bottom_elem = nullptr;
1136  for (auto & elem : mesh.active_element_ptr_range())
1137  {
1138  if (elem->processor_id() != mesh.processor_id())
1139  continue;
1140 
1141  const Point c = elem->vertex_average();
1142  if (c(0) < 0.5 && c(1) < 0.5 && elem->neighbor_ptr(internal_side) != nullptr)
1143  {
1144  left_bottom_elem = elem;
1145  break;
1146  }
1147  }
1148 
1149 
1150  if (left_bottom_elem)
1151  {
1152  bi.add_side(left_bottom_elem, internal_side, BID);
1153 
1154  const unsigned int found_side = bi.side_with_boundary_id(left_bottom_elem, BID);
1155  CPPUNIT_ASSERT_EQUAL(internal_side, found_side);
1156  }
1157  }
1158 
1159 
1160 };
1161 
void remove_id(boundary_id_type id, bool global=false)
Removes all entities (nodes, sides, edges, shellfaces) with boundary id id from their respective cont...
A class to stub for features that should be in libMesh, but haven&#39;t been written yet, to be thrown by "libmesh_not_implemented();".
void allow_children_on_boundary_side(const bool children_on_boundary)
Whether or not to allow directly setting boundary sides on child elements.
This is the EquationSystems class.
const std::set< boundary_id_type > & get_side_boundary_ids() const
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2564
A Node is like a Point, but with more information.
Definition: node.h:52
std::string & nodeset_name(boundary_id_type id)
void testInternalBoundary()
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
ConstFunction that simply returns 0.
Definition: zero_function.h:38
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false)=0
Interfaces for reading/writing a mesh to/from a file.
std::vector< unsigned int > sides_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const
void testShellFaceConstraints()
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
void synchronize_global_id_set()
Synchronizes the boundary_ids set on each processor to determine global_boundary_ids.
std::size_t n_edge_conds() const
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2201
void side_boundary_ids(const Elem *const elem, std::vector< std::vector< boundary_id_type >> &vec_to_fill) const
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:1004
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
bool refine_elements()
Only refines the user-requested elements.
std::size_t n_shellface_conds() const
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
Definition: mesh_base.C:824
void build_node_list_from_side_list(const std::set< boundary_id_type > &sideset_list={})
Adds nodes with boundary ids based on the side&#39;s boundary ids they are connected to.
CPPUNIT_TEST_SUITE_REGISTRATION(BoundaryInfoTest)
void remove_side_id(boundary_id_type id, bool global=false)
Removes all sides with boundary id id from the BoundaryInfo object, removes it from the set of side b...
void barrier() const
unsigned int side_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
const Parallel::Communicator & comm() 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.
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:170
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
void renumber_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all entities (nodes, sides, edges, shellfaces) with boundary id old_id to instead be labeled ...
virtual std::unique_ptr< MeshBase > clone() const =0
Virtual "copy constructor".
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
std::size_t n_boundary_ids() const
void build_side_list_from_node_list(const std::set< boundary_id_type > &nodeset_list={})
Adds sides to a sideset if every node on that side are in the same sideset.
bool coarsen_elements()
Only coarsens the user-requested elements.
const std::set< boundary_id_type > & get_node_boundary_ids() const
void renumber_side_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all sides with boundary id old_id to instead be labeled by boundary id new_id.
void testBoundaryOnChildrenBoundaryIDs()
dof_id_type n_active_local_elem() const
Definition: mesh_base.h:704
virtual bool is_serial() const
Definition: mesh_base.h:347
void testEdgeBoundaryConditions()
Implements (adaptive) mesh refinement algorithms for a MeshBase.
int8_t boundary_id_type
Definition: id_types.h:51
void testSelectiveRenumber()
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:98
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:442
virtual dof_id_type max_elem_id() const =0
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
bool is_constrained_dof(const dof_id_type dof) const
Definition: dof_map.h:2426
void testBoundaryOnChildrenErrors()
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition: system.C:1344
std::string & sideset_name(boundary_id_type id)
void renumber_node_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all nodes with boundary id old_id to instead be labeled by boundary id new_id.
virtual void write(const std::string &name) const =0
const std::set< boundary_id_type > & get_boundary_ids() const
void remove_side(const Elem *elem, const unsigned short int side)
Removes all boundary conditions associated with side side of element elem, if any exist...
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
void max(const T &r, T &o, Request &req) const
const std::set< boundary_id_type > & get_edge_boundary_ids() const
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 add_shellface(const dof_id_type elem, const unsigned short int shellface, const boundary_id_type id)
Add shell face shellface of element number elem with boundary id id to the boundary information data ...
void testBuildNodeListFromSideList()
std::string & edgeset_name(boundary_id_type id)
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.
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
void renumber_edge_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all edges with boundary id old_id to instead be labeled by boundary id new_id.
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
bool is_children_on_boundary_side() const
void testBoundaryOnChildrenBoundarySides()
void testBuildSideListFromNodeList()
virtual const Node * node_ptr(const dof_id_type i) const =0
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
processor_id_type processor_id() const
void remove_node_id(boundary_id_type id, bool global=false)
Removes all nodes with boundary id id from the BoundaryInfo object, removes it from the set of node b...
const DofMap & get_dof_map() const
Definition: system.h:2417
processor_id_type processor_id() const
Definition: dof_object.h:881
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Point & point(const unsigned int i) const
Definition: elem.h:2459
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.
void testBoundaryOnChildrenElementsRefineCoarsen()
dof_id_type n_constrained_dofs() const
Definition: system.C:125
uint8_t dof_id_type
Definition: id_types.h:67
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure...