$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // C++ includes 00021 00022 // Local Includes 00023 #include "libmesh/elem.h" 00024 #include "libmesh/libmesh_logging.h" 00025 #include "libmesh/mesh_base.h" 00026 #include "libmesh/mesh_tools.h" 00027 #include "libmesh/point_locator_tree.h" 00028 #include "libmesh/tree.h" 00029 00030 namespace libMesh 00031 { 00032 00033 00034 00035 //------------------------------------------------------------------ 00036 // PointLocator methods 00037 PointLocatorTree::PointLocatorTree (const MeshBase& mesh, 00038 const PointLocatorBase* master) : 00039 PointLocatorBase (mesh,master), 00040 _tree (NULL), 00041 _element (NULL), 00042 _out_of_mesh_mode(false), 00043 _target_bin_size (200), 00044 _build_type(Trees::NODES) 00045 { 00046 this->init(_build_type); 00047 } 00048 00049 00050 00051 PointLocatorTree::PointLocatorTree (const MeshBase& mesh, 00052 const Trees::BuildType build_type, 00053 const PointLocatorBase* master) : 00054 PointLocatorBase (mesh,master), 00055 _tree (NULL), 00056 _element (NULL), 00057 _out_of_mesh_mode(false), 00058 _target_bin_size (200), 00059 _build_type(build_type) 00060 { 00061 this->init(_build_type); 00062 } 00063 00064 00065 00066 PointLocatorTree::~PointLocatorTree () 00067 { 00068 this->clear (); 00069 } 00070 00071 00072 00073 void PointLocatorTree::clear () 00074 { 00075 // only delete the tree when we are the master 00076 if (this->_tree != NULL) 00077 { 00078 if (this->_master == NULL) 00079 // we own the tree 00080 delete this->_tree; 00081 else 00082 // someone else owns and therefore deletes the tree 00083 this->_tree = NULL; 00084 } 00085 } 00086 00087 00088 00089 void PointLocatorTree::init() 00090 { 00091 this->init(_build_type); 00092 } 00093 00094 00095 00096 void PointLocatorTree::init (Trees::BuildType build_type) 00097 { 00098 libmesh_assert (!this->_tree); 00099 00100 if (this->_initialized) 00101 { 00102 // Warn that we are already initialized 00103 libMesh::err << "Warning: PointLocatorTree already initialized! Will ignore this call..." << std::endl; 00104 00105 // Further warn if we try to init() again with a different build_type 00106 if (_build_type != build_type) 00107 { 00108 libMesh::err << "Warning: PointLocatorTree is using build_type = " << _build_type << ".\n" 00109 << "Your requested build_type, " << build_type << " will not be used!" << std::endl; 00110 } 00111 } 00112 00113 else 00114 { 00115 // Let the requested build_type override the _build_type we were 00116 // constructed with. This is no big deal since we have not been 00117 // initialized before. 00118 _build_type = build_type; 00119 00120 if (this->_master == NULL) 00121 { 00122 START_LOG("init(no master)", "PointLocatorTree"); 00123 00124 if (this->_mesh.mesh_dimension() == 3) 00125 _tree = new Trees::OctTree (this->_mesh, get_target_bin_size(), _build_type); 00126 else 00127 { 00128 // A 1D/2D mesh in 3D space needs special consideration. 00129 // If the mesh is planar XY, we want to build a QuadTree 00130 // to search efficiently. If the mesh is truly a manifold, 00131 // then we need an octree 00132 #if LIBMESH_DIM > 2 00133 bool is_planar_xy = false; 00134 00135 // Build the bounding box for the mesh. If the delta-z bound is 00136 // negligibly small then we can use a quadtree. 00137 { 00138 MeshTools::BoundingBox bbox = MeshTools::bounding_box(this->_mesh); 00139 00140 const Real 00141 Dx = bbox.second(0) - bbox.first(0), 00142 Dz = bbox.second(2) - bbox.first(2); 00143 00144 if (std::abs(Dz/(Dx + 1.e-20)) < 1e-10) 00145 is_planar_xy = true; 00146 } 00147 00148 if (!is_planar_xy) 00149 _tree = new Trees::OctTree (this->_mesh, get_target_bin_size(), _build_type); 00150 else 00151 #endif 00152 #if LIBMESH_DIM > 1 00153 _tree = new Trees::QuadTree (this->_mesh, get_target_bin_size(), _build_type); 00154 #else 00155 _tree = new Trees::BinaryTree (this->_mesh, get_target_bin_size(), _build_type); 00156 #endif 00157 } 00158 00159 STOP_LOG("init(no master)", "PointLocatorTree"); 00160 } 00161 00162 else 00163 { 00164 // We are _not_ the master. Let our Tree point to 00165 // the master's tree. But for this we first transform 00166 // the master in a state for which we are friends. 00167 // And make sure the master @e has a tree! 00168 const PointLocatorTree* my_master = 00169 cast_ptr<const PointLocatorTree*>(this->_master); 00170 00171 if (my_master->initialized()) 00172 this->_tree = my_master->_tree; 00173 else 00174 libmesh_error_msg("ERROR: Initialize master first, then servants!"); 00175 } 00176 00177 // Not all PointLocators may own a tree, but all of them 00178 // use their own element pointer. Let the element pointer 00179 // be unique for every interpolator. 00180 // Suppose the interpolators are used concurrently 00181 // at different locations in the mesh, then it makes quite 00182 // sense to have unique start elements. 00183 this->_element = NULL; 00184 } 00185 00186 // ready for take-off 00187 this->_initialized = true; 00188 } 00189 00190 00191 00192 const Elem* PointLocatorTree::operator() (const Point& p, const std::set<subdomain_id_type> *allowed_subdomains) const 00193 { 00194 libmesh_assert (this->_initialized); 00195 00196 START_LOG("operator()", "PointLocatorTree"); 00197 00198 // If we're provided with an allowed_subdomains list and have a cached element, make sure it complies 00199 if (allowed_subdomains && this->_element && !allowed_subdomains->count(this->_element->subdomain_id())) this->_element = NULL; 00200 00201 // First check the element from last time before asking the tree 00202 if (this->_element==NULL || !(this->_element->contains_point(p))) 00203 { 00204 // ask the tree 00205 this->_element = this->_tree->find_element (p,allowed_subdomains); 00206 00207 if (this->_element == NULL) 00208 { 00209 // No element seems to contain this point. Thus: 00210 // 1.) If _out_of_mesh_mode == true, we can just return NULL 00211 // without searching further. 00212 // 2.) If _out_of_mesh_mode == false, we perform a linear 00213 // search over all active (possibly local) elements. 00214 // The idea here is that, in the case of curved elements, 00215 // the bounding box computed in \p TreeNode::insert(const 00216 // Elem*) might be slightly inaccurate and therefore we may 00217 // have generated a false negative. 00218 if (_out_of_mesh_mode == false) 00219 { 00220 this->_element = this->perform_linear_search(p, allowed_subdomains, /*use_close_to_point*/ false); 00221 00222 STOP_LOG("operator()", "PointLocatorTree"); 00223 return this->_element; 00224 } 00225 00226 // If we haven't found the element, we may want to do a linear 00227 // search using a tolerance. We only do this if _out_of_mesh_mode == true, 00228 // since we're looking for a point that may be outside of the mesh (within the 00229 // specified tolerance). 00230 if( _use_close_to_point_tol ) 00231 { 00232 if(_verbose) 00233 { 00234 libMesh::out << "Performing linear search using close-to-point tolerance " 00235 << _close_to_point_tol 00236 << std::endl; 00237 } 00238 00239 this->_element = 00240 this->perform_linear_search(p, 00241 allowed_subdomains, 00242 /*use_close_to_point*/ true, 00243 _close_to_point_tol); 00244 00245 STOP_LOG("operator()", "PointLocatorTree"); 00246 return this->_element; 00247 } 00248 } 00249 } 00250 00251 // If we found an element, it should be active 00252 libmesh_assert (!this->_element || this->_element->active()); 00253 00254 // If we found an element and have a restriction list, they better match 00255 libmesh_assert (!this->_element || !allowed_subdomains || allowed_subdomains->count(this->_element->subdomain_id())); 00256 00257 STOP_LOG("operator()", "PointLocatorTree"); 00258 00259 // return the element 00260 return this->_element; 00261 } 00262 00263 00264 00265 const Elem* PointLocatorTree::perform_linear_search(const Point& p, 00266 const std::set<subdomain_id_type> *allowed_subdomains, 00267 bool use_close_to_point, 00268 Real close_to_point_tolerance) const 00269 { 00270 START_LOG("perform_linear_search", "PointLocatorTree"); 00271 00272 // The type of iterator depends on the Trees::BuildType 00273 // used for this PointLocator. If it's 00274 // TREE_LOCAL_ELEMENTS, we only want to double check 00275 // local elements during this linear search. 00276 MeshBase::const_element_iterator pos = 00277 this->_build_type == Trees::LOCAL_ELEMENTS ? 00278 this->_mesh.active_local_elements_begin() : this->_mesh.active_elements_begin(); 00279 00280 const MeshBase::const_element_iterator end_pos = 00281 this->_build_type == Trees::LOCAL_ELEMENTS ? 00282 this->_mesh.active_local_elements_end() : this->_mesh.active_elements_end(); 00283 00284 for ( ; pos != end_pos; ++pos) 00285 { 00286 if (!allowed_subdomains || 00287 allowed_subdomains->count((*pos)->subdomain_id())) 00288 { 00289 if(!use_close_to_point) 00290 { 00291 if ((*pos)->contains_point(p)) 00292 { 00293 STOP_LOG("perform_linear_search", "PointLocatorTree"); 00294 return (*pos); 00295 } 00296 } 00297 else 00298 { 00299 if ((*pos)->close_to_point(p, close_to_point_tolerance)) 00300 { 00301 STOP_LOG("perform_linear_search", "PointLocatorTree"); 00302 return (*pos); 00303 } 00304 } 00305 } 00306 } 00307 00308 STOP_LOG("perform_linear_search", "PointLocatorTree"); 00309 return NULL; 00310 } 00311 00312 00313 void PointLocatorTree::enable_out_of_mesh_mode () 00314 { 00315 // Out-of-mesh mode is currently only supported if all of the 00316 // elements have affine mappings. The reason is that for quadratic 00317 // mappings, it is not easy to construct a reliable bounding box of 00318 // the element, and thus, the fallback linear search in \p 00319 // operator() is required. Hence, out-of-mesh mode would be 00320 // extremely slow. 00321 if (_out_of_mesh_mode == false) 00322 { 00323 #ifdef DEBUG 00324 MeshBase::const_element_iterator pos = this->_mesh.active_elements_begin(); 00325 const MeshBase::const_element_iterator end_pos = this->_mesh.active_elements_end(); 00326 for ( ; pos != end_pos; ++pos) 00327 if (!(*pos)->has_affine_map()) 00328 libmesh_error_msg("ERROR: Out-of-mesh mode is currently only supported if all elements have affine mappings."); 00329 #endif 00330 00331 _out_of_mesh_mode = true; 00332 } 00333 } 00334 00335 00336 void PointLocatorTree::disable_out_of_mesh_mode () 00337 { 00338 _out_of_mesh_mode = false; 00339 } 00340 00341 00342 void PointLocatorTree::set_target_bin_size (unsigned int target_bin_size) 00343 { 00344 _target_bin_size = target_bin_size; 00345 } 00346 00347 00348 unsigned int PointLocatorTree::get_target_bin_size () const 00349 { 00350 return _target_bin_size; 00351 } 00352 00353 00354 } // namespace libMesh