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