mesh_refinement.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it 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 // C++ includes
20 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
21 #include <cmath> // for isnan(), when it's defined
22 #include <limits>
23 
24 // Local includes
25 #include "libmesh/libmesh_config.h"
26 
27 // only compile these functions if the user requests AMR support
28 #ifdef LIBMESH_ENABLE_AMR
29 
30 #include "libmesh/boundary_info.h"
31 #include "libmesh/error_vector.h"
33 #include "libmesh/mesh_base.h"
36 #include "libmesh/parallel.h"
38 #include "libmesh/partitioner.h"
39 #include "libmesh/remote_elem.h"
41 
42 #ifdef DEBUG
43 // Some extra validation for DistributedMesh
44 #include "libmesh/mesh_tools.h"
45 #endif // DEBUG
46 
47 #ifdef LIBMESH_ENABLE_PERIODIC
49 #endif
50 
51 
52 
53 // Anonymous namespace for helper functions
54 // namespace {
55 //
56 // using namespace libMesh;
57 //
58 // struct SyncCoarsenInactive
59 // {
60 // bool operator() (const Elem * elem) const {
61 // // If we're not an ancestor, there's no chance our coarsening
62 // // settings need to be changed.
63 // if (!elem->ancestor())
64 // return false;
65 //
66 // // If we don't have any remote children, we already know enough to
67 // // determine the correct refinement flag ourselves.
68 // //
69 // // If we know we have a child that isn't being coarsened, that
70 // // also forces a specific flag.
71 // //
72 // // Either way there's nothing we need to communicate.
73 // bool found_remote_child = false;
74 // for (auto & child : elem->child_ref_range())
75 // {
76 // if (child.refinement_flag() != Elem::COARSEN)
77 // return false;
78 // if (&child == remote_elem)
79 // found_remote_child = true;
80 // }
81 // return found_remote_child;
82 // }
83 // };
84 // }
85 
86 
87 
88 namespace libMesh
89 {
90 
91 //-----------------------------------------------------------------
92 // Mesh refinement methods
94  ParallelObject(m),
95  _mesh(m),
96  _use_member_parameters(false),
97  _coarsen_by_parents(false),
98  _refine_fraction(0.3),
99  _coarsen_fraction(0.0),
100  _max_h_level(libMesh::invalid_uint),
101  _coarsen_threshold(10),
102  _nelem_target(0),
103  _absolute_global_tolerance(0.0),
104  _face_level_mismatch_limit(1),
105  _edge_level_mismatch_limit(0),
106  _node_level_mismatch_limit(0),
107  _overrefined_boundary_limit(0),
108  _underrefined_boundary_limit(0),
109  _enforce_mismatch_limit_prior_to_refinement(false)
110 #ifdef LIBMESH_ENABLE_PERIODIC
111  , _periodic_boundaries(nullptr)
112 #endif
113 {
114 }
115 
116 
117 
118 #ifdef LIBMESH_ENABLE_PERIODIC
120 {
121  _periodic_boundaries = pb_ptr;
122 }
123 #endif
124 
125 
126 
128 {
129  this->clear();
130 }
131 
132 
133 
135 {
137 }
138 
139 
140 
142  unsigned int child,
143  unsigned int node,
144  processor_id_type proc_id)
145 {
146  LOG_SCOPE("add_node()", "MeshRefinement");
147 
148  unsigned int parent_n = parent.as_parent_node(child, node);
149 
150  if (parent_n != libMesh::invalid_uint)
151  return parent.node_ptr(parent_n);
152 
153  const std::vector<std::pair<dof_id_type, dof_id_type>>
154  bracketing_nodes = parent.bracketing_nodes(child, node);
155 
156  // If we're not a parent node, we *must* be bracketed by at least
157  // one pair of parent nodes
158  libmesh_assert(bracketing_nodes.size());
159 
160  const dof_id_type new_node_id =
161  _new_nodes_map.find(bracketing_nodes);
162 
163  // Return the node if it already exists.
164  //
165  // We'll leave the processor_id untouched in this case - if we're
166  // repartitioning later or if this is a new unpartitioned node,
167  // we'll update it then, and if not then we don't want to update it.
168  if (new_node_id != DofObject::invalid_id)
169  return _mesh.node_ptr(new_node_id);
170 
171  // Otherwise we need to add a new node.
172  //
173  // Figure out where to add the point:
174 
175  Point p; // defaults to 0,0,0
176 
177  for (auto n : parent.node_index_range())
178  {
179  // The value from the embedding matrix
180  const float em_val = parent.embedding_matrix(child,node,n);
181 
182  if (em_val != 0.)
183  {
184  p.add_scaled (parent.point(n), em_val);
185 
186  // If we'd already found the node we shouldn't be here
187  libmesh_assert_not_equal_to (em_val, 1);
188  }
189  }
190 
191  // Although we're leaving new nodes unpartitioned at first, with a
192  // DistributedMesh we would need a default id based on the numbering
193  // scheme for the requested processor_id.
194  Node * new_node = _mesh.add_point (p, DofObject::invalid_id, proc_id);
195 
196  libmesh_assert(new_node);
197 
198  // But then we'll make sure this node is marked as unpartitioned.
200 
201  // Add the node to the map.
202  _new_nodes_map.add_node(*new_node, bracketing_nodes);
203 
204  // Return the address of the new node
205  return new_node;
206 }
207 
208 
209 
211 {
212  libmesh_assert(elem);
213  _mesh.add_elem (elem);
214  return elem;
215 }
216 
217 
218 
220  ErrorVector & error_per_parent,
221  Real & parent_error_min,
222  Real & parent_error_max)
223 {
224  // This function must be run on all processors at once
225  parallel_object_only();
226 
227  // Make sure the input error vector is valid
228 #ifdef DEBUG
229  for (std::size_t i=0; i != error_per_cell.size(); ++i)
230  {
231  libmesh_assert_greater_equal (error_per_cell[i], 0);
232  // isnan() isn't standard C++ yet
233 #ifdef isnan
234  libmesh_assert(!isnan(error_per_cell[i]));
235 #endif
236  }
237 
238  // Use a reference to std::vector to avoid confusing
239  // this->comm().verify
240  std::vector<ErrorVectorReal> & epc = error_per_parent;
241  libmesh_assert(this->comm().verify(epc));
242 #endif // #ifdef DEBUG
243 
244  // error values on uncoarsenable elements will be left at -1
245  error_per_parent.clear();
246  error_per_parent.resize(error_per_cell.size(), 0.0);
247 
248  {
249  // Find which elements are uncoarsenable
250  for (auto & elem : _mesh.active_local_element_ptr_range())
251  {
252  Elem * parent = elem->parent();
253 
254  // Active elements are uncoarsenable
255  error_per_parent[elem->id()] = -1.0;
256 
257  // Grandparents and up are uncoarsenable
258  while (parent)
259  {
260  parent = parent->parent();
261  if (parent)
262  {
263  const dof_id_type parentid = parent->id();
264  libmesh_assert_less (parentid, error_per_parent.size());
265  error_per_parent[parentid] = -1.0;
266  }
267  }
268  }
269 
270  // Sync between processors.
271  // Use a reference to std::vector to avoid confusing
272  // this->comm().min
273  std::vector<ErrorVectorReal> & epp = error_per_parent;
274  this->comm().min(epp);
275  }
276 
277  // The parent's error is defined as the square root of the
278  // sum of the children's errors squared, so errors that are
279  // Hilbert norms remain Hilbert norms.
280  //
281  // Because the children may be on different processors, we
282  // calculate local contributions to the parents' errors squared
283  // first, then sum across processors and take the square roots
284  // second.
285  for (auto & elem : _mesh.active_local_element_ptr_range())
286  {
287  Elem * parent = elem->parent();
288 
289  // Calculate each contribution to parent cells
290  if (parent)
291  {
292  const dof_id_type parentid = parent->id();
293  libmesh_assert_less (parentid, error_per_parent.size());
294 
295  // If the parent has grandchildren we won't be able to
296  // coarsen it, so forget it. Otherwise, add this child's
297  // contribution to the sum of the squared child errors
298  if (error_per_parent[parentid] != -1.0)
299  error_per_parent[parentid] += (error_per_cell[elem->id()] *
300  error_per_cell[elem->id()]);
301  }
302  }
303 
304  // Sum the vector across all processors
305  this->comm().sum(static_cast<std::vector<ErrorVectorReal> &>(error_per_parent));
306 
307  // Calculate the min and max as we loop
308  parent_error_min = std::numeric_limits<double>::max();
309  parent_error_max = 0.;
310 
311  for (std::size_t i = 0; i != error_per_parent.size(); ++i)
312  {
313  // If this element isn't a coarsenable parent with error, we
314  // have nothing to do. Just flag it as -1 and move on
315  // Note that this->comm().sum might have left uncoarsenable
316  // elements with error_per_parent=-n_proc, so reset it to
317  // error_per_parent=-1
318  if (error_per_parent[i] < 0.)
319  {
320  error_per_parent[i] = -1.;
321  continue;
322  }
323 
324  // The error estimator might have already given us an
325  // estimate on the coarsenable parent elements; if so then
326  // we want to retain that estimate
327  if (error_per_cell[i])
328  {
329  error_per_parent[i] = error_per_cell[i];
330  continue;
331  }
332  // if not, then e_parent = sqrt(sum(e_child^2))
333  else
334  error_per_parent[i] = std::sqrt(error_per_parent[i]);
335 
336  parent_error_min = std::min (parent_error_min,
337  error_per_parent[i]);
338  parent_error_max = std::max (parent_error_max,
339  error_per_parent[i]);
340  }
341 }
342 
343 
344 
346 {
347  this->_new_nodes_map.init(_mesh);
348 }
349 
350 
351 
352 bool MeshRefinement::test_level_one (bool libmesh_dbg_var(libmesh_assert_pass))
353 {
354  // This function must be run on all processors at once
355  parallel_object_only();
356 
357  // We may need a PointLocator for topological_neighbor() tests
358  // later, which we need to make sure gets constructed on all
359  // processors at once.
360  std::unique_ptr<PointLocatorBase> point_locator;
361 
362 #ifdef LIBMESH_ENABLE_PERIODIC
363  bool has_periodic_boundaries =
365  libmesh_assert(this->comm().verify(has_periodic_boundaries));
366 
367  if (has_periodic_boundaries)
368  point_locator = _mesh.sub_point_locator();
369 #endif
370 
371  bool failure = false;
372 
373 #ifndef NDEBUG
374  Elem * failed_elem = nullptr;
375  Elem * failed_neighbor = nullptr;
376 #endif // !NDEBUG
377 
378  for (auto & elem : _mesh.active_local_element_ptr_range())
379  for (auto n : elem->side_index_range())
380  {
381  Elem * neighbor =
382  topological_neighbor(elem, point_locator.get(), n);
383 
384  if (!neighbor || !neighbor->active() ||
385  neighbor == remote_elem)
386  continue;
387 
388  if ((neighbor->level() + 1 < elem->level()) ||
389  (neighbor->p_level() + 1 < elem->p_level()) ||
390  (neighbor->p_level() > elem->p_level() + 1))
391  {
392  failure = true;
393 #ifndef NDEBUG
394  failed_elem = elem;
395  failed_neighbor = neighbor;
396 #endif // !NDEBUG
397  break;
398  }
399  }
400 
401  // If any processor failed, we failed globally
402  this->comm().max(failure);
403 
404  if (failure)
405  {
406  // We didn't pass the level one test, so libmesh_assert that
407  // we're allowed not to
408 #ifndef NDEBUG
409  if (libmesh_assert_pass)
410  {
411  libMesh::out << "MeshRefinement Level one failure, element: "
412  << *failed_elem
413  << std::endl;
414  libMesh::out << "MeshRefinement Level one failure, neighbor: "
415  << *failed_neighbor
416  << std::endl;
417  }
418 #endif // !NDEBUG
419  libmesh_assert(!libmesh_assert_pass);
420  return false;
421  }
422  return true;
423 }
424 
425 
426 
427 bool MeshRefinement::test_unflagged (bool libmesh_dbg_var(libmesh_assert_pass))
428 {
429  // This function must be run on all processors at once
430  parallel_object_only();
431 
432  bool found_flag = false;
433 
434 #ifndef NDEBUG
435  Elem * failed_elem = nullptr;
436 #endif
437 
438  // Search for local flags
439  for (auto & elem : _mesh.active_local_element_ptr_range())
440  if (elem->refinement_flag() == Elem::REFINE ||
441  elem->refinement_flag() == Elem::COARSEN ||
442  elem->p_refinement_flag() == Elem::REFINE ||
443  elem->p_refinement_flag() == Elem::COARSEN)
444  {
445  found_flag = true;
446 #ifndef NDEBUG
447  failed_elem = elem;
448 #endif
449  break;
450  }
451 
452  // If we found a flag on any processor, it counts
453  this->comm().max(found_flag);
454 
455  if (found_flag)
456  {
457 #ifndef NDEBUG
458  if (libmesh_assert_pass)
459  {
460  libMesh::out <<
461  "MeshRefinement test_unflagged failure, element: " <<
462  *failed_elem << std::endl;
463  }
464 #endif
465  // We didn't pass the "elements are unflagged" test,
466  // so libmesh_assert that we're allowed not to
467  libmesh_assert(!libmesh_assert_pass);
468  return false;
469  }
470  return true;
471 }
472 
473 
474 
476 {
477  // This function must be run on all processors at once
478  parallel_object_only();
479 
480  // We can't yet turn a non-level-one mesh into a level-one mesh
482  libmesh_assert(test_level_one(true));
483 
484  // Possibly clean up the refinement flags from
485  // a previous step. While we're at it, see if this method should be
486  // a no-op.
487  bool elements_flagged = false;
488 
489  for (auto & elem : _mesh.element_ptr_range())
490  {
491  // This might be left over from the last step
492  const Elem::RefinementState flag = elem->refinement_flag();
493 
494  // Set refinement flag to INACTIVE if the
495  // element isn't active
496  if ( !elem->active())
497  {
498  elem->set_refinement_flag(Elem::INACTIVE);
499  elem->set_p_refinement_flag(Elem::INACTIVE);
500  }
501  else if (flag == Elem::JUST_REFINED)
502  elem->set_refinement_flag(Elem::DO_NOTHING);
503  else if (!elements_flagged)
504  {
505  if (flag == Elem::REFINE || flag == Elem::COARSEN)
506  elements_flagged = true;
507  else
508  {
509  const Elem::RefinementState pflag =
510  elem->p_refinement_flag();
511  if (pflag == Elem::REFINE || pflag == Elem::COARSEN)
512  elements_flagged = true;
513  }
514  }
515  }
516 
517  // Did *any* processor find elements flagged for AMR/C?
518  _mesh.comm().max(elements_flagged);
519 
520  // If we have nothing to do, let's not bother verifying that nothing
521  // is compatible with nothing.
522  if (!elements_flagged)
523  return false;
524 
525  // Parallel consistency has to come first, or coarsening
526  // along processor boundaries might occasionally be falsely
527  // prevented
528 #ifdef DEBUG
529  bool flags_were_consistent = this->make_flags_parallel_consistent();
530 
531  libmesh_assert (flags_were_consistent);
532 #endif
533 
534  // Smooth refinement and coarsening flags
535  _smooth_flags(true, true);
536 
537  // First coarsen the flagged elements.
538  const bool coarsening_changed_mesh =
539  this->_coarsen_elements ();
540 
541  // First coarsen the flagged elements.
542  // FIXME: test_level_one now tests consistency across periodic
543  // boundaries, which requires a point_locator, which just got
544  // invalidated by _coarsen_elements() and hasn't yet been cleared by
545  // prepare_for_use().
546 
547  // libmesh_assert(this->make_coarsening_compatible());
548  // libmesh_assert(this->make_refinement_compatible());
549 
550  // FIXME: This won't pass unless we add a redundant find_neighbors()
551  // call or replace find_neighbors() with on-the-fly neighbor updating
552  // libmesh_assert(!this->eliminate_unrefined_patches());
553 
554  // We can't contract the mesh ourselves anymore - a System might
555  // need to restrict old coefficient vectors first
556  // _mesh.contract();
557 
558  // First coarsen the flagged elements.
559  // Now refine the flagged elements. This will
560  // take up some space, maybe more than what was freed.
561  const bool refining_changed_mesh =
562  this->_refine_elements();
563 
564  // First coarsen the flagged elements.
565  // Finally, the new mesh needs to be prepared for use
566  if (coarsening_changed_mesh || refining_changed_mesh)
567  {
568 #ifdef DEBUG
570 #endif
571 
572  _mesh.prepare_for_use (/*skip_renumber =*/false);
573 
575  libmesh_assert(test_level_one(true));
576  libmesh_assert(test_unflagged(true));
577  libmesh_assert(this->make_coarsening_compatible());
578  libmesh_assert(this->make_refinement_compatible());
579  // FIXME: This won't pass unless we add a redundant find_neighbors()
580  // call or replace find_neighbors() with on-the-fly neighbor updating
581  // libmesh_assert(!this->eliminate_unrefined_patches());
582 
583  return true;
584  }
585  else
586  {
588  libmesh_assert(test_level_one(true));
589  libmesh_assert(test_unflagged(true));
590  libmesh_assert(this->make_coarsening_compatible());
591  libmesh_assert(this->make_refinement_compatible());
592  }
593 
594  // Otherwise there was no change in the mesh,
595  // let the user know. Also, there is no need
596  // to prepare the mesh for use since it did not change.
597  return false;
598 
599 }
600 
601 
602 
603 
604 
605 
606 
608 {
609  // This function must be run on all processors at once
610  parallel_object_only();
611 
612  // We can't yet turn a non-level-one mesh into a level-one mesh
614  libmesh_assert(test_level_one(true));
615 
616  // Possibly clean up the refinement flags from
617  // a previous step
618  for (auto & elem : _mesh.element_ptr_range())
619  {
620  // Set refinement flag to INACTIVE if the
621  // element isn't active
622  if (!elem->active())
623  {
624  elem->set_refinement_flag(Elem::INACTIVE);
625  elem->set_p_refinement_flag(Elem::INACTIVE);
626  }
627 
628  // This might be left over from the last step
629  if (elem->refinement_flag() == Elem::JUST_REFINED)
630  elem->set_refinement_flag(Elem::DO_NOTHING);
631  }
632 
633  // Parallel consistency has to come first, or coarsening
634  // along processor boundaries might occasionally be falsely
635  // prevented
636  bool flags_were_consistent = this->make_flags_parallel_consistent();
637 
638  // In theory, we should be able to remove the above call, which can
639  // be expensive and should be unnecessary. In practice, doing
640  // consistent flagging in parallel is hard, it's impossible to
641  // verify at the library level if it's being done by user code, and
642  // we don't want to abort large parallel runs in opt mode... but we
643  // do want to warn that they should be fixed.
644  libmesh_assert(flags_were_consistent);
645  if (!flags_were_consistent)
646  {
647  libMesh::out << "Refinement flags were not consistent between processors!\n"
648  << "Correcting and continuing.";
649  }
650 
651  // Smooth coarsening flags
652  _smooth_flags(false, true);
653 
654  // Coarsen the flagged elements.
655  const bool mesh_changed =
656  this->_coarsen_elements ();
657 
659  libmesh_assert(test_level_one(true));
660  libmesh_assert(this->make_coarsening_compatible());
661  // FIXME: This won't pass unless we add a redundant find_neighbors()
662  // call or replace find_neighbors() with on-the-fly neighbor updating
663  // libmesh_assert(!this->eliminate_unrefined_patches());
664 
665  // We can't contract the mesh ourselves anymore - a System might
666  // need to restrict old coefficient vectors first
667  // _mesh.contract();
668 
669  // Finally, the new mesh may need to be prepared for use
670  if (mesh_changed)
671  _mesh.prepare_for_use (/*skip_renumber =*/false);
672 
673  return mesh_changed;
674 }
675 
676 
677 
678 
679 
680 
681 
683 {
684  // This function must be run on all processors at once
685  parallel_object_only();
686 
688  libmesh_assert(test_level_one(true));
689 
690  // Possibly clean up the refinement flags from
691  // a previous step
692  for (auto & elem : _mesh.element_ptr_range())
693  {
694  // Set refinement flag to INACTIVE if the
695  // element isn't active
696  if (!elem->active())
697  {
698  elem->set_refinement_flag(Elem::INACTIVE);
699  elem->set_p_refinement_flag(Elem::INACTIVE);
700  }
701 
702  // This might be left over from the last step
703  if (elem->refinement_flag() == Elem::JUST_REFINED)
704  elem->set_refinement_flag(Elem::DO_NOTHING);
705  }
706 
707 
708 
709  // Parallel consistency has to come first, or coarsening
710  // along processor boundaries might occasionally be falsely
711  // prevented
712  bool flags_were_consistent = this->make_flags_parallel_consistent();
713 
714  // In theory, we should be able to remove the above call, which can
715  // be expensive and should be unnecessary. In practice, doing
716  // consistent flagging in parallel is hard, it's impossible to
717  // verify at the library level if it's being done by user code, and
718  // we don't want to abort large parallel runs in opt mode... but we
719  // do want to warn that they should be fixed.
720  libmesh_assert(flags_were_consistent);
721  if (!flags_were_consistent)
722  {
723  libMesh::out << "Refinement flags were not consistent between processors!\n"
724  << "Correcting and continuing.";
725  }
726 
727  // Smooth refinement flags
728  _smooth_flags(true, false);
729 
730  // Now refine the flagged elements. This will
731  // take up some space, maybe more than what was freed.
732  const bool mesh_changed =
733  this->_refine_elements();
734 
736  libmesh_assert(test_level_one(true));
737  libmesh_assert(this->make_refinement_compatible());
738  // FIXME: This won't pass unless we add a redundant find_neighbors()
739  // call or replace find_neighbors() with on-the-fly neighbor updating
740  // libmesh_assert(!this->eliminate_unrefined_patches());
741 
742  // Finally, the new mesh needs to be prepared for use
743  if (mesh_changed)
744  _mesh.prepare_for_use (/*skip_renumber =*/false);
745 
746  return mesh_changed;
747 }
748 
749 
750 
752 {
753  // This function must be run on all processors at once
754  parallel_object_only();
755 
756  LOG_SCOPE ("make_flags_parallel_consistent()", "MeshRefinement");
757 
761  (this->comm(), _mesh.elements_begin(), _mesh.elements_end(), hsync);
762 
766  (this->comm(), _mesh.elements_begin(), _mesh.elements_end(), psync);
767 
768  // If we weren't consistent in both h and p on every processor then
769  // we weren't globally consistent
770  bool parallel_consistent = hsync.parallel_consistent &&
771  psync.parallel_consistent;
772  this->comm().min(parallel_consistent);
773 
774  return parallel_consistent;
775 }
776 
777 
778 
780 {
781  // This function must be run on all processors at once
782  parallel_object_only();
783 
784  // We may need a PointLocator for topological_neighbor() tests
785  // later, which we need to make sure gets constructed on all
786  // processors at once.
787  std::unique_ptr<PointLocatorBase> point_locator;
788 
789 #ifdef LIBMESH_ENABLE_PERIODIC
790  bool has_periodic_boundaries =
792  libmesh_assert(this->comm().verify(has_periodic_boundaries));
793 
794  if (has_periodic_boundaries)
795  point_locator = _mesh.sub_point_locator();
796 #endif
797 
798  LOG_SCOPE ("make_coarsening_compatible()", "MeshRefinement");
799 
800  // Unless we encounter a specific situation level-one
801  // will be satisfied after executing this loop just once
802  bool level_one_satisfied = true;
803 
804 
805  // Unless we encounter a specific situation we will be compatible
806  // with any selected refinement flags
807  bool compatible_with_refinement = true;
808 
809 
810  // find the maximum h and p levels in the mesh
811  unsigned int max_level = 0;
812  unsigned int max_p_level = 0;
813 
814  {
815  // First we look at all the active level-0 elements. Since it doesn't make
816  // sense to coarsen them we must un-set their coarsen flags if
817  // they are set.
818  for (auto & elem : _mesh.active_element_ptr_range())
819  {
820  max_level = std::max(max_level, elem->level());
821  max_p_level =
822  std::max(max_p_level,
823  static_cast<unsigned int>(elem->p_level()));
824 
825  if ((elem->level() == 0) &&
826  (elem->refinement_flag() == Elem::COARSEN))
827  elem->set_refinement_flag(Elem::DO_NOTHING);
828 
829  if ((elem->p_level() == 0) &&
830  (elem->p_refinement_flag() == Elem::COARSEN))
831  elem->set_p_refinement_flag(Elem::DO_NOTHING);
832  }
833  }
834 
835  // Even if there are no refined elements on this processor then
836  // there may still be work for us to do on e.g. ancestor elements.
837  // At the very least we need to be in the loop if a distributed mesh
838  // needs to synchronize data.
839 #if 0
840  if (max_level == 0 && max_p_level == 0)
841  {
842  // But we still have to check with other processors
843  this->comm().min(compatible_with_refinement);
844 
845  return compatible_with_refinement;
846  }
847 #endif
848 
849  // Loop over all the active elements. If an element is marked
850  // for coarsening we better check its neighbors. If ANY of these neighbors
851  // are marked for refinement AND are at the same level then there is a
852  // conflict. By convention refinement wins, so we un-mark the element for
853  // coarsening. Level-one would be violated in this case so we need to re-run
854  // the loop.
856  {
857 
858  repeat:
859  level_one_satisfied = true;
860 
861  do
862  {
863  level_one_satisfied = true;
864 
865  for (auto & elem : _mesh.active_element_ptr_range())
866  {
867  bool my_flag_changed = false;
868 
869  if (elem->refinement_flag() == Elem::COARSEN) // If the element is active and
870  // the coarsen flag is set
871  {
872  const unsigned int my_level = elem->level();
873 
874  for (auto n : elem->side_index_range())
875  {
876  const Elem * neighbor =
877  topological_neighbor(elem, point_locator.get(), n);
878 
879  if (neighbor != nullptr && // I have a
880  neighbor != remote_elem) // neighbor here
881  {
882  if (neighbor->active()) // and it is active
883  {
884  if ((neighbor->level() == my_level) &&
885  (neighbor->refinement_flag() == Elem::REFINE)) // the neighbor is at my level
886  // and wants to be refined
887  {
889  my_flag_changed = true;
890  break;
891  }
892  }
893  else // I have a neighbor and it is not active. That means it has children.
894  { // While it _may_ be possible to coarsen us if all the children of
895  // that element want to be coarsened, it is impossible to know at this
896  // stage. Forget about it for the moment... This can be handled in
897  // two steps.
898  elem->set_refinement_flag(Elem::DO_NOTHING);
899  my_flag_changed = true;
900  break;
901  }
902  }
903  }
904  }
905  if (elem->p_refinement_flag() == Elem::COARSEN) // If
906  // the element is active and the order reduction flag is set
907  {
908  const unsigned int my_p_level = elem->p_level();
909 
910  for (auto n : elem->side_index_range())
911  {
912  const Elem * neighbor =
913  topological_neighbor(elem, point_locator.get(), n);
914 
915  if (neighbor != nullptr && // I have a
916  neighbor != remote_elem) // neighbor here
917  {
918  if (neighbor->active()) // and it is active
919  {
920  if ((neighbor->p_level() > my_p_level &&
921  neighbor->p_refinement_flag() != Elem::COARSEN)
922  || (neighbor->p_level() == my_p_level &&
923  neighbor->p_refinement_flag() == Elem::REFINE))
924  {
926  my_flag_changed = true;
927  break;
928  }
929  }
930  else // I have a neighbor and it is not active.
931  { // We need to find which of its children
932  // have me as a neighbor, and maintain
933  // level one p compatibility with them.
934  // Because we currently have level one h
935  // compatibility, we don't need to check
936  // grandchildren
937 
938  libmesh_assert(neighbor->has_children());
939  for (auto & subneighbor : neighbor->child_ref_range())
940  if (&subneighbor != remote_elem &&
941  subneighbor.active() &&
942  has_topological_neighbor(&subneighbor, point_locator.get(), elem))
943  if ((subneighbor.p_level() > my_p_level &&
944  subneighbor.p_refinement_flag() != Elem::COARSEN)
945  || (subneighbor.p_level() == my_p_level &&
946  subneighbor.p_refinement_flag() == Elem::REFINE))
947  {
948  elem->set_p_refinement_flag(Elem::DO_NOTHING);
949  my_flag_changed = true;
950  break;
951  }
952  if (my_flag_changed)
953  break;
954  }
955  }
956  }
957  }
958 
959  // If the current element's flag changed, we hadn't
960  // satisfied the level one rule.
961  if (my_flag_changed)
962  level_one_satisfied = false;
963 
964  // Additionally, if it has non-local neighbors, and
965  // we're not in serial, then we'll eventually have to
966  // return compatible_with_refinement = false, because
967  // our change has to propagate to neighboring
968  // processors.
969  if (my_flag_changed && !_mesh.is_serial())
970  for (auto n : elem->side_index_range())
971  {
972  Elem * neigh =
973  topological_neighbor(elem, point_locator.get(), n);
974 
975  if (!neigh)
976  continue;
977  if (neigh == remote_elem ||
978  neigh->processor_id() !=
979  this->processor_id())
980  {
981  compatible_with_refinement = false;
982  break;
983  }
984  // FIXME - for non-level one meshes we should
985  // test all descendants
986  if (neigh->has_children())
987  for (auto & child : neigh->child_ref_range())
988  if (&child == remote_elem ||
989  child.processor_id() !=
990  this->processor_id())
991  {
992  compatible_with_refinement = false;
993  break;
994  }
995  }
996  }
997  }
998  while (!level_one_satisfied);
999 
1000  } // end if (_face_level_mismatch_limit)
1001 
1002 
1003  // Next we look at all of the ancestor cells.
1004  // If there is a parent cell with all of its children
1005  // wanting to be unrefined then the element is a candidate
1006  // for unrefinement. If all the children don't
1007  // all want to be unrefined then ALL of them need to have their
1008  // unrefinement flags cleared.
1009  for (int level = max_level; level >= 0; level--)
1010  for (auto & elem : as_range(_mesh.level_elements_begin(level), _mesh.level_elements_end(level)))
1011  if (elem->ancestor())
1012  {
1013  // right now the element hasn't been disqualified
1014  // as a candidate for unrefinement
1015  bool is_a_candidate = true;
1016  bool found_remote_child = false;
1017 
1018  for (auto & child : elem->child_ref_range())
1019  {
1020  if (&child == remote_elem)
1021  found_remote_child = true;
1022  else if ((child.refinement_flag() != Elem::COARSEN) ||
1023  !child.active() )
1024  is_a_candidate = false;
1025  }
1026 
1027  if (!is_a_candidate && !found_remote_child)
1028  {
1030 
1031  for (auto & child : elem->child_ref_range())
1032  {
1033  if (&child == remote_elem)
1034  continue;
1035  if (child.refinement_flag() == Elem::COARSEN)
1036  {
1037  level_one_satisfied = false;
1038  child.set_refinement_flag(Elem::DO_NOTHING);
1039  }
1040  }
1041  }
1042  }
1043 
1044  if (!level_one_satisfied && _face_level_mismatch_limit) goto repeat;
1045 
1046 
1047  // If all the children of a parent are set to be coarsened
1048  // then flag the parent so that they can kill their kids.
1049 
1050  // On a distributed mesh, we won't always be able to determine this
1051  // on parent elements with remote children, even if we own the
1052  // parent, without communication.
1053  //
1054  // We'll first communicate *to* parents' owners when we determine
1055  // they cannot be coarsened, then we'll sync the final refinement
1056  // flag *from* the parents.
1057 
1058  // uncoarsenable_parents[p] live on processor id p
1059  const processor_id_type n_proc = _mesh.n_processors();
1060  const processor_id_type my_proc_id = _mesh.processor_id();
1061  const bool distributed_mesh = !_mesh.is_replicated();
1062 
1063  std::vector<std::vector<dof_id_type>>
1064  uncoarsenable_parents(n_proc);
1065 
1067  {
1068  // Presume all the children are flagged for coarsening and
1069  // then look for a contradiction
1070  bool all_children_flagged_for_coarsening = true;
1071 
1072  for (auto & child : elem->child_ref_range())
1073  {
1074  if (&child != remote_elem &&
1075  child.refinement_flag() != Elem::COARSEN)
1076  {
1077  all_children_flagged_for_coarsening = false;
1078  if (!distributed_mesh)
1079  break;
1080  if (child.processor_id() != elem->processor_id())
1081  {
1082  uncoarsenable_parents[elem->processor_id()].push_back(elem->id());
1083  break;
1084  }
1085  }
1086  }
1087 
1088  if (all_children_flagged_for_coarsening)
1089  elem->set_refinement_flag(Elem::COARSEN_INACTIVE);
1090  else
1091  elem->set_refinement_flag(Elem::INACTIVE);
1092  }
1093 
1094  // If we have a distributed mesh, we might need to sync up
1095  // INACTIVE vs. COARSEN_INACTIVE flags.
1096  if (distributed_mesh)
1097  {
1098  // We'd better still be in sync here
1099  parallel_object_only();
1100 
1102  uncoarsenable_tag = this->comm().get_unique_tag(2718);
1103  std::vector<Parallel::Request> uncoarsenable_push_requests(n_proc-1);
1104 
1105  for (processor_id_type p = 0; p != n_proc; ++p)
1106  {
1107  if (p == my_proc_id)
1108  continue;
1109 
1111  uncoarsenable_push_requests[p - (p > my_proc_id)];
1112 
1113  _mesh.comm().send
1114  (p, uncoarsenable_parents[p], request, uncoarsenable_tag);
1115  }
1116 
1117  for (processor_id_type p = 1; p != n_proc; ++p)
1118  {
1119  std::vector<dof_id_type> my_uncoarsenable_parents;
1120  _mesh.comm().receive
1121  (Parallel::any_source, my_uncoarsenable_parents,
1122  uncoarsenable_tag);
1123 
1124  for (const auto & id : my_uncoarsenable_parents)
1125  {
1126  Elem & elem = _mesh.elem_ref(id);
1127  libmesh_assert(elem.refinement_flag() == Elem::INACTIVE ||
1130  }
1131  }
1132 
1133  Parallel::wait(uncoarsenable_push_requests);
1134 
1138  (this->comm(), _mesh.not_local_elements_begin(),
1140  // We'd like a smaller sync, but this leads to bugs?
1141  // SyncCoarsenInactive(),
1142  hsync);
1143  }
1144 
1145  // If one processor finds an incompatibility, we're globally
1146  // incompatible
1147  this->comm().min(compatible_with_refinement);
1148 
1149  return compatible_with_refinement;
1150 }
1151 
1152 
1153 
1154 
1155 
1156 
1157 
1158 
1160 {
1161  // This function must be run on all processors at once
1162  parallel_object_only();
1163 
1164  // We may need a PointLocator for topological_neighbor() tests
1165  // later, which we need to make sure gets constructed on all
1166  // processors at once.
1167  std::unique_ptr<PointLocatorBase> point_locator;
1168 
1169 #ifdef LIBMESH_ENABLE_PERIODIC
1170  bool has_periodic_boundaries =
1172  libmesh_assert(this->comm().verify(has_periodic_boundaries));
1173 
1174  if (has_periodic_boundaries)
1175  point_locator = _mesh.sub_point_locator();
1176 #endif
1177 
1178  LOG_SCOPE ("make_refinement_compatible()", "MeshRefinement");
1179 
1180  // Unless we encounter a specific situation we will be compatible
1181  // with any selected coarsening flags
1182  bool compatible_with_coarsening = true;
1183 
1184  // This loop enforces the level-1 rule. We should only
1185  // execute it if the user indeed wants level-1 satisfied!
1187  {
1188  // Unless we encounter a specific situation level-one
1189  // will be satisfied after executing this loop just once
1190  bool level_one_satisfied = true;
1191 
1192  do
1193  {
1194  level_one_satisfied = true;
1195 
1196  for (auto & elem : _mesh.active_element_ptr_range())
1197  {
1198  const unsigned short n_sides = elem->n_sides();
1199 
1200  if (elem->refinement_flag() == Elem::REFINE) // If the element is active and the
1201  // h refinement flag is set
1202  {
1203  const unsigned int my_level = elem->level();
1204 
1205  for (unsigned short side = 0; side != n_sides;
1206  ++side)
1207  {
1208  Elem * neighbor =
1209  topological_neighbor(elem, point_locator.get(), side);
1210 
1211  if (neighbor != nullptr && // I have a
1212  neighbor != remote_elem && // neighbor here
1213  neighbor->active()) // and it is active
1214  {
1215  // Case 1: The neighbor is at the same level I am.
1216  // 1a: The neighbor will be refined -> NO PROBLEM
1217  // 1b: The neighbor won't be refined -> NO PROBLEM
1218  // 1c: The neighbor wants to be coarsened -> PROBLEM
1219  if (neighbor->level() == my_level)
1220  {
1221  if (neighbor->refinement_flag() == Elem::COARSEN)
1222  {
1224  if (neighbor->parent())
1226  compatible_with_coarsening = false;
1227  level_one_satisfied = false;
1228  }
1229  }
1230 
1231 
1232  // Case 2: The neighbor is one level lower than I am.
1233  // The neighbor thus MUST be refined to satisfy
1234  // the level-one rule, regardless of whether it
1235  // was originally flagged for refinement. If it
1236  // wasn't flagged already we need to repeat
1237  // this process.
1238  else if ((neighbor->level()+1) == my_level)
1239  {
1240  if (neighbor->refinement_flag() != Elem::REFINE)
1241  {
1242  neighbor->set_refinement_flag(Elem::REFINE);
1243  if (neighbor->parent())
1245  compatible_with_coarsening = false;
1246  level_one_satisfied = false;
1247  }
1248  }
1249 #ifdef DEBUG
1250  // Note that the only other possibility is that the
1251  // neighbor is already refined, in which case it isn't
1252  // active and we should never get here.
1253  else
1254  libmesh_error_msg("ERROR: Neighbor level must be equal or 1 higher than mine.");
1255 #endif
1256  }
1257  }
1258  }
1259  if (elem->p_refinement_flag() == Elem::REFINE) // If the element is active and the
1260  // p refinement flag is set
1261  {
1262  const unsigned int my_p_level = elem->p_level();
1263 
1264  for (unsigned int side=0; side != n_sides; side++)
1265  {
1266  Elem * neighbor =
1267  topological_neighbor(elem, point_locator.get(), side);
1268 
1269  if (neighbor != nullptr && // I have a
1270  neighbor != remote_elem) // neighbor here
1271  {
1272  if (neighbor->active()) // and it is active
1273  {
1274  if (neighbor->p_level() < my_p_level &&
1275  neighbor->p_refinement_flag() != Elem::REFINE)
1276  {
1278  level_one_satisfied = false;
1279  compatible_with_coarsening = false;
1280  }
1281  if (neighbor->p_level() == my_p_level &&
1282  neighbor->p_refinement_flag() == Elem::COARSEN)
1283  {
1285  level_one_satisfied = false;
1286  compatible_with_coarsening = false;
1287  }
1288  }
1289  else // I have an inactive neighbor
1290  {
1291  libmesh_assert(neighbor->has_children());
1292  for (auto & subneighbor : neighbor->child_ref_range())
1293  if (&subneighbor != remote_elem && subneighbor.active() &&
1294  has_topological_neighbor(&subneighbor, point_locator.get(), elem))
1295  {
1296  if (subneighbor.p_level() < my_p_level &&
1297  subneighbor.p_refinement_flag() != Elem::REFINE)
1298  {
1299  // We should already be level one
1300  // compatible
1301  libmesh_assert_greater (subneighbor.p_level() + 2u,
1302  my_p_level);
1303  subneighbor.set_p_refinement_flag(Elem::REFINE);
1304  level_one_satisfied = false;
1305  compatible_with_coarsening = false;
1306  }
1307  if (subneighbor.p_level() == my_p_level &&
1308  subneighbor.p_refinement_flag() == Elem::COARSEN)
1309  {
1310  subneighbor.set_p_refinement_flag(Elem::DO_NOTHING);
1311  level_one_satisfied = false;
1312  compatible_with_coarsening = false;
1313  }
1314  }
1315  }
1316  }
1317  }
1318  }
1319  }
1320  }
1321 
1322  while (!level_one_satisfied);
1323  } // end if (_face_level_mismatch_limit)
1324 
1325  // If we're not compatible on one processor, we're globally not
1326  // compatible
1327  this->comm().min(compatible_with_coarsening);
1328 
1329  return compatible_with_coarsening;
1330 }
1331 
1332 
1333 
1334 
1336 {
1337  // This function must be run on all processors at once
1338  parallel_object_only();
1339 
1340  LOG_SCOPE ("_coarsen_elements()", "MeshRefinement");
1341 
1342  // Flags indicating if this call actually changes the mesh
1343  bool mesh_changed = false;
1344  bool mesh_p_changed = false;
1345 
1346  // Clear the unused_elements data structure.
1347  // The elements have been packed since it was built,
1348  // so there are _no_ unused elements. We cannot trust
1349  // any iterators currently in this data structure.
1350  // _unused_elements.clear();
1351 
1352  // Loop over the elements first to determine if the mesh will
1353  // undergo h-coarsening. If it will, then we'll need to communicate
1354  // more ghosted elements. We need to communicate them *before* we
1355  // do the coarsening; otherwise it is possible to coarsen away a
1356  // one-element-thick layer partition and leave the partitions on
1357  // either side unable to figure out how to talk to each other.
1358  for (auto & elem : _mesh.element_ptr_range())
1359  if (elem->refinement_flag() == Elem::COARSEN)
1360  {
1361  mesh_changed = true;
1362  break;
1363  }
1364 
1365  // If the mesh changed on any processor, it changed globally
1366  this->comm().max(mesh_changed);
1367 
1368  // And then we may need to widen the ghosting layers.
1369  if (mesh_changed)
1371 
1372  for (auto & elem : _mesh.element_ptr_range())
1373  {
1374  // active elements flagged for coarsening will
1375  // no longer be deleted until MeshRefinement::contract()
1376  if (elem->refinement_flag() == Elem::COARSEN)
1377  {
1378  // Huh? no level-0 element should be active
1379  // and flagged for coarsening.
1380  libmesh_assert_not_equal_to (elem->level(), 0);
1381 
1382  // Remove this element from any neighbor
1383  // lists that point to it.
1384  elem->nullify_neighbors();
1385 
1386  // Remove any boundary information associated
1387  // with this element
1388  _mesh.get_boundary_info().remove (elem);
1389 
1390  // Add this iterator to the _unused_elements
1391  // data structure so we might fill it.
1392  // The _unused_elements optimization is currently off.
1393  // _unused_elements.push_back (it);
1394 
1395  // Don't delete the element until
1396  // MeshRefinement::contract()
1397  // _mesh.delete_elem(elem);
1398  }
1399 
1400  // inactive elements flagged for coarsening
1401  // will become active
1402  else if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
1403  {
1404  elem->coarsen();
1405  libmesh_assert (elem->active());
1406 
1407  // the mesh has certainly changed
1408  mesh_changed = true;
1409  }
1410  if (elem->p_refinement_flag() == Elem::COARSEN)
1411  {
1412  if (elem->p_level() > 0)
1413  {
1414  elem->set_p_refinement_flag(Elem::JUST_COARSENED);
1415  elem->set_p_level(elem->p_level() - 1);
1416  mesh_p_changed = true;
1417  }
1418  else
1419  {
1420  elem->set_p_refinement_flag(Elem::DO_NOTHING);
1421  }
1422  }
1423  }
1424 
1425  this->comm().max(mesh_p_changed);
1426 
1427  // And we may need to update DistributedMesh values reflecting the changes
1428  if (mesh_changed)
1430 
1431  // Node processor ids may need to change if an element of that id
1432  // was coarsened away
1433  if (mesh_changed && !_mesh.is_serial())
1434  {
1435  // Update the _new_nodes_map so that processors can
1436  // find requested nodes
1437  this->update_nodes_map ();
1438 
1440 
1441  // Clear the _new_nodes_map
1442  this->clear();
1443 
1444 #ifdef DEBUG
1445  MeshTools::libmesh_assert_valid_procids<Node>(_mesh);
1446 #endif
1447  }
1448 
1449  // If p levels changed all we need to do is make sure that parent p
1450  // levels changed in sync
1451  if (mesh_p_changed && !_mesh.is_serial())
1452  {
1454  }
1455 
1456  return (mesh_changed || mesh_p_changed);
1457 }
1458 
1459 
1460 
1462 {
1463  // This function must be run on all processors at once
1464  parallel_object_only();
1465 
1466  // Update the _new_nodes_map so that elements can
1467  // find nodes to connect to.
1468  this->update_nodes_map ();
1469 
1470  LOG_SCOPE ("_refine_elements()", "MeshRefinement");
1471 
1472  // Iterate over the elements, counting the elements
1473  // flagged for h refinement.
1474  dof_id_type n_elems_flagged = 0;
1475 
1476  for (auto & elem : _mesh.element_ptr_range())
1477  if (elem->refinement_flag() == Elem::REFINE)
1478  n_elems_flagged++;
1479 
1480  // Construct a local vector of Elem * which have been
1481  // previously marked for refinement. We reserve enough
1482  // space to allow for every element to be refined.
1483  std::vector<Elem *> local_copy_of_elements;
1484  local_copy_of_elements.reserve(n_elems_flagged);
1485 
1486  // If mesh p levels changed, we might need to synchronize parent p
1487  // levels on a distributed mesh.
1488  bool mesh_p_changed = false;
1489 
1490  // Iterate over the elements, looking for elements flagged for
1491  // refinement.
1492 
1493  // If we are on a ReplicatedMesh, then we just do the refinement in
1494  // the same order on every processor and everything stays in sync.
1495 
1496  // If we are on a DistributedMesh, that's impossible.
1497  //
1498  // If the mesh is distributed, we need to make sure that if we end
1499  // up as the owner of a new node, which might happen if that node is
1500  // attached to one of our own elements, then we have given it a
1501  // legitimate node id and our own processor id. We generate
1502  // legitimate node ids and use our own processor id when we are
1503  // refining our own elements but not when we refine others'
1504  // elements. Therefore we want to refine our own elements *first*,
1505  // thereby generating all nodes which might belong to us, and then
1506  // refine others' elements *after*, thereby generating nodes with
1507  // temporary ids which we know we will discard.
1508  //
1509  // Even if the DistributedMesh is serialized, we can't just treat it
1510  // like a ReplicatedMesh, because DistributedMesh doesn't *trust*
1511  // users to refine partitioned elements in a serialized way, so it
1512  // assigns temporary ids, so we need to synchronize ids afterward to
1513  // be safe anyway, so we might as well use the distributed mesh code
1514  // path.
1516  {
1517  if (elem->refinement_flag() == Elem::REFINE)
1518  local_copy_of_elements.push_back(elem);
1519  if (elem->p_refinement_flag() == Elem::REFINE &&
1520  elem->active())
1521  {
1522  elem->set_p_level(elem->p_level()+1);
1523  elem->set_p_refinement_flag(Elem::JUST_REFINED);
1524  mesh_p_changed = true;
1525  }
1526  }
1527 
1528  if (!_mesh.is_replicated())
1529  {
1530  for (auto & elem : as_range(_mesh.active_not_local_elements_begin(),
1532  {
1533  if (elem->refinement_flag() == Elem::REFINE)
1534  local_copy_of_elements.push_back(elem);
1535  if (elem->p_refinement_flag() == Elem::REFINE &&
1536  elem->active())
1537  {
1538  elem->set_p_level(elem->p_level()+1);
1539  elem->set_p_refinement_flag(Elem::JUST_REFINED);
1540  mesh_p_changed = true;
1541  }
1542  }
1543  }
1544 
1545  // Now iterate over the local copies and refine each one.
1546  // This may resize the mesh's internal container and invalidate
1547  // any existing iterators.
1548 
1549  for (std::size_t e = 0; e != local_copy_of_elements.size(); ++e)
1550  local_copy_of_elements[e]->refine(*this);
1551 
1552  // The mesh changed if there were elements h refined
1553  bool mesh_changed = !local_copy_of_elements.empty();
1554 
1555  // If the mesh changed on any processor, it changed globally
1556  this->comm().max(mesh_changed);
1557  this->comm().max(mesh_p_changed);
1558 
1559  // And we may need to update DistributedMesh values reflecting the changes
1560  if (mesh_changed)
1562 
1563  if (mesh_changed && !_mesh.is_replicated())
1564  {
1567 #ifdef DEBUG
1569 #endif
1570  }
1571 
1572  // If we're refining a ReplicatedMesh, then we haven't yet assigned
1573  // node processor ids. But if we're refining a partitioned
1574  // ReplicatedMesh, then we *need* to assign node processor ids.
1575  if (mesh_changed && _mesh.is_replicated() &&
1579 
1580  if (mesh_p_changed && !_mesh.is_replicated())
1581  {
1583  }
1584 
1585  // Clear the _new_nodes_map and _unused_elements data structures.
1586  this->clear();
1587 
1588  return (mesh_changed || mesh_p_changed);
1589 }
1590 
1591 
1592 void MeshRefinement::_smooth_flags(bool refining, bool coarsening)
1593 {
1594  // Smoothing can break in weird ways on a mesh with broken topology
1595 #ifdef DEBUG
1597 #endif
1598 
1599  // Repeat until flag changes match on every processor
1600  do
1601  {
1602  // Repeat until coarsening & refinement flags jive
1603  bool satisfied = false;
1604  do
1605  {
1606  // If we're refining or coarsening, hit the corresponding
1607  // face level test code. Short-circuiting || is our friend
1608  const bool coarsening_satisfied =
1609  !coarsening ||
1611 
1612  const bool refinement_satisfied =
1613  !refining ||
1615 
1616  bool smoothing_satisfied =
1617  !this->eliminate_unrefined_patches();// &&
1618 
1620  smoothing_satisfied = smoothing_satisfied &&
1622 
1624  smoothing_satisfied = smoothing_satisfied &&
1626 
1628  smoothing_satisfied = smoothing_satisfied &&
1630 
1632  smoothing_satisfied = smoothing_satisfied &&
1634 
1635  satisfied = (coarsening_satisfied &&
1636  refinement_satisfied &&
1637  smoothing_satisfied);
1638 
1639  libmesh_assert(this->comm().verify(satisfied));
1640  }
1641  while (!satisfied);
1642  }
1643  while (!_mesh.is_serial() && !this->make_flags_parallel_consistent());
1644 }
1645 
1646 
1648 {
1649  // Refine n times
1650  for (unsigned int rstep=0; rstep<n; rstep++)
1651  for (auto & elem : _mesh.active_element_ptr_range())
1652  {
1653  // P refine all the active elements
1654  elem->set_p_level(elem->p_level()+1);
1655  elem->set_p_refinement_flag(Elem::JUST_REFINED);
1656  }
1657 }
1658 
1659 
1660 
1662 {
1663  // Coarsen p times
1664  for (unsigned int rstep=0; rstep<n; rstep++)
1665  for (auto & elem : _mesh.active_element_ptr_range())
1666  if (elem->p_level() > 0)
1667  {
1668  // P coarsen all the active elements
1669  elem->set_p_level(elem->p_level()-1);
1670  elem->set_p_refinement_flag(Elem::JUST_COARSENED);
1671  }
1672 }
1673 
1674 
1675 
1677 {
1678  // Refine n times
1679  // FIXME - this won't work if n>1 and the mesh
1680  // has already been attached to an equation system
1681  for (unsigned int rstep=0; rstep<n; rstep++)
1682  {
1683  // Clean up the refinement flags
1684  this->clean_refinement_flags();
1685 
1686  // Flag all the active elements for refinement.
1687  for (auto & elem : _mesh.active_element_ptr_range())
1688  elem->set_refinement_flag(Elem::REFINE);
1689 
1690  // Refine all the elements we just flagged.
1691  this->_refine_elements();
1692  }
1693 
1694  // Finally, the new mesh probably needs to be prepared for use
1695  if (n > 0)
1696  _mesh.prepare_for_use (/*skip_renumber =*/false);
1697 }
1698 
1699 
1700 
1702 {
1703  // Coarsen n times
1704  for (unsigned int rstep=0; rstep<n; rstep++)
1705  {
1706  // Clean up the refinement flags
1707  this->clean_refinement_flags();
1708 
1709  // Flag all the active elements for coarsening.
1710  for (auto & elem : _mesh.active_element_ptr_range())
1711  {
1712  elem->set_refinement_flag(Elem::COARSEN);
1713  if (elem->parent())
1714  elem->parent()->set_refinement_flag(Elem::COARSEN_INACTIVE);
1715  }
1716 
1717  // On a distributed mesh, we may have parent elements with
1718  // remote active children. To keep flags consistent, we'll need
1719  // a communication step.
1720  if (!_mesh.is_replicated())
1721  {
1722  const processor_id_type n_proc = _mesh.n_processors();
1723  const processor_id_type my_proc_id = _mesh.processor_id();
1724 
1725  std::vector<std::vector<dof_id_type>>
1726  parents_to_coarsen(n_proc);
1727 
1728  for (const auto & elem : as_range(_mesh.ancestor_elements_begin(), _mesh.ancestor_elements_end()))
1729  if (elem->processor_id() != my_proc_id &&
1730  elem->refinement_flag() == Elem::COARSEN_INACTIVE)
1731  parents_to_coarsen[elem->processor_id()].push_back(elem->id());
1732 
1734  coarsen_tag = this->comm().get_unique_tag(271);
1735  std::vector<Parallel::Request> coarsen_push_requests(n_proc-1);
1736 
1737  for (processor_id_type p = 0; p != n_proc; ++p)
1738  {
1739  if (p == my_proc_id)
1740  continue;
1741 
1743  coarsen_push_requests[p - (p > my_proc_id)];
1744 
1745  _mesh.comm().send
1746  (p, parents_to_coarsen[p], request, coarsen_tag);
1747  }
1748 
1749  for (processor_id_type p = 1; p != n_proc; ++p)
1750  {
1751  std::vector<dof_id_type> my_parents_to_coarsen;
1752  _mesh.comm().receive
1753  (Parallel::any_source, my_parents_to_coarsen,
1754  coarsen_tag);
1755 
1756  for (const auto & id : my_parents_to_coarsen)
1757  {
1758  Elem & elem = _mesh.elem_ref(id);
1759  libmesh_assert(elem.refinement_flag() == Elem::INACTIVE ||
1762  }
1763  }
1764 
1765  Parallel::wait(coarsen_push_requests);
1766 
1770  (this->comm(), _mesh.not_local_elements_begin(),
1772  // We'd like a smaller sync, but this leads to bugs?
1773  // SyncCoarsenInactive(),
1774  hsync);
1775  }
1776 
1777  // Coarsen all the elements we just flagged.
1778  this->_coarsen_elements();
1779  }
1780 
1781 
1782  // Finally, the new mesh probably needs to be prepared for use
1783  if (n > 0)
1784  _mesh.prepare_for_use (/*skip_renumber =*/false);
1785 }
1786 
1787 
1788 
1790  const PointLocatorBase * point_locator,
1791  const unsigned int side)
1792 {
1793 #ifdef LIBMESH_ENABLE_PERIODIC
1794  if (_periodic_boundaries && !_periodic_boundaries->empty())
1795  {
1796  libmesh_assert(point_locator);
1797  return elem->topological_neighbor(side, _mesh, *point_locator, _periodic_boundaries);
1798  }
1799 #endif
1800  return elem->neighbor_ptr(side);
1801 }
1802 
1803 
1804 
1806  const PointLocatorBase * point_locator,
1807  const Elem * neighbor)
1808 {
1809 #ifdef LIBMESH_ENABLE_PERIODIC
1810  if (_periodic_boundaries && !_periodic_boundaries->empty())
1811  {
1812  libmesh_assert(point_locator);
1813  return elem->has_topological_neighbor(neighbor, _mesh, *point_locator, _periodic_boundaries);
1814  }
1815 #endif
1816  return elem->has_neighbor(neighbor);
1817 }
1818 
1819 
1820 
1821 } // namespace libMesh
1822 
1823 
1824 #endif
bool limit_level_mismatch_at_edge(const unsigned int max_mismatch)
bool has_neighbor(const Elem *elem) const
Definition: elem.h:2093
RefinementState refinement_flag() const
Definition: elem.h:2638
void send(const unsigned int dest_processor_id, const T &buf, const MessageTag &tag=no_tag) const
virtual element_iterator ancestor_elements_begin()=0
void uniformly_p_refine(unsigned int n=1)
void wait(std::vector< Request > &r)
Definition: request.C:213
const Elem * parent() const
Definition: elem.h:2479
virtual const std::vector< std::pair< dof_id_type, dof_id_type > > bracketing_nodes(unsigned int c, unsigned int n) const
Definition: elem.C:2206
A geometric point in (x,y,z) space associated with a DOF.
Definition: node.h:52
const unsigned int invalid_uint
Definition: libmesh.h:245
virtual element_iterator not_local_elements_end()=0
std::unique_ptr< PointLocatorBase > sub_point_locator() const
Definition: mesh_base.C:496
bool limit_level_mismatch_at_node(const unsigned int max_mismatch)
virtual element_iterator level_elements_begin(unsigned int level)=0
const Elem * topological_neighbor(const unsigned int i, const MeshBase &mesh, const PointLocatorBase &point_locator, const PeriodicBoundaries *pb) const
Definition: elem.C:920
const unsigned int any_source
Definition: communicator.h:70
bool limit_underrefined_boundary(const signed char max_mismatch)
void add_scaled(const TypeVector< T2 > &, const T)
Definition: type_vector.h:627
Maps between boundary ids and PeriodicBoundaryBase objects.
void make_elems_parallel_consistent(MeshBase &)
static void set_node_processor_ids(MeshBase &mesh)
Definition: partitioner.C:679
dof_id_type find(dof_id_type bracket_node1, dof_id_type bracket_node2) const
Definition: topology_map.C:118
virtual element_iterator unpartitioned_elements_begin()=0
RefinementState p_refinement_flag() const
Definition: elem.h:2654
void add_node(const Node &mid_node, const std::vector< std::pair< dof_id_type, dof_id_type >> &bracketing_nodes)
Definition: topology_map.C:52
void remove(const Node *node)
unsigned short int side
Definition: xdr_io.C:50
The base class for all geometric element types.
Definition: elem.h:100
virtual element_iterator ancestor_elements_end()=0
uint8_t processor_id_type
Definition: id_types.h:99
MPI_Request request
Definition: request.h:40
void uniformly_p_coarsen(unsigned int n=1)
void set_refinement_flag(const RefinementState rflag)
Definition: elem.h:2646
virtual float embedding_matrix(const unsigned int child_num, const unsigned int child_node_num, const unsigned int parent_node_num) const =0
void init(MeshBase &)
Definition: topology_map.C:35
const Parallel::Communicator & comm() const
bool limit_overrefined_boundary(const signed char max_mismatch)
unsigned int p_level() const
Definition: elem.h:2555
void create_parent_error_vector(const ErrorVector &error_per_cell, ErrorVector &error_per_parent, Real &parent_error_min, Real &parent_error_max)
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
MessageTag get_unique_tag(int tagvalue) const
Definition: communicator.C:201
const BoundaryInfo & get_boundary_info() const
Definition: mesh_base.h:131
long double max(long double a, double b)
PeriodicBoundaries * _periodic_boundaries
unsigned int max_level(const MeshBase &mesh)
signed char _underrefined_boundary_limit
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Base class for Mesh.
Definition: mesh_base.h:77
SimpleRange< ChildRefIter > child_ref_range()
Definition: elem.h:1779
bool has_topological_neighbor(const Elem *elem, const MeshBase &mesh, const PointLocatorBase &point_locator, const PeriodicBoundaries *pb) const
Definition: elem.C:957
virtual element_iterator elements_begin()=0
virtual SimpleRange< element_iterator > active_local_element_ptr_range()=0
virtual element_iterator level_elements_end(unsigned int level)=0
processor_id_type n_processors() const
virtual bool is_serial() const
Definition: mesh_base.h:154
bool test_level_one(bool libmesh_assert_yes=false)
virtual SimpleRange< element_iterator > element_ptr_range()=0
dof_id_type id() const
Definition: dof_object.h:655
unsigned char _face_level_mismatch_limit
static const processor_id_type invalid_processor_id
Definition: dof_object.h:358
virtual unsigned int as_parent_node(unsigned int c, unsigned int n) const
Definition: elem.C:1933
virtual Elem * add_elem(Elem *e)=0
virtual void update_parallel_id_counts()=0
virtual element_iterator elements_end()=0
void uniformly_coarsen(unsigned int n=1)
void make_p_levels_parallel_consistent(MeshBase &)
SimpleRange< I > as_range(const std::pair< I, I > &p)
Definition: simple_range.h:57
static const dof_id_type invalid_id
Definition: dof_object.h:347
void prepare_for_use(const bool skip_renumber_nodes_and_elements=false, const bool skip_find_neighbors=false)
Definition: mesh_base.C:152
signed char _overrefined_boundary_limit
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
An object whose state is distributed along a set of processors.
bool has_topological_neighbor(const Elem *elem, const PointLocatorBase *point_locator, const Elem *neighbor)
MeshRefinement(MeshBase &mesh)
Node * add_node(Elem &parent, unsigned int child, unsigned int node, processor_id_type proc_id)
void send_coarse_ghosts(MeshBase &) const
unsigned char _node_level_mismatch_limit
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2050
virtual element_iterator active_not_local_elements_end()=0
unsigned int level() const
Definition: elem.h:2521
bool test_unflagged(bool libmesh_assert_yes=false)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Elem * add_elem(Elem *elem)
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:1957
void make_nodes_parallel_consistent(MeshBase &)
virtual bool is_replicated() const
Definition: mesh_base.h:176
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:504
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
virtual element_iterator unpartitioned_elements_end()=0
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2148
void _smooth_flags(bool refining, bool coarsening)
virtual element_iterator active_not_local_elements_begin()=0
virtual void libmesh_assert_valid_parallel_ids() const
Definition: mesh_base.h:1007
unsigned char _edge_level_mismatch_limit
void set_p_refinement_flag(const RefinementState pflag)
Definition: elem.h:2662
void libmesh_assert_valid_neighbors(const MeshBase &mesh, bool assert_valid_remote_elems=true)
Definition: mesh_tools.C:2068
virtual element_iterator not_local_elements_begin()=0
virtual const Node * node_ptr(const dof_id_type i) const =0
processor_id_type processor_id() const
void make_new_nodes_parallel_consistent(MeshBase &)
OStreamProxy out(std::cout)
bool active() const
Definition: elem.h:2390
processor_id_type processor_id() const
Definition: dof_object.h:717
void set_periodic_boundaries_ptr(PeriodicBoundaries *pb_ptr)
Elem * topological_neighbor(Elem *elem, const PointLocatorBase *point_locator, const unsigned int side)
long double min(long double a, double b)
A geometric point in (x,y,z) space.
Definition: point.h:38
const Point & point(const unsigned int i) const
Definition: elem.h:1892
bool has_children() const
Definition: elem.h:2428
uint8_t dof_id_type
Definition: id_types.h:64
void uniformly_refine(unsigned int n=1)
const RemoteElem * remote_elem
Definition: remote_elem.C:57