libMesh
nodal_neighbors.C
Go to the documentation of this file.
1 #include <libmesh/libmesh.h>
2 #include <libmesh/node.h>
3 #include <libmesh/mesh_generation.h>
4 #include <libmesh/mesh_tools.h>
5 #include <libmesh/replicated_mesh.h>
6 #include <libmesh/elem.h>
7 
8 #include "test_comm.h"
9 #include "libmesh_cppunit.h"
10 
11 
12 using namespace libMesh;
13 
14 class NodalNeighborsTest : public CppUnit::TestCase
15 {
33 public:
34  LIBMESH_CPPUNIT_TEST_SUITE( NodalNeighborsTest );
35 
36  CPPUNIT_TEST( testEdge2 );
37  CPPUNIT_TEST( testEdge3 );
38  CPPUNIT_TEST( testEdge4 );
39  CPPUNIT_TEST( testOrientation );
40 
41  CPPUNIT_TEST_SUITE_END();
42 
43 protected:
44 
45  // Builds a 1D mesh with the specified ElemType and number of elements
46  void do_test(unsigned n_elem,
47  ElemType elem_type,
48  dof_id_type * validation_data)
49  {
50  ReplicatedMesh mesh(*TestCommWorld, /*dim=*/1);
51 
53  n_elem,
54  /*xmin=*/0.,
55  /*xmax=*/1.,
56  elem_type);
57 
58  // find_nodal_neighbors() needs a data structure which is prepared by another function
59  std::vector<std::vector<const Elem *>> nodes_to_elem_map;
60  MeshTools::build_nodes_to_elem_map(mesh, nodes_to_elem_map);
61 
62  // Loop over the nodes and call find_nodal_neighbors()
63  {
64  std::vector<const Node*> neighbor_nodes;
65 
66  unsigned ctr = 0;
67  for (const auto & node : mesh.node_ptr_range())
68  {
69  MeshTools::find_nodal_neighbors(mesh, *node, nodes_to_elem_map, neighbor_nodes);
70 
71  // The entries in neighbor_nodes are just sorted according
72  // to memory address, which is somewhat arbitrary, so create
73  // a vector sorted by IDs for test purposes.
74  std::vector<dof_id_type> neighbor_node_ids(neighbor_nodes.size());
75  for (std::size_t i=0; i<neighbor_nodes.size(); ++i)
76  neighbor_node_ids[i] = neighbor_nodes[i]->id();
77  std::sort(neighbor_node_ids.begin(), neighbor_node_ids.end());
78 
79  // Compare to validation_data
80  for (std::size_t j=0; j<neighbor_node_ids.size(); ++j)
81  {
82  CPPUNIT_ASSERT_EQUAL( validation_data[2*ctr + j], neighbor_node_ids[j] );
83  }
84 
85  ++ctr;
86  }
87  }
88  }
89 
90 public:
91  void setUp() {}
92 
93  void tearDown() {}
94 
95  void testEdge2()
96  {
97  LOG_UNIT_TEST;
98 
99  // 11 nodes, 2 neighbor entries per node
100  dof_id_type validation_data[22] =
101  {
103  0, 2,
104  1, 3,
105  2, 4,
106  3, 5,
107  4, 6,
108  5, 7,
109  6, 8,
110  7, 9,
111  8, 10,
113  };
114 
115  do_test(/*n_elem=*/10, EDGE2, validation_data);
116  }
117 
118 
119  void testEdge3()
120  {
121  LOG_UNIT_TEST;
122 
123  // 11 nodes, 2 neighbor entries per node
124  dof_id_type validation_data[22] =
125  {
127  2, 4,
128  0, 1,
129  4, 6,
130  1, 3,
131  6, 8,
132  3, 5,
133  8, 10,
134  5, 7,
136  7, 9
137  };
138 
139  do_test(/*n_elem=*/5, EDGE3, validation_data);
140  }
141 
142 
143  void testEdge4()
144  {
145  LOG_UNIT_TEST;
146 
147  // 10 nodes, 2 neighbor entries per node
148  dof_id_type validation_data[20] =
149  {
151  3, 5,
152  0, 3,
153  1, 2,
154  6, 8,
155  1, 6,
156  4, 5,
158  4, 9,
159  7, 8
160  };
161 
162  do_test(/*n_elem=*/3, EDGE4, validation_data);
163  }
164 
166  {
167  LOG_UNIT_TEST;
168 
170 
171  // The (1-based) node numbering and element orientation (represented
172  // by arrows) for this mesh:
173  // 1 -> 3 -> 4 -> 7 -> 8 <- 6 <- 5 <- 2
174  // So the two elements that meet at node 8 have opposite orientation
175  // and were not detected as neighbors using the original (before the
176  // addition of this test) find_neighbors() algorithm.
177 
178  // These nodes are copied from an exo file where we originally
179  // noticed the problem, but otherwise are not significant to the
180  // test. Note: the actual ids are 0-based but we are using a
181  // 1-based connectivity array below which is copied from the exo
182  // file.
183  mesh.add_point(Point(1.68, -1.695, 8.298), /*id=*/0);
184  mesh.add_point(Point(5.55, -1.695, 8.298), /*id=*/1);
185  mesh.add_point(Point(1.68, -0.175, 8.298), /*id=*/2);
186  mesh.add_point(Point(1.68, -0.175, 9.643), /*id=*/3);
187  mesh.add_point(Point(5.55, -0.175, 8.298), /*id=*/4);
188  mesh.add_point(Point(5.55, -0.175, 9.643), /*id=*/5);
189  mesh.add_point(Point(1.68, -0.075, 9.643), /*id=*/6);
190  mesh.add_point(Point(5.55, -0.075, 9.643), /*id=*/7);
191 
192  // 1-based connectivity array (2 nodes per Elem) copied directly
193  // from exo file. We will convert these to 0-based ids when they
194  // are used.
195  std::vector<unsigned int> conn =
196  {
197  7, 8,
198  1, 3,
199  2, 5,
200  3, 4,
201  5, 6,
202  4, 7,
203  6, 8
204  };
205 
206  // Add 7 EDGE2 elements and assign connectivity
207  for (unsigned int e=0; e<7; ++e)
208  {
210  elem->set_node(0, mesh.node_ptr(conn[2*e] - 1)); // convert to 0-based index
211  elem->set_node(1, mesh.node_ptr(conn[2*e + 1] - 1)); // convert to 0-based index
212  }
213 
214  // Find neighbors, etc.
216 
217  for (const auto & elem : mesh.element_ptr_range())
218  {
219  auto elem_id = elem->id();
220 
221  // Elems 1, 2 should have no neighbor on side 0
222  if (elem_id == 1 || elem_id == 2)
223  {
224  CPPUNIT_ASSERT(elem->neighbor_ptr(0) == nullptr);
225  CPPUNIT_ASSERT(elem->neighbor_ptr(1) != nullptr);
226  }
227  // Otherwise, elem should have neighbor on both sides
228  else
229  {
230  CPPUNIT_ASSERT(elem->neighbor_ptr(0) != nullptr);
231  CPPUNIT_ASSERT(elem->neighbor_ptr(1) != nullptr);
232  }
233 
234  // Debugging
235  // libMesh::out << "elem " << elem_id << std::endl;
236  // for (auto side_idx : make_range(elem->n_sides()))
237  // {
238  // if (elem->neighbor_ptr(side_idx))
239  // libMesh::out << "Neighbor on side " << side_idx << std::endl;
240  // else
241  // libMesh::out << "No neighbor on side " << side_idx << std::endl;
242  // }
243  }
244  }
245 };
246 
247 
ElemType
Defines an enum for geometric element types.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2558
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:969
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:759
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
void find_nodal_neighbors(const MeshBase &mesh, const Node &n, const std::vector< std::vector< const Elem *>> &nodes_to_elem_map, std::vector< const Node *> &neighbors)
Given a mesh and a node in the mesh, the vector will be filled with every node directly attached to t...
Definition: mesh_tools.C:1036
void build_nodes_to_elem_map(const MeshBase &mesh, std::vector< std::vector< dof_id_type >> &nodes_to_elem_map)
After calling this function the input vector nodes_to_elem_map will contain the node to element conne...
Definition: mesh_tools.C:449
The libMesh namespace provides an interface to certain functionality in the library.
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 Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
void do_test(unsigned n_elem, ElemType elem_type, dof_id_type *validation_data)
static const dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition: dof_object.h:482
static std::unique_ptr< Elem > build_with_id(const ElemType type, dof_id_type id)
Calls the build() method above with a nullptr parent, and additionally sets the newly-created Elem&#39;s ...
Definition: elem.C:558
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.
CPPUNIT_TEST_SUITE_REGISTRATION(NodalNeighborsTest)
virtual const Node * node_ptr(const dof_id_type i) const =0
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