libMesh
Loading...
Searching...
No Matches
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
18using namespace libMesh;
19
20class BoundaryInfoTest : public CppUnit::TestCase {
24public:
26
28
29#if LIBMESH_DIM > 1
33# if LIBMESH_DIM > 2
35# endif
36# ifdef LIBMESH_ENABLE_AMR
37# ifdef LIBMESH_ENABLE_EXCEPTIONS
39# endif
44# endif
47# ifdef LIBMESH_ENABLE_DIRICHLET
49# endif
50#endif
51#if LIBMESH_DIM > 2
53#endif
54
56
57protected:
58
59public:
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
444 TestCommWorld->barrier();
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
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
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);
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;
674 bi.allow_children_on_boundary_side(true);
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
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
CPPUNIT_TEST(testInternalBoundary)
CPPUNIT_TEST(testBoundaryOnChildrenBoundaryIDs)
CPPUNIT_TEST(testShellFaceConstraints)
CPPUNIT_TEST(testEdgeBoundaryConditions)
CPPUNIT_TEST(testBoundaryIDs)
void testSelectiveRenumber()
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 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={})
Adds sides to a sideset if every node on that side are in the same sideset.
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
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...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
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:2426
processor_id_type processor_id() const
Definition dof_object.h:881
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:2567
const Point & point(const unsigned int i) const
Definition elem.h:2462
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
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:1355
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:714
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:40
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
uint8_t dof_id_type
Definition id_types.h:67
CPPUNIT_TEST_SUITE_REGISTRATION(BoundaryInfoTest)