libMesh
Loading...
Searching...
No Matches
boundary_mesh.C
Go to the documentation of this file.
1#include <libmesh/distributed_mesh.h>
2#include <libmesh/mesh.h>
3#include <libmesh/mesh_generation.h>
4#include <libmesh/mesh_refinement.h>
5#include <libmesh/mesh_serializer.h>
6#include <libmesh/remote_elem.h>
7#include <libmesh/replicated_mesh.h>
8#include <libmesh/boundary_info.h>
9#include <libmesh/mesh_tools.h>
11
12#include "test_comm.h"
13#include "libmesh_cppunit.h"
14
15#include <memory>
16
17namespace {
18
19 using namespace libMesh;
20
21 // Check that the interior_parent side indices that we set on a
22 // BoundaryMesh as extra integers agree with the side returned by
23 // which_side_am_i().
24 void check_parent_side_index_tag(UnstructuredMesh & boundary_mesh)
25 {
26 const unsigned int parent_side_index_tag =
27 boundary_mesh.get_elem_integer_index("parent_side_index");
28
29 for (const auto & belem : boundary_mesh.element_ptr_range())
30 {
31 const dof_id_type parent_side_index =
32 belem->get_extra_integer(parent_side_index_tag);
33
34 if (belem->interior_parent() != remote_elem)
35 CPPUNIT_ASSERT_EQUAL
36 (static_cast<dof_id_type>(belem->interior_parent()->which_side_am_i(belem)),
37 parent_side_index);
38 }
39 }
40
41 void sanity_check_mesh(const UnstructuredMesh & mesh,
42 ElemType boundary_type,
43 ElemType interior_type,
44 bool is_mixed)
45 {
46 const unsigned int interior_dim = Elem::type_to_dim_map[interior_type];
47
48 for (const auto & elem : mesh.active_element_ptr_range())
49 {
50 const Elem * pip = elem->dim() < interior_dim ?
51 elem->interior_parent() : nullptr;
52
53 // On a DistributedMesh we might not be able to see the
54 // interior_parent of a non-local element
55 if (pip == remote_elem)
56 {
57 CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
58 continue;
59 }
60
61 // The boundary elements should have interior parents of the
62 // specified type; interior element shouldn't have any
63 // interior parents.
64 if (pip)
65 {
66 CPPUNIT_ASSERT_EQUAL(elem->type(), boundary_type);
67 CPPUNIT_ASSERT_EQUAL(pip->type(), interior_type);
68 CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
69 }
70 else
71 {
72 // We should only see interior elements if we expected
73 // them
74 CPPUNIT_ASSERT(is_mixed);
75 CPPUNIT_ASSERT_EQUAL(elem->type(), interior_type);
76 }
77 }
78 }
79}
80
81using namespace libMesh;
82
83class BoundaryMesh0DTest : public CppUnit::TestCase {
88public:
90
91#if LIBMESH_DIM > 1
93#endif
94
96
97protected:
98
99 std::unique_ptr<UnstructuredMesh> _mesh;
100 std::unique_ptr<UnstructuredMesh> _replicated_boundary_mesh;
101 std::unique_ptr<UnstructuredMesh> _distributed_boundary_mesh;
102 std::unique_ptr<UnstructuredMesh> _interior_node_mesh;
103
105 {
106 _mesh = std::make_unique<Mesh>(*TestCommWorld);
107 _replicated_boundary_mesh = std::make_unique<ReplicatedMesh>(*TestCommWorld);
108 _distributed_boundary_mesh = std::make_unique<DistributedMesh>(*TestCommWorld);
109 _interior_node_mesh = std::make_unique<Mesh>(*TestCommWorld);
110
112 0.2, 0.8, EDGE3);
113
114 static constexpr boundary_id_type bid_int = 2;
115
116 // Add an interior boundary too
117 BoundaryInfo & bi = _mesh->get_boundary_info();
118 for (auto & elem : _mesh->active_element_ptr_range())
119 {
120 const Point c = elem->vertex_average();
121 if (c(0) > 0.6)
122 bi.add_side(elem, 0, bid_int);
123 }
124
125 // We'll need to skip most repartitioning with DistributedMesh for
126 // now; otherwise the boundary meshes' interior parents might get
127 // shuffled off to different processors.
128 if (!_mesh->is_serial())
129 {
130 _mesh->skip_noncritical_partitioning(true);
131 _replicated_boundary_mesh->skip_noncritical_partitioning(true);
132 _distributed_boundary_mesh->skip_noncritical_partitioning(true);
133 }
134 }
135
137 {
138 // Get the border of the line
139 const std::set<boundary_id_type> exterior_boundaries {0, 1};
140
141 _mesh->get_boundary_info().sync(exterior_boundaries,
143 check_parent_side_index_tag(*_replicated_boundary_mesh);
144
145 _mesh->get_boundary_info().sync(exterior_boundaries,
147 check_parent_side_index_tag(*_distributed_boundary_mesh);
148
149 const std::set<boundary_id_type> interior_boundaries {2};
150 _mesh->get_boundary_info().sync(interior_boundaries,
152 check_parent_side_index_tag(*_interior_node_mesh);
153
154 // Add the right side of the square to the square; this should
155 // make it a mixed dimension mesh. We skip storing the parent
156 // side ids (which is the default) since they are not needed
157 // in this particular test.
158 std::set<boundary_id_type> right_id;
159 right_id.insert(1);
160
161 _mesh->get_boundary_info().add_elements
162 (right_id, *_mesh, /*store_parent_side_ids=*/false);
163 _mesh->prepare_for_use();
164 }
165
166public:
167 void setUp()
168 {
169#if LIBMESH_DIM > 1
170 this->build_mesh();
171 this->sync_and_test_meshes();
172#endif
173 }
174
175 void testMesh()
176 {
177 LOG_UNIT_TEST;
178
179 // There'd better be 3 + 1 elements in the interior plus right
180 // boundary
181 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4),
182 _mesh->n_elem());
183
184 // There'd better be 7 nodes in the interior
185 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(7),
186 _mesh->n_nodes());
187
188 // There'd better be 2 elements on the exterior boundary
189 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
190 _replicated_boundary_mesh->n_elem());
191 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
193
194 // There'd better be 2 nodes on the exterior boundary
195 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
196 _replicated_boundary_mesh->n_nodes());
197 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
198 _distributed_boundary_mesh->n_nodes());
199
200 // There'd better be 1 nodeelem on the interior boundary
201 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(1),
202 _interior_node_mesh->n_elem());
203 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(1),
204 _interior_node_mesh->n_nodes());
205
206 this->sanityCheck();
207 }
208
210 {
211 LOG_UNIT_TEST;
212
213 MeshSerializer internal_serializer(*_distributed_boundary_mesh);
214
215 // There'd better be 2 elements on the exterior boundary
216 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
217 _replicated_boundary_mesh->n_elem());
218 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
220
221 // There'd better be 2 nodes on the exterior boundary
222 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
223 _replicated_boundary_mesh->n_nodes());
224 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(2),
225 _distributed_boundary_mesh->n_nodes());
226
227 this->sanityCheck();
228 }
229
231 {
232 sanity_check_mesh(*_mesh, NODEELEM, EDGE3, true);
233
234 sanity_check_mesh(*_replicated_boundary_mesh, NODEELEM, EDGE3, false);
235 sanity_check_mesh(*_distributed_boundary_mesh, NODEELEM, EDGE3, false);
236 sanity_check_mesh(*_interior_node_mesh, NODEELEM, EDGE3, false);
237 }
238};
239
241
242
243class BoundaryMeshTest : public CppUnit::TestCase {
248public:
250
251#if LIBMESH_DIM > 1
254#endif
255
257
258protected:
259
260 std::unique_ptr<UnstructuredMesh> _mesh;
261 std::unique_ptr<UnstructuredMesh> _multi_boundary_mesh;
262 std::unique_ptr<UnstructuredMesh> _exterior_boundary_mesh;
263 std::unique_ptr<UnstructuredMesh> _left_boundary_mesh;
264 std::unique_ptr<UnstructuredMesh> _internal_boundary_mesh;
265
266 // We create internal sideset IDs that do not conflict with
267 // sidesets 0-3 that get created by build_square().
268 static constexpr boundary_id_type bid1 = 5;
269 static constexpr boundary_id_type bid2 = 6;
270
272 {
273 _mesh = std::make_unique<Mesh>(*TestCommWorld);
274 _multi_boundary_mesh = std::make_unique<Mesh>(*TestCommWorld);
275 _exterior_boundary_mesh = std::make_unique<Mesh>(*TestCommWorld);
276
277 // We want to test Distributed->Replicated sync; this does that in
278 // some builds
279 _left_boundary_mesh = std::make_unique<ReplicatedMesh>(*TestCommWorld);
280
281 // We want to test Replicated->Distributed sync; this does that in
282 // other builds
283 _internal_boundary_mesh = std::make_unique<DistributedMesh>(*TestCommWorld);
284
286 0.2, 0.8, 0.2, 0.7, QUAD9);
287
288 // We'll need to skip most repartitioning with DistributedMesh for
289 // now; otherwise the boundary meshes' interior parents might get
290 // shuffled off to different processors.
291 if (!_mesh->is_serial())
292 {
293 _mesh->skip_noncritical_partitioning(true);
294 _left_boundary_mesh->skip_noncritical_partitioning(true);
295 _multi_boundary_mesh->skip_noncritical_partitioning(true);
296 _exterior_boundary_mesh->skip_noncritical_partitioning(true);
297 _internal_boundary_mesh->skip_noncritical_partitioning(true);
298 }
299
300 // Set subdomain ids for specific elements. This allows us to later
301 // build an internal sideset with respect to a given
302 // subdomain. The element subdomains look like:
303 // ___________________
304 // | 2 | 2 | 2 |
305 // |_____|_____|_____|
306 // | 2 | 2 | 2 |
307 // |_____|_____|_____|
308 // | 2 | 2 | 2 |
309 // |_____|_____|_____|
310 // | 1 | 1 | 2 |
311 // |_____|_____|_____|
312 // | 1 | 1 | 2 |
313 // |_____|_____|_____|
314 //
315 // and we will create an internal sideset along the border between
316 // subdomains 1 and 2.
317
318 for (auto & elem : _mesh->active_element_ptr_range())
319 {
320 const Point c = elem->vertex_average();
321 if (c(0) < 0.6 && c(1) < 0.4)
322 elem->subdomain_id() = 1;
323 else
324 elem->subdomain_id() = 2;
325 }
326
327 // To test the "relative to" feature, we add the same sides to the
328 // same sideset twice, from elements in subdomain 2 the second
329 // time. These should not show up in the BoundaryMesh, i.e. there
330 // should not be overlapped elems in the BoundaryMesh.
331 BoundaryInfo & bi = _mesh->get_boundary_info();
332
333 for (auto & elem : _mesh->active_element_ptr_range())
334 {
335 const Point c = elem->vertex_average();
336 if (c(0) < 0.6 && c(1) < 0.4)
337 {
338 if (c(0) > 0.4)
339 bi.add_side(elem, 1, bid1);
340 if (c(1) > 0.3)
341 bi.add_side(elem, 2, bid1);
342 }
343 else
344 {
345 if (c(0) < 0.75 && c(1) < 0.4)
346 bi.add_side(elem, 3, bid2);
347 if (c(0) < 0.6 && c(1) < 0.5)
348 bi.add_side(elem, 0, bid2);
349 }
350 }
351 }
352
354 {
355 // Get the border of the square
356 const std::set<boundary_id_type> exterior_boundaries {0, 1, 2, 3};
357 _mesh->get_boundary_info().sync(exterior_boundaries,
359 check_parent_side_index_tag(*_exterior_boundary_mesh);
360
361 // The mesh of all boundaries is, because of the two nodes each
362 // joining three edges where the internal boundary meets the
363 // external boundary, not a manifold mesh. We still have work to
364 // do to properly support non-manifold meshes, and
365 // find_neighbors() when preparing such a mesh is likely to fail,
366 // so we'll just do the best test we can here, requesting a set of
367 // three different boundaries. We drop the left and bottom
368 // boundaries because they have any T intersections with the
369 // interior boundaries, and we drop one of the interior boundaries
370 // because with both together we'd have 4 edges meeting at every
371 // interior boundary vertex.
372 const std::set<boundary_id_type> multi_boundaries {1, 2, 5};
373 _mesh->get_boundary_info().sync(multi_boundaries,
375 check_parent_side_index_tag(*_multi_boundary_mesh);
376
377 std::set<boundary_id_type> left_id, right_id;
378 left_id.insert(3);
379 right_id.insert(1);
380
381 // Add the right side of the square to the square; this should
382 // make it a mixed dimension mesh. We skip storing the parent
383 // side ids (which is the default) since they are not needed
384 // in this particular test.
385 _mesh->get_boundary_info().add_elements
386 (right_id, *_mesh, /*store_parent_side_ids=*/false);
387 _mesh->prepare_for_use();
388
389 // Add the left side of the square to its own boundary mesh.
390 _mesh->get_boundary_info().sync(left_id, *_left_boundary_mesh);
391 check_parent_side_index_tag(*_left_boundary_mesh);
392
393 // Create a BoundaryMesh from the internal sidesets relative to subdomain 1.
394 {
395 std::set<boundary_id_type> requested_boundary_ids {bid1, bid2};
396 std::set<subdomain_id_type> subdomains_relative_to;
397 subdomains_relative_to.insert(1);
398 _mesh->get_boundary_info().sync(requested_boundary_ids,
400 subdomains_relative_to);
401 check_parent_side_index_tag(*_internal_boundary_mesh);
402 }
403 }
404
405public:
406 void setUp()
407 {
408#if LIBMESH_DIM > 1
409 this->build_mesh();
410 this->sync_and_test_meshes();
411#endif
412 }
413
414 void testMesh()
415 {
416 LOG_UNIT_TEST;
417
418 // There'd better be 3*5 + 5 elements in the interior plus right
419 // boundary
420 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(20),
421 _mesh->n_elem());
422
423 // There'd better be 7*11 nodes in the interior
424 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(77),
425 _mesh->n_nodes());
426
427 // There'd better be 2*(3+5) elements on the exterior boundary
428 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(16),
429 _exterior_boundary_mesh->n_elem());
430
431 // There'd better be 2*2*(3+5) nodes on the exterior boundary
432 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
433 _exterior_boundary_mesh->n_nodes());
434
435 // There'd better be 5 elements on the left boundary
436 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(5),
437 _left_boundary_mesh->n_elem());
438
439 // There'd better be 2*5+1 nodes on the left boundary
440 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(11),
441 _left_boundary_mesh->n_nodes());
442
443 // There are four elements in the one-sided internal sideset mesh.
444 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4),
445 _internal_boundary_mesh->n_elem());
446
447 // There are 2*n_elem + 1 nodes in the one-sided internal sideset mesh.
448 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(9),
449 _internal_boundary_mesh->n_nodes());
450
451 // There'd better be 3+5 + 4 elements on the multi-boundary
452 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
453 _multi_boundary_mesh->n_elem());
454
455 // There'd better be (3+5)*2+1 + 4*2+1 nodes on the multi-boundary
456 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(26),
457 _multi_boundary_mesh->n_nodes());
458
459 this->sanityCheck();
460 }
461
463 {
464 LOG_UNIT_TEST;
465
466 MeshSerializer internal_serializer(*_internal_boundary_mesh);
467
468 // There are four elements in the internal sideset mesh.
469 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4),
470 _internal_boundary_mesh->n_elem());
471
472 // There are 2*n_elem + 1 nodes in the internal sideset mesh.
473 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(9),
474 _internal_boundary_mesh->n_nodes());
475
476 this->sanityCheck();
477 }
478
480 {
481 sanity_check_mesh(*_mesh, EDGE3, QUAD9, true);
482 sanity_check_mesh(*_multi_boundary_mesh, EDGE3, QUAD9, false);
483 sanity_check_mesh(*_exterior_boundary_mesh, EDGE3, QUAD9, false);
484 sanity_check_mesh(*_left_boundary_mesh, EDGE3, QUAD9, false);
485 sanity_check_mesh(*_internal_boundary_mesh, EDGE3, QUAD9, false);
486
487 for (const auto & elem : _left_boundary_mesh->active_element_ptr_range())
488 {
489 // We only added left edges here
490 LIBMESH_ASSERT_FP_EQUAL(0.2, elem->vertex_average()(0),
492 }
493
494 // Sanity check for the internal sideset mesh.
495 for (const auto & elem : _internal_boundary_mesh->active_element_ptr_range())
496 {
497 // All of the elements in the internal sideset mesh should
498 // have the same subdomain id as the parent Elems (i.e. 1)
499 // they came from.
500 CPPUNIT_ASSERT_EQUAL(static_cast<subdomain_id_type>(1),
501 elem->subdomain_id());
502 }
503 }
504
505};
506
508
509
510class BoundaryMeshSubdomainTest : public CppUnit::TestCase {
521public:
523
524#if LIBMESH_DIM > 1
528#endif
529
531
532public:
534 {
535 LOG_UNIT_TEST;
536
538 MeshTools::Generation::build_square(mesh, 3, 3, 0., 1., 0., 1., QUAD4);
539
540 const BoundaryInfo & bi = mesh.get_boundary_info();
541 const auto & side_boundary_ids = bi.get_side_boundary_ids();
542
543 mesh.get_boundary_info().add_elements(side_boundary_ids, mesh);
545
546 for (const auto & elem : mesh.active_element_ptr_range())
547 if (elem->dim() < mesh.mesh_dimension())
548 CPPUNIT_ASSERT_EQUAL(static_cast<subdomain_id_type>(0), elem->subdomain_id());
549 }
550
552 {
553 LOG_UNIT_TEST;
554
556 MeshTools::Generation::build_square(mesh, 3, 3, 0., 1., 0., 1., QUAD4);
557
558 const BoundaryInfo & bi = mesh.get_boundary_info();
559 const auto & side_boundary_ids = bi.get_side_boundary_ids();
560
561 const subdomain_id_type sid = 42;
562 mesh.get_boundary_info().add_elements(side_boundary_ids, mesh, false, {sid});
564
565 unsigned int n_lower = 0;
566 for (const auto & elem : mesh.active_element_ptr_range())
567 if (elem->dim() < mesh.mesh_dimension())
568 {
569 CPPUNIT_ASSERT_EQUAL(sid, elem->subdomain_id());
570 if (elem->processor_id() == mesh.processor_id())
571 ++n_lower;
572 }
573
574 // 3x3 quad mesh has 12 edges across its sides
575 mesh.comm().sum(n_lower);
576 CPPUNIT_ASSERT_EQUAL(12u, n_lower);
577 }
578
580 {
581 LOG_UNIT_TEST;
582
584 MeshTools::Generation::build_square(mesh, 3, 3, 0., 1., 0., 1., QUAD4);
585
586 const BoundaryInfo & bi = mesh.get_boundary_info();
587 const boundary_id_type right_id = bi.get_id_by_name("right");
588 const boundary_id_type top_id = bi.get_id_by_name("top");
589
590 // The set is iterated in sorted boundary_id order, so the subdomain_ids
591 // vector must be ordered accordingly.
592 const subdomain_id_type right_sid = 10;
593 const subdomain_id_type top_sid = 20;
594 std::set<boundary_id_type> ids = {right_id, top_id};
595 std::vector<subdomain_id_type> sids;
596 for (const auto id : ids)
597 sids.push_back(id == right_id ? right_sid : top_sid);
598
599 mesh.get_boundary_info().add_elements(ids, mesh, false, sids);
601
602 unsigned int n_right = 0, n_top = 0;
603 for (const auto & elem : mesh.active_element_ptr_range())
604 if (elem->dim() < mesh.mesh_dimension())
605 {
606 const Real cx = elem->vertex_average()(0);
607 if (cx > 0.9)
608 {
609 CPPUNIT_ASSERT_EQUAL(right_sid, elem->subdomain_id());
610 if (elem->processor_id() == mesh.processor_id())
611 ++n_right;
612 }
613 else
614 {
615 CPPUNIT_ASSERT_EQUAL(top_sid, elem->subdomain_id());
616 if (elem->processor_id() == mesh.processor_id())
617 ++n_top;
618 }
619 }
620
621 mesh.comm().sum(n_right);
622 mesh.comm().sum(n_top);
623 CPPUNIT_ASSERT_EQUAL(3u, n_right);
624 CPPUNIT_ASSERT_EQUAL(3u, n_top);
625 }
626};
627
629
630
631#ifdef LIBMESH_ENABLE_AMR
632
640public:
642
643#if LIBMESH_DIM > 1
646#endif
647
649
650 // Yes, this is necessary. Somewhere in those macros is a protected/private
651public:
652
653 void setUp()
654 {
655#if LIBMESH_DIM > 1
656 this->build_mesh();
657 this->sync_and_test_meshes();
658
659 // Need to refine interior mesh before separate boundary meshes,
660 // if we want to get interior_parent links right.
662
663 MeshRefinement(*_multi_boundary_mesh).uniformly_refine(1);
664 MeshRefinement(*_exterior_boundary_mesh).uniformly_refine(1);
665 MeshRefinement(*_left_boundary_mesh).uniformly_refine(1);
666 MeshRefinement(*_internal_boundary_mesh).uniformly_refine(1);
667#endif
668 }
669
670 void testMesh()
671 {
672 LOG_UNIT_TEST;
673
674 // There'd better be 3*5*4 + 5*2 active elements in the interior
675 // plus right boundary
676 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(70),
677 _mesh->n_active_elem());
678
679 // Plus the original 20 now-inactive elements
680 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(90),
681 _mesh->n_elem());
682
683 // There'd better be 13*21 nodes in the interior
684 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(273),
685 _mesh->n_nodes());
686
687 // There'd better be 2*2*(3+5) active elements on the exterior boundary
688 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
689 _exterior_boundary_mesh->n_active_elem());
690
691 // Plus the original 16 now-inactive elements
692 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(48),
693 _exterior_boundary_mesh->n_elem());
694
695 // There'd better be 2*2*2*(3+5) nodes on the exterior boundary
696 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(64),
697 _exterior_boundary_mesh->n_nodes());
698
699 // There'd better be 2*5 active elements on the left boundary
700 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(10),
701 _left_boundary_mesh->n_active_elem());
702
703 // Plus the original 5 now-inactive elements
704 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(15),
705 _left_boundary_mesh->n_elem());
706
707 // There'd better be 2*2*5+1 nodes on the left boundary
708 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(21),
709 _left_boundary_mesh->n_nodes());
710
711 // There'd better be 2*4 active elements on the one-sided internal
712 // sideset mesh
713 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
714 _internal_boundary_mesh->n_active_elem());
715
716 // Plus the original 4 now-inactive elements
717 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
718 _internal_boundary_mesh->n_elem());
719
720 // There'd better be 2*2*4+1 nodes on the internal boundary
721 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
722 _internal_boundary_mesh->n_nodes());
723
724 // There'd better be 2*(3+5) + 2*4 active elements on the
725 // multi-boundary
726 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(24),
727 _multi_boundary_mesh->n_active_elem());
728
729 // Plus the original 12 now-inactive elements
730 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(36),
731 _multi_boundary_mesh->n_elem());
732
733 // There'd better be 2*2*(3+5)+1 + 2*2*4+1 nodes on the
734 // multi-boundary
735 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(50),
736 _multi_boundary_mesh->n_nodes());
737
738
739 this->sanityCheck();
740 }
741
742
744 {
745 LOG_UNIT_TEST;
746
747 MeshSerializer internal_serializer(*_internal_boundary_mesh);
748
749 // There'd better be 2*4 active elements on the internal
750 // sideset mesh
751 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
752 _internal_boundary_mesh->n_active_elem());
753
754 // Plus the original 4 now-inactive elements
755 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
756 _internal_boundary_mesh->n_elem());
757
758 // There'd better be 2*2*4+1 nodes on the internal boundary
759 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
760 _internal_boundary_mesh->n_nodes());
761
762 this->sanityCheck();
763 }
764
765};
766
768
769
776public:
778
779#if LIBMESH_DIM > 1
782#endif
783
785
786 // Yes, this is necessary. Somewhere in those macros is a protected/private
787public:
788
789 void setUp()
790 {
791#if LIBMESH_DIM > 1
792 this->build_mesh();
793
794 // Refine interior mesh before creating boundary meshes
796
797 this->sync_and_test_meshes();
798#endif
799 }
800
801 void testMesh()
802 {
803 LOG_UNIT_TEST;
804
805 // There'd better be 3*5*4 + 5*2 active elements in the interior
806 // plus right boundary
807 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(70),
808 _mesh->n_active_elem());
809
810 // Plus the original 20 now-inactive elements
811 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(90),
812 _mesh->n_elem());
813
814 // There'd better be 13*21 nodes in the interior
815 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(273),
816 _mesh->n_nodes());
817
818 // There'd better be 2*2*(3+5) active elements on the exterior boundary
819 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
820 _exterior_boundary_mesh->n_active_elem());
821
822 // Plus the original 16 now-inactive elements
823 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(48),
824 _exterior_boundary_mesh->n_elem());
825
826 // There'd better be 2*2*2*(3+5) nodes on the exterior boundary
827 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(64),
828 _exterior_boundary_mesh->n_nodes());
829
830 // There'd better be 2*5 active elements on the left boundary
831 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(10),
832 _left_boundary_mesh->n_active_elem());
833
834 // Plus the original 5 now-inactive elements
835 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(15),
836 _left_boundary_mesh->n_elem());
837
838 // There'd better be 2*2*5+1 nodes on the left boundary
839 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(21),
840 _left_boundary_mesh->n_nodes());
841
842 // There'd better be 2*4 active elements on the internal
843 // sideset mesh
844 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
845 _internal_boundary_mesh->n_active_elem());
846
847 // Plus the original 4 now-inactive elements
848 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
849 _internal_boundary_mesh->n_elem());
850
851 // There'd better be 2*2*4+1 nodes on the one-sided internal boundary
852 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
853 _internal_boundary_mesh->n_nodes());
854
855 // There'd better be 2*(3+5) + 2*4 active elements on the
856 // multi-boundary
857 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(24),
858 _multi_boundary_mesh->n_active_elem());
859
860 // Plus the original 12 now-inactive elements
861 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(36),
862 _multi_boundary_mesh->n_elem());
863
864 // There'd better be 2*2*2*(3+5) + 2*2*4-1 nodes on the total boundary
865 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(50),
866 _multi_boundary_mesh->n_nodes());
867
868 this->sanityCheck();
869 }
870
872 {
873 LOG_UNIT_TEST;
874
875 MeshSerializer internal_serializer(*_internal_boundary_mesh);
876
877 // There'd better be 2*4 active elements on the internal
878 // sideset mesh
879 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(8),
880 _internal_boundary_mesh->n_active_elem());
881
882 // Plus the original 4 now-inactive elements
883 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12),
884 _internal_boundary_mesh->n_elem());
885
886 // There'd better be 2*2*4+1 nodes on the internal boundary
887 CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17),
888 _internal_boundary_mesh->n_nodes());
889
890 this->sanityCheck();
891 }
892
893};
894
896
897#endif
CPPUNIT_TEST(testMesh)
LIBMESH_CPPUNIT_TEST_SUITE(BoundaryMesh0DTest)
The goal of this test is to ensure that a 1D mesh generates boundary meshes correctly.
std::unique_ptr< UnstructuredMesh > _replicated_boundary_mesh
std::unique_ptr< UnstructuredMesh > _mesh
std::unique_ptr< UnstructuredMesh > _distributed_boundary_mesh
std::unique_ptr< UnstructuredMesh > _interior_node_mesh
void testBoundarySerialization()
CPPUNIT_TEST(testPerBoundarySubdomain)
CPPUNIT_TEST(testSingleSubdomain)
CPPUNIT_TEST(testDefaultSubdomain)
LIBMESH_CPPUNIT_TEST_SUITE(BoundaryMeshSubdomainTest)
Tests the new_subdomain_ids parameter of add_elements(), which assigns subdomain IDs to newly-created...
void sync_and_test_meshes()
CPPUNIT_TEST(testMesh)
void testBoundarySerialization()
std::unique_ptr< UnstructuredMesh > _multi_boundary_mesh
std::unique_ptr< UnstructuredMesh > _exterior_boundary_mesh
std::unique_ptr< UnstructuredMesh > _internal_boundary_mesh
CPPUNIT_TEST(testBoundarySerialization)
std::unique_ptr< UnstructuredMesh > _mesh
static constexpr boundary_id_type bid2
static constexpr boundary_id_type bid1
LIBMESH_CPPUNIT_TEST_SUITE(BoundaryMeshTest)
The goal of this test is to ensure that a 2D mesh generates boundary meshes correctly.
std::unique_ptr< UnstructuredMesh > _left_boundary_mesh
CPPUNIT_TEST(testBoundarySerialization)
LIBMESH_CPPUNIT_TEST_SUITE(BoundaryOfRefinedMeshTest)
The goal of this test is the same as the previous, but now we do a uniform refinement before synchron...
CPPUNIT_TEST(testBoundarySerialization)
LIBMESH_CPPUNIT_TEST_SUITE(BoundaryRefinedMeshTest)
The goal of this test is the same as the previous, but now we do a uniform refinement and make sure t...
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
void add_elements(const std::set< boundary_id_type > &requested_boundary_ids, UnstructuredMesh &boundary_mesh, bool store_parent_side_ids=false, const std::vector< subdomain_id_type > &new_subdomain_ids={})
Generates elements along the boundary of our _mesh, which use pre-existing nodes on the boundary_mesh...
boundary_id_type get_id_by_name(std::string_view name) const
const std::set< boundary_id_type > & get_side_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.
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual unsigned short dim() const =0
static const unsigned int type_to_dim_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the geometric dimension of the ele...
Definition elem.h:628
unsigned int level() const
Definition elem.h:3091
virtual ElemType type() const =0
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
unsigned int mesh_dimension() const
Definition mesh_base.C:430
void complete_preparation()
Definition mesh_base.C:874
unsigned int get_elem_integer_index(std::string_view name) const
Definition mesh_base.C:689
Implements (adaptive) mesh refinement algorithms for a MeshBase.
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
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
The UnstructuredMesh class is derived from the MeshBase class.
static const boundary_id_type left_id
static const boundary_id_type right_id
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.
The libMesh namespace provides an interface to certain functionality in the library.
ElemType
Defines an enum for geometric element types.
int8_t boundary_id_type
Definition id_types.h:51
const RemoteElem * remote_elem
Definition remote_elem.C:57
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const boundary_id_type top_id
CPPUNIT_TEST_SUITE_REGISTRATION(BoundaryMesh0DTest)