libMesh
Loading...
Searching...
No Matches
boundary_info.C
Go to the documentation of this file.
1#include <libmesh/mesh.h>
2#include <libmesh/distributed_mesh.h>
3#include <libmesh/mesh_generation.h>
4#include <libmesh/boundary_info.h>
5#include <libmesh/elem.h>
6#include <libmesh/remote_elem.h>
7#include <libmesh/face_quad4_shell.h>
8#include <libmesh/equation_systems.h>
9#include <libmesh/zero_function.h>
10#include <libmesh/dirichlet_boundaries.h>
11#include <libmesh/dof_map.h>
12#include <libmesh/parallel.h>
13#include <libmesh/mesh_refinement.h>
14
15#include "test_comm.h"
16#include "libmesh_cppunit.h"
17
18#include <regex>
19
20using namespace libMesh;
21
22class BoundaryInfoTest : public CppUnit::TestCase {
26public:
28
31
32#if LIBMESH_DIM > 1
36# if LIBMESH_DIM > 2
38# endif
39# ifdef LIBMESH_ENABLE_AMR
40# ifdef LIBMESH_ENABLE_EXCEPTIONS
42# endif
47# endif
51# ifdef LIBMESH_ENABLE_DIRICHLET
53# endif
54#endif
55#if LIBMESH_DIM > 2
57#endif
58
60
61protected:
62
63public:
64 void setUp()
65 {
66 }
67
68 void tearDown()
69 {
70 }
71
72 void testMesh()
73 {
74 LOG_UNIT_TEST;
75
77
79 2, 2,
80 0., 1.,
81 0., 1.,
82 QUAD4);
83
85
86 // build_square adds boundary_ids 0,1,2,3 for the bottom, right,
87 // top, and left sides, respectively.
88
89 // On a ReplicatedMesh, we should see all 4 ids on each processor
90 if (mesh.is_serial())
91 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), bi.n_boundary_ids());
92
93 // On any mesh, we should see each id on *some* processor
94 {
95 const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
96 for (boundary_id_type i = 0 ; i != 4; ++i)
97 {
98 bool has_bcid = bc_ids.count(i);
99 mesh.comm().max(has_bcid);
100 CPPUNIT_ASSERT(has_bcid);
101 }
102 }
103
104 // Check that there are exactly 8 sides in the BoundaryInfo for a
105 // replicated mesh
106 auto bc_triples = bi.build_side_list();
107 if (mesh.is_serial())
108 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), bc_triples.size());
109
110 // Let's test that they are preserved (in a relative sense) when
111 // we clone a mesh.
112 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
113 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
115
116 // Let's test that we can remove them successfully.
117 bi.remove_id(0);
118
119 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() !=
121
122 // Check that there are now only 3 boundary ids total on the Mesh.
123 if (mesh.is_serial())
124 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
125
126 {
127 const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
128 CPPUNIT_ASSERT(!bc_ids.count(0));
129 for (boundary_id_type i = 1 ; i != 4; ++i)
130 {
131 bool has_bcid = bc_ids.count(i);
132 mesh.comm().max(has_bcid);
133 CPPUNIT_ASSERT(has_bcid);
134 }
135 }
136
137 // Build the side list again
138 bc_triples = bi.build_side_list();
139
140 // Check that there are now exactly 6 sides left in the
141 // BoundaryInfo on a replicated mesh
142 if (mesh.is_serial())
143 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), bc_triples.size());
144
145 // Check that the removed ID is really removed
146 CPPUNIT_ASSERT(std::find_if(bc_triples.begin(), bc_triples.end(),
147 [](const auto & t) { return std::get<2>(t) == 0; }) == bc_triples.end());
148
149 // Remove the same id again, make sure nothing changes.
150 bi.remove_id(0);
151 if (mesh.is_serial())
152 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
153
154 // Remove the remaining IDs, verify that we have no sides left and
155 // that we can safely reuse the same vectors in the
156 // build_side_list() call.
157 bi.remove_id(1);
158 bi.remove_id(2);
159 bi.remove_id(3);
160 bc_triples = bi.build_side_list();
161
162 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_boundary_ids());
163 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bc_triples.size());
164 }
165
166
168 {
169 LOG_UNIT_TEST;
170
172
174 2, 2,
175 0., 1.,
176 0., 1.,
177 QUAD4);
178
180
181 // build_square adds boundary_ids 0,1,2,3 for the bottom, right,
182 // top, and left sides, respectively. Let's remap those, not 1-1.
183 bi.renumber_id(0, 4);
184 bi.renumber_id(1, 5);
185 bi.renumber_id(2, 6);
186 bi.renumber_id(3, 6);
187
188 const std::map<boundary_id_type, std::string> expected_names =
189 {{4,"bottom"}, {5,"right"}, {6,"left"}};
190
191 // On a ReplicatedMesh, we should see ids 4,5,6 on each processor
192 if (mesh.is_serial())
193 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
194
195 // On any mesh, we should see each new id on *some* processor, and
196 // shouldn't see old ids on *any* processor
197 {
198 const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
199 for (boundary_id_type i = 0 ; i != 4; ++i)
200 {
201 bool has_bcid = bc_ids.count(i);
202 mesh.comm().max(has_bcid);
203 CPPUNIT_ASSERT(!has_bcid);
204 }
205 for (boundary_id_type i = 4 ; i != 7; ++i)
206 {
207 bool has_bcid = bc_ids.count(i);
208
209 bool bad_name = false;
210 if (has_bcid)
211 {
212 const std::string & current_name = bi.sideset_name(i);
213
214 bad_name = (current_name != libmesh_map_find(expected_names, i));
215 }
216
217 // At least one proc should have each of these BCs
218 mesh.comm().max(has_bcid);
219 CPPUNIT_ASSERT(has_bcid);
220
221 // No proc should have the wrong name for a BC it has
222 mesh.comm().max(bad_name);
223 CPPUNIT_ASSERT(!bad_name);
224 }
225 }
226
227 // Check that there are still exactly 8 sides in the BoundaryInfo
228 // for a replicated mesh
229 auto bc_triples = bi.build_side_list();
230
231 if (mesh.is_serial())
232 {
233 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), bc_triples.size());
234 }
235
236 // Remove the new IDs, verify that we have no sides left
237 bi.remove_id(4);
238 bi.remove_id(5);
239 bi.remove_id(6);
240 bc_triples = bi.build_side_list();
241
242 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_boundary_ids());
243 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bc_triples.size());
244 }
245
246
248 {
249 LOG_UNIT_TEST;
250
252
254 2, 2, 2,
255 0., 1.,
256 0., 1.,
257 0., 1.,
258 HEX8);
259
261
262 // build_cube adds boundary_ids 0-5 for "back", "bottom", "right",
263 // "top", "left", and "front" (as viewed facing the usual XY plane
264 // with the Z axis pointing toward the viewer) respectively.
265 // Let's scramble those, and scramble them differently on nodes vs
266 // sides.
267 bi.renumber_side_id(0, 6);
268 bi.renumber_side_id(5, 7);
269 bi.renumber_node_id(0, 7);
270 bi.renumber_node_id(5, 6);
271
272 Elem * elem = mesh.query_elem_ptr(0);
273
274 if (elem)
275 {
276 // Let's add a couple edges
277 bi.add_edge(elem, 2, 1);
278 bi.add_edge(elem, 3, 2);
279 bi.edgeset_name(1) = "firstedge";
280 bi.edgeset_name(2) = "secondedge";
281 // And scramble them
282 bi.renumber_edge_id(1, 3);
283 bi.renumber_edge_id(2, 4);
284 }
285
286 // We should get global ids squared away
288
289 const std::map<boundary_id_type, std::string> expected_basic_names =
290 {{1,"bottom"}, {2,"right"}, {3,"top"}, {4,"left"}};
291
292 std::map<boundary_id_type, std::string> expected_side_names =
293 expected_basic_names;
294 expected_side_names.insert({{6,"back"}, {7,"front"}});
295
296 std::map<boundary_id_type, std::string> expected_node_names =
297 expected_basic_names;
298 expected_node_names.insert({{6,"front"}, {7,"back"}});
299
300 const std::map<boundary_id_type, std::string> expected_edge_names =
301 {{3,"firstedge"}, {4,"secondedge"}};
302
303 // On a ReplicatedMesh, we should see ids 1-4,6,7 on each processor
304 if (mesh.is_serial())
305 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), bi.n_boundary_ids());
306
307 // On any mesh, we should see each new id on *some* processor, and
308 // shouldn't see old ids on *any* processor
309 {
310 auto & bc_ids = bi.get_boundary_ids();
311 auto & side_bc_ids = bi.get_side_boundary_ids();
312 auto & edge_bc_ids = bi.get_edge_boundary_ids();
313 auto & node_bc_ids = bi.get_node_boundary_ids();
314
315 for (boundary_id_type noid : {0, 5})
316 {
317 bool has_bcid = bc_ids.count(noid) ||
318 side_bc_ids.count(noid) ||
319 edge_bc_ids.count(noid) ||
320 node_bc_ids.count(noid);
321 mesh.comm().max(has_bcid);
322 CPPUNIT_ASSERT(!has_bcid);
323 }
324
325 for (boundary_id_type id : {1, 2, 3, 4, 6, 7})
326 {
327 bool has_bcid = bc_ids.count(id),
328 has_side_id = side_bc_ids.count(id),
329 has_edge_id = edge_bc_ids.count(id),
330 has_node_id = node_bc_ids.count(id);
331
332 bool bad_name = false;
333 if (has_side_id)
334 {
335 const std::string & side_name = bi.sideset_name(id);
336 bad_name = bad_name || (side_name != libmesh_map_find(expected_side_names, id));
337 }
338
339 if (has_edge_id)
340 {
341 const std::string & edge_name = bi.edgeset_name(id);
342 bad_name = bad_name || (edge_name != libmesh_map_find(expected_edge_names, id));
343 }
344
345 if (has_node_id)
346 {
347 const std::string & node_name = bi.nodeset_name(id);
348 bad_name = bad_name || (node_name != libmesh_map_find(expected_node_names, id));
349 }
350
351 // At least one proc should have each the BCs we expect
352 mesh.comm().max(has_bcid);
353 CPPUNIT_ASSERT(has_bcid);
354
355 mesh.comm().max(has_side_id);
356 CPPUNIT_ASSERT(has_side_id);
357
358 mesh.comm().max(has_edge_id);
359 if (id == 3 || id == 4)
360 CPPUNIT_ASSERT(has_edge_id);
361 else
362 CPPUNIT_ASSERT(!has_edge_id);
363
364 mesh.comm().max(has_node_id);
365 CPPUNIT_ASSERT(has_node_id);
366
367 // No proc should have the wrong name for a BC it has
368 mesh.comm().max(bad_name);
369 CPPUNIT_ASSERT(!bad_name);
370 }
371 }
372 }
373
374
376 {
377 LOG_UNIT_TEST;
378
379 const unsigned int n_elem = 5;
380 const std::string mesh_filename = "cube_mesh.xda";
381
382 {
385 n_elem, n_elem, n_elem,
386 0., 1.,
387 0., 1.,
388 0., 1.,
389 HEX8);
390
392
393 // build_cube does not add any edge boundary IDs
394 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_edge_conds());
395
396 // Let's now add some edge boundary IDs.
397 // We loop over all elements (not just local elements) so that
398 // all processors know about the boundary IDs
399 const boundary_id_type BOUNDARY_ID_MAX_X = 2;
400 const boundary_id_type BOUNDARY_ID_MIN_Y = 1;
401 const boundary_id_type EDGE_BOUNDARY_ID = 20;
402
403 for (const auto & elem : mesh.element_ptr_range())
404 {
405 unsigned short side_max_x = 0, side_min_y = 0;
406 bool found_side_max_x = false, found_side_min_y = false;
407
408 for (unsigned short side=0; side<elem->n_sides(); side++)
409 {
410 if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MAX_X))
411 {
412 side_max_x = side;
413 found_side_max_x = true;
414 }
415
416 if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MIN_Y))
417 {
418 side_min_y = side;
419 found_side_min_y = true;
420 }
421 }
422
423 // If elem has sides on boundaries
424 // BOUNDARY_ID_MAX_X and BOUNDARY_ID_MIN_Y
425 // then let's set an edge boundary condition
426 if (found_side_max_x && found_side_min_y)
427 for (unsigned short e=0; e<elem->n_edges(); e++)
428 if (elem->is_edge_on_side(e, side_max_x) &&
429 elem->is_edge_on_side(e, side_min_y))
430 bi.add_edge(elem, e, EDGE_BOUNDARY_ID);
431 }
432
433 // Check that we have the expected number of edge boundary IDs after
434 // updating bi
435 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
436
437 // Let's test that edge BCIDs are preserved (in a relative
438 // sense) when we clone a mesh.
439 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
440 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
442
443 mesh.write(mesh_filename);
444 }
445
446 // Make sure all processors are done writing before we try to
447 // start reading
448 TestCommWorld->barrier();
449
451 mesh.read(mesh_filename);
452
453 // Check that writing and reading preserves the edge boundary IDs
455 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
456 }
457
459 {
460 LOG_UNIT_TEST;
461
464 8,
465 0., 1.,
466 EDGE2);
467
468 Mesh mesh2(mesh);
469
471 bi.sideset_name(0) = "zero";
472 bi.sideset_name(1) = "one";
473 bi.sideset_name(2) = "two";
474 bi.sideset_name(3) = "three";
475 bi.nodeset_name(0) = "ZERO";
476 bi.nodeset_name(1) = "ONE";
477
478 BoundaryInfo bi2 {bi};
479 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(0), std::string("zero"));
480 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(1), std::string("one"));
481 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(2), std::string("two"));
482 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(3), std::string("three"));
483 CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(0), std::string("ZERO"));
484 CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(1), std::string("ONE"));
485
486 BoundaryInfo & bi3 = mesh2.get_boundary_info();
487 bi3 = bi;
488 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(0), std::string("zero"));
489 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(1), std::string("one"));
490 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(2), std::string("two"));
491 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(3), std::string("three"));
492 CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(0), std::string("ZERO"));
493 CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(1), std::string("ONE"));
494 }
495
496#ifdef LIBMESH_ENABLE_DIRICHLET
498 {
499 LOG_UNIT_TEST;
500
501 // Make a simple two element mesh that we can use to test constraints
503
504 // (0,1) (1,1)
505 // x---------------x
506 // | |
507 // | |
508 // | |
509 // | |
510 // | |
511 // x---------------x
512 // (0,0) (1,0)
513 // | |
514 // | |
515 // | |
516 // | |
517 // x---------------x
518 // (0,-1) (1,-1)
519
520 mesh.add_point( Point(0.0,-1.0), 4 );
521 mesh.add_point( Point(1.0,-1.0), 5 );
522 mesh.add_point( Point(1.0, 0.0), 1 );
523 mesh.add_point( Point(1.0, 1.0), 2 );
524 mesh.add_point( Point(0.0, 1.0), 3 );
525 mesh.add_point( Point(0.0, 0.0), 0 );
526
527 Elem * elem_top = mesh.add_elem(Elem::build(QUADSHELL4));
528 elem_top->set_node(0, mesh.node_ptr(0));
529 elem_top->set_node(1, mesh.node_ptr(1));
530 elem_top->set_node(2, mesh.node_ptr(2));
531 elem_top->set_node(3, mesh.node_ptr(3));
532
533 Elem * elem_bottom = mesh.add_elem(Elem::build(QUADSHELL4));
534 elem_bottom->set_node(0, mesh.node_ptr(4));
535 elem_bottom->set_node(1, mesh.node_ptr(5));
536 elem_bottom->set_node(2, mesh.node_ptr(1));
537 elem_bottom->set_node(3, mesh.node_ptr(0));
538
540 bi.add_shellface(elem_top, 0, 10);
541 bi.add_shellface(elem_bottom, 1, 20);
542
545
546 // Let's test that shellface BCIDs are preserved (in a relative
547 // sense) when we clone a mesh.
548 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
549 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
551
552 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), bi.n_shellface_conds());
553
555 System & system = es.add_system<System> ("SimpleSystem");
556 system.add_variable("u", FIRST);
557
558 // Add a Dirichlet constraint to check that we impose constraints
559 // correctly on shell faces.
560 std::vector<unsigned int> variables;
561 variables.push_back(0);
562 std::set<boundary_id_type> shellface_ids;
563 shellface_ids.insert(20);
565 DirichletBoundary dirichlet_bc(shellface_ids,
566 variables,
567 &zf);
568 system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
569 es.init();
570
571 // Find elem_bottom again if we have it (it may have been deleted
572 // in a DistributedMesh or renumbered in theory)
573 elem_bottom = nullptr;
574 for (unsigned int e = 0; e != mesh.max_elem_id(); ++e)
575 {
576 Elem *elem = mesh.query_elem_ptr(e);
577 if (elem && elem->point(3) == Point(0,0))
578 elem_bottom = elem;
579 }
580
581 // We expect to have a dof constraint on all four dofs of
582 // elem_bottom
583 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), static_cast<std::size_t>(system.n_constrained_dofs()));
584
585 // But we may only know the details of that
586 // constraint on the processor which owns elem_bottom.
587 if (elem_bottom &&
588 elem_bottom->processor_id() == mesh.processor_id())
589 {
590 std::vector<dof_id_type> dof_indices;
591 system.get_dof_map().dof_indices(elem_bottom, dof_indices);
592 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), dof_indices.size());
593
594 for(unsigned int i=0; i<dof_indices.size(); i++)
595 {
596 dof_id_type dof_id = dof_indices[i];
597 CPPUNIT_ASSERT( system.get_dof_map().is_constrained_dof(dof_id) );
598 }
599 }
600 }
601#endif // LIBMESH_ENABLE_DIRICHLET
602
603#if LIBMESH_ENABLE_AMR
604# if LIBMESH_ENABLE_EXCEPTIONS
606 {
607 LOG_UNIT_TEST;
608
609 // We create one cell only. The default boundaries of the cell are below.
610 // ___2___
611 // 3 | | 1
612 // |_____|
613 // 0
614
615 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
617 1, 1,
618 0., 1.,
619 0., 1.,
620 QUAD4);
621
623
624 // We only have one element, but for easy access we use the iterator
625 for (auto & elem : mesh->active_element_ptr_range())
626 elem->set_refinement_flag(Elem::REFINE);
628
631
632 // Now we try to add boundary id 3 to a child on side 3. This should
633 // result in a "not implemented" error message
634 bool threw_desired_exception = false;
635 try {
636 for (auto & elem : mesh->active_element_ptr_range())
637 {
638 const Point c = elem->vertex_average();
639 if (c(0) < 0.5 && c(1) > 0.5)
640 bi.add_side(elem, 3, 3);
641 }
642 }
643 catch (libMesh::NotImplemented & e) {
644 std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
645 CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
646 threw_desired_exception = true;
647 }
648 // If we have more than 4 processors, or a poor partitioner, we
649 // might not get an exception on every processor
650 mesh->comm().max(threw_desired_exception);
651
652 CPPUNIT_ASSERT(threw_desired_exception);
653
654 threw_desired_exception = false;
655 try {
656 for (auto & elem : mesh->active_element_ptr_range())
657 {
658 const Point c = elem->vertex_average();
659 if (c(0) < 0.5 && c(1) > 0.5)
660 bi.add_side(elem, 3, {3,4});
661 }
662 }
663 catch (libMesh::NotImplemented & e) {
664 std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
665 CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
666 threw_desired_exception = true;
667 }
668
669 // If we have more than 4 processors, or a poor partitioner, we
670 // might not get an exception on every processor
671 mesh->comm().max(threw_desired_exception);
672
673 CPPUNIT_ASSERT(threw_desired_exception);
674
675 // We tested the side addition errors, now we move to the removal parts.
676 // We will attempt the removal of boundary 3 through the child
677 threw_desired_exception = false;
678 bi.allow_children_on_boundary_side(true);
679 try {
680 for (auto & elem : mesh->active_element_ptr_range())
681 {
682 const Point c = elem->vertex_average();
683 if (c(0) < 0.5 && c(1) > 0.5)
684 bi.remove_side(elem, 3, 3);
685 }
686 }
687 catch (libMesh::NotImplemented & e) {
688 std::regex msg_regex("We cannot delete boundary ID 3 using a child because it is inherited from an ancestor");
689 CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
690 threw_desired_exception = true;
691 }
692
693 // If we have more than 4 processors, or a poor partitioner, we
694 // might not get an exception on every processor
695 mesh->comm().max(threw_desired_exception);
696
697 CPPUNIT_ASSERT(threw_desired_exception);
698 }
699# endif // LIBMESH_ENABLE_EXCEPTIONS
700
701
703 {
704 LOG_UNIT_TEST;
705
706 // We create one cell only. The default boundaries of the cell are below.
707 // ___2___
708 // 3 | | 1
709 // |_____|
710 // 0
711
712 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
714 1, 1,
715 0., 1.,
716 0., 1.,
717 QUAD4);
718
720
721 // Now we add the extra boundary ID (5) to the element on side 3
722 auto elem = mesh->query_elem_ptr(0);
723 if (elem)
724 bi.add_side(elem, 3, 5);
726
727 // Check the element now
728 if (elem && elem->processor_id() == mesh->processor_id())
729 {
730 std::vector<boundary_id_type> container;
731 bi.boundary_ids(elem, 3, container);
732
733 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
734 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[0]);
735 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[1]);
736
737 std::vector<std::vector<boundary_id_type>> all_bids_container;
738 bi.side_boundary_ids(elem, all_bids_container);
739 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
740 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
741 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
742 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][1]);
743 // Check other sides
744 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[0].size());
745 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(0), all_bids_container[0][0]);
746 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
747 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(1), all_bids_container[1][0]);
748 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
749 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
750 }
751 }
752
754 {
755 LOG_UNIT_TEST;
756
757 // Set subdomain ids for specific elements, we will refine/coarsen
758 // the cell on subdomain 1
759 // _____________
760 // | 1 | 2 |
761 // |_____|_____|
762
763 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
765 2, 1,
766 0., 2.,
767 0., 1.,
768 QUAD4);
769
771
772 for (auto & elem : mesh->active_element_ptr_range())
773 {
774 const Point c = elem->vertex_average();
775 if (c(0) < 1)
776 {
777 elem->subdomain_id() = 1;
778 elem->set_refinement_flag(Elem::REFINE);
779 }
780 else
781 elem->subdomain_id() = 2;
782 }
784
785 // Refine the elements once in subdomain 1, and
786 // add the right side subdomain 1 as boundary 5
789
790 for (auto & elem : mesh->active_element_ptr_range())
791 {
792 const Point c = elem->vertex_average();
793 if (c(0) < 1 && c(0) > 0.5)
794 bi.add_side(elem, 1, 5);
795 }
797
798 // Check the middle boundary, we expect to have two sides in boundary 5
799 unsigned int count = 0;
800 for (auto & elem : mesh->active_element_ptr_range())
801 if (bi.has_boundary_id(elem, 1, 5))
802 count++;
803
805 {
806 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(2), count);
807 CPPUNIT_ASSERT(bi.is_children_on_boundary_side());
808 }
809
810 // First, we will coarsen the the elements on subdomain 1. This
811 // is to check if the boundary information propagates upward upon
812 // coarsening.
813 for (auto & elem : mesh->active_element_ptr_range())
814 {
815 const Point c = elem->vertex_average();
816 if (c(0) < 1)
817 elem->set_refinement_flag(Elem::COARSEN);
818 }
820
821 // The coarsened element should have its side on boundary 5
822 // This is boundary info transferred from this child element
825
826 for (auto & elem : mesh->active_element_ptr_range())
827 {
828 const Point c = elem->vertex_average();
829 if (c(0) < 1)
830 {
831 CPPUNIT_ASSERT(bi.has_boundary_id(elem, 1, 5));
832 // We clean up this boundary ID for the next round of tests
833 bi.remove_side(elem, 1, 5);
834 // we will refine this element again
835 elem->set_refinement_flag(Elem::REFINE);
836 }
837 }
838
841
842 // This time we remove boundary 5 from one of the children. We expect
843 // the boundary not to propagate to the next level. Furthermore we
844 // expect boundary 5 to be deleted from the parent's boundaries
845 for (auto & elem : mesh->active_element_ptr_range())
846 {
847 const Point c = elem->vertex_average();
848 if (c(0) < 1)
849 elem->set_refinement_flag(Elem::COARSEN);
850 if (c(0) > 0.5 && c(0) < 1 && c(1) < 0.5)
851 bi.add_side(elem, 1, 5);
852 }
854
856
858
859 // The parent element should not have any side associated with boundary 5
860 for (auto & elem : mesh->active_element_ptr_range())
861 {
862 const Point c = elem->vertex_average();
863 if (c(0) < 1)
864 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, 1, 5));
865 }
866 }
867
869 {
870 LOG_UNIT_TEST;
871
872 // We create one cell only. The default boundaries of the cell are below.
873 // We will refine the mesh and add a new boundary id to the left side (side 3).
874 // Then will query the available boundary ids on the added side. It should return
875 // both the parent's and the child's boundaries.
876 // ___2___
877 // 3 | | 1
878 // |_____|
879 // 0
880
881 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
883 1, 1,
884 0., 1.,
885 0., 1.,
886 QUAD4);
887
889
890 // We only have one element, but for easy access we use the iterator
891 for (auto & elem : mesh->active_element_ptr_range())
892 elem->set_refinement_flag(Elem::REFINE);
894
896
897 // Now we add the extra boundary ID (5) to the element in the top
898 // left corner
899 for (auto & elem : mesh->active_element_ptr_range())
900 {
901 const Point c = elem->vertex_average();
902 if (c(0) < 0.5 && c(1) > 0.5)
903 bi.add_side(elem, 3, 5);
904 }
906
907 // Okay, now we query the boundary ids on side 3 of the child and check if it has
908 // the right elements
909 for (auto & elem : mesh->active_element_ptr_range())
910 {
911 const Point c = elem->vertex_average();
912 if (c(0) < 0.5 && c(1) > 0.5)
913 {
914 std::vector<boundary_id_type> container;
915 bi.boundary_ids(elem, 3, container);
916
917 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
918 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[0]);
919 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[1]);
920
921 std::vector<std::vector<boundary_id_type>> all_bids_container;
922 bi.side_boundary_ids(elem, all_bids_container);
923 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
924 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
925 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][0]);
926 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][1]);
927 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
928 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
929 // Check other sides
930 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[0].size());
931 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[1].size());
932
933 // This is against the spirit of the test, and undefined behavior which
934 // may be changed later. Setting allow_children_on_boundary_side(false) could
935 // be actively doing a transfer_boundary_ids_from_children() and then deleting the
936 // children's data, not leaving the children's data there-but-ignored.
938 bi.side_boundary_ids(elem, all_bids_container);
939 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
940 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[3].size());
941 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
942 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
943 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
944 }
945 }
946 }
947
949 {
950 LOG_UNIT_TEST;
951
952 // We create one cell only. The default boundaries of the cell are below.
953 // We will refine mesh and see if we can get back the correct sides
954 // for a given boundary id on an internal boundary.
955 // ___2___
956 // 3 | | 1
957 // |_____|
958 // 0
959
960 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
962 1, 1,
963 0., 1.,
964 0., 1.,
965 QUAD4);
966
968
969
970 // We only have one element, but for easy access we use the iterator
971 for (auto & elem : mesh->active_element_ptr_range())
972 elem->set_refinement_flag(Elem::REFINE);
975
976 // Now we add the extra boundary ID (5) to two sides of
977 // the element in the bottom left corner. then we refine again
978 for (auto & elem : mesh->active_element_ptr_range())
979 {
980 const Point c = elem->vertex_average();
981 if (c(0) < 0.5 && c(1) < 0.5)
982 {
983 bi.add_side(elem, 1, 5);
984 bi.add_side(elem, 2, 5);
985 elem->set_refinement_flag(Elem::REFINE);
986 }
987 }
990
991 // Okay, now we add another boundary id (6) to the cell which is in the bottom
992 // right corner of the refined element
993 for (auto & elem : mesh->active_element_ptr_range())
994 {
995 const Point c = elem->vertex_average();
996 if (c(0) < 0.5 && c(0) > 0.25 && c(1) < 0.25)
997 bi.add_side(elem, 1, 6);
998 }
999
1000 // Time to test if we can get back the boundary sides, first we
1001 // check if we can get back boundary from the ancestors of (5) on
1002 // the cell which only has boundary (6) registered. We also check
1003 // if we can get boundary (6) back.
1004
1005 for (auto & elem : mesh->active_element_ptr_range())
1006 {
1007 const Point c = elem->vertex_average();
1008 if (c(0) < 0.5 && c(0) > 0.25 && c(1) < 0.25)
1009 {
1010 const auto side_5 = bi.side_with_boundary_id(elem, 5);
1011 const auto side_6 = bi.side_with_boundary_id(elem, 6);
1012 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), side_5);
1013 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), side_6);
1014 }
1015 }
1016
1017 // Now we go and try to query the sides with boundary id (5) using
1018 // the element which is at the top right corner of the bottom
1019 // right parent.
1020 for (auto & elem : mesh->active_element_ptr_range())
1021 {
1022 const Point c = elem->vertex_average();
1023 if (c(0) < 0.5 && c(0) > 0.25 && c(1) > 0.25 && c(1) < 0.5)
1024 {
1025 const auto sides = bi.sides_with_boundary_id(elem, 5);
1026 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned long>(2), sides.size());
1027 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), sides[0]);
1028 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(2), sides[1]);
1029 }
1030 }
1031 }
1032#endif //LIBMESH_ENABLE_AMR
1033
1034
1036 {
1037 LOG_UNIT_TEST;
1038
1040
1042 2, 2,
1043 0., 1.,
1044 0., 1.,
1045 QUAD4);
1046
1048
1049 // build_square gave us ids 0-3 as both side sets and node sets
1050 bi.remove_node_id(0);
1051 bi.remove_node_id(1);
1052 bi.remove_node_id(2);
1053 bi.remove_node_id(3);
1054
1055 CPPUNIT_ASSERT(bi.build_node_list().empty());
1056
1058
1059 for (const auto & elem : mesh.element_ptr_range())
1060 {
1061 for (auto n : elem->node_index_range())
1062 {
1063 const Node * node = elem->node_ptr(n);
1064 for (auto s : {0,2})
1065 if (elem->is_node_on_side(n, s) && !elem->neighbor_ptr(s))
1066 CPPUNIT_ASSERT(bi.has_boundary_id(node, s));
1067 for (auto s : {1,3})
1068 CPPUNIT_ASSERT(!bi.has_boundary_id(node, s));
1069 }
1070 }
1071 }
1072
1073
1075 {
1076 LOG_UNIT_TEST;
1077
1079
1081 2, 2,
1082 0., 1.,
1083 0., 1.,
1084 QUAD4);
1085
1087
1088 // build_square gave us ids 0-3 as both side sets and node sets
1089 bi.remove_side_id(0);
1090 bi.remove_side_id(1);
1091 bi.remove_side_id(2);
1092 bi.remove_side_id(3);
1093
1094 CPPUNIT_ASSERT(bi.build_side_list().empty());
1095
1097
1098 for (const auto & elem : mesh.element_ptr_range())
1099 {
1100 for (auto s : {0,2})
1101 {
1102 if (!elem->neighbor_ptr(s))
1103 {
1104 CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, s));
1105 CPPUNIT_ASSERT_EQUAL(bi.n_boundary_ids(elem, s), 1u);
1106 }
1107 else
1108 CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1109 }
1110 for (auto s : {1,3})
1111 {
1112 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, s));
1113 CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1114 }
1115 }
1116 }
1117
1118
1120 {
1121 LOG_UNIT_TEST;
1122
1124
1125 // A mesh that is only one element deep in y: every node in the
1126 // mesh lies on either the bottom (y=0) or top (y=1) exterior
1127 // face, so a nodeset containing "the top and bottom nodes" ends
1128 // up containing *every* node, including those on the interior
1129 // sides between elements.
1131 8, 1,
1132 0., 1.,
1133 0., 1.,
1134 QUAD4);
1135
1137
1138 const boundary_id_type nodeset_id = 100;
1139 for (const auto & node : mesh.node_ptr_range())
1140 bi.add_node(node, nodeset_id);
1141
1142 // Sanity check: every node in this thin mesh is in the nodeset.
1143 for (const auto & node : mesh.node_ptr_range())
1144 CPPUNIT_ASSERT(bi.has_boundary_id(node, nodeset_id));
1145
1146 // build_side_list_from_node_list() is purely additive (it never
1147 // removes a side once added), so we must run the strict
1148 // skip_interior_sides = true check first, before any call adds
1149 // the interior side to the sideset.
1150 //
1151 // Passing skip_interior_sides = true should skip the interior
1152 // side, even though all of its nodes are (trivially) in the
1153 // nodeset.
1154 bi.build_side_list_from_node_list({nodeset_id}, /*skip_interior_sides=*/true);
1155
1156 // We only examine local elements here: a ghost element's neighbor
1157 // may be a RemoteElem, whose subdomain_id() tells us nothing about
1158 // the subdomain of the element it stands in for, so we couldn't
1159 // predict the correct answer for its sides.
1160 for (const auto & elem : mesh.active_local_element_ptr_range())
1161 for (auto s : elem->side_index_range())
1162 {
1163 const Elem * neigh = elem->neighbor_ptr(s);
1164 libmesh_assert(neigh != remote_elem);
1165 if (neigh && neigh->subdomain_id() == elem->subdomain_id())
1166 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, nodeset_id));
1167 else
1168 CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, nodeset_id));
1169 }
1170
1171 // Default behavior (skip_interior_sides = false) should preserve
1172 // the old, unconditional behavior, adding the interior side even
1173 // though it isn't a true boundary. Since add_side() is additive,
1174 // this call only needs to add the interior side; the exterior
1175 // sides are already present from the call above.
1176 bi.build_side_list_from_node_list({nodeset_id});
1177
1178 bool found_interior_side = false;
1179 for (const auto & elem : mesh.active_local_element_ptr_range())
1180 for (auto s : elem->side_index_range())
1181 {
1182 const Elem * neigh = elem->neighbor_ptr(s);
1183 libmesh_assert(neigh != remote_elem);
1184 if (neigh && neigh->subdomain_id() == elem->subdomain_id() &&
1185 bi.has_boundary_id(elem, s, nodeset_id))
1186 found_interior_side = true;
1187 }
1188
1189 // A processor with no local elements of its own can't find one.
1190 mesh.comm().max(found_interior_side);
1191 CPPUNIT_ASSERT(found_interior_side);
1192 }
1193
1194
1195 // Regression test for a deadlock in build_side_list_from_node_list()
1196 // (libMesh issue #4564): on a DistributedMesh, _boundary_node_id can
1197 // be empty on some processors (ones that don't own or ghost any
1198 // node in the nodeset) while it's non-empty on others. The
1199 // function used to return early based purely on local state, which
1200 // caused processors that took the early return to skip a later
1201 // collective communication call that the remaining processors still
1202 // entered, deadlocking.
1204 {
1205 LOG_UNIT_TEST;
1206
1208
1210
1212
1213 // Only the two domain endpoint nodes are in the nodeset, like a
1214 // Neumann-BC-at-the-ends use case. With enough processors, most
1215 // ranks won't locally own or ghost either endpoint.
1216 //
1217 // Pick the endpoints out geometrically rather than by node id:
1218 // prepare_for_use() renumbers a DistributedMesh's nodes so that
1219 // each processor's are contiguous, so the ids the line was built
1220 // with don't survive, and with enough processors ids 0 and 40
1221 // land on interior nodes.
1222 const boundary_id_type nodeset_id = 100;
1223 for (const auto & node : mesh.node_ptr_range())
1224 if (std::abs((*node)(0) - 0.) < TOLERANCE ||
1225 std::abs((*node)(0) - 1.) < TOLERANCE)
1226 bi.add_node(node, nodeset_id);
1227
1228 bi.build_side_list_from_node_list({nodeset_id}, /*skip_interior_sides=*/true);
1229
1230 for (const auto & elem : mesh.active_local_element_ptr_range())
1231 for (auto s : elem->side_index_range())
1232 {
1233 // Only the two exterior sides, at the physical ends of the
1234 // line, should have been added to the sideset; every other
1235 // side is interior to the (single) subdomain, whether or
1236 // not its neighbor was a RemoteElem that had to be resolved
1237 // via communication.
1238 if (!elem->neighbor_ptr(s))
1239 CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, nodeset_id));
1240 else
1241 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, nodeset_id));
1242 }
1243 }
1244
1245
1247 {
1248 LOG_UNIT_TEST;
1249
1251
1252 // Build a 2x2 QUAD4 structured mesh on [0,1]x[0,1].
1254 2, 2,
1255 0., 1.,
1256 0., 1.,
1257 QUAD4);
1258
1260
1261 const unsigned int internal_side = 1; // east side for left elems
1262 const boundary_id_type BID = 7;
1263
1265
1266 Elem * left_bottom_elem = nullptr;
1267 for (auto & elem : mesh.active_element_ptr_range())
1268 {
1269 if (elem->processor_id() != mesh.processor_id())
1270 continue;
1271
1272 const Point c = elem->vertex_average();
1273 if (c(0) < 0.5 && c(1) < 0.5 && elem->neighbor_ptr(internal_side) != nullptr)
1274 {
1275 left_bottom_elem = elem;
1276 break;
1277 }
1278 }
1279
1280
1281 if (left_bottom_elem)
1282 {
1283 bi.add_side(left_bottom_elem, internal_side, BID);
1284
1285 const unsigned int found_side = bi.side_with_boundary_id(left_bottom_elem, BID);
1286 CPPUNIT_ASSERT_EQUAL(internal_side, found_side);
1287 }
1288 }
1289
1290
1291};
1292
CPPUNIT_TEST(testInternalBoundary)
CPPUNIT_TEST(testBoundaryOnChildrenBoundaryIDs)
CPPUNIT_TEST(testShellFaceConstraints)
CPPUNIT_TEST(testEdgeBoundaryConditions)
CPPUNIT_TEST(testBoundaryIDs)
void testSelectiveRenumber()
CPPUNIT_TEST(testBuildSideListFromNodeListDistributedMesh)
CPPUNIT_TEST(testBuildSideListFromNodeListThinMesh)
void testBuildSideListFromNodeListThinMesh()
CPPUNIT_TEST(testBoundaryOnChildrenElementsRefineCoarsen)
void testShellFaceConstraints()
void testBoundaryOnChildrenErrors()
void testBuildSideListFromNodeList()
CPPUNIT_TEST(testBoundaryOnChildrenErrors)
CPPUNIT_TEST(testBoundaryOnChildrenBoundarySides)
CPPUNIT_TEST(testBuildSideListFromNodeList)
CPPUNIT_TEST(testSelectiveRenumber)
CPPUNIT_TEST(testMesh)
CPPUNIT_TEST(testNameCopying)
void testBoundaryOnChildrenElementsRefineCoarsen()
void testEdgeBoundaryConditions()
CPPUNIT_TEST(testBuildNodeListFromSideList)
CPPUNIT_TEST(testRenumber)
void testBuildNodeListFromSideList()
void testBoundaryOnChildrenBoundarySides()
LIBMESH_CPPUNIT_TEST_SUITE(BoundaryInfoTest)
This test ensures various aspects of the BoundaryInfo class work as expected.
void testBoundaryOnChildrenBoundaryIDs()
void testBuildSideListFromNodeListDistributedMesh()
void max(const T &r, T &o, Request &req) const
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
std::size_t n_boundary_ids() const
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 ...
std::string & sideset_name(boundary_id_type id)
void side_boundary_ids(const Elem *const elem, std::vector< std::vector< boundary_id_type > > &vec_to_fill) const
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.
void synchronize_global_id_set()
Synchronizes the boundary_ids set on each processor to determine global_boundary_ids.
void allow_children_on_boundary_side(const bool children_on_boundary)
Whether or not to allow directly setting boundary sides on child elements.
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.
void build_side_list_from_node_list(const std::set< boundary_id_type > &nodeset_list={}, bool skip_interior_sides=false)
Adds sides to a sideset if every node on that side is in the same nodeset.
unsigned int side_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
std::size_t n_edge_conds() 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...
std::vector< unsigned int > sides_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
const std::set< boundary_id_type > & get_edge_boundary_ids() const
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.
std::string & nodeset_name(boundary_id_type id)
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...
std::size_t n_shellface_conds() const
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...
const std::string & get_nodeset_name(boundary_id_type id) const
const std::set< boundary_id_type > & get_boundary_ids() const
const std::set< boundary_id_type > & get_node_boundary_ids() const
void build_node_list_from_side_list(const std::set< boundary_id_type > &sideset_list={})
Adds nodes with boundary ids based on the side's boundary ids they are connected to.
const std::string & get_sideset_name(boundary_id_type id) const
std::string & edgeset_name(boundary_id_type id)
const std::set< boundary_id_type > & get_side_boundary_ids() const
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
bool is_children_on_boundary_side() 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 ...
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 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.
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.
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.
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2203
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
bool is_constrained_dof(const dof_id_type dof) const
Definition dof_map.h:2439
processor_id_type processor_id() const
Definition dof_object.h:895
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual Node *& set_node(const unsigned int i)
Definition elem.h:2688
const Point & point(const unsigned int i) const
Definition elem.h:2583
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:382
subdomain_id_type subdomain_id() const
Definition elem.h:2712
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2736
This is the EquationSystems class.
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
virtual bool is_serial() const
Definition mesh_base.h:357
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
virtual const Node * node_ptr(const dof_id_type i) const =0
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:1359
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
virtual void write(const std::string &name) const =0
virtual std::unique_ptr< MeshBase > clone() const =0
Virtual "copy constructor".
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.
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.
virtual dof_id_type max_elem_id() const =0
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
dof_id_type n_active_local_elem() const
Definition mesh_base.h:711
Implements (adaptive) mesh refinement algorithms for a MeshBase.
bool coarsen_elements()
Only coarsens the user-requested elements.
bool refine_elements()
Only refines the user-requested elements.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
A Node is like a Point, but with more information.
Definition node.h:55
A class to stub for features that should be in libMesh, but haven't been written yet,...
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
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
dof_id_type n_constrained_dofs() const
Definition system.C:125
const DofMap & get_dof_map() const
Definition system.h:2417
ConstFunction that simply returns 0.
Communicator * TestCommWorld
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.
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 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.
The libMesh namespace provides an interface to certain functionality in the library.
int8_t boundary_id_type
Definition id_types.h:51
libmesh_assert(ctx)
const RemoteElem * remote_elem
Definition remote_elem.C:57
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
CPPUNIT_TEST_SUITE_REGISTRATION(BoundaryInfoTest)