$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 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 // library configuration 00021 #include "libmesh/libmesh_config.h" 00022 00023 // C++ includes 00024 #include <algorithm> // for std::min 00025 #include <map> // for std::multimap 00026 #include <sstream> // for std::ostringstream 00027 00028 00029 // Local includes 00030 #include "libmesh/boundary_info.h" 00031 #include "libmesh/elem.h" 00032 #include "libmesh/mesh_base.h" 00033 #include "libmesh/parallel.h" 00034 #include "libmesh/partitioner.h" 00035 #include "libmesh/point_locator_base.h" 00036 #include "libmesh/threads.h" 00037 00038 namespace libMesh 00039 { 00040 00041 00042 00043 // ------------------------------------------------------------ 00044 // MeshBase class member functions 00045 MeshBase::MeshBase (const Parallel::Communicator &comm_in, 00046 unsigned char d) : 00047 ParallelObject (comm_in), 00048 boundary_info (new BoundaryInfo(*this)), 00049 _n_parts (1), 00050 _is_prepared (false), 00051 _point_locator (), 00052 _partitioner (), 00053 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00054 _next_unique_id(DofObject::invalid_unique_id), 00055 #endif 00056 _skip_partitioning(libMesh::on_command_line("--skip-partitioning")), 00057 _skip_renumber_nodes_and_elements(false) 00058 { 00059 _elem_dims.insert(d); 00060 libmesh_assert_less_equal (LIBMESH_DIM, 3); 00061 libmesh_assert_greater_equal (LIBMESH_DIM, d); 00062 libmesh_assert (libMesh::initialized()); 00063 } 00064 00065 00066 #ifndef LIBMESH_DISABLE_COMMWORLD 00067 MeshBase::MeshBase (unsigned char d) : 00068 ParallelObject (CommWorld), 00069 boundary_info (new BoundaryInfo(*this)), 00070 _n_parts (1), 00071 _is_prepared (false), 00072 _point_locator (), 00073 _partitioner (), 00074 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00075 _next_unique_id(DofObject::invalid_unique_id), 00076 #endif 00077 _skip_partitioning(libMesh::on_command_line("--skip-partitioning")), 00078 _skip_renumber_nodes_and_elements(false) 00079 { 00080 _elem_dims.insert(d); 00081 libmesh_assert_less_equal (LIBMESH_DIM, 3); 00082 libmesh_assert_greater_equal (LIBMESH_DIM, d); 00083 libmesh_assert (libMesh::initialized()); 00084 } 00085 #endif // !LIBMESH_DISABLE_COMMWORLD 00086 00087 00088 00089 MeshBase::MeshBase (const MeshBase& other_mesh) : 00090 ParallelObject (other_mesh), 00091 boundary_info (new BoundaryInfo(*this)), 00092 _n_parts (other_mesh._n_parts), 00093 _is_prepared (other_mesh._is_prepared), 00094 _point_locator (), 00095 _partitioner (), 00096 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00097 _next_unique_id(other_mesh._next_unique_id), 00098 #endif 00099 _skip_partitioning(libMesh::on_command_line("--skip-partitioning")), 00100 _skip_renumber_nodes_and_elements(false), 00101 _elem_dims(other_mesh._elem_dims) 00102 { 00103 if(other_mesh._partitioner.get()) 00104 { 00105 _partitioner = other_mesh._partitioner->clone(); 00106 } 00107 } 00108 00109 00110 00111 MeshBase::~MeshBase() 00112 { 00113 this->clear(); 00114 00115 libmesh_exceptionless_assert (!libMesh::closed()); 00116 } 00117 00118 unsigned int MeshBase::mesh_dimension() const 00119 { 00120 libmesh_assert(!_elem_dims.empty()); 00121 return cast_int<unsigned int>(*_elem_dims.rbegin()); 00122 } 00123 00124 void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors) 00125 { 00126 parallel_object_only(); 00127 00128 libmesh_assert(this->comm().verify(this->is_serial())); 00129 00130 // A distributed mesh may have processors with no elements (or 00131 // processors with no elements of higher dimension, if we ever 00132 // support mixed-dimension meshes), but we want consistent 00133 // mesh_dimension anyways. 00134 // 00135 // cache_elem_dims() should get the elem_dimensions() and 00136 // mesh_dimension() correct later, and we don't need it earlier. 00137 00138 00139 // Renumber the nodes and elements so that they in contiguous 00140 // blocks. By default, _skip_renumber_nodes_and_elements is false. 00141 // 00142 // We may currently change that by passing 00143 // skip_renumber_nodes_and_elements==true to this function, but we 00144 // should use the allow_renumbering() accessor instead. 00145 // 00146 // Instances where you if prepare_for_use() should not renumber the nodes 00147 // and elements include reading in e.g. an xda/r or gmv file. In 00148 // this case, the ordering of the nodes may depend on an accompanying 00149 // solution, and the node ordering cannot be changed. 00150 00151 if (skip_renumber_nodes_and_elements) 00152 { 00153 libmesh_deprecated(); 00154 this->allow_renumbering(false); 00155 } 00156 00157 // Mesh modification operations might not leave us with consistent 00158 // id counts, but our partitioner might need that consistency. 00159 if(!_skip_renumber_nodes_and_elements) 00160 this->renumber_nodes_and_elements(); 00161 else 00162 this->update_parallel_id_counts(); 00163 00164 // Let all the elements find their neighbors 00165 if(!skip_find_neighbors) 00166 this->find_neighbors(); 00167 00168 // Partition the mesh. 00169 this->partition(); 00170 00171 // If we're using ParallelMesh, we'll want it parallelized. 00172 this->delete_remote_elements(); 00173 00174 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00175 // Assign DOF object unique ids 00176 this->assign_unique_ids(); 00177 #endif 00178 00179 if(!_skip_renumber_nodes_and_elements) 00180 this->renumber_nodes_and_elements(); 00181 00182 // Search the mesh for all the dimensions of the elements 00183 // and cache them. 00184 this->cache_elem_dims(); 00185 00186 // Reset our PointLocator. This needs to happen any time the elements 00187 // in the underlying elements in the mesh have changed, so we do it here. 00188 this->clear_point_locator(); 00189 00190 // The mesh is now prepared for use. 00191 _is_prepared = true; 00192 } 00193 00194 00195 00196 void MeshBase::clear () 00197 { 00198 // Reset the number of partitions 00199 _n_parts = 1; 00200 00201 // Reset the _is_prepared flag 00202 _is_prepared = false; 00203 00204 // Clear boundary information 00205 this->get_boundary_info().clear(); 00206 00207 // Clear element dimensions 00208 _elem_dims.clear(); 00209 00210 // Clear our point locator. 00211 this->clear_point_locator(); 00212 } 00213 00214 00215 00216 void MeshBase::subdomain_ids (std::set<subdomain_id_type> &ids) const 00217 { 00218 // This requires an inspection on every processor 00219 parallel_object_only(); 00220 00221 ids.clear(); 00222 00223 const_element_iterator el = this->active_local_elements_begin(); 00224 const_element_iterator end = this->active_local_elements_end(); 00225 00226 for (; el!=end; ++el) 00227 ids.insert((*el)->subdomain_id()); 00228 00229 // Some subdomains may only live on other processors 00230 this->comm().set_union(ids); 00231 } 00232 00233 00234 00235 subdomain_id_type MeshBase::n_subdomains() const 00236 { 00237 // This requires an inspection on every processor 00238 parallel_object_only(); 00239 00240 std::set<subdomain_id_type> ids; 00241 00242 this->subdomain_ids (ids); 00243 00244 return cast_int<subdomain_id_type>(ids.size()); 00245 } 00246 00247 00248 00249 00250 dof_id_type MeshBase::n_nodes_on_proc (const processor_id_type proc_id) const 00251 { 00252 // We're either counting a processor's nodes or unpartitioned 00253 // nodes 00254 libmesh_assert (proc_id < this->n_processors() || 00255 proc_id == DofObject::invalid_processor_id); 00256 00257 return static_cast<dof_id_type>(std::distance (this->pid_nodes_begin(proc_id), 00258 this->pid_nodes_end (proc_id))); 00259 } 00260 00261 00262 00263 dof_id_type MeshBase::n_elem_on_proc (const processor_id_type proc_id) const 00264 { 00265 // We're either counting a processor's elements or unpartitioned 00266 // elements 00267 libmesh_assert (proc_id < this->n_processors() || 00268 proc_id == DofObject::invalid_processor_id); 00269 00270 return static_cast<dof_id_type>(std::distance (this->pid_elements_begin(proc_id), 00271 this->pid_elements_end (proc_id))); 00272 } 00273 00274 00275 00276 dof_id_type MeshBase::n_active_elem_on_proc (const processor_id_type proc_id) const 00277 { 00278 libmesh_assert_less (proc_id, this->n_processors()); 00279 return static_cast<dof_id_type>(std::distance (this->active_pid_elements_begin(proc_id), 00280 this->active_pid_elements_end (proc_id))); 00281 } 00282 00283 00284 00285 dof_id_type MeshBase::n_sub_elem () const 00286 { 00287 dof_id_type ne=0; 00288 00289 const_element_iterator el = this->elements_begin(); 00290 const const_element_iterator end = this->elements_end(); 00291 00292 for (; el!=end; ++el) 00293 ne += (*el)->n_sub_elem(); 00294 00295 return ne; 00296 } 00297 00298 00299 00300 dof_id_type MeshBase::n_active_sub_elem () const 00301 { 00302 dof_id_type ne=0; 00303 00304 const_element_iterator el = this->active_elements_begin(); 00305 const const_element_iterator end = this->active_elements_end(); 00306 00307 for (; el!=end; ++el) 00308 ne += (*el)->n_sub_elem(); 00309 00310 return ne; 00311 } 00312 00313 00314 00315 std::string MeshBase::get_info() const 00316 { 00317 std::ostringstream oss; 00318 00319 oss << " Mesh Information:" << '\n' 00320 << " elem_dimensions()={"; 00321 { 00322 std::set<unsigned char>::const_iterator it = 00323 this->elem_dimensions().begin(); 00324 if (it != this->elem_dimensions().end()) 00325 oss << *it; 00326 for (; it != this->elem_dimensions().end(); ++it) 00327 oss << ',' << *it; 00328 } 00329 oss << " spatial_dimension()=" << this->spatial_dimension() << '\n' 00330 << " n_nodes()=" << this->n_nodes() << '\n' 00331 << " n_local_nodes()=" << this->n_local_nodes() << '\n' 00332 << " n_elem()=" << this->n_elem() << '\n' 00333 << " n_local_elem()=" << this->n_local_elem() << '\n' 00334 #ifdef LIBMESH_ENABLE_AMR 00335 << " n_active_elem()=" << this->n_active_elem() << '\n' 00336 #endif 00337 << " n_subdomains()=" << static_cast<std::size_t>(this->n_subdomains()) << '\n' 00338 << " n_partitions()=" << static_cast<std::size_t>(this->n_partitions()) << '\n' 00339 << " n_processors()=" << static_cast<std::size_t>(this->n_processors()) << '\n' 00340 << " n_threads()=" << static_cast<std::size_t>(libMesh::n_threads()) << '\n' 00341 << " processor_id()=" << static_cast<std::size_t>(this->processor_id()) << '\n'; 00342 00343 return oss.str(); 00344 } 00345 00346 00347 void MeshBase::print_info(std::ostream& os) const 00348 { 00349 os << this->get_info() 00350 << std::endl; 00351 } 00352 00353 00354 std::ostream& operator << (std::ostream& os, const MeshBase& m) 00355 { 00356 m.print_info(os); 00357 return os; 00358 } 00359 00360 00361 void MeshBase::partition (const unsigned int n_parts) 00362 { 00363 // If we get here and we have unpartitioned elements, we need that 00364 // fixed. 00365 if (this->n_unpartitioned_elem() > 0) 00366 { 00367 libmesh_assert (partitioner().get()); 00368 libmesh_assert (this->is_serial()); 00369 partitioner()->partition (*this, n_parts); 00370 } 00371 // NULL partitioner means don't repartition 00372 // Non-serial meshes may not be ready for repartitioning here. 00373 else if(!skip_partitioning() && 00374 partitioner().get() && 00375 this->is_serial()) 00376 { 00377 partitioner()->partition (*this, n_parts); 00378 } 00379 else 00380 { 00381 // Adaptive coarsening may have "orphaned" nodes on processors 00382 // whose elements no longer share them. We need to check for 00383 // and possibly fix that. 00384 Partitioner::set_node_processor_ids(*this); 00385 00386 // Make sure locally cached partition count 00387 this->recalculate_n_partitions(); 00388 00389 // Make sure any other locally cached data is correct 00390 this->update_post_partitioning(); 00391 } 00392 } 00393 00394 unsigned int MeshBase::recalculate_n_partitions() 00395 { 00396 // This requires an inspection on every processor 00397 parallel_object_only(); 00398 00399 const_element_iterator el = this->active_local_elements_begin(); 00400 const_element_iterator end = this->active_local_elements_end(); 00401 00402 unsigned int max_proc_id=0; 00403 00404 for (; el!=end; ++el) 00405 max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id())); 00406 00407 // The number of partitions is one more than the max processor ID. 00408 _n_parts = max_proc_id+1; 00409 00410 this->comm().max(_n_parts); 00411 00412 return _n_parts; 00413 } 00414 00415 00416 00417 const PointLocatorBase& MeshBase::point_locator () const 00418 { 00419 libmesh_deprecated(); 00420 00421 if (_point_locator.get() == NULL) 00422 { 00423 // PointLocator construction may not be safe within threads 00424 libmesh_assert(!Threads::in_threads); 00425 00426 _point_locator.reset (PointLocatorBase::build(TREE_ELEMENTS, *this).release()); 00427 } 00428 00429 return *_point_locator; 00430 } 00431 00432 00433 UniquePtr<PointLocatorBase> MeshBase::sub_point_locator () const 00434 { 00435 // If there's no master point locator, then we need one. 00436 if (_point_locator.get() == NULL) 00437 { 00438 // PointLocator construction may not be safe within threads 00439 libmesh_assert(!Threads::in_threads); 00440 00441 // And it may require parallel communication 00442 parallel_object_only(); 00443 00444 _point_locator.reset (PointLocatorBase::build(TREE_ELEMENTS, *this).release()); 00445 } 00446 00447 // Otherwise there was a master point locator, and we can grab a 00448 // sub-locator easily. 00449 return PointLocatorBase::build(TREE_ELEMENTS, *this, _point_locator.get()); 00450 } 00451 00452 00453 00454 void MeshBase::clear_point_locator () 00455 { 00456 _point_locator.reset(NULL); 00457 } 00458 00459 00460 00461 std::string& MeshBase::subdomain_name(subdomain_id_type id) 00462 { 00463 return _block_id_to_name[id]; 00464 } 00465 00466 const std::string& MeshBase::subdomain_name(subdomain_id_type id) const 00467 { 00468 // An empty string to return when no matching subdomain name is found 00469 static const std::string empty; 00470 00471 std::map<subdomain_id_type, std::string>::const_iterator iter = _block_id_to_name.find(id); 00472 if (iter == _block_id_to_name.end()) 00473 return empty; 00474 else 00475 return iter->second; 00476 } 00477 00478 00479 00480 00481 subdomain_id_type MeshBase::get_id_by_name(const std::string& name) const 00482 { 00483 // Linear search over the map values. 00484 std::map<subdomain_id_type, std::string>::const_iterator 00485 iter = _block_id_to_name.begin(), 00486 end_iter = _block_id_to_name.end(); 00487 00488 for ( ; iter != end_iter; ++iter) 00489 if (iter->second == name) 00490 return iter->first; 00491 00492 // If we made it here without returning, we don't have a subdomain 00493 // with the requested name, so return Elem::invalid_subdomain_id. 00494 return Elem::invalid_subdomain_id; 00495 } 00496 00497 void MeshBase::cache_elem_dims() 00498 { 00499 // This requires an inspection on every processor 00500 parallel_object_only(); 00501 00502 const_element_iterator el = this->active_local_elements_begin(); 00503 const_element_iterator end = this->active_local_elements_end(); 00504 00505 for (; el!=end; ++el) 00506 _elem_dims.insert((*el)->dim()); 00507 00508 // Some different dimension elements may only live on other processors 00509 this->comm().set_union(_elem_dims); 00510 } 00511 00512 } // namespace libMesh