LCOV - code coverage report
Current view: top level - src/mesh - mesh_generation.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 997 1306 76.3 %
Date: 2025-08-19 19:27:09 Functions: 15 23 65.2 %
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             : // libmesh includes
      21             : #include "libmesh/mesh_generation.h"
      22             : #include "libmesh/unstructured_mesh.h"
      23             : #include "libmesh/mesh_refinement.h"
      24             : #include "libmesh/edge_edge2.h"
      25             : #include "libmesh/edge_edge3.h"
      26             : #include "libmesh/edge_edge4.h"
      27             : #include "libmesh/face_tri3.h"
      28             : #include "libmesh/face_tri6.h"
      29             : #include "libmesh/face_tri7.h"
      30             : #include "libmesh/face_quad4.h"
      31             : #include "libmesh/face_quad8.h"
      32             : #include "libmesh/face_quad9.h"
      33             : #include "libmesh/cell_hex8.h"
      34             : #include "libmesh/cell_hex20.h"
      35             : #include "libmesh/cell_hex27.h"
      36             : #include "libmesh/cell_prism6.h"
      37             : #include "libmesh/cell_prism15.h"
      38             : #include "libmesh/cell_prism18.h"
      39             : #include "libmesh/cell_prism20.h"
      40             : #include "libmesh/cell_prism21.h"
      41             : #include "libmesh/cell_tet4.h"
      42             : #include "libmesh/cell_pyramid5.h"
      43             : #include "libmesh/libmesh_logging.h"
      44             : #include "libmesh/boundary_info.h"
      45             : #include "libmesh/remote_elem.h"
      46             : #include "libmesh/sphere.h"
      47             : #include "libmesh/mesh_modification.h"
      48             : #include "libmesh/mesh_smoother_laplace.h"
      49             : #include "libmesh/node_elem.h"
      50             : #include "libmesh/vector_value.h"
      51             : #include "libmesh/function_base.h"
      52             : #include "libmesh/enum_order.h"
      53             : #include "libmesh/int_range.h"
      54             : #include "libmesh/parallel.h"
      55             : #include "libmesh/parallel_ghost_sync.h"
      56             : #include "libmesh/enum_to_string.h"
      57             : 
      58             : // C++ includes
      59             : #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
      60             : #include <cmath> // for std::sqrt
      61             : #include <unordered_set>
      62             : 
      63             : 
      64             : namespace libMesh
      65             : {
      66             : 
      67             : namespace MeshTools {
      68             : namespace Generation {
      69             : namespace Private {
      70             : /**
      71             :  * A useful inline function which replaces the macros
      72             :  * used previously.  Not private since this is a namespace,
      73             :  * but would be if this were a class.  The first one returns
      74             :  * the proper node number for 2D elements while the second
      75             :  * one returns the node number for 3D elements.
      76             :  */
      77             : inline
      78    16996803 : unsigned int idx(const ElemType type,
      79             :                  const unsigned int nx,
      80             :                  const unsigned int i,
      81             :                  const unsigned int j)
      82             : {
      83    16520583 :   switch(type)
      84             :     {
      85     3388676 :     case INVALID_ELEM:
      86             :     case QUAD4:
      87             :     case QUADSHELL4:
      88             :     case TRI3:
      89             :     case TRISHELL3:
      90             :       {
      91     3388676 :         return i + j*(nx+1);
      92             :       }
      93             : 
      94    13608127 :     case QUAD8:
      95             :     case QUADSHELL8:
      96             :     case QUAD9:
      97             :     case QUADSHELL9:
      98             :     case TRI6:
      99             :     case TRI7:
     100             :       {
     101    13608127 :         return i + j*(2*nx+1);
     102             :       }
     103             : 
     104           0 :     default:
     105           0 :       libmesh_error_msg("ERROR: Unrecognized 2D element type == " << Utility::enum_to_string(type));
     106             :     }
     107             : 
     108             :   return libMesh::invalid_uint;
     109             : }
     110             : 
     111             : 
     112             : 
     113             : // Same as the function above, but for 3D elements
     114             : inline
     115    44393205 : unsigned int idx(const ElemType type,
     116             :                  const unsigned int nx,
     117             :                  const unsigned int ny,
     118             :                  const unsigned int i,
     119             :                  const unsigned int j,
     120             :                  const unsigned int k)
     121             : {
     122    43134615 :   switch(type)
     123             :     {
     124     8530164 :     case INVALID_ELEM:
     125             :     case HEX8:
     126             :     case PRISM6:
     127             :       {
     128     8530164 :         return i + (nx+1)*(j + k*(ny+1));
     129             :       }
     130             : 
     131    35863041 :     case HEX20:
     132             :     case HEX27:
     133             :     case TET4:  // TET4's are created from an initial HEX27 discretization
     134             :     case TET10: // TET10's are created from an initial HEX27 discretization
     135             :     case TET14: // TET14's are created from an initial HEX27 discretization
     136             :     case PYRAMID5: // PYRAMID5's are created from an initial HEX27 discretization
     137             :     case PYRAMID13:
     138             :     case PYRAMID14:
     139             :     case PYRAMID18:
     140             :     case PRISM15:
     141             :     case PRISM18:
     142             :     case PRISM20:
     143             :     case PRISM21:
     144             :       {
     145    35863041 :         return i + (2*nx+1)*(j + k*(2*ny+1));
     146             :       }
     147             : 
     148           0 :     default:
     149           0 :       libmesh_error_msg("ERROR: Unrecognized element type == " << Utility::enum_to_string(type));
     150             :     }
     151             : 
     152             :   return libMesh::invalid_uint;
     153             : }
     154             : 
     155             : 
     156             : /**
     157             :  * This object is passed to MeshTools::Modification::redistribute() to
     158             :  * redistribute the points on a uniform grid into the Gauss-Lobatto
     159             :  * points on the actual grid.
     160             :  */
     161             : class GaussLobattoRedistributionFunction : public FunctionBase<Real>
     162             : {
     163             : public:
     164             :   /**
     165             :    * Constructor.
     166             :    */
     167           0 :   GaussLobattoRedistributionFunction(unsigned int nx,
     168             :                                      Real xmin,
     169             :                                      Real xmax,
     170             :                                      unsigned int ny=0,
     171             :                                      Real ymin=0,
     172             :                                      Real ymax=0,
     173             :                                      unsigned int nz=0,
     174             :                                      Real zmin=0,
     175           0 :                                      Real zmax=0) :
     176           0 :     FunctionBase<Real>(nullptr)
     177             :   {
     178           0 :     _nelem.resize(3);
     179           0 :     _nelem[0] = nx;
     180           0 :     _nelem[1] = ny;
     181           0 :     _nelem[2] = nz;
     182             : 
     183           0 :     _mins.resize(3);
     184           0 :     _mins[0] = xmin;
     185           0 :     _mins[1] = ymin;
     186           0 :     _mins[2] = zmin;
     187             : 
     188           0 :     _widths.resize(3);
     189           0 :     _widths[0] = xmax - xmin;
     190           0 :     _widths[1] = ymax - ymin;
     191           0 :     _widths[2] = zmax - zmin;
     192             : 
     193             :     // Precompute the cosine values.
     194           0 :     _cosines.resize(3);
     195           0 :     for (unsigned dir=0; dir<3; ++dir)
     196           0 :       if (_nelem[dir] != 0)
     197             :         {
     198           0 :           _cosines[dir].resize(_nelem[dir]+1);
     199           0 :           for (auto i : index_range(_cosines[dir]))
     200           0 :             _cosines[dir][i] = std::cos(libMesh::pi * Real(i) / _nelem[dir]);
     201             :         }
     202           0 :   }
     203             : 
     204             :   /**
     205             :    * The 5 special functions can be defaulted for this class.
     206             :    */
     207             :   GaussLobattoRedistributionFunction (GaussLobattoRedistributionFunction &&) = default;
     208           0 :   GaussLobattoRedistributionFunction (const GaussLobattoRedistributionFunction &) = default;
     209             :   GaussLobattoRedistributionFunction & operator= (const GaussLobattoRedistributionFunction &) = default;
     210             :   GaussLobattoRedistributionFunction & operator= (GaussLobattoRedistributionFunction &&) = default;
     211           0 :   virtual ~GaussLobattoRedistributionFunction () = default;
     212             : 
     213             :   /**
     214             :    * We must provide a way to clone ourselves to satisfy the pure
     215             :    * virtual interface.  We use the autogenerated copy constructor.
     216             :    */
     217           0 :   virtual std::unique_ptr<FunctionBase<Real>> clone () const override
     218             :   {
     219           0 :     return std::make_unique<GaussLobattoRedistributionFunction>(*this);
     220             :   }
     221             : 
     222             :   /**
     223             :    * This is the actual function that
     224             :    * MeshTools::Modification::redistribute() calls.  Moves the points
     225             :    * of the grid to the Gauss-Lobatto points.
     226             :    */
     227           0 :   virtual void operator() (const Point & p,
     228             :                            const Real /*time*/,
     229             :                            DenseVector<Real> & output) override
     230             :   {
     231           0 :     output.resize(3);
     232             : 
     233           0 :     for (unsigned dir=0; dir<3; ++dir)
     234           0 :       if (_nelem[dir] != 0)
     235             :         {
     236             :           // Figure out the index of the current point.
     237           0 :           Real float_index = (p(dir) - _mins[dir]) * _nelem[dir] / _widths[dir];
     238             : 
     239             :           // std::modf separates the fractional and integer parts of the index.
     240           0 :           Real integer_part_f = 0;
     241           0 :           const Real fractional_part = std::modf(float_index, &integer_part_f);
     242             : 
     243           0 :           const int integer_part = int(integer_part_f);
     244             : 
     245             :           // Vertex node?
     246           0 :           if (std::abs(fractional_part) < TOLERANCE || std::abs(fractional_part - 1.0) < TOLERANCE)
     247             :             {
     248           0 :               int index = int(round(float_index));
     249             : 
     250             :               // Move node to the Gauss-Lobatto position.
     251           0 :               output(dir) = _mins[dir] + _widths[dir] * 0.5 * (1.0 - _cosines[dir][index]);
     252             :             }
     253             : 
     254             :           // Mid-edge (quadratic) node?
     255           0 :           else if (std::abs(fractional_part - 0.5) < TOLERANCE)
     256             :             {
     257             :               // Move node to the Gauss-Lobatto position, which is the average of
     258             :               // the node to the left and the node to the right.
     259           0 :               output(dir) = _mins[dir] + _widths[dir] * 0.5 *
     260           0 :                 (1.0 - 0.5*(_cosines[dir][integer_part] + _cosines[dir][integer_part+1]));
     261             :             }
     262             : 
     263             :           // 1D only: Left interior (cubic) node?
     264           0 :           else if (std::abs(fractional_part - 1./3.) < TOLERANCE)
     265             :             {
     266             :               // Move node to the Gauss-Lobatto position, which is
     267             :               // 2/3*left_vertex + 1/3*right_vertex.
     268           0 :               output(dir) = _mins[dir] + _widths[dir] * 0.5 *
     269           0 :                 (1.0 - 2./3.*_cosines[dir][integer_part] - 1./3.*_cosines[dir][integer_part+1]);
     270             :             }
     271             : 
     272             :           // 1D only: Right interior (cubic) node?
     273           0 :           else if (std::abs(fractional_part - 2./3.) < TOLERANCE)
     274             :             {
     275             :               // Move node to the Gauss-Lobatto position, which is
     276             :               // 1/3*left_vertex + 2/3*right_vertex.
     277           0 :               output(dir) = _mins[dir] + _widths[dir] * 0.5 *
     278           0 :                 (1.0 - 1./3.*_cosines[dir][integer_part] - 2./3.*_cosines[dir][integer_part+1]);
     279             :             }
     280             : 
     281             :           else
     282           0 :             libmesh_error_msg("Cannot redistribute node: " << p);
     283             :         }
     284           0 :   }
     285             : 
     286             :   /**
     287             :    * We must also override operator() which returns a Real, but this function
     288             :    * should never be called, so it's left unimplemented.
     289             :    */
     290           0 :   virtual Real operator() (const Point & /*p*/,
     291             :                            const Real /*time*/) override
     292             :   {
     293           0 :     libmesh_not_implemented();
     294             :   }
     295             : 
     296             : protected:
     297             :   // Stored data
     298             :   std::vector<Real> _mins;
     299             :   std::vector<unsigned int> _nelem;
     300             :   std::vector<Real> _widths;
     301             : 
     302             :   // Precomputed values
     303             :   std::vector<std::vector<Real>> _cosines;
     304             : };
     305             : 
     306             : 
     307             : } // namespace Private
     308             : } // namespace Generation
     309             : } // namespace MeshTools
     310             : 
     311             : // ------------------------------------------------------------
     312             : // MeshTools::Generation function for mesh generation
     313      265006 : void MeshTools::Generation::build_cube(UnstructuredMesh & mesh,
     314             :                                        const unsigned int nx,
     315             :                                        const unsigned int ny,
     316             :                                        const unsigned int nz,
     317             :                                        const Real xmin, const Real xmax,
     318             :                                        const Real ymin, const Real ymax,
     319             :                                        const Real zmin, const Real zmax,
     320             :                                        const ElemType type,
     321             :                                        const bool gauss_lobatto_grid)
     322             : {
     323       15000 :   LOG_SCOPE("build_cube()", "MeshTools::Generation");
     324             : 
     325             :   // Declare that we are using the indexing utility routine
     326             :   // in the "Private" part of our current namespace.  If this doesn't
     327             :   // work in GCC 2.95.3 we can either remove it or stop supporting
     328             :   // 2.95.3 altogether.
     329             :   // Changing this to import the whole namespace... just importing idx
     330             :   // causes an internal compiler error for Intel Compiler 11.0 on Linux
     331             :   // in debug mode.
     332             :   using namespace MeshTools::Generation::Private;
     333             : 
     334             :   // Clear the mesh and start from scratch
     335      265006 :   mesh.clear();
     336             : 
     337        7500 :   BoundaryInfo & boundary_info = mesh.get_boundary_info();
     338             : 
     339      265006 :   if (nz != 0)
     340             :     {
     341      122695 :       mesh.set_mesh_dimension(3);
     342      122695 :       mesh.set_spatial_dimension(3);
     343             :     }
     344      142311 :   else if (ny != 0)
     345             :     {
     346      106324 :       mesh.set_mesh_dimension(2);
     347      106324 :       mesh.set_spatial_dimension(2);
     348             :     }
     349       35987 :   else if (nx != 0)
     350             :     {
     351       33786 :       mesh.set_mesh_dimension(1);
     352       33786 :       mesh.set_spatial_dimension(1);
     353             :     }
     354             :   else
     355             :     {
     356             :       // Will we get here?
     357        2201 :       mesh.set_mesh_dimension(0);
     358        2201 :       mesh.set_spatial_dimension(0);
     359             :     }
     360             : 
     361      265006 :   switch (mesh.mesh_dimension())
     362             :     {
     363             :       //---------------------------------------------------------------------
     364             :       // Build a 0D point
     365        2201 :     case 0:
     366             :       {
     367          62 :         libmesh_assert_equal_to (nx, 0);
     368          62 :         libmesh_assert_equal_to (ny, 0);
     369          62 :         libmesh_assert_equal_to (nz, 0);
     370             : 
     371          62 :         libmesh_assert (type == INVALID_ELEM || type == NODEELEM);
     372             : 
     373             :         // Build one nodal element for the mesh
     374        2263 :         mesh.add_point (Point(0, 0, 0), 0);
     375        2201 :         Elem * elem = mesh.add_elem(Elem::build(NODEELEM));
     376        2201 :         elem->set_node(0, mesh.node_ptr(0));
     377             : 
     378        2139 :         break;
     379             :       }
     380             : 
     381             : 
     382             : 
     383             :       //---------------------------------------------------------------------
     384             :       // Build a 1D line
     385       33786 :     case 1:
     386             :       {
     387         952 :         libmesh_assert_not_equal_to (nx, 0);
     388         952 :         libmesh_assert_equal_to (ny, 0);
     389         952 :         libmesh_assert_equal_to (nz, 0);
     390         952 :         libmesh_assert_less (xmin, xmax);
     391             : 
     392             :         // Reserve elements
     393             :         switch (type)
     394             :           {
     395       33786 :           case INVALID_ELEM:
     396             :           case EDGE2:
     397             :           case EDGE3:
     398             :           case EDGE4:
     399             :             {
     400       33786 :               mesh.reserve_elem (nx);
     401         952 :               break;
     402             :             }
     403             : 
     404           0 :           default:
     405           0 :             libmesh_error_msg("ERROR: Unrecognized 1D element type == " << Utility::enum_to_string(type));
     406             :           }
     407             : 
     408             :         // Reserve nodes
     409             :         switch (type)
     410             :           {
     411       11070 :           case INVALID_ELEM:
     412             :           case EDGE2:
     413             :             {
     414       11070 :               mesh.reserve_nodes(nx+1);
     415       10758 :               break;
     416             :             }
     417             : 
     418       20941 :           case EDGE3:
     419             :             {
     420       20941 :               mesh.reserve_nodes(2*nx+1);
     421       20351 :               break;
     422             :             }
     423             : 
     424        1775 :           case EDGE4:
     425             :             {
     426        1775 :               mesh.reserve_nodes(3*nx+1);
     427        1725 :               break;
     428             :             }
     429             : 
     430           0 :           default:
     431           0 :             libmesh_error_msg("ERROR: Unrecognized 1D element type == " << Utility::enum_to_string(type));
     432             :           }
     433             : 
     434             : 
     435             :         // Build the nodes, depends on whether we're using linears,
     436             :         // quadratics or cubics and whether using uniform grid or Gauss-Lobatto
     437         952 :         unsigned int node_id = 0;
     438             :         switch(type)
     439             :           {
     440         312 :           case INVALID_ELEM:
     441             :           case EDGE2:
     442             :             {
     443      331394 :               for (unsigned int i=0; i<=nx; i++)
     444             :               {
     445      329464 :                 const Node * const node = mesh.add_point (Point(static_cast<Real>(i)/nx, 0, 0), node_id++);
     446      320324 :                 if (i == 0)
     447       11070 :                   boundary_info.add_node(node, 0);
     448      320324 :                 if (i == nx)
     449       11070 :                   boundary_info.add_node(node, 1);
     450             :               }
     451             : 
     452         312 :               break;
     453             :             }
     454             : 
     455         590 :           case EDGE3:
     456             :             {
     457      111808 :               for (unsigned int i=0; i<=2*nx; i++)
     458             :               {
     459       93429 :                 const Node * const node = mesh.add_point (Point(static_cast<Real>(i)/(2*nx), 0, 0), node_id++);
     460       90867 :                 if (i == 0)
     461       20941 :                   boundary_info.add_node(node, 0);
     462       90867 :                 if (i == 2*nx)
     463       20941 :                   boundary_info.add_node(node, 1);
     464             :               }
     465         590 :               break;
     466             :             }
     467             : 
     468          50 :           case EDGE4:
     469             :             {
     470       18673 :               for (unsigned int i=0; i<=3*nx; i++)
     471             :               {
     472       17374 :                 const Node * const node = mesh.add_point (Point(static_cast<Real>(i)/(3*nx), 0, 0), node_id++);
     473       16898 :                 if (i == 0)
     474        1775 :                   boundary_info.add_node(node, 0);
     475       16898 :                 if (i == 3*nx)
     476        1775 :                   boundary_info.add_node(node, 1);
     477             :               }
     478             : 
     479          50 :               break;
     480             :             }
     481             : 
     482           0 :           default:
     483           0 :             libmesh_error_msg("ERROR: Unrecognized 1D element type == " << Utility::enum_to_string(type));
     484             : 
     485             :           }
     486             : 
     487             :         // Build the elements of the mesh
     488             :         switch(type)
     489             :           {
     490         312 :           case INVALID_ELEM:
     491             :           case EDGE2:
     492             :             {
     493      320324 :               for (unsigned int i=0; i<nx; i++)
     494             :                 {
     495      309254 :                   Elem * elem = mesh.add_elem(Elem::build_with_id(EDGE2, i));
     496      309254 :                   elem->set_node(0, mesh.node_ptr(i));
     497      309254 :                   elem->set_node(1, mesh.node_ptr(i+1));
     498             : 
     499      309254 :                   if (i == 0)
     500       11070 :                     boundary_info.add_side(elem, 0, 0);
     501             : 
     502      309254 :                   if (i == (nx-1))
     503       11070 :                     boundary_info.add_side(elem, 1, 1);
     504             : 
     505             :                 }
     506         312 :               break;
     507             :             }
     508             : 
     509         590 :           case EDGE3:
     510             :             {
     511       55904 :               for (unsigned int i=0; i<nx; i++)
     512             :                 {
     513       34963 :                   Elem * elem = mesh.add_elem(Elem::build_with_id(EDGE3, i));
     514       34963 :                   elem->set_node(0, mesh.node_ptr(2*i));
     515       34963 :                   elem->set_node(2, mesh.node_ptr(2*i+1));
     516       34963 :                   elem->set_node(1, mesh.node_ptr(2*i+2));
     517             : 
     518       34963 :                   if (i == 0)
     519       20941 :                     boundary_info.add_side(elem, 0, 0);
     520             : 
     521       34963 :                   if (i == (nx-1))
     522       20941 :                     boundary_info.add_side(elem, 1, 1);
     523             :                 }
     524         590 :               break;
     525             :             }
     526             : 
     527          50 :           case EDGE4:
     528             :             {
     529        6816 :               for (unsigned int i=0; i<nx; i++)
     530             :                 {
     531        5041 :                   Elem * elem = mesh.add_elem(Elem::build_with_id(EDGE4, i));
     532        5041 :                   elem->set_node(0, mesh.node_ptr(3*i));
     533        5041 :                   elem->set_node(2, mesh.node_ptr(3*i+1));
     534        5041 :                   elem->set_node(3, mesh.node_ptr(3*i+2));
     535        5041 :                   elem->set_node(1, mesh.node_ptr(3*i+3));
     536             : 
     537        5041 :                   if (i == 0)
     538        1775 :                     boundary_info.add_side(elem, 0, 0);
     539             : 
     540        5041 :                   if (i == (nx-1))
     541        1775 :                     boundary_info.add_side(elem, 1, 1);
     542             :                 }
     543          50 :               break;
     544             :             }
     545             : 
     546           0 :           default:
     547           0 :             libmesh_error_msg("ERROR: Unrecognized 1D element type == " << Utility::enum_to_string(type));
     548             :           }
     549             : 
     550             :         // Move the nodes to their final locations.
     551       33786 :         if (gauss_lobatto_grid)
     552             :           {
     553           0 :             GaussLobattoRedistributionFunction func(nx, xmin, xmax);
     554           0 :             MeshTools::Modification::redistribute(mesh, func);
     555           0 :           }
     556             :         else // !gauss_lobatto_grid
     557             :           {
     558      494709 :             for (Node * node : mesh.node_ptr_range())
     559      459971 :               (*node)(0) = (*node)(0)*(xmax-xmin) + xmin;
     560             :           }
     561             : 
     562             :         // Add sideset names to boundary info
     563       33786 :         boundary_info.sideset_name(0) = "left";
     564       33786 :         boundary_info.sideset_name(1) = "right";
     565             : 
     566             :         // Add nodeset names to boundary info
     567       33786 :         boundary_info.nodeset_name(0) = "left";
     568       33786 :         boundary_info.nodeset_name(1) = "right";
     569             : 
     570         952 :         break;
     571             :       }
     572             : 
     573             : 
     574             : 
     575             : 
     576             : 
     577             : 
     578             : 
     579             : 
     580             : 
     581             : 
     582             :       //---------------------------------------------------------------------
     583             :       // Build a 2D quadrilateral
     584      106324 :     case 2:
     585             :       {
     586        2998 :         libmesh_assert_not_equal_to (nx, 0);
     587        2998 :         libmesh_assert_not_equal_to (ny, 0);
     588        2998 :         libmesh_assert_equal_to (nz, 0);
     589        2998 :         libmesh_assert_less (xmin, xmax);
     590        2998 :         libmesh_assert_less (ymin, ymax);
     591             : 
     592             :         // Reserve elements.  The TRI3 and TRI6 meshes
     593             :         // have twice as many elements...
     594             :         switch (type)
     595             :           {
     596       52941 :           case INVALID_ELEM:
     597             :           case QUAD4:
     598             :           case QUADSHELL4:
     599             :           case QUAD8:
     600             :           case QUADSHELL8:
     601             :           case QUAD9:
     602             :           case QUADSHELL9:
     603             :             {
     604       52941 :               mesh.reserve_elem (nx*ny);
     605       51447 :               break;
     606             :             }
     607             : 
     608       53383 :           case TRI3:
     609             :           case TRISHELL3:
     610             :           case TRI6:
     611             :           case TRI7:
     612             :             {
     613       53383 :               mesh.reserve_elem (2*nx*ny);
     614       51879 :               break;
     615             :             }
     616             : 
     617           0 :           default:
     618           0 :             libmesh_error_msg("ERROR: Unrecognized 2D element type == " << Utility::enum_to_string(type));
     619             :           }
     620             : 
     621             : 
     622             : 
     623             :         // Reserve nodes.  The quadratic element types
     624             :         // need to reserve more nodes than the linear types.
     625             :         switch (type)
     626             :           {
     627       27953 :           case INVALID_ELEM:
     628             :           case QUAD4:
     629             :           case QUADSHELL4:
     630             :           case TRI3:
     631             :           case TRISHELL3:
     632             :             {
     633       27953 :               mesh.reserve_nodes( (nx+1)*(ny+1) );
     634       27163 :               break;
     635             :             }
     636             : 
     637       57426 :           case QUAD8:
     638             :           case QUADSHELL8:
     639             :           case QUAD9:
     640             :           case QUADSHELL9:
     641             :           case TRI6:
     642             :             {
     643       57426 :               mesh.reserve_nodes( (2*nx+1)*(2*ny+1) );
     644       55808 :               break;
     645             :             }
     646             : 
     647       20945 :           case TRI7:
     648             :             {
     649       20945 :               mesh.reserve_nodes( (2*nx+1)*(2*ny+1) + 2*nx*ny );
     650       20355 :               break;
     651             :             }
     652             : 
     653           0 :           default:
     654           0 :             libmesh_error_msg("ERROR: Unrecognized 2D element type == " << Utility::enum_to_string(type));
     655             :           }
     656             : 
     657             : 
     658             : 
     659             :         // Build the nodes. Depends on whether you are using a linear
     660             :         // or quadratic element, and whether you are using a uniform
     661             :         // grid or the Gauss-Lobatto grid points.
     662        2998 :         unsigned int node_id = 0;
     663             :         switch (type)
     664             :           {
     665         790 :           case INVALID_ELEM:
     666             :           case QUAD4:
     667             :           case QUADSHELL4:
     668             :           case TRI3:
     669             :           case TRISHELL3:
     670             :             {
     671      131061 :               for (unsigned int j=0; j<=ny; j++)
     672     1105430 :                 for (unsigned int i=0; i<=nx; i++)
     673             :                 {
     674             :                   const Node * const node =
     675     1949584 :                       mesh.add_point(Point(static_cast<Real>(i) / static_cast<Real>(nx),
     676     1002322 :                                            static_cast<Real>(j) / static_cast<Real>(ny),
     677             :                                            0.),
     678      992820 :                                      node_id++);
     679     1002322 :                   if (j == 0)
     680       97002 :                     boundary_info.add_node(node, 0);
     681     1002322 :                   if (j == ny)
     682       97002 :                     boundary_info.add_node(node, 2);
     683     1002322 :                   if (i == 0)
     684      103108 :                     boundary_info.add_node(node, 3);
     685     1002322 :                   if (i == nx)
     686      103108 :                     boundary_info.add_node(node, 1);
     687             :                 }
     688             : 
     689         790 :               break;
     690             :             }
     691             : 
     692        2208 :           case QUAD8:
     693             :           case QUADSHELL8:
     694             :           case QUAD9:
     695             :           case QUADSHELL9:
     696             :           case TRI6:
     697             :           case TRI7:
     698             :             {
     699      496316 :               for (unsigned int j=0; j<=(2*ny); j++)
     700     6614094 :                 for (unsigned int i=0; i<=(2*nx); i++)
     701             :                 {
     702             :                   const Node * const node =
     703    12043154 :                       mesh.add_point(Point(static_cast<Real>(i) / static_cast<Real>(2 * nx),
     704     6196149 :                                            static_cast<Real>(j) / static_cast<Real>(2 * ny),
     705             :                                            0),
     706     6110461 :                                      node_id++);
     707     6196149 :                   if (j == 0)
     708      431119 :                     boundary_info.add_node(node, 0);
     709     6196149 :                   if (j == 2*ny)
     710      431119 :                     boundary_info.add_node(node, 2);
     711     6196149 :                   if (i == 0)
     712      417945 :                     boundary_info.add_node(node, 3);
     713     6196149 :                   if (i == 2*nx)
     714      417945 :                     boundary_info.add_node(node, 1);
     715             :                 }
     716             : 
     717             :               // We'll add any interior Tri7 nodes last, to keep from
     718             :               // messing with our idx function
     719       78371 :               if (type == TRI7)
     720       57652 :                 for (unsigned int j=0; j<(3*ny); j += 3)
     721      271646 :                   for (unsigned int i=0; i<(3*nx); i += 3)
     722             :                     {
     723             :                       // The bottom-right triangle's center node
     724      456642 :                       mesh.add_point(Point(static_cast<Real>(i+2) / static_cast<Real>(3 * nx),
     725      234939 :                                            static_cast<Real>(j+1) / static_cast<Real>(3 * ny),
     726             :                                            0),
     727      231630 :                                      node_id++);
     728             :                       // The top-left triangle's center node
     729      234939 :                       mesh.add_point(Point(static_cast<Real>(i+1) / static_cast<Real>(3 * nx),
     730      234939 :                                            static_cast<Real>(j+2) / static_cast<Real>(3 * ny),
     731             :                                            0),
     732      231630 :                                      node_id++);
     733             :                     }
     734             : 
     735        2208 :               break;
     736             :             }
     737             : 
     738             : 
     739           0 :           default:
     740           0 :             libmesh_error_msg("ERROR: Unrecognized 2D element type == " << Utility::enum_to_string(type));
     741             :           }
     742             : 
     743             : 
     744             : 
     745             : 
     746             : 
     747             : 
     748             :         // Build the elements.  Each one is a bit different.
     749        2998 :         unsigned int elem_id = 0;
     750             :         switch (type)
     751             :           {
     752             : 
     753         488 :           case INVALID_ELEM:
     754             :           case QUAD4:
     755             :           case QUADSHELL4:
     756             :             {
     757       76627 :               for (unsigned int j=0; j<ny; j++)
     758      855551 :                 for (unsigned int i=0; i<nx; i++)
     759             :                   {
     760      818270 :                     Elem * elem = mesh.add_elem(Elem::build_with_id(type == INVALID_ELEM ? QUAD4 : type, elem_id++));
     761      796157 :                     elem->set_node(0, mesh.node_ptr(idx(type,nx,i,j)    ));
     762      796157 :                     elem->set_node(1, mesh.node_ptr(idx(type,nx,i+1,j)  ));
     763      796157 :                     elem->set_node(2, mesh.node_ptr(idx(type,nx,i+1,j+1)));
     764      796157 :                     elem->set_node(3, mesh.node_ptr(idx(type,nx,i,j+1)  ));
     765             : 
     766      796157 :                     if (j == 0)
     767       53217 :                       boundary_info.add_side(elem, 0, 0);
     768             : 
     769      796157 :                     if (j == (ny-1))
     770       53217 :                       boundary_info.add_side(elem, 2, 2);
     771             : 
     772      796157 :                     if (i == 0)
     773       59394 :                       boundary_info.add_side(elem, 3, 3);
     774             : 
     775      796157 :                     if (i == (nx-1))
     776       59394 :                       boundary_info.add_side(elem, 1, 1);
     777             :                   }
     778         488 :               break;
     779             :             }
     780             : 
     781             : 
     782         302 :           case TRI3:
     783             :           case TRISHELL3:
     784             :             {
     785       26481 :               for (unsigned int j=0; j<ny; j++)
     786       49769 :                 for (unsigned int i=0; i<nx; i++)
     787             :                   {
     788             :                     // Add first Tri3
     789       34008 :                     Elem * elem = mesh.add_elem(Elem::build_with_id(type, elem_id++));
     790       34008 :                     elem->set_node(0, mesh.node_ptr(idx(type,nx,i,j)    ));
     791       34008 :                     elem->set_node(1, mesh.node_ptr(idx(type,nx,i+1,j)  ));
     792       34008 :                     elem->set_node(2, mesh.node_ptr(idx(type,nx,i+1,j+1)));
     793             : 
     794       34008 :                     if (j == 0)
     795       15832 :                       boundary_info.add_side(elem, 0, 0);
     796             : 
     797       34008 :                     if (i == (nx-1))
     798       15761 :                       boundary_info.add_side(elem, 1, 1);
     799             : 
     800             :                     // Add second Tri3
     801       34008 :                     elem = mesh.add_elem(Elem::build_with_id(type, elem_id++));
     802       34008 :                     elem->set_node(0, mesh.node_ptr(idx(type,nx,i,j)    ));
     803       34008 :                     elem->set_node(1, mesh.node_ptr(idx(type,nx,i+1,j+1)));
     804       34008 :                     elem->set_node(2, mesh.node_ptr(idx(type,nx,i,j+1)  ));
     805             : 
     806       34008 :                     if (j == (ny-1))
     807       15832 :                       boundary_info.add_side(elem, 1, 2);
     808             : 
     809       34008 :                     if (i == 0)
     810       15761 :                       boundary_info.add_side(elem, 2, 3);
     811             :                   }
     812         302 :               break;
     813             :             }
     814             : 
     815             : 
     816             : 
     817        1006 :           case QUAD8:
     818             :           case QUADSHELL8:
     819             :           case QUAD9:
     820             :           case QUADSHELL9:
     821             :             {
     822      125707 :               for (unsigned int j=0; j<(2*ny); j += 2)
     823      913927 :                 for (unsigned int i=0; i<(2*nx); i += 2)
     824             :                   {
     825      823928 :                     Elem * elem = mesh.add_elem(Elem::build_with_id(type, elem_id++));
     826      823928 :                     elem->set_node(0, mesh.node_ptr(idx(type,nx,i,j)    ));
     827      823928 :                     elem->set_node(1, mesh.node_ptr(idx(type,nx,i+2,j)  ));
     828      823928 :                     elem->set_node(2, mesh.node_ptr(idx(type,nx,i+2,j+2)));
     829      823928 :                     elem->set_node(3, mesh.node_ptr(idx(type,nx,i,j+2)  ));
     830      823928 :                     elem->set_node(4, mesh.node_ptr(idx(type,nx,i+1,j)  ));
     831      823928 :                     elem->set_node(5, mesh.node_ptr(idx(type,nx,i+2,j+1)));
     832      823928 :                     elem->set_node(6, mesh.node_ptr(idx(type,nx,i+1,j+2)));
     833      823928 :                     elem->set_node(7, mesh.node_ptr(idx(type,nx,i,j+1)  ));
     834             : 
     835      823928 :                     if (type == QUAD9 || type == QUADSHELL9)
     836      627471 :                       elem->set_node(8, mesh.node_ptr(idx(type,nx,i+1,j+1)));
     837             : 
     838      823928 :                     if (j == 0)
     839       95466 :                       boundary_info.add_side(elem, 0, 0);
     840             : 
     841      823928 :                     if (j == 2*(ny-1))
     842       95466 :                       boundary_info.add_side(elem, 2, 2);
     843             : 
     844      823928 :                     if (i == 0)
     845       89999 :                       boundary_info.add_side(elem, 3, 3);
     846             : 
     847      823928 :                     if (i == 2*(nx-1))
     848       89999 :                       boundary_info.add_side(elem, 1, 1);
     849             :                   }
     850        1006 :               break;
     851             :             }
     852             : 
     853             : 
     854        1202 :           case TRI6:
     855             :           case TRI7:
     856             :             {
     857      122451 :               for (unsigned int j=0; j<(2*ny); j += 2)
     858      612224 :                 for (unsigned int i=0; i<(2*nx); i += 2)
     859             :                   {
     860             :                     // Add first Tri in the bottom-right of its quad
     861      532436 :                     Elem * elem = mesh.add_elem(Elem::build_with_id(type, elem_id++));
     862      532436 :                     elem->set_node(0, mesh.node_ptr(idx(type,nx,i,j)    ));
     863      532436 :                     elem->set_node(1, mesh.node_ptr(idx(type,nx,i+2,j)  ));
     864      532436 :                     elem->set_node(2, mesh.node_ptr(idx(type,nx,i+2,j+2)));
     865      532436 :                     elem->set_node(3, mesh.node_ptr(idx(type,nx,i+1,j)  ));
     866      532436 :                     elem->set_node(4, mesh.node_ptr(idx(type,nx,i+2,j+1)));
     867      532436 :                     elem->set_node(5, mesh.node_ptr(idx(type,nx,i+1,j+1)));
     868             : 
     869      532436 :                     if (type == TRI7)
     870      234939 :                       elem->set_node(6, mesh.node_ptr(elem->id()+(2*nx+1)*(2*ny+1)));
     871             : 
     872      532436 :                     if (j == 0)
     873       80908 :                       boundary_info.add_side(elem, 0, 0);
     874             : 
     875      532436 :                     if (i == 2*(nx-1))
     876       79788 :                       boundary_info.add_side(elem, 1, 1);
     877             : 
     878             :                     // Add second Tri in the top left of its quad
     879      532436 :                     elem = mesh.add_elem(Elem::build_with_id(type, elem_id++));
     880      532436 :                     elem->set_node(0, mesh.node_ptr(idx(type,nx,i,j)    ));
     881      532436 :                     elem->set_node(1, mesh.node_ptr(idx(type,nx,i+2,j+2)));
     882      532436 :                     elem->set_node(2, mesh.node_ptr(idx(type,nx,i,j+2)  ));
     883      532436 :                     elem->set_node(3, mesh.node_ptr(idx(type,nx,i+1,j+1)));
     884      532436 :                     elem->set_node(4, mesh.node_ptr(idx(type,nx,i+1,j+2)));
     885      532436 :                     elem->set_node(5, mesh.node_ptr(idx(type,nx,i,j+1)  ));
     886             : 
     887      532436 :                     if (type == TRI7)
     888      234939 :                       elem->set_node(6, mesh.node_ptr(elem->id()+(2*nx+1)*(2*ny+1)));
     889             : 
     890      532436 :                     if (j == 2*(ny-1))
     891       80908 :                       boundary_info.add_side(elem, 1, 2);
     892             : 
     893      532436 :                     if (i == 0)
     894       79788 :                       boundary_info.add_side(elem, 2, 3);
     895             :                   }
     896        1202 :               break;
     897             :             };
     898             : 
     899             : 
     900           0 :           default:
     901           0 :             libmesh_error_msg("ERROR: Unrecognized 2D element type == " << Utility::enum_to_string(type));
     902             :           }
     903             : 
     904             : 
     905             : 
     906             : 
     907             :         // Scale the nodal positions
     908      106324 :         if (gauss_lobatto_grid)
     909             :           {
     910             :             GaussLobattoRedistributionFunction func(nx, xmin, xmax,
     911           0 :                                                     ny, ymin, ymax);
     912           0 :             MeshTools::Modification::redistribute(mesh, func);
     913           0 :           }
     914             :         else // !gauss_lobatto_grid
     915             :           {
     916     7877999 :             for (Node * node : mesh.node_ptr_range())
     917             :               {
     918     7668349 :                 (*node)(0) = ((*node)(0))*(xmax-xmin) + xmin;
     919     7668349 :                 (*node)(1) = ((*node)(1))*(ymax-ymin) + ymin;
     920      100328 :               }
     921             :           }
     922             : 
     923             :         // Add sideset names to boundary info
     924      106324 :         boundary_info.sideset_name(0) = "bottom";
     925      106324 :         boundary_info.sideset_name(1) = "right";
     926      106324 :         boundary_info.sideset_name(2) = "top";
     927      106324 :         boundary_info.sideset_name(3) = "left";
     928             : 
     929             :         // Add nodeset names to boundary info
     930      106324 :         boundary_info.nodeset_name(0) = "bottom";
     931      106324 :         boundary_info.nodeset_name(1) = "right";
     932      106324 :         boundary_info.nodeset_name(2) = "top";
     933      106324 :         boundary_info.nodeset_name(3) = "left";
     934             : 
     935        2998 :         break;
     936             :       }
     937             : 
     938             : 
     939             : 
     940             : 
     941             : 
     942             : 
     943             : 
     944             : 
     945             : 
     946             : 
     947             : 
     948             :       //---------------------------------------------------------------------
     949             :       // Build a 3D mesh using hexes, tets, prisms, or pyramids.
     950      122695 :     case 3:
     951             :       {
     952        3488 :         libmesh_assert_not_equal_to (nx, 0);
     953        3488 :         libmesh_assert_not_equal_to (ny, 0);
     954        3488 :         libmesh_assert_not_equal_to (nz, 0);
     955        3488 :         libmesh_assert_less (xmin, xmax);
     956        3488 :         libmesh_assert_less (ymin, ymax);
     957        3488 :         libmesh_assert_less (zmin, zmax);
     958             : 
     959             : 
     960             :         // Reserve elements.  Meshes with prismatic elements require
     961             :         // twice as many elements.
     962             :         switch (type)
     963             :           {
     964       76606 :           case INVALID_ELEM:
     965             :           case HEX8:
     966             :           case HEX20:
     967             :           case HEX27:
     968             :           case TET4:  // TET4's are created from an initial HEX27 discretization
     969             :           case TET10: // TET10's are created from an initial HEX27 discretization
     970             :           case TET14: // TET14's are created from an initial HEX27 discretization
     971             :           case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
     972             :           case PYRAMID13:
     973             :           case PYRAMID14:
     974             :           case PYRAMID18:
     975             :             {
     976       76606 :               mesh.reserve_elem(nx*ny*nz);
     977       74420 :               break;
     978             :             }
     979             : 
     980       46089 :           case PRISM6:
     981             :           case PRISM15:
     982             :           case PRISM18:
     983             :           case PRISM20:
     984             :           case PRISM21:
     985             :             {
     986       46089 :               mesh.reserve_elem(2*nx*ny*nz);
     987       44787 :               break;
     988             :             }
     989             : 
     990           0 :           default:
     991           0 :             libmesh_error_msg("ERROR: Unrecognized 3D element type == " << Utility::enum_to_string(type));
     992             :           }
     993             : 
     994             : 
     995             : 
     996             : 
     997             : 
     998             :         // Reserve nodes.  Quadratic elements need twice as many nodes as linear elements.
     999             :         switch (type)
    1000             :           {
    1001       20654 :           case INVALID_ELEM:
    1002             :           case HEX8:
    1003             :           case PRISM6:
    1004             :             {
    1005       20654 :               mesh.reserve_nodes( (nx+1)*(ny+1)*(nz+1) );
    1006       20046 :               break;
    1007             :             }
    1008             : 
    1009       68671 :           case HEX20:
    1010             :           case HEX27:
    1011             :           case TET4: // TET4's are created from an initial HEX27 discretization
    1012             :           case TET10: // TET10's are created from an initial HEX27 discretization
    1013             :           case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
    1014             :           case PYRAMID13:
    1015             :           case PYRAMID14:
    1016             :           case PYRAMID18:
    1017             :           case PRISM15:
    1018             :           case PRISM18:
    1019             :             {
    1020             :               // FYI: The resulting TET4 mesh will have exactly
    1021             :               // 5*(nx*ny*nz) + 2*(nx*ny + nx*nz + ny*nz) + (nx+ny+nz) + 1
    1022             :               // nodes once the additional mid-edge nodes for the HEX27 discretization
    1023             :               // have been deleted.
    1024       68671 :               mesh.reserve_nodes( (2*nx+1)*(2*ny+1)*(2*nz+1) );
    1025       66731 :               break;
    1026             :             }
    1027             : 
    1028       11644 :           case TET14:
    1029             :             {
    1030       13284 :               mesh.reserve_nodes( (2*nx+1)*(2*ny+1)*(2*nz+1) +
    1031       11644 :                                   24*nx*ny*nz +
    1032       11644 :                                   4*(nx*ny + ny*nz + nx*nz) );
    1033       11316 :               break;
    1034             :             }
    1035             : 
    1036        9869 :           case PRISM20:
    1037             :             {
    1038       10703 :               mesh.reserve_nodes( (2*nx+1)*(2*ny+1)*(2*nz+1) +
    1039        9869 :                                   2*nx*ny*(nz+1) );
    1040        9591 :               break;
    1041             :             }
    1042             : 
    1043       11857 :           case PRISM21:
    1044             :             {
    1045       12859 :               mesh.reserve_nodes( (2*nx+1)*(2*ny+1)*(2*nz+1) +
    1046       11857 :                                   2*nx*ny*(2*nz+1) );
    1047       11523 :               break;
    1048             :             }
    1049             : 
    1050           0 :           default:
    1051           0 :             libmesh_error_msg("ERROR: Unrecognized 3D element type == " << Utility::enum_to_string(type));
    1052             :           }
    1053             : 
    1054             : 
    1055             : 
    1056             : 
    1057             :         // Build the nodes.
    1058        3488 :         unsigned int node_id = 0;
    1059             :         switch (type)
    1060             :           {
    1061         608 :           case INVALID_ELEM:
    1062             :           case HEX8:
    1063             :           case PRISM6:
    1064             :             {
    1065       75789 :               for (unsigned int k=0; k<=nz; k++)
    1066      253558 :                 for (unsigned int j=0; j<=ny; j++)
    1067     1825226 :                   for (unsigned int i=0; i<=nx; i++)
    1068             :                   {
    1069             :                     const Node * const node =
    1070     3161298 :                         mesh.add_point(Point(static_cast<Real>(i) / static_cast<Real>(nx),
    1071     1626803 :                                              static_cast<Real>(j) / static_cast<Real>(ny),
    1072     1626803 :                                              static_cast<Real>(k) / static_cast<Real>(nz)),
    1073     1607748 :                                        node_id++);
    1074     1626803 :                     if (k == 0)
    1075      287883 :                       boundary_info.add_node(node, 0);
    1076     1626803 :                     if (k == nz)
    1077      287883 :                       boundary_info.add_node(node, 5);
    1078     1626803 :                     if (j == 0)
    1079      241023 :                       boundary_info.add_node(node, 1);
    1080     1626803 :                     if (j == ny)
    1081      241023 :                       boundary_info.add_node(node, 3);
    1082     1626803 :                     if (i == 0)
    1083      198423 :                       boundary_info.add_node(node, 4);
    1084     1626803 :                     if (i == nx)
    1085      198423 :                       boundary_info.add_node(node, 2);
    1086             :                   }
    1087             : 
    1088         608 :               break;
    1089             :             }
    1090             : 
    1091        2880 :           case HEX20:
    1092             :           case HEX27:
    1093             :           case TET4: // TET4's are created from an initial HEX27 discretization
    1094             :           case TET10: // TET10's are created from an initial HEX27 discretization
    1095             :           case TET14: // TET14's are created from an initial HEX27 discretization
    1096             :           case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
    1097             :           case PYRAMID13:
    1098             :           case PYRAMID14:
    1099             :           case PYRAMID18:
    1100             :           case PRISM15:
    1101             :           case PRISM18:
    1102             :           case PRISM20:
    1103             :           case PRISM21:
    1104             :             {
    1105      487610 :               for (unsigned int k=0; k<=(2*nz); k++)
    1106     2173896 :                 for (unsigned int j=0; j<=(2*ny); j++)
    1107    16711758 :                   for (unsigned int i=0; i<=(2*nx); i++)
    1108             :                   {
    1109             :                     const Node * const node =
    1110    29001030 :                         mesh.add_point(Point(static_cast<Real>(i) / static_cast<Real>(2 * nx),
    1111    14923431 :                                              static_cast<Real>(j) / static_cast<Real>(2 * ny),
    1112    14923431 :                                              static_cast<Real>(k) / static_cast<Real>(2 * nz)),
    1113    14712498 :                                        node_id++);
    1114    14923431 :                     if (k == 0)
    1115     1901115 :                       boundary_info.add_node(node, 0);
    1116    14923431 :                     if (k == 2*nz)
    1117     1901115 :                       boundary_info.add_node(node, 5);
    1118    14923431 :                     if (j == 0)
    1119     1845725 :                       boundary_info.add_node(node, 1);
    1120    14923431 :                     if (j == 2*ny)
    1121     1845725 :                       boundary_info.add_node(node, 3);
    1122    14923431 :                     if (i == 0)
    1123     1788327 :                       boundary_info.add_node(node, 4);
    1124    14923431 :                     if (i == 2*nx)
    1125     1788327 :                       boundary_info.add_node(node, 2);
    1126             :                   }
    1127             : 
    1128      102041 :               if (type == PRISM20 ||
    1129             :                   type == PRISM21)
    1130             :                 {
    1131       21726 :                   const unsigned int kmax = (type == PRISM20) ? nz : 2*nz;
    1132       87259 :                   for (unsigned int k=0; k<=kmax; k++)
    1133      158330 :                     for (unsigned int j=0; j<ny; j++)
    1134      240122 :                       for (unsigned int i=0; i<nx; i++)
    1135             :                         {
    1136             :                           const Node * const node1 =
    1137      286350 :                               mesh.add_point(Point((static_cast<Real>(i)+1/Real(3)) / static_cast<Real>(nx),
    1138      147325 :                                                    (static_cast<Real>(j)+1/Real(3)) / static_cast<Real>(ny),
    1139      147325 :                                                    static_cast<Real>(k) / static_cast<Real>(kmax)),
    1140      145250 :                                              node_id++);
    1141      147325 :                           if (k == 0)
    1142       42174 :                             boundary_info.add_node(node1, 0);
    1143      147325 :                           if (k == kmax)
    1144       42174 :                             boundary_info.add_node(node1, 5);
    1145             : 
    1146             :                           const Node * const node2 =
    1147      286350 :                               mesh.add_point(Point((static_cast<Real>(i)+2/Real(3)) / static_cast<Real>(nx),
    1148      147325 :                                                    (static_cast<Real>(j)+2/Real(3)) / static_cast<Real>(ny),
    1149        4150 :                                                    static_cast<Real>(k) / static_cast<Real>(kmax)),
    1150      145250 :                                              node_id++);
    1151      147325 :                           if (k == 0)
    1152       42174 :                             boundary_info.add_node(node2, 0);
    1153      147325 :                           if (k == kmax)
    1154       42174 :                             boundary_info.add_node(node2, 5);
    1155             :                         }
    1156             :                 }
    1157             : 
    1158        2880 :               break;
    1159             :             }
    1160             : 
    1161             : 
    1162           0 :           default:
    1163           0 :             libmesh_error_msg("ERROR: Unrecognized 3D element type == " << Utility::enum_to_string(type));
    1164             :           }
    1165             : 
    1166             : 
    1167             : 
    1168             : 
    1169             :         // Build the elements.
    1170        3488 :         unsigned int elem_id = 0;
    1171             :         switch (type)
    1172             :           {
    1173         394 :           case INVALID_ELEM:
    1174             :           case HEX8:
    1175             :             {
    1176       38095 :               for (unsigned int k=0; k<nz; k++)
    1177      119148 :                 for (unsigned int j=0; j<ny; j++)
    1178     1128324 :                   for (unsigned int i=0; i<nx; i++)
    1179             :                     {
    1180     1034214 :                       Elem * elem = mesh.add_elem(Elem::build_with_id(HEX8, elem_id++));
    1181     1034214 :                       elem->set_node(0, mesh.node_ptr(idx(type,nx,ny,i,j,k)      ));
    1182     1034214 :                       elem->set_node(1, mesh.node_ptr(idx(type,nx,ny,i+1,j,k)    ));
    1183     1034214 :                       elem->set_node(2, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  ));
    1184     1034214 :                       elem->set_node(3, mesh.node_ptr(idx(type,nx,ny,i,j+1,k)    ));
    1185     1034214 :                       elem->set_node(4, mesh.node_ptr(idx(type,nx,ny,i,j,k+1)    ));
    1186     1034214 :                       elem->set_node(5, mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1)  ));
    1187     1034214 :                       elem->set_node(6, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1)));
    1188     1034214 :                       elem->set_node(7, mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1)  ));
    1189             : 
    1190     1034214 :                       if (k == 0)
    1191      173630 :                         boundary_info.add_side(elem, 0, 0);
    1192             : 
    1193     1034214 :                       if (k == (nz-1))
    1194      173630 :                         boundary_info.add_side(elem, 5, 5);
    1195             : 
    1196     1034214 :                       if (j == 0)
    1197      128190 :                         boundary_info.add_side(elem, 1, 1);
    1198             : 
    1199     1034214 :                       if (j == (ny-1))
    1200      128190 :                         boundary_info.add_side(elem, 3, 3);
    1201             : 
    1202     1034214 :                       if (i == 0)
    1203       94110 :                         boundary_info.add_side(elem, 4, 4);
    1204             : 
    1205     1034214 :                       if (i == (nx-1))
    1206       94110 :                         boundary_info.add_side(elem, 2, 2);
    1207             :                     }
    1208         394 :               break;
    1209             :             }
    1210             : 
    1211             : 
    1212             : 
    1213             : 
    1214         214 :           case PRISM6:
    1215             :             {
    1216       17040 :               for (unsigned int k=0; k<nz; k++)
    1217       22720 :                 for (unsigned int j=0; j<ny; j++)
    1218       34648 :                   for (unsigned int i=0; i<nx; i++)
    1219             :                     {
    1220             :                       // First Prism
    1221       21371 :                       Elem * elem = mesh.add_elem(Elem::build_with_id(PRISM6, elem_id++));
    1222       21371 :                       elem->set_node(0, mesh.node_ptr(idx(type,nx,ny,i,j,k)      ));
    1223       21371 :                       elem->set_node(1, mesh.node_ptr(idx(type,nx,ny,i+1,j,k)    ));
    1224       21371 :                       elem->set_node(2, mesh.node_ptr(idx(type,nx,ny,i,j+1,k)    ));
    1225       21371 :                       elem->set_node(3, mesh.node_ptr(idx(type,nx,ny,i,j,k+1)    ));
    1226       21371 :                       elem->set_node(4, mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1)  ));
    1227       21371 :                       elem->set_node(5, mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1)  ));
    1228             : 
    1229             :                       // Add sides for first prism to boundary info object
    1230       21371 :                       if (i==0)
    1231       13277 :                         boundary_info.add_side(elem, 3, 4);
    1232             : 
    1233       21371 :                       if (j==0)
    1234       13277 :                         boundary_info.add_side(elem, 1, 1);
    1235             : 
    1236       21371 :                       if (k==0)
    1237       13277 :                         boundary_info.add_side(elem, 0, 0);
    1238             : 
    1239       21371 :                       if (k == (nz-1))
    1240       13277 :                         boundary_info.add_side(elem, 4, 5);
    1241             : 
    1242             :                       // Second Prism
    1243       21371 :                       elem = mesh.add_elem(Elem::build_with_id(PRISM6, elem_id++));
    1244       21371 :                       elem->set_node(0, mesh.node_ptr(idx(type,nx,ny,i+1,j,k)    ));
    1245       21371 :                       elem->set_node(1, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  ));
    1246       21371 :                       elem->set_node(2, mesh.node_ptr(idx(type,nx,ny,i,j+1,k)    ));
    1247       21371 :                       elem->set_node(3, mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1)  ));
    1248       21371 :                       elem->set_node(4, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1)));
    1249       21371 :                       elem->set_node(5, mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1)  ));
    1250             : 
    1251             :                       // Add sides for second prism to boundary info object
    1252       21371 :                       if (i == (nx-1))
    1253       13277 :                         boundary_info.add_side(elem, 1, 2);
    1254             : 
    1255       21371 :                       if (j == (ny-1))
    1256       13277 :                         boundary_info.add_side(elem, 2, 3);
    1257             : 
    1258       21371 :                       if (k==0)
    1259       13277 :                         boundary_info.add_side(elem, 0, 0);
    1260             : 
    1261       21371 :                       if (k == (nz-1))
    1262       13277 :                         boundary_info.add_side(elem, 4, 5);
    1263             :                     }
    1264         214 :               break;
    1265             :             }
    1266             : 
    1267             : 
    1268             : 
    1269             : 
    1270             : 
    1271             : 
    1272        1792 :           case HEX20:
    1273             :           case HEX27:
    1274             :           case TET4: // TET4's are created from an initial HEX27 discretization
    1275             :           case TET10: // TET10's are created from an initial HEX27 discretization
    1276             :           case TET14: // TET14's are created from an initial HEX27 discretization
    1277             :           case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
    1278             :           case PYRAMID13:
    1279             :           case PYRAMID14:
    1280             :           case PYRAMID18:
    1281             :             {
    1282      156724 :               for (unsigned int k=0; k<(2*nz); k += 2)
    1283      303949 :                 for (unsigned int j=0; j<(2*ny); j += 2)
    1284     1407944 :                   for (unsigned int i=0; i<(2*nx); i += 2)
    1285             :                     {
    1286     1197170 :                       ElemType build_type = (type == HEX20) ? HEX20 : HEX27;
    1287     1197170 :                       Elem * elem = mesh.add_elem(Elem::build_with_id(build_type, elem_id++));
    1288             : 
    1289     1197170 :                       elem->set_node(0,  mesh.node_ptr(idx(type,nx,ny,i,  j,  k)  ));
    1290     1197170 :                       elem->set_node(1,  mesh.node_ptr(idx(type,nx,ny,i+2,j,  k)  ));
    1291     1197170 :                       elem->set_node(2,  mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k)  ));
    1292     1197170 :                       elem->set_node(3,  mesh.node_ptr(idx(type,nx,ny,i,  j+2,k)  ));
    1293     1197170 :                       elem->set_node(4,  mesh.node_ptr(idx(type,nx,ny,i,  j,  k+2)));
    1294     1197170 :                       elem->set_node(5,  mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+2)));
    1295     1197170 :                       elem->set_node(6,  mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+2)));
    1296     1197170 :                       elem->set_node(7,  mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+2)));
    1297     1197170 :                       elem->set_node(8,  mesh.node_ptr(idx(type,nx,ny,i+1,j,  k)  ));
    1298     1197170 :                       elem->set_node(9,  mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k)  ));
    1299     1197170 :                       elem->set_node(10, mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k)  ));
    1300     1197170 :                       elem->set_node(11, mesh.node_ptr(idx(type,nx,ny,i,  j+1,k)  ));
    1301     1197170 :                       elem->set_node(12, mesh.node_ptr(idx(type,nx,ny,i,  j,  k+1)));
    1302     1197170 :                       elem->set_node(13, mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+1)));
    1303     1197170 :                       elem->set_node(14, mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+1)));
    1304     1197170 :                       elem->set_node(15, mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+1)));
    1305     1197170 :                       elem->set_node(16, mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+2)));
    1306     1197170 :                       elem->set_node(17, mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+2)));
    1307     1197170 :                       elem->set_node(18, mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+2)));
    1308     1197170 :                       elem->set_node(19, mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+2)));
    1309             : 
    1310     1197170 :                       if ((type == HEX27) || (type == TET4) || (type == TET10) || (type == TET14) ||
    1311        4882 :                           (type == PYRAMID5) || (type == PYRAMID13) || (type == PYRAMID14) ||
    1312        1854 :                           (type == PYRAMID18))
    1313             :                         {
    1314     1156487 :                           elem->set_node(20, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  ));
    1315     1156487 :                           elem->set_node(21, mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+1)));
    1316     1156487 :                           elem->set_node(22, mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+1)));
    1317     1156487 :                           elem->set_node(23, mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+1)));
    1318     1156487 :                           elem->set_node(24, mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+1)));
    1319     1156487 :                           elem->set_node(25, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2)));
    1320     1156487 :                           elem->set_node(26, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1)));
    1321             :                         }
    1322             : 
    1323     1197170 :                       if (k == 0)
    1324      236582 :                         boundary_info.add_side(elem, 0, 0);
    1325             : 
    1326     1197170 :                       if (k == 2*(nz-1))
    1327      236582 :                         boundary_info.add_side(elem, 5, 5);
    1328             : 
    1329     1197170 :                       if (j == 0)
    1330      222995 :                         boundary_info.add_side(elem, 1, 1);
    1331             : 
    1332     1197170 :                       if (j == 2*(ny-1))
    1333      222995 :                         boundary_info.add_side(elem, 3, 3);
    1334             : 
    1335     1197170 :                       if (i == 0)
    1336      210774 :                         boundary_info.add_side(elem, 4, 4);
    1337             : 
    1338     1197170 :                       if (i == 2*(nx-1))
    1339      210774 :                         boundary_info.add_side(elem, 2, 2);
    1340             :                     }
    1341        1792 :               break;
    1342             :             }
    1343             : 
    1344             : 
    1345             : 
    1346             : 
    1347        1088 :           case PRISM15:
    1348             :           case PRISM18:
    1349             :           case PRISM20:
    1350             :           case PRISM21:
    1351             :             {
    1352       87081 :               for (unsigned int k=0; k<(2*nz); k += 2)
    1353      117412 :                 for (unsigned int j=0; j<(2*ny); j += 2)
    1354      178294 :                   for (unsigned int i=0; i<(2*nx); i += 2)
    1355             :                     {
    1356             :                       // First Prism
    1357      109471 :                       Elem * elem = mesh.add_elem(Elem::build_with_id(type, elem_id++));
    1358      109471 :                       elem->set_node(0,  mesh.node_ptr(idx(type,nx,ny,i,  j,  k)  ));
    1359      109471 :                       elem->set_node(1,  mesh.node_ptr(idx(type,nx,ny,i+2,j,  k)  ));
    1360      109471 :                       elem->set_node(2,  mesh.node_ptr(idx(type,nx,ny,i,  j+2,k)  ));
    1361      109471 :                       elem->set_node(3,  mesh.node_ptr(idx(type,nx,ny,i,  j,  k+2)));
    1362      109471 :                       elem->set_node(4,  mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+2)));
    1363      109471 :                       elem->set_node(5,  mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+2)));
    1364      109471 :                       elem->set_node(6,  mesh.node_ptr(idx(type,nx,ny,i+1,j,  k)  ));
    1365      109471 :                       elem->set_node(7,  mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  ));
    1366      109471 :                       elem->set_node(8,  mesh.node_ptr(idx(type,nx,ny,i,  j+1,k)  ));
    1367      109471 :                       elem->set_node(9,  mesh.node_ptr(idx(type,nx,ny,i,  j,  k+1)));
    1368      109471 :                       elem->set_node(10, mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+1)));
    1369      109471 :                       elem->set_node(11, mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+1)));
    1370      109471 :                       elem->set_node(12, mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+2)));
    1371      109471 :                       elem->set_node(13, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2)));
    1372      109471 :                       elem->set_node(14, mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+2)));
    1373             : 
    1374      112709 :                       if (type == PRISM18 ||
    1375      107787 :                           type == PRISM20 ||
    1376             :                           type == PRISM21)
    1377             :                         {
    1378       90017 :                           elem->set_node(15, mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+1)));
    1379       90017 :                           elem->set_node(16, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1)));
    1380       90017 :                           elem->set_node(17, mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+1)));
    1381             :                         }
    1382             : 
    1383      109471 :                       if (type == PRISM20)
    1384             :                         {
    1385       33725 :                           const dof_id_type base_idx = (2*nx+1)*(2*ny+1)*(2*nz+1);
    1386       33725 :                           elem->set_node(18, mesh.node_ptr(base_idx+((k/2)*(nx*ny)+j/2*nx+i/2)*2));
    1387       33725 :                           elem->set_node(19, mesh.node_ptr(base_idx+(((k/2)+1)*(nx*ny)+j/2*nx+i/2)*2));
    1388             :                         }
    1389             : 
    1390      109471 :                       if (type == PRISM21)
    1391             :                         {
    1392       35713 :                           const dof_id_type base_idx = (2*nx+1)*(2*ny+1)*(2*nz+1);
    1393       35713 :                           elem->set_node(18, mesh.node_ptr(base_idx+(k*(nx*ny)+j/2*nx+i/2)*2));
    1394       35713 :                           elem->set_node(19, mesh.node_ptr(base_idx+((k+2)*(nx*ny)+j/2*nx+i/2)*2));
    1395       35713 :                           elem->set_node(20, mesh.node_ptr(base_idx+((k+1)*(nx*ny)+j/2*nx+i/2)*2));
    1396             :                         }
    1397             : 
    1398             :                       // Add sides for first prism to boundary info object
    1399      109471 :                       if (i==0)
    1400       68823 :                         boundary_info.add_side(elem, 3, 4);
    1401             : 
    1402      109471 :                       if (j==0)
    1403       68823 :                         boundary_info.add_side(elem, 1, 1);
    1404             : 
    1405      109471 :                       if (k==0)
    1406       68873 :                         boundary_info.add_side(elem, 0, 0);
    1407             : 
    1408      109471 :                       if (k == 2*(nz-1))
    1409       68873 :                         boundary_info.add_side(elem, 4, 5);
    1410             : 
    1411             : 
    1412             :                       // Second Prism
    1413      109471 :                       elem = mesh.add_elem(Elem::build_with_id(type, elem_id++));
    1414      109471 :                       elem->set_node(0,  mesh.node_ptr(idx(type,nx,ny,i+2,j,k)     ));
    1415      109471 :                       elem->set_node(1,  mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k)   ));
    1416      109471 :                       elem->set_node(2,  mesh.node_ptr(idx(type,nx,ny,i,j+2,k)     ));
    1417      109471 :                       elem->set_node(3,  mesh.node_ptr(idx(type,nx,ny,i+2,j,k+2)   ));
    1418      109471 :                       elem->set_node(4,  mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+2) ));
    1419      109471 :                       elem->set_node(5,  mesh.node_ptr(idx(type,nx,ny,i,j+2,k+2)   ));
    1420      109471 :                       elem->set_node(6,  mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k)  ));
    1421      109471 :                       elem->set_node(7,  mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k)  ));
    1422      109471 :                       elem->set_node(8,  mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  ));
    1423      109471 :                       elem->set_node(9,  mesh.node_ptr(idx(type,nx,ny,i+2,j,k+1)  ));
    1424      109471 :                       elem->set_node(10, mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+1)));
    1425      109471 :                       elem->set_node(11, mesh.node_ptr(idx(type,nx,ny,i,j+2,k+1)  ));
    1426      109471 :                       elem->set_node(12, mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+2)));
    1427      109471 :                       elem->set_node(13, mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+2)));
    1428      109471 :                       elem->set_node(14, mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2)));
    1429             : 
    1430      109471 :                       if (type == PRISM18 ||
    1431       55167 :                           type == PRISM20 ||
    1432             :                           type == PRISM21)
    1433             :                         {
    1434       90017 :                           elem->set_node(15,  mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+1)));
    1435       90017 :                           elem->set_node(16,  mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+1)));
    1436       90017 :                           elem->set_node(17,  mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1)));
    1437             :                         }
    1438             : 
    1439      109471 :                       if (type == PRISM20)
    1440             :                         {
    1441       33725 :                           const dof_id_type base_idx = (2*nx+1)*(2*ny+1)*(2*nz+1);
    1442       33725 :                           elem->set_node(18, mesh.node_ptr(base_idx+((k/2)*(nx*ny)+j/2*nx+i/2)*2+1));
    1443       33725 :                           elem->set_node(19, mesh.node_ptr(base_idx+(((k/2)+1)*(nx*ny)+j/2*nx+i/2)*2+1));
    1444             :                         }
    1445             : 
    1446      109471 :                       if (type == PRISM21)
    1447             :                         {
    1448       35713 :                           const dof_id_type base_idx = (2*nx+1)*(2*ny+1)*(2*nz+1);
    1449       35713 :                           elem->set_node(18, mesh.node_ptr(base_idx+(k*(nx*ny)+j/2*nx+i/2)*2+1));
    1450       35713 :                           elem->set_node(19, mesh.node_ptr(base_idx+((k+2)*(nx*ny)+j/2*nx+i/2)*2+1));
    1451       35713 :                           elem->set_node(20, mesh.node_ptr(base_idx+((k+1)*(nx*ny)+j/2*nx+i/2)*2+1));
    1452             :                         }
    1453             : 
    1454             :                       // Add sides for second prism to boundary info object
    1455      109471 :                       if (i == 2*(nx-1))
    1456       68823 :                         boundary_info.add_side(elem, 1, 2);
    1457             : 
    1458      109471 :                       if (j == 2*(ny-1))
    1459       68823 :                         boundary_info.add_side(elem, 2, 3);
    1460             : 
    1461      109471 :                       if (k==0)
    1462       68873 :                         boundary_info.add_side(elem, 0, 0);
    1463             : 
    1464      109471 :                       if (k == 2*(nz-1))
    1465       68873 :                         boundary_info.add_side(elem, 4, 5);
    1466             : 
    1467             :                     }
    1468        1088 :               break;
    1469             :             }
    1470             : 
    1471             : 
    1472             : 
    1473             : 
    1474             : 
    1475           0 :           default:
    1476           0 :             libmesh_error_msg("ERROR: Unrecognized 3D element type == " << Utility::enum_to_string(type));
    1477             :           }
    1478             : 
    1479             : 
    1480             : 
    1481             : 
    1482             :         //.......................................
    1483             :         // Scale the nodal positions
    1484      122695 :         if (gauss_lobatto_grid)
    1485             :           {
    1486             :             GaussLobattoRedistributionFunction func(nx, xmin, xmax,
    1487             :                                                     ny, ymin, ymax,
    1488           0 :                                                     nz, zmin, zmax);
    1489           0 :             MeshTools::Modification::redistribute(mesh, func);
    1490           0 :           }
    1491             :         else // !gauss_lobatto_grid
    1492             :           {
    1493    16967579 :             for (unsigned int p=0; p<mesh.n_nodes(); p++)
    1494             :               {
    1495    16844884 :                 mesh.node_ref(p)(0) = (mesh.node_ref(p)(0))*(xmax-xmin) + xmin;
    1496    16844884 :                 mesh.node_ref(p)(1) = (mesh.node_ref(p)(1))*(ymax-ymin) + ymin;
    1497    16844884 :                 mesh.node_ref(p)(2) = (mesh.node_ref(p)(2))*(zmax-zmin) + zmin;
    1498             :               }
    1499             :           }
    1500             : 
    1501             : 
    1502             : 
    1503             :         // Additional work for tets and pyramids: we take the existing
    1504             :         // HEX27 discretization and split each element into 24
    1505             :         // sub-tets or 6 sub-pyramids.
    1506             :         //
    1507             :         // 24 isn't the minimum-possible number of tets, but it
    1508             :         // obviates any concerns about the edge orientations between
    1509             :         // the various elements.
    1510      126183 :         if ((type == TET4) ||
    1511      122223 :             (type == TET10) ||
    1512      121895 :             (type == TET14) ||
    1513       94295 :             (type == PYRAMID5) ||
    1514        2558 :             (type == PYRAMID13) ||
    1515       92240 :             (type == PYRAMID14) ||
    1516       87188 :             (type == PYRAMID18))
    1517             :           {
    1518             :             // Temporary storage for new elements. (24 tets per hex, 6 pyramids)
    1519        3150 :             std::vector<std::unique_ptr<Elem>> new_elements;
    1520             : 
    1521             :             // For avoiding extraneous construction of element sides
    1522       37209 :             std::unique_ptr<Elem> side;
    1523             : 
    1524       37209 :             if ((type == TET4) || (type == TET10) || (type == TET14))
    1525       28334 :               new_elements.reserve(24*mesh.n_elem());
    1526             :             else
    1527        8875 :               new_elements.reserve(6*mesh.n_elem());
    1528             : 
    1529             :             // Create tetrahedra or pyramids
    1530      460914 :             for (auto & base_hex : mesh.element_ptr_range())
    1531             :               {
    1532             :                 // Get a pointer to the node located at the HEX27 center
    1533      199447 :                 Node * apex_node = base_hex->node_ptr(26);
    1534             : 
    1535             :                 // Container to catch ids handed back from BoundaryInfo
    1536       11348 :                 std::vector<boundary_id_type> ids;
    1537             : 
    1538     1396129 :                 for (auto s : base_hex->side_index_range())
    1539             :                   {
    1540             :                     // Get the boundary ID(s) for this side
    1541     1196682 :                     boundary_info.boundary_ids(base_hex, s, ids);
    1542             : 
    1543             :                     // We're creating this Mesh, so there should be 0 or 1 boundary IDs.
    1544       34044 :                     libmesh_assert(ids.size() <= 1);
    1545             : 
    1546             :                     // A convenient name for the side's ID.
    1547     1196682 :                     boundary_id_type b_id = ids.empty() ? BoundaryInfo::invalid_id : ids[0];
    1548             : 
    1549             :                     // Need to build the full-ordered side!
    1550     1196682 :                     base_hex->build_side_ptr(side, s);
    1551             : 
    1552     1196682 :                     if ((type == TET4) || (type == TET10) || (type == TET14))
    1553             :                       {
    1554             :                         // Build 4 sub-tets per side
    1555     4390170 :                         for (unsigned int sub_tet=0; sub_tet<4; ++sub_tet)
    1556             :                           {
    1557     6924000 :                             new_elements.push_back( Elem::build(TET4) );
    1558      100272 :                             auto & sub_elem = new_elements.back();
    1559     3712680 :                             sub_elem->set_node(0, side->node_ptr(sub_tet));
    1560     3712680 :                             sub_elem->set_node(1, side->node_ptr(8));                           // center of the face
    1561     3612408 :                             sub_elem->set_node(2, side->node_ptr(sub_tet==3 ? 0 : sub_tet+1 )); // wrap-around
    1562     3512136 :                             sub_elem->set_node(3, apex_node);                                   // apex node always used!
    1563             : 
    1564             :                             // If the original hex was a boundary hex, add the new sub_tet's side
    1565             :                             // 0 with the same b_id.  Note: the tets are all aligned so that their
    1566             :                             // side 0 is on the boundary.
    1567     3512136 :                             if (b_id != BoundaryInfo::invalid_id)
    1568     1541744 :                               boundary_info.add_side(sub_elem.get(), 0, b_id);
    1569       25068 :                           }
    1570             :                       } // end if ((type == TET4) || (type == TET10) || (type == TET14))
    1571             : 
    1572             :                     else // type==PYRAMID*
    1573             :                       {
    1574             :                         // Build 1 sub-pyramid per side.
    1575      628320 :                         new_elements.push_back( Elem::build(PYRAMID5) );
    1576        8976 :                         auto & sub_elem = new_elements.back();
    1577             : 
    1578             :                         // Set the base.  Note that since the apex is *inside* the base_hex,
    1579             :                         // and the pyramid uses a counter-clockwise base numbering, we need to
    1580             :                         // reverse the [1] and [3] node indices.
    1581      336600 :                         sub_elem->set_node(0, side->node_ptr(0));
    1582      336600 :                         sub_elem->set_node(1, side->node_ptr(3));
    1583      336600 :                         sub_elem->set_node(2, side->node_ptr(2));
    1584      336600 :                         sub_elem->set_node(3, side->node_ptr(1));
    1585             : 
    1586             :                         // Set the apex
    1587      318648 :                         sub_elem->set_node(4, apex_node);
    1588             : 
    1589             :                         // If the original hex was a boundary hex, add the new sub_pyr's side
    1590             :                         // 4 (the square base) with the same b_id.
    1591      318648 :                         if (b_id != BoundaryInfo::invalid_id)
    1592      171696 :                           boundary_info.add_side(sub_elem.get(), 4, b_id);
    1593             :                       } // end else type==PYRAMID*
    1594             :                   }
    1595       35109 :               }
    1596             : 
    1597             : 
    1598             :             // Delete the original HEX27 elements from the mesh, and the boundary info structure.
    1599      460914 :             for (auto & elem : mesh.element_ptr_range())
    1600             :               {
    1601      199447 :                 boundary_info.remove(elem); // Safe even if elem has no boundary info.
    1602      199447 :                 mesh.delete_elem(elem);
    1603       35109 :               }
    1604             : 
    1605             :             // Add the new elements
    1606     3867993 :             for (auto i : index_range(new_elements))
    1607             :               {
    1608      382368 :                 new_elements[i]->set_id(i);
    1609     4049280 :                 mesh.add_elem( std::move(new_elements[i]) );
    1610             :               }
    1611             : 
    1612       35109 :           } // end if (type == TET*,PYRAMID*)
    1613             : 
    1614             : 
    1615             :         // Use all_second_order to convert the TET4's to TET10's or PYRAMID5's to PYRAMID14's
    1616      122695 :         if ((type == TET10) || (type == PYRAMID14))
    1617       10868 :           mesh.all_second_order();
    1618             : 
    1619      111827 :         else if (type == PYRAMID13)
    1620        2272 :           mesh.all_second_order(/*full_ordered=*/false);
    1621             : 
    1622      109555 :         else if ((type == TET14) || (type == PYRAMID18))
    1623       13632 :           mesh.all_complete_order();
    1624             : 
    1625             : 
    1626             :         // Add sideset names to boundary info (Z axis out of the screen)
    1627      122695 :         boundary_info.sideset_name(0) = "back";
    1628      122695 :         boundary_info.sideset_name(1) = "bottom";
    1629      122695 :         boundary_info.sideset_name(2) = "right";
    1630      122695 :         boundary_info.sideset_name(3) = "top";
    1631      122695 :         boundary_info.sideset_name(4) = "left";
    1632      122695 :         boundary_info.sideset_name(5) = "front";
    1633             : 
    1634             :         // Add nodeset names to boundary info
    1635      122695 :         boundary_info.nodeset_name(0) = "back";
    1636      122695 :         boundary_info.nodeset_name(1) = "bottom";
    1637      122695 :         boundary_info.nodeset_name(2) = "right";
    1638      122695 :         boundary_info.nodeset_name(3) = "top";
    1639      122695 :         boundary_info.nodeset_name(4) = "left";
    1640      122695 :         boundary_info.nodeset_name(5) = "front";
    1641             : 
    1642        3488 :         break;
    1643             :       } // end case dim==3
    1644             : 
    1645           0 :     default:
    1646           0 :       libmesh_error_msg("Unknown dimension " << mesh.mesh_dimension());
    1647             :     }
    1648             : 
    1649             :   // Done building the mesh.  Now prepare it for use.
    1650      265006 :   mesh.prepare_for_use ();
    1651      265006 : }
    1652             : 
    1653             : 
    1654             : 
    1655         994 : void MeshTools::Generation::build_point (UnstructuredMesh & mesh,
    1656             :                                          const ElemType type,
    1657             :                                          const bool gauss_lobatto_grid)
    1658             : {
    1659             :   // This method only makes sense in 0D!
    1660             :   // But we now just turn a non-0D mesh into a 0D mesh
    1661             :   //libmesh_assert_equal_to (mesh.mesh_dimension(), 1);
    1662             : 
    1663         994 :   build_cube(mesh,
    1664             :              0, 0, 0,
    1665             :              0., 0.,
    1666             :              0., 0.,
    1667             :              0., 0.,
    1668             :              type,
    1669             :              gauss_lobatto_grid);
    1670         994 : }
    1671             : 
    1672             : 
    1673        4748 : void MeshTools::Generation::build_line (UnstructuredMesh & mesh,
    1674             :                                         const unsigned int nx,
    1675             :                                         const Real xmin, const Real xmax,
    1676             :                                         const ElemType type,
    1677             :                                         const bool gauss_lobatto_grid)
    1678             : {
    1679             :   // This method only makes sense in 1D!
    1680             :   // But we now just turn a non-1D mesh into a 1D mesh
    1681             :   //libmesh_assert_equal_to (mesh.mesh_dimension(), 1);
    1682             : 
    1683        4748 :   build_cube(mesh,
    1684             :              nx, 0, 0,
    1685             :              xmin, xmax,
    1686             :              0., 0.,
    1687             :              0., 0.,
    1688             :              type,
    1689             :              gauss_lobatto_grid);
    1690        4748 : }
    1691             : 
    1692             : 
    1693             : 
    1694       18214 : void MeshTools::Generation::build_square (UnstructuredMesh & mesh,
    1695             :                                           const unsigned int nx,
    1696             :                                           const unsigned int ny,
    1697             :                                           const Real xmin, const Real xmax,
    1698             :                                           const Real ymin, const Real ymax,
    1699             :                                           const ElemType type,
    1700             :                                           const bool gauss_lobatto_grid)
    1701             : {
    1702             :   // This method only makes sense in 2D!
    1703             :   // But we now just turn a non-2D mesh into a 2D mesh
    1704             :   //libmesh_assert_equal_to (mesh.mesh_dimension(), 2);
    1705             : 
    1706             :   // Call the build_cube() member to actually do the work for us.
    1707       18214 :   build_cube (mesh,
    1708             :               nx, ny, 0,
    1709             :               xmin, xmax,
    1710             :               ymin, ymax,
    1711             :               0., 0.,
    1712             :               type,
    1713             :               gauss_lobatto_grid);
    1714       18214 : }
    1715             : 
    1716             : 
    1717             : 
    1718             : 
    1719             : 
    1720             : 
    1721             : 
    1722             : 
    1723             : 
    1724             : #ifndef LIBMESH_ENABLE_AMR
    1725             : void MeshTools::Generation::build_sphere (UnstructuredMesh &,
    1726             :                                           const Real,
    1727             :                                           const unsigned int,
    1728             :                                           const ElemType,
    1729             :                                           const unsigned int,
    1730             :                                           const bool)
    1731             : {
    1732             :   libmesh_error_msg("Building a circle/sphere only works with AMR.");
    1733             : }
    1734             : 
    1735             : #else
    1736             : 
    1737        1074 : void MeshTools::Generation::build_sphere (UnstructuredMesh & mesh,
    1738             :                                           const Real rad,
    1739             :                                           const unsigned int nr,
    1740             :                                           const ElemType type,
    1741             :                                           const unsigned int n_smooth,
    1742             :                                           const bool flat)
    1743             : {
    1744          34 :   libmesh_assert_greater (rad, 0.);
    1745             :   //libmesh_assert_greater (nr, 0); // must refine at least once otherwise will end up with a square/cube
    1746             : 
    1747          68 :   LOG_SCOPE("build_sphere()", "MeshTools::Generation");
    1748             : 
    1749             :   // Clear the mesh and start from scratch, but save the original
    1750             :   // mesh_dimension, since the original intent of this function was to
    1751             :   // allow the geometric entity (line, circle, ball, sphere)
    1752             :   // constructed to be determined by the mesh's dimension.
    1753             :   unsigned char orig_mesh_dimension =
    1754        1074 :     cast_int<unsigned char>(mesh.mesh_dimension());
    1755        1074 :   mesh.clear();
    1756        1074 :   mesh.set_mesh_dimension(orig_mesh_dimension);
    1757             : 
    1758             :   // If mesh.mesh_dimension()==1, it *could* be because the user
    1759             :   // constructed a Mesh without specifying a dimension (since this is
    1760             :   // allowed now) and hence it got the default dimension of 1.  In
    1761             :   // this case, we will try to infer the dimension they *really*
    1762             :   // wanted from the requested ElemType, and if they don't match, go
    1763             :   // with the ElemType.
    1764        1074 :   if (mesh.mesh_dimension() == 1)
    1765             :     {
    1766        1074 :       switch (type)
    1767             :       {
    1768         431 :       case HEX8:
    1769             :       case HEX27:
    1770             :       case TET4:
    1771             :       case TET10:
    1772             :       case TET14:
    1773         431 :         mesh.set_mesh_dimension(3);
    1774          14 :         break;
    1775         359 :       case TRI3:
    1776             :       case TRI6:
    1777             :       case TRI7:
    1778             :       case QUAD4:
    1779             :       case QUADSHELL4:
    1780             :       case QUAD8:
    1781             :       case QUADSHELL8:
    1782             :       case QUAD9:
    1783             :       case QUADSHELL9:
    1784         359 :         mesh.set_mesh_dimension(2);
    1785          12 :         break;
    1786         284 :       case EDGE2:
    1787             :       case EDGE3:
    1788             :       case EDGE4:
    1789         284 :         mesh.set_mesh_dimension(1);
    1790           8 :         break;
    1791           0 :       case INVALID_ELEM:
    1792             :         // Just keep the existing dimension
    1793           0 :         break;
    1794           0 :       default:
    1795           0 :         libmesh_error_msg("build_sphere(): Please specify a mesh dimension or a valid ElemType (EDGE{2,3,4}, TRI{3,6,7}, QUAD{4,8,9}, HEX{8,27}, TET{4,10,14})");
    1796             :       }
    1797             :     }
    1798             : 
    1799          34 :   BoundaryInfo & boundary_info = mesh.get_boundary_info();
    1800             : 
    1801             :   // Building while distributed is a little more complicated
    1802        1074 :   const bool is_replicated = mesh.is_replicated();
    1803             : 
    1804             :   // Sphere is centered at origin by default
    1805          34 :   const Point cent;
    1806             : 
    1807        2148 :   const Sphere sphere (cent, rad);
    1808             : 
    1809        1074 :   switch (mesh.mesh_dimension())
    1810             :     {
    1811             :       //-----------------------------------------------------------------
    1812             :       // Build a line in one dimension
    1813         284 :     case 1:
    1814             :       {
    1815         284 :         build_line (mesh, 3, -rad, rad, type);
    1816             : 
    1817           8 :         break;
    1818             :       }
    1819             : 
    1820             : 
    1821             : 
    1822             : 
    1823             :       //-----------------------------------------------------------------
    1824             :       // Build a circle or hollow sphere in two dimensions
    1825         359 :     case 2:
    1826             :       {
    1827             :         // For DistributedMesh, if we don't specify node IDs the Mesh
    1828             :         // will try to pick an appropriate (unique) one for us.  But
    1829             :         // since we are adding these nodes on all processors, we want
    1830             :         // to be sure they have consistent IDs across all processors.
    1831          12 :         unsigned node_id = 0;
    1832             : 
    1833         359 :         if (flat)
    1834             :           {
    1835          12 :             const Real sqrt_2     = std::sqrt(2.);
    1836         359 :             const Real rad_2      = .25*rad;
    1837         359 :             const Real rad_sqrt_2 = rad/sqrt_2;
    1838             : 
    1839             :             // (Temporary) convenient storage for node pointers
    1840         371 :             std::vector<Node *> nodes(8);
    1841             : 
    1842             :             // Point 0
    1843         371 :             nodes[0] = mesh.add_point (Point(-rad_2,-rad_2, 0.), node_id++);
    1844             : 
    1845             :             // Point 1
    1846         371 :             nodes[1] = mesh.add_point (Point( rad_2,-rad_2, 0.), node_id++);
    1847             : 
    1848             :             // Point 2
    1849         371 :             nodes[2] = mesh.add_point (Point( rad_2, rad_2, 0.), node_id++);
    1850             : 
    1851             :             // Point 3
    1852         371 :             nodes[3] = mesh.add_point (Point(-rad_2, rad_2, 0.), node_id++);
    1853             : 
    1854             :             // Point 4
    1855         371 :             nodes[4] = mesh.add_point (Point(-rad_sqrt_2,-rad_sqrt_2, 0.), node_id++);
    1856             : 
    1857             :             // Point 5
    1858         371 :             nodes[5] = mesh.add_point (Point( rad_sqrt_2,-rad_sqrt_2, 0.), node_id++);
    1859             : 
    1860             :             // Point 6
    1861         371 :             nodes[6] = mesh.add_point (Point( rad_sqrt_2, rad_sqrt_2, 0.), node_id++);
    1862             : 
    1863             :             // Point 7
    1864         371 :             nodes[7] = mesh.add_point (Point(-rad_sqrt_2, rad_sqrt_2, 0.), node_id++);
    1865             : 
    1866             :             // Build the elements & set node pointers
    1867             : 
    1868             :             // Element 0
    1869             :             {
    1870         359 :               Elem * elem0 = mesh.add_elem (Elem::build(QUAD4));
    1871         359 :               elem0->set_node(0, nodes[0]);
    1872         359 :               elem0->set_node(1, nodes[1]);
    1873         359 :               elem0->set_node(2, nodes[2]);
    1874         359 :               elem0->set_node(3, nodes[3]);
    1875             :             }
    1876             : 
    1877             :             // Element 1
    1878             :             {
    1879         359 :               Elem * elem1 = mesh.add_elem (Elem::build(QUAD4));
    1880         359 :               elem1->set_node(0, nodes[4]);
    1881         359 :               elem1->set_node(1, nodes[0]);
    1882         359 :               elem1->set_node(2, nodes[3]);
    1883         359 :               elem1->set_node(3, nodes[7]);
    1884             :             }
    1885             : 
    1886             :             // Element 2
    1887             :             {
    1888         359 :               Elem * elem2 = mesh.add_elem (Elem::build(QUAD4));
    1889         359 :               elem2->set_node(0, nodes[4]);
    1890         359 :               elem2->set_node(1, nodes[5]);
    1891         359 :               elem2->set_node(2, nodes[1]);
    1892         359 :               elem2->set_node(3, nodes[0]);
    1893             :             }
    1894             : 
    1895             :             // Element 3
    1896             :             {
    1897         359 :               Elem * elem3 = mesh.add_elem (Elem::build(QUAD4));
    1898         359 :               elem3->set_node(0, nodes[1]);
    1899         359 :               elem3->set_node(1, nodes[5]);
    1900         359 :               elem3->set_node(2, nodes[6]);
    1901         359 :               elem3->set_node(3, nodes[2]);
    1902             :             }
    1903             : 
    1904             :             // Element 4
    1905             :             {
    1906         359 :               Elem * elem4 = mesh.add_elem (Elem::build(QUAD4));
    1907         359 :               elem4->set_node(0, nodes[3]);
    1908         359 :               elem4->set_node(1, nodes[2]);
    1909         359 :               elem4->set_node(2, nodes[6]);
    1910         359 :               elem4->set_node(3, nodes[7]);
    1911             :             }
    1912             : 
    1913             :           }
    1914             :         else
    1915             :           {
    1916             :             // Create the 12 vertices of a regular unit icosahedron
    1917           0 :             Real t = 0.5 * (1 + std::sqrt(5.0));
    1918           0 :             Real s = rad / std::sqrt(1 + t*t);
    1919           0 :             t *= s;
    1920             : 
    1921           0 :             mesh.add_point (Point(-s,  t,  0), node_id++);
    1922           0 :             mesh.add_point (Point( s,  t,  0), node_id++);
    1923           0 :             mesh.add_point (Point(-s, -t,  0), node_id++);
    1924           0 :             mesh.add_point (Point( s, -t,  0), node_id++);
    1925             : 
    1926           0 :             mesh.add_point (Point( 0, -s,  t), node_id++);
    1927           0 :             mesh.add_point (Point( 0,  s,  t), node_id++);
    1928           0 :             mesh.add_point (Point( 0, -s, -t), node_id++);
    1929           0 :             mesh.add_point (Point( 0,  s, -t), node_id++);
    1930             : 
    1931           0 :             mesh.add_point (Point( t,  0, -s), node_id++);
    1932           0 :             mesh.add_point (Point( t,  0,  s), node_id++);
    1933           0 :             mesh.add_point (Point(-t,  0, -s), node_id++);
    1934           0 :             mesh.add_point (Point(-t,  0,  s), node_id++);
    1935             : 
    1936             :             // Create the 20 triangles of the icosahedron
    1937             :             static const unsigned int idx1 [6] = {11, 5, 1, 7, 10, 11};
    1938             :             static const unsigned int idx2 [6] = {9, 4, 2, 6, 8, 9};
    1939             :             static const unsigned int idx3 [6] = {1, 5, 11, 10, 7, 1};
    1940             : 
    1941           0 :             for (unsigned int i = 0; i < 5; ++i)
    1942             :               {
    1943             :                 // 5 elems around point 0
    1944           0 :                 Elem * new_elem = mesh.add_elem(Elem::build(TRI3));
    1945           0 :                 new_elem->set_node(0, mesh.node_ptr(0));
    1946           0 :                 new_elem->set_node(1, mesh.node_ptr(idx1[i]));
    1947           0 :                 new_elem->set_node(2, mesh.node_ptr(idx1[i+1]));
    1948             : 
    1949             :                 // 5 adjacent elems
    1950           0 :                 new_elem = mesh.add_elem(Elem::build(TRI3));
    1951           0 :                 new_elem->set_node(0, mesh.node_ptr(idx3[i]));
    1952           0 :                 new_elem->set_node(1, mesh.node_ptr(idx3[i+1]));
    1953           0 :                 new_elem->set_node(2, mesh.node_ptr(idx2[i]));
    1954             : 
    1955             :                 // 5 elems around point 3
    1956           0 :                 new_elem = mesh.add_elem(Elem::build(TRI3));
    1957           0 :                 new_elem->set_node(0, mesh.node_ptr(3));
    1958           0 :                 new_elem->set_node(1, mesh.node_ptr(idx2[i]));
    1959           0 :                 new_elem->set_node(2, mesh.node_ptr(idx2[i+1]));
    1960             : 
    1961             :                 // 5 adjacent elems
    1962           0 :                 new_elem = mesh.add_elem(Elem::build(TRI3));
    1963           0 :                 new_elem->set_node(0, mesh.node_ptr(idx2[i+1]));
    1964           0 :                 new_elem->set_node(1, mesh.node_ptr(idx2[i]));
    1965           0 :                 new_elem->set_node(2, mesh.node_ptr(idx3[i+1]));
    1966             :               }
    1967             :           }
    1968             : 
    1969          12 :         break;
    1970             :       } // end case 2
    1971             : 
    1972             : 
    1973             : 
    1974             : 
    1975             : 
    1976             :       //-----------------------------------------------------------------
    1977             :       // Build a sphere in three dimensions
    1978         431 :     case 3:
    1979             :       {
    1980             :         // (Currently) supported types
    1981         431 :         if (!((type == HEX8) || (type == HEX27) || (type == TET4) ||
    1982             :               (type == TET10) || (type == TET14)))
    1983             :           {
    1984           0 :             libmesh_error_msg("Error: Only HEX8/27 and TET4/10/14 are currently supported in 3D.");
    1985             :           }
    1986             : 
    1987             : 
    1988             :         // 3D analog of 2D initial grid:
    1989             :         const Real
    1990         431 :           r_small = 0.25*rad,                      //  0.25 *radius
    1991         431 :           r_med   = (0.125*std::sqrt(2.)+0.5)*rad; // .67677*radius
    1992             : 
    1993             :         // (Temporary) convenient storage for node pointers
    1994         445 :         std::vector<Node *> nodes(16);
    1995             : 
    1996             :         // For DistributedMesh, if we don't specify node IDs the Mesh
    1997             :         // will try to pick an appropriate (unique) one for us.  But
    1998             :         // since we are adding these nodes on all processors, we want
    1999             :         // to be sure they have consistent IDs across all processors.
    2000          14 :         unsigned node_id = 0;
    2001             : 
    2002             :         // Points 0-7 are the initial HEX8
    2003         445 :         nodes[0] = mesh.add_point (Point(-r_small,-r_small, -r_small), node_id++);
    2004         445 :         nodes[1] = mesh.add_point (Point( r_small,-r_small, -r_small), node_id++);
    2005         445 :         nodes[2] = mesh.add_point (Point( r_small, r_small, -r_small), node_id++);
    2006         445 :         nodes[3] = mesh.add_point (Point(-r_small, r_small, -r_small), node_id++);
    2007         445 :         nodes[4] = mesh.add_point (Point(-r_small,-r_small,  r_small), node_id++);
    2008         445 :         nodes[5] = mesh.add_point (Point( r_small,-r_small,  r_small), node_id++);
    2009         445 :         nodes[6] = mesh.add_point (Point( r_small, r_small,  r_small), node_id++);
    2010         445 :         nodes[7] = mesh.add_point (Point(-r_small, r_small,  r_small), node_id++);
    2011             : 
    2012             :         //  Points 8-15 are for the outer hexes, we number them in the same way
    2013         445 :         nodes[8]  = mesh.add_point (Point(-r_med,-r_med, -r_med), node_id++);
    2014         445 :         nodes[9]  = mesh.add_point (Point( r_med,-r_med, -r_med), node_id++);
    2015         445 :         nodes[10] = mesh.add_point (Point( r_med, r_med, -r_med), node_id++);
    2016         445 :         nodes[11] = mesh.add_point (Point(-r_med, r_med, -r_med), node_id++);
    2017         445 :         nodes[12] = mesh.add_point (Point(-r_med,-r_med,  r_med), node_id++);
    2018         445 :         nodes[13] = mesh.add_point (Point( r_med,-r_med,  r_med), node_id++);
    2019         445 :         nodes[14] = mesh.add_point (Point( r_med, r_med,  r_med), node_id++);
    2020         445 :         nodes[15] = mesh.add_point (Point(-r_med, r_med,  r_med), node_id++);
    2021             : 
    2022             :         // Now create the elements and add them to the mesh
    2023             :         // Element 0 - center element
    2024             :         {
    2025         431 :           Elem * elem0 = mesh.add_elem(Elem::build(HEX8));
    2026         431 :           elem0->set_node(0, nodes[0]);
    2027         431 :           elem0->set_node(1, nodes[1]);
    2028         431 :           elem0->set_node(2, nodes[2]);
    2029         431 :           elem0->set_node(3, nodes[3]);
    2030         431 :           elem0->set_node(4, nodes[4]);
    2031         431 :           elem0->set_node(5, nodes[5]);
    2032         431 :           elem0->set_node(6, nodes[6]);
    2033         431 :           elem0->set_node(7, nodes[7]);
    2034             :         }
    2035             : 
    2036             :         // Element 1 - "bottom"
    2037             :         {
    2038         431 :           Elem * elem1 = mesh.add_elem(Elem::build(HEX8));
    2039         431 :           elem1->set_node(0, nodes[8]);
    2040         431 :           elem1->set_node(1, nodes[9]);
    2041         431 :           elem1->set_node(2, nodes[10]);
    2042         431 :           elem1->set_node(3, nodes[11]);
    2043         431 :           elem1->set_node(4, nodes[0]);
    2044         431 :           elem1->set_node(5, nodes[1]);
    2045         431 :           elem1->set_node(6, nodes[2]);
    2046         431 :           elem1->set_node(7, nodes[3]);
    2047             :         }
    2048             : 
    2049             :         // Element 2 - "front"
    2050             :         {
    2051         431 :           Elem * elem2 = mesh.add_elem(Elem::build(HEX8));
    2052         431 :           elem2->set_node(0, nodes[8]);
    2053         431 :           elem2->set_node(1, nodes[9]);
    2054         431 :           elem2->set_node(2, nodes[1]);
    2055         431 :           elem2->set_node(3, nodes[0]);
    2056         431 :           elem2->set_node(4, nodes[12]);
    2057         431 :           elem2->set_node(5, nodes[13]);
    2058         431 :           elem2->set_node(6, nodes[5]);
    2059         431 :           elem2->set_node(7, nodes[4]);
    2060             :         }
    2061             : 
    2062             :         // Element 3 - "right"
    2063             :         {
    2064         431 :           Elem * elem3 = mesh.add_elem(Elem::build(HEX8));
    2065         431 :           elem3->set_node(0, nodes[1]);
    2066         431 :           elem3->set_node(1, nodes[9]);
    2067         431 :           elem3->set_node(2, nodes[10]);
    2068         431 :           elem3->set_node(3, nodes[2]);
    2069         431 :           elem3->set_node(4, nodes[5]);
    2070         431 :           elem3->set_node(5, nodes[13]);
    2071         431 :           elem3->set_node(6, nodes[14]);
    2072         431 :           elem3->set_node(7, nodes[6]);
    2073             :         }
    2074             : 
    2075             :         // Element 4 - "back"
    2076             :         {
    2077         431 :           Elem * elem4 = mesh.add_elem(Elem::build(HEX8));
    2078         431 :           elem4->set_node(0, nodes[3]);
    2079         431 :           elem4->set_node(1, nodes[2]);
    2080         431 :           elem4->set_node(2, nodes[10]);
    2081         431 :           elem4->set_node(3, nodes[11]);
    2082         431 :           elem4->set_node(4, nodes[7]);
    2083         431 :           elem4->set_node(5, nodes[6]);
    2084         431 :           elem4->set_node(6, nodes[14]);
    2085         431 :           elem4->set_node(7, nodes[15]);
    2086             :         }
    2087             : 
    2088             :         // Element 5 - "left"
    2089             :         {
    2090         431 :           Elem * elem5 = mesh.add_elem(Elem::build(HEX8));
    2091         431 :           elem5->set_node(0, nodes[8]);
    2092         431 :           elem5->set_node(1, nodes[0]);
    2093         431 :           elem5->set_node(2, nodes[3]);
    2094         431 :           elem5->set_node(3, nodes[11]);
    2095         431 :           elem5->set_node(4, nodes[12]);
    2096         431 :           elem5->set_node(5, nodes[4]);
    2097         431 :           elem5->set_node(6, nodes[7]);
    2098         431 :           elem5->set_node(7, nodes[15]);
    2099             :         }
    2100             : 
    2101             :         // Element 6 - "top"
    2102             :         {
    2103         431 :           Elem * elem6 = mesh.add_elem(Elem::build(HEX8));
    2104         431 :           elem6->set_node(0, nodes[4]);
    2105         431 :           elem6->set_node(1, nodes[5]);
    2106         431 :           elem6->set_node(2, nodes[6]);
    2107         431 :           elem6->set_node(3, nodes[7]);
    2108         431 :           elem6->set_node(4, nodes[12]);
    2109         431 :           elem6->set_node(5, nodes[13]);
    2110         431 :           elem6->set_node(6, nodes[14]);
    2111         431 :           elem6->set_node(7, nodes[15]);
    2112             :         }
    2113             : 
    2114          14 :         break;
    2115             :       } // end case 3
    2116             : 
    2117           0 :     default:
    2118           0 :       libmesh_error_msg("Unknown dimension " << mesh.mesh_dimension());
    2119             : 
    2120             : 
    2121             : 
    2122             :     } // end switch (dim)
    2123             : 
    2124             :   // Now we have the beginnings of a sphere.
    2125             :   // Add some more elements by doing uniform refinements and
    2126             :   // popping nodes to the boundary.
    2127        2148 :   MeshRefinement mesh_refinement (mesh);
    2128             : 
    2129             :   // For avoiding extraneous element side construction
    2130        1074 :   std::unique_ptr<Elem> side;
    2131             : 
    2132             :   // Loop over the elements, refine, pop nodes to boundary.
    2133        3147 :   for (unsigned int r=0; r<nr; r++)
    2134             :     {
    2135             :       // A DistributedMesh needs a little prep before refinement, and
    2136             :       // may need us to keep track of ghost node movement.
    2137         128 :       std::unordered_set<dof_id_type> moved_ghost_nodes;
    2138        2073 :       if (!is_replicated)
    2139        1172 :         mesh.prepare_for_use();
    2140             : 
    2141        2073 :       mesh_refinement.uniformly_refine(1);
    2142             : 
    2143      345068 :       for (const auto & elem : mesh.active_element_ptr_range())
    2144     1198169 :         for (auto s : elem->side_index_range())
    2145     1054972 :           if (elem->neighbor_ptr(s) == nullptr || (mesh.mesh_dimension() == 2 && !flat))
    2146             :             {
    2147       41893 :               elem->build_side_ptr(side, s);
    2148             : 
    2149             :               // Pop each point to the sphere boundary.  Keep track of
    2150             :               // any points we don't own, so we can push their "moved"
    2151             :               // status to their owners.
    2152      197794 :               for (auto n : side->node_index_range())
    2153             :                 {
    2154        6552 :                   Node & side_node = side->node_ref(n);
    2155             :                   side_node =
    2156      155901 :                     sphere.closest_point(side->point(n));
    2157             : 
    2158      157381 :                   if (!is_replicated &&
    2159       71061 :                       side_node.processor_id() != mesh.processor_id())
    2160       50485 :                     moved_ghost_nodes.insert(side_node.id());
    2161             :                 }
    2162        1945 :             }
    2163             : 
    2164        2073 :       if (!is_replicated)
    2165             :         {
    2166          24 :           std::map<processor_id_type, std::vector<dof_id_type>> moved_nodes_map;
    2167       17801 :           for (auto id : moved_ghost_nodes)
    2168             :             {
    2169       16629 :               const Node & node = mesh.node_ref(id);
    2170       16629 :               moved_nodes_map[node.processor_id()].push_back(node.id());
    2171             :             }
    2172             : 
    2173             :           auto action_functor =
    2174        3454 :             [& mesh, & sphere]
    2175             :             (processor_id_type /* pid */,
    2176       33794 :              const std::vector<dof_id_type> & my_moved_nodes)
    2177             :             {
    2178       20115 :               for (auto id : my_moved_nodes)
    2179             :                 {
    2180       16629 :                   Node & node = mesh.node_ref(id);
    2181       16629 :                   node = sphere.closest_point(node);
    2182             :                 }
    2183        1180 :             };
    2184             : 
    2185             :           // First get new node positions to their owners
    2186             :           Parallel::push_parallel_vector_data
    2187        1172 :             (mesh.comm(), moved_nodes_map, action_functor);
    2188             : 
    2189             :           // Then get node positions to anyone else with them ghosted
    2190        1172 :           SyncNodalPositions sync_object(mesh);
    2191             :           Parallel::sync_dofobject_data_by_id
    2192        2320 :             (mesh.comm(), mesh.nodes_begin(), mesh.nodes_end(),
    2193             :              sync_object);
    2194             :         }
    2195             :     }
    2196             : 
    2197             :   // A DistributedMesh needs a little prep before flattening
    2198        1074 :   if (is_replicated)
    2199         456 :     mesh.prepare_for_use();
    2200             : 
    2201             :   // The mesh now contains a refinement hierarchy due to the refinements
    2202             :   // used to generate the grid.  In order to call other support functions
    2203             :   // like all_tri() and all_second_order, you need a "flat" mesh file (with no
    2204             :   // refinement trees) so
    2205        1074 :   MeshTools::Modification::flatten(mesh);
    2206             : 
    2207             :   // Convert all the tensor product elements to simplices if requested
    2208        1074 :   if ((type == TRI7) || (type == TRI6) || (type == TRI3) ||
    2209          60 :       (type == TET4) || (type == TET10) || (type == TET14))
    2210             :     {
    2211             :       // A DistributedMesh needs a little prep before all_tri()
    2212         284 :       if (is_replicated)
    2213          85 :         mesh.prepare_for_use();
    2214             : 
    2215         284 :       MeshTools::Modification::all_tri(mesh);
    2216             :     }
    2217             : 
    2218             :   // Convert to second-order elements if the user requested it.
    2219        1108 :   if (Elem::build(type)->default_order() != FIRST)
    2220             :     {
    2221         364 :       if (type == TET14)
    2222           0 :         mesh.all_complete_order();
    2223             :       else
    2224             :         {
    2225             :           // type is second-order, determine if it is the
    2226             :           // "full-ordered" second-order element, or the "serendipity"
    2227             :           // second order element.  Note also that all_second_order
    2228             :           // can't be called once the mesh has been refined.
    2229         364 :           bool full_ordered = !((type==QUAD8) || (type==HEX20));
    2230         364 :           mesh.all_second_order(full_ordered);
    2231             :         }
    2232             : 
    2233             :       // And pop to the boundary again...
    2234       91242 :       for (const auto & elem : mesh.active_element_ptr_range())
    2235      331060 :         for (auto s : elem->side_index_range())
    2236      295556 :           if (elem->neighbor_ptr(s) == nullptr)
    2237             :             {
    2238       10024 :               elem->build_side_ptr(side, s);
    2239             : 
    2240             :               // Pop each point to the sphere boundary
    2241       97080 :               for (auto n : side->node_index_range())
    2242       91766 :                 side->point(n) =
    2243       91766 :                   sphere.closest_point(side->point(n));
    2244         336 :             }
    2245             :     }
    2246             : 
    2247             : 
    2248             :   // The meshes could probably use some smoothing.
    2249        1074 :   if (mesh.mesh_dimension() > 1)
    2250             :     {
    2251         816 :       LaplaceMeshSmoother smoother(mesh);
    2252         790 :       smoother.smooth(n_smooth);
    2253             :     }
    2254             : 
    2255             :   // We'll give the whole sphere surface a boundary id of 0
    2256      725146 :   for (const auto & elem : mesh.active_element_ptr_range())
    2257     2060914 :     for (auto s : elem->side_index_range())
    2258     1737734 :       if (!elem->neighbor_ptr(s))
    2259       41714 :         boundary_info.add_side(elem, s, 0);
    2260             : 
    2261             :   // Done building the mesh.  Now prepare it for use.
    2262        1074 :   mesh.prepare_for_use();
    2263        1074 : }
    2264             : 
    2265             : #endif // #ifndef LIBMESH_ENABLE_AMR
    2266             : 
    2267             : 
    2268             : // Meshes the tensor product of a 1D and a 1D-or-2D domain.
    2269         355 : void MeshTools::Generation::build_extrusion (UnstructuredMesh & mesh,
    2270             :                                              const MeshBase & cross_section,
    2271             :                                              const unsigned int nz,
    2272             :                                              RealVectorValue extrusion_vector,
    2273             :                                              QueryElemSubdomainIDBase * elem_subdomain)
    2274             : {
    2275          10 :   LOG_SCOPE("build_extrusion()", "MeshTools::Generation");
    2276             : 
    2277         355 :   if (!cross_section.n_elem())
    2278           0 :     return;
    2279             : 
    2280         355 :   dof_id_type orig_elem = cross_section.n_elem();
    2281         355 :   dof_id_type orig_nodes = cross_section.n_nodes();
    2282             : 
    2283             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    2284         355 :   unique_id_type orig_unique_ids = cross_section.parallel_max_unique_id();
    2285             : #endif
    2286             : 
    2287         355 :   unsigned int order = 1;
    2288             : 
    2289          10 :   BoundaryInfo & boundary_info = mesh.get_boundary_info();
    2290          10 :   const BoundaryInfo & cross_section_boundary_info = cross_section.get_boundary_info();
    2291             : 
    2292             :   // Copy name maps from old to new boundary.  We won't copy the whole
    2293             :   // BoundaryInfo because that copies bc ids too, and we need to set
    2294             :   // those more carefully.
    2295          10 :   boundary_info.set_sideset_name_map() = cross_section_boundary_info.get_sideset_name_map();
    2296          10 :   boundary_info.set_nodeset_name_map() = cross_section_boundary_info.get_nodeset_name_map();
    2297          10 :   boundary_info.set_edgeset_name_map() = cross_section_boundary_info.get_edgeset_name_map();
    2298             : 
    2299             :   // If cross_section is distributed, so is its extrusion
    2300         355 :   if (!cross_section.is_serial())
    2301         256 :     mesh.delete_remote_elements();
    2302             : 
    2303             :   // We know a priori how many elements we'll need
    2304         355 :   mesh.reserve_elem(nz*orig_elem);
    2305             : 
    2306             :   // For straightforward meshes we need one or two additional layers per
    2307             :   // element.
    2308        1310 :   if (cross_section.elements_begin() != cross_section.elements_end() &&
    2309         865 :       (*cross_section.elements_begin())->default_order() == SECOND)
    2310           0 :     order = 2;
    2311         355 :   mesh.comm().max(order);
    2312             : 
    2313         355 :   mesh.reserve_nodes((order*nz+1)*orig_nodes);
    2314             : 
    2315             :   // Container to catch the boundary IDs handed back by the BoundaryInfo object
    2316          20 :   std::vector<boundary_id_type> ids_to_copy;
    2317             : 
    2318        6478 :   for (const auto & node : cross_section.node_ptr_range())
    2319             :     {
    2320       14334 :       for (unsigned int k=0; k != order*nz+1; ++k)
    2321             :         {
    2322       11331 :           const dof_id_type new_node_id = node->id() + k * orig_nodes;
    2323       11331 :           Node * my_node = mesh.query_node_ptr(new_node_id);
    2324       11331 :           if (!my_node)
    2325             :             {
    2326             :               std::unique_ptr<Node> new_node = Node::build
    2327       11709 :                 (*node + (extrusion_vector * k / nz / order),
    2328         378 :                  new_node_id);
    2329       11331 :               new_node->processor_id() = node->processor_id();
    2330             : 
    2331             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    2332             :               // Let's give the base of the extruded mesh the same
    2333             :               // unique_ids as the source mesh, in case anyone finds that
    2334             :               // a useful map to preserve.
    2335       11331 :               const unique_id_type uid = (k == 0) ?
    2336         228 :                 node->unique_id() :
    2337        8328 :                 orig_unique_ids + (k-1)*(orig_nodes + orig_elem) + node->id();
    2338             : 
    2339         378 :               new_node->set_unique_id(uid);
    2340             : #endif
    2341             : 
    2342       11331 :               cross_section_boundary_info.boundary_ids(node, ids_to_copy);
    2343       11331 :               boundary_info.add_node(new_node.get(), ids_to_copy);
    2344             : 
    2345       12087 :               mesh.add_node(std::move(new_node));
    2346       10575 :             }
    2347             :         }
    2348         335 :     }
    2349             : 
    2350             :   const std::set<boundary_id_type> & side_ids =
    2351          10 :     cross_section_boundary_info.get_side_boundary_ids();
    2352             : 
    2353          10 :   boundary_id_type next_side_id = side_ids.empty() ?
    2354         355 :     0 : cast_int<boundary_id_type>(*side_ids.rbegin() + 1);
    2355             : 
    2356             :   // side_ids may not include ids from remote elements, in which case
    2357             :   // some processors may have underestimated the next_side_id; let's
    2358             :   // fix that.
    2359         355 :   cross_section.comm().max(next_side_id);
    2360             : 
    2361        4532 :   for (const auto & elem : cross_section.element_ptr_range())
    2362             :     {
    2363        1996 :       const ElemType etype = elem->type();
    2364             : 
    2365             :       // build_extrusion currently only works on coarse meshes
    2366          80 :       libmesh_assert (!elem->parent());
    2367             : 
    2368        7400 :       for (unsigned int k=0; k != nz; ++k)
    2369             :         {
    2370        5228 :           std::unique_ptr<Elem> new_elem;
    2371        5404 :           switch (etype)
    2372             :             {
    2373           0 :             case EDGE2:
    2374             :               {
    2375           0 :                 new_elem = Elem::build(QUAD4);
    2376           0 :                 new_elem->set_node(0, mesh.node_ptr(elem->node_ptr(0)->id() + (k * orig_nodes)));
    2377           0 :                 new_elem->set_node(1, mesh.node_ptr(elem->node_ptr(1)->id() + (k * orig_nodes)));
    2378           0 :                 new_elem->set_node(2, mesh.node_ptr(elem->node_ptr(1)->id() + ((k+1) * orig_nodes)));
    2379           0 :                 new_elem->set_node(3, mesh.node_ptr(elem->node_ptr(0)->id() + ((k+1) * orig_nodes)));
    2380             : 
    2381           0 :                 if (elem->neighbor_ptr(0) == remote_elem)
    2382           0 :                   new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
    2383           0 :                 if (elem->neighbor_ptr(1) == remote_elem)
    2384           0 :                   new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
    2385             : 
    2386           0 :                 break;
    2387             :               }
    2388           0 :             case EDGE3:
    2389             :               {
    2390           0 :                 new_elem = Elem::build(QUAD9);
    2391           0 :                 new_elem->set_node(0, mesh.node_ptr(elem->node_ptr(0)->id() + (2*k * orig_nodes)));
    2392           0 :                 new_elem->set_node(1, mesh.node_ptr(elem->node_ptr(1)->id() + (2*k * orig_nodes)));
    2393           0 :                 new_elem->set_node(2, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+2) * orig_nodes)));
    2394           0 :                 new_elem->set_node(3, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+2) * orig_nodes)));
    2395           0 :                 new_elem->set_node(4, mesh.node_ptr(elem->node_ptr(2)->id() + (2*k * orig_nodes)));
    2396           0 :                 new_elem->set_node(5, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+1) * orig_nodes)));
    2397           0 :                 new_elem->set_node(6, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+2) * orig_nodes)));
    2398           0 :                 new_elem->set_node(7, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+1) * orig_nodes)));
    2399           0 :                 new_elem->set_node(8, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+1) * orig_nodes)));
    2400             : 
    2401           0 :                 if (elem->neighbor_ptr(0) == remote_elem)
    2402           0 :                   new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
    2403           0 :                 if (elem->neighbor_ptr(1) == remote_elem)
    2404           0 :                   new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
    2405             : 
    2406           0 :                 break;
    2407             :               }
    2408         860 :             case TRI3:
    2409             :               {
    2410        1624 :                 new_elem = Elem::build(PRISM6);
    2411         908 :                 new_elem->set_node(0, mesh.node_ptr(elem->node_ptr(0)->id() + (k * orig_nodes)));
    2412         908 :                 new_elem->set_node(1, mesh.node_ptr(elem->node_ptr(1)->id() + (k * orig_nodes)));
    2413         908 :                 new_elem->set_node(2, mesh.node_ptr(elem->node_ptr(2)->id() + (k * orig_nodes)));
    2414         908 :                 new_elem->set_node(3, mesh.node_ptr(elem->node_ptr(0)->id() + ((k+1) * orig_nodes)));
    2415         908 :                 new_elem->set_node(4, mesh.node_ptr(elem->node_ptr(1)->id() + ((k+1) * orig_nodes)));
    2416         908 :                 new_elem->set_node(5, mesh.node_ptr(elem->node_ptr(2)->id() + ((k+1) * orig_nodes)));
    2417             : 
    2418         908 :                 if (elem->neighbor_ptr(0) == remote_elem)
    2419           0 :                   new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
    2420         908 :                 if (elem->neighbor_ptr(1) == remote_elem)
    2421           0 :                   new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
    2422         908 :                 if (elem->neighbor_ptr(2) == remote_elem)
    2423           0 :                   new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
    2424             : 
    2425          48 :                 break;
    2426             :               }
    2427           0 :             case TRI6:
    2428             :               {
    2429           0 :                 new_elem = Elem::build(PRISM18);
    2430           0 :                 new_elem->set_node(0, mesh.node_ptr(elem->node_ptr(0)->id() + (2*k * orig_nodes)));
    2431           0 :                 new_elem->set_node(1, mesh.node_ptr(elem->node_ptr(1)->id() + (2*k * orig_nodes)));
    2432           0 :                 new_elem->set_node(2, mesh.node_ptr(elem->node_ptr(2)->id() + (2*k * orig_nodes)));
    2433           0 :                 new_elem->set_node(3, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+2) * orig_nodes)));
    2434           0 :                 new_elem->set_node(4, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+2) * orig_nodes)));
    2435           0 :                 new_elem->set_node(5, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+2) * orig_nodes)));
    2436           0 :                 new_elem->set_node(6, mesh.node_ptr(elem->node_ptr(3)->id() + (2*k * orig_nodes)));
    2437           0 :                 new_elem->set_node(7, mesh.node_ptr(elem->node_ptr(4)->id() + (2*k * orig_nodes)));
    2438           0 :                 new_elem->set_node(8, mesh.node_ptr(elem->node_ptr(5)->id() + (2*k * orig_nodes)));
    2439           0 :                 new_elem->set_node(9, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+1) * orig_nodes)));
    2440           0 :                 new_elem->set_node(10, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+1) * orig_nodes)));
    2441           0 :                 new_elem->set_node(11, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+1) * orig_nodes)));
    2442           0 :                 new_elem->set_node(12, mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+2) * orig_nodes)));
    2443           0 :                 new_elem->set_node(13, mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+2) * orig_nodes)));
    2444           0 :                 new_elem->set_node(14, mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+2) * orig_nodes)));
    2445           0 :                 new_elem->set_node(15, mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+1) * orig_nodes)));
    2446           0 :                 new_elem->set_node(16, mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+1) * orig_nodes)));
    2447           0 :                 new_elem->set_node(17, mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+1) * orig_nodes)));
    2448             : 
    2449           0 :                 if (elem->neighbor_ptr(0) == remote_elem)
    2450           0 :                   new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
    2451           0 :                 if (elem->neighbor_ptr(1) == remote_elem)
    2452           0 :                   new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
    2453           0 :                 if (elem->neighbor_ptr(2) == remote_elem)
    2454           0 :                   new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
    2455             : 
    2456           0 :                 break;
    2457             :               }
    2458           0 :             case TRI7:
    2459             :               {
    2460           0 :                 new_elem = Elem::build(PRISM21);
    2461           0 :                 new_elem->set_node(0, mesh.node_ptr(elem->node_ptr(0)->id() + (2*k * orig_nodes)));
    2462           0 :                 new_elem->set_node(1, mesh.node_ptr(elem->node_ptr(1)->id() + (2*k * orig_nodes)));
    2463           0 :                 new_elem->set_node(2, mesh.node_ptr(elem->node_ptr(2)->id() + (2*k * orig_nodes)));
    2464           0 :                 new_elem->set_node(3, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+2) * orig_nodes)));
    2465           0 :                 new_elem->set_node(4, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+2) * orig_nodes)));
    2466           0 :                 new_elem->set_node(5, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+2) * orig_nodes)));
    2467           0 :                 new_elem->set_node(6, mesh.node_ptr(elem->node_ptr(3)->id() + (2*k * orig_nodes)));
    2468           0 :                 new_elem->set_node(7, mesh.node_ptr(elem->node_ptr(4)->id() + (2*k * orig_nodes)));
    2469           0 :                 new_elem->set_node(8, mesh.node_ptr(elem->node_ptr(5)->id() + (2*k * orig_nodes)));
    2470           0 :                 new_elem->set_node(9, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+1) * orig_nodes)));
    2471           0 :                 new_elem->set_node(10, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+1) * orig_nodes)));
    2472           0 :                 new_elem->set_node(11, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+1) * orig_nodes)));
    2473           0 :                 new_elem->set_node(12, mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+2) * orig_nodes)));
    2474           0 :                 new_elem->set_node(13, mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+2) * orig_nodes)));
    2475           0 :                 new_elem->set_node(14, mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+2) * orig_nodes)));
    2476           0 :                 new_elem->set_node(15, mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+1) * orig_nodes)));
    2477           0 :                 new_elem->set_node(16, mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+1) * orig_nodes)));
    2478           0 :                 new_elem->set_node(17, mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+1) * orig_nodes)));
    2479             : 
    2480           0 :                 new_elem->set_node(18, mesh.node_ptr(elem->node_ptr(6)->id() + (2*k * orig_nodes)));
    2481           0 :                 new_elem->set_node(19, mesh.node_ptr(elem->node_ptr(6)->id() + ((2*k+2) * orig_nodes)));
    2482           0 :                 new_elem->set_node(20, mesh.node_ptr(elem->node_ptr(6)->id() + ((2*k+1) * orig_nodes)));
    2483             : 
    2484           0 :                 if (elem->neighbor_ptr(0) == remote_elem)
    2485           0 :                   new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
    2486           0 :                 if (elem->neighbor_ptr(1) == remote_elem)
    2487           0 :                   new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
    2488           0 :                 if (elem->neighbor_ptr(2) == remote_elem)
    2489           0 :                   new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
    2490             : 
    2491           0 :                 break;
    2492             :               }
    2493        4544 :             case QUAD4:
    2494             :               {
    2495        8832 :                 new_elem = Elem::build(HEX8);
    2496        4672 :                 new_elem->set_node(0, mesh.node_ptr(elem->node_ptr(0)->id() + (k * orig_nodes)));
    2497        4672 :                 new_elem->set_node(1, mesh.node_ptr(elem->node_ptr(1)->id() + (k * orig_nodes)));
    2498        4672 :                 new_elem->set_node(2, mesh.node_ptr(elem->node_ptr(2)->id() + (k * orig_nodes)));
    2499        4672 :                 new_elem->set_node(3, mesh.node_ptr(elem->node_ptr(3)->id() + (k * orig_nodes)));
    2500        4672 :                 new_elem->set_node(4, mesh.node_ptr(elem->node_ptr(0)->id() + ((k+1) * orig_nodes)));
    2501        4672 :                 new_elem->set_node(5, mesh.node_ptr(elem->node_ptr(1)->id() + ((k+1) * orig_nodes)));
    2502        4672 :                 new_elem->set_node(6, mesh.node_ptr(elem->node_ptr(2)->id() + ((k+1) * orig_nodes)));
    2503        4672 :                 new_elem->set_node(7, mesh.node_ptr(elem->node_ptr(3)->id() + ((k+1) * orig_nodes)));
    2504             : 
    2505        4672 :                 if (elem->neighbor_ptr(0) == remote_elem)
    2506           0 :                   new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
    2507        4672 :                 if (elem->neighbor_ptr(1) == remote_elem)
    2508           0 :                   new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
    2509        4672 :                 if (elem->neighbor_ptr(2) == remote_elem)
    2510           0 :                   new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
    2511        4672 :                 if (elem->neighbor_ptr(3) == remote_elem)
    2512           0 :                   new_elem->set_neighbor(4, const_cast<RemoteElem *>(remote_elem));
    2513             : 
    2514         128 :                 break;
    2515             :               }
    2516           0 :             case QUAD9:
    2517             :               {
    2518           0 :                 new_elem = Elem::build(HEX27);
    2519           0 :                 new_elem->set_node(0, mesh.node_ptr(elem->node_ptr(0)->id() + (2*k * orig_nodes)));
    2520           0 :                 new_elem->set_node(1, mesh.node_ptr(elem->node_ptr(1)->id() + (2*k * orig_nodes)));
    2521           0 :                 new_elem->set_node(2, mesh.node_ptr(elem->node_ptr(2)->id() + (2*k * orig_nodes)));
    2522           0 :                 new_elem->set_node(3, mesh.node_ptr(elem->node_ptr(3)->id() + (2*k * orig_nodes)));
    2523           0 :                 new_elem->set_node(4, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+2) * orig_nodes)));
    2524           0 :                 new_elem->set_node(5, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+2) * orig_nodes)));
    2525           0 :                 new_elem->set_node(6, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+2) * orig_nodes)));
    2526           0 :                 new_elem->set_node(7, mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+2) * orig_nodes)));
    2527           0 :                 new_elem->set_node(8, mesh.node_ptr(elem->node_ptr(4)->id() + (2*k * orig_nodes)));
    2528           0 :                 new_elem->set_node(9, mesh.node_ptr(elem->node_ptr(5)->id() + (2*k * orig_nodes)));
    2529           0 :                 new_elem->set_node(10, mesh.node_ptr(elem->node_ptr(6)->id() + (2*k * orig_nodes)));
    2530           0 :                 new_elem->set_node(11, mesh.node_ptr(elem->node_ptr(7)->id() + (2*k * orig_nodes)));
    2531           0 :                 new_elem->set_node(12, mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+1) * orig_nodes)));
    2532           0 :                 new_elem->set_node(13, mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+1) * orig_nodes)));
    2533           0 :                 new_elem->set_node(14, mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+1) * orig_nodes)));
    2534           0 :                 new_elem->set_node(15, mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+1) * orig_nodes)));
    2535           0 :                 new_elem->set_node(16, mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+2) * orig_nodes)));
    2536           0 :                 new_elem->set_node(17, mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+2) * orig_nodes)));
    2537           0 :                 new_elem->set_node(18, mesh.node_ptr(elem->node_ptr(6)->id() + ((2*k+2) * orig_nodes)));
    2538           0 :                 new_elem->set_node(19, mesh.node_ptr(elem->node_ptr(7)->id() + ((2*k+2) * orig_nodes)));
    2539           0 :                 new_elem->set_node(20, mesh.node_ptr(elem->node_ptr(8)->id() + (2*k * orig_nodes)));
    2540           0 :                 new_elem->set_node(21, mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+1) * orig_nodes)));
    2541           0 :                 new_elem->set_node(22, mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+1) * orig_nodes)));
    2542           0 :                 new_elem->set_node(23, mesh.node_ptr(elem->node_ptr(6)->id() + ((2*k+1) * orig_nodes)));
    2543           0 :                 new_elem->set_node(24, mesh.node_ptr(elem->node_ptr(7)->id() + ((2*k+1) * orig_nodes)));
    2544           0 :                 new_elem->set_node(25, mesh.node_ptr(elem->node_ptr(8)->id() + ((2*k+2) * orig_nodes)));
    2545           0 :                 new_elem->set_node(26, mesh.node_ptr(elem->node_ptr(8)->id() + ((2*k+1) * orig_nodes)));
    2546             : 
    2547           0 :                 if (elem->neighbor_ptr(0) == remote_elem)
    2548           0 :                   new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
    2549           0 :                 if (elem->neighbor_ptr(1) == remote_elem)
    2550           0 :                   new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
    2551           0 :                 if (elem->neighbor_ptr(2) == remote_elem)
    2552           0 :                   new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
    2553           0 :                 if (elem->neighbor_ptr(3) == remote_elem)
    2554           0 :                   new_elem->set_neighbor(4, const_cast<RemoteElem *>(remote_elem));
    2555             : 
    2556           0 :                 break;
    2557             :               }
    2558           0 :             default:
    2559             :               {
    2560           0 :                 libmesh_not_implemented();
    2561             :                 break;
    2562             :               }
    2563             :             }
    2564             : 
    2565        5404 :           new_elem->set_id(elem->id() + (k * orig_elem));
    2566        5404 :           new_elem->processor_id() = elem->processor_id();
    2567             : 
    2568             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    2569             :           // Let's give the base of the extruded mesh the same
    2570             :           // unique_ids as the source mesh, in case anyone finds that
    2571             :           // a useful map to preserve.
    2572        5404 :           const unique_id_type uid = (k == 0) ?
    2573         160 :             elem->unique_id() :
    2574        3408 :             orig_unique_ids + (k-1)*(orig_nodes + orig_elem) + orig_nodes + elem->id();
    2575             : 
    2576         176 :           new_elem->set_unique_id(uid);
    2577             : #endif
    2578             : 
    2579        5404 :           if (!elem_subdomain)
    2580             :             // maintain the subdomain_id
    2581         860 :             new_elem->subdomain_id() = elem->subdomain_id();
    2582             :           else
    2583             :             // Allow the user to choose new subdomain_ids
    2584        4544 :             new_elem->subdomain_id() = elem_subdomain->get_subdomain_for_layer(elem, k);
    2585             : 
    2586        5580 :           Elem * added_elem = mesh.add_elem(std::move(new_elem));
    2587             : 
    2588             :           // Copy any old boundary ids on all sides
    2589       26336 :           for (auto s : elem->side_index_range())
    2590             :             {
    2591       20756 :               cross_section_boundary_info.boundary_ids(elem, s, ids_to_copy);
    2592             : 
    2593       20756 :               if (added_elem->dim() == 3)
    2594             :                 {
    2595             :                   // For 2D->3D extrusion, we give the boundary IDs
    2596             :                   // for side s on the old element to side s+1 on the
    2597             :                   // new element.  This is just a happy coincidence as
    2598             :                   // far as I can tell...
    2599       20756 :                   boundary_info.add_side(added_elem,
    2600       20100 :                                          cast_int<unsigned short>(s+1),
    2601             :                                          ids_to_copy);
    2602             :                 }
    2603             :               else
    2604             :                 {
    2605             :                   // For 1D->2D extrusion, the boundary IDs map as:
    2606             :                   // Old elem -> New elem
    2607             :                   // 0        -> 3
    2608             :                   // 1        -> 1
    2609           0 :                   libmesh_assert_less(s, 2);
    2610           0 :                   const unsigned short sidemap[2] = {3, 1};
    2611           0 :                   boundary_info.add_side(added_elem, sidemap[s], ids_to_copy);
    2612             :                 }
    2613             :             }
    2614             : 
    2615             :           // Give new boundary ids to bottom and top
    2616        5404 :           if (k == 0)
    2617        1996 :             boundary_info.add_side(added_elem, 0, next_side_id);
    2618        5404 :           if (k == nz-1)
    2619             :             {
    2620             :               // For 2D->3D extrusion, the "top" ID is 1+the original
    2621             :               // element's number of sides.  For 1D->2D extrusion, the
    2622             :               // "top" ID is side 2.
    2623        1996 :               const unsigned short top_id = added_elem->dim() == 3 ?
    2624        1996 :                 cast_int<unsigned short>(elem->n_sides()+1) : 2;
    2625             :               boundary_info.add_side
    2626        1996 :                 (added_elem, top_id,
    2627        1996 :                  cast_int<boundary_id_type>(next_side_id+1));
    2628             :             }
    2629        5052 :         }
    2630         335 :     }
    2631             : 
    2632             :   // Done building the mesh.  Now prepare it for use.
    2633         355 :   mesh.prepare_for_use();
    2634             : }
    2635             : 
    2636             : 
    2637             : 
    2638             : 
    2639             : #if defined(LIBMESH_HAVE_TRIANGLE) && LIBMESH_DIM > 1
    2640             : 
    2641             : // Triangulates a 2D rectangular region with or without holes
    2642           0 : void MeshTools::Generation::build_delaunay_square(UnstructuredMesh & mesh,
    2643             :                                                   const unsigned int nx, // num. of elements in x-dir
    2644             :                                                   const unsigned int ny, // num. of elements in y-dir
    2645             :                                                   const Real xmin, const Real xmax,
    2646             :                                                   const Real ymin, const Real ymax,
    2647             :                                                   const ElemType type,
    2648             :                                                   const std::vector<TriangleInterface::Hole*> * holes)
    2649             : {
    2650             :   // Check for reasonable size
    2651           0 :   libmesh_assert_greater_equal (nx, 1); // need at least 1 element in x-direction
    2652           0 :   libmesh_assert_greater_equal (ny, 1); // need at least 1 element in y-direction
    2653           0 :   libmesh_assert_less (xmin, xmax);
    2654           0 :   libmesh_assert_less (ymin, ymax);
    2655             : 
    2656             :   // Clear out any data which may have been in the Mesh
    2657           0 :   mesh.clear();
    2658             : 
    2659           0 :   BoundaryInfo & boundary_info = mesh.get_boundary_info();
    2660             : 
    2661             :   // Make sure the new Mesh will be 2D
    2662           0 :   mesh.set_mesh_dimension(2);
    2663             : 
    2664             :   // The x and y spacing between boundary points
    2665           0 :   const Real delta_x = (xmax-xmin) / static_cast<Real>(nx);
    2666           0 :   const Real delta_y = (ymax-ymin) / static_cast<Real>(ny);
    2667             : 
    2668             :   // Bottom
    2669           0 :   for (unsigned int p=0; p<=nx; ++p)
    2670           0 :     mesh.add_point(Point(xmin + p*delta_x, ymin));
    2671             : 
    2672             :   // Right side
    2673           0 :   for (unsigned int p=1; p<ny; ++p)
    2674           0 :     mesh.add_point(Point(xmax, ymin + p*delta_y));
    2675             : 
    2676             :   // Top
    2677           0 :   for (unsigned int p=0; p<=nx; ++p)
    2678           0 :     mesh.add_point(Point(xmax - p*delta_x, ymax));
    2679             : 
    2680             :   // Left side
    2681           0 :   for (unsigned int p=1; p<ny; ++p)
    2682           0 :     mesh.add_point(Point(xmin,  ymax - p*delta_y));
    2683             : 
    2684             :   // Be sure we added as many points as we thought we did
    2685           0 :   libmesh_assert_equal_to (mesh.n_nodes(), 2*(nx+ny));
    2686             : 
    2687             :   // Construct the Triangle Interface object
    2688           0 :   TriangleInterface t(mesh);
    2689             : 
    2690             :   // Set custom variables for the triangulation
    2691           0 :   t.desired_area()       = 0.5 * (xmax-xmin)*(ymax-ymin) / static_cast<Real>(nx*ny);
    2692           0 :   t.triangulation_type() = TriangleInterface::PSLG;
    2693           0 :   t.elem_type()          = type;
    2694             : 
    2695           0 :   if (holes != nullptr)
    2696           0 :     t.attach_hole_list(holes);
    2697             : 
    2698             :   // Triangulate!
    2699           0 :   t.triangulate();
    2700             : 
    2701             :   // For avoiding extraneous side element construction
    2702           0 :   std::unique_ptr<const Elem> side;
    2703             : 
    2704             :   // The mesh is now generated, but we still need to mark the boundaries
    2705             :   // to be consistent with the other build_square routines.  Note that all
    2706             :   // hole boundary elements get the same ID, 4.
    2707           0 :   for (auto & elem : mesh.element_ptr_range())
    2708           0 :     for (auto s : elem->side_index_range())
    2709           0 :       if (elem->neighbor_ptr(s) == nullptr)
    2710             :         {
    2711           0 :           elem->build_side_ptr(side, s);
    2712             : 
    2713             :           // Check the location of the side's midpoint.  Since
    2714             :           // the square has straight sides, the midpoint is not
    2715             :           // on the corner and thus it is uniquely on one of the
    2716             :           // sides.
    2717           0 :           Point side_midpoint= 0.5f*( side->point(0) + side->point(1) );
    2718             : 
    2719             :           // The boundary ids are set following the same convention as Quad4 sides
    2720             :           // bottom = 0
    2721             :           // right  = 1
    2722             :           // top = 2
    2723             :           // left = 3
    2724             :           // hole = 4
    2725           0 :           boundary_id_type bc_id=4;
    2726             : 
    2727             :           // bottom
    2728           0 :           if      (std::fabs(side_midpoint(1) - ymin) < TOLERANCE)
    2729           0 :             bc_id=0;
    2730             : 
    2731             :           // right
    2732           0 :           else if (std::fabs(side_midpoint(0) - xmax) < TOLERANCE)
    2733           0 :             bc_id=1;
    2734             : 
    2735             :           // top
    2736           0 :           else if (std::fabs(side_midpoint(1) - ymax) < TOLERANCE)
    2737           0 :             bc_id=2;
    2738             : 
    2739             :           // left
    2740           0 :           else if (std::fabs(side_midpoint(0) - xmin) < TOLERANCE)
    2741           0 :             bc_id=3;
    2742             : 
    2743             :           // If the point is not on any of the external boundaries, it
    2744             :           // is on one of the holes....
    2745             : 
    2746             :           // Finally, add this element's information to the boundary info object.
    2747           0 :           boundary_info.add_side(elem->id(), s, bc_id);
    2748             :         }
    2749             : 
    2750           0 : } // end build_delaunay_square
    2751             : 
    2752             : #endif // LIBMESH_HAVE_TRIANGLE && LIBMESH_DIM > 1
    2753             : 
    2754             : 
    2755         307 : void MeshTools::Generation::surface_octahedron
    2756             :   (UnstructuredMesh & mesh,
    2757             :    Real xmin, Real xmax,
    2758             :    Real ymin, Real ymax,
    2759             :    Real zmin, Real zmax,
    2760             :    bool flip_tris)
    2761             : {
    2762         307 :   const Real xavg = (xmin + xmax)/2;
    2763         307 :   const Real yavg = (ymin + ymax)/2;
    2764         307 :   const Real zavg = (zmin + zmax)/2;
    2765         317 :   mesh.add_point(Point(xavg,yavg,zmin), 0);
    2766         317 :   mesh.add_point(Point(xmax,yavg,zavg), 1);
    2767         317 :   mesh.add_point(Point(xavg,ymax,zavg), 2);
    2768         317 :   mesh.add_point(Point(xmin,yavg,zavg), 3);
    2769         317 :   mesh.add_point(Point(xavg,ymin,zavg), 4);
    2770         317 :   mesh.add_point(Point(xavg,yavg,zmax), 5);
    2771             : 
    2772       12920 :   auto add_tri = [&mesh, flip_tris](std::array<dof_id_type,3> nodes)
    2773             :   {
    2774        2456 :     auto elem = mesh.add_elem(Elem::build(TRI3));
    2775        2456 :     elem->set_node(0, mesh.node_ptr(nodes[0]));
    2776        2456 :     elem->set_node(1, mesh.node_ptr(nodes[1]));
    2777        2456 :     elem->set_node(2, mesh.node_ptr(nodes[2]));
    2778        2456 :     if (flip_tris)
    2779           0 :       elem->flip(&mesh.get_boundary_info());
    2780        2466 :   };
    2781             : 
    2782         307 :   add_tri({0,2,1});
    2783         307 :   add_tri({0,3,2});
    2784         307 :   add_tri({0,4,3});
    2785         307 :   add_tri({0,1,4});
    2786         307 :   add_tri({5,4,1});
    2787         307 :   add_tri({5,3,4});
    2788         307 :   add_tri({5,2,3});
    2789         307 :   add_tri({5,1,2});
    2790             : 
    2791         307 :   mesh.prepare_for_use();
    2792         307 : }
    2793             : 
    2794             : 
    2795             : } // namespace libMesh

Generated by: LCOV version 1.14