tree_node.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // C++ includes
21 #include <set>
22 #include <array>
23 
24 // Local includes
25 #include "libmesh/libmesh_config.h"
26 #include "libmesh/tree_node.h"
27 #include "libmesh/mesh_base.h"
28 #include "libmesh/elem.h"
29 
30 namespace libMesh
31 {
32 
33 // ------------------------------------------------------------
34 // TreeNode class methods
35 template <unsigned int N>
36 bool TreeNode<N>::insert (const Node * nd)
37 {
38  libmesh_assert(nd);
39  libmesh_assert_less (nd->id(), mesh.n_nodes());
40 
41  // Return if we don't bound the node
42  if (!this->bounds_node(nd))
43  return false;
44 
45  // Add the node to ourself if we are active
46  if (this->active())
47  {
48  nodes.push_back (nd);
49 
50  // Refine ourself if we reach the target bin size for a TreeNode.
51  if (nodes.size() == tgt_bin_size)
52  this->refine();
53 
54  return true;
55  }
56 
57  // If we are not active simply pass the node along to
58  // our children
59  libmesh_assert_equal_to (children.size(), N);
60 
61  bool was_inserted = false;
62  for (unsigned int c=0; c<N; c++)
63  if (children[c]->insert (nd))
64  was_inserted = true;
65  return was_inserted;
66 }
67 
68 
69 
70 template <unsigned int N>
71 bool TreeNode<N>::insert (const Elem * elem)
72 {
73  libmesh_assert(elem);
74 
75  // We first want to find the corners of the cuboid surrounding the cell.
76  const BoundingBox bbox = elem->loose_bounding_box();
77 
78  // Next, find out whether this cuboid has got non-empty intersection
79  // with the bounding box of the current tree node.
80  //
81  // If not, we should not care about this element.
82  if (!this->bounding_box.intersects(bbox))
83  return false;
84 
85  // Only add the element if we are active
86  if (this->active())
87  {
88  elements.push_back (elem);
89 
90 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
91 
92  // flag indicating this node contains
93  // infinite elements
94  if (elem->infinite())
95  this->contains_ifems = true;
96 
97 #endif
98 
99  unsigned int element_count = cast_int<unsigned int>(elements.size());
101  {
102  const std::set<unsigned char> & elem_dimensions = mesh.elem_dimensions();
103  if (elem_dimensions.size() > 1)
104  {
105  element_count = 0;
106  unsigned char highest_dim_elem = *elem_dimensions.rbegin();
107  for (std::size_t i=0; i<elements.size(); i++)
108  {
109  if (elements[i]->dim() == highest_dim_elem)
110  {
111  element_count++;
112  }
113  }
114  }
115  }
116 
117  // Refine ourself if we reach the target bin size for a TreeNode.
118  if (element_count == tgt_bin_size)
119  this->refine();
120 
121  return true;
122  }
123 
124  // If we are not active simply pass the element along to
125  // our children
126  libmesh_assert_equal_to (children.size(), N);
127 
128  bool was_inserted = false;
129  for (unsigned int c=0; c<N; c++)
130  if (children[c]->insert (elem))
131  was_inserted = true;
132  return was_inserted;
133 }
134 
135 
136 
137 template <unsigned int N>
139 {
140  // Huh? better be active...
141  libmesh_assert (this->active());
142  libmesh_assert (children.empty());
143 
144  // A TreeNode<N> has by definition N children
145  children.resize(N);
146 
147  // Scale up the target bin size in child TreeNodes if we have reached
148  // the maximum number of refinement levels.
149  unsigned int new_target_bin_size = tgt_bin_size;
150  if (level() >= target_bin_size_increase_level)
151  {
152  new_target_bin_size *= 2;
153  }
154 
155  for (unsigned int c=0; c<N; c++)
156  {
157  // Create the child and set its bounding box.
158  children[c] = new TreeNode<N> (mesh, new_target_bin_size, this);
159  children[c]->set_bounding_box(this->create_bounding_box(c));
160 
161  // Pass off our nodes to our children
162  for (std::size_t n=0; n<nodes.size(); n++)
163  children[c]->insert(nodes[n]);
164 
165  // Pass off our elements to our children
166  for (std::size_t e=0; e<elements.size(); e++)
167  children[c]->insert(elements[e]);
168  }
169 
170  // We don't need to store nodes or elements any more, they have been
171  // added to the children. Use the "swap trick" to actually reduce
172  // the capacity of these vectors.
173  std::vector<const Node *>().swap(nodes);
174  std::vector<const Elem *>().swap(elements);
175 
176  libmesh_assert_equal_to (nodes.capacity(), 0);
177  libmesh_assert_equal_to (elements.capacity(), 0);
178 }
179 
180 
181 
182 template <unsigned int N>
183 void TreeNode<N>::set_bounding_box (const std::pair<Point, Point> & bbox)
184 {
185  bounding_box = bbox;
186 }
187 
188 
189 
190 template <unsigned int N>
192  Real relative_tol) const
193 {
194  libmesh_assert(nd);
195  return bounds_point(*nd, relative_tol);
196 }
197 
198 
199 
200 template <unsigned int N>
202  Real relative_tol) const
203 {
204  const Point & min = bounding_box.first;
205  const Point & max = bounding_box.second;
206 
207  const Real tol = (max - min).norm() * relative_tol;
208 
209  if ((p(0) >= min(0) - tol)
210  && (p(0) <= max(0) + tol)
211 #if LIBMESH_DIM > 1
212  && (p(1) >= min(1) - tol)
213  && (p(1) <= max(1) + tol)
214 #endif
215 #if LIBMESH_DIM > 2
216  && (p(2) >= min(2) - tol)
217  && (p(2) <= max(2) + tol)
218 #endif
219  )
220  return true;
221 
222  return false;
223 }
224 
225 
226 
227 template <unsigned int N>
229 TreeNode<N>::create_bounding_box (unsigned int c) const
230 {
231  switch (N)
232  {
233  // How to refine an OctTree Node
234  case 8:
235  {
236  const Real xmin = bounding_box.first(0);
237  const Real ymin = bounding_box.first(1);
238  const Real zmin = bounding_box.first(2);
239 
240  const Real xmax = bounding_box.second(0);
241  const Real ymax = bounding_box.second(1);
242  const Real zmax = bounding_box.second(2);
243 
244  const Real xc = .5*(xmin + xmax);
245  const Real yc = .5*(ymin + ymax);
246  const Real zc = .5*(zmin + zmax);
247 
248  switch (c)
249  {
250  case 0:
251  return BoundingBox (Point(xmin, ymin, zmin),
252  Point(xc, yc, zc));
253  case 1:
254  return BoundingBox (Point(xc, ymin, zmin),
255  Point(xmax, yc, zc));
256  case 2:
257  return BoundingBox (Point(xmin, yc, zmin),
258  Point(xc, ymax, zc));
259  case 3:
260  return BoundingBox (Point(xc, yc, zmin),
261  Point(xmax, ymax, zc));
262  case 4:
263  return BoundingBox (Point(xmin, ymin, zc),
264  Point(xc, yc, zmax));
265  case 5:
266  return BoundingBox (Point(xc, ymin, zc),
267  Point(xmax, yc, zmax));
268  case 6:
269  return BoundingBox (Point(xmin, yc, zc),
270  Point(xc, ymax, zmax));
271  case 7:
272  return BoundingBox (Point(xc, yc, zc),
273  Point(xmax, ymax, zmax));
274  default:
275  libmesh_error_msg("c >= N! : " << c);
276  }
277 
278  break;
279  } // case 8
280 
281  // How to refine an QuadTree Node
282  case 4:
283  {
284  const Real xmin = bounding_box.first(0);
285  const Real ymin = bounding_box.first(1);
286 
287  const Real xmax = bounding_box.second(0);
288  const Real ymax = bounding_box.second(1);
289 
290  const Real xc = .5*(xmin + xmax);
291  const Real yc = .5*(ymin + ymax);
292 
293  switch (c)
294  {
295  case 0:
296  return BoundingBox (Point(xmin, ymin),
297  Point(xc, yc));
298  case 1:
299  return BoundingBox (Point(xc, ymin),
300  Point(xmax, yc));
301  case 2:
302  return BoundingBox (Point(xmin, yc),
303  Point(xc, ymax));
304  case 3:
305  return BoundingBox (Point(xc, yc),
306  Point(xmax, ymax));
307  default:
308  libmesh_error_msg("c >= N!");
309  }
310 
311  break;
312  } // case 4
313 
314  // How to refine a BinaryTree Node
315  case 2:
316  {
317  const Real xmin = bounding_box.first(0);
318 
319  const Real xmax = bounding_box.second(0);
320 
321  const Real xc = .5*(xmin + xmax);
322 
323  switch (c)
324  {
325  case 0:
326  return BoundingBox (Point(xmin),
327  Point(xc));
328  case 1:
329  return BoundingBox (Point(xc),
330  Point(xmax));
331  default:
332  libmesh_error_msg("c >= N!");
333  }
334 
335  break;
336  } // case 2
337 
338  default:
339  libmesh_error_msg("Only implemented for Octrees, QuadTrees, and Binary Trees!");
340  }
341 }
342 
343 
344 
345 template <unsigned int N>
346 void TreeNode<N>::print_nodes(std::ostream & out_stream) const
347 {
348  if (this->active())
349  {
350  out_stream << "TreeNode Level: " << this->level() << std::endl;
351 
352  for (std::size_t n=0; n<nodes.size(); n++)
353  out_stream << " " << nodes[n]->id();
354 
355  out_stream << std::endl << std::endl;
356  }
357  else
358  {
359  for (std::size_t child=0; child<children.size(); child++)
360  children[child]->print_nodes();
361  }
362 }
363 
364 
365 
366 template <unsigned int N>
367 void TreeNode<N>::print_elements(std::ostream & out_stream) const
368 {
369  if (this->active())
370  {
371  out_stream << "TreeNode Level: " << this->level() << std::endl;
372 
373  for (const auto & elem : elements)
374  out_stream << " " << elem;
375 
376  out_stream << std::endl << std::endl;
377  }
378  else
379  {
380  for (std::size_t child=0; child<children.size(); child++)
381  children[child]->print_elements();
382  }
383 }
384 
385 
386 
387 template <unsigned int N>
388 void TreeNode<N>::transform_nodes_to_elements (std::vector<std::vector<const Elem *>> & nodes_to_elem)
389 {
390  if (this->active())
391  {
392  elements.clear();
393 
394  // Temporarily use a set. Since multiple nodes
395  // will likely map to the same element we use a
396  // set to eliminate the duplication.
397  std::set<const Elem *> elements_set;
398 
399  for (std::size_t n=0; n<nodes.size(); n++)
400  {
401  // the actual global node number we are replacing
402  // with the connected elements
403  const dof_id_type node_number = nodes[n]->id();
404 
405  libmesh_assert_less (node_number, mesh.n_nodes());
406  libmesh_assert_less (node_number, nodes_to_elem.size());
407 
408  for (std::size_t e=0; e<nodes_to_elem[node_number].size(); e++)
409  elements_set.insert(nodes_to_elem[node_number][e]);
410  }
411 
412  // Done with the nodes.
413  std::vector<const Node *>().swap(nodes);
414 
415  // Now the set is built. We can copy this to the
416  // vector. Note that the resulting vector will
417  // already be sorted, and will require less memory
418  // than the set.
419  elements.reserve(elements_set.size());
420 
421  for (const auto & elem : elements_set)
422  {
423  elements.push_back(elem);
424 
425 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
426 
427  // flag indicating this node contains
428  // infinite elements
429  if (elem->infinite())
430  this->contains_ifems = true;
431 
432 #endif
433  }
434  }
435  else
436  {
437  for (std::size_t child=0; child<children.size(); child++)
438  children[child]->transform_nodes_to_elements (nodes_to_elem);
439  }
440 
441 }
442 
443 
444 
445 template <unsigned int N>
446 void TreeNode<N>::transform_nodes_to_elements (std::unordered_map<dof_id_type, std::vector<const Elem *>> & nodes_to_elem)
447 {
448  if (this->active())
449  {
450  elements.clear();
451 
452  // Temporarily use a set. Since multiple nodes
453  // will likely map to the same element we use a
454  // set to eliminate the duplication.
455  std::set<const Elem *> elements_set;
456 
457  for (std::size_t n=0; n<nodes.size(); n++)
458  {
459  // the actual global node number we are replacing
460  // with the connected elements
461  const dof_id_type node_number = nodes[n]->id();
462 
463  libmesh_assert_less (node_number, mesh.n_nodes());
464 
465  auto & my_elems = nodes_to_elem[node_number];
466  elements_set.insert(my_elems.begin(), my_elems.end());
467  }
468 
469  // Done with the nodes.
470  std::vector<const Node *>().swap(nodes);
471 
472  // Now the set is built. We can copy this to the
473  // vector. Note that the resulting vector will
474  // already be sorted, and will require less memory
475  // than the set.
476  elements.reserve(elements_set.size());
477 
478  for (const auto & elem : elements_set)
479  {
480  elements.push_back(elem);
481 
482 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
483 
484  // flag indicating this node contains
485  // infinite elements
486  if (elem->infinite())
487  this->contains_ifems = true;
488 
489 #endif
490  }
491  }
492  else
493  {
494  for (std::size_t child=0; child<children.size(); child++)
495  children[child]->transform_nodes_to_elements (nodes_to_elem);
496  }
497 
498 }
499 
500 
501 
502 template <unsigned int N>
503 unsigned int TreeNode<N>::n_active_bins() const
504 {
505  if (this->active())
506  return 1;
507 
508  else
509  {
510  unsigned int sum=0;
511 
512  for (std::size_t c=0; c<children.size(); c++)
513  sum += children[c]->n_active_bins();
514 
515  return sum;
516  }
517 }
518 
519 
520 
521 template <unsigned int N>
522 const Elem *
524  const std::set<subdomain_id_type> * allowed_subdomains,
525  Real relative_tol) const
526 {
527  if (this->active())
528  {
529  // Only check our children if the point is in our bounding box
530  // or if the node contains infinite elements
531  if (this->bounds_point(p, relative_tol) || this->contains_ifems)
532  // Search the active elements in the active TreeNode.
533  for (const auto & elem : elements)
534  if (!allowed_subdomains || allowed_subdomains->count(elem->subdomain_id()))
535  if (elem->active() && elem->contains_point(p, relative_tol))
536  return elem;
537 
538  // The point was not found in any element
539  return nullptr;
540  }
541  else
542  return this->find_element_in_children(p,allowed_subdomains,
543  relative_tol);
544 }
545 
546 
547 
548 
549 template <unsigned int N>
551  const std::set<subdomain_id_type> * allowed_subdomains,
552  Real relative_tol) const
553 {
554  libmesh_assert (!this->active());
555 
556  // value-initialization sets all array members to false
557  auto searched_child = std::array<bool, N>();
558 
559  // First only look in the children whose bounding box
560  // contain the point p.
561  for (std::size_t c=0; c<children.size(); c++)
562  if (children[c]->bounds_point(p, relative_tol))
563  {
564  const Elem * e =
565  children[c]->find_element(p,allowed_subdomains,
566  relative_tol);
567 
568  if (e != nullptr)
569  return e;
570 
571  // If we get here then a child that bounds the
572  // point does not have any elements that contain
573  // the point. So, we will search all our children.
574  // However, we have already searched child c so there
575  // is no use searching her again.
576  searched_child[c] = true;
577  }
578 
579 
580  // If we get here then our child whose bounding box
581  // was searched and did not find any elements containing
582  // the point p. So, let's look at the other children
583  // but exclude the one we have already searched.
584  for (std::size_t c=0; c<children.size(); c++)
585  if (!searched_child[c])
586  {
587  const Elem * e =
588  children[c]->find_element(p,allowed_subdomains,
589  relative_tol);
590 
591  if (e != nullptr)
592  return e;
593  }
594 
595  // If we get here we have searched all our children.
596  // Since this process was started at the root node then
597  // we have searched all the elements in the tree without
598  // success. So, we should return nullptr since at this point
599  // _no_ elements in the tree claim to contain point p.
600  return nullptr;
601 }
602 
603 
604 
605 // ------------------------------------------------------------
606 // Explicit Instantiations
607 template class TreeNode<2>;
608 template class TreeNode<4>;
609 template class TreeNode<8>;
610 
611 } // namespace libMesh
BoundingBox create_bounding_box(unsigned int c) const
Definition: tree_node.C:229
A geometric point in (x,y,z) space associated with a DOF.
Definition: node.h:52
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:386
bool intersects(const BoundingBox &) const
Definition: bounding_box.C:35
bool bounds_point(const Point &p, Real relative_tol=0) const
Definition: tree_node.C:201
unsigned int n_active_bins() const
Definition: tree_node.C:503
bool get_count_lower_dim_elems_in_point_locator() const
Definition: mesh_base.C:531
The base class for all geometric element types.
Definition: elem.h:100
MeshBase & mesh
virtual BoundingBox loose_bounding_box() const
Definition: elem.C:2857
void transform_nodes_to_elements(std::vector< std::vector< const Elem *>> &nodes_to_elem)
Definition: tree_node.C:388
bool bounds_node(const Node *nd, Real relative_tol=0) const
Definition: tree_node.C:191
long double max(long double a, double b)
bool insert(const Node *nd)
Definition: tree_node.C:36
BoundingBox bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:373
const Elem * find_element_in_children(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains, Real relative_tol) const
Definition: tree_node.C:550
dof_id_type id() const
Definition: dof_object.h:655
const std::set< unsigned char > & elem_dimensions() const
Definition: mesh_base.h:220
Base class for different Tree types.
Definition: tree_node.h:53
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void print_nodes(std::ostream &out=libMesh::out) const
Definition: tree_node.C:346
void swap(Iterator &lhs, Iterator &rhs)
const Elem * find_element(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains=nullptr, Real relative_tol=TOLERANCE) const
Definition: tree_node.C:523
virtual bool infinite() const =0
void set_bounding_box(const std::pair< Point, Point > &bbox)
Definition: tree_node.C:183
long double min(long double a, double b)
void print_elements(std::ostream &out=libMesh::out) const
Definition: tree_node.C:367
A geometric point in (x,y,z) space.
Definition: point.h:38
virtual dof_id_type n_nodes() const =0
uint8_t dof_id_type
Definition: id_types.h:64