libMesh
Loading...
Searching...
No Matches
point_locator_tree.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
30namespace 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
69
71{
72 this->_initialized = false;
73
74 // reset() actually frees the memory if we are master, otherwise it
75 // just reduces the ref. count.
76 _tree.reset();
77}
78
79
80
82{
83 this->init(_build_type);
84}
85
86
87
89{
90 libmesh_assert (!this->_tree);
91
92 if (this->_initialized)
93 {
94 // Warn that we are already initialized
95 libMesh::err << "Warning: PointLocatorTree already initialized! Will ignore this call..." << std::endl;
96
97 // Further warn if we try to init() again with a different build_type
98 if (_build_type != build_type)
99 {
100 libMesh::err << "Warning: PointLocatorTree is using build_type = " << _build_type << ".\n"
101 << "Your requested build_type, " << build_type << " will not be used!" << std::endl;
102 }
103 }
104
105 else
106 {
107 // Let the requested build_type override the _build_type we were
108 // constructed with. This is no big deal since we have not been
109 // initialized before.
110 _build_type = build_type;
111
112 if (this->_master == nullptr)
113 {
114 LOG_SCOPE("init(no master)", "PointLocatorTree");
115
116 if (LIBMESH_DIM == 1)
117 _tree = std::make_shared<Trees::BinaryTree>(this->_mesh, get_target_bin_size(), _build_type);
118 else if (LIBMESH_DIM == 2)
119 _tree = std::make_shared<Trees::QuadTree>(this->_mesh, get_target_bin_size(), _build_type);
120 else if (this->_mesh.mesh_dimension() == 3) // && LIBMESH_DIM==3
121 _tree = std::make_shared<Trees::OctTree>(this->_mesh, get_target_bin_size(), _build_type);
122 else
123 {
124 // LIBMESH_DIM==3 but we have a mesh with only 1D/2D
125 // elements, which needs special consideration. If the
126 // mesh is planar XY, we want to build a QuadTree to
127 // search efficiently. If the mesh is truly a manifold,
128 // then we need an octree
129 bool is_planar_xy = false;
130
131 // Build the bounding box for the mesh. If the delta-z bound is
132 // negligibly small then we can use a quadtree.
134
135 const Real
136 Dx = bbox.second(0) - bbox.first(0),
137 Dz = bbox.second(2) - bbox.first(2);
138
139 // In order to satisfy is_planar_xy the mesh should be planar and should
140 // also be in the z=0 plane, since otherwise it is incorrect to use a
141 // QuadTree since QuadTrees assume z=0.
142 if ( (std::abs(Dz/(Dx + 1.e-20)) < 1e-10) && (std::abs(bbox.second(2)) < 1.e-10) )
143 is_planar_xy = true;
144
145 if (is_planar_xy)
146 _tree = std::make_shared<Trees::QuadTree>(this->_mesh, get_target_bin_size(), _build_type);
147 else
148 _tree = std::make_shared<Trees::OctTree>(this->_mesh, get_target_bin_size(), _build_type);
149 }
150 }
151
152 else
153 {
154 // We are _not_ the master. Let our Tree point to
155 // the master's tree. But for this we first transform
156 // the master in a state for which we are friends.
157 // And make sure the master has a tree!
158 const PointLocatorTree * my_master =
159 cast_ptr<const PointLocatorTree *>(this->_master);
160
161 if (my_master->initialized())
162 this->_tree = my_master->_tree;
163 else
164 libmesh_error_msg("ERROR: Initialize master first, then servants!");
165 }
166
167 // Not all PointLocators may own a tree, but all of them
168 // use their own element pointer. Let the element pointer
169 // be unique for every interpolator.
170 // Suppose the interpolators are used concurrently
171 // at different locations in the mesh, then it makes quite
172 // sense to have unique start elements.
173 this->_element = nullptr;
174 }
175
176 // ready for take-off
177 this->_initialized = true;
178
179 // This may be too expensive to use even in debug mode, but it's
180 // helpful to uncomment for debugging.
181 // this->libmesh_assert_valid_point_locator();
182}
183
185 const std::set<subdomain_id_type> * allowed_subdomains) const
186{
188
189 LOG_SCOPE("operator()", "PointLocatorTree");
190
191 // If we're provided with an allowed_subdomains list and have a cached element, make sure it complies
192 if (allowed_subdomains && this->_element && !allowed_subdomains->count(this->_element->subdomain_id()))
193 this->_element = nullptr;
194
195 if (this->_element != nullptr)
196 {
197 // If the user specified a custom tolerance, we actually call
198 // Elem::close_to_point() instead, since Elem::contains_point()
199 // warns about using non-default BoundingBox tolerances.
201 this->_element = nullptr;
202
203 // Otherwise, just call contains_point(p) with default tolerances.
204 else if (!(this->_element->contains_point(p)))
205 this->_element = nullptr;
206 }
207
208 // First check the element from last time before asking the tree
209 if (this->_element==nullptr)
210 {
211 // ask the tree
213 this->_element = this->_tree->find_element(p, allowed_subdomains, _contains_point_tol);
214 else
215 this->_element = this->_tree->find_element(p, allowed_subdomains);
216
217 if (this->_element == nullptr)
218 {
219 // If we haven't found the element, we may want to do a linear
220 // search using a tolerance.
222 {
223 if (_verbose)
224 {
225 libMesh::out << "Performing linear search using close-to-point tolerance "
227 << std::endl;
228 }
229
230 this->_element =
231 this->perform_linear_search(p,
232 allowed_subdomains,
233 /*use_close_to_point*/ true,
235
236 return this->_element;
237 }
238
239 // No element seems to contain this point. In theory, our
240 // tree now correctly handles curved elements. In
241 // out-of-mesh mode this is sometimes expected, and we can
242 // just return nullptr without searching further. Out of
243 // out-of-mesh mode, something must have gone wrong.
244 libmesh_assert_equal_to (_out_of_mesh_mode, true);
245
246 return this->_element;
247 }
248 }
249
250 // If we found an element, it should be active
251 libmesh_assert (!this->_element || this->_element->active());
252
253 // If we found an element and have a restriction list, they better match
254 libmesh_assert (!this->_element || !allowed_subdomains || allowed_subdomains->count(this->_element->subdomain_id()));
255
256 // return the element
257 return this->_element;
258}
259
260
262 std::set<const Elem *> & candidate_elements,
263 const std::set<subdomain_id_type> * allowed_subdomains) const
264{
266
267 LOG_SCOPE("operator() - Version 2", "PointLocatorTree");
268
269 // ask the tree
270 this->_tree->find_elements (p, candidate_elements, allowed_subdomains, _close_to_point_tol);
271}
272
273
274
276 const std::set<subdomain_id_type> * allowed_subdomains,
277 bool use_close_to_point,
278 Real close_to_point_tolerance) const
279{
280 LOG_SCOPE("perform_linear_search", "PointLocatorTree");
281
282 // The type of iterator depends on the Trees::BuildType
283 // used for this PointLocator. If it's
284 // TREE_LOCAL_ELEMENTS, we only want to double check
285 // local elements during this linear search.
288 this->_mesh.active_local_element_ptr_range() :
289 this->_mesh.active_element_ptr_range();
290
291 for (const auto & elem : r)
292 {
293 if (!allowed_subdomains ||
294 allowed_subdomains->count(elem->subdomain_id()))
295 {
296 if (!use_close_to_point)
297 {
298 if (elem->contains_point(p, _contains_point_tol))
299 return elem;
300 }
301 else
302 {
303 if (elem->close_to_point(p, close_to_point_tolerance))
304 return elem;
305 }
306 }
307 }
308
309 return nullptr;
310}
311
312
314 const std::set<subdomain_id_type> * allowed_subdomains,
315 Real close_to_point_tolerance) const
316{
317 LOG_SCOPE("perform_fuzzy_linear_search", "PointLocatorTree");
318
319 std::set<const Elem *> candidate_elements;
320
321 // The type of iterator depends on the Trees::BuildType
322 // used for this PointLocator. If it's
323 // TREE_LOCAL_ELEMENTS, we only want to double check
324 // local elements during this linear search.
327 this->_mesh.active_local_element_ptr_range() :
328 this->_mesh.active_element_ptr_range();
329
330 for (const auto & elem : r)
331 if ((!allowed_subdomains || allowed_subdomains->count(elem->subdomain_id())) && elem->close_to_point(p, close_to_point_tolerance))
332 candidate_elements.insert(elem);
333
334 return candidate_elements;
335}
336
337
338
340{
341 // Out-of-mesh mode should now work properly even on meshes with
342 // non-affine elements.
343 _out_of_mesh_mode = true;
344}
345
346
351
352
353void PointLocatorTree::set_target_bin_size (unsigned int target_bin_size)
354{
355 _target_bin_size = target_bin_size;
356}
357
358
360{
361 return _target_bin_size;
362}
363
364
365} // namespace libMesh
Defines a Cartesian bounding box by the two corner extremum.
This is the base class from which all geometric element types are derived.
Definition elem.h:96
bool active() const
Definition elem.h:2958
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
Definition elem.C:2784
virtual bool close_to_point(const Point &p, Real tol) const
Definition elem.C:2809
This is the MeshBase class.
Definition mesh_base.h:81
unsigned int mesh_dimension() const
Definition mesh_base.C:430
This is the base class for point locators.
Real _close_to_point_tol
The tolerance to use.
Real _contains_point_tol
The tolerance to use when locating an element in the tree.
bool _initialized
true when properly initialized, false otherwise.
bool _use_contains_point_tol
true if we will use a user-specified tolerance for locating the element.
bool _use_close_to_point_tol
true if we will use a user-specified tolerance for locating the element in an exhaustive search.
bool _verbose
Boolean flag to indicate whether to print out extra info.
const MeshBase & _mesh
constant reference to the mesh in which the point is looked for.
const PointLocatorBase * _master
Const pointer to our master, initialized to nullptr if none given.
This is a point locator.
unsigned int _target_bin_size
Target bin size, which gets passed to the constructor of _tree.
~PointLocatorTree()
Destructor.
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.
const Elem * _element
Pointer to the last element that was found by the tree.
virtual void init() override final
Initializes the locator, so that the operator() methods can be used.
Trees::BuildType _build_type
How the underlying tree is built.
PointLocatorTree(const MeshBase &mesh, const PointLocatorBase *master=nullptr)
Constructor.
unsigned int get_target_bin_size() const
Get the target bin size.
void set_target_bin_size(unsigned int target)
Set the target bin size.
virtual const Elem * operator()(const Point &p, const std::set< subdomain_id_type > *allowed_subdomains=nullptr) const override final
Locates the element in which the point with global coordinates p is located, optionally restricted to...
std::shared_ptr< TreeBase > _tree
Pointer to our tree.
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.
virtual void clear() override final
Clears the locator.
virtual void enable_out_of_mesh_mode() override final
Enables out-of-mesh mode.
bool _out_of_mesh_mode
true if out-of-mesh mode is enabled.
virtual void disable_out_of_mesh_mode() override final
Disables out-of-mesh mode (default).
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
The SimpleRange templated class is intended to make it easy to construct ranges from pairs of iterato...
MeshBase & mesh
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition mesh_tools.C:566
BuildType
enum defining how to build the tree.
Definition tree_base.h:58
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
libmesh_assert(ctx)
OStreamProxy out
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real