libMesh
point_locator_tree.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 
22 // Local Includes
23 #include "libmesh/elem.h"
24 #include "libmesh/libmesh_logging.h"
25 #include "libmesh/mesh_base.h"
26 #include "libmesh/mesh_tools.h"
27 #include "libmesh/point_locator_tree.h"
28 #include "libmesh/tree.h"
29 
30 namespace libMesh
31 {
32 
33 
34 
35 //------------------------------------------------------------------
36 // PointLocator methods
38  const PointLocatorBase * master) :
39  PointLocatorBase (mesh,master),
40  _tree (nullptr),
41  _element (nullptr),
42  _out_of_mesh_mode(false),
43  _target_bin_size (200),
44  _build_type(Trees::NODES)
45 {
46  this->init(_build_type);
47 }
48 
49 
50 
52  const Trees::BuildType build_type,
53  const PointLocatorBase * master) :
54  PointLocatorBase (mesh,master),
55  _tree (nullptr),
56  _element (nullptr),
57  _out_of_mesh_mode(false),
58  _target_bin_size (200),
59  _build_type(build_type)
60 {
61  this->init(_build_type);
62 }
63 
64 
65 
67 {
68  this->clear ();
69 }
70 
71 
72 
74 {
75  // only delete the tree when we are the master
76  if (this->_tree != nullptr)
77  {
78  if (this->_master == nullptr)
79  // we own the tree
80  delete this->_tree;
81  else
82  // someone else owns and therefore deletes the tree
83  this->_tree = nullptr;
84 
85  // make sure operator () throws an assertion
86  this->_initialized = false;
87  }
88 }
89 
90 
91 
93 {
94  this->init(_build_type);
95 }
96 
97 
98 
100 {
101  libmesh_assert (!this->_tree);
102 
103  if (this->_initialized)
104  {
105  // Warn that we are already initialized
106  libMesh::err << "Warning: PointLocatorTree already initialized! Will ignore this call..." << std::endl;
107 
108  // Further warn if we try to init() again with a different build_type
109  if (_build_type != build_type)
110  {
111  libMesh::err << "Warning: PointLocatorTree is using build_type = " << _build_type << ".\n"
112  << "Your requested build_type, " << build_type << " will not be used!" << std::endl;
113  }
114  }
115 
116  else
117  {
118  // Let the requested build_type override the _build_type we were
119  // constructed with. This is no big deal since we have not been
120  // initialized before.
121  _build_type = build_type;
122 
123  if (this->_master == nullptr)
124  {
125  LOG_SCOPE("init(no master)", "PointLocatorTree");
126 
127  if (this->_mesh.mesh_dimension() == 3)
129  else
130  {
131  // A 1D/2D mesh in 3D space needs special consideration.
132  // If the mesh is planar XY, we want to build a QuadTree
133  // to search efficiently. If the mesh is truly a manifold,
134  // then we need an octree
135 #if LIBMESH_DIM > 2
136  bool is_planar_xy = false;
137 
138  // Build the bounding box for the mesh. If the delta-z bound is
139  // negligibly small then we can use a quadtree.
140  {
142 
143  const Real
144  Dx = bbox.second(0) - bbox.first(0),
145  Dz = bbox.second(2) - bbox.first(2);
146 
147  // In order to satisfy is_planar_xy the mesh should be planar and should
148  // also be in the z=0 plane, since otherwise it is incorrect to use a
149  // QuadTree since QuadTrees assume z=0.
150  if ( (std::abs(Dz/(Dx + 1.e-20)) < 1e-10) && (std::abs(bbox.second(2)) < 1.e-10) )
151  is_planar_xy = true;
152  }
153 
154  if (!is_planar_xy)
156  else
157 #endif
158 #if LIBMESH_DIM > 1
160 #else
162 #endif
163  }
164  }
165 
166  else
167  {
168  // We are _not_ the master. Let our Tree point to
169  // the master's tree. But for this we first transform
170  // the master in a state for which we are friends.
171  // And make sure the master has a tree!
172  const PointLocatorTree * my_master =
173  cast_ptr<const PointLocatorTree *>(this->_master);
174 
175  if (my_master->initialized())
176  this->_tree = my_master->_tree;
177  else
178  libmesh_error_msg("ERROR: Initialize master first, then servants!");
179  }
180 
181  // Not all PointLocators may own a tree, but all of them
182  // use their own element pointer. Let the element pointer
183  // be unique for every interpolator.
184  // Suppose the interpolators are used concurrently
185  // at different locations in the mesh, then it makes quite
186  // sense to have unique start elements.
187  this->_element = nullptr;
188  }
189 
190  // ready for take-off
191  this->_initialized = true;
192 }
193 
194 
195 
197  const std::set<subdomain_id_type> * allowed_subdomains) const
198 {
200 
201  LOG_SCOPE("operator()", "PointLocatorTree");
202 
203  // If we're provided with an allowed_subdomains list and have a cached element, make sure it complies
204  if (allowed_subdomains && this->_element && !allowed_subdomains->count(this->_element->subdomain_id())) this->_element = nullptr;
205 
206  // First check the element from last time before asking the tree
207  if (this->_element==nullptr || !(this->_element->contains_point(p)))
208  {
209  // ask the tree
210  this->_element = this->_tree->find_element (p,allowed_subdomains);
211 
212  if (this->_element == nullptr)
213  {
214  // If we haven't found the element, we may want to do a linear
215  // search using a tolerance.
217  {
218  if (_verbose)
219  {
220  libMesh::out << "Performing linear search using close-to-point tolerance "
222  << std::endl;
223  }
224 
225  this->_element =
226  this->perform_linear_search(p,
227  allowed_subdomains,
228  /*use_close_to_point*/ true,
230 
231  return this->_element;
232  }
233 
234  // No element seems to contain this point. In theory, our
235  // tree now correctly handles curved elements. In
236  // out-of-mesh mode this is sometimes expected, and we can
237  // just return nullptr without searching further. Out of
238  // out-of-mesh mode, something must have gone wrong.
239  libmesh_assert_equal_to (_out_of_mesh_mode, true);
240 
241  return this->_element;
242  }
243  }
244 
245  // If we found an element, it should be active
246  libmesh_assert (!this->_element || this->_element->active());
247 
248  // If we found an element and have a restriction list, they better match
249  libmesh_assert (!this->_element || !allowed_subdomains || allowed_subdomains->count(this->_element->subdomain_id()));
250 
251  // return the element
252  return this->_element;
253 }
254 
255 
257  std::set<const Elem *> & candidate_elements,
258  const std::set<subdomain_id_type> * allowed_subdomains) const
259 {
261 
262  LOG_SCOPE("operator() - Version 2", "PointLocatorTree");
263 
264  // ask the tree
265  this->_tree->find_elements (p, candidate_elements, allowed_subdomains, _close_to_point_tol);
266 }
267 
268 
269 
271  const std::set<subdomain_id_type> * allowed_subdomains,
272  bool use_close_to_point,
273  Real close_to_point_tolerance) const
274 {
275  LOG_SCOPE("perform_linear_search", "PointLocatorTree");
276 
277  // The type of iterator depends on the Trees::BuildType
278  // used for this PointLocator. If it's
279  // TREE_LOCAL_ELEMENTS, we only want to double check
280  // local elements during this linear search.
285 
286  for (const auto & elem : r)
287  {
288  if (!allowed_subdomains ||
289  allowed_subdomains->count(elem->subdomain_id()))
290  {
291  if (!use_close_to_point)
292  {
293  if (elem->contains_point(p))
294  return elem;
295  }
296  else
297  {
298  if (elem->close_to_point(p, close_to_point_tolerance))
299  return elem;
300  }
301  }
302  }
303 
304  return nullptr;
305 }
306 
307 
308 std::set<const Elem *> PointLocatorTree::perform_fuzzy_linear_search(const Point & p,
309  const std::set<subdomain_id_type> * allowed_subdomains,
310  Real close_to_point_tolerance) const
311 {
312  LOG_SCOPE("perform_fuzzy_linear_search", "PointLocatorTree");
313 
314  std::set<const Elem *> candidate_elements;
315 
316  // The type of iterator depends on the Trees::BuildType
317  // used for this PointLocator. If it's
318  // TREE_LOCAL_ELEMENTS, we only want to double check
319  // local elements during this linear search.
324 
325  for (const auto & elem : r)
326  if ((!allowed_subdomains || allowed_subdomains->count(elem->subdomain_id())) && elem->close_to_point(p, close_to_point_tolerance))
327  candidate_elements.insert(elem);
328 
329  return candidate_elements;
330 }
331 
332 
333 
335 {
336  // Out-of-mesh mode should now work properly even on meshes with
337  // non-affine elements.
338  _out_of_mesh_mode = true;
339 }
340 
341 
343 {
344  _out_of_mesh_mode = false;
345 }
346 
347 
348 void PointLocatorTree::set_target_bin_size (unsigned int target_bin_size)
349 {
350  _target_bin_size = target_bin_size;
351 }
352 
353 
355 {
356  return _target_bin_size;
357 }
358 
359 
360 } // namespace libMesh
libMesh::PointLocatorTree::enable_out_of_mesh_mode
virtual void enable_out_of_mesh_mode() override
Enables out-of-mesh mode.
Definition: point_locator_tree.C:334
libMesh::PointLocatorBase::_master
const PointLocatorBase * _master
Const pointer to our master, initialized to nullptr if none given.
Definition: point_locator_base.h:191
libMesh::SimpleRange
The SimpleRange templated class is intended to make it easy to construct ranges from pairs of iterato...
Definition: simple_range.h:36
libMesh::Elem::contains_point
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
Definition: elem.C:2094
libMesh::PointLocatorTree::_build_type
Trees::BuildType _build_type
How the underlying tree is built.
Definition: point_locator_tree.h:194
libMesh::Trees::LOCAL_ELEMENTS
Definition: tree_base.h:57
libMesh::MeshBase::active_local_element_ptr_range
virtual SimpleRange< element_iterator > active_local_element_ptr_range()=0
libMesh::BoundingBox
Defines a Cartesian bounding box by the two corner extremum.
Definition: bounding_box.h:40
libMesh::Trees::BinaryTree
Tree< 2 > BinaryTree
A BinaryTree is a tree appropriate for 1D meshes.
Definition: tree.h:133
libMesh::MeshBase::active_element_ptr_range
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
libMesh::PointLocatorTree::_target_bin_size
unsigned int _target_bin_size
Target bin size, which gets passed to the constructor of _tree.
Definition: point_locator_tree.h:189
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::PointLocatorBase::_verbose
bool _verbose
Boolean flag to indicate whether to print out extra info.
Definition: point_locator_base.h:183
libMesh::PointLocatorBase::_close_to_point_tol
Real _close_to_point_tol
The tolerance to use.
Definition: point_locator_base.h:212
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::MeshBase::mesh_dimension
unsigned int mesh_dimension() const
Definition: mesh_base.C:135
libMesh::Trees::BuildType
BuildType
enum defining how to build the tree.
Definition: tree_base.h:55
libMesh::TreeBase::find_element
virtual const Elem * find_element(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains=nullptr, Real relative_tol=TOLERANCE) const =0
libMesh::Elem::active
bool active() const
Definition: elem.h:2345
libMesh::PointLocatorTree::PointLocatorTree
PointLocatorTree(const MeshBase &mesh, const PointLocatorBase *master=nullptr)
Constructor.
Definition: point_locator_tree.C:37
libMesh::PointLocatorTree
This is a point locator.
Definition: point_locator_tree.h:48
libMesh::PointLocatorTree::set_target_bin_size
void set_target_bin_size(unsigned int target)
Set the target bin size.
Definition: point_locator_tree.C:348
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::PointLocatorBase::_use_close_to_point_tol
bool _use_close_to_point_tol
true if we will use a user-specified tolerance for locating the element.
Definition: point_locator_base.h:207
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::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
std::abs
MetaPhysicL::DualNumber< T, D > abs(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::PointLocatorTree::clear
virtual void clear() override
Clears the locator.
Definition: point_locator_tree.C:73
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::TreeBase::find_elements
virtual 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 =0
Fills candidate_elements with any elements containing the specified point p, optionally restricted to...
libMesh::PointLocatorBase::initialized
bool initialized() const
Definition: point_locator_base.C:59
libMesh::PointLocatorTree::_out_of_mesh_mode
bool _out_of_mesh_mode
true if out-of-mesh mode is enabled.
Definition: point_locator_tree.h:184
libMesh::PointLocatorTree::init
virtual void init() override
Initializes the locator, so that the operator() methods can be used.
Definition: point_locator_tree.C:92
libMesh::PointLocatorTree::operator()
virtual const Elem * operator()(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains=nullptr) const override
Locates the element in which the point with global coordinates p is located, optionally restricted to...
Definition: point_locator_tree.C:196
libMesh::PointLocatorTree::perform_linear_search
const Elem * perform_linear_search(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains, bool use_close_to_point, Real close_to_point_tolerance=TOLERANCE) const
As a fallback option, it's helpful to be able to do a linear search over the entire mesh.
Definition: point_locator_tree.C:270
libMesh::PointLocatorBase::_mesh
const MeshBase & _mesh
constant reference to the mesh in which the point is looked for.
Definition: point_locator_base.h:196
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::Trees::NODES
Definition: tree_base.h:55
libMesh::PointLocatorTree::_element
const Elem * _element
Pointer to the last element that was found by the tree.
Definition: point_locator_tree.h:178
libMesh::PointLocatorTree::disable_out_of_mesh_mode
virtual void disable_out_of_mesh_mode() override
Disables out-of-mesh mode (default).
Definition: point_locator_tree.C:342
libMesh::err
OStreamProxy err
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::Trees::OctTree
Tree< 8 > OctTree
An OctTree is a tree appropriate for 3D meshes.
Definition: tree.h:145
libMesh::Tree
This class defines a tree that may be used for fast point location in space.
Definition: tree.h:44
libMesh::PointLocatorTree::get_target_bin_size
unsigned int get_target_bin_size() const
Get the target bin size.
Definition: point_locator_tree.C:354
libMesh::out
OStreamProxy out
libMesh::PointLocatorTree::_tree
TreeBase * _tree
Pointer to our tree.
Definition: point_locator_tree.h:171
libMesh::PointLocatorBase
This is the base class for point locators.
Definition: point_locator_base.h:62
libMesh::PointLocatorBase::_initialized
bool _initialized
true when properly initialized, false otherwise.
Definition: point_locator_base.h:201
libMesh::Trees::QuadTree
Tree< 4 > QuadTree
A QuadTree is a tree appropriate for 2D meshes.
Definition: tree.h:139
libMesh::PointLocatorTree::~PointLocatorTree
~PointLocatorTree()
Destructor.
Definition: point_locator_tree.C:66
libMesh::PointLocatorTree::perform_fuzzy_linear_search
std::set< const Elem * > perform_fuzzy_linear_search(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains, Real close_to_point_tolerance=TOLERANCE) const
A method to check if "fat" point p is in multiple elements.
Definition: point_locator_tree.C:308