LCOV - code coverage report
Current view: top level - src/mesh - mesh_refinement_flagging.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 174 288 60.4 %
Date: 2025-08-19 19:27:09 Functions: 6 9 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 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
      44       10908 : 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         404 :   parallel_object_only();
      50             : 
      51             :   // Verify that our error vector is consistent, using std::vector to
      52             :   // avoid confusing this->comm().verify
      53         404 :   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       10908 :   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           0 :       _refine_fraction = refine_frac;
      67           0 :       _coarsen_fraction = coarsen_frac;
      68           0 :       _max_h_level = max_l;
      69             :     }
      70             : 
      71             :   // Check for valid fractions..
      72             :   // The fraction values must be in [0,1]
      73         404 :   libmesh_assert_greater_equal (_refine_fraction, 0);
      74         404 :   libmesh_assert_less_equal (_refine_fraction, 1);
      75         404 :   libmesh_assert_greater_equal (_coarsen_fraction, 0);
      76         404 :   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       10908 :   this->clean_refinement_flags();
      81             : 
      82             :   // We're getting the minimum and maximum error values
      83             :   // for the ACTIVE elements
      84       10908 :   Real error_min = 1.e30;
      85       10908 :   Real error_max = 0.;
      86             : 
      87             :   // And, if necessary, for their parents
      88       10908 :   Real parent_error_min = 1.e30;
      89       10908 :   Real parent_error_max = 0.;
      90             : 
      91             :   // Prepare another error vector if we need to sum parent errors
      92         808 :   ErrorVector error_per_parent;
      93       10908 :   if (_coarsen_by_parents)
      94             :     {
      95           0 :       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      979722 :   for (auto & elem : _mesh.active_local_element_ptr_range())
     103             :     {
     104      958310 :       const dof_id_type id  = elem->id();
     105      108750 :       libmesh_assert_less (id, error_per_cell.size());
     106             : 
     107     1067060 :       error_max = std::max (error_max, error_per_cell[id]);
     108     1020739 :       error_min = std::min (error_min, error_per_cell[id]);
     109       10100 :     }
     110       10908 :   this->comm().max(error_max);
     111       10908 :   this->comm().min(error_min);
     112             : 
     113             :   // Compute the cutoff values for coarsening and refinement
     114       10908 :   const Real error_delta = (error_max - error_min);
     115       10908 :   const Real parent_error_delta = parent_error_max - parent_error_min;
     116             : 
     117       10908 :   const Real refine_cutoff  = (1.- _refine_fraction)*error_max;
     118       10908 :   const Real coarsen_cutoff = _coarsen_fraction*error_delta + error_min;
     119       10908 :   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     9568674 :   for (auto & elem : _mesh.active_element_ptr_range())
     135             :     {
     136     4991131 :       const dof_id_type id = elem->id();
     137             : 
     138      217500 :       libmesh_assert_less (id, error_per_cell.size());
     139             : 
     140     4991131 :       const ErrorVectorReal elem_error = error_per_cell[id];
     141             : 
     142     4991131 :       if (_coarsen_by_parents)
     143             :         {
     144           0 :           Elem * parent           = elem->parent();
     145           0 :           if (parent)
     146             :             {
     147           0 :               const dof_id_type parentid  = parent->id();
     148           0 :               if (error_per_parent[parentid] >= 0. &&
     149           0 :                   error_per_parent[parentid] <= parent_cutoff)
     150           0 :                 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     4991131 :       else if (elem_error <= coarsen_cutoff)
     156             :         {
     157       72200 :           elem->set_refinement_flag(Elem::COARSEN);
     158             :         }
     159             : 
     160             :       // Flag the element for refinement if its error
     161             :       // is >= refinement_cutoff.
     162     4991131 :       if (elem_error >= refine_cutoff)
     163     1000769 :         if (elem->level() < _max_h_level)
     164      135626 :           elem->set_refinement_flag(Elem::REFINE);
     165       10100 :     }
     166       10908 : }
     167             : 
     168             : 
     169             : 
     170           0 : void MeshRefinement::flag_elements_by_error_tolerance (const ErrorVector & error_per_cell_in)
     171             : {
     172           0 :   parallel_object_only();
     173             : 
     174             :   // Verify that our error vector is consistent, using std::vector to
     175             :   // avoid confusing this->comm().verify
     176           0 :   libmesh_assert(this->comm().verify(dynamic_cast<const std::vector<ErrorVectorReal> &>(error_per_cell_in)));
     177             : 
     178           0 :   libmesh_assert_greater (_coarsen_threshold, 0);
     179             : 
     180             :   // Check for valid fractions..
     181             :   // The fraction values must be in [0,1]
     182           0 :   libmesh_assert_greater_equal (_refine_fraction, 0);
     183           0 :   libmesh_assert_less_equal (_refine_fraction, 1);
     184           0 :   libmesh_assert_greater_equal (_coarsen_fraction, 0);
     185           0 :   libmesh_assert_less_equal (_coarsen_fraction, 1);
     186             : 
     187             :   // How much error per cell will we tolerate?
     188             :   const Real local_refinement_tolerance =
     189           0 :     _absolute_global_tolerance / std::sqrt(static_cast<Real>(_mesh.n_active_elem()));
     190           0 :   const Real local_coarsening_tolerance =
     191           0 :     local_refinement_tolerance * _coarsen_threshold;
     192             : 
     193             :   // Prepare another error vector if we need to sum parent errors
     194           0 :   ErrorVector error_per_parent;
     195           0 :   if (_coarsen_by_parents)
     196             :     {
     197             :       Real parent_error_min, parent_error_max;
     198             : 
     199           0 :       create_parent_error_vector(error_per_cell_in,
     200             :                                  error_per_parent,
     201             :                                  parent_error_min,
     202             :                                  parent_error_max);
     203             :     }
     204             : 
     205           0 :   for (auto & elem : _mesh.active_element_ptr_range())
     206             :     {
     207           0 :       Elem * parent = elem->parent();
     208           0 :       const dof_id_type elem_number    = elem->id();
     209           0 :       const ErrorVectorReal elem_error = error_per_cell_in[elem_number];
     210             : 
     211           0 :       if (elem_error > local_refinement_tolerance &&
     212           0 :           elem->level() < _max_h_level)
     213           0 :         elem->set_refinement_flag(Elem::REFINE);
     214             : 
     215           0 :       if (!_coarsen_by_parents && elem_error <
     216             :           local_coarsening_tolerance)
     217           0 :         elem->set_refinement_flag(Elem::COARSEN);
     218             : 
     219           0 :       if (_coarsen_by_parents && parent)
     220             :         {
     221           0 :           ErrorVectorReal parent_error = error_per_parent[parent->id()];
     222           0 :           if (parent_error >= 0.)
     223             :             {
     224             :               const Real parent_coarsening_tolerance =
     225           0 :                 std::sqrt(parent->n_children() *
     226             :                           local_coarsening_tolerance *
     227             :                           local_coarsening_tolerance);
     228           0 :               if (parent_error < parent_coarsening_tolerance)
     229           0 :                 elem->set_refinement_flag(Elem::COARSEN);
     230             :             }
     231             :         }
     232           0 :     }
     233           0 : }
     234             : 
     235             : 
     236             : 
     237        1590 : bool MeshRefinement::flag_elements_by_nelem_target (const ErrorVector & error_per_cell)
     238             : {
     239          82 :   parallel_object_only();
     240             : 
     241             :   // Verify that our error vector is consistent, using std::vector to
     242             :   // avoid confusing this->comm().verify
     243          82 :   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          82 :   libmesh_assert_greater_equal (_refine_fraction, 0);
     248          82 :   libmesh_assert_less_equal (_refine_fraction, 1);
     249          82 :   libmesh_assert_greater_equal (_coarsen_fraction, 0);
     250          82 :   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          82 :   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        1590 :   const dof_id_type n_active_elem  = _mesh.n_active_elem();
     260             : 
     261             :   // The maximum number of active elements to flag for coarsening
     262        1590 :   const dof_id_type max_elem_coarsen =
     263        1590 :     static_cast<dof_id_type>(_coarsen_fraction * n_active_elem) + 1;
     264             : 
     265             :   // The maximum number of elements to flag for refinement
     266        1590 :   const dof_id_type max_elem_refine  =
     267        1590 :     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        1590 :   this->clean_refinement_flags();
     272             : 
     273             :   // The target number of elements to add or remove
     274        1590 :   const std::ptrdiff_t n_elem_new =
     275        1590 :     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        1590 :   const dof_id_type max_elem_id = _mesh.max_elem_id();
     280         164 :   std::vector<std::pair<ErrorVectorReal, dof_id_type>> sorted_error;
     281             : 
     282        1590 :   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        1672 :     std::vector<bool> is_active(max_elem_id, false);
     288             : 
     289       79026 :     for (auto & elem : _mesh.active_local_element_ptr_range())
     290             :       {
     291       42484 :         const dof_id_type eid = elem->id();
     292       12646 :         is_active[eid] = true;
     293        4520 :         libmesh_assert_less (eid, error_per_cell.size());
     294       47004 :         sorted_error.emplace_back(error_per_cell[eid], eid);
     295        1426 :       }
     296             : 
     297        1590 :     this->comm().max(is_active);
     298             : 
     299        1590 :     this->comm().allgather(sorted_error);
     300             :   }
     301             : 
     302             :   // Default sort works since pairs are sorted lexicographically
     303        1590 :   std::sort (sorted_error.begin(), sorted_error.end());
     304        1508 :   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         164 :   ErrorVector error_per_parent;
     309         164 :   std::vector<std::pair<ErrorVectorReal, dof_id_type>> sorted_parent_error;
     310             :   Real parent_error_min, parent_error_max;
     311             : 
     312        1590 :   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      302928 :   for (auto i : index_range(error_per_parent))
     320      312918 :     if (error_per_parent[i] != -1)
     321       43980 :       sorted_parent_error.emplace_back(error_per_parent[i], i);
     322             : 
     323        1590 :   std::sort (sorted_parent_error.begin(), sorted_parent_error.end());
     324             : 
     325             :   // Keep track of how many elements we plan to coarsen & refine
     326          82 :   dof_id_type coarsen_count = 0;
     327          82 :   dof_id_type refine_count = 0;
     328             : 
     329        1590 :   const unsigned int dim = _mesh.mesh_dimension();
     330          82 :   unsigned int twotodim = 1;
     331        4770 :   for (unsigned int i=0; i!=dim; ++i)
     332        3180 :     twotodim *= 2;
     333             : 
     334             :   // First, let's try to get our element count to target_nelem
     335        1590 :   if (n_elem_new >= 0)
     336             :     {
     337             :       // Every element refinement creates at least
     338             :       // 2^dim-1 new elements
     339        1590 :       refine_count =
     340        3262 :         std::min(cast_int<dof_id_type>(n_elem_new / (twotodim-1)),
     341          82 :                  max_elem_refine);
     342             :     }
     343             :   else
     344             :     {
     345             :       // Every successful element coarsening is likely to destroy
     346             :       // 2^dim-1 net elements.
     347           0 :       coarsen_count =
     348           0 :         std::min(cast_int<dof_id_type>(-n_elem_new / (twotodim-1)),
     349           0 :                  max_elem_coarsen);
     350             :     }
     351             : 
     352             :   // Next, let's see if we can trade any refinement for coarsening
     353        1672 :   while (coarsen_count < max_elem_coarsen &&
     354          82 :          refine_count < max_elem_refine &&
     355           0 :          coarsen_count < sorted_parent_error.size() &&
     356        1672 :          refine_count < sorted_error.size() &&
     357           0 :          sorted_error[refine_count].first >
     358           0 :          sorted_parent_error[coarsen_count].first * _coarsen_threshold)
     359             :     {
     360           0 :       coarsen_count++;
     361           0 :       refine_count++;
     362             :     }
     363             : 
     364             :   // On a DistributedMesh, we need to communicate to know which remote ids
     365             :   // correspond to refinable elements
     366          82 :   dof_id_type successful_refine_count = 0;
     367             :   {
     368        1672 :     std::vector<bool> is_refinable(max_elem_id, false);
     369             : 
     370      239189 :     for (const auto & pr : sorted_error)
     371             :       {
     372      237599 :         dof_id_type eid = pr.second;
     373      237599 :         Elem * elem = _mesh.query_elem_ptr(eid);
     374      237599 :         if (elem && elem->level() < _max_h_level)
     375       18080 :           is_refinable[eid] = true;
     376             :       }
     377        1590 :     this->comm().max(is_refinable);
     378             : 
     379         164 :     if (refine_count > max_elem_refine)
     380           0 :       refine_count = max_elem_refine;
     381       29362 :     for (const auto & pr : sorted_error)
     382             :       {
     383       29362 :         if (successful_refine_count >= refine_count)
     384          82 :           break;
     385             : 
     386       27772 :         dof_id_type eid = pr.second;
     387       27772 :         Elem * elem = _mesh.query_elem_ptr(eid);
     388       28690 :         if (is_refinable[eid])
     389             :           {
     390       27772 :             if (elem)
     391         918 :               elem->set_refinement_flag(Elem::REFINE);
     392       27772 :             successful_refine_count++;
     393             :           }
     394             :       }
     395             :   }
     396             : 
     397             :   // If we couldn't refine enough elements, don't coarsen too many
     398             :   // either
     399        1590 :   if (coarsen_count < (refine_count - successful_refine_count))
     400           0 :     coarsen_count = 0;
     401             :   else
     402        1590 :     coarsen_count -= (refine_count - successful_refine_count);
     403             : 
     404         164 :   if (coarsen_count > max_elem_coarsen)
     405           0 :     coarsen_count = max_elem_coarsen;
     406             : 
     407          82 :   dof_id_type successful_coarsen_count = 0;
     408        1590 :   if (coarsen_count)
     409             :     {
     410           0 :       for (const auto & pr : sorted_parent_error)
     411             :         {
     412           0 :           if (successful_coarsen_count >= coarsen_count * twotodim)
     413           0 :             break;
     414             : 
     415           0 :           dof_id_type parent_id = pr.second;
     416           0 :           Elem * parent = _mesh.query_elem_ptr(parent_id);
     417             : 
     418             :           // On a DistributedMesh we skip remote elements
     419           0 :           if (!parent)
     420           0 :             continue;
     421             : 
     422           0 :           libmesh_assert(parent->has_children());
     423           0 :           for (auto & elem : parent->child_ref_range())
     424             :             {
     425           0 :               if (&elem != remote_elem)
     426             :                 {
     427           0 :                   libmesh_assert(elem.active());
     428           0 :                   elem.set_refinement_flag(Elem::COARSEN);
     429           0 :                   successful_coarsen_count++;
     430             :                 }
     431             :             }
     432             :         }
     433             :     }
     434             : 
     435             :   // Return true if we've done all the AMR/C we can
     436        1590 :   if (!successful_coarsen_count &&
     437             :       !successful_refine_count)
     438           0 :     return true;
     439             :   // And false if there may still be more to do.
     440          82 :   return false;
     441             : }
     442             : 
     443             : 
     444             : 
     445        2982 : 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          84 :   parallel_object_only();
     451             : 
     452             :   // Verify that our error vector is consistent, using std::vector to
     453             :   // avoid confusing this->comm().verify
     454          84 :   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        2982 :   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           0 :       _refine_fraction = refine_frac;
     468           0 :       _coarsen_fraction = coarsen_frac;
     469           0 :       _max_h_level = max_l;
     470             :     }
     471             : 
     472             :   // Check for valid fractions..
     473             :   // The fraction values must be in [0,1]
     474          84 :   libmesh_assert_greater_equal (_refine_fraction, 0);
     475          84 :   libmesh_assert_less_equal (_refine_fraction, 1);
     476          84 :   libmesh_assert_greater_equal (_coarsen_fraction, 0);
     477          84 :   libmesh_assert_less_equal (_coarsen_fraction, 1);
     478             : 
     479             :   // The number of active elements in the mesh
     480        2982 :   const dof_id_type n_active_elem  = _mesh.n_active_elem();
     481             : 
     482             :   // The number of elements to flag for coarsening
     483        2982 :   const dof_id_type n_elem_coarsen =
     484        2982 :     static_cast<dof_id_type>(_coarsen_fraction * n_active_elem);
     485             : 
     486             :   // The number of elements to flag for refinement
     487        2982 :   const dof_id_type n_elem_refine =
     488        2982 :     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        2982 :   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         168 :   std::vector<ErrorVectorReal> sorted_error;
     501             : 
     502        2982 :   sorted_error.reserve (n_active_elem);
     503             : 
     504             :   // Loop over the active elements and create the entry
     505             :   // in the sorted_error vector
     506       47980 :   for (auto & elem : _mesh.active_local_element_ptr_range())
     507       27676 :     sorted_error.push_back (error_per_cell[elem->id()]);
     508             : 
     509        2982 :   this->comm().allgather(sorted_error);
     510             : 
     511             :   // Now sort the sorted_error vector
     512        2982 :   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         168 :   ErrorVector error_per_parent, sorted_parent_error;
     518        2982 :   if (_coarsen_by_parents)
     519             :     {
     520             :       Real parent_error_min, parent_error_max;
     521             : 
     522           0 :       create_parent_error_vector(error_per_cell,
     523             :                                  error_per_parent,
     524             :                                  parent_error_min,
     525             :                                  parent_error_max);
     526             : 
     527           0 :       sorted_parent_error = error_per_parent;
     528           0 :       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           0 :       sorted_parent_error.erase (std::remove(sorted_parent_error.begin(),
     532           0 :                                              sorted_parent_error.end(), 0.),
     533           0 :                                  sorted_parent_error.end());
     534             :     }
     535             : 
     536             : 
     537          84 :   ErrorVectorReal top_error= 0., bottom_error = 0.;
     538             : 
     539             :   // Get the maximum error value corresponding to the
     540             :   // bottom n_elem_coarsen elements
     541        2982 :   if (_coarsen_by_parents && n_elem_coarsen)
     542             :     {
     543           0 :       const unsigned int dim = _mesh.mesh_dimension();
     544           0 :       unsigned int twotodim = 1;
     545           0 :       for (unsigned int i=0; i!=dim; ++i)
     546           0 :         twotodim *= 2;
     547             : 
     548           0 :       dof_id_type n_parent_coarsen = n_elem_coarsen / (twotodim - 1);
     549             : 
     550           0 :       if (n_parent_coarsen)
     551           0 :         bottom_error = sorted_parent_error[n_parent_coarsen - 1];
     552             :     }
     553        2982 :   else if (n_elem_coarsen)
     554             :     {
     555           0 :       bottom_error = sorted_error[n_elem_coarsen - 1];
     556             :     }
     557             : 
     558        2982 :   if (n_elem_refine)
     559        2100 :     top_error = sorted_error[sorted_error.size() - n_elem_refine];
     560             : 
     561             :   // Finally, let's do the element flagging
     562       93738 :   for (auto & elem : _mesh.active_element_ptr_range())
     563             :     {
     564       47741 :       Elem * parent = elem->parent();
     565             : 
     566       47741 :       if (_coarsen_by_parents && parent && n_elem_coarsen &&
     567           0 :           error_per_parent[parent->id()] <= bottom_error)
     568           0 :         elem->set_refinement_flag(Elem::COARSEN);
     569             : 
     570       47741 :       if (!_coarsen_by_parents && n_elem_coarsen &&
     571           0 :           error_per_cell[elem->id()] <= bottom_error)
     572           0 :         elem->set_refinement_flag(Elem::COARSEN);
     573             : 
     574       50937 :       if (n_elem_refine &&
     575       51497 :           elem->level() < _max_h_level &&
     576       50881 :           error_per_cell[elem->id()] >= top_error)
     577         996 :         elem->set_refinement_flag(Elem::REFINE);
     578        2814 :     }
     579        2982 : }
     580             : 
     581             : 
     582             : 
     583           0 : 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           0 :   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           0 :   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           0 :       _refine_fraction = refine_frac;
     604           0 :       _coarsen_fraction = coarsen_frac;
     605           0 :       _max_h_level = max_l;
     606             :     }
     607             : 
     608             :   // Get the mean value from the error vector
     609           0 :   const Real mean = error_per_cell.mean();
     610             : 
     611             :   // Get the standard deviation.  This equals the
     612             :   // square-root of the variance
     613           0 :   const Real stddev = std::sqrt (error_per_cell.variance());
     614             : 
     615             :   // Check for valid fractions
     616           0 :   libmesh_assert_greater_equal (_refine_fraction, 0);
     617           0 :   libmesh_assert_less_equal (_refine_fraction, 1);
     618           0 :   libmesh_assert_greater_equal (_coarsen_fraction, 0);
     619           0 :   libmesh_assert_less_equal (_coarsen_fraction, 1);
     620             : 
     621             :   // The refine and coarsen cutoff
     622           0 :   const Real refine_cutoff  =  mean + _refine_fraction  * stddev;
     623           0 :   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           0 :   for (auto & elem : _mesh.active_element_ptr_range())
     628             :     {
     629           0 :       const dof_id_type id  = elem->id();
     630             : 
     631           0 :       libmesh_assert_less (id, error_per_cell.size());
     632             : 
     633           0 :       const ErrorVectorReal elem_error = error_per_cell[id];
     634             : 
     635             :       // Possibly flag the element for coarsening ...
     636           0 :       if (elem_error <= coarsen_cutoff)
     637           0 :         elem->set_refinement_flag(Elem::COARSEN);
     638             : 
     639             :       // ... or refinement
     640           0 :       if ((elem_error >= refine_cutoff) && (elem->level() < _max_h_level))
     641           0 :         elem->set_refinement_flag(Elem::REFINE);
     642           0 :     }
     643           0 : }
     644             : 
     645             : 
     646             : 
     647           0 : void MeshRefinement::flag_elements_by (ElementFlagging & element_flagging)
     648             : {
     649           0 :   element_flagging.flag_elements();
     650           0 : }
     651             : 
     652             : 
     653             : 
     654        1349 : void MeshRefinement::switch_h_to_p_refinement ()
     655             : {
     656       40330 :   for (auto & elem : _mesh.element_ptr_range())
     657             :     {
     658       20193 :       if (elem->active())
     659             :         {
     660        1196 :           elem->set_p_refinement_flag(elem->refinement_flag());
     661        2392 :           elem->set_refinement_flag(Elem::DO_NOTHING);
     662             :         }
     663             :       else
     664             :         {
     665         162 :           elem->set_p_refinement_flag(elem->refinement_flag());
     666         324 :           elem->set_refinement_flag(Elem::INACTIVE);
     667             :         }
     668        1273 :     }
     669        1349 : }
     670             : 
     671             : 
     672             : 
     673         639 : void MeshRefinement::add_p_to_h_refinement ()
     674             : {
     675        5402 :   for (auto & elem : _mesh.element_ptr_range())
     676        2808 :     elem->set_p_refinement_flag(elem->refinement_flag());
     677         639 : }
     678             : 
     679             : 
     680             : 
     681      276852 : void MeshRefinement::clean_refinement_flags ()
     682             : {
     683             :   // Possibly clean up the refinement flags from
     684             :   // a previous step
     685    36362504 :   for (auto & elem : _mesh.element_ptr_range())
     686             :     {
     687    19280618 :       if (elem->active())
     688             :         {
     689     1103786 :           elem->set_refinement_flag(Elem::DO_NOTHING);
     690     2207572 :           elem->set_p_refinement_flag(Elem::DO_NOTHING);
     691             :         }
     692             :       else
     693             :         {
     694      268372 :           elem->set_refinement_flag(Elem::INACTIVE);
     695      536744 :           elem->set_p_refinement_flag(Elem::INACTIVE);
     696             :         }
     697      260612 :     }
     698      276852 : }
     699             : 
     700             : } // namespace libMesh
     701             : 
     702             : #endif

Generated by: LCOV version 1.14