LCOV - code coverage report
Current view: top level - src/mesh - simplex_refiner.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 225 264 85.2 %
Date: 2025-08-19 19:27:09 Functions: 12 22 54.5 %
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             : // Local includes
      20             : #include "libmesh/simplex_refiner.h"
      21             : 
      22             : #include "libmesh/boundary_info.h"
      23             : #include "libmesh/face_tri3.h"
      24             : #include "libmesh/int_range.h"
      25             : #include "libmesh/libmesh_logging.h"
      26             : #include "libmesh/mesh_base.h"
      27             : #include "libmesh/mesh_communication.h"
      28             : #include "libmesh/mesh_tools.h"
      29             : #include "libmesh/node.h"
      30             : #include "libmesh/parallel_algebra.h"
      31             : #include "libmesh/remote_elem.h"
      32             : #include "libmesh/unstructured_mesh.h"
      33             : #include "libmesh/utility.h"
      34             : 
      35             : // TIMPI includes
      36             : #include "timpi/parallel_implementation.h"
      37             : #include "timpi/parallel_sync.h"
      38             : 
      39             : 
      40             : namespace libMesh
      41             : {
      42             : 
      43             : //-----------------------------------------------------------------
      44             : // Mesh refinement methods
      45          94 : SimplexRefiner::SimplexRefiner (UnstructuredMesh & mesh) :
      46          86 :   _mesh(mesh),
      47          94 :   _desired_volume(0.1)
      48          94 : {}
      49             : 
      50             : 
      51             : 
      52          94 : bool SimplexRefiner::refine_elements()
      53             : {
      54          94 :   if (!_mesh.is_prepared())
      55           0 :     _mesh.prepare_for_use();
      56             : 
      57             :   // We should add more options later: to refine via circumcenter
      58             :   // insertion instead of edge center insertion, to do Delaunay swaps,
      59             :   // etc.
      60          94 :   return this->refine_via_edges();
      61             : }
      62             : 
      63             : 
      64             : 
      65       44097 : bool SimplexRefiner::should_refine_elem(Elem & elem)
      66             : {
      67       44097 :   const Real min_volume_target = this->desired_volume();
      68       44097 :   FunctionBase<Real> *volume_func = this->get_desired_volume_function();
      69             : 
      70             :   // If this isn't a question, why are we here?
      71        3212 :   libmesh_assert(min_volume_target > 0 ||
      72             :                  volume_func != nullptr);
      73             : 
      74             :   // If we don't have position-dependent volume targets we can make a
      75             :   // decision quickly
      76       44097 :   const Real volume = elem.volume();
      77             : 
      78             :   if (volume < TOLERANCE*TOLERANCE)
      79             :     libmesh_warning
      80             :       ("Warning: trying to refine sliver element with volume " <<
      81             :        volume << "!\n");
      82             : 
      83       44097 :   if (!volume_func)
      84       44097 :     return (volume > min_volume_target);
      85             : 
      86             :   // If we do?
      87             :   //
      88             :   // See if we're meeting the local volume target at all the elem
      89             :   // vertices first
      90           0 :   for (auto v : make_range(elem.n_vertices()))
      91             :     {
      92             :       // If we have an auto volume function, we'll use it and override other volume options
      93           0 :       const Real local_volume_target = (*volume_func)(elem.point(v));
      94           0 :       libmesh_error_msg_if
      95             :         (local_volume_target <= 0,
      96             :          "Non-positive desired element volumes are unachievable");
      97           0 :       if (volume > local_volume_target)
      98           0 :         return true;
      99             :     }
     100             : 
     101             :   // If our vertices are happy, it's still possible that our interior
     102             :   // isn't.  Are we allowed not to bother checking it?
     103           0 :   if (!min_volume_target)
     104           0 :     return false;
     105             : 
     106           0 :   libmesh_not_implemented_msg
     107             :     ("Combining a minimum desired_volume with an volume function isn't yet supported.");
     108             : }
     109             : 
     110             : 
     111       44097 : std::size_t SimplexRefiner::refine_via_edges(Elem & elem,
     112             :                                              dof_id_type coarse_id)
     113             : {
     114             :   // Do we need to be refined for our own sake, or only if our
     115             :   // neighbors were refined?
     116       44097 :   const bool should_refine = this->should_refine_elem(elem);
     117             : 
     118             :   // We only currently handle coarse conforming meshes here.
     119             :   // Uniformly refined meshes should be flattened before using this.
     120        3212 :   libmesh_assert_equal_to(elem.level(), 0u);
     121             : 
     122             :   // Adding Tets or Tri6/Tri7 wouldn't be too much harder.  Quads or
     123             :   // other elements will get tricky.
     124        3212 :   libmesh_assert_equal_to(elem.type(), TRI3);
     125             : 
     126       44097 :   const int n_sides = elem.n_sides();
     127        3212 :   int side_to_refine = 0;
     128        3212 :   Real length_to_refine = 0;
     129       44097 :   std::pair<Node *, Node *> vertices_to_refine;
     130             : 
     131             :   // Find the longest side and refine it first.  We might change that
     132             :   // heuristic at some point, to enable anisotropic refinement.
     133      176388 :   for (int side : make_range(n_sides))
     134             :     {
     135             :       std::pair<Node *, Node *> vertices
     136      132291 :         {elem.node_ptr((side+1)%n_sides),
     137       19272 :          elem.node_ptr(side)};
     138             : 
     139      132291 :       if ((Point&)(*vertices.first) >
     140        9636 :           (Point&)(*vertices.second))
     141        4820 :         std::swap(vertices.first, vertices.second);
     142             : 
     143      132291 :       const auto sidevec = *(Point*)vertices.first -
     144      132291 :                            *(Point*)vertices.second;
     145      122655 :       Real length = sidevec.norm();
     146             : 
     147             :       // We might need to ask the owner of a coarse ghost element
     148             :       // about whether it saw any refinement forced by a coarse
     149             :       // neighbor with a smaller desired area.
     150      132291 :       if (const processor_id_type pid = elem.processor_id();
     151      137109 :           pid != _mesh.processor_id() && !_mesh.is_serial() &&
     152      137109 :           !_desired_volume_func.get() &&
     153       74763 :           elem.id() == coarse_id)
     154        1980 :         edge_queries[pid].emplace_back(vertices.first->id(),
     155         990 :                                        vertices.second->id());
     156             : 
     157             :       // Test should_refine, but also test for any edges that were
     158             :       // already refined by neighbors, which might happen even if
     159             :       // !should_refine in cases where we're refining non-uniformly.
     160      139719 :       if (length > length_to_refine &&
     161       99633 :           (should_refine ||
     162       17064 :            new_nodes.find(vertices) != new_nodes.end()))
     163             :         {
     164        1496 :           side_to_refine = side;
     165        1496 :           length_to_refine = length;
     166        2992 :           vertices_to_refine = vertices;
     167             :         }
     168             :     }
     169             : 
     170             :   // We might not refine anything.
     171       44097 :   if (!length_to_refine)
     172        2348 :     return 0;
     173             : 
     174             :   // But if we must, then do it.
     175             :   //
     176             :   // Find all the edge neighbors we can.  For a triangle there'll just
     177             :   // be the one, but we want to extend to tets later.
     178        1728 :   std::vector<Elem *> neighbors;
     179       13158 :   if (Elem * neigh = elem.neighbor_ptr(side_to_refine); neigh)
     180       11310 :     neighbors.push_back(neigh);
     181             : 
     182             :   Node * midedge_node;
     183       12294 :   if (auto it = new_nodes.find(vertices_to_refine);
     184         864 :       it != new_nodes.end())
     185             :     {
     186        5535 :       midedge_node = it->second;
     187             :     }
     188             :   else
     189             :     {
     190             :       // Add with our own processor id first, so we can request a temporary
     191             :       // id that won't conflict with anyone else's canonical ids later
     192             :       midedge_node =
     193        6759 :         _mesh.add_point((*(Point*)vertices_to_refine.first +
     194        6759 :                          *(Point*)vertices_to_refine.second)/2,
     195             :                         DofObject::invalid_id,
     196         912 :                         _mesh.processor_id());
     197             : 
     198             :       // Then give the new node the best pid we can.
     199        6759 :       midedge_node->processor_id() = elem.processor_id();
     200       12534 :       for (const Elem * neigh : neighbors)
     201        5775 :         if (neigh != remote_elem)
     202        5519 :           midedge_node->processor_id() = std::min(midedge_node->processor_id(),
     203        5927 :                                                   neigh->processor_id());
     204             : 
     205        6759 :       new_nodes[vertices_to_refine] = midedge_node;
     206             :     }
     207             : 
     208             :   // Good for Tris and Tets; we'll need more for Quads.
     209         864 :   constexpr int max_subelems = 2;
     210       26316 :   std::unique_ptr<Tri3> subelem[max_subelems];
     211             : 
     212             :   // We'll switch(elem->type()) here eventually
     213       22860 :   subelem[0] = std::make_unique<Tri3>();
     214       13158 :   subelem[0]->set_node(0, elem.node_ptr(side_to_refine));
     215       12294 :   subelem[0]->set_node(1, midedge_node);
     216       13158 :   subelem[0]->set_node(2, elem.node_ptr((side_to_refine+2)%3));
     217             : 
     218       22860 :   subelem[1] = std::make_unique<Tri3>();
     219       13158 :   subelem[1]->set_node(0, elem.node_ptr((side_to_refine+2)%3));
     220       12294 :   subelem[1]->set_node(1, midedge_node);
     221       13158 :   subelem[1]->set_node(2, elem.node_ptr((side_to_refine+1)%3));
     222             : 
     223             :   // Preserve boundary and sort-of-preserve neighbor information.  We
     224             :   // need remote_elem neighbors to avoid breaking distributed meshes
     225             :   // (which can't reconstruct them from scratch), and we need at least
     226             :   // placeholder neighbors to make sure we'll have good processor_id()
     227             :   // options for new nodes in future splits of the same edge.
     228        1728 :   subelem[0]->set_neighbor(1, proxy_elements[elem.processor_id()].get());
     229        1728 :   subelem[1]->set_neighbor(0, proxy_elements[elem.processor_id()].get());
     230             : 
     231       12294 :   BoundaryInfo & boundary_info = _mesh.get_boundary_info();
     232         864 :   std::vector<boundary_id_type> bc_ids;
     233       12294 :   boundary_info.boundary_ids(&elem, side_to_refine, bc_ids);
     234       12294 :   boundary_info.add_side(subelem[0].get(), 0, bc_ids);
     235       12294 :   boundary_info.add_side(subelem[1].get(), 1, bc_ids);
     236        2592 :   subelem[0]->set_neighbor(0, elem.neighbor_ptr(side_to_refine));
     237        1728 :   subelem[1]->set_neighbor(1, elem.neighbor_ptr(side_to_refine));
     238             : 
     239       12294 :   boundary_info.boundary_ids(&elem, (side_to_refine+1)%3, bc_ids);
     240       12294 :   boundary_info.add_side(subelem[1].get(), 2, bc_ids);
     241        2592 :   subelem[1]->set_neighbor(2, elem.neighbor_ptr((side_to_refine+1)%3));
     242             : 
     243       12294 :   boundary_info.boundary_ids(&elem, (side_to_refine+2)%3, bc_ids);
     244       12294 :   boundary_info.add_side(subelem[0].get(), 2, bc_ids);
     245        2592 :   subelem[0]->set_neighbor(2, elem.neighbor_ptr((side_to_refine+2)%3));
     246             : 
     247             :   // Be sure the correct data is set for all subelems.
     248       12294 :   const unsigned int nei = elem.n_extra_integers();
     249       36882 :   for (unsigned int i=0; i != max_subelems; ++i)
     250       26316 :     if (subelem[i])
     251             :       {
     252             :         // We'd love to assert that we don't have a sliver here,
     253             :         // but maybe our input had a sliver and we can't fix it.
     254        1728 :         libmesh_assert_greater_equal(subelem[i]->volume() + TOLERANCE,
     255             :                                      elem.volume() / 2);
     256             : 
     257             :         // Copy any extra element data.  Since the subelements
     258             :         // haven't been added to the mesh yet any allocation has
     259             :         // to be done manually.
     260       24588 :         subelem[i]->add_extra_integers(nei);
     261       24588 :         for (unsigned int ei=0; ei != nei; ++ei)
     262           0 :           subelem[ei]->set_extra_integer(ei, elem.get_extra_integer(ei));
     263             : 
     264       24588 :         subelem[i]->inherit_data_from(elem);
     265             :       }
     266             : 
     267       12294 :   boundary_info.remove(&elem);
     268             : 
     269       12294 :   if (auto it = this->added_elements.find(coarse_id);
     270         864 :       it != this->added_elements.end())
     271             :     {
     272         832 :       auto & added = it->second;
     273       22680 :       if (auto sub_it = added.find(elem.vertex_average());
     274         832 :           sub_it != added.end())
     275             :         {
     276       11756 :           if (&elem == sub_it->second)
     277         832 :             added.erase(sub_it);
     278             :         }
     279             :     }
     280             : 
     281             :   // We only add an element to new_elements *right* before
     282             :   // checking it for further refinement, so we only need to check the
     283             :   // back() to see where the elem here came from.
     284       13152 :   if (!this->new_elements.empty() &&
     285         858 :       &elem == this->new_elements.back().get())
     286             :     {
     287         748 :       this->new_elements.pop_back();
     288       10855 :       this->coarse_parent.erase(&elem);
     289             :     }
     290             :   else
     291        1439 :     _mesh.delete_elem(&elem);
     292             : 
     293             :   // We refined at least ourselves
     294         864 :   std::size_t n_refined_elements = 1;
     295             : 
     296       36882 :   for (unsigned int i=0; i != max_subelems; ++i)
     297             :     {
     298       26316 :       Elem * add_elem = subelem[i].get();
     299       24588 :       added_elements[coarse_id].emplace(add_elem->vertex_average(),
     300        1728 :                                         add_elem);
     301       24588 :       this->new_elements.push_back(std::move(subelem[i]));
     302       24588 :       this->coarse_parent[add_elem] = coarse_id;
     303       24588 :       n_refined_elements +=
     304       24588 :         this->refine_via_edges(*add_elem, coarse_id);
     305             :     }
     306             : 
     307         864 :   return n_refined_elements;
     308       31698 : }
     309             : 
     310             : 
     311             : 
     312          94 : std::size_t SimplexRefiner::refine_via_edges()
     313             : {
     314           4 :   this->new_nodes.clear();
     315          90 :   this->new_elements.clear();
     316             : 
     317             :   // We need to look at neighbors' pids to determine new node pids,
     318             :   // but we might be deleting elements and leaving dangling neighbor
     319             :   // pointers.  Put proxy neighbors in those pointers places instead.
     320        1196 :   for (auto & elem : _mesh.element_ptr_range())
     321        2152 :     for (auto n : make_range(elem->n_neighbors()))
     322             :       {
     323        1614 :         Elem * neigh = elem->neighbor_ptr(n);
     324        1614 :         if (!neigh || neigh == remote_elem)
     325         408 :           continue;
     326             : 
     327        1206 :         const processor_id_type p = neigh->processor_id();
     328          80 :         std::unique_ptr<Elem> & proxy_neighbor = proxy_elements[p];
     329        1206 :         if (!proxy_neighbor.get())
     330         748 :           proxy_neighbor = Elem::build(NODEELEM);
     331             : 
     332        1286 :         elem->set_neighbor(n, proxy_neighbor.get());
     333          86 :       }
     334             : 
     335             :   // If we have a _desired_volume_func then we might still have
     336             :   // some unsplit edges that could have been split by their
     337             :   // remote_elem neighbors, and we'll need to query those.
     338             :   auto edge_gather_functor =
     339         352 :     [this]
     340             :     (processor_id_type,
     341             :      const std::vector<std::pair<dof_id_type, dof_id_type>> & edges,
     342        1254 :      std::vector<refinement_datum> & edge_refinements)
     343             :     {
     344             :       // Fill those requests
     345           0 :       const std::size_t query_size = edges.size();
     346         352 :       edge_refinements.resize(query_size);
     347        1606 :       for (std::size_t i=0; i != query_size; ++i)
     348             :         {
     349        1254 :           auto vertex_ids = edges[i];
     350             :           std::pair<Node *, Node *> vertices
     351        1254 :             {_mesh.node_ptr(vertex_ids.first),
     352        1254 :              _mesh.node_ptr(vertex_ids.second)};
     353        1254 :           fill_refinement_datum(vertices, edge_refinements[i]);
     354             :         }
     355         442 :     };
     356             : 
     357             :   auto edge_action_functor =
     358         352 :     [this]
     359             :     (processor_id_type,
     360             :      const std::vector<std::pair<dof_id_type, dof_id_type>> &,
     361             :      const std::vector<refinement_datum> & edge_refinements
     362        4466 :     )
     363             :     {
     364        1606 :       for (const auto & one_edges_refinements : edge_refinements)
     365        5720 :         for (const auto & refinement : one_edges_refinements)
     366             :           {
     367             :             std::pair<Node *, Node *> vertices
     368        4466 :               {_mesh.node_ptr(std::get<0>(refinement)),
     369        4466 :                _mesh.node_ptr(std::get<1>(refinement))};
     370             : 
     371        4466 :             if ((Point&)(*vertices.first) >
     372           0 :                 (Point&)(*vertices.second))
     373           0 :               std::swap(vertices.first, vertices.second);
     374             : 
     375        4466 :             if (auto it = new_nodes.find(vertices);
     376           0 :                 it != new_nodes.end())
     377             :               {
     378        4450 :                 _mesh.renumber_node(it->second->id(),
     379           0 :                                     std::get<2>(refinement));
     380        4450 :                 it->second->processor_id() = std::get<3>(refinement);
     381             :               }
     382             :             else
     383             :               {
     384             :                 Node * new_node =
     385          32 :                   _mesh.add_point((*(Point*)vertices.first +
     386          16 :                                    *(Point*)vertices.second)/2,
     387           0 :                                   std::get<2>(refinement),
     388           0 :                                   std::get<3>(refinement));
     389          16 :                 new_nodes[vertices] = new_node;
     390             :               }
     391             :           }
     392          90 :     };
     393             : 
     394           4 :   std::size_t refined_elements = 0;
     395           4 :   std::size_t newly_refined_elements = 0;
     396           6 :   do
     397             :     {
     398         211 :       newly_refined_elements = 0;
     399             : 
     400             :       // Refinement results should agree on ghost elements, except for
     401             :       // id and unique_id assignment
     402       19921 :       for (auto & elem : _mesh.element_ptr_range())
     403             :         {
     404        1484 :           auto it = coarse_parent.find(elem);
     405             :           const dof_id_type coarse_id =
     406       20961 :             (it == coarse_parent.end()) ?
     407        1990 :             elem->id() : it->second;
     408             : 
     409       19509 :           newly_refined_elements +=
     410       19509 :             this->refine_via_edges(*elem, coarse_id);
     411         191 :         }
     412         211 :       refined_elements += newly_refined_elements;
     413       13944 :       for (auto & elem : this->new_elements)
     414       15693 :         _mesh.add_elem(std::move(elem));
     415          10 :       this->new_elements.clear();
     416             : 
     417             :       // Yeah, this is just a lower bound in parallel
     418         211 :       _mesh.comm().max(newly_refined_elements);
     419             : 
     420         211 :       if (newly_refined_elements && !_mesh.is_replicated())
     421             :         {
     422          96 :           bool have_edge_queries = !edge_queries.empty();
     423          96 :           _mesh.comm().max(have_edge_queries);
     424           0 :           refinement_datum * refinement_data_ex = nullptr;
     425          96 :           if (have_edge_queries)
     426             :             Parallel::pull_parallel_vector_data
     427          93 :               (_mesh.comm(), edge_queries, edge_gather_functor,
     428             :                edge_action_functor, refinement_data_ex);
     429             :         }
     430             :     }
     431         211 :   while (newly_refined_elements);
     432             : 
     433             :   // If we're replicated then we should be done here.
     434          94 :   if (!_mesh.is_replicated())
     435             :     {
     436             :       // If we're not replicated then we might have a bunch of nodes
     437             :       // and elements that still have temporary id and unique_id
     438             :       // values.  Give them permanent ones.
     439           0 :       std::unordered_map<processor_id_type, std::vector<dof_id_type>> elems_to_query;
     440         506 :       for (const auto & [coarse_id, added_elem_map] : added_elements)
     441             :         {
     442         426 :           if (added_elem_map.empty())
     443          96 :             continue;
     444             : 
     445             :           const processor_id_type pid =
     446         426 :             added_elem_map.begin()->second->processor_id();
     447         426 :           if (pid == _mesh.processor_id())
     448          96 :             continue;
     449             : 
     450         330 :           elems_to_query[pid].push_back(coarse_id);
     451             :         }
     452             : 
     453             :       // Return fine element data based on vertex_average()
     454             :       typedef
     455             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     456             :         std::vector<std::tuple<Point, dof_id_type, unique_id_type>>
     457             : #else
     458             :         std::vector<std::tuple<Point, dof_id_type>>
     459             : #endif
     460             :         elem_refinement_datum;
     461             : 
     462             :       auto added_gather_functor =
     463         288 :         [this]
     464             :         (processor_id_type,
     465             :          const std::vector<dof_id_type> & coarse_elems,
     466         330 :          std::vector<elem_refinement_datum> & coarse_refinements)
     467             :         {
     468             :           // Fill those requests
     469           0 :           const std::size_t query_size = coarse_elems.size();
     470         288 :           coarse_refinements.resize(query_size);
     471         618 :           for (auto i : make_range(query_size))
     472             :             {
     473         330 :               const dof_id_type coarse_id = coarse_elems[i];
     474             :               const auto & added =
     475         330 :                 libmesh_map_find(added_elements, coarse_id);
     476             : 
     477        7722 :               for (auto [vertex_avg, elem] : added)
     478             :                 {
     479           0 :                   coarse_refinements[i].emplace_back
     480        7392 :                     (vertex_avg,
     481        7392 :                      elem->id()
     482             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     483        7392 :                      , elem->unique_id()
     484             : #endif
     485           0 :                     );
     486             :                 }
     487             :             }
     488         288 :         };
     489             : 
     490             :       auto added_action_functor =
     491         288 :         [this]
     492             :         (processor_id_type,
     493             :          const std::vector<dof_id_type> & coarse_elems,
     494        7722 :          const std::vector<elem_refinement_datum> & coarse_refinements)
     495             :         {
     496           0 :           const std::size_t query_size = coarse_elems.size();
     497         618 :           for (auto i : make_range(query_size))
     498             :             {
     499         330 :               const dof_id_type coarse_id = coarse_elems[i];
     500           0 :               const auto & refinement_data = coarse_refinements[i];
     501             :               const auto & our_added =
     502         330 :                 libmesh_map_find(added_elements, coarse_id);
     503         330 :               for (auto [vertex_avg, id
     504             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     505             :                          , unique_id
     506             : #endif
     507        7722 :                    ] : refinement_data)
     508             :                 {
     509        7392 :                   Elem & our_elem = *libmesh_map_find(our_added,
     510             :                                                       vertex_avg);
     511           0 :                   libmesh_assert_equal_to(our_elem.vertex_average(),
     512             :                                           vertex_avg);
     513             : 
     514             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     515        7392 :                   our_elem.set_unique_id(unique_id);
     516             : #endif
     517        7392 :                   _mesh.renumber_elem(our_elem.id(), id);
     518             :                 }
     519             :             }
     520         288 :         };
     521             : 
     522           0 :       elem_refinement_datum * refinement_data_ex = nullptr;
     523             :       Parallel::pull_parallel_vector_data
     524          80 :         (_mesh.comm(), elems_to_query, added_gather_functor,
     525             :          added_action_functor, refinement_data_ex);
     526             : 
     527             :       // That took care of our element ids; now get node ids.
     528             :       MeshCommunication mc;
     529          80 :       mc.make_node_proc_ids_parallel_consistent (_mesh);
     530          80 :       mc.make_node_ids_parallel_consistent (_mesh);
     531          80 :       mc.make_node_unique_ids_parallel_consistent (_mesh);
     532             :     }
     533             : 
     534             :   // In theory the operations on ghost elements are, after remote edge
     535             :   // splittings are known, embarrassingly parallel.  In practice ...
     536             :   // let's verify that we haven't just desynchronized our mesh.
     537             : #ifdef DEBUG
     538           4 :   MeshTools::libmesh_assert_equal_points(_mesh);
     539           4 :   MeshTools::libmesh_assert_equal_connectivity (_mesh);
     540             : #  ifdef LIBMESH_ENABLE_UNIQUE_ID
     541           4 :   MeshTools::libmesh_assert_valid_unique_ids(_mesh);
     542             : #  endif
     543             : #endif
     544             : 
     545          94 :   return refined_elements;
     546             : }
     547             : 
     548             : 
     549             : 
     550           0 : void SimplexRefiner::set_desired_volume_function
     551             :   (FunctionBase<Real> * desired)
     552             : {
     553           0 :   if (desired)
     554           0 :     _desired_volume_func = desired->clone();
     555             :   else
     556           0 :     _desired_volume_func.reset();
     557           0 : }
     558             : 
     559             : 
     560             : 
     561       44097 : FunctionBase<Real> * SimplexRefiner::get_desired_volume_function ()
     562             : {
     563       44097 :   return _desired_volume_func.get();
     564             : }
     565             : 
     566             : 
     567       10186 : void SimplexRefiner::fill_refinement_datum(std::pair<Node *, Node *> vertices,
     568             :                                            refinement_datum & vec)
     569             : {
     570           0 :   auto it = new_nodes.find(vertices);
     571       10186 :   if (it == new_nodes.end())
     572           0 :     return;
     573             : 
     574        8932 :   vec.emplace_back(vertices.first->id(),
     575        8932 :                    vertices.second->id(),
     576        4466 :                    it->second->id(),
     577        4466 :                    it->second->processor_id());
     578             : 
     579           0 :   std::pair<Node *, Node *> subedge {vertices.first, it->second};
     580        4466 :   if ((Point&)(*subedge.first) >
     581           0 :       (Point&)(*subedge.second))
     582           0 :     std::swap(subedge.first, subedge.second);
     583        4466 :   fill_refinement_datum(subedge, vec);
     584             : 
     585           0 :   subedge = std::make_pair(it->second, vertices.second);
     586        4466 :   if ((Point&)(*subedge.first) >
     587           0 :       (Point&)(*subedge.second))
     588           0 :     std::swap(subedge.first, subedge.second);
     589        4466 :   fill_refinement_datum(subedge, vec);
     590             : }
     591             : 
     592             : 
     593             : } // namespace libMesh
     594             : 

Generated by: LCOV version 1.14