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