libMesh
Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
BoundaryRefinedMeshTest Class Reference
Inheritance diagram for BoundaryRefinedMeshTest:
[legend]

Public Member Functions

 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 the result mesh is consistent. More...
 
 CPPUNIT_TEST (testMesh)
 
 CPPUNIT_TEST_SUITE_END ()
 
void setUp ()
 
void testMesh ()
 
 LIBMESH_CPPUNIT_TEST_SUITE (BoundaryMeshTest)
 The goal of this test is to ensure that a 2D mesh generates boundary meshes correctly. More...
 
void sanityCheck ()
 

Protected Member Functions

void build_mesh ()
 

Protected Attributes

std::unique_ptr< Mesh_mesh
 
std::unique_ptr< Mesh_all_boundary_mesh
 
std::unique_ptr< Mesh_left_boundary_mesh
 
std::unique_ptr< Mesh_internal_boundary_mesh
 

Detailed Description

Definition at line 304 of file boundary_mesh.C.

Member Function Documentation

◆ build_mesh()

void BoundaryMeshTest::build_mesh ( )
inlineprotectedinherited

Definition at line 36 of file boundary_mesh.C.

References libMesh::BoundaryInfo::add_side(), libMesh::MeshTools::Generation::build_square(), and libMesh::QUAD9.

37  {
38  _mesh = std::make_unique<Mesh>(*TestCommWorld);
39  _all_boundary_mesh = std::make_unique<Mesh>(*TestCommWorld);
40  _left_boundary_mesh = std::make_unique<Mesh>(*TestCommWorld);
41  _internal_boundary_mesh = std::make_unique<Mesh>(*TestCommWorld);
42 
44  0.2, 0.8, 0.2, 0.7, QUAD9);
45 
46  // We'll need to skip most repartitioning with DistributedMesh for
47  // now; otherwise the boundary meshes' interior parents might get
48  // shuffled off to different processors.
49  if (!_mesh->is_serial())
50  {
51  _mesh->skip_noncritical_partitioning(true);
52  _left_boundary_mesh->skip_noncritical_partitioning(true);
53  _all_boundary_mesh->skip_noncritical_partitioning(true);
54  _internal_boundary_mesh->skip_noncritical_partitioning(true);
55  }
56 
57  // Set subdomain ids for specific elements. This allows us to later
58  // build an internal sideset with respect to a given
59  // subdomain. The element subdomains look like:
60  // ___________________
61  // | 2 | 2 | 2 |
62  // |_____|_____|_____|
63  // | 2 | 2 | 2 |
64  // |_____|_____|_____|
65  // | 2 | 2 | 2 |
66  // |_____|_____|_____|
67  // | 1 | 1 | 2 |
68  // |_____|_____|_____|
69  // | 1 | 1 | 2 |
70  // |_____|_____|_____|
71  //
72  // and we will create an internal sideset along the border between
73  // subdomains 1 and 2.
74 
75  for (auto & elem : _mesh->active_element_ptr_range())
76  {
77  const Point c = elem->vertex_average();
78  if (c(0) < 0.6 && c(1) < 0.4)
79  elem->subdomain_id() = 1;
80  else
81  elem->subdomain_id() = 2;
82  }
83 
84  // Get the border of the square
85  _mesh->get_boundary_info().sync(*_all_boundary_mesh);
86 
87  // Check that the interior_parent side indices that we set on the
88  // BoundaryMesh as extra integers agree with the side returned
89  // by which_side_am_i().
90  unsigned int parent_side_index_tag =
91  _all_boundary_mesh->get_elem_integer_index("parent_side_index");
92 
93  for (const auto & belem : _all_boundary_mesh->element_ptr_range())
94  {
95  dof_id_type parent_side_index =
96  belem->get_extra_integer(parent_side_index_tag);
97 
98  CPPUNIT_ASSERT_EQUAL
99  (static_cast<dof_id_type>(belem->interior_parent()->which_side_am_i(belem)),
100  parent_side_index);
101  }
102 
103  std::set<boundary_id_type> left_id, right_id;
104  left_id.insert(3);
105  right_id.insert(1);
106 
107  // Add the right side of the square to the square; this should
108  // make it a mixed dimension mesh. We skip storing the parent
109  // side ids (which is the default) since they are not needed
110  // in this particular test.
111  _mesh->get_boundary_info().add_elements
112  (right_id, *_mesh, /*store_parent_side_ids=*/false);
113  _mesh->prepare_for_use();
114 
115  // Add the left side of the square to its own boundary mesh.
116  _mesh->get_boundary_info().sync(left_id, *_left_boundary_mesh);
117 
118  // We create an internal sideset ID that does not conflict with
119  // sidesets 0-3 that get created by build_square().
120  boundary_id_type bid = 5;
121 
122  // To test the "relative to" feature, we add the same sides to the
123  // same sideset twice, from elements in subdomain 2 the second
124  // time. These should not show up in the BoundaryMesh, i.e. there
125  // should not be overlapped elems in the BoundaryMesh.
126  BoundaryInfo & bi = _mesh->get_boundary_info();
127 
128  for (auto & elem : _mesh->active_element_ptr_range())
129  {
130  const Point c = elem->vertex_average();
131  if (c(0) < 0.6 && c(1) < 0.4)
132  {
133  if (c(0) > 0.4)
134  bi.add_side(elem, 1, bid);
135  if (c(1) > 0.3)
136  bi.add_side(elem, 2, bid);
137  }
138  else
139  {
140  if (c(0) < 0.75 && c(1) < 0.4)
141  bi.add_side(elem, 3, bid);
142  if (c(0) < 0.6 && c(1) < 0.5)
143  bi.add_side(elem, 0, bid);
144  }
145  }
146 
147 
148  // Create a BoundaryMesh from the internal sideset relative to subdomain 1.
149  {
150  std::set<boundary_id_type> requested_boundary_ids;
151  requested_boundary_ids.insert(bid);
152  std::set<subdomain_id_type> subdomains_relative_to;
153  subdomains_relative_to.insert(1);
154  _mesh->get_boundary_info().sync(requested_boundary_ids,
156  subdomains_relative_to);
157  }
158  }
std::unique_ptr< Mesh > _internal_boundary_mesh
Definition: boundary_mesh.C:34
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.
std::unique_ptr< Mesh > _mesh
Definition: boundary_mesh.C:31
int8_t boundary_id_type
Definition: id_types.h:51
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
std::unique_ptr< Mesh > _left_boundary_mesh
Definition: boundary_mesh.C:33
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...
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
uint8_t dof_id_type
Definition: id_types.h:67
std::unique_ptr< Mesh > _all_boundary_mesh
Definition: boundary_mesh.C:32

◆ CPPUNIT_TEST()

BoundaryRefinedMeshTest::CPPUNIT_TEST ( testMesh  )

◆ CPPUNIT_TEST_SUITE_END()

BoundaryRefinedMeshTest::CPPUNIT_TEST_SUITE_END ( )

◆ LIBMESH_CPPUNIT_TEST_SUITE() [1/2]

BoundaryMeshTest::LIBMESH_CPPUNIT_TEST_SUITE ( BoundaryMeshTest  )
inherited

The goal of this test is to ensure that a 2D mesh generates boundary meshes correctly.

◆ LIBMESH_CPPUNIT_TEST_SUITE() [2/2]

BoundaryRefinedMeshTest::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 the result mesh is consistent.

i.e. the new node shared between the 1D elements is the same as the node shared on the underlying quads, and so on.

◆ sanityCheck()

void BoundaryMeshTest::sanityCheck ( )
inlineinherited

Definition at line 208 of file boundary_mesh.C.

References libMesh::Elem::dim(), libMesh::EDGE3, libMesh::Elem::interior_parent(), libMesh::Elem::level(), libMesh::QUAD9, TIMPI::Communicator::rank(), libMesh::remote_elem, TestCommWorld, libMesh::TOLERANCE, and libMesh::Elem::type().

209  {
210  // Sanity check all the elements
211  for (const auto & elem : _mesh->active_element_ptr_range())
212  {
213  const Elem * pip = elem->dim() < 2 ? elem->interior_parent() : nullptr;
214 
215  // On a DistributedMesh we might not be able to see the
216  // interior_parent of a non-local element
217  if (pip == remote_elem)
218  {
219  CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
220  continue;
221  }
222 
223  // All the edges should have interior parents; none of the
224  // quads should.
225  if (pip)
226  {
227  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
228  CPPUNIT_ASSERT_EQUAL(pip->type(), QUAD9);
229  CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
230 
231  // We only added right edges
232  LIBMESH_ASSERT_FP_EQUAL(0.8, elem->vertex_average()(0),
234  }
235  else
236  {
237  CPPUNIT_ASSERT_EQUAL(elem->type(), QUAD9);
238  }
239  }
240 
241  for (const auto & elem : _left_boundary_mesh->active_element_ptr_range())
242  {
243  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
244 
245  const Elem * pip = elem->interior_parent();
246 
247  // On a DistributedMesh we might not be able to see the
248  // interior_parent of a non-local element
249  if (pip == remote_elem)
250  {
251  CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
252  continue;
253  }
254 
255  // All the edges should have interior parents
256  CPPUNIT_ASSERT(pip);
257  CPPUNIT_ASSERT_EQUAL(pip->type(), QUAD9);
258  CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
259 
260  // We only added left edges
261  LIBMESH_ASSERT_FP_EQUAL(0.2, elem->vertex_average()(0),
263  }
264 
265  for (const auto & elem : _left_boundary_mesh->active_element_ptr_range())
266  {
267  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
268 
269  const Elem * pip = elem->interior_parent();
270 
271  // On a DistributedMesh we might not be able to see the
272  // interior_parent of a non-local element
273  if (pip == remote_elem)
274  {
275  CPPUNIT_ASSERT(elem->processor_id() != TestCommWorld->rank());
276  continue;
277  }
278 
279  // All the edges should have interior parents
280  CPPUNIT_ASSERT(pip);
281  CPPUNIT_ASSERT_EQUAL(pip->type(), QUAD9);
282  CPPUNIT_ASSERT_EQUAL(pip->level(), elem->level());
283  }
284 
285  // Sanity check for the internal sideset mesh.
286  for (const auto & elem : _internal_boundary_mesh->active_element_ptr_range())
287  {
288  CPPUNIT_ASSERT_EQUAL(elem->type(), EDGE3);
289 
290  // All of the elements in the internal sideset mesh should
291  // have the same subdomain id as the parent Elems (i.e. 1)
292  // they came from.
293  CPPUNIT_ASSERT_EQUAL(static_cast<subdomain_id_type>(1),
294  elem->subdomain_id());
295  }
296  }
std::unique_ptr< Mesh > _internal_boundary_mesh
Definition: boundary_mesh.C:34
const Elem * interior_parent() const
Definition: elem.C:994
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:159
static constexpr Real TOLERANCE
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
processor_id_type rank() const
std::unique_ptr< Mesh > _mesh
Definition: boundary_mesh.C:31
std::unique_ptr< Mesh > _left_boundary_mesh
Definition: boundary_mesh.C:33
unsigned int level() const
Definition: elem.h:2911
virtual unsigned short dim() const =0
virtual ElemType type() const =0
const RemoteElem * remote_elem
Definition: remote_elem.C:54

◆ setUp()

void BoundaryRefinedMeshTest::setUp ( )
inline

Definition at line 323 of file boundary_mesh.C.

References libMesh::MeshRefinement::uniformly_refine().

324  {
325 #if LIBMESH_DIM > 1
326  this->build_mesh();
327 
328  // Need to refine interior mesh before separate boundary meshes,
329  // if we want to get interior_parent links right.
330  MeshRefinement(*_mesh).uniformly_refine(1);
331  MeshRefinement(*_left_boundary_mesh).uniformly_refine(1);
332  MeshRefinement(*_all_boundary_mesh).uniformly_refine(1);
333 #endif
334  }
Implements (adaptive) mesh refinement algorithms for a MeshBase.
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.

◆ testMesh()

void BoundaryRefinedMeshTest::testMesh ( )
inline

Definition at line 336 of file boundary_mesh.C.

337  {
338  LOG_UNIT_TEST;
339 
340  // There'd better be 3*5*4 + 5*2 active elements in the interior
341  // plus right boundary
342  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(70),
343  _mesh->n_active_elem());
344 
345  // Plus the original 20 now-inactive elements
346  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(90),
347  _mesh->n_elem());
348 
349  // There'd better be only 13*21 nodes in the interior
350  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(273),
351  _mesh->n_nodes());
352 
353  // There'd better be only 2*2*(3+5) active elements on the full boundary
354  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(32),
355  _all_boundary_mesh->n_active_elem());
356 
357  // Plus the original 16 now-inactive elements
358  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(48),
359  _all_boundary_mesh->n_elem());
360 
361  // There'd better be only 2*2*2*(3+5) nodes on the full boundary
362  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(64),
363  _all_boundary_mesh->n_nodes());
364 
365  // There'd better be only 2*5 active elements on the left boundary
366  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(10),
367  _left_boundary_mesh->n_active_elem());
368 
369  // Plus the original 5 now-inactive elements
370  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(15),
371  _left_boundary_mesh->n_elem());
372 
373  // There'd better be only 2*2*5+1 nodes on the left boundary
374  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(21),
375  _left_boundary_mesh->n_nodes());
376 
377  this->sanityCheck();
378  }
std::unique_ptr< Mesh > _mesh
Definition: boundary_mesh.C:31
std::unique_ptr< Mesh > _left_boundary_mesh
Definition: boundary_mesh.C:33
std::unique_ptr< Mesh > _all_boundary_mesh
Definition: boundary_mesh.C:32

Member Data Documentation

◆ _all_boundary_mesh

std::unique_ptr<Mesh> BoundaryMeshTest::_all_boundary_mesh
protectedinherited

Definition at line 32 of file boundary_mesh.C.

◆ _internal_boundary_mesh

std::unique_ptr<Mesh> BoundaryMeshTest::_internal_boundary_mesh
protectedinherited

Definition at line 34 of file boundary_mesh.C.

◆ _left_boundary_mesh

std::unique_ptr<Mesh> BoundaryMeshTest::_left_boundary_mesh
protectedinherited

Definition at line 33 of file boundary_mesh.C.

◆ _mesh

std::unique_ptr<Mesh> BoundaryMeshTest::_mesh
protectedinherited

Definition at line 31 of file boundary_mesh.C.


The documentation for this class was generated from the following file: