libMesh
mesh_base.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute 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 // library configuration
21 #include "libmesh/libmesh_config.h"
22 
23 // C++ includes
24 #include <algorithm> // for std::min
25 #include <map> // for std::multimap
26 #include <sstream> // for std::ostringstream
27 #include <unordered_map>
28 
29 // Local includes
30 #include "libmesh/boundary_info.h"
31 #include "libmesh/libmesh_logging.h"
32 #include "libmesh/elem.h"
33 #include "libmesh/ghost_point_neighbors.h"
34 #include "libmesh/mesh_base.h"
35 #include "libmesh/mesh_communication.h"
36 #include "libmesh/mesh_tools.h"
37 #include "libmesh/parallel.h"
38 #include "libmesh/partitioner.h"
39 #include "libmesh/point_locator_base.h"
40 #include "libmesh/threads.h"
41 #include "libmesh/enum_elem_type.h"
42 #include "libmesh/enum_point_locator_type.h"
43 #include "libmesh/auto_ptr.h" // libmesh_make_unique
44 
45 namespace libMesh
46 {
47 
48 
49 
50 // ------------------------------------------------------------
51 // MeshBase class member functions
52 MeshBase::MeshBase (const Parallel::Communicator & comm_in,
53  unsigned char d) :
54  ParallelObject (comm_in),
55  boundary_info (new BoundaryInfo(*this)),
56  _n_parts (1),
57  _default_mapping_type(LAGRANGE_MAP),
58  _default_mapping_data(0),
59  _is_prepared (false),
60  _point_locator (),
61  _count_lower_dim_elems_in_point_locator(true),
62  _partitioner (),
63 #ifdef LIBMESH_ENABLE_UNIQUE_ID
64  _next_unique_id(DofObject::invalid_unique_id),
65 #endif
66  _skip_noncritical_partitioning(false),
67  _skip_all_partitioning(libMesh::on_command_line("--skip-partitioning")),
68  _skip_renumber_nodes_and_elements(false),
69  _allow_remote_element_removal(true),
70  _spatial_dimension(d),
71  _default_ghosting(libmesh_make_unique<GhostPointNeighbors>(*this)),
72  _point_locator_close_to_point_tol(0.)
73 {
74  _elem_dims.insert(d);
76  libmesh_assert_less_equal (LIBMESH_DIM, 3);
77  libmesh_assert_greater_equal (LIBMESH_DIM, d);
79 }
80 
81 
82 
83 MeshBase::MeshBase (const MeshBase & other_mesh) :
84  ParallelObject (other_mesh),
85  boundary_info (new BoundaryInfo(*this)),
86  _n_parts (other_mesh._n_parts),
87  _default_mapping_type(other_mesh._default_mapping_type),
88  _default_mapping_data(other_mesh._default_mapping_data),
89  _is_prepared (other_mesh._is_prepared),
90  _point_locator (),
91  _count_lower_dim_elems_in_point_locator(other_mesh._count_lower_dim_elems_in_point_locator),
92  _partitioner (),
93 #ifdef LIBMESH_ENABLE_UNIQUE_ID
94  _next_unique_id(other_mesh._next_unique_id),
95 #endif
96  _skip_noncritical_partitioning(false),
97  _skip_all_partitioning(libMesh::on_command_line("--skip-partitioning")),
98  _skip_renumber_nodes_and_elements(false),
99  _allow_remote_element_removal(true),
100  _elem_dims(other_mesh._elem_dims),
101  _spatial_dimension(other_mesh._spatial_dimension),
102  _default_ghosting(libmesh_make_unique<GhostPointNeighbors>(*this)),
103  _ghosting_functors(other_mesh._ghosting_functors),
104  _point_locator_close_to_point_tol(other_mesh._point_locator_close_to_point_tol)
105 {
106  // Make sure we don't accidentally delete the other mesh's default
107  // ghosting functor; we'll use our own if that's needed.
108  if (other_mesh._ghosting_functors.count(other_mesh._default_ghosting.get()))
109  {
110  _ghosting_functors.erase(other_mesh._default_ghosting.get());
112  }
113 
114  if (other_mesh._partitioner.get())
115  {
116  _partitioner = other_mesh._partitioner->clone();
117  }
118 }
119 
120 
121 
122 MeshBase::MeshBase(MeshBase &&) = default;
123 
124 
125 
127 {
128  this->clear();
129 
130  libmesh_exceptionless_assert (!libMesh::closed());
131 }
132 
133 
134 
135 unsigned int MeshBase::mesh_dimension() const
136 {
137  if (!_elem_dims.empty())
138  return cast_int<unsigned int>(*_elem_dims.rbegin());
139  return 0;
140 }
141 
142 
143 
144 void MeshBase::set_elem_dimensions(const std::set<unsigned char> & elem_dims)
145 {
146 #ifdef DEBUG
147  // In debug mode, we call cache_elem_dims() and then make sure
148  // the result actually agrees with what the user specified.
149  parallel_object_only();
150 
151  this->cache_elem_dims();
152  libmesh_assert_msg(_elem_dims == elem_dims, \
153  "Specified element dimensions does not match true element dimensions!");
154 #endif
155 
156  _elem_dims = elem_dims;
157 }
158 
159 unsigned int MeshBase::spatial_dimension () const
160 {
161  return cast_int<unsigned int>(_spatial_dimension);
162 }
163 
164 
165 
166 void MeshBase::set_spatial_dimension(unsigned char d)
167 {
168  // The user can set the _spatial_dimension however they wish,
169  // libMesh will only *increase* the spatial dimension, however,
170  // never decrease it.
171  _spatial_dimension = d;
172 }
173 
174 
175 
176 unsigned int MeshBase::add_elem_integer(const std::string & name,
177  bool allocate_data)
178 {
179  for (auto i : index_range(_elem_integer_names))
180  if (_elem_integer_names[i] == name)
181  return i;
182 
183  _elem_integer_names.push_back(name);
184  if (allocate_data)
185  this->size_elem_extra_integers();
186  return _elem_integer_names.size()-1;
187 }
188 
189 
190 
191 std::vector<unsigned int> MeshBase::add_elem_integers(const std::vector<std::string> & names,
192  bool allocate_data)
193 {
194  std::unordered_map<std::string, std::size_t> name_indices;
195  for (auto i : index_range(_elem_integer_names))
196  name_indices[_elem_integer_names[i]] = i;
197 
198  std::vector<unsigned int> returnval(names.size());
199 
200  bool added_an_integer = false;
201  for (auto i : index_range(names))
202  {
203  const std::string & name = names[i];
204  auto it = name_indices.find(name);
205  if (it != name_indices.end())
206  returnval[i] = it->second;
207  else
208  {
209  returnval[i] = _elem_integer_names.size();
210  name_indices[name] = returnval[i];
211  _elem_integer_names.push_back(name);
212  added_an_integer = true;
213  }
214  }
215 
216  if (allocate_data && added_an_integer)
217  this->size_elem_extra_integers();
218 
219  return returnval;
220 }
221 
222 
223 
224 unsigned int MeshBase::get_elem_integer_index(const std::string & name) const
225 {
226  for (auto i : index_range(_elem_integer_names))
227  if (_elem_integer_names[i] == name)
228  return i;
229 
230  libmesh_error_msg("Unknown elem integer " << name);
231  return libMesh::invalid_uint;
232 }
233 
234 
235 
236 bool MeshBase::has_elem_integer(const std::string & name) const
237 {
238  for (auto & entry : _elem_integer_names)
239  if (entry == name)
240  return true;
241 
242  return false;
243 }
244 
245 
246 
247 unsigned int MeshBase::add_node_integer(const std::string & name,
248  bool allocate_data)
249 {
250  for (auto i : index_range(_node_integer_names))
251  if (_node_integer_names[i] == name)
252  return i;
253 
254  _node_integer_names.push_back(name);
255  if (allocate_data)
256  this->size_node_extra_integers();
257  return _node_integer_names.size()-1;
258 }
259 
260 
261 
262 std::vector<unsigned int> MeshBase::add_node_integers(const std::vector<std::string> & names,
263  bool allocate_data)
264 {
265  std::unordered_map<std::string, std::size_t> name_indices;
266  for (auto i : index_range(_node_integer_names))
267  name_indices[_node_integer_names[i]] = i;
268 
269  std::vector<unsigned int> returnval(names.size());
270 
271  bool added_an_integer = false;
272  for (auto i : index_range(names))
273  {
274  const std::string & name = names[i];
275  auto it = name_indices.find(name);
276  if (it != name_indices.end())
277  returnval[i] = it->second;
278  else
279  {
280  returnval[i] = _node_integer_names.size();
281  name_indices[name] = returnval[i];
282  _node_integer_names.push_back(name);
283  added_an_integer = true;
284  }
285  }
286 
287  if (allocate_data && added_an_integer)
288  this->size_node_extra_integers();
289 
290  return returnval;
291 }
292 
293 
294 
295 unsigned int MeshBase::get_node_integer_index(const std::string & name) const
296 {
297  for (auto i : index_range(_node_integer_names))
298  if (_node_integer_names[i] == name)
299  return i;
300 
301  libmesh_error_msg("Unknown node integer " << name);
302  return libMesh::invalid_uint;
303 }
304 
305 
306 
307 bool MeshBase::has_node_integer(const std::string & name) const
308 {
309  for (auto & entry : _node_integer_names)
310  if (entry == name)
311  return true;
312 
313  return false;
314 }
315 
316 
317 
318 void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
319 {
320  LOG_SCOPE("prepare_for_use()", "MeshBase");
321 
322  parallel_object_only();
323 
324  libmesh_assert(this->comm().verify(this->is_serial()));
325 
326  // A distributed mesh may have processors with no elements (or
327  // processors with no elements of higher dimension, if we ever
328  // support mixed-dimension meshes), but we want consistent
329  // mesh_dimension anyways.
330  //
331  // cache_elem_dims() should get the elem_dimensions() and
332  // mesh_dimension() correct later, and we don't need it earlier.
333 
334 
335  // Renumber the nodes and elements so that they in contiguous
336  // blocks. By default, _skip_renumber_nodes_and_elements is false.
337  //
338  // We may currently change that by passing
339  // skip_renumber_nodes_and_elements==true to this function, but we
340  // should use the allow_renumbering() accessor instead.
341  //
342  // Instances where you if prepare_for_use() should not renumber the nodes
343  // and elements include reading in e.g. an xda/r or gmv file. In
344  // this case, the ordering of the nodes may depend on an accompanying
345  // solution, and the node ordering cannot be changed.
346 
347  if (skip_renumber_nodes_and_elements)
348  {
349  libmesh_deprecated();
350  this->allow_renumbering(false);
351  }
352 
353  // Mesh modification operations might not leave us with consistent
354  // id counts, but our partitioner might need that consistency.
355  if (!_skip_renumber_nodes_and_elements)
356  this->renumber_nodes_and_elements();
357  else
358  this->update_parallel_id_counts();
359 
360  // Let all the elements find their neighbors
361  if (!skip_find_neighbors)
362  this->find_neighbors();
363 
364  // The user may have set boundary conditions. We require that the
365  // boundary conditions were set consistently. Because we examine
366  // neighbors when evaluating non-raw boundary condition IDs, this
367  // assert is only valid when our neighbor links are in place.
368 #ifdef DEBUG
370 #endif
371 
372  // Search the mesh for all the dimensions of the elements
373  // and cache them.
374  this->cache_elem_dims();
375 
376  // Search the mesh for elements that have a neighboring element
377  // of dim+1 and set that element as the interior parent
378  this->detect_interior_parents();
379 
380  // Fix up node unique ids in case mesh generation code didn't take
381  // exceptional care to do so.
382  // MeshCommunication().make_node_unique_ids_parallel_consistent(*this);
383 
384  // We're going to still require that mesh generation code gets
385  // element unique ids consistent.
386 #if defined(DEBUG) && defined(LIBMESH_ENABLE_UNIQUE_ID)
388 #endif
389 
390  // Reset our PointLocator. Any old locator is invalidated any time
391  // the elements in the underlying elements in the mesh have changed,
392  // so we clear it here.
393  this->clear_point_locator();
394 
395  // Allow our GhostingFunctor objects to reinit if necessary.
396  // Do this before partitioning and redistributing, and before
397  // deleting remote elements.
398  for (auto & gf : _ghosting_functors)
399  {
400  libmesh_assert(gf);
401  gf->mesh_reinit();
402  }
403 
404  // Partition the mesh unless *all* partitioning is to be skipped.
405  // If only noncritical partitioning is to be skipped, the
406  // partition() call will still check for orphaned nodes.
407  if (!skip_partitioning())
408  this->partition();
409 
410  // If we're using DistributedMesh, we'll probably want it
411  // parallelized.
412  if (this->_allow_remote_element_removal)
413  this->delete_remote_elements();
414 
415  if (!_skip_renumber_nodes_and_elements)
416  this->renumber_nodes_and_elements();
417 
418  // The mesh is now prepared for use.
419  _is_prepared = true;
420 
421 #if defined(DEBUG) && defined(LIBMESH_ENABLE_UNIQUE_ID)
424 #endif
425 }
426 
427 
428 
429 void MeshBase::clear ()
430 {
431  // Reset the number of partitions
432  _n_parts = 1;
433 
434  // Reset the _is_prepared flag
435  _is_prepared = false;
436 
437  // Clear boundary information
438  if (boundary_info)
439  boundary_info->clear();
440 
441  // Clear element dimensions
442  _elem_dims.clear();
443 
444  // Clear our point locator.
445  this->clear_point_locator();
446 }
447 
448 
449 
450 void MeshBase::remove_ghosting_functor(GhostingFunctor & ghosting_functor)
451 {
452  _ghosting_functors.erase(&ghosting_functor);
453 
454  auto it = _shared_functors.find(&ghosting_functor);
455  if (it != _shared_functors.end())
456  _shared_functors.erase(it);
457 }
458 
459 
460 
461 void MeshBase::subdomain_ids (std::set<subdomain_id_type> & ids) const
462 {
463  // This requires an inspection on every processor
464  parallel_object_only();
465 
466  ids.clear();
467 
468  for (const auto & elem : this->active_local_element_ptr_range())
469  ids.insert(elem->subdomain_id());
470 
471  // Some subdomains may only live on other processors
472  this->comm().set_union(ids);
473 }
474 
475 
476 
477 subdomain_id_type MeshBase::n_subdomains() const
478 {
479  // This requires an inspection on every processor
480  parallel_object_only();
481 
482  std::set<subdomain_id_type> ids;
483 
484  this->subdomain_ids (ids);
485 
486  return cast_int<subdomain_id_type>(ids.size());
487 }
488 
489 
490 
491 
492 dof_id_type MeshBase::n_nodes_on_proc (const processor_id_type proc_id) const
493 {
494  // We're either counting a processor's nodes or unpartitioned
495  // nodes
496  libmesh_assert (proc_id < this->n_processors() ||
497  proc_id == DofObject::invalid_processor_id);
498 
499  return static_cast<dof_id_type>(std::distance (this->pid_nodes_begin(proc_id),
500  this->pid_nodes_end (proc_id)));
501 }
502 
503 
504 
505 dof_id_type MeshBase::n_elem_on_proc (const processor_id_type proc_id) const
506 {
507  // We're either counting a processor's elements or unpartitioned
508  // elements
509  libmesh_assert (proc_id < this->n_processors() ||
510  proc_id == DofObject::invalid_processor_id);
511 
512  return static_cast<dof_id_type>(std::distance (this->pid_elements_begin(proc_id),
513  this->pid_elements_end (proc_id)));
514 }
515 
516 
517 
518 dof_id_type MeshBase::n_active_elem_on_proc (const processor_id_type proc_id) const
519 {
520  libmesh_assert_less (proc_id, this->n_processors());
521  return static_cast<dof_id_type>(std::distance (this->active_pid_elements_begin(proc_id),
522  this->active_pid_elements_end (proc_id)));
523 }
524 
525 
526 
527 dof_id_type MeshBase::n_sub_elem () const
528 {
529  dof_id_type ne=0;
530 
531  for (const auto & elem : this->element_ptr_range())
532  ne += elem->n_sub_elem();
533 
534  return ne;
535 }
536 
537 
538 
539 dof_id_type MeshBase::n_active_sub_elem () const
540 {
541  dof_id_type ne=0;
542 
543  for (const auto & elem : this->active_element_ptr_range())
544  ne += elem->n_sub_elem();
545 
546  return ne;
547 }
548 
549 
550 
551 std::string MeshBase::get_info() const
552 {
553  std::ostringstream oss;
554 
555  oss << " Mesh Information:" << '\n';
556 
557  if (!_elem_dims.empty())
558  {
559  oss << " elem_dimensions()={";
560  std::copy(_elem_dims.begin(),
561  --_elem_dims.end(), // --end() is valid if the set is non-empty
562  std::ostream_iterator<unsigned int>(oss, ", "));
563  oss << cast_int<unsigned int>(*_elem_dims.rbegin());
564  oss << "}\n";
565  }
566 
567  oss << " spatial_dimension()=" << this->spatial_dimension() << '\n'
568  << " n_nodes()=" << this->n_nodes() << '\n'
569  << " n_local_nodes()=" << this->n_local_nodes() << '\n'
570  << " n_elem()=" << this->n_elem() << '\n'
571  << " n_local_elem()=" << this->n_local_elem() << '\n'
572 #ifdef LIBMESH_ENABLE_AMR
573  << " n_active_elem()=" << this->n_active_elem() << '\n'
574 #endif
575  << " n_subdomains()=" << static_cast<std::size_t>(this->n_subdomains()) << '\n'
576  << " n_partitions()=" << static_cast<std::size_t>(this->n_partitions()) << '\n'
577  << " n_processors()=" << static_cast<std::size_t>(this->n_processors()) << '\n'
578  << " n_threads()=" << static_cast<std::size_t>(libMesh::n_threads()) << '\n'
579  << " processor_id()=" << static_cast<std::size_t>(this->processor_id()) << '\n';
580 
581  return oss.str();
582 }
583 
584 
585 void MeshBase::print_info(std::ostream & os) const
586 {
587  os << this->get_info()
588  << std::endl;
589 }
590 
591 
592 std::ostream & operator << (std::ostream & os, const MeshBase & m)
593 {
594  m.print_info(os);
595  return os;
596 }
597 
598 
599 void MeshBase::partition (const unsigned int n_parts)
600 {
601  // If we get here and we have unpartitioned elements, we need that
602  // fixed.
603  if (this->n_unpartitioned_elem() > 0)
604  {
605  libmesh_assert (partitioner().get());
606  libmesh_assert (this->is_serial());
607  partitioner()->partition (*this, n_parts);
608  }
609  // A nullptr partitioner or a skip_partitioning(true) call or a
610  // skip_noncritical_partitioning(true) call means don't repartition;
611  // skip_noncritical_partitioning() checks all these.
612  else if (!skip_noncritical_partitioning())
613  {
614  partitioner()->partition (*this, n_parts);
615  }
616  else
617  {
618  // Adaptive coarsening may have "orphaned" nodes on processors
619  // whose elements no longer share them. We need to check for
620  // and possibly fix that.
622 
623  // Make sure locally cached partition count is correct
624  this->recalculate_n_partitions();
625 
626  // Make sure any other locally cached data is correct
627  this->update_post_partitioning();
628  }
629 }
630 
631 unsigned int MeshBase::recalculate_n_partitions()
632 {
633  // This requires an inspection on every processor
634  parallel_object_only();
635 
636  unsigned int max_proc_id=0;
637 
638  for (const auto & elem : this->active_local_element_ptr_range())
639  max_proc_id = std::max(max_proc_id, static_cast<unsigned int>(elem->processor_id()));
640 
641  // The number of partitions is one more than the max processor ID.
642  _n_parts = max_proc_id+1;
643 
644  this->comm().max(_n_parts);
645 
646  return _n_parts;
647 }
648 
649 
650 
651 #ifdef LIBMESH_ENABLE_DEPRECATED
652 const PointLocatorBase & MeshBase::point_locator () const
653 {
654  libmesh_deprecated();
655 
656  if (_point_locator.get() == nullptr)
657  {
658  // PointLocator construction may not be safe within threads
660 
661  _point_locator = PointLocatorBase::build(TREE_ELEMENTS, *this);
662 
663  if (_point_locator_close_to_point_tol > 0.)
664  _point_locator->set_close_to_point_tol(_point_locator_close_to_point_tol);
665  }
666 
667  return *_point_locator;
668 }
669 #endif
670 
671 
672 std::unique_ptr<PointLocatorBase> MeshBase::sub_point_locator () const
673 {
674  // If there's no master point locator, then we need one.
675  if (_point_locator.get() == nullptr)
676  {
677  // PointLocator construction may not be safe within threads
679 
680  // And it may require parallel communication
681  parallel_object_only();
682 
683  _point_locator = PointLocatorBase::build(TREE_ELEMENTS, *this);
684 
685  if (_point_locator_close_to_point_tol > 0.)
686  _point_locator->set_close_to_point_tol(_point_locator_close_to_point_tol);
687  }
688 
689  // Otherwise there was a master point locator, and we can grab a
690  // sub-locator easily.
691  return PointLocatorBase::build(TREE_ELEMENTS, *this, _point_locator.get());
692 }
693 
694 
695 
696 void MeshBase::clear_point_locator ()
697 {
698  _point_locator.reset(nullptr);
699 }
700 
701 
702 
703 void MeshBase::set_count_lower_dim_elems_in_point_locator(bool count_lower_dim_elems)
704 {
705  _count_lower_dim_elems_in_point_locator = count_lower_dim_elems;
706 }
707 
708 
709 
710 bool MeshBase::get_count_lower_dim_elems_in_point_locator() const
711 {
712  return _count_lower_dim_elems_in_point_locator;
713 }
714 
715 
716 
717 std::string & MeshBase::subdomain_name(subdomain_id_type id)
718 {
719  return _block_id_to_name[id];
720 }
721 
722 const std::string & MeshBase::subdomain_name(subdomain_id_type id) const
723 {
724  // An empty string to return when no matching subdomain name is found
725  static const std::string empty;
726 
727  std::map<subdomain_id_type, std::string>::const_iterator iter = _block_id_to_name.find(id);
728  if (iter == _block_id_to_name.end())
729  return empty;
730  else
731  return iter->second;
732 }
733 
734 
735 
736 
737 subdomain_id_type MeshBase::get_id_by_name(const std::string & name) const
738 {
739  // Linear search over the map values.
740  std::map<subdomain_id_type, std::string>::const_iterator
741  iter = _block_id_to_name.begin(),
742  end_iter = _block_id_to_name.end();
743 
744  for ( ; iter != end_iter; ++iter)
745  if (iter->second == name)
746  return iter->first;
747 
748  // If we made it here without returning, we don't have a subdomain
749  // with the requested name, so return Elem::invalid_subdomain_id.
750  return Elem::invalid_subdomain_id;
751 }
752 
753 void MeshBase::cache_elem_dims()
754 {
755  // This requires an inspection on every processor
756  parallel_object_only();
757 
758  // Need to clear _elem_dims first in case all elements of a
759  // particular dimension have been deleted.
760  _elem_dims.clear();
761 
762  for (const auto & elem : this->active_element_ptr_range())
763  _elem_dims.insert(cast_int<unsigned char>(elem->dim()));
764 
765  // Some different dimension elements may only live on other processors
766  this->comm().set_union(_elem_dims);
767 
768  // If the largest element dimension found is larger than the current
769  // _spatial_dimension, increase _spatial_dimension.
770  unsigned int max_dim = this->mesh_dimension();
771  if (max_dim > _spatial_dimension)
772  _spatial_dimension = cast_int<unsigned char>(max_dim);
773 
774  // _spatial_dimension may need to increase from 1->2 or 2->3 if the
775  // mesh is full of 1D elements but they are not x-aligned, or the
776  // mesh is full of 2D elements but they are not in the x-y plane.
777  // If the mesh is x-aligned or x-y planar, we will end up checking
778  // every node's coordinates and not breaking out of the loop
779  // early...
780 #if LIBMESH_DIM > 1
781  if (_spatial_dimension < 3)
782  {
783  for (const auto & node : this->node_ptr_range())
784  {
785  // Note: the exact floating point comparison is intentional,
786  // we don't want to get tripped up by tolerances.
787  if ((*node)(1) != 0.)
788  {
789  _spatial_dimension = 2;
790 #if LIBMESH_DIM == 2
791  // If libmesh is compiled in 2D mode, this is the
792  // largest spatial dimension possible so we can break
793  // out.
794  break;
795 #endif
796  }
797 
798 #if LIBMESH_DIM > 2
799  if ((*node)(2) != 0.)
800  {
801  // Spatial dimension can't get any higher than this, so
802  // we can break out.
803  _spatial_dimension = 3;
804  break;
805  }
806 #endif
807  }
808  }
809 #endif // LIBMESH_DIM > 1
810 }
811 
812 void MeshBase::detect_interior_parents()
813 {
814  // This requires an inspection on every processor
815  parallel_object_only();
816 
817  // Check if the mesh contains mixed dimensions. If so, then set interior parents, otherwise return.
818  if (this->elem_dimensions().size() == 1)
819  return;
820 
821  //This map will be used to set interior parents
822  std::unordered_map<dof_id_type, std::vector<dof_id_type>> node_to_elem;
823 
824  for (const auto & elem : this->active_element_ptr_range())
825  {
826  // Populating the node_to_elem map, same as MeshTools::build_nodes_to_elem_map
827  for (auto n : IntRange<unsigned int>(0, elem->n_vertices()))
828  {
829  libmesh_assert_less (elem->id(), this->max_elem_id());
830 
831  node_to_elem[elem->node_id(n)].push_back(elem->id());
832  }
833  }
834 
835  // Automatically set interior parents
836  for (const auto & element : this->element_ptr_range())
837  {
838  // Ignore an 3D element or an element that already has an interior parent
839  if (element->dim()>=LIBMESH_DIM || element->interior_parent())
840  continue;
841 
842  // Start by generating a SET of elements that are dim+1 to the current
843  // element at each vertex of the current element, thus ignoring interior nodes.
844  // If one of the SET of elements is empty, then we will not have an interior parent
845  // since an interior parent must be connected to all vertices of the current element
846  std::vector<std::set<dof_id_type>> neighbors( element->n_vertices() );
847 
848  bool found_interior_parents = false;
849 
850  for (auto n : IntRange<unsigned int>(0, element->n_vertices()))
851  {
852  std::vector<dof_id_type> & element_ids = node_to_elem[element->node_id(n)];
853  for (const auto & eid : element_ids)
854  if (this->elem_ref(eid).dim() == element->dim()+1)
855  neighbors[n].insert(eid);
856 
857  if (neighbors[n].size()>0)
858  {
859  found_interior_parents = true;
860  }
861  else
862  {
863  // We have found an empty set, no reason to continue
864  // Ensure we set this flag to false before the break since it could have
865  // been set to true for previous vertex
866  found_interior_parents = false;
867  break;
868  }
869  }
870 
871  // If we have successfully generated a set of elements for each vertex, we will compare
872  // the set for vertex 0 will the sets for the vertices until we find a id that exists in
873  // all sets. If found, this is our an interior parent id. The interior parent id found
874  // will be the lowest element id if there is potential for multiple interior parents.
875  if (found_interior_parents)
876  {
877  std::set<dof_id_type> & neighbors_0 = neighbors[0];
878  for (const auto & interior_parent_id : neighbors_0)
879  {
880  found_interior_parents = false;
881  for (auto n : IntRange<unsigned int>(1, element->n_vertices()))
882  {
883  if (neighbors[n].find(interior_parent_id)!=neighbors[n].end())
884  {
885  found_interior_parents=true;
886  }
887  else
888  {
889  found_interior_parents=false;
890  break;
891  }
892  }
893  if (found_interior_parents)
894  {
895  element->set_interior_parent(this->elem_ptr(interior_parent_id));
896  break;
897  }
898  }
899  }
900  }
901 }
902 
903 
904 
905 void MeshBase::set_point_locator_close_to_point_tol(Real val)
906 {
907  _point_locator_close_to_point_tol = val;
908  if (_point_locator)
909  {
910  if (val > 0.)
911  _point_locator->set_close_to_point_tol(val);
912  else
913  _point_locator->unset_close_to_point_tol();
914  }
915 }
916 
917 
918 
919 Real MeshBase::get_point_locator_close_to_point_tol() const
920 {
921  return _point_locator_close_to_point_tol;
922 }
923 
924 
925 
926 void MeshBase::size_elem_extra_integers()
927 {
928  const std::size_t new_size = _elem_integer_names.size();
929  for (auto elem : this->element_ptr_range())
930  elem->add_extra_integers(new_size);
931 }
932 
933 
934 
935 void MeshBase::size_node_extra_integers()
936 {
937  const std::size_t new_size = _node_integer_names.size();
938  for (auto node : this->node_ptr_range())
939  node->add_extra_integers(new_size);
940 }
941 
942 
943 std::pair<std::vector<unsigned int>, std::vector<unsigned int>>
944 MeshBase::merge_extra_integer_names(const MeshBase & other)
945 {
946  std::pair<std::vector<unsigned int>, std::vector<unsigned int>> returnval;
947  returnval.first = this->add_elem_integers(other._elem_integer_names);
948  returnval.second = this->add_node_integers(other._node_integer_names);
949  return returnval;
950 }
951 
952 
953 } // namespace libMesh
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::BoundaryInfo
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Definition: boundary_info.h:57
libMesh::invalid_uint
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value.
Definition: libmesh.h:249
libMesh::MeshTools::n_elem
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:705
libMesh::MeshBase::_elem_dims
std::set< unsigned char > _elem_dims
We cache the dimension of the elements present in the mesh.
Definition: mesh_base.h:1768
libMesh::MeshTools::libmesh_assert_valid_boundary_ids
void libmesh_assert_valid_boundary_ids(const MeshBase &mesh)
A function for verifying that boundary condition ids match across processors.
Definition: mesh_tools.C:1396
libMesh::MeshBase::_default_ghosting
std::unique_ptr< GhostingFunctor > _default_ghosting
The default geometric GhostingFunctor, used to implement standard libMesh element ghosting behavior.
Definition: mesh_base.h:1812
libMesh::n_threads
unsigned int n_threads()
Definition: libmesh_base.h:96
libMesh::MeshBase::add_elem_integers
std::vector< unsigned int > add_elem_integers(const std::vector< std::string > &names, bool allocate_data=true)
Register integer data (of type dof_id_type) to be added to each element in the mesh,...
Definition: mesh_base.C:191
libMesh::MeshBase::set_elem_dimensions
void set_elem_dimensions(const std::set< unsigned char > &elem_dims)
Most of the time you should not need to call this, as the element dimensions will be set automaticall...
Definition: mesh_base.C:144
libMesh::TREE_ELEMENTS
Definition: enum_point_locator_type.h:37
libMesh::index_range
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:106
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::operator<<
std::ostream & operator<<(std::ostream &os, const MeshBase &m)
Definition: mesh_base.C:592
libMesh::GhostPointNeighbors
This class implements the default geometry ghosting in libMesh: point neighbors and interior_parent e...
Definition: ghost_point_neighbors.h:36
libMesh::MeshBase::mesh_dimension
unsigned int mesh_dimension() const
Definition: mesh_base.C:135
libMesh::DofObject
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
Definition: dof_object.h:53
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::MeshBase::MeshBase
MeshBase(const Parallel::Communicator &comm_in, unsigned char dim=1)
Constructor.
Definition: mesh_base.C:52
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::IntRange
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
Definition: int_range.h:53
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
libMesh::MeshTools::libmesh_assert_valid_unique_ids
void libmesh_assert_valid_unique_ids(const MeshBase &mesh)
A function for verifying that unique ids match across processors.
Definition: mesh_tools.C:1634
libMesh::MeshBase::_spatial_dimension
unsigned char _spatial_dimension
The "spatial dimension" of the Mesh.
Definition: mesh_base.h:1774
libMesh::MeshBase::_elem_integer_names
std::vector< std::string > _elem_integer_names
The array of names for integer data associated with each element in the mesh.
Definition: mesh_base.h:1780
libMesh::Threads::in_threads
bool in_threads
A boolean which is true iff we are in a Threads:: function It may be useful to assert(!...
Definition: threads.C:31
libMesh::GhostingFunctor
This abstract base class defines the interface by which library code and user code can report associa...
Definition: ghosting_functor.h:153
libMesh::processor_id_type
uint8_t processor_id_type
Definition: id_types.h:104
libMesh::MeshBase::add_elem_integer
unsigned int add_elem_integer(const std::string &name, bool allocate_data=true)
Register an integer datum (of type dof_id_type) to be added to each element in the mesh.
Definition: mesh_base.C:176
libMesh::MeshBase::size_elem_extra_integers
void size_elem_extra_integers()
Size extra-integer arrays of all elements in the mesh.
Definition: mesh_base.C:926
libMesh::MeshBase::_ghosting_functors
std::set< GhostingFunctor * > _ghosting_functors
The list of all GhostingFunctor objects to be used when distributing a DistributedMesh.
Definition: mesh_base.h:1821
libMesh::MeshBase::spatial_dimension
unsigned int spatial_dimension() const
Definition: mesh_base.C:159
n_nodes
const dof_id_type n_nodes
Definition: tecplot_io.C:68
libMesh::MeshBase::_node_integer_names
std::vector< std::string > _node_integer_names
The array of names for integer data associated with each node in the mesh.
Definition: mesh_base.h:1786
libMesh::MeshBase::cache_elem_dims
void cache_elem_dims()
Search the mesh and cache the different dimensions of the elements present in the mesh.
Definition: mesh_base.C:753
libMesh::MeshBase::_partitioner
std::unique_ptr< Partitioner > _partitioner
A partitioner to use at each prepare_for_use().
Definition: mesh_base.h:1721
libMesh::initialized
bool initialized()
Checks that library initialization has been done.
Definition: libmesh.C:265
libMesh::LAGRANGE_MAP
Definition: enum_elem_type.h:83
distance
Real distance(const Point &p)
Definition: subdomains_ex3.C:50
libMesh::ReferenceElem::get
const Elem & get(const ElemType type_in)
Definition: reference_elem.C:237
libMesh::MeshBase::print_info
void print_info(std::ostream &os=libMesh::out) const
Prints relevant information about the mesh.
Definition: mesh_base.C:585
libMesh::on_command_line
bool on_command_line(std::string arg)
Definition: libmesh.C:898
libMesh::TestClass
Definition: id_types.h:33
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::ParallelObject
An object whose state is distributed along a set of processors.
Definition: parallel_object.h:55
libMesh::MeshBase::clear
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:429
libMesh::MeshBase::~MeshBase
virtual ~MeshBase()
Destructor.
Definition: mesh_base.C:126
libMesh::PointLocatorBase
This is the base class for point locators.
Definition: point_locator_base.h:62
libMesh::MeshTools::correct_node_proc_ids
void correct_node_proc_ids(MeshBase &)
Changes the processor ids on each node so be the same as the id of the lowest element touching that n...
Definition: mesh_tools.C:2252
libMesh::Quality::name
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
libMesh::MeshBase::set_spatial_dimension
void set_spatial_dimension(unsigned char d)
Sets the "spatial dimension" of the Mesh.
Definition: mesh_base.C:166
libMesh::closed
bool closed()
Checks that the library has been closed.
Definition: libmesh.C:272