libMesh
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 
12 #include "test_comm.h"
13 #include "libmesh_cppunit.h"
14 
15 
16 using namespace libMesh;
17 
18 class BoundaryInfoTest : public CppUnit::TestCase {
22 public:
23  CPPUNIT_TEST_SUITE( BoundaryInfoTest );
24 
25 #if LIBMESH_DIM > 1
26  CPPUNIT_TEST( testMesh );
27 # ifdef LIBMESH_ENABLE_DIRICHLET
28  CPPUNIT_TEST( testShellFaceConstraints );
29 # endif
30 #endif
31 #if LIBMESH_DIM > 2
32  CPPUNIT_TEST( testEdgeBoundaryConditions );
33 #endif
34 
35  CPPUNIT_TEST_SUITE_END();
36 
37 protected:
38 
39 public:
40  void setUp()
41  {
42  }
43 
44  void tearDown()
45  {
46  }
47 
48  void testMesh()
49  {
51 
53  2, 2,
54  0., 1.,
55  0., 1.,
56  QUAD4);
57 
59 
60  // Side lists should be cleared and refilled by each call
61 #ifdef LIBMESH_ENABLE_DEPRECATED
62  std::vector<dof_id_type> element_id_list;
63  std::vector<unsigned short int> side_list;
64  std::vector<boundary_id_type> bc_id_list;
65 #endif
66 
67  // build_square adds boundary_ids 0,1,2,3 for the bottom, right,
68  // top, and left sides, respectively.
69 
70  // On a ReplicatedMesh, we should see all 4 ids on each processor
71  if (mesh.is_serial())
72  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), bi.n_boundary_ids());
73 
74  // On any mesh, we should see each id on *some* processor
75  {
76  const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
77  for (boundary_id_type i = 0 ; i != 4; ++i)
78  {
79  bool has_bcid = bc_ids.count(i);
80  mesh.comm().max(has_bcid);
81  CPPUNIT_ASSERT(has_bcid);
82  }
83  }
84 
85  // Build the side list
86 #ifdef LIBMESH_ENABLE_DEPRECATED
87  bi.build_side_list (element_id_list, side_list, bc_id_list);
88 #endif
89 
90  // Test that the new vector-of-tuples API works equivalently.
91  auto bc_triples = bi.build_side_list();
92 
93  // Check that there are exactly 8 sides in the BoundaryInfo for a
94  // replicated mesh
95  if (mesh.is_serial())
96  {
97 #ifdef LIBMESH_ENABLE_DEPRECATED
98  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), element_id_list.size());
99 #endif
100  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), bc_triples.size());
101  }
102 
103  // Let's test that we can remove them successfully.
104  bi.remove_id(0);
105 
106  // Check that there are now only 3 boundary ids total on the Mesh.
107  if (mesh.is_serial())
108  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
109 
110  {
111  const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
112  CPPUNIT_ASSERT(!bc_ids.count(0));
113  for (boundary_id_type i = 1 ; i != 4; ++i)
114  {
115  bool has_bcid = bc_ids.count(i);
116  mesh.comm().max(has_bcid);
117  CPPUNIT_ASSERT(has_bcid);
118  }
119  }
120 
121  // Build the side list again
122 #ifdef LIBMESH_ENABLE_DEPRECATED
123  bi.build_side_list (element_id_list, side_list, bc_id_list);
124 #endif
125  bc_triples = bi.build_side_list();
126 
127  // Check that there are now exactly 6 sides left in the
128  // BoundaryInfo on a replicated mesh
129  if (mesh.is_serial())
130  {
131 #ifdef LIBMESH_ENABLE_DEPRECATED
132  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), element_id_list.size());
133 #endif
134  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), bc_triples.size());
135  }
136 
137  // Check that the removed ID is really removed
138 #ifdef LIBMESH_ENABLE_DEPRECATED
139  CPPUNIT_ASSERT(std::find(bc_id_list.begin(), bc_id_list.end(), 0) == bc_id_list.end());
140 #endif
141  typedef std::tuple<dof_id_type, unsigned short int, boundary_id_type> Tuple;
142  CPPUNIT_ASSERT(std::find_if(bc_triples.begin(), bc_triples.end(),
143  [](const Tuple & t)->bool { 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 #ifdef LIBMESH_ENABLE_DEPRECATED
157  bi.build_side_list (element_id_list, side_list, bc_id_list);
158 #endif
159  bc_triples = bi.build_side_list();
160 
161  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_boundary_ids());
162 #ifdef LIBMESH_ENABLE_DEPRECATED
163  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), element_id_list.size());
164 #endif
165  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bc_triples.size());
166  }
167 
169  {
170  const unsigned int n_elem = 5;
171  const std::string mesh_filename = "cube_mesh.xda";
172 
173  {
176  n_elem, n_elem, n_elem,
177  0., 1.,
178  0., 1.,
179  0., 1.,
180  HEX8);
181 
183 
184  // build_cube does not add any edge boundary IDs
185  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_edge_conds());
186 
187  // Let's now add some edge boundary IDs.
188  // We loop over all elements (not just local elements) so that
189  // all processors know about the boundary IDs
190  const boundary_id_type BOUNDARY_ID_MAX_X = 2;
191  const boundary_id_type BOUNDARY_ID_MIN_Y = 1;
192  const boundary_id_type EDGE_BOUNDARY_ID = 20;
193 
194  for (const auto & elem : mesh.element_ptr_range())
195  {
196  unsigned short side_max_x = 0, side_min_y = 0;
197  bool found_side_max_x = false, found_side_min_y = false;
198 
199  for (unsigned short side=0; side<elem->n_sides(); side++)
200  {
201  if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MAX_X))
202  {
203  side_max_x = side;
204  found_side_max_x = true;
205  }
206 
207  if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MIN_Y))
208  {
209  side_min_y = side;
210  found_side_min_y = true;
211  }
212  }
213 
214  // If elem has sides on boundaries
215  // BOUNDARY_ID_MAX_X and BOUNDARY_ID_MIN_Y
216  // then let's set an edge boundary condition
217  if (found_side_max_x && found_side_min_y)
218  for (unsigned short e=0; e<elem->n_edges(); e++)
219  if (elem->is_edge_on_side(e, side_max_x) &&
220  elem->is_edge_on_side(e, side_min_y))
221  bi.add_edge(elem, e, EDGE_BOUNDARY_ID);
222  }
223 
224  // Check that we have the expected number of edge boundary IDs after
225  // updating bi
226  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
227 
228  mesh.write(mesh_filename);
229  }
230 
231  // Make sure all processors are done writing before we try to
232  // start reading
233  TestCommWorld->barrier();
234 
236  mesh.read(mesh_filename);
237 
238  // Check that writing and reading preserves the edge boundary IDs
240  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
241  }
242 
243 #ifdef LIBMESH_ENABLE_DIRICHLET
245  {
246  // Make a simple two element mesh that we can use to test constraints
248 
249  // (0,1) (1,1)
250  // x---------------x
251  // | |
252  // | |
253  // | |
254  // | |
255  // | |
256  // x---------------x
257  // (0,0) (1,0)
258  // | |
259  // | |
260  // | |
261  // | |
262  // x---------------x
263  // (0,-1) (1,-1)
264 
265  mesh.add_point( Point(0.0,-1.0), 4 );
266  mesh.add_point( Point(1.0,-1.0), 5 );
267  mesh.add_point( Point(1.0, 0.0), 1 );
268  mesh.add_point( Point(1.0, 1.0), 2 );
269  mesh.add_point( Point(0.0, 1.0), 3 );
270  mesh.add_point( Point(0.0, 0.0), 0 );
271 
272  Elem* elem_top = mesh.add_elem( new QuadShell4 );
273  elem_top->set_node(0) = mesh.node_ptr(0);
274  elem_top->set_node(1) = mesh.node_ptr(1);
275  elem_top->set_node(2) = mesh.node_ptr(2);
276  elem_top->set_node(3) = mesh.node_ptr(3);
277 
278  Elem* elem_bottom = mesh.add_elem( new QuadShell4 );
279  elem_bottom->set_node(0) = mesh.node_ptr(4);
280  elem_bottom->set_node(1) = mesh.node_ptr(5);
281  elem_bottom->set_node(2) = mesh.node_ptr(1);
282  elem_bottom->set_node(3) = mesh.node_ptr(0);
283 
285  bi.add_shellface(elem_top, 0, 10);
286  bi.add_shellface(elem_bottom, 1, 20);
287 
288  mesh.prepare_for_use(false /*skip_renumber*/);
289 
290  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), bi.n_shellface_conds());
291 
292  EquationSystems es(mesh);
293  System & system = es.add_system<System> ("SimpleSystem");
294  system.add_variable("u", FIRST);
295 
296  // Add a Dirichlet constraint to check that we impose constraints
297  // correctly on shell faces.
298  std::vector<unsigned int> variables;
299  variables.push_back(0);
300  std::set<boundary_id_type> shellface_ids;
301  shellface_ids.insert(20);
302  ZeroFunction<> zf;
303  DirichletBoundary dirichlet_bc(shellface_ids,
304  variables,
305  &zf);
306  system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
307  es.init();
308 
309  // Find elem_bottom again if we have it (it may have been deleted
310  // in a DistributedMesh or renumbered in theory)
311  elem_bottom = nullptr;
312  for (unsigned int e = 0; e != mesh.max_elem_id(); ++e)
313  {
314  Elem *elem = mesh.query_elem_ptr(e);
315  if (elem && elem->point(3) == Point(0,0))
316  elem_bottom = elem;
317  }
318 
319  // We expect to have a dof constraint on all four dofs of
320  // elem_bottom
321  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), static_cast<std::size_t>(system.n_constrained_dofs()));
322 
323  // But we may only know the details of that
324  // constraint on the processor which owns elem_bottom.
325  if (elem_bottom &&
326  elem_bottom->processor_id() == mesh.processor_id())
327  {
328  std::vector<dof_id_type> dof_indices;
329  system.get_dof_map().dof_indices(elem_bottom, dof_indices);
330  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), dof_indices.size());
331 
332  for(unsigned int i=0; i<dof_indices.size(); i++)
333  {
334  dof_id_type dof_id = dof_indices[i];
335  CPPUNIT_ASSERT( system.get_dof_map().is_constrained_dof(dof_id) );
336  }
337  }
338  }
339 #endif // LIBMESH_ENABLE_DIRICHLET
340 
341 };
342 
libMesh::System
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:100
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::BoundaryInfo::remove_id
void remove_id(boundary_id_type id)
Removes all entities (nodes, sides, edges, shellfaces) with boundary id id from their respective cont...
Definition: boundary_info.C:1492
libMesh::BoundaryInfo
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Definition: boundary_info.h:57
libMesh::Mesh
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
libMesh::MeshTools::n_elem
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:705
libMesh::MeshBase::read
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false)=0
Interfaces for reading/writing a mesh to/from a file.
libMesh::MeshBase::get_boundary_info
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:132
libMesh::DofMap::dof_indices
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Fills the vector di with the global degree of freedom indices for the element.
Definition: dof_map.C:1967
libMesh::MeshBase::is_serial
virtual bool is_serial() const
Definition: mesh_base.h:159
libMesh::DofMap::add_dirichlet_boundary
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
Definition: dof_map_constraints.C:4390
libMesh::HEX8
Definition: enum_elem_type.h:47
libMesh::MeshBase::write
virtual void write(const std::string &name)=0
libMesh::MeshBase::max_elem_id
virtual dof_id_type max_elem_id() const =0
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
BoundaryInfoTest
Definition: boundary_info.C:18
libMesh::MeshTools::Generation::build_cube
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.
Definition: mesh_generation.C:298
BoundaryInfoTest::tearDown
void tearDown()
Definition: boundary_info.C:44
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::BoundaryInfo::n_shellface_conds
std::size_t n_shellface_conds() const
Definition: boundary_info.C:1658
libMesh::BoundaryInfo::n_edge_conds
std::size_t n_edge_conds() const
Definition: boundary_info.C:1636
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::MeshBase::node_ptr
virtual const Node * node_ptr(const dof_id_type i) const =0
libMesh::DofMap::is_constrained_dof
bool is_constrained_dof(const dof_id_type dof) const
Definition: dof_map.h:1962
libMesh::boundary_id_type
int8_t boundary_id_type
Definition: id_types.h:51
libMesh::DofObject::processor_id
processor_id_type processor_id() const
Definition: dof_object.h:829
libMesh::Elem::point
const Point & point(const unsigned int i) const
Definition: elem.h:1955
libMesh::MeshBase::query_elem_ptr
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
libMesh::BoundaryInfo::build_side_list
void build_side_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &side_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of element numbers, sides, and ids for those sides.
Definition: boundary_info.C:1976
libMesh::BoundaryInfo::get_boundary_ids
const std::set< boundary_id_type > & get_boundary_ids() const
Definition: boundary_info.h:787
libMesh::MeshBase::element_ptr_range
virtual SimpleRange< element_iterator > element_ptr_range()=0
BoundaryInfoTest::testMesh
void testMesh()
Definition: boundary_info.C:48
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
BoundaryInfoTest::testEdgeBoundaryConditions
void testEdgeBoundaryConditions()
Definition: boundary_info.C:168
BoundaryInfoTest::testShellFaceConstraints
void testShellFaceConstraints()
Definition: boundary_info.C:244
libMesh::ParallelObject::processor_id
processor_id_type processor_id() const
Definition: parallel_object.h:106
libMesh::System::add_variable
unsigned int add_variable(const std::string &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:1069
libMesh::QUAD4
Definition: enum_elem_type.h:41
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
libMesh::BoundaryInfo::n_boundary_ids
std::size_t n_boundary_ids() const
Definition: boundary_info.h:360
BoundaryInfoTest::setUp
void setUp()
Definition: boundary_info.C:40
libMesh::ZeroFunction
ConstFunction that simply returns 0.
Definition: zero_function.h:36
libMesh::EquationSystems
This is the EquationSystems class.
Definition: equation_systems.h:74
libMesh::Elem::set_node
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2059
libMesh::MeshBase::add_elem
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
libmesh_cppunit.h
libMesh::BoundaryInfo::add_edge
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.
Definition: boundary_info.C:707
libMesh::System::n_constrained_dofs
dof_id_type n_constrained_dofs() const
Definition: system.C:157
libMesh::DirichletBoundary
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
Definition: dirichlet_boundaries.h:88
CPPUNIT_TEST_SUITE_REGISTRATION
CPPUNIT_TEST_SUITE_REGISTRATION(BoundaryInfoTest)
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::System::get_dof_map
const DofMap & get_dof_map() const
Definition: system.h:2099
libMesh::BoundaryInfo::add_shellface
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 ...
Definition: boundary_info.C:794
libMesh::MeshBase::add_point
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.
test_comm.h
libMesh::MeshBase::prepare_for_use
void prepare_for_use(const bool skip_renumber_nodes_and_elements=false, const bool skip_find_neighbors=false)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:318
libMesh::BoundaryInfo::has_boundary_id
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
Definition: boundary_info.C:972
libMesh::FIRST
Definition: enum_order.h:42
libMesh::QuadShell4
QuadShell4 is almost identical to Quad4.
Definition: face_quad4_shell.h:36