$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/point_locator_list.h" 00027 00028 namespace libMesh 00029 { 00030 00031 00032 // typedefs 00033 typedef std::vector<Point>::const_iterator const_list_iterator; 00034 00035 00036 //------------------------------------------------------------------ 00037 // PointLocator methods 00038 PointLocatorList::PointLocatorList (const MeshBase& mesh, 00039 const PointLocatorBase* master) : 00040 PointLocatorBase (mesh,master), 00041 _list (NULL) 00042 { 00043 // This code will only work if your mesh is the Voroni mesh of it's 00044 // own elements' centroids. If your mesh is that regular you might 00045 // as well hand-code an O(1) algorithm for locating points within 00046 // it. - RHS 00047 libmesh_experimental(); 00048 00049 this->init(); 00050 } 00051 00052 00053 00054 PointLocatorList::~PointLocatorList () 00055 { 00056 this->clear (); 00057 } 00058 00059 00060 00061 void PointLocatorList::clear () 00062 { 00063 // only delete the list when we are the master 00064 if (this->_list != NULL) 00065 { 00066 if (this->_master == NULL) 00067 { 00068 // we own the list 00069 this->_list->clear(); 00070 delete this->_list; 00071 } 00072 else 00073 // someone else owns and therefore deletes the list 00074 this->_list = NULL; 00075 } 00076 } 00077 00078 00079 00080 void PointLocatorList::init () 00081 { 00082 libmesh_assert (!this->_list); 00083 00084 if (this->_initialized) 00085 libMesh::err << "ERROR: Already initialized! Will ignore this call..." << std::endl; 00086 00087 else 00088 { 00089 if (this->_master == NULL) 00090 { 00091 START_LOG("init(no master)", "PointLocatorList"); 00092 00093 // We are the master, so we have to build the list. 00094 // First create it, then get a handy reference, and 00095 // then try to speed up by reserving space... 00096 this->_list = new std::vector<std::pair<Point, const Elem *> >; 00097 std::vector<std::pair<Point, const Elem *> >& my_list = *(this->_list); 00098 00099 my_list.clear(); 00100 my_list.reserve(this->_mesh.n_active_elem()); 00101 00102 // fill our list with the centroids and element 00103 // pointers of the mesh. For this use the handy 00104 // element iterators. 00105 MeshBase::const_element_iterator el = _mesh.active_elements_begin(); 00106 const MeshBase::const_element_iterator end = _mesh.active_elements_end(); 00107 00108 for (; el!=end; ++el) 00109 my_list.push_back(std::make_pair((*el)->centroid(), *el)); 00110 00111 STOP_LOG("init(no master)", "PointLocatorList"); 00112 } 00113 00114 else 00115 { 00116 // We are _not_ the master. Let our _list point to 00117 // the master's list. But for this we first transform 00118 // the master in a state for which we are friends 00119 // (this should also beware of a bad master pointer?). 00120 // And make sure the master @e has a list! 00121 const PointLocatorList* my_master = 00122 cast_ptr<const PointLocatorList*>(this->_master); 00123 00124 if (my_master->initialized()) 00125 this->_list = my_master->_list; 00126 else 00127 libmesh_error_msg("ERROR: Initialize master first, then servants!"); 00128 } 00129 } 00130 00131 // ready for take-off 00132 this->_initialized = true; 00133 } 00134 00135 00136 00137 const Elem* PointLocatorList::operator() (const Point& p, const std::set<subdomain_id_type> *allowed_subdomains) const 00138 { 00139 libmesh_assert (this->_initialized); 00140 00141 START_LOG("operator()", "PointLocatorList"); 00142 00143 // Ask the list. This is quite expensive, since 00144 // we loop through the whole list to try to find 00145 // the @e nearest element. 00146 // However, there is not much else to do: when 00147 // we would use bounding boxes like in a tree, 00148 // it may happen that a surface element is just 00149 // in plane with a bounding box face, and quite 00150 // close to it. But when a point comes, this 00151 // point may belong to the bounding box (where the 00152 // coplanar element does @e not belong to). Then 00153 // we would search through the elements in this 00154 // bounding box, while the other bounding box'es 00155 // element is closer, but we simply don't consider 00156 // it! 00157 // 00158 // We _can_, however, use size_sq() instead of size() 00159 // here to avoid repeated calls to std::sqrt(), which is 00160 // pretty expensive. 00161 { 00162 std::vector<std::pair<Point, const Elem *> >& my_list = *(this->_list); 00163 00164 Real last_distance_sq = std::numeric_limits<Real>::max(); 00165 const Elem * last_elem = NULL; 00166 const std::size_t max_index = my_list.size(); 00167 00168 for (std::size_t n=0; n<max_index; n++) 00169 { 00170 // Only consider elements in the allowed_subdomains list, if it exists 00171 if (!allowed_subdomains || 00172 allowed_subdomains->count(my_list[n].second->subdomain_id())) 00173 { 00174 const Real current_distance_sq = Point(my_list[n].first -p).size_sq(); 00175 00176 if (current_distance_sq < last_distance_sq) 00177 { 00178 last_distance_sq = current_distance_sq; 00179 last_elem = my_list[n].second; 00180 } 00181 } 00182 } 00183 00184 // If we found an element, it should be active 00185 libmesh_assert (!last_elem || last_elem->active()); 00186 00187 // If we found an element and have a restriction list, they better match 00188 libmesh_assert (!last_elem || !allowed_subdomains || allowed_subdomains->count(last_elem->subdomain_id())); 00189 00190 STOP_LOG("operator()", "PointLocatorList"); 00191 00192 // return the element 00193 return last_elem; 00194 } 00195 } 00196 00197 00198 00199 void PointLocatorList::enable_out_of_mesh_mode () 00200 { 00201 // This functionality is not yet implemented for PointLocatorList. 00202 libmesh_not_implemented(); 00203 } 00204 00205 00206 00207 void PointLocatorList::disable_out_of_mesh_mode () 00208 { 00209 // This functionality is not yet implemented for PointLocatorList. 00210 libmesh_not_implemented(); 00211 } 00212 00213 00214 void PointLocatorList::set_close_to_point_tol (Real /*close_to_point_tol*/) 00215 { 00216 // This functionality is not yet implemented for PointLocatorList. 00217 libmesh_not_implemented(); 00218 } 00219 00220 00221 void PointLocatorList::unset_close_to_point_tol () 00222 { 00223 // This functionality is not yet implemented for PointLocatorList. 00224 libmesh_not_implemented(); 00225 } 00226 00227 } // namespace libMesh