libMesh
boundary_mesh.C
Go to the documentation of this file.
1 #include <libmesh/mesh.h>
2 #include <libmesh/mesh_generation.h>
3 #include <libmesh/mesh_refinement.h>
4 #include <libmesh/remote_elem.h>
5 #include <libmesh/replicated_mesh.h>
6 #include <libmesh/auto_ptr.h> // libmesh_make_unique
7 
8 #include "test_comm.h"
9 #include "libmesh_cppunit.h"
10 
11 
12 using namespace libMesh;
13 
14 class BoundaryMeshTest : public CppUnit::TestCase {
19 public:
20  CPPUNIT_TEST_SUITE( BoundaryMeshTest );
21 
22 #if LIBMESH_DIM > 1
23  CPPUNIT_TEST( testMesh );
24 #endif
25 
26  CPPUNIT_TEST_SUITE_END();
27 
28 protected:
29 
30  std::unique_ptr<Mesh> _mesh;
31  std::unique_ptr<Mesh> _all_boundary_mesh;
32  std::unique_ptr<Mesh> _left_boundary_mesh;
33  std::unique_ptr<Mesh> _internal_boundary_mesh;
34 
35  void build_mesh()
36  {
37  _mesh = libmesh_make_unique<Mesh>(*TestCommWorld);
38  _all_boundary_mesh = libmesh_make_unique<Mesh>(*TestCommWorld);
39  _left_boundary_mesh = libmesh_make_unique<Mesh>(*TestCommWorld);
40  _internal_boundary_mesh = libmesh_make_unique<Mesh>(*TestCommWorld);
41 
43  0.2, 0.8, 0.2, 0.7, QUAD9);
44 
45  // We'll need to skip most repartitioning with DistributedMesh for
46  // now; otherwise the boundary meshes' interior parents might get
47  // shuffled off to different processors.
48  if (!_mesh->is_serial())
49  {
50  _mesh->skip_noncritical_partitioning(true);
51  _left_boundary_mesh->skip_noncritical_partitioning(true);
52  _all_boundary_mesh->skip_noncritical_partitioning(true);
53  _internal_boundary_mesh->skip_noncritical_partitioning(true);
54  }
55 
56  // Set subdomain ids for specific elements. This allows us to later
57  // build an internal sideset with respect to a given
58  // subdomain. The element subdomains look like:
59  // ___________________
60  // | 2 | 2 | 2 |
61  // |_____|_____|_____|
62  // | 2 | 2 | 2 |
63  // |_____|_____|_____|
64  // | 2 | 2 | 2 |
65  // |_____|_____|_____|
66  // | 1 | 1 | 2 |
67  // |_____|_____|_____|
68  // | 1 | 1 | 2 |
69  // |_____|_____|_____|
70  //
71  // and we will create an internal sideset along the border between
72  // subdomains 1 and 2.
73 
74  for (auto & elem : _mesh->active_element_ptr_range())
75  {
76  const Point c = elem->centroid();
77  if (c(0) < 0.6 && c(1) < 0.4)
78  elem->subdomain_id() = 1;
79  else
80  elem->subdomain_id() = 2;
81  }
82 
83  // Get the border of the square
84  _mesh->get_boundary_info().sync(*_all_boundary_mesh);
85 
86  std::set<boundary_id_type> left_id, right_id;
87  left_id.insert(3);
88  right_id.insert(1);
89 
90  // Add the right side of the square to the square; this should
91  // make it a mixed dimension mesh
92  _mesh->get_boundary_info().add_elements(right_id, *_mesh);
93  _mesh->prepare_for_use();
94 
95  // Add the left side of the square to its own boundary mesh.
96  _mesh->get_boundary_info().sync(left_id, *_left_boundary_mesh);
97 
98  // We create an internal sideset ID that does not conflict with
99  // sidesets 0-3 that get created by build_square().
100  boundary_id_type bid = 5;
101 
102  // To test the "relative to" feature, we add the same sides to the
103  // same sideset twice, from elements in subdomain 2 the second
104  // time. These should not show up in the BoundaryMesh, i.e. there
105  // should not be overlapped elems in the BoundaryMesh.
106  BoundaryInfo & bi = _mesh->get_boundary_info();
107 
108  for (auto & elem : _mesh->active_element_ptr_range())
109  {
110  const Point c = elem->centroid();
111  if (c(0) < 0.6 && c(1) < 0.4)
112  {
113  if (c(0) > 0.4)
114  bi.add_side(elem, 1, bid);
115  if (c(1) > 0.3)
116  bi.add_side(elem, 2, bid);
117  }
118  else
119  {
120  if (c(0) < 0.75 && c(1) < 0.4)
121  bi.add_side(elem, 3, bid);
122  if (c(0) < 0.6 && c(1) < 0.5)
123  bi.add_side(elem, 0, bid);
124  }
125  }
126 
127 
128  // Create a BoundaryMesh from the internal sideset relative to subdomain 1.
129  {
130  std::set<boundary_id_type> requested_boundary_ids;
131  requested_boundary_ids.insert(bid);
132  std::set<subdomain_id_type> subdomains_relative_to;
133  subdomains_relative_to.insert(1);
134  _mesh->get_boundary_info().sync(requested_boundary_ids,
135  *_internal_boundary_mesh,
136  subdomains_relative_to);
137  }
138  }
139 
140 public:
141  void setUp()
142  {
143 #if LIBMESH_DIM > 1
144  this->build_mesh();
145 #endif
146  }
147 
148  void testMesh()
149  {
150  // There'd better be 3*5 + 5 elements in the interior plus right
151  // boundary
152  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(20),
153  _mesh->n_elem());
154 
155  // There'd better be only 7*11 nodes in the interior
156  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(77),
157  _mesh->n_nodes());
158 
159  // There'd better be only 2*(3+5) elements on the full boundary
160  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(16),
161  _all_boundary_mesh->n_elem());
162 
163  // There'd better be only 2*2*(3+5) nodes on the full boundary
164  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
165  _all_boundary_mesh->n_nodes());
166 
167  // There'd better be only 5 elements on the left boundary
168  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(5),
169  _left_boundary_mesh->n_elem());
170 
171  // There'd better be only 2*5+1 nodes on the left boundary
172  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(11),
173  _left_boundary_mesh->n_nodes());
174 
175  // There are only four elements in the internal sideset mesh.
176  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4),
177  _internal_boundary_mesh->n_elem());
178 
179  // There are 2*n_elem + 1 nodes in the internal sideset mesh.
180  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(9),
181  _internal_boundary_mesh->n_nodes());
182 
183  this->sanityCheck();
184  }
185 
186  void sanityCheck()
187  {
188  // Sanity check all the elements
189  for (const auto & elem : _mesh->active_element_ptr_range())
190  {
191  const Elem * pip = elem->dim() < 2 ? elem->interior_parent() : nullptr;
192 
193  // On a DistributedMesh we might not be able to see the
194  // interior_parent of a non-local element
195  if (pip == remote_elem)
196  {
197  CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
198  continue;
199  }
200 
201  // All the edges should have interior parents; none of the
202  // quads should.
203  if (pip)
204  {
205  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
206  CPPUNIT_ASSERT_EQUAL(pip->type(), QUAD9);
207  CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
208 
209  // We only added right edges
210  LIBMESH_ASSERT_FP_EQUAL(elem->centroid()(0), 0.8,
212  }
213  else
214  {
215  CPPUNIT_ASSERT_EQUAL(elem->type(), QUAD9);
216  }
217  }
218 
219  for (const auto & elem : _left_boundary_mesh->active_element_ptr_range())
220  {
221  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
222 
223  const Elem * pip = elem->interior_parent();
224 
225  // On a DistributedMesh we might not be able to see the
226  // interior_parent of a non-local element
227  if (pip == remote_elem)
228  {
229  CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
230  continue;
231  }
232 
233  // All the edges should have interior parents
234  CPPUNIT_ASSERT(pip);
235  CPPUNIT_ASSERT_EQUAL(pip->type(), QUAD9);
236  CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
237 
238  // We only added left edges
239  LIBMESH_ASSERT_FP_EQUAL(elem->centroid()(0), 0.2,
241  }
242 
243  for (const auto & elem : _left_boundary_mesh->active_element_ptr_range())
244  {
245  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
246 
247  const Elem * pip = elem->interior_parent();
248 
249  // On a DistributedMesh we might not be able to see the
250  // interior_parent of a non-local element
251  if (pip == remote_elem)
252  {
253  CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
254  continue;
255  }
256 
257  // All the edges should have interior parents
258  CPPUNIT_ASSERT(pip);
259  CPPUNIT_ASSERT_EQUAL(pip->type(), QUAD9);
260  CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
261  }
262 
263  // Sanity check for the internal sideset mesh.
264  for (const auto & elem : _internal_boundary_mesh->active_element_ptr_range())
265  {
266  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
267 
268  // All of the elements in the internal sideset mesh should
269  // have the same subdomain id as the parent Elems (i.e. 1)
270  // they came from.
271  CPPUNIT_ASSERT_EQUAL(static_cast<subdomain_id_type>(1),
272  elem->subdomain_id());
273  }
274  }
275 
276 };
277 
279 
280 #ifdef LIBMESH_ENABLE_AMR
281 
289 public:
290  CPPUNIT_TEST_SUITE( BoundaryRefinedMeshTest );
291 
292 #if LIBMESH_DIM > 1
293  CPPUNIT_TEST( testMesh );
294 #endif
295 
296  CPPUNIT_TEST_SUITE_END();
297 
298  // Yes, this is necessary. Somewhere in those macros is a protected/private
299 public:
300 
301  void setUp()
302  {
303 #if LIBMESH_DIM > 1
304  this->build_mesh();
305 
306  // Need to refine interior mesh before separate boundary meshes,
307  // if we want to get interior_parent links right.
308  MeshRefinement(*_mesh).uniformly_refine(1);
309  MeshRefinement(*_left_boundary_mesh).uniformly_refine(1);
310  MeshRefinement(*_all_boundary_mesh).uniformly_refine(1);
311 #endif
312  }
313 
314  void testMesh()
315  {
316  // There'd better be 3*5*4 + 5*2 active elements in the interior
317  // plus right boundary
318  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(70),
319  _mesh->n_active_elem());
320 
321  // Plus the original 20 now-inactive elements
322  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(90),
323  _mesh->n_elem());
324 
325  // There'd better be only 13*21 nodes in the interior
326  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(273),
327  _mesh->n_nodes());
328 
329  // There'd better be only 2*2*(3+5) active elements on the full boundary
330  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
331  _all_boundary_mesh->n_active_elem());
332 
333  // Plus the original 16 now-inactive elements
334  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(48),
335  _all_boundary_mesh->n_elem());
336 
337  // There'd better be only 2*2*2*(3+5) nodes on the full boundary
338  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(64),
339  _all_boundary_mesh->n_nodes());
340 
341  // There'd better be only 2*5 active elements on the left boundary
342  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(10),
343  _left_boundary_mesh->n_active_elem());
344 
345  // Plus the original 5 now-inactive elements
346  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(15),
347  _left_boundary_mesh->n_elem());
348 
349  // There'd better be only 2*2*5+1 nodes on the left boundary
350  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(21),
351  _left_boundary_mesh->n_nodes());
352 
353  this->sanityCheck();
354  }
355 
356 };
357 
359 
360 #endif
libMesh::BoundaryInfo
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Definition: boundary_info.h:57
libMesh::Elem::level
unsigned int level() const
Definition: elem.h:2478
BoundaryMeshTest::build_mesh
void build_mesh()
Definition: boundary_mesh.C:35
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::Elem::dim
virtual unsigned short dim() const =0
libMesh::TOLERANCE
static const Real TOLERANCE
Definition: libmesh_common.h:128
libMesh::boundary_id_type
int8_t boundary_id_type
Definition: id_types.h:51
BoundaryMeshTest::testMesh
void testMesh()
Definition: boundary_mesh.C:148
libMesh::MeshRefinement
Implements (adaptive) mesh refinement algorithms for a MeshBase.
Definition: mesh_refinement.h:61
libMesh::MeshTools::Generation::build_square
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.
Definition: mesh_generation.C:1501
BoundaryRefinedMeshTest
Definition: boundary_mesh.C:282
BoundaryMeshTest::_mesh
std::unique_ptr< Mesh > _mesh
Definition: boundary_mesh.C:30
BoundaryMeshTest::_left_boundary_mesh
std::unique_ptr< Mesh > _left_boundary_mesh
Definition: boundary_mesh.C:32
TestCommWorld
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:111
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
BoundaryRefinedMeshTest::testMesh
void testMesh()
Definition: boundary_mesh.C:314
BoundaryMeshTest::_all_boundary_mesh
std::unique_ptr< Mesh > _all_boundary_mesh
Definition: boundary_mesh.C:31
BoundaryMeshTest
Definition: boundary_mesh.C:14
libMesh::Elem::interior_parent
const Elem * interior_parent() const
Definition: elem.C:749
BoundaryMeshTest::setUp
void setUp()
Definition: boundary_mesh.C:141
libmesh_cppunit.h
libMesh::EDGE3
Definition: enum_elem_type.h:36
BoundaryRefinedMeshTest::setUp
void setUp()
Definition: boundary_mesh.C:301
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
BoundaryMeshTest::sanityCheck
void sanityCheck()
Definition: boundary_mesh.C:186
libMesh::QUAD9
Definition: enum_elem_type.h:43
test_comm.h
BoundaryMeshTest::_internal_boundary_mesh
std::unique_ptr< Mesh > _internal_boundary_mesh
Definition: boundary_mesh.C:33
libMesh::MeshRefinement::uniformly_refine
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.
Definition: mesh_refinement.C:1678
libMesh::BoundaryInfo::add_side
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.
Definition: boundary_info.C:886
libMesh::Elem::type
virtual ElemType type() const =0
libMesh::remote_elem
const RemoteElem * remote_elem
Definition: remote_elem.C:57
CPPUNIT_TEST_SUITE_REGISTRATION
CPPUNIT_TEST_SUITE_REGISTRATION(BoundaryMeshTest)