LCOV - code coverage report
Current view: top level - src/mesh - mesh_modification.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 518 811 63.9 %
Date: 2025-08-19 19:27:09 Functions: 16 18 88.9 %
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             : // C++ includes
      21             : #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
      22             : #include <cmath> // for std::acos()
      23             : #include <algorithm>
      24             : #include <limits>
      25             : #include <map>
      26             : #include <array>
      27             : 
      28             : // Local includes
      29             : #include "libmesh/boundary_info.h"
      30             : #include "libmesh/function_base.h"
      31             : #include "libmesh/cell_tet4.h"
      32             : #include "libmesh/cell_tet10.h"
      33             : #include "libmesh/face_tri3.h"
      34             : #include "libmesh/face_tri6.h"
      35             : #include "libmesh/libmesh_logging.h"
      36             : #include "libmesh/mesh_communication.h"
      37             : #include "libmesh/mesh_modification.h"
      38             : #include "libmesh/mesh_tools.h"
      39             : #include "libmesh/parallel.h"
      40             : #include "libmesh/remote_elem.h"
      41             : #include "libmesh/enum_to_string.h"
      42             : #include "libmesh/unstructured_mesh.h"
      43             : #include "libmesh/elem_side_builder.h"
      44             : #include "libmesh/tensor_value.h"
      45             : 
      46             : namespace
      47             : {
      48             : using namespace libMesh;
      49             : 
      50        1712 : bool split_first_diagonal(const Elem * elem,
      51             :                           unsigned int diag_1_node_1,
      52             :                           unsigned int diag_1_node_2,
      53             :                           unsigned int diag_2_node_1,
      54             :                           unsigned int diag_2_node_2)
      55             : {
      56         372 :   return ((elem->node_id(diag_1_node_1) > elem->node_id(diag_2_node_1) &&
      57        2044 :            elem->node_id(diag_1_node_1) > elem->node_id(diag_2_node_2)) ||
      58        1712 :           (elem->node_id(diag_1_node_2) > elem->node_id(diag_2_node_1) &&
      59        1768 :            elem->node_id(diag_1_node_2) > elem->node_id(diag_2_node_2)));
      60             : }
      61             : 
      62             : 
      63             : // Return the local index of the vertex on \p elem with the highest
      64             : // node id.
      65       44535 : unsigned int highest_vertex_on(const Elem * elem)
      66             : {
      67        1792 :   unsigned int highest_n = 0;
      68        3584 :   dof_id_type highest_n_id = elem->node_id(0);
      69      356280 :   for (auto n : make_range(1u, elem->n_vertices()))
      70             :     {
      71       25088 :       const dof_id_type n_id = elem->node_id(n);
      72      311745 :       if (n_id > highest_n_id)
      73             :         {
      74        6928 :           highest_n = n;
      75        6928 :           highest_n_id = n_id;
      76             :         }
      77             :     }
      78             : 
      79       44535 :   return highest_n;
      80             : }
      81             : 
      82             : 
      83             : static const std::array<std::array<unsigned int, 3>, 8> opposing_nodes =
      84             : {{ {2,5,7},{3,4,6},{0,5,7},{1,4,6},{1,3,6},{0,2,7},{1,3,4},{0,2,5} }};
      85             : 
      86             : 
      87             : // Find the highest id on these side nodes of this element
      88             : std::pair<unsigned int, unsigned int>
      89      201543 : split_diagonal(const Elem * elem,
      90             :                const std::vector<unsigned int> & nodes_on_side)
      91             : {
      92        6552 :   libmesh_assert_equal_to(elem->type(), HEX8);
      93             : 
      94      201543 :   unsigned int highest_n = nodes_on_side.front();
      95       13104 :   dof_id_type highest_n_id = elem->node_id(nodes_on_side.front());
      96     1007715 :   for (auto n : nodes_on_side)
      97             :     {
      98       26208 :       const dof_id_type n_id = elem->node_id(n);
      99      806172 :       if (n_id > highest_n_id)
     100             :         {
     101       11056 :           highest_n = n;
     102       11056 :           highest_n_id = n_id;
     103             :         }
     104             :     }
     105             : 
     106      409839 :   for (auto n : nodes_on_side)
     107             :     {
     108     1114271 :       for (auto n2 : opposing_nodes[highest_n])
     109      905975 :         if (n2 == n)
     110        6552 :           return std::make_pair(highest_n, n2);
     111             :     }
     112             : 
     113           0 :   libmesh_error();
     114             : 
     115             :   return std::make_pair(libMesh::invalid_uint, libMesh::invalid_uint);
     116             : }
     117             : 
     118             : 
     119             : // Reconstruct a C++20 feature in C++14
     120             : template <typename T>
     121             : struct reversion_wrapper { T& iterable; };
     122             : 
     123             : template <typename T>
     124        4928 : auto begin (reversion_wrapper<T> w) {return std::rbegin(w.iterable);}
     125             : 
     126             : template <typename T>
     127        4928 : auto end (reversion_wrapper<T> w) {return std::rend(w.iterable);}
     128             : 
     129             : template <typename T>
     130        4928 : reversion_wrapper<T> reverse(T&& iterable) {return {iterable};}
     131             : 
     132             : }
     133             : 
     134             : 
     135             : namespace libMesh
     136             : {
     137             : 
     138             : 
     139             : // ------------------------------------------------------------
     140             : // MeshTools::Modification functions for mesh modification
     141         426 : void MeshTools::Modification::distort (MeshBase & mesh,
     142             :                                        const Real factor,
     143             :                                        const bool perturb_boundary)
     144             : {
     145          12 :   libmesh_assert (mesh.n_nodes());
     146          12 :   libmesh_assert (mesh.n_elem());
     147          12 :   libmesh_assert ((factor >= 0.) && (factor <= 1.));
     148             : 
     149          24 :   LOG_SCOPE("distort()", "MeshTools::Modification");
     150             : 
     151             :   // If we are not perturbing boundary nodes, make a
     152             :   // quickly-searchable list of node ids we can check against.
     153          24 :   std::unordered_set<dof_id_type> boundary_node_ids;
     154         426 :   if (!perturb_boundary)
     155         840 :     boundary_node_ids = MeshTools::find_boundary_nodes (mesh);
     156             : 
     157             :   // Now calculate the minimum distance to
     158             :   // neighboring nodes for each node.
     159             :   // hmin holds these distances.
     160         438 :   std::vector<float> hmin (mesh.max_node_id(),
     161         438 :                            std::numeric_limits<float>::max());
     162             : 
     163       13674 :   for (const auto & elem : mesh.active_element_ptr_range())
     164       43425 :     for (auto & n : elem->node_ref_range())
     165       38700 :       hmin[n.id()] = std::min(hmin[n.id()],
     166       48831 :                               static_cast<float>(elem->hmin()));
     167             : 
     168             :   // Now actually move the nodes
     169             :   {
     170          12 :     const unsigned int seed = 123456;
     171             : 
     172             :     // seed the random number generator.
     173             :     // We'll loop from 1 to n_nodes on every processor, even those
     174             :     // that don't have a particular node, so that the pseudorandom
     175             :     // numbers will be the same everywhere.
     176         426 :     std::srand(seed);
     177             : 
     178             :     // If the node is on the boundary or
     179             :     // the node is not used by any element (hmin[n]<1.e20)
     180             :     // then we should not move it.
     181             :     // [Note: Testing for (in)equality might be wrong
     182             :     // (different types, namely float and double)]
     183       10437 :     for (auto n : make_range(mesh.max_node_id()))
     184       11432 :       if ((perturb_boundary || !boundary_node_ids.count(n)) && hmin[n] < 1.e20)
     185             :         {
     186             :           // the direction, random but unit normalized
     187        1207 :           Point dir (static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX),
     188        2414 :                      (mesh.mesh_dimension() > 1) ? static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX) : 0.,
     189        4828 :                      ((mesh.mesh_dimension() == 3) ? static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX) : 0.));
     190             : 
     191        1207 :           dir(0) = (dir(0)-.5)*2.;
     192             : #if LIBMESH_DIM > 1
     193        1207 :           if (mesh.mesh_dimension() > 1)
     194        1207 :             dir(1) = (dir(1)-.5)*2.;
     195             : #endif
     196             : #if LIBMESH_DIM > 2
     197        1207 :           if (mesh.mesh_dimension() == 3)
     198         852 :             dir(2) = (dir(2)-.5)*2.;
     199             : #endif
     200             : 
     201        1207 :           dir = dir.unit();
     202             : 
     203        1207 :           Node * node = mesh.query_node_ptr(n);
     204        1207 :           if (!node)
     205           0 :             continue;
     206             : 
     207        1207 :           (*node)(0) += dir(0)*factor*hmin[n];
     208             : #if LIBMESH_DIM > 1
     209        1207 :           if (mesh.mesh_dimension() > 1)
     210        1241 :             (*node)(1) += dir(1)*factor*hmin[n];
     211             : #endif
     212             : #if LIBMESH_DIM > 2
     213        1207 :           if (mesh.mesh_dimension() == 3)
     214         876 :             (*node)(2) += dir(2)*factor*hmin[n];
     215             : #endif
     216             :         }
     217             :   }
     218         426 : }
     219             : 
     220             : 
     221             : 
     222      186659 : void MeshTools::Modification::permute_elements(MeshBase & mesh)
     223             : {
     224       10516 :   LOG_SCOPE("permute_elements()", "MeshTools::Modification");
     225             : 
     226             :   // We don't yet support doing permute() on a parent element, which
     227             :   // would require us to consistently permute all its children and
     228             :   // give them different local child numbers.
     229      186659 :   unsigned int n_levels = MeshTools::n_levels(mesh);
     230      186659 :   if (n_levels > 1)
     231           0 :     libmesh_error();
     232             : 
     233        5258 :   const unsigned int seed = 123456;
     234             : 
     235             :   // seed the random number generator.
     236             :   // We'll loop from 1 to max_elem_id on every processor, even those
     237             :   // that don't have a particular element, so that the pseudorandom
     238             :   // numbers will be the same everywhere.
     239      186659 :   std::srand(seed);
     240             : 
     241             : 
     242     4852992 :   for (auto e_id : make_range(mesh.max_elem_id()))
     243             :     {
     244     4666333 :       int my_rand = std::rand();
     245             : 
     246     4666333 :       Elem * elem = mesh.query_elem_ptr(e_id);
     247             : 
     248     4666333 :       if (!elem)
     249     2768542 :         continue;
     250             : 
     251     1897791 :       const unsigned int max_permutation = elem->n_permutations();
     252     1897791 :       if (!max_permutation)
     253        4627 :         continue;
     254             : 
     255     1892506 :       const unsigned int perm = my_rand % max_permutation;
     256             : 
     257     1892506 :       elem->permute(perm);
     258             :     }
     259      186659 : }
     260             : 
     261             : 
     262        2236 : void MeshTools::Modification::orient_elements(MeshBase & mesh)
     263             : {
     264         152 :   LOG_SCOPE("orient_elements()", "MeshTools::Modification");
     265             : 
     266             :   // We don't yet support doing orient() on a parent element, which
     267             :   // would require us to consistently orient all its children and
     268             :   // give them different local child numbers.
     269        2236 :   unsigned int n_levels = MeshTools::n_levels(mesh);
     270        2236 :   if (n_levels > 1)
     271           0 :     libmesh_not_implemented_msg("orient_elements() does not support refined meshes");
     272             : 
     273          76 :   BoundaryInfo & boundary_info = mesh.get_boundary_info();
     274       92940 :   for (auto elem : mesh.element_ptr_range())
     275       45412 :     elem->orient(&boundary_info);
     276        2236 : }
     277             : 
     278             : 
     279             : 
     280      184174 : void MeshTools::Modification::redistribute (MeshBase & mesh,
     281             :                                             const FunctionBase<Real> & mapfunc)
     282             : {
     283        5188 :   libmesh_assert (mesh.n_nodes());
     284        5188 :   libmesh_assert (mesh.n_elem());
     285             : 
     286       10376 :   LOG_SCOPE("redistribute()", "MeshTools::Modification");
     287             : 
     288      184174 :   DenseVector<Real> output_vec(LIBMESH_DIM);
     289             : 
     290             :   // FIXME - we should thread this later.
     291      189362 :   std::unique_ptr<FunctionBase<Real>> myfunc = mapfunc.clone();
     292             : 
     293     4390348 :   for (auto & node : mesh.node_ptr_range())
     294             :     {
     295     4027188 :       (*myfunc)(*node, output_vec);
     296             : 
     297     4027188 :       (*node)(0) = output_vec(0);
     298             : #if LIBMESH_DIM > 1
     299     4027188 :       (*node)(1) = output_vec(1);
     300             : #endif
     301             : #if LIBMESH_DIM > 2
     302     4027188 :       (*node)(2) = output_vec(2);
     303             : #endif
     304      173798 :     }
     305      357972 : }
     306             : 
     307             : 
     308             : 
     309         217 : void MeshTools::Modification::translate (MeshBase & mesh,
     310             :                                          const Real xt,
     311             :                                          const Real yt,
     312             :                                          const Real zt)
     313             : {
     314           8 :   const Point p(xt, yt, zt);
     315             : 
     316       72638 :   for (auto & node : mesh.node_ptr_range())
     317       37599 :     *node += p;
     318         217 : }
     319             : 
     320             : 
     321             : // void MeshTools::Modification::rotate2D (MeshBase & mesh,
     322             : //                                         const Real alpha)
     323             : // {
     324             : //   libmesh_assert_not_equal_to (mesh.mesh_dimension(), 1);
     325             : 
     326             : //   const Real pi = std::acos(-1);
     327             : //   const Real  a = alpha/180.*pi;
     328             : //   for (unsigned int n=0; n<mesh.n_nodes(); n++)
     329             : //     {
     330             : //       const Point p = mesh.node_ref(n);
     331             : //       const Real  x = p(0);
     332             : //       const Real  y = p(1);
     333             : //       const Real  z = p(2);
     334             : //       mesh.node_ref(n) = Point(std::cos(a)*x - std::sin(a)*y,
     335             : //                                std::sin(a)*x + std::cos(a)*y,
     336             : //                                z);
     337             : //     }
     338             : 
     339             : // }
     340             : 
     341             : 
     342             : 
     343             : RealTensorValue
     344      162519 : MeshTools::Modification::rotate (MeshBase & mesh,
     345             :                                  const Real phi,
     346             :                                  const Real theta,
     347             :                                  const Real psi)
     348             : {
     349             : #if LIBMESH_DIM == 3
     350      162519 :   const auto R = RealTensorValue::intrinsic_rotation_matrix(phi, theta, psi);
     351             : 
     352      162519 :   if (theta)
     353       88253 :     mesh.set_spatial_dimension(3);
     354             : 
     355    10235306 :   for (auto & node : mesh.node_ptr_range())
     356             :     {
     357     5267113 :       Point & pt = *node;
     358     5267113 :       pt = R * pt;
     359      153363 :     }
     360             : 
     361      162519 :   return R;
     362             : 
     363             : #else
     364             :   libmesh_ignore(mesh, phi, theta, psi);
     365             :   libmesh_error_msg("MeshTools::Modification::rotate() requires libMesh to be compiled with LIBMESH_DIM==3");
     366             :   // We'll never get here
     367             :   return RealTensorValue();
     368             : #endif
     369             : }
     370             : 
     371             : 
     372          71 : void MeshTools::Modification::scale (MeshBase & mesh,
     373             :                                      const Real xs,
     374             :                                      const Real ys,
     375             :                                      const Real zs)
     376             : {
     377           2 :   const Real x_scale = xs;
     378           2 :   Real y_scale       = ys;
     379           2 :   Real z_scale       = zs;
     380             : 
     381          71 :   if (ys == 0.)
     382             :     {
     383           0 :       libmesh_assert_equal_to (zs, 0.);
     384             : 
     385           0 :       y_scale = z_scale = x_scale;
     386             :     }
     387             : 
     388             :   // Scale the x coordinate in all dimensions
     389         495 :   for (auto & node : mesh.node_ptr_range())
     390         422 :     (*node)(0) *= x_scale;
     391             : 
     392             :   // Only scale the y coordinate in 2 and 3D
     393             :   if (LIBMESH_DIM < 2)
     394             :     return;
     395             : 
     396         495 :   for (auto & node : mesh.node_ptr_range())
     397         422 :     (*node)(1) *= y_scale;
     398             : 
     399             :   // Only scale the z coordinate in 3D
     400             :   if (LIBMESH_DIM < 3)
     401             :     return;
     402             : 
     403         495 :   for (auto & node : mesh.node_ptr_range())
     404         422 :     (*node)(2) *= z_scale;
     405             : }
     406             : 
     407             : 
     408             : 
     409        2272 : void MeshTools::Modification::all_tri (MeshBase & mesh)
     410             : {
     411        2272 :   if (!mesh.is_replicated() && !mesh.is_prepared())
     412           0 :     mesh.prepare_for_use();
     413             : 
     414             :   // The number of elements in the original mesh before any additions
     415             :   // or deletions.
     416        2272 :   const dof_id_type n_orig_elem = mesh.n_elem();
     417        2272 :   const dof_id_type max_orig_id = mesh.max_elem_id();
     418             : 
     419             :   // We store pointers to the newly created elements in a vector
     420             :   // until they are ready to be added to the mesh.  This is because
     421             :   // adding new elements on the fly can cause reallocation and invalidation
     422             :   // of existing mesh element_iterators.
     423         192 :   std::vector<std::unique_ptr<Elem>> new_elements;
     424             : 
     425          64 :   unsigned int max_subelems = 1;  // in 1D nothing needs to change
     426        2272 :   if (mesh.mesh_dimension() == 2) // in 2D quads can split into 2 tris
     427          52 :     max_subelems = 2;
     428        2272 :   if (mesh.mesh_dimension() == 3) // in 3D hexes can split into 6 tets
     429          12 :     max_subelems = 6;
     430             : 
     431        2272 :   new_elements.reserve (max_subelems*n_orig_elem);
     432             : 
     433             :   // If the original mesh has *side* boundary data, we carry that over
     434             :   // to the new mesh with triangular elements.  We currently only
     435             :   // support bringing over side-based BCs to the all-tri mesh, but
     436             :   // that could probably be extended to node and edge-based BCs as
     437             :   // well.
     438        2272 :   const bool mesh_has_boundary_data = (mesh.get_boundary_info().n_boundary_conds() > 0);
     439             : 
     440             :   // Temporary vectors to store the new boundary element pointers, side numbers, and boundary ids
     441         128 :   std::vector<Elem *> new_bndry_elements;
     442         128 :   std::vector<unsigned short int> new_bndry_sides;
     443         128 :   std::vector<boundary_id_type> new_bndry_ids;
     444             : 
     445             :   // We may need to add new points if we run into a 1.5th order
     446             :   // element; if we do that on a DistributedMesh in a ghost element then
     447             :   // we will need to fix their ids / unique_ids
     448        2272 :   bool added_new_ghost_point = false;
     449             : 
     450             :   // Iterate over the elements, splitting:
     451             :   // QUADs into pairs of conforming triangles
     452             :   // PYRAMIDs into pairs of conforming tets,
     453             :   // PRISMs into triplets of conforming tets, and
     454             :   // HEXs into quintets or sextets of conforming tets.
     455             :   // We split on the shortest diagonal to give us better
     456             :   // triangle quality in 2D, and we split based on node ids
     457             :   // to guarantee consistency in 3D.
     458             : 
     459             :   // FIXME: This algorithm does not work on refined grids!
     460             :   {
     461             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     462        2272 :     unique_id_type max_unique_id = mesh.parallel_max_unique_id();
     463             : #endif
     464             : 
     465             :     // For avoiding extraneous allocation when building side elements
     466        2272 :     std::unique_ptr<const Elem> elem_side, subside_elem;
     467             : 
     468      151078 :     for (auto & elem : mesh.element_ptr_range())
     469             :       {
     470       76325 :         const ElemType etype = elem->type();
     471             : 
     472             :         // all_tri currently only works on coarse meshes
     473       79351 :         if (elem->parent())
     474           0 :           libmesh_not_implemented_msg("Cannot convert a refined element into simplices\n");
     475             : 
     476             :         // The new elements we will split the quad into.
     477             :         // In 3D we may need as many as 6 tets per hex
     478       73299 :         std::array<std::unique_ptr<Elem>, 6> subelem {};
     479             : 
     480       76325 :         switch (etype)
     481             :           {
     482        9323 :           case QUAD4:
     483             :             {
     484       17966 :               subelem[0] = Elem::build(TRI3);
     485       17966 :               subelem[1] = Elem::build(TRI3);
     486             : 
     487             :               // Check for possible edge swap
     488        9663 :               if ((elem->point(0) - elem->point(2)).norm() <
     489        9323 :                   (elem->point(1) - elem->point(3)).norm())
     490             :                 {
     491        3118 :                   subelem[0]->set_node(0, elem->node_ptr(0));
     492        3118 :                   subelem[0]->set_node(1, elem->node_ptr(1));
     493        3118 :                   subelem[0]->set_node(2, elem->node_ptr(2));
     494             : 
     495        3118 :                   subelem[1]->set_node(0, elem->node_ptr(0));
     496        3118 :                   subelem[1]->set_node(1, elem->node_ptr(2));
     497        3118 :                   subelem[1]->set_node(2, elem->node_ptr(3));
     498             :                 }
     499             : 
     500             :               else
     501             :                 {
     502        6545 :                   subelem[0]->set_node(0, elem->node_ptr(0));
     503        6545 :                   subelem[0]->set_node(1, elem->node_ptr(1));
     504        6545 :                   subelem[0]->set_node(2, elem->node_ptr(3));
     505             : 
     506        6545 :                   subelem[1]->set_node(0, elem->node_ptr(1));
     507        6545 :                   subelem[1]->set_node(1, elem->node_ptr(2));
     508        6545 :                   subelem[1]->set_node(2, elem->node_ptr(3));
     509             :                 }
     510             : 
     511             : 
     512         340 :               break;
     513             :             }
     514             : 
     515         142 :           case QUAD8:
     516             :             {
     517         146 :               if (elem->processor_id() != mesh.processor_id())
     518         118 :                 added_new_ghost_point = true;
     519             : 
     520         276 :               subelem[0] = Elem::build(TRI6);
     521         276 :               subelem[1] = Elem::build(TRI6);
     522             : 
     523             :               // Add a new node at the center (vertex average) of the element.
     524         150 :               Node * new_node = mesh.add_point((mesh.point(elem->node_id(0)) +
     525         150 :                                                 mesh.point(elem->node_id(1)) +
     526         150 :                                                 mesh.point(elem->node_id(2)) +
     527         146 :                                                 mesh.point(elem->node_id(3)))/4,
     528             :                                                DofObject::invalid_id,
     529         142 :                                                elem->processor_id());
     530             : 
     531             :               // Check for possible edge swap
     532         146 :               if ((elem->point(0) - elem->point(2)).norm() <
     533         142 :                   (elem->point(1) - elem->point(3)).norm())
     534             :                 {
     535           0 :                   subelem[0]->set_node(0, elem->node_ptr(0));
     536           0 :                   subelem[0]->set_node(1, elem->node_ptr(1));
     537           0 :                   subelem[0]->set_node(2, elem->node_ptr(2));
     538           0 :                   subelem[0]->set_node(3, elem->node_ptr(4));
     539           0 :                   subelem[0]->set_node(4, elem->node_ptr(5));
     540           0 :                   subelem[0]->set_node(5, new_node);
     541             : 
     542           0 :                   subelem[1]->set_node(0, elem->node_ptr(0));
     543           0 :                   subelem[1]->set_node(1, elem->node_ptr(2));
     544           0 :                   subelem[1]->set_node(2, elem->node_ptr(3));
     545           0 :                   subelem[1]->set_node(3, new_node);
     546           0 :                   subelem[1]->set_node(4, elem->node_ptr(6));
     547           0 :                   subelem[1]->set_node(5, elem->node_ptr(7));
     548             : 
     549             :                 }
     550             : 
     551             :               else
     552             :                 {
     553         146 :                   subelem[0]->set_node(0, elem->node_ptr(3));
     554         146 :                   subelem[0]->set_node(1, elem->node_ptr(0));
     555         146 :                   subelem[0]->set_node(2, elem->node_ptr(1));
     556         146 :                   subelem[0]->set_node(3, elem->node_ptr(7));
     557         146 :                   subelem[0]->set_node(4, elem->node_ptr(4));
     558         142 :                   subelem[0]->set_node(5, new_node);
     559             : 
     560         146 :                   subelem[1]->set_node(0, elem->node_ptr(1));
     561         146 :                   subelem[1]->set_node(1, elem->node_ptr(2));
     562         146 :                   subelem[1]->set_node(2, elem->node_ptr(3));
     563         146 :                   subelem[1]->set_node(3, elem->node_ptr(5));
     564         146 :                   subelem[1]->set_node(4, elem->node_ptr(6));
     565         142 :                   subelem[1]->set_node(5, new_node);
     566             :                 }
     567             : 
     568           4 :               break;
     569             :             }
     570             : 
     571         422 :           case QUAD9:
     572             :             {
     573         804 :               subelem[0] = Elem::build(TRI6);
     574         804 :               subelem[1] = Elem::build(TRI6);
     575             : 
     576             :               // Check for possible edge swap
     577         442 :               if ((elem->point(0) - elem->point(2)).norm() <
     578         422 :                   (elem->point(1) - elem->point(3)).norm())
     579             :                 {
     580           0 :                   subelem[0]->set_node(0, elem->node_ptr(0));
     581           0 :                   subelem[0]->set_node(1, elem->node_ptr(1));
     582           0 :                   subelem[0]->set_node(2, elem->node_ptr(2));
     583           0 :                   subelem[0]->set_node(3, elem->node_ptr(4));
     584           0 :                   subelem[0]->set_node(4, elem->node_ptr(5));
     585           0 :                   subelem[0]->set_node(5, elem->node_ptr(8));
     586             : 
     587           0 :                   subelem[1]->set_node(0, elem->node_ptr(0));
     588           0 :                   subelem[1]->set_node(1, elem->node_ptr(2));
     589           0 :                   subelem[1]->set_node(2, elem->node_ptr(3));
     590           0 :                   subelem[1]->set_node(3, elem->node_ptr(8));
     591           0 :                   subelem[1]->set_node(4, elem->node_ptr(6));
     592           0 :                   subelem[1]->set_node(5, elem->node_ptr(7));
     593             :                 }
     594             : 
     595             :               else
     596             :                 {
     597         442 :                   subelem[0]->set_node(0, elem->node_ptr(0));
     598         442 :                   subelem[0]->set_node(1, elem->node_ptr(1));
     599         442 :                   subelem[0]->set_node(2, elem->node_ptr(3));
     600         442 :                   subelem[0]->set_node(3, elem->node_ptr(4));
     601         442 :                   subelem[0]->set_node(4, elem->node_ptr(8));
     602         442 :                   subelem[0]->set_node(5, elem->node_ptr(7));
     603             : 
     604         442 :                   subelem[1]->set_node(0, elem->node_ptr(1));
     605         442 :                   subelem[1]->set_node(1, elem->node_ptr(2));
     606         442 :                   subelem[1]->set_node(2, elem->node_ptr(3));
     607         442 :                   subelem[1]->set_node(3, elem->node_ptr(5));
     608         442 :                   subelem[1]->set_node(4, elem->node_ptr(6));
     609         442 :                   subelem[1]->set_node(5, elem->node_ptr(8));
     610             :                 }
     611             : 
     612          20 :               break;
     613             :             }
     614             : 
     615        1792 :           case HEX8:
     616             :             {
     617        1792 :               BoundaryInfo & boundary_info = mesh.get_boundary_info();
     618             : 
     619             :               // Hexes all split into six tetrahedra
     620       85486 :               subelem[0] = Elem::build(TET4);
     621       85486 :               subelem[1] = Elem::build(TET4);
     622       85486 :               subelem[2] = Elem::build(TET4);
     623       85486 :               subelem[3] = Elem::build(TET4);
     624       85486 :               subelem[4] = Elem::build(TET4);
     625       85486 :               subelem[5] = Elem::build(TET4);
     626             : 
     627             :               // On faces, we choose the node with the highest
     628             :               // global id, and we split on the diagonal which
     629             :               // includes that node.  This ensures that (even in
     630             :               // parallel, even on distributed meshes) the same
     631             :               // diagonal split will be chosen for elements on either
     632             :               // side of the same quad face.
     633       44535 :               const unsigned int highest_n = highest_vertex_on(elem);
     634             : 
     635             :               // opposing_node[n] is the local node number of the node
     636             :               // on the farthest corner of a hex8 from local node n
     637             :               static const std::array<unsigned int, 8> opposing_node =
     638             :                 {6, 7, 4, 5, 2, 3, 0, 1};
     639             : 
     640             :               static const std::vector<std::vector<unsigned int>> sides_opposing_highest =
     641       45170 :                 {{2,3,5},{3,4,5},{1,4,5},{1,2,5},{0,2,3},{0,3,4},{0,1,4},{0,1,2}};
     642             :               static const std::vector<std::vector<unsigned int>> nodes_neighboring_highest =
     643       45170 :                 {{1,3,4},{0,2,5},{1,3,6},{0,2,7},{0,5,7},{1,4,6},{2,5,7},{3,4,6}};
     644             : 
     645             :               // Start by looking in three directions away from the
     646             :               // highest-id node.  In each direction there will be two
     647             :               // different possibilities for the split depending on
     648             :               // how the opposing face nodes are numbered.
     649             :               //
     650             :               // This is tricky enough that I'm not going to worry
     651             :               // about manually keeping tets oriented; we'll just call
     652             :               // orient() on each as we go.
     653             : 
     654        1792 :               unsigned int next_subelem = 0;
     655      179932 :               for (auto side : sides_opposing_highest[highest_n])
     656             :                 {
     657             :                   const std::vector<unsigned int> nodes_on_side =
     658      138981 :                     elem->nodes_on_side(side);
     659             : 
     660      133605 :                   auto [dn, dn2] = split_diagonal(elem, nodes_on_side);
     661             : 
     662        5376 :                   unsigned int split_on_neighbor = false;
     663      342347 :                   for (auto n : nodes_neighboring_highest[highest_n])
     664      302750 :                     if (dn == n || dn2 == n)
     665             :                       {
     666        4928 :                         split_on_neighbor = true;
     667        4928 :                         break;
     668             :                       }
     669             : 
     670             :                   // Add one or two elements for each opposing side,
     671             :                   // depending on whether the diagonal split there
     672             :                   // connects to the neighboring diagonal split or
     673             :                   // not.
     674      133605 :                   if (split_on_neighbor)
     675             :                     {
     676      109240 :                       subelem[next_subelem]->set_node(0, elem->node_ptr(highest_n));
     677      104312 :                       subelem[next_subelem]->set_node(1, elem->node_ptr(dn));
     678      104312 :                       subelem[next_subelem]->set_node(2, elem->node_ptr(dn2));
     679      150357 :                       for (auto n : nodes_on_side)
     680      150357 :                         if (n != dn && n != dn2)
     681             :                           {
     682      104312 :                             subelem[next_subelem]->set_node(3, elem->node_ptr(n));
     683        4928 :                             break;
     684             :                           }
     685       94456 :                       subelem[next_subelem]->orient(&boundary_info);
     686       99384 :                       ++next_subelem;
     687             : 
     688      109240 :                       subelem[next_subelem]->set_node(0, elem->node_ptr(highest_n));
     689      104312 :                       subelem[next_subelem]->set_node(1, elem->node_ptr(dn));
     690      104312 :                       subelem[next_subelem]->set_node(2, elem->node_ptr(dn2));
     691      147795 :                       for (auto n : reverse(nodes_on_side))
     692      147795 :                         if (n != dn && n != dn2)
     693             :                           {
     694      104312 :                             subelem[next_subelem]->set_node(3, elem->node_ptr(n));
     695        4928 :                             break;
     696             :                           }
     697       94456 :                       subelem[next_subelem]->orient(&boundary_info);
     698       99384 :                       ++next_subelem;
     699             :                     }
     700             :                   else
     701             :                     {
     702       35117 :                       subelem[next_subelem]->set_node(0, elem->node_ptr(highest_n));
     703       34669 :                       subelem[next_subelem]->set_node(1, elem->node_ptr(dn));
     704       34669 :                       subelem[next_subelem]->set_node(2, elem->node_ptr(dn2));
     705      101845 :                       for (auto n : nodes_on_side)
     706      339087 :                         for (auto n2 : nodes_neighboring_highest[highest_n])
     707      269995 :                           if (n == n2)
     708             :                             {
     709       34669 :                               subelem[next_subelem]->set_node(3, elem->node_ptr(n));
     710       33773 :                               goto break_both_loops;
     711             :                             }
     712             : 
     713       34221 :                       break_both_loops:
     714       33773 :                       subelem[next_subelem]->orient(&boundary_info);
     715       34221 :                       ++next_subelem;
     716             :                     }
     717             :                 }
     718             : 
     719             :               // At this point we've created between 3 and 6 tets.
     720             :               // What's left to do depends on how many.
     721             : 
     722             :               // If we just chopped off three vertices into three
     723             :               // tets, then the best way to split this hex would be
     724             :               // the symmetric five-split.  Chop off the opposing
     725             :               // vertex too, and then the remaining interior is our
     726             :               // final tet.
     727       44535 :               if (next_subelem == 3)
     728             :                 {
     729        2525 :                   subelem[next_subelem]->set_node(0, elem->node_ptr(opposing_nodes[highest_n][0]));
     730        2525 :                   subelem[next_subelem]->set_node(1, elem->node_ptr(opposing_nodes[highest_n][1]));
     731        2525 :                   subelem[next_subelem]->set_node(2, elem->node_ptr(opposing_nodes[highest_n][2]));
     732        2525 :                   subelem[next_subelem]->set_node(3, elem->node_ptr(opposing_node[highest_n]));
     733        2525 :                   subelem[next_subelem]->orient(&boundary_info);
     734           0 :                   ++next_subelem;
     735             : 
     736        2525 :                   subelem[next_subelem]->set_node(0, elem->node_ptr(opposing_nodes[highest_n][0]));
     737        2525 :                   subelem[next_subelem]->set_node(1, elem->node_ptr(opposing_nodes[highest_n][1]));
     738        2525 :                   subelem[next_subelem]->set_node(2, elem->node_ptr(opposing_nodes[highest_n][2]));
     739        2525 :                   subelem[next_subelem]->set_node(3, elem->node_ptr(highest_n));
     740        2525 :                   subelem[next_subelem]->orient(&boundary_info);
     741           0 :                   ++next_subelem;
     742             : 
     743             :                   // We don't need the 6th tet after all
     744           0 :                   subelem[next_subelem].reset();
     745           0 :                   ++next_subelem;
     746             :                 }
     747             : 
     748             :               // If we just chopped off one (or two) vertices into
     749             :               // tets, then the remaining gap is best (or only) filled
     750             :               // by pairing another tet with each.
     751       44535 :               if (next_subelem == 4 ||
     752             :                   next_subelem == 5)
     753             :                 {
     754       90976 :                   for (auto side : sides_opposing_highest[highest_n])
     755             :                     {
     756             :                       const std::vector<unsigned int> nodes_on_side =
     757       69114 :                         elem->nodes_on_side(side);
     758             : 
     759       67938 :                       auto [dn, dn2] = split_diagonal(elem, nodes_on_side);
     760             : 
     761        1176 :                       unsigned int split_on_neighbor = false;
     762      191663 :                       for (auto n : nodes_neighboring_highest[highest_n])
     763      163841 :                         if (dn == n || dn2 == n)
     764             :                           {
     765         728 :                             split_on_neighbor = true;
     766         728 :                             break;
     767             :                           }
     768             : 
     769             :                       // The two !split_on_neighbor sides are where we
     770             :                       // need the two remaining tets
     771       67938 :                       if (!split_on_neighbor)
     772             :                         {
     773       27542 :                           subelem[next_subelem]->set_node(0, elem->node_ptr(highest_n));
     774       27094 :                           subelem[next_subelem]->set_node(1, elem->node_ptr(dn));
     775       27094 :                           subelem[next_subelem]->set_node(2, elem->node_ptr(dn2));
     776       27094 :                           subelem[next_subelem]->set_node(3, elem->node_ptr(opposing_node[highest_n]));
     777       26198 :                           subelem[next_subelem]->orient(&boundary_info);
     778       26646 :                           ++next_subelem;
     779             :                         }
     780             :                     }
     781             :                 }
     782             : 
     783             :               // Whether we got there by creating six tets from the
     784             :               // first for loop or by patching up the split afterward,
     785             :               // we should have considered six tets (possibly
     786             :               // including one deleted one...) at this point.
     787        1792 :               libmesh_assert(next_subelem == 6);
     788             : 
     789        1792 :               break;
     790             :             }
     791             : 
     792         142 :           case PRISM6:
     793             :             {
     794             :               // Prisms all split into three tetrahedra
     795         276 :               subelem[0] = Elem::build(TET4);
     796         276 :               subelem[1] = Elem::build(TET4);
     797         276 :               subelem[2] = Elem::build(TET4);
     798             : 
     799             :               // Triangular faces are not split.
     800             : 
     801             :               // On quad faces, we choose the node with the highest
     802             :               // global id, and we split on the diagonal which
     803             :               // includes that node.  This ensures that (even in
     804             :               // parallel, even on distributed meshes) the same
     805             :               // diagonal split will be chosen for elements on either
     806             :               // side of the same quad face.  It also ensures that we
     807             :               // always have a mix of "clockwise" and
     808             :               // "counterclockwise" split faces (two of one and one
     809             :               // of the other on each prism; this is useful since the
     810             :               // alternative all-clockwise or all-counterclockwise
     811             :               // face splittings can't be turned into tets without
     812             :               // adding more nodes
     813             : 
     814             :               // Split on 0-4 diagonal
     815         142 :               if (split_first_diagonal(elem, 0,4, 1,3))
     816             :                 {
     817             :                   // Split on 0-5 diagonal
     818         142 :                   if (split_first_diagonal(elem, 0,5, 2,3))
     819             :                     {
     820             :                       // Split on 1-5 diagonal
     821         142 :                       if (split_first_diagonal(elem, 1,5, 2,4))
     822             :                         {
     823          73 :                           subelem[0]->set_node(0, elem->node_ptr(0));
     824          73 :                           subelem[0]->set_node(1, elem->node_ptr(4));
     825          73 :                           subelem[0]->set_node(2, elem->node_ptr(5));
     826          73 :                           subelem[0]->set_node(3, elem->node_ptr(3));
     827             : 
     828          73 :                           subelem[1]->set_node(0, elem->node_ptr(0));
     829          73 :                           subelem[1]->set_node(1, elem->node_ptr(4));
     830          73 :                           subelem[1]->set_node(2, elem->node_ptr(1));
     831          73 :                           subelem[1]->set_node(3, elem->node_ptr(5));
     832             : 
     833          73 :                           subelem[2]->set_node(0, elem->node_ptr(0));
     834          73 :                           subelem[2]->set_node(1, elem->node_ptr(1));
     835          73 :                           subelem[2]->set_node(2, elem->node_ptr(2));
     836          73 :                           subelem[2]->set_node(3, elem->node_ptr(5));
     837             :                         }
     838             :                       else // Split on 2-4 diagonal
     839             :                         {
     840           2 :                           libmesh_assert (split_first_diagonal(elem, 2,4, 1,5));
     841             : 
     842          73 :                           subelem[0]->set_node(0, elem->node_ptr(0));
     843          73 :                           subelem[0]->set_node(1, elem->node_ptr(4));
     844          73 :                           subelem[0]->set_node(2, elem->node_ptr(5));
     845          73 :                           subelem[0]->set_node(3, elem->node_ptr(3));
     846             : 
     847          73 :                           subelem[1]->set_node(0, elem->node_ptr(0));
     848          73 :                           subelem[1]->set_node(1, elem->node_ptr(4));
     849          73 :                           subelem[1]->set_node(2, elem->node_ptr(2));
     850          73 :                           subelem[1]->set_node(3, elem->node_ptr(5));
     851             : 
     852          73 :                           subelem[2]->set_node(0, elem->node_ptr(0));
     853          73 :                           subelem[2]->set_node(1, elem->node_ptr(1));
     854          73 :                           subelem[2]->set_node(2, elem->node_ptr(2));
     855          73 :                           subelem[2]->set_node(3, elem->node_ptr(4));
     856             :                         }
     857             :                     }
     858             :                   else // Split on 2-3 diagonal
     859             :                     {
     860           0 :                       libmesh_assert (split_first_diagonal(elem, 2,3, 0,5));
     861             : 
     862             :                       // 0-4 and 2-3 split implies 2-4 split
     863           0 :                       libmesh_assert (split_first_diagonal(elem, 2,4, 1,5));
     864             : 
     865           0 :                       subelem[0]->set_node(0, elem->node_ptr(0));
     866           0 :                       subelem[0]->set_node(1, elem->node_ptr(4));
     867           0 :                       subelem[0]->set_node(2, elem->node_ptr(2));
     868           0 :                       subelem[0]->set_node(3, elem->node_ptr(3));
     869             : 
     870           0 :                       subelem[1]->set_node(0, elem->node_ptr(3));
     871           0 :                       subelem[1]->set_node(1, elem->node_ptr(4));
     872           0 :                       subelem[1]->set_node(2, elem->node_ptr(2));
     873           0 :                       subelem[1]->set_node(3, elem->node_ptr(5));
     874             : 
     875           0 :                       subelem[2]->set_node(0, elem->node_ptr(0));
     876           0 :                       subelem[2]->set_node(1, elem->node_ptr(1));
     877           0 :                       subelem[2]->set_node(2, elem->node_ptr(2));
     878           0 :                       subelem[2]->set_node(3, elem->node_ptr(4));
     879             :                     }
     880             :                 }
     881             :               else // Split on 1-3 diagonal
     882             :                 {
     883           0 :                   libmesh_assert (split_first_diagonal(elem, 1,3, 0,4));
     884             : 
     885             :                   // Split on 0-5 diagonal
     886           0 :                   if (split_first_diagonal(elem, 0,5, 2,3))
     887             :                     {
     888             :                       // 1-3 and 0-5 split implies 1-5 split
     889           0 :                       libmesh_assert (split_first_diagonal(elem, 1,5, 2,4));
     890             : 
     891           0 :                       subelem[0]->set_node(0, elem->node_ptr(1));
     892           0 :                       subelem[0]->set_node(1, elem->node_ptr(3));
     893           0 :                       subelem[0]->set_node(2, elem->node_ptr(4));
     894           0 :                       subelem[0]->set_node(3, elem->node_ptr(5));
     895             : 
     896           0 :                       subelem[1]->set_node(0, elem->node_ptr(1));
     897           0 :                       subelem[1]->set_node(1, elem->node_ptr(0));
     898           0 :                       subelem[1]->set_node(2, elem->node_ptr(3));
     899           0 :                       subelem[1]->set_node(3, elem->node_ptr(5));
     900             : 
     901           0 :                       subelem[2]->set_node(0, elem->node_ptr(0));
     902           0 :                       subelem[2]->set_node(1, elem->node_ptr(1));
     903           0 :                       subelem[2]->set_node(2, elem->node_ptr(2));
     904           0 :                       subelem[2]->set_node(3, elem->node_ptr(5));
     905             :                     }
     906             :                   else // Split on 2-3 diagonal
     907             :                     {
     908           0 :                       libmesh_assert (split_first_diagonal(elem, 2,3, 0,5));
     909             : 
     910             :                       // Split on 1-5 diagonal
     911           0 :                       if (split_first_diagonal(elem, 1,5, 2,4))
     912             :                         {
     913           0 :                           subelem[0]->set_node(0, elem->node_ptr(0));
     914           0 :                           subelem[0]->set_node(1, elem->node_ptr(1));
     915           0 :                           subelem[0]->set_node(2, elem->node_ptr(2));
     916           0 :                           subelem[0]->set_node(3, elem->node_ptr(3));
     917             : 
     918           0 :                           subelem[1]->set_node(0, elem->node_ptr(3));
     919           0 :                           subelem[1]->set_node(1, elem->node_ptr(1));
     920           0 :                           subelem[1]->set_node(2, elem->node_ptr(2));
     921           0 :                           subelem[1]->set_node(3, elem->node_ptr(5));
     922             : 
     923           0 :                           subelem[2]->set_node(0, elem->node_ptr(1));
     924           0 :                           subelem[2]->set_node(1, elem->node_ptr(3));
     925           0 :                           subelem[2]->set_node(2, elem->node_ptr(4));
     926           0 :                           subelem[2]->set_node(3, elem->node_ptr(5));
     927             :                         }
     928             :                       else // Split on 2-4 diagonal
     929             :                         {
     930           0 :                           libmesh_assert (split_first_diagonal(elem, 2,4, 1,5));
     931             : 
     932           0 :                           subelem[0]->set_node(0, elem->node_ptr(0));
     933           0 :                           subelem[0]->set_node(1, elem->node_ptr(1));
     934           0 :                           subelem[0]->set_node(2, elem->node_ptr(2));
     935           0 :                           subelem[0]->set_node(3, elem->node_ptr(3));
     936             : 
     937           0 :                           subelem[1]->set_node(0, elem->node_ptr(2));
     938           0 :                           subelem[1]->set_node(1, elem->node_ptr(3));
     939           0 :                           subelem[1]->set_node(2, elem->node_ptr(4));
     940           0 :                           subelem[1]->set_node(3, elem->node_ptr(5));
     941             : 
     942           0 :                           subelem[2]->set_node(0, elem->node_ptr(3));
     943           0 :                           subelem[2]->set_node(1, elem->node_ptr(1));
     944           0 :                           subelem[2]->set_node(2, elem->node_ptr(2));
     945           0 :                           subelem[2]->set_node(3, elem->node_ptr(4));
     946             :                         }
     947             :                     }
     948             :                 }
     949             : 
     950           4 :               break;
     951             :             }
     952             : 
     953         426 :           case PRISM20:
     954             :           case PRISM21:
     955             :             libmesh_experimental(); // We should upgrade this to TET14...
     956             :             libmesh_fallthrough();
     957             :           case PRISM18:
     958             :             {
     959         828 :               subelem[0] = Elem::build(TET10);
     960         828 :               subelem[1] = Elem::build(TET10);
     961         828 :               subelem[2] = Elem::build(TET10);
     962             : 
     963             :               // Split on 0-4 diagonal
     964         426 :               if (split_first_diagonal(elem, 0,4, 1,3))
     965             :                 {
     966             :                   // Split on 0-5 diagonal
     967         426 :                   if (split_first_diagonal(elem, 0,5, 2,3))
     968             :                     {
     969             :                       // Split on 1-5 diagonal
     970         426 :                       if (split_first_diagonal(elem, 1,5, 2,4))
     971             :                         {
     972         219 :                           subelem[0]->set_node(0, elem->node_ptr(0));
     973         219 :                           subelem[0]->set_node(1, elem->node_ptr(4));
     974         219 :                           subelem[0]->set_node(2, elem->node_ptr(5));
     975         219 :                           subelem[0]->set_node(3, elem->node_ptr(3));
     976             : 
     977         219 :                           subelem[0]->set_node(4, elem->node_ptr(15));
     978         219 :                           subelem[0]->set_node(5, elem->node_ptr(13));
     979         219 :                           subelem[0]->set_node(6, elem->node_ptr(17));
     980         219 :                           subelem[0]->set_node(7, elem->node_ptr(9));
     981         219 :                           subelem[0]->set_node(8, elem->node_ptr(12));
     982         219 :                           subelem[0]->set_node(9, elem->node_ptr(14));
     983             : 
     984         219 :                           subelem[1]->set_node(0, elem->node_ptr(0));
     985         219 :                           subelem[1]->set_node(1, elem->node_ptr(4));
     986         219 :                           subelem[1]->set_node(2, elem->node_ptr(1));
     987         219 :                           subelem[1]->set_node(3, elem->node_ptr(5));
     988             : 
     989         219 :                           subelem[1]->set_node(4, elem->node_ptr(15));
     990         219 :                           subelem[1]->set_node(5, elem->node_ptr(10));
     991         219 :                           subelem[1]->set_node(6, elem->node_ptr(6));
     992         219 :                           subelem[1]->set_node(7, elem->node_ptr(17));
     993         219 :                           subelem[1]->set_node(8, elem->node_ptr(13));
     994         219 :                           subelem[1]->set_node(9, elem->node_ptr(16));
     995             : 
     996         219 :                           subelem[2]->set_node(0, elem->node_ptr(0));
     997         219 :                           subelem[2]->set_node(1, elem->node_ptr(1));
     998         219 :                           subelem[2]->set_node(2, elem->node_ptr(2));
     999         219 :                           subelem[2]->set_node(3, elem->node_ptr(5));
    1000             : 
    1001         219 :                           subelem[2]->set_node(4, elem->node_ptr(6));
    1002         219 :                           subelem[2]->set_node(5, elem->node_ptr(7));
    1003         219 :                           subelem[2]->set_node(6, elem->node_ptr(8));
    1004         219 :                           subelem[2]->set_node(7, elem->node_ptr(17));
    1005         219 :                           subelem[2]->set_node(8, elem->node_ptr(16));
    1006         219 :                           subelem[2]->set_node(9, elem->node_ptr(11));
    1007             :                         }
    1008             :                       else // Split on 2-4 diagonal
    1009             :                         {
    1010           6 :                           libmesh_assert (split_first_diagonal(elem, 2,4, 1,5));
    1011             : 
    1012         219 :                           subelem[0]->set_node(0, elem->node_ptr(0));
    1013         219 :                           subelem[0]->set_node(1, elem->node_ptr(4));
    1014         219 :                           subelem[0]->set_node(2, elem->node_ptr(5));
    1015         219 :                           subelem[0]->set_node(3, elem->node_ptr(3));
    1016             : 
    1017         219 :                           subelem[0]->set_node(4, elem->node_ptr(15));
    1018         219 :                           subelem[0]->set_node(5, elem->node_ptr(13));
    1019         219 :                           subelem[0]->set_node(6, elem->node_ptr(17));
    1020         219 :                           subelem[0]->set_node(7, elem->node_ptr(9));
    1021         219 :                           subelem[0]->set_node(8, elem->node_ptr(12));
    1022         219 :                           subelem[0]->set_node(9, elem->node_ptr(14));
    1023             : 
    1024         219 :                           subelem[1]->set_node(0, elem->node_ptr(0));
    1025         219 :                           subelem[1]->set_node(1, elem->node_ptr(4));
    1026         219 :                           subelem[1]->set_node(2, elem->node_ptr(2));
    1027         219 :                           subelem[1]->set_node(3, elem->node_ptr(5));
    1028             : 
    1029         219 :                           subelem[1]->set_node(4, elem->node_ptr(15));
    1030         219 :                           subelem[1]->set_node(5, elem->node_ptr(16));
    1031         219 :                           subelem[1]->set_node(6, elem->node_ptr(8));
    1032         219 :                           subelem[1]->set_node(7, elem->node_ptr(17));
    1033         219 :                           subelem[1]->set_node(8, elem->node_ptr(13));
    1034         219 :                           subelem[1]->set_node(9, elem->node_ptr(11));
    1035             : 
    1036         219 :                           subelem[2]->set_node(0, elem->node_ptr(0));
    1037         219 :                           subelem[2]->set_node(1, elem->node_ptr(1));
    1038         219 :                           subelem[2]->set_node(2, elem->node_ptr(2));
    1039         219 :                           subelem[2]->set_node(3, elem->node_ptr(4));
    1040             : 
    1041         219 :                           subelem[2]->set_node(4, elem->node_ptr(6));
    1042         219 :                           subelem[2]->set_node(5, elem->node_ptr(7));
    1043         219 :                           subelem[2]->set_node(6, elem->node_ptr(8));
    1044         219 :                           subelem[2]->set_node(7, elem->node_ptr(15));
    1045         219 :                           subelem[2]->set_node(8, elem->node_ptr(10));
    1046         219 :                           subelem[2]->set_node(9, elem->node_ptr(16));
    1047             :                         }
    1048             :                     }
    1049             :                   else // Split on 2-3 diagonal
    1050             :                     {
    1051           0 :                       libmesh_assert (split_first_diagonal(elem, 2,3, 0,5));
    1052             : 
    1053             :                       // 0-4 and 2-3 split implies 2-4 split
    1054           0 :                       libmesh_assert (split_first_diagonal(elem, 2,4, 1,5));
    1055             : 
    1056           0 :                       subelem[0]->set_node(0, elem->node_ptr(0));
    1057           0 :                       subelem[0]->set_node(1, elem->node_ptr(4));
    1058           0 :                       subelem[0]->set_node(2, elem->node_ptr(2));
    1059           0 :                       subelem[0]->set_node(3, elem->node_ptr(3));
    1060             : 
    1061           0 :                       subelem[0]->set_node(4, elem->node_ptr(15));
    1062           0 :                       subelem[0]->set_node(5, elem->node_ptr(16));
    1063           0 :                       subelem[0]->set_node(6, elem->node_ptr(8));
    1064           0 :                       subelem[0]->set_node(7, elem->node_ptr(9));
    1065           0 :                       subelem[0]->set_node(8, elem->node_ptr(12));
    1066           0 :                       subelem[0]->set_node(9, elem->node_ptr(17));
    1067             : 
    1068           0 :                       subelem[1]->set_node(0, elem->node_ptr(3));
    1069           0 :                       subelem[1]->set_node(1, elem->node_ptr(4));
    1070           0 :                       subelem[1]->set_node(2, elem->node_ptr(2));
    1071           0 :                       subelem[1]->set_node(3, elem->node_ptr(5));
    1072             : 
    1073           0 :                       subelem[1]->set_node(4, elem->node_ptr(12));
    1074           0 :                       subelem[1]->set_node(5, elem->node_ptr(16));
    1075           0 :                       subelem[1]->set_node(6, elem->node_ptr(17));
    1076           0 :                       subelem[1]->set_node(7, elem->node_ptr(14));
    1077           0 :                       subelem[1]->set_node(8, elem->node_ptr(13));
    1078           0 :                       subelem[1]->set_node(9, elem->node_ptr(11));
    1079             : 
    1080           0 :                       subelem[2]->set_node(0, elem->node_ptr(0));
    1081           0 :                       subelem[2]->set_node(1, elem->node_ptr(1));
    1082           0 :                       subelem[2]->set_node(2, elem->node_ptr(2));
    1083           0 :                       subelem[2]->set_node(3, elem->node_ptr(4));
    1084             : 
    1085           0 :                       subelem[2]->set_node(4, elem->node_ptr(6));
    1086           0 :                       subelem[2]->set_node(5, elem->node_ptr(7));
    1087           0 :                       subelem[2]->set_node(6, elem->node_ptr(8));
    1088           0 :                       subelem[2]->set_node(7, elem->node_ptr(15));
    1089           0 :                       subelem[2]->set_node(8, elem->node_ptr(10));
    1090           0 :                       subelem[2]->set_node(9, elem->node_ptr(16));
    1091             :                     }
    1092             :                 }
    1093             :               else // Split on 1-3 diagonal
    1094             :                 {
    1095           0 :                   libmesh_assert (split_first_diagonal(elem, 1,3, 0,4));
    1096             : 
    1097             :                   // Split on 0-5 diagonal
    1098           0 :                   if (split_first_diagonal(elem, 0,5, 2,3))
    1099             :                     {
    1100             :                       // 1-3 and 0-5 split implies 1-5 split
    1101           0 :                       libmesh_assert (split_first_diagonal(elem, 1,5, 2,4));
    1102             : 
    1103           0 :                       subelem[0]->set_node(0, elem->node_ptr(1));
    1104           0 :                       subelem[0]->set_node(1, elem->node_ptr(3));
    1105           0 :                       subelem[0]->set_node(2, elem->node_ptr(4));
    1106           0 :                       subelem[0]->set_node(3, elem->node_ptr(5));
    1107             : 
    1108           0 :                       subelem[0]->set_node(4, elem->node_ptr(15));
    1109           0 :                       subelem[0]->set_node(5, elem->node_ptr(12));
    1110           0 :                       subelem[0]->set_node(6, elem->node_ptr(10));
    1111           0 :                       subelem[0]->set_node(7, elem->node_ptr(16));
    1112           0 :                       subelem[0]->set_node(8, elem->node_ptr(14));
    1113           0 :                       subelem[0]->set_node(9, elem->node_ptr(13));
    1114             : 
    1115           0 :                       subelem[1]->set_node(0, elem->node_ptr(1));
    1116           0 :                       subelem[1]->set_node(1, elem->node_ptr(0));
    1117           0 :                       subelem[1]->set_node(2, elem->node_ptr(3));
    1118           0 :                       subelem[1]->set_node(3, elem->node_ptr(5));
    1119             : 
    1120           0 :                       subelem[1]->set_node(4, elem->node_ptr(6));
    1121           0 :                       subelem[1]->set_node(5, elem->node_ptr(9));
    1122           0 :                       subelem[1]->set_node(6, elem->node_ptr(15));
    1123           0 :                       subelem[1]->set_node(7, elem->node_ptr(16));
    1124           0 :                       subelem[1]->set_node(8, elem->node_ptr(17));
    1125           0 :                       subelem[1]->set_node(9, elem->node_ptr(14));
    1126             : 
    1127           0 :                       subelem[2]->set_node(0, elem->node_ptr(0));
    1128           0 :                       subelem[2]->set_node(1, elem->node_ptr(1));
    1129           0 :                       subelem[2]->set_node(2, elem->node_ptr(2));
    1130           0 :                       subelem[2]->set_node(3, elem->node_ptr(5));
    1131             : 
    1132           0 :                       subelem[2]->set_node(4, elem->node_ptr(6));
    1133           0 :                       subelem[2]->set_node(5, elem->node_ptr(7));
    1134           0 :                       subelem[2]->set_node(6, elem->node_ptr(8));
    1135           0 :                       subelem[2]->set_node(7, elem->node_ptr(17));
    1136           0 :                       subelem[2]->set_node(8, elem->node_ptr(16));
    1137           0 :                       subelem[2]->set_node(9, elem->node_ptr(11));
    1138             :                     }
    1139             :                   else // Split on 2-3 diagonal
    1140             :                     {
    1141           0 :                       libmesh_assert (split_first_diagonal(elem, 2,3, 0,5));
    1142             : 
    1143             :                       // Split on 1-5 diagonal
    1144           0 :                       if (split_first_diagonal(elem, 1,5, 2,4))
    1145             :                         {
    1146           0 :                           subelem[0]->set_node(0, elem->node_ptr(0));
    1147           0 :                           subelem[0]->set_node(1, elem->node_ptr(1));
    1148           0 :                           subelem[0]->set_node(2, elem->node_ptr(2));
    1149           0 :                           subelem[0]->set_node(3, elem->node_ptr(3));
    1150             : 
    1151           0 :                           subelem[0]->set_node(4, elem->node_ptr(6));
    1152           0 :                           subelem[0]->set_node(5, elem->node_ptr(7));
    1153           0 :                           subelem[0]->set_node(6, elem->node_ptr(8));
    1154           0 :                           subelem[0]->set_node(7, elem->node_ptr(9));
    1155           0 :                           subelem[0]->set_node(8, elem->node_ptr(15));
    1156           0 :                           subelem[0]->set_node(9, elem->node_ptr(17));
    1157             : 
    1158           0 :                           subelem[1]->set_node(0, elem->node_ptr(3));
    1159           0 :                           subelem[1]->set_node(1, elem->node_ptr(1));
    1160           0 :                           subelem[1]->set_node(2, elem->node_ptr(2));
    1161           0 :                           subelem[1]->set_node(3, elem->node_ptr(5));
    1162             : 
    1163           0 :                           subelem[1]->set_node(4, elem->node_ptr(15));
    1164           0 :                           subelem[1]->set_node(5, elem->node_ptr(7));
    1165           0 :                           subelem[1]->set_node(6, elem->node_ptr(17));
    1166           0 :                           subelem[1]->set_node(7, elem->node_ptr(14));
    1167           0 :                           subelem[1]->set_node(8, elem->node_ptr(16));
    1168           0 :                           subelem[1]->set_node(9, elem->node_ptr(11));
    1169             : 
    1170           0 :                           subelem[2]->set_node(0, elem->node_ptr(1));
    1171           0 :                           subelem[2]->set_node(1, elem->node_ptr(3));
    1172           0 :                           subelem[2]->set_node(2, elem->node_ptr(4));
    1173           0 :                           subelem[2]->set_node(3, elem->node_ptr(5));
    1174             : 
    1175           0 :                           subelem[2]->set_node(4, elem->node_ptr(15));
    1176           0 :                           subelem[2]->set_node(5, elem->node_ptr(12));
    1177           0 :                           subelem[2]->set_node(6, elem->node_ptr(10));
    1178           0 :                           subelem[2]->set_node(7, elem->node_ptr(16));
    1179           0 :                           subelem[2]->set_node(8, elem->node_ptr(14));
    1180           0 :                           subelem[2]->set_node(9, elem->node_ptr(13));
    1181             :                         }
    1182             :                       else // Split on 2-4 diagonal
    1183             :                         {
    1184           0 :                           libmesh_assert (split_first_diagonal(elem, 2,4, 1,5));
    1185             : 
    1186           0 :                           subelem[0]->set_node(0, elem->node_ptr(0));
    1187           0 :                           subelem[0]->set_node(1, elem->node_ptr(1));
    1188           0 :                           subelem[0]->set_node(2, elem->node_ptr(2));
    1189           0 :                           subelem[0]->set_node(3, elem->node_ptr(3));
    1190             : 
    1191           0 :                           subelem[0]->set_node(4, elem->node_ptr(6));
    1192           0 :                           subelem[0]->set_node(5, elem->node_ptr(7));
    1193           0 :                           subelem[0]->set_node(6, elem->node_ptr(8));
    1194           0 :                           subelem[0]->set_node(7, elem->node_ptr(9));
    1195           0 :                           subelem[0]->set_node(8, elem->node_ptr(15));
    1196           0 :                           subelem[0]->set_node(9, elem->node_ptr(17));
    1197             : 
    1198           0 :                           subelem[1]->set_node(0, elem->node_ptr(2));
    1199           0 :                           subelem[1]->set_node(1, elem->node_ptr(3));
    1200           0 :                           subelem[1]->set_node(2, elem->node_ptr(4));
    1201           0 :                           subelem[1]->set_node(3, elem->node_ptr(5));
    1202             : 
    1203           0 :                           subelem[1]->set_node(4, elem->node_ptr(17));
    1204           0 :                           subelem[1]->set_node(5, elem->node_ptr(12));
    1205           0 :                           subelem[1]->set_node(6, elem->node_ptr(16));
    1206           0 :                           subelem[1]->set_node(7, elem->node_ptr(11));
    1207           0 :                           subelem[1]->set_node(8, elem->node_ptr(14));
    1208           0 :                           subelem[1]->set_node(9, elem->node_ptr(13));
    1209             : 
    1210           0 :                           subelem[2]->set_node(0, elem->node_ptr(3));
    1211           0 :                           subelem[2]->set_node(1, elem->node_ptr(1));
    1212           0 :                           subelem[2]->set_node(2, elem->node_ptr(2));
    1213           0 :                           subelem[2]->set_node(3, elem->node_ptr(4));
    1214             : 
    1215           0 :                           subelem[2]->set_node(4, elem->node_ptr(15));
    1216           0 :                           subelem[2]->set_node(5, elem->node_ptr(7));
    1217           0 :                           subelem[2]->set_node(6, elem->node_ptr(17));
    1218           0 :                           subelem[2]->set_node(7, elem->node_ptr(12));
    1219           0 :                           subelem[2]->set_node(8, elem->node_ptr(10));
    1220           0 :                           subelem[2]->set_node(9, elem->node_ptr(16));
    1221             :                         }
    1222             :                     }
    1223             :                 }
    1224             : 
    1225          12 :               break;
    1226             :             }
    1227             : 
    1228             :             // No need to split elements that are already simplicial:
    1229       20481 :           case EDGE2:
    1230             :           case EDGE3:
    1231             :           case EDGE4:
    1232             :           case TRI3:
    1233             :           case TRI6:
    1234             :           case TRI7:
    1235             :           case TET4:
    1236             :           case TET10:
    1237             :           case TET14:
    1238             :           case INFEDGE2:
    1239             :             // No way to split infinite quad/prism elements, so
    1240             :             // hopefully no need to
    1241             :           case INFQUAD4:
    1242             :           case INFQUAD6:
    1243             :           case INFPRISM6:
    1244             :           case INFPRISM12:
    1245         854 :             continue;
    1246             :             // If we're left with an unimplemented hex we're probably
    1247             :             // out of luck.  TODO: implement hexes
    1248           0 :           default:
    1249             :             {
    1250           0 :               libMesh::err << "Error, encountered unimplemented element "
    1251           0 :                            << Utility::enum_to_string<ElemType>(etype)
    1252           0 :                            << " in MeshTools::Modification::all_tri()..."
    1253           0 :                            << std::endl;
    1254           0 :               libmesh_not_implemented();
    1255         854 :             }
    1256       19627 :           } // end switch (etype)
    1257             : 
    1258             :         // Be sure the correct data is set for all subelems.
    1259       54990 :         const unsigned int nei = elem->n_extra_integers();
    1260      345382 :         for (unsigned int i=0; i != max_subelems; ++i)
    1261      301968 :           if (subelem[i]) {
    1262      286163 :             subelem[i]->processor_id() = elem->processor_id();
    1263      286163 :             subelem[i]->subdomain_id() = elem->subdomain_id();
    1264             : 
    1265             :             // Copy any extra element data.  Since the subelements
    1266             :             // haven't been added to the mesh yet any allocation has
    1267             :             // to be done manually.
    1268      286163 :             subelem[i]->add_extra_integers(nei);
    1269      286163 :             for (unsigned int ei=0; ei != nei; ++ei)
    1270           0 :               subelem[ei]->set_extra_integer(ei, elem->get_extra_integer(ei));
    1271             : 
    1272             : 
    1273             :             // Copy any mapping data.
    1274      286163 :             subelem[i]->set_mapping_type(elem->mapping_type());
    1275       23056 :             subelem[i]->set_mapping_data(elem->mapping_data());
    1276             :           }
    1277             : 
    1278             :         // On a mesh with boundary data, we need to move that data to
    1279             :         // the new elements.
    1280             : 
    1281             :         // On a mesh which is distributed, we need to move
    1282             :         // remote_elem links to the new elements.
    1283       54990 :         bool mesh_is_serial = mesh.is_serial();
    1284             : 
    1285       54990 :         if (mesh_has_boundary_data || !mesh_is_serial)
    1286             :           {
    1287             :             // Container to key boundary IDs handed back by the BoundaryInfo object.
    1288         392 :             std::vector<boundary_id_type> bc_ids;
    1289             : 
    1290       87516 :             for (auto sn : elem->side_index_range())
    1291             :               {
    1292       73806 :                 mesh.get_boundary_info().boundary_ids(elem, sn, bc_ids);
    1293             : 
    1294       73806 :                 if (bc_ids.empty() && elem->neighbor_ptr(sn) != remote_elem)
    1295       59665 :                   continue;
    1296             : 
    1297             :                 // Make a sorted list of node ids for elem->side(sn)
    1298       14141 :                 elem->build_side_ptr(elem_side, sn);
    1299       14425 :                 std::vector<dof_id_type> elem_side_nodes(elem_side->n_nodes());
    1300       15713 :                 for (unsigned int esn=0,
    1301         568 :                      n_esn = cast_int<unsigned int>(elem_side_nodes.size());
    1302       68855 :                      esn != n_esn; ++esn)
    1303       55642 :                   elem_side_nodes[esn] = elem_side->node_id(esn);
    1304       14141 :                 std::sort(elem_side_nodes.begin(), elem_side_nodes.end());
    1305             : 
    1306       79967 :                 for (unsigned int i=0; i != max_subelems; ++i)
    1307       66650 :                   if (subelem[i])
    1308             :                     {
    1309      283200 :                       for (auto subside : subelem[i]->side_index_range())
    1310             :                         {
    1311      224658 :                           subelem[i]->build_side_ptr(subside_elem, subside);
    1312             : 
    1313             :                           // Make a list of *vertex* node ids for this subside, see if they are all present
    1314             :                           // in elem->side(sn).  Note 1: we can't just compare elem->key(sn) to
    1315             :                           // subelem[i]->key(subside) in the Prism cases, since the new side is
    1316             :                           // a different type.  Note 2: we only use vertex nodes since, in the future,
    1317             :                           // a Hex20 or Prism15's QUAD8 face may be split into two Tri6 faces, and the
    1318             :                           // original face will not contain the mid-edge node.
    1319      226746 :                           std::vector<dof_id_type> subside_nodes(subside_elem->n_vertices());
    1320      232458 :                           for (unsigned int ssn=0,
    1321        4176 :                                n_ssn = cast_int<unsigned int>(subside_nodes.size());
    1322      870102 :                                ssn != n_ssn; ++ssn)
    1323      650388 :                             subside_nodes[ssn] = subside_elem->node_id(ssn);
    1324      224658 :                           std::sort(subside_nodes.begin(), subside_nodes.end());
    1325             : 
    1326             :                           // std::includes returns true if every element of the second sorted range is
    1327             :                           // contained in the first sorted range.
    1328      224658 :                           if (std::includes(elem_side_nodes.begin(), elem_side_nodes.end(),
    1329             :                                             subside_nodes.begin(), subside_nodes.end()))
    1330             :                             {
    1331       29493 :                               for (const auto & b_id : bc_ids)
    1332        7102 :                                 if (b_id != BoundaryInfo::invalid_id)
    1333             :                                   {
    1334        7102 :                                     new_bndry_ids.push_back(b_id);
    1335        7102 :                                     new_bndry_elements.push_back(subelem[i].get());
    1336        7102 :                                     new_bndry_sides.push_back(subside);
    1337             :                                   }
    1338             : 
    1339             :                               // If the original element had a RemoteElem neighbor on side 'sn',
    1340             :                               // then the subelem has one on side 'subside'.
    1341       22707 :                               if (elem->neighbor_ptr(sn) == remote_elem)
    1342          48 :                                 subelem[i]->set_neighbor(subside, const_cast<RemoteElem*>(remote_elem));
    1343             :                             }
    1344             :                         }
    1345             :                     } // end for loop over subelem
    1346             :               } // end for loop over sides
    1347             : 
    1348             :             // Remove the original element from the BoundaryInfo structure.
    1349       13514 :             mesh.get_boundary_info().remove(elem);
    1350             : 
    1351             :           } // end if (mesh_has_boundary_data)
    1352             : 
    1353             :         // Determine new IDs for the split elements which will be
    1354             :         // the same on all processors, therefore keeping the Mesh
    1355             :         // in sync.  Note: we offset the new IDs by max_orig_id to
    1356             :         // avoid overwriting any of the original IDs.
    1357      345382 :         for (unsigned int i=0; i != max_subelems; ++i)
    1358      301968 :           if (subelem[i])
    1359             :             {
    1360             :               // Determine new IDs for the split elements which will be
    1361             :               // the same on all processors, therefore keeping the Mesh
    1362             :               // in sync.  Note: we offset the new IDs by the max of the
    1363             :               // pre-existing ids to avoid conflicting with originals.
    1364      286163 :               subelem[i]->set_id( max_orig_id + 6*elem->id() + i );
    1365             : 
    1366             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1367      286163 :               subelem[i]->set_unique_id(max_unique_id + max_subelems*elem->unique_id() + i);
    1368             : #endif
    1369             : 
    1370             :               // Prepare to add the newly-created simplices
    1371       11528 :               new_elements.push_back(std::move(subelem[i]));
    1372             :             }
    1373             : 
    1374             :         // Delete the original element
    1375       54990 :         mesh.delete_elem(elem);
    1376        2144 :       } // End for loop over elements
    1377        2144 :   } // end scope
    1378             : 
    1379             : 
    1380             :   // Now, iterate over the new elements vector, and add them each to
    1381             :   // the Mesh.
    1382      288435 :   for (auto & elem : new_elements)
    1383      309219 :     mesh.add_elem(std::move(elem));
    1384             : 
    1385        2272 :   if (mesh_has_boundary_data)
    1386             :     {
    1387             :       // If the old mesh had boundary data, the new mesh better have
    1388             :       // some.  However, we can't assert that the size of
    1389             :       // new_bndry_elements vector is > 0, since we may not have split
    1390             :       // any elements actually on the boundary.  We also can't assert
    1391             :       // that the original number of boundary sides is equal to the
    1392             :       // sum of the boundary sides currently in the mesh and the
    1393             :       // newly-added boundary sides, since in 3D, we may have split a
    1394             :       // boundary QUAD into two boundary TRIs.  Therefore, we won't be
    1395             :       // too picky about the actual number of BCs, and just assert that
    1396             :       // there are some, somewhere.
    1397             : #ifndef NDEBUG
    1398          36 :       bool nbe_nonempty = new_bndry_elements.size();
    1399          36 :       mesh.comm().max(nbe_nonempty);
    1400          36 :       libmesh_assert(nbe_nonempty ||
    1401             :                      mesh.get_boundary_info().n_boundary_conds()>0);
    1402             : #endif
    1403             : 
    1404             :       // We should also be sure that the lengths of the new boundary data vectors
    1405             :       // are all the same.
    1406          36 :       libmesh_assert_equal_to (new_bndry_elements.size(), new_bndry_sides.size());
    1407          36 :       libmesh_assert_equal_to (new_bndry_sides.size(), new_bndry_ids.size());
    1408             : 
    1409             :       // Add the new boundary info to the mesh
    1410        8380 :       for (auto s : index_range(new_bndry_elements))
    1411        7686 :         mesh.get_boundary_info().add_side(new_bndry_elements[s],
    1412         584 :                                           new_bndry_sides[s],
    1413         584 :                                           new_bndry_ids[s]);
    1414             :     }
    1415             : 
    1416             :   // In a DistributedMesh any newly added ghost node ids may be
    1417             :   // inconsistent, and unique_ids of newly added ghost nodes remain
    1418             :   // unset.
    1419             :   // make_nodes_parallel_consistent() will fix all this.
    1420        2272 :   if (!mesh.is_serial())
    1421             :     {
    1422         903 :       mesh.comm().max(added_new_ghost_point);
    1423             : 
    1424         903 :       if (added_new_ghost_point)
    1425           0 :         MeshCommunication().make_nodes_parallel_consistent (mesh);
    1426             :     }
    1427             : 
    1428             : 
    1429             : 
    1430             :   // Prepare the newly created mesh for use.
    1431        2272 :   mesh.prepare_for_use();
    1432             : 
    1433             :   // Let the new_elements and new_bndry_elements vectors go out of scope.
    1434        2540 : }
    1435             : 
    1436             : 
    1437           0 : void MeshTools::Modification::smooth (MeshBase & mesh,
    1438             :                                       const unsigned int n_iterations,
    1439             :                                       const Real power)
    1440             : {
    1441             :   /**
    1442             :    * This implementation assumes every element "side" has only 2 nodes.
    1443             :    */
    1444           0 :   libmesh_assert_equal_to (mesh.mesh_dimension(), 2);
    1445             : 
    1446             :   /*
    1447             :    * Create a quickly-searchable list of boundary nodes.
    1448             :    */
    1449             :   std::unordered_set<dof_id_type> boundary_node_ids =
    1450           0 :     MeshTools::find_boundary_nodes (mesh);
    1451             : 
    1452             :   // For avoiding extraneous element side allocation
    1453           0 :   ElemSideBuilder side_builder;
    1454             : 
    1455           0 :   for (unsigned int iter=0; iter<n_iterations; iter++)
    1456             :     {
    1457             :       /*
    1458             :        * loop over the mesh refinement level
    1459             :        */
    1460           0 :       unsigned int n_levels = MeshTools::n_levels(mesh);
    1461           0 :       for (unsigned int refinement_level=0; refinement_level != n_levels;
    1462             :            refinement_level++)
    1463             :         {
    1464             :           // initialize the storage (have to do it on every level to get empty vectors
    1465           0 :           std::vector<Point> new_positions;
    1466           0 :           std::vector<Real>   weight;
    1467           0 :           new_positions.resize(mesh.n_nodes());
    1468           0 :           weight.resize(mesh.n_nodes());
    1469             : 
    1470             :           {
    1471             :             // Loop over the elements to calculate new node positions
    1472           0 :             for (const auto & elem : as_range(mesh.level_elements_begin(refinement_level),
    1473           0 :                                               mesh.level_elements_end(refinement_level)))
    1474             :               {
    1475             :                 /*
    1476             :                  * We relax all nodes on level 0 first
    1477             :                  * If the element is refined (level > 0), we interpolate the
    1478             :                  * parents nodes with help of the embedding matrix
    1479             :                  */
    1480           0 :                 if (refinement_level == 0)
    1481             :                   {
    1482           0 :                     for (auto s : elem->side_index_range())
    1483             :                       {
    1484             :                         /*
    1485             :                          * Only operate on sides which are on the
    1486             :                          * boundary or for which the current element's
    1487             :                          * id is greater than its neighbor's.
    1488             :                          * Sides get only built once.
    1489             :                          */
    1490           0 :                         if ((elem->neighbor_ptr(s) != nullptr) &&
    1491           0 :                             (elem->id() > elem->neighbor_ptr(s)->id()))
    1492             :                           {
    1493           0 :                             const Elem & side = side_builder(*elem, s);
    1494           0 :                             const Node & node0 = side.node_ref(0);
    1495           0 :                             const Node & node1 = side.node_ref(1);
    1496             : 
    1497           0 :                             Real node_weight = 1.;
    1498             :                             // calculate the weight of the nodes
    1499           0 :                             if (power > 0)
    1500             :                               {
    1501           0 :                                 Point diff = node0-node1;
    1502           0 :                                 node_weight = std::pow(diff.norm(), power);
    1503             :                               }
    1504             : 
    1505           0 :                             const dof_id_type id0 = node0.id(), id1 = node1.id();
    1506           0 :                             new_positions[id0].add_scaled( node1, node_weight );
    1507           0 :                             new_positions[id1].add_scaled( node0, node_weight );
    1508           0 :                             weight[id0] += node_weight;
    1509           0 :                             weight[id1] += node_weight;
    1510             :                           }
    1511             :                       } // element neighbor loop
    1512             :                   }
    1513             : #ifdef LIBMESH_ENABLE_AMR
    1514             :                 else   // refinement_level > 0
    1515             :                   {
    1516             :                     /*
    1517             :                      * Find the positions of the hanging nodes of refined elements.
    1518             :                      * We do this by calculating their position based on the parent
    1519             :                      * (one level less refined) element, and the embedding matrix
    1520             :                      */
    1521             : 
    1522           0 :                     const Elem * parent = elem->parent();
    1523             : 
    1524             :                     /*
    1525             :                      * find out which child I am
    1526             :                      */
    1527           0 :                     unsigned int c = parent->which_child_am_i(elem);
    1528             :                     /*
    1529             :                      *loop over the childs (that is, the current elements) nodes
    1530             :                      */
    1531           0 :                     for (auto nc : elem->node_index_range())
    1532             :                       {
    1533             :                         /*
    1534             :                          * the new position of the node
    1535             :                          */
    1536           0 :                         Point point;
    1537           0 :                         for (auto n : parent->node_index_range())
    1538             :                           {
    1539             :                             /*
    1540             :                              * The value from the embedding matrix
    1541             :                              */
    1542           0 :                             const Real em_val = parent->embedding_matrix(c,nc,n);
    1543             : 
    1544           0 :                             if (em_val != 0.)
    1545           0 :                               point.add_scaled (parent->point(n), em_val);
    1546             :                           }
    1547             : 
    1548           0 :                         const dof_id_type id = elem->node_ptr(nc)->id();
    1549           0 :                         new_positions[id] = point;
    1550           0 :                         weight[id] = 1.;
    1551             :                       }
    1552             :                   } // if element refinement_level
    1553             : #endif // #ifdef LIBMESH_ENABLE_AMR
    1554             : 
    1555           0 :               } // element loop
    1556             : 
    1557             :             /*
    1558             :              * finally reposition the vertex nodes
    1559             :              */
    1560           0 :             for (auto nid : make_range(mesh.n_nodes()))
    1561           0 :               if (!boundary_node_ids.count(nid) && weight[nid] > 0.)
    1562           0 :                 mesh.node_ref(nid) = new_positions[nid]/weight[nid];
    1563             :           }
    1564             : 
    1565             :           // Now handle the additional second_order nodes by calculating
    1566             :           // their position based on the vertex positions
    1567             :           // we do a second loop over the level elements
    1568           0 :           for (auto & elem : as_range(mesh.level_elements_begin(refinement_level),
    1569           0 :                                       mesh.level_elements_end(refinement_level)))
    1570             :             {
    1571           0 :               const unsigned int son_begin = elem->n_vertices();
    1572           0 :               const unsigned int son_end   = elem->n_nodes();
    1573           0 :               for (unsigned int n=son_begin; n<son_end; n++)
    1574             :                 {
    1575             :                   const unsigned int n_adjacent_vertices =
    1576           0 :                     elem->n_second_order_adjacent_vertices(n);
    1577             : 
    1578           0 :                   Point point;
    1579           0 :                   for (unsigned int v=0; v<n_adjacent_vertices; v++)
    1580           0 :                     point.add(elem->point( elem->second_order_adjacent_vertex(n,v) ));
    1581             : 
    1582           0 :                   const dof_id_type id = elem->node_ptr(n)->id();
    1583           0 :                   mesh.node_ref(id) = point/n_adjacent_vertices;
    1584             :                 }
    1585           0 :             }
    1586             :         } // refinement_level loop
    1587             :     } // end iteration
    1588           0 : }
    1589             : 
    1590             : 
    1591             : 
    1592             : #ifdef LIBMESH_ENABLE_AMR
    1593        1145 : void MeshTools::Modification::flatten(MeshBase & mesh)
    1594             : {
    1595          36 :   libmesh_assert(mesh.is_prepared() || mesh.is_replicated());
    1596             : 
    1597             :   // Algorithm:
    1598             :   // .) For each active element in the mesh: construct a
    1599             :   //    copy which is the same in every way *except* it is
    1600             :   //    a level 0 element.  Store the pointers to these in
    1601             :   //    a separate vector. Save any boundary information as well.
    1602             :   //    Delete the active element from the mesh.
    1603             :   // .) Loop over all (remaining) elements in the mesh, delete them.
    1604             :   // .) Add the level-0 copies back to the mesh
    1605             : 
    1606             :   // Temporary storage for new element pointers
    1607         108 :   std::vector<std::unique_ptr<Elem>> new_elements;
    1608             : 
    1609             :   // BoundaryInfo Storage for element ids, sides, and BC ids
    1610          72 :   std::vector<Elem *>              saved_boundary_elements;
    1611          72 :   std::vector<boundary_id_type>   saved_bc_ids;
    1612          72 :   std::vector<unsigned short int> saved_bc_sides;
    1613             : 
    1614             :   // Container to catch boundary ids passed back by BoundaryInfo
    1615          72 :   std::vector<boundary_id_type> bc_ids;
    1616             : 
    1617             :   // Reserve a reasonable amt. of space for each
    1618        1145 :   new_elements.reserve(mesh.n_active_elem());
    1619        1145 :   saved_boundary_elements.reserve(mesh.get_boundary_info().n_boundary_conds());
    1620        1145 :   saved_bc_ids.reserve(mesh.get_boundary_info().n_boundary_conds());
    1621        1145 :   saved_bc_sides.reserve(mesh.get_boundary_info().n_boundary_conds());
    1622             : 
    1623      329648 :   for (auto & elem : mesh.active_element_ptr_range())
    1624             :     {
    1625             :       // Make a new element of the same type
    1626      177481 :       auto copy = Elem::build(elem->type());
    1627             : 
    1628             :       // Set node pointers (they still point to nodes in the original mesh)
    1629     1374787 :       for (auto n : elem->node_index_range())
    1630     1247032 :         copy->set_node(n, elem->node_ptr(n));
    1631             : 
    1632             :       // Copy over ids
    1633      170589 :       copy->processor_id() = elem->processor_id();
    1634      170589 :       copy->subdomain_id() = elem->subdomain_id();
    1635             : 
    1636             :       // Retain the original element's ID(s) as well, otherwise
    1637             :       // the Mesh may try to create them for you...
    1638       13784 :       copy->set_id( elem->id() );
    1639             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1640       13784 :       copy->set_unique_id(elem->unique_id());
    1641             : #endif
    1642             : 
    1643             :       // This element could have boundary info or DistributedMesh
    1644             :       // remote_elem links as well.  We need to save the (elem,
    1645             :       // side, bc_id) triples and those links
    1646     1098669 :       for (auto s : elem->side_index_range())
    1647             :         {
    1648      966376 :           if (elem->neighbor_ptr(s) == remote_elem)
    1649         744 :             copy->set_neighbor(s, const_cast<RemoteElem *>(remote_elem));
    1650             : 
    1651      928080 :           mesh.get_boundary_info().boundary_ids(elem, s, bc_ids);
    1652      928414 :           for (const auto & bc_id : bc_ids)
    1653         334 :             if (bc_id != BoundaryInfo::invalid_id)
    1654             :               {
    1655         334 :                 saved_boundary_elements.push_back(copy.get());
    1656         334 :                 saved_bc_ids.push_back(bc_id);
    1657         334 :                 saved_bc_sides.push_back(s);
    1658             :               }
    1659             :         }
    1660             : 
    1661             :       // Copy any extra element data.  Since the copy hasn't been
    1662             :       // added to the mesh yet any allocation has to be done manually.
    1663      170589 :       const unsigned int nei = elem->n_extra_integers();
    1664      170589 :       copy->add_extra_integers(nei);
    1665      170589 :       for (unsigned int i=0; i != nei; ++i)
    1666           0 :         copy->set_extra_integer(i, elem->get_extra_integer(i));
    1667             : 
    1668             :       // Copy any mapping data.
    1669      170589 :       copy->set_mapping_type(elem->mapping_type());
    1670       13784 :       copy->set_mapping_data(elem->mapping_data());
    1671             : 
    1672             :       // We're done with this element
    1673      170589 :       mesh.delete_elem(elem);
    1674             : 
    1675             :       // But save the copy
    1676        6892 :       new_elements.push_back(std::move(copy));
    1677      157878 :     }
    1678             : 
    1679             :   // Make sure we saved the same number of boundary conditions
    1680             :   // in each vector.
    1681          36 :   libmesh_assert_equal_to (saved_boundary_elements.size(), saved_bc_ids.size());
    1682          36 :   libmesh_assert_equal_to (saved_bc_ids.size(), saved_bc_sides.size());
    1683             : 
    1684             :   // Loop again, delete any remaining elements
    1685       71004 :   for (auto & elem : mesh.element_ptr_range())
    1686       36722 :     mesh.delete_elem(elem);
    1687             : 
    1688             :   // Add the copied (now level-0) elements back to the mesh
    1689      171734 :   for (auto & new_elem : new_elements)
    1690             :     {
    1691             :       // Save the original ID, because the act of adding the Elem can
    1692             :       // change new_elem's id!
    1693        6892 :       dof_id_type orig_id = new_elem->id();
    1694             : 
    1695      184373 :       Elem * added_elem = mesh.add_elem(std::move(new_elem));
    1696             : 
    1697             :       // If the Elem, as it was re-added to the mesh, now has a
    1698             :       // different ID (this is unlikely, so it's just an assert)
    1699             :       // the boundary information will no longer be correct.
    1700        6892 :       libmesh_assert_equal_to (orig_id, added_elem->id());
    1701             : 
    1702             :       // Avoid compiler warnings in opt mode.
    1703        6892 :       libmesh_ignore(added_elem, orig_id);
    1704             :     }
    1705             : 
    1706             :   // Finally, also add back the saved boundary information
    1707        1479 :   for (auto e : index_range(saved_boundary_elements))
    1708         358 :     mesh.get_boundary_info().add_side(saved_boundary_elements[e],
    1709          24 :                                       saved_bc_sides[e],
    1710          24 :                                       saved_bc_ids[e]);
    1711             : 
    1712             :   // Trim unused and renumber nodes and elements
    1713        1145 :   mesh.prepare_for_use();
    1714        1145 : }
    1715             : #endif // #ifdef LIBMESH_ENABLE_AMR
    1716             : 
    1717             : 
    1718             : 
    1719        3408 : void MeshTools::Modification::change_boundary_id (MeshBase & mesh,
    1720             :                                                   const boundary_id_type old_id,
    1721             :                                                   const boundary_id_type new_id)
    1722             : {
    1723             :   // This is just a shim around the member implementation, now
    1724        3408 :   mesh.get_boundary_info().renumber_id(old_id, new_id);
    1725        3408 : }
    1726             : 
    1727             : 
    1728             : 
    1729           0 : void MeshTools::Modification::change_subdomain_id (MeshBase & mesh,
    1730             :                                                    const subdomain_id_type old_id,
    1731             :                                                    const subdomain_id_type new_id)
    1732             : {
    1733           0 :   if (old_id == new_id)
    1734             :     {
    1735             :       // If the IDs are the same, this is a no-op.
    1736           0 :       return;
    1737             :     }
    1738             : 
    1739           0 :   for (auto & elem : mesh.element_ptr_range())
    1740             :     {
    1741           0 :       if (elem->subdomain_id() == old_id)
    1742           0 :         elem->subdomain_id() = new_id;
    1743           0 :     }
    1744             : }
    1745             : 
    1746             : 
    1747             : } // namespace libMesh

Generated by: LCOV version 1.14