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 
20 // Local includes
21 #include "libmesh/libmesh_config.h"
22 
23 // only compile these functions if the user requests AMR support
24 #ifdef LIBMESH_ENABLE_AMR
25 
26 // C++ includes
27 #include <algorithm> // for std::sort
28 
29 // Local includes
30 #include "libmesh/elem.h"
31 #include "libmesh/error_vector.h"
32 #include "libmesh/mesh_refinement.h"
33 #include "libmesh/mesh_base.h"
34 #include "libmesh/parallel.h"
35 #include "libmesh/remote_elem.h"
36 
37 namespace libMesh
38 {
39 
40 
41 
42 //-----------------------------------------------------------------
43 // Mesh refinement methods
flag_elements_by_error_fraction(const ErrorVector & error_per_cell,const Real refine_frac,const Real coarsen_frac,const unsigned int max_l)44 void MeshRefinement::flag_elements_by_error_fraction (const ErrorVector & error_per_cell,
45                                                       const Real refine_frac,
46                                                       const Real coarsen_frac,
47                                                       const unsigned int max_l)
48 {
49   parallel_object_only();
50 
51   // Verify that our error vector is consistent, using std::vector to
52   // avoid confusing this->comm().verify
53   libmesh_assert(this->comm().verify(dynamic_cast<const std::vector<ErrorVectorReal> &>(error_per_cell)));
54 
55   // The function arguments are currently just there for
56   // backwards_compatibility
57   if (!_use_member_parameters)
58     {
59       // If the user used non-default parameters, lets warn
60       // that they're deprecated
61       if (refine_frac != 0.3 ||
62           coarsen_frac != 0.0 ||
63           max_l != libMesh::invalid_uint)
64         libmesh_deprecated();
65 
66       _refine_fraction = refine_frac;
67       _coarsen_fraction = coarsen_frac;
68       _max_h_level = max_l;
69     }
70 
71   // Check for valid fractions..
72   // The fraction values must be in [0,1]
73   libmesh_assert_greater_equal (_refine_fraction, 0);
74   libmesh_assert_less_equal (_refine_fraction, 1);
75   libmesh_assert_greater_equal (_coarsen_fraction, 0);
76   libmesh_assert_less_equal (_coarsen_fraction, 1);
77 
78   // Clean up the refinement flags.  These could be left
79   // over from previous refinement steps.
80   this->clean_refinement_flags();
81 
82   // We're getting the minimum and maximum error values
83   // for the ACTIVE elements
84   Real error_min = 1.e30;
85   Real error_max = 0.;
86 
87   // And, if necessary, for their parents
88   Real parent_error_min = 1.e30;
89   Real parent_error_max = 0.;
90 
91   // Prepare another error vector if we need to sum parent errors
92   ErrorVector error_per_parent;
93   if (_coarsen_by_parents)
94     {
95       create_parent_error_vector(error_per_cell,
96                                  error_per_parent,
97                                  parent_error_min,
98                                  parent_error_max);
99     }
100 
101   // We need to loop over all active elements to find the minimum
102   for (auto & elem : _mesh.active_local_element_ptr_range())
103     {
104       const dof_id_type id  = elem->id();
105       libmesh_assert_less (id, error_per_cell.size());
106 
107       error_max = std::max (error_max, error_per_cell[id]);
108       error_min = std::min (error_min, error_per_cell[id]);
109     }
110   this->comm().max(error_max);
111   this->comm().min(error_min);
112 
113   // Compute the cutoff values for coarsening and refinement
114   const Real error_delta = (error_max - error_min);
115   const Real parent_error_delta = parent_error_max - parent_error_min;
116 
117   const Real refine_cutoff  = (1.- _refine_fraction)*error_max;
118   const Real coarsen_cutoff = _coarsen_fraction*error_delta + error_min;
119   const Real parent_cutoff = _coarsen_fraction*parent_error_delta + error_min;
120 
121   //   // Print information about the error
122   //   libMesh::out << " Error Information:"                     << std::endl
123   //     << " ------------------"                     << std::endl
124   //     << "   min:              " << error_min      << std::endl
125   //     << "   max:              " << error_max      << std::endl
126   //     << "   delta:            " << error_delta    << std::endl
127   //     << "     refine_cutoff:  " << refine_cutoff  << std::endl
128   //     << "     coarsen_cutoff: " << coarsen_cutoff << std::endl;
129 
130 
131 
132   // Loop over the elements and flag them for coarsening or
133   // refinement based on the element error
134   for (auto & elem : _mesh.active_element_ptr_range())
135     {
136       const dof_id_type id = elem->id();
137 
138       libmesh_assert_less (id, error_per_cell.size());
139 
140       const ErrorVectorReal elem_error = error_per_cell[id];
141 
142       if (_coarsen_by_parents)
143         {
144           Elem * parent           = elem->parent();
145           if (parent)
146             {
147               const dof_id_type parentid  = parent->id();
148               if (error_per_parent[parentid] >= 0. &&
149                   error_per_parent[parentid] <= parent_cutoff)
150                 elem->set_refinement_flag(Elem::COARSEN);
151             }
152         }
153       // Flag the element for coarsening if its error
154       // is <= coarsen_fraction*delta + error_min
155       else if (elem_error <= coarsen_cutoff)
156         {
157           elem->set_refinement_flag(Elem::COARSEN);
158         }
159 
160       // Flag the element for refinement if its error
161       // is >= refinement_cutoff.
162       if (elem_error >= refine_cutoff)
163         if (elem->level() < _max_h_level)
164           elem->set_refinement_flag(Elem::REFINE);
165     }
166 }
167 
168 
169 
flag_elements_by_error_tolerance(const ErrorVector & error_per_cell_in)170 void MeshRefinement::flag_elements_by_error_tolerance (const ErrorVector & error_per_cell_in)
171 {
172   parallel_object_only();
173 
174   // Verify that our error vector is consistent, using std::vector to
175   // avoid confusing this->comm().verify
176   libmesh_assert(this->comm().verify(dynamic_cast<const std::vector<ErrorVectorReal> &>(error_per_cell_in)));
177 
178   libmesh_assert_greater (_coarsen_threshold, 0);
179 
180   // Check for valid fractions..
181   // The fraction values must be in [0,1]
182   libmesh_assert_greater_equal (_refine_fraction, 0);
183   libmesh_assert_less_equal (_refine_fraction, 1);
184   libmesh_assert_greater_equal (_coarsen_fraction, 0);
185   libmesh_assert_less_equal (_coarsen_fraction, 1);
186 
187   // How much error per cell will we tolerate?
188   const Real local_refinement_tolerance =
189     _absolute_global_tolerance / std::sqrt(static_cast<Real>(_mesh.n_active_elem()));
190   const Real local_coarsening_tolerance =
191     local_refinement_tolerance * _coarsen_threshold;
192 
193   // Prepare another error vector if we need to sum parent errors
194   ErrorVector error_per_parent;
195   if (_coarsen_by_parents)
196     {
197       Real parent_error_min, parent_error_max;
198 
199       create_parent_error_vector(error_per_cell_in,
200                                  error_per_parent,
201                                  parent_error_min,
202                                  parent_error_max);
203     }
204 
205   for (auto & elem : _mesh.active_element_ptr_range())
206     {
207       Elem * parent = elem->parent();
208       const dof_id_type elem_number    = elem->id();
209       const ErrorVectorReal elem_error = error_per_cell_in[elem_number];
210 
211       if (elem_error > local_refinement_tolerance &&
212           elem->level() < _max_h_level)
213         elem->set_refinement_flag(Elem::REFINE);
214 
215       if (!_coarsen_by_parents && elem_error <
216           local_coarsening_tolerance)
217         elem->set_refinement_flag(Elem::COARSEN);
218 
219       if (_coarsen_by_parents && parent)
220         {
221           ErrorVectorReal parent_error = error_per_parent[parent->id()];
222           if (parent_error >= 0.)
223             {
224               const Real parent_coarsening_tolerance =
225                 std::sqrt(parent->n_children() *
226                           local_coarsening_tolerance *
227                           local_coarsening_tolerance);
228               if (parent_error < parent_coarsening_tolerance)
229                 elem->set_refinement_flag(Elem::COARSEN);
230             }
231         }
232     }
233 }
234 
235 
236 
flag_elements_by_nelem_target(const ErrorVector & error_per_cell)237 bool MeshRefinement::flag_elements_by_nelem_target (const ErrorVector & error_per_cell)
238 {
239   parallel_object_only();
240 
241   // Verify that our error vector is consistent, using std::vector to
242   // avoid confusing this->comm().verify
243   libmesh_assert(this->comm().verify(dynamic_cast<const std::vector<ErrorVectorReal> &>(error_per_cell)));
244 
245   // Check for valid fractions..
246   // The fraction values must be in [0,1]
247   libmesh_assert_greater_equal (_refine_fraction, 0);
248   libmesh_assert_less_equal (_refine_fraction, 1);
249   libmesh_assert_greater_equal (_coarsen_fraction, 0);
250   libmesh_assert_less_equal (_coarsen_fraction, 1);
251 
252   // This function is currently only coded to work when coarsening by
253   // parents - it's too hard to guess how many coarsenings will be
254   // performed otherwise.
255   libmesh_assert (_coarsen_by_parents);
256 
257   // The number of active elements in the mesh - hopefully less than
258   // 2 billion on 32 bit machines
259   const dof_id_type n_active_elem  = _mesh.n_active_elem();
260 
261   // The maximum number of active elements to flag for coarsening
262   const dof_id_type max_elem_coarsen =
263     static_cast<dof_id_type>(_coarsen_fraction * n_active_elem) + 1;
264 
265   // The maximum number of elements to flag for refinement
266   const dof_id_type max_elem_refine  =
267     static_cast<dof_id_type>(_refine_fraction  * n_active_elem) + 1;
268 
269   // Clean up the refinement flags.  These could be left
270   // over from previous refinement steps.
271   this->clean_refinement_flags();
272 
273   // The target number of elements to add or remove
274   const std::ptrdiff_t n_elem_new =
275     std::ptrdiff_t(_nelem_target) - std::ptrdiff_t(n_active_elem);
276 
277   // Create an vector with active element errors and ids,
278   // sorted by highest errors first
279   const dof_id_type max_elem_id = _mesh.max_elem_id();
280   std::vector<std::pair<ErrorVectorReal, dof_id_type>> sorted_error;
281 
282   sorted_error.reserve (n_active_elem);
283 
284   // On a DistributedMesh, we need to communicate to know which remote ids
285   // correspond to active elements.
286   {
287     std::vector<bool> is_active(max_elem_id, false);
288 
289     for (auto & elem : _mesh.active_local_element_ptr_range())
290       {
291         const dof_id_type eid = elem->id();
292         is_active[eid] = true;
293         libmesh_assert_less (eid, error_per_cell.size());
294         sorted_error.emplace_back(error_per_cell[eid], eid);
295       }
296 
297     this->comm().max(is_active);
298 
299     this->comm().allgather(sorted_error);
300   }
301 
302   // Default sort works since pairs are sorted lexicographically
303   std::sort (sorted_error.begin(), sorted_error.end());
304   std::reverse (sorted_error.begin(), sorted_error.end());
305 
306   // Create a sorted error vector with coarsenable parent elements
307   // only, sorted by lowest errors first
308   ErrorVector error_per_parent;
309   std::vector<std::pair<ErrorVectorReal, dof_id_type>> sorted_parent_error;
310   Real parent_error_min, parent_error_max;
311 
312   create_parent_error_vector(error_per_cell,
313                              error_per_parent,
314                              parent_error_min,
315                              parent_error_max);
316 
317   // create_parent_error_vector sets values for non-parents and
318   // non-coarsenable parents to -1.  Get rid of them.
319   for (auto i : index_range(error_per_parent))
320     if (error_per_parent[i] != -1)
321       sorted_parent_error.emplace_back(error_per_parent[i], i);
322 
323   std::sort (sorted_parent_error.begin(), sorted_parent_error.end());
324 
325   // Keep track of how many elements we plan to coarsen & refine
326   dof_id_type coarsen_count = 0;
327   dof_id_type refine_count = 0;
328 
329   const unsigned int dim = _mesh.mesh_dimension();
330   unsigned int twotodim = 1;
331   for (unsigned int i=0; i!=dim; ++i)
332     twotodim *= 2;
333 
334   // First, let's try to get our element count to target_nelem
335   if (n_elem_new >= 0)
336     {
337       // Every element refinement creates at least
338       // 2^dim-1 new elements
339       refine_count =
340         std::min(cast_int<dof_id_type>(n_elem_new / (twotodim-1)),
341                  max_elem_refine);
342     }
343   else
344     {
345       // Every successful element coarsening is likely to destroy
346       // 2^dim-1 net elements.
347       coarsen_count =
348         std::min(cast_int<dof_id_type>(-n_elem_new / (twotodim-1)),
349                  max_elem_coarsen);
350     }
351 
352   // Next, let's see if we can trade any refinement for coarsening
353   while (coarsen_count < max_elem_coarsen &&
354          refine_count < max_elem_refine &&
355          coarsen_count < sorted_parent_error.size() &&
356          refine_count < sorted_error.size() &&
357          sorted_error[refine_count].first >
358          sorted_parent_error[coarsen_count].first * _coarsen_threshold)
359     {
360       coarsen_count++;
361       refine_count++;
362     }
363 
364   // On a DistributedMesh, we need to communicate to know which remote ids
365   // correspond to refinable elements
366   dof_id_type successful_refine_count = 0;
367   {
368     std::vector<bool> is_refinable(max_elem_id, false);
369 
370     for (const auto & pr : sorted_error)
371       {
372         dof_id_type eid = pr.second;
373         Elem * elem = _mesh.query_elem_ptr(eid);
374         if (elem && elem->level() < _max_h_level)
375           is_refinable[eid] = true;
376       }
377     this->comm().max(is_refinable);
378 
379     if (refine_count > max_elem_refine)
380       refine_count = max_elem_refine;
381     for (const auto & pr : sorted_error)
382       {
383         if (successful_refine_count >= refine_count)
384           break;
385 
386         dof_id_type eid = pr.second;
387         Elem * elem = _mesh.query_elem_ptr(eid);
388         if (is_refinable[eid])
389           {
390             if (elem)
391               elem->set_refinement_flag(Elem::REFINE);
392             successful_refine_count++;
393           }
394       }
395   }
396 
397   // If we couldn't refine enough elements, don't coarsen too many
398   // either
399   if (coarsen_count < (refine_count - successful_refine_count))
400     coarsen_count = 0;
401   else
402     coarsen_count -= (refine_count - successful_refine_count);
403 
404   if (coarsen_count > max_elem_coarsen)
405     coarsen_count = max_elem_coarsen;
406 
407   dof_id_type successful_coarsen_count = 0;
408   if (coarsen_count)
409     {
410       for (const auto & pr : sorted_parent_error)
411         {
412           if (successful_coarsen_count >= coarsen_count * twotodim)
413             break;
414 
415           dof_id_type parent_id = pr.second;
416           Elem * parent = _mesh.query_elem_ptr(parent_id);
417 
418           // On a DistributedMesh we skip remote elements
419           if (!parent)
420             continue;
421 
422           libmesh_assert(parent->has_children());
423           for (auto & elem : parent->child_ref_range())
424             {
425               if (&elem != remote_elem)
426                 {
427                   libmesh_assert(elem.active());
428                   elem.set_refinement_flag(Elem::COARSEN);
429                   successful_coarsen_count++;
430                 }
431             }
432         }
433     }
434 
435   // Return true if we've done all the AMR/C we can
436   if (!successful_coarsen_count &&
437       !successful_refine_count)
438     return true;
439   // And false if there may still be more to do.
440   return false;
441 }
442 
443 
444 
flag_elements_by_elem_fraction(const ErrorVector & error_per_cell,const Real refine_frac,const Real coarsen_frac,const unsigned int max_l)445 void MeshRefinement::flag_elements_by_elem_fraction (const ErrorVector & error_per_cell,
446                                                      const Real refine_frac,
447                                                      const Real coarsen_frac,
448                                                      const unsigned int max_l)
449 {
450   parallel_object_only();
451 
452   // Verify that our error vector is consistent, using std::vector to
453   // avoid confusing this->comm().verify
454   libmesh_assert(this->comm().verify(dynamic_cast<const std::vector<ErrorVectorReal> &>(error_per_cell)));
455 
456   // The function arguments are currently just there for
457   // backwards_compatibility
458   if (!_use_member_parameters)
459     {
460       // If the user used non-default parameters, lets warn
461       // that they're deprecated
462       if (refine_frac != 0.3 ||
463           coarsen_frac != 0.0 ||
464           max_l != libMesh::invalid_uint)
465         libmesh_deprecated();
466 
467       _refine_fraction = refine_frac;
468       _coarsen_fraction = coarsen_frac;
469       _max_h_level = max_l;
470     }
471 
472   // Check for valid fractions..
473   // The fraction values must be in [0,1]
474   libmesh_assert_greater_equal (_refine_fraction, 0);
475   libmesh_assert_less_equal (_refine_fraction, 1);
476   libmesh_assert_greater_equal (_coarsen_fraction, 0);
477   libmesh_assert_less_equal (_coarsen_fraction, 1);
478 
479   // The number of active elements in the mesh
480   const dof_id_type n_active_elem  = _mesh.n_active_elem();
481 
482   // The number of elements to flag for coarsening
483   const dof_id_type n_elem_coarsen =
484     static_cast<dof_id_type>(_coarsen_fraction * n_active_elem);
485 
486   // The number of elements to flag for refinement
487   const dof_id_type n_elem_refine =
488     static_cast<dof_id_type>(_refine_fraction  * n_active_elem);
489 
490 
491 
492   // Clean up the refinement flags.  These could be left
493   // over from previous refinement steps.
494   this->clean_refinement_flags();
495 
496 
497   // This vector stores the error and element number for all the
498   // active elements.  It will be sorted and the top & bottom
499   // elements will then be flagged for coarsening & refinement
500   std::vector<ErrorVectorReal> sorted_error;
501 
502   sorted_error.reserve (n_active_elem);
503 
504   // Loop over the active elements and create the entry
505   // in the sorted_error vector
506   for (auto & elem : _mesh.active_local_element_ptr_range())
507     sorted_error.push_back (error_per_cell[elem->id()]);
508 
509   this->comm().allgather(sorted_error);
510 
511   // Now sort the sorted_error vector
512   std::sort (sorted_error.begin(), sorted_error.end());
513 
514   // If we're coarsening by parents:
515   // Create a sorted error vector with coarsenable parent elements
516   // only, sorted by lowest errors first
517   ErrorVector error_per_parent, sorted_parent_error;
518   if (_coarsen_by_parents)
519     {
520       Real parent_error_min, parent_error_max;
521 
522       create_parent_error_vector(error_per_cell,
523                                  error_per_parent,
524                                  parent_error_min,
525                                  parent_error_max);
526 
527       sorted_parent_error = error_per_parent;
528       std::sort (sorted_parent_error.begin(), sorted_parent_error.end());
529 
530       // All the other error values will be 0., so get rid of them.
531       sorted_parent_error.erase (std::remove(sorted_parent_error.begin(),
532                                              sorted_parent_error.end(), 0.),
533                                  sorted_parent_error.end());
534     }
535 
536 
537   ErrorVectorReal top_error= 0., bottom_error = 0.;
538 
539   // Get the maximum error value corresponding to the
540   // bottom n_elem_coarsen elements
541   if (_coarsen_by_parents && n_elem_coarsen)
542     {
543       const unsigned int dim = _mesh.mesh_dimension();
544       unsigned int twotodim = 1;
545       for (unsigned int i=0; i!=dim; ++i)
546         twotodim *= 2;
547 
548       dof_id_type n_parent_coarsen = n_elem_coarsen / (twotodim - 1);
549 
550       if (n_parent_coarsen)
551         bottom_error = sorted_parent_error[n_parent_coarsen - 1];
552     }
553   else if (n_elem_coarsen)
554     {
555       bottom_error = sorted_error[n_elem_coarsen - 1];
556     }
557 
558   if (n_elem_refine)
559     top_error = sorted_error[sorted_error.size() - n_elem_refine];
560 
561   // Finally, let's do the element flagging
562   for (auto & elem : _mesh.active_element_ptr_range())
563     {
564       Elem * parent = elem->parent();
565 
566       if (_coarsen_by_parents && parent && n_elem_coarsen &&
567           error_per_parent[parent->id()] <= bottom_error)
568         elem->set_refinement_flag(Elem::COARSEN);
569 
570       if (!_coarsen_by_parents && n_elem_coarsen &&
571           error_per_cell[elem->id()] <= bottom_error)
572         elem->set_refinement_flag(Elem::COARSEN);
573 
574       if (n_elem_refine &&
575           elem->level() < _max_h_level &&
576           error_per_cell[elem->id()] >= top_error)
577         elem->set_refinement_flag(Elem::REFINE);
578     }
579 }
580 
581 
582 
flag_elements_by_mean_stddev(const ErrorVector & error_per_cell,const Real refine_frac,const Real coarsen_frac,const unsigned int max_l)583 void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector & error_per_cell,
584                                                    const Real refine_frac,
585                                                    const Real coarsen_frac,
586                                                    const unsigned int max_l)
587 {
588   // Verify that our error vector is consistent, using std::vector to
589   // avoid confusing this->comm().verify
590   libmesh_assert(this->comm().verify(dynamic_cast<const std::vector<ErrorVectorReal> &>(error_per_cell)));
591 
592   // The function arguments are currently just there for
593   // backwards_compatibility
594   if (!_use_member_parameters)
595     {
596       // If the user used non-default parameters, lets warn
597       // that they're deprecated
598       if (refine_frac != 0.3 ||
599           coarsen_frac != 0.0 ||
600           max_l != libMesh::invalid_uint)
601         libmesh_deprecated();
602 
603       _refine_fraction = refine_frac;
604       _coarsen_fraction = coarsen_frac;
605       _max_h_level = max_l;
606     }
607 
608   // Get the mean value from the error vector
609   const Real mean = error_per_cell.mean();
610 
611   // Get the standard deviation.  This equals the
612   // square-root of the variance
613   const Real stddev = std::sqrt (error_per_cell.variance());
614 
615   // Check for valid fractions
616   libmesh_assert_greater_equal (_refine_fraction, 0);
617   libmesh_assert_less_equal (_refine_fraction, 1);
618   libmesh_assert_greater_equal (_coarsen_fraction, 0);
619   libmesh_assert_less_equal (_coarsen_fraction, 1);
620 
621   // The refine and coarsen cutoff
622   const Real refine_cutoff  =  mean + _refine_fraction  * stddev;
623   const Real coarsen_cutoff =  std::max(mean - _coarsen_fraction * stddev, 0.);
624 
625   // Loop over the elements and flag them for coarsening or
626   // refinement based on the element error
627   for (auto & elem : _mesh.active_element_ptr_range())
628     {
629       const dof_id_type id  = elem->id();
630 
631       libmesh_assert_less (id, error_per_cell.size());
632 
633       const ErrorVectorReal elem_error = error_per_cell[id];
634 
635       // Possibly flag the element for coarsening ...
636       if (elem_error <= coarsen_cutoff)
637         elem->set_refinement_flag(Elem::COARSEN);
638 
639       // ... or refinement
640       if ((elem_error >= refine_cutoff) && (elem->level() < _max_h_level))
641         elem->set_refinement_flag(Elem::REFINE);
642     }
643 }
644 
645 
646 
flag_elements_by(ElementFlagging & element_flagging)647 void MeshRefinement::flag_elements_by (ElementFlagging & element_flagging)
648 {
649   element_flagging.flag_elements();
650 }
651 
652 
653 
switch_h_to_p_refinement()654 void MeshRefinement::switch_h_to_p_refinement ()
655 {
656   for (auto & elem : _mesh.element_ptr_range())
657     {
658       if (elem->active())
659         {
660           elem->set_p_refinement_flag(elem->refinement_flag());
661           elem->set_refinement_flag(Elem::DO_NOTHING);
662         }
663       else
664         {
665           elem->set_p_refinement_flag(elem->refinement_flag());
666           elem->set_refinement_flag(Elem::INACTIVE);
667         }
668     }
669 }
670 
671 
672 
add_p_to_h_refinement()673 void MeshRefinement::add_p_to_h_refinement ()
674 {
675   for (auto & elem : _mesh.element_ptr_range())
676     elem->set_p_refinement_flag(elem->refinement_flag());
677 }
678 
679 
680 
clean_refinement_flags()681 void MeshRefinement::clean_refinement_flags ()
682 {
683   // Possibly clean up the refinement flags from
684   // a previous step
685   for (auto & elem : _mesh.element_ptr_range())
686     {
687       if (elem->active())
688         {
689           elem->set_refinement_flag(Elem::DO_NOTHING);
690           elem->set_p_refinement_flag(Elem::DO_NOTHING);
691         }
692       else
693         {
694           elem->set_refinement_flag(Elem::INACTIVE);
695           elem->set_p_refinement_flag(Elem::INACTIVE);
696         }
697     }
698 }
699 
700 } // namespace libMesh
701 
702 #endif
703