$extrastylesheet
mesh_base.C
Go to the documentation of this file.
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