libMesh
tree_node.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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 (const Elem * other_elem : elements)
108  if (other_elem->dim() == highest_dim_elem)
109  element_count++;
110  }
111  }
112 
113  // Refine ourself if we reach the target bin size for a TreeNode.
114  if (element_count == tgt_bin_size)
115  this->refine();
116 
117  return true;
118  }
119 
120  // If we are not active simply pass the element along to
121  // our children
122  libmesh_assert_equal_to (children.size(), N);
123 
124  bool was_inserted = false;
125  for (unsigned int c=0; c<N; c++)
126  if (children[c]->insert (elem))
127  was_inserted = true;
128  return was_inserted;
129 }
130 
131 
132 
133 template <unsigned int N>
135 {
136  // Huh? better be active...
137  libmesh_assert (this->active());
138  libmesh_assert (children.empty());
139 
140  // A TreeNode<N> has by definition N children
141  children.resize(N);
142 
143  // Scale up the target bin size in child TreeNodes if we have reached
144  // the maximum number of refinement levels.
145  unsigned int new_target_bin_size = tgt_bin_size;
146  if (level() >= target_bin_size_increase_level)
147  {
148  new_target_bin_size *= 2;
149  }
150 
151  for (unsigned int c=0; c<N; c++)
152  {
153  // Create the child and set its bounding box.
154  children[c] = new TreeNode<N> (mesh, new_target_bin_size, this);
155  children[c]->set_bounding_box(this->create_bounding_box(c));
156 
157  // Pass off our nodes to our children
158  for (const Node * node : nodes)
159  children[c]->insert(node);
160 
161  // Pass off our elements to our children
162  for (const Elem * elem : elements)
163  children[c]->insert(elem);
164  }
165 
166  // We don't need to store nodes or elements any more, they have been
167  // added to the children. Use the "swap trick" to actually reduce
168  // the capacity of these vectors.
169  std::vector<const Node *>().swap(nodes);
170  std::vector<const Elem *>().swap(elements);
171 
172  libmesh_assert_equal_to (nodes.capacity(), 0);
173  libmesh_assert_equal_to (elements.capacity(), 0);
174 }
175 
176 
177 
178 template <unsigned int N>
179 void TreeNode<N>::set_bounding_box (const std::pair<Point, Point> & bbox)
180 {
181  bounding_box = bbox;
182 }
183 
184 
185 
186 template <unsigned int N>
188  Real relative_tol) const
189 {
190  libmesh_assert(nd);
191  return bounds_point(*nd, relative_tol);
192 }
193 
194 
195 
196 template <unsigned int N>
198  Real relative_tol) const
199 {
200  const Point & min = bounding_box.first;
201  const Point & max = bounding_box.second;
202 
203  const Real tol = (max - min).norm() * relative_tol;
204 
205  if ((p(0) >= min(0) - tol)
206  && (p(0) <= max(0) + tol)
207 #if LIBMESH_DIM > 1
208  && (p(1) >= min(1) - tol)
209  && (p(1) <= max(1) + tol)
210 #endif
211 #if LIBMESH_DIM > 2
212  && (p(2) >= min(2) - tol)
213  && (p(2) <= max(2) + tol)
214 #endif
215  )
216  return true;
217 
218  return false;
219 }
220 
221 
222 
223 template <unsigned int N>
225 TreeNode<N>::create_bounding_box (unsigned int c) const
226 {
227  switch (N)
228  {
229  // How to refine an OctTree Node
230  case 8:
231  {
232  const Real xmin = bounding_box.first(0);
233  const Real ymin = bounding_box.first(1);
234  const Real zmin = bounding_box.first(2);
235 
236  const Real xmax = bounding_box.second(0);
237  const Real ymax = bounding_box.second(1);
238  const Real zmax = bounding_box.second(2);
239 
240  const Real xc = .5*(xmin + xmax);
241  const Real yc = .5*(ymin + ymax);
242  const Real zc = .5*(zmin + zmax);
243 
244  switch (c)
245  {
246  case 0:
247  return BoundingBox (Point(xmin, ymin, zmin),
248  Point(xc, yc, zc));
249  case 1:
250  return BoundingBox (Point(xc, ymin, zmin),
251  Point(xmax, yc, zc));
252  case 2:
253  return BoundingBox (Point(xmin, yc, zmin),
254  Point(xc, ymax, zc));
255  case 3:
256  return BoundingBox (Point(xc, yc, zmin),
257  Point(xmax, ymax, zc));
258  case 4:
259  return BoundingBox (Point(xmin, ymin, zc),
260  Point(xc, yc, zmax));
261  case 5:
262  return BoundingBox (Point(xc, ymin, zc),
263  Point(xmax, yc, zmax));
264  case 6:
265  return BoundingBox (Point(xmin, yc, zc),
266  Point(xc, ymax, zmax));
267  case 7:
268  return BoundingBox (Point(xc, yc, zc),
269  Point(xmax, ymax, zmax));
270  default:
271  libmesh_error_msg("c >= N! : " << c);
272  }
273 
274  break;
275  } // case 8
276 
277  // How to refine an QuadTree Node
278  case 4:
279  {
280  const Real xmin = bounding_box.first(0);
281  const Real ymin = bounding_box.first(1);
282 
283  const Real xmax = bounding_box.second(0);
284  const Real ymax = bounding_box.second(1);
285 
286  const Real xc = .5*(xmin + xmax);
287  const Real yc = .5*(ymin + ymax);
288 
289  switch (c)
290  {
291  case 0:
292  return BoundingBox (Point(xmin, ymin),
293  Point(xc, yc));
294  case 1:
295  return BoundingBox (Point(xc, ymin),
296  Point(xmax, yc));
297  case 2:
298  return BoundingBox (Point(xmin, yc),
299  Point(xc, ymax));
300  case 3:
301  return BoundingBox (Point(xc, yc),
302  Point(xmax, ymax));
303  default:
304  libmesh_error_msg("c >= N!");
305  }
306 
307  break;
308  } // case 4
309 
310  // How to refine a BinaryTree Node
311  case 2:
312  {
313  const Real xmin = bounding_box.first(0);
314 
315  const Real xmax = bounding_box.second(0);
316 
317  const Real xc = .5*(xmin + xmax);
318 
319  switch (c)
320  {
321  case 0:
322  return BoundingBox (Point(xmin),
323  Point(xc));
324  case 1:
325  return BoundingBox (Point(xc),
326  Point(xmax));
327  default:
328  libmesh_error_msg("c >= N!");
329  }
330 
331  break;
332  } // case 2
333 
334  default:
335  libmesh_error_msg("Only implemented for Octrees, QuadTrees, and Binary Trees!");
336  }
337 }
338 
339 
340 
341 template <unsigned int N>
342 void TreeNode<N>::print_nodes(std::ostream & out_stream) const
343 {
344  if (this->active())
345  {
346  out_stream << "TreeNode Level: " << this->level() << std::endl;
347 
348  for (const Node * node : nodes)
349  out_stream << " " << node->id();
350 
351  out_stream << std::endl << std::endl;
352  }
353  else
354  for (TreeNode<N> * child : children)
355  child->print_nodes();
356 }
357 
358 
359 
360 template <unsigned int N>
361 void TreeNode<N>::print_elements(std::ostream & out_stream) const
362 {
363  if (this->active())
364  {
365  out_stream << "TreeNode Level: " << this->level() << std::endl;
366 
367  for (const auto & elem : elements)
368  out_stream << " " << elem;
369 
370  out_stream << std::endl << std::endl;
371  }
372  else
373  for (TreeNode<N> * child : children)
374  child->print_elements();
375 }
376 
377 
378 
379 template <unsigned int N>
380 void TreeNode<N>::transform_nodes_to_elements (std::vector<std::vector<const Elem *>> & nodes_to_elem)
381 {
382  if (this->active())
383  {
384  elements.clear();
385 
386  // Temporarily use a set. Since multiple nodes
387  // will likely map to the same element we use a
388  // set to eliminate the duplication.
389  std::set<const Elem *> elements_set;
390 
391  for (const Node * node : nodes)
392  {
393  // the actual global node number we are replacing
394  // with the connected elements
395  const dof_id_type node_number = node->id();
396 
397  libmesh_assert_less (node_number, mesh.n_nodes());
398  libmesh_assert_less (node_number, nodes_to_elem.size());
399 
400  for (const Elem * elem : nodes_to_elem[node_number])
401  elements_set.insert(elem);
402  }
403 
404  // Done with the nodes.
405  std::vector<const Node *>().swap(nodes);
406 
407  // Now the set is built. We can copy this to the
408  // vector. Note that the resulting vector will
409  // already be sorted, and will require less memory
410  // than the set.
411  elements.reserve(elements_set.size());
412 
413  for (const auto & elem : elements_set)
414  {
415  elements.push_back(elem);
416 
417 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
418 
419  // flag indicating this node contains
420  // infinite elements
421  if (elem->infinite())
422  this->contains_ifems = true;
423 
424 #endif
425  }
426  }
427  else
428  for (TreeNode<N> * child : children)
429  child->transform_nodes_to_elements (nodes_to_elem);
430 }
431 
432 
433 
434 template <unsigned int N>
435 void TreeNode<N>::transform_nodes_to_elements (std::unordered_map<dof_id_type, std::vector<const Elem *>> & nodes_to_elem)
436 {
437  if (this->active())
438  {
439  elements.clear();
440 
441  // Temporarily use a set. Since multiple nodes
442  // will likely map to the same element we use a
443  // set to eliminate the duplication.
444  std::set<const Elem *> elements_set;
445 
446  for (const Node * node : nodes)
447  {
448  // the actual global node number we are replacing
449  // with the connected elements
450  const dof_id_type node_number = node->id();
451 
452  libmesh_assert_less (node_number, mesh.n_nodes());
453 
454  auto & my_elems = nodes_to_elem[node_number];
455  elements_set.insert(my_elems.begin(), my_elems.end());
456  }
457 
458  // Done with the nodes.
459  std::vector<const Node *>().swap(nodes);
460 
461  // Now the set is built. We can copy this to the
462  // vector. Note that the resulting vector will
463  // already be sorted, and will require less memory
464  // than the set.
465  elements.reserve(elements_set.size());
466 
467  for (const auto & elem : elements_set)
468  {
469  elements.push_back(elem);
470 
471 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
472 
473  // flag indicating this node contains
474  // infinite elements
475  if (elem->infinite())
476  this->contains_ifems = true;
477 
478 #endif
479  }
480  }
481  else
482  for (TreeNode<N> * child : children)
483  child->transform_nodes_to_elements (nodes_to_elem);
484 }
485 
486 
487 
488 template <unsigned int N>
489 unsigned int TreeNode<N>::n_active_bins() const
490 {
491  if (this->active())
492  return 1;
493 
494  else
495  {
496  unsigned int sum=0;
497 
498  for (TreeNode<N> * child : children)
499  sum += child->n_active_bins();
500 
501  return sum;
502  }
503 }
504 
505 
506 
507 template <unsigned int N>
508 const Elem *
510  const std::set<subdomain_id_type> * allowed_subdomains,
511  Real relative_tol) const
512 {
513  if (this->active())
514  {
515  // Only check our children if the point is in our bounding box
516  // or if the node contains infinite elements
517  if (this->bounds_point(p, relative_tol) || this->contains_ifems)
518  // Search the active elements in the active TreeNode.
519  for (const auto & elem : elements)
520  if (!allowed_subdomains || allowed_subdomains->count(elem->subdomain_id()))
521  if (elem->active() && elem->contains_point(p, relative_tol))
522  return elem;
523 
524  // The point was not found in any element
525  return nullptr;
526  }
527  else
528  return this->find_element_in_children(p,allowed_subdomains,
529  relative_tol);
530 }
531 
532 
533 
534 template <unsigned int N>
535 void
537  std::set<const Elem *> & candidate_elements,
538  const std::set<subdomain_id_type> * allowed_subdomains,
539  Real relative_tol) const
540 {
541  if (this->active())
542  {
543  // Only check our children if the point is in our bounding box
544  // or if the node contains infinite elements
545  if (this->bounds_point(p, relative_tol) || this->contains_ifems)
546  // Search the active elements in the active TreeNode.
547  for (const auto & elem : elements)
548  if (!allowed_subdomains || allowed_subdomains->count(elem->subdomain_id()))
549  if (elem->active() && elem->contains_point(p, relative_tol))
550  candidate_elements.insert(elem);
551  }
552  else
553  this->find_elements_in_children(p, candidate_elements,
554  allowed_subdomains, relative_tol);
555 }
556 
557 
558 
559 template <unsigned int N>
561  const std::set<subdomain_id_type> * allowed_subdomains,
562  Real relative_tol) const
563 {
564  libmesh_assert (!this->active());
565 
566  // value-initialization sets all array members to false
567  auto searched_child = std::array<bool, N>();
568 
569  // First only look in the children whose bounding box
570  // contain the point p.
571  for (auto c : index_range(children))
572  if (children[c]->bounds_point(p, relative_tol))
573  {
574  const Elem * e =
575  children[c]->find_element(p,allowed_subdomains,
576  relative_tol);
577 
578  if (e != nullptr)
579  return e;
580 
581  // If we get here then a child that bounds the
582  // point does not have any elements that contain
583  // the point. So, we will search all our children.
584  // However, we have already searched child c so there
585  // is no use searching her again.
586  searched_child[c] = true;
587  }
588 
589 
590  // If we get here then our child whose bounding box
591  // was searched and did not find any elements containing
592  // the point p. So, let's look at the other children
593  // but exclude the one we have already searched.
594  for (auto c : index_range(children))
595  if (!searched_child[c])
596  {
597  const Elem * e =
598  children[c]->find_element(p,allowed_subdomains,
599  relative_tol);
600 
601  if (e != nullptr)
602  return e;
603  }
604 
605  // If we get here we have searched all our children.
606  // Since this process was started at the root node then
607  // we have searched all the elements in the tree without
608  // success. So, we should return nullptr since at this point
609  // _no_ elements in the tree claim to contain point p.
610  return nullptr;
611 }
612 
613 
614 
615 template <unsigned int N>
617  std::set<const Elem *> & candidate_elements,
618  const std::set<subdomain_id_type> * allowed_subdomains,
619  Real relative_tol) const
620 {
621  libmesh_assert (!this->active());
622 
623  // First only look in the children whose bounding box
624  // contain the point p.
625  for (std::size_t c=0; c<children.size(); c++)
626  if (children[c]->bounds_point(p, relative_tol))
627  children[c]->find_elements(p, candidate_elements,
628  allowed_subdomains, relative_tol);
629 }
630 
631 
632 
633 // ------------------------------------------------------------
634 // Explicit Instantiations
635 template class TreeNode<2>;
636 template class TreeNode<4>;
637 template class TreeNode<8>;
638 
639 } // namespace libMesh
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::TreeNode::print_elements
void print_elements(std::ostream &out=libMesh::out) const
Prints the contents of the elements set if we are active.
Definition: tree_node.C:361
libMesh::TreeNode::find_elements
void find_elements(const Point &p, std::set< const Elem * > &candidate_elements, const std::set< subdomain_id_type > *allowed_subdomains=nullptr, Real relative_tol=TOLERANCE) const
Fills candidate_elements with any elements containing the specified point p, optionally restricted to...
Definition: tree_node.C:536
libMesh::TreeNode::create_bounding_box
BoundingBox create_bounding_box(unsigned int c) const
Constructs the bounding box for child c.
Definition: tree_node.C:225
libMesh::BoundingBox
Defines a Cartesian bounding box by the two corner extremum.
Definition: bounding_box.h:40
libMesh::index_range
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:106
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::MeshTools::bounding_box
BoundingBox bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:376
libMesh::Elem::infinite
virtual bool infinite() const =0
libMesh::TreeNode::find_elements_in_children
void find_elements_in_children(const Point &p, std::set< const Elem * > &candidate_elements, const std::set< subdomain_id_type > *allowed_subdomains, Real relative_tol) const
Look for points in our children, optionally restricted to a set of allowed subdomains.
Definition: tree_node.C:616
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::TreeNode
This class defines a node on a tree.
Definition: tree_node.h:53
libMesh::TreeNode::refine
void refine()
Refine the tree node into N children if it contains more than tol nodes.
Definition: tree_node.C:134
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::MeshTools::create_bounding_box
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
The same functionality as the deprecated MeshTools::bounding_box().
Definition: mesh_tools.C:389
libMesh::TreeNode::transform_nodes_to_elements
void transform_nodes_to_elements(std::vector< std::vector< const Elem * >> &nodes_to_elem)
Transforms node numbers to element pointers.
Definition: tree_node.C:380
libMesh::MeshBase::get_count_lower_dim_elems_in_point_locator
bool get_count_lower_dim_elems_in_point_locator() const
Get the current value of _count_lower_dim_elems_in_point_locator.
Definition: mesh_base.C:710
libMesh::TreeNode::insert
bool insert(const Node *nd)
Tries to insert Node nd into the TreeNode.
Definition: tree_node.C:36
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::MeshBase::elem_dimensions
const std::set< unsigned char > & elem_dimensions() const
Definition: mesh_base.h:225
libMesh::Node
A Node is like a Point, but with more information.
Definition: node.h:52
libMesh::Elem::loose_bounding_box
virtual BoundingBox loose_bounding_box() const
Definition: elem.C:2649
libMesh::TreeNode::set_bounding_box
void set_bounding_box(const std::pair< Point, Point > &bbox)
Sets the bounding box;.
Definition: tree_node.C:179
libMesh::BoundingBox::intersects
bool intersects(const BoundingBox &) const
Definition: bounding_box.C:35
libMesh::MeshBase::n_nodes
virtual dof_id_type n_nodes() const =0
libMesh::TreeNode::print_nodes
void print_nodes(std::ostream &out=libMesh::out) const
Prints the contents of the node_numbers vector if we are active.
Definition: tree_node.C:342
libMesh::TreeNode::find_element_in_children
const Elem * find_element_in_children(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains, Real relative_tol) const
Look for point p in our children, optionally restricted to a set of allowed subdomains.
Definition: tree_node.C:560
libMesh::TreeNode::bounds_point
bool bounds_point(const Point &p, Real relative_tol=0) const
Definition: tree_node.C:197
libMesh::TreeNode::bounds_node
bool bounds_node(const Node *nd, Real relative_tol=0) const
Definition: tree_node.C:187
libMesh::DofObject::id
dof_id_type id() const
Definition: dof_object.h:767
libMesh::TreeNode::find_element
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:509
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
std::norm
MetaPhysicL::DualNumber< T, D > norm(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::TreeNode::n_active_bins
unsigned int n_active_bins() const
Definition: tree_node.C:489
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121