LCOV - code coverage report
Current view: top level - src/meshgenerators - RevolveGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #31405 (292dce) with base fef103 Lines: 1115 1204 92.6 %
Date: 2025-09-04 07:56:24 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "RevolveGenerator.h"
      11             : #include "PolygonalMeshGenerationUtils.h"
      12             : 
      13             : #include "libmesh/cell_prism6.h"
      14             : #include "libmesh/cell_prism15.h"
      15             : #include "libmesh/cell_prism18.h"
      16             : #include "libmesh/cell_prism21.h"
      17             : #include "libmesh/cell_pyramid5.h"
      18             : #include "libmesh/cell_pyramid13.h"
      19             : #include "libmesh/cell_pyramid14.h"
      20             : #include "libmesh/cell_pyramid18.h"
      21             : #include "libmesh/cell_tet4.h"
      22             : #include "libmesh/cell_tet10.h"
      23             : #include "libmesh/cell_tet14.h"
      24             : #include "libmesh/cell_hex8.h"
      25             : #include "libmesh/cell_hex20.h"
      26             : #include "libmesh/cell_hex27.h"
      27             : #include "libmesh/face_tri3.h"
      28             : #include "libmesh/face_tri7.h"
      29             : #include "libmesh/face_quad4.h"
      30             : #include "libmesh/face_quad9.h"
      31             : #include "libmesh/point.h"
      32             : #include "libmesh/mesh_tools.h"
      33             : 
      34             : using namespace libMesh;
      35             : 
      36             : // C++ includes
      37             : #include <cmath>
      38             : 
      39             : registerMooseObject("ReactorApp", RevolveGenerator);
      40             : 
      41             : InputParameters
      42         430 : RevolveGenerator::validParams()
      43             : {
      44         430 :   InputParameters params = PolygonMeshGeneratorBase::validParams();
      45         430 :   params.addClassDescription("This RevolveGenerator object is designed to revolve a 1D mesh into "
      46             :                              "2D, or a 2D mesh into 3D based on an axis.");
      47             : 
      48         860 :   params.addRequiredParam<MeshGeneratorName>("input", "The mesh to revolve");
      49             : 
      50         860 :   params.addRequiredParam<Point>("axis_point", "A point on the axis of revolution");
      51             : 
      52         860 :   params.addRequiredParam<Point>("axis_direction", "The direction of the axis of revolution");
      53             : 
      54         860 :   params.addRangeCheckedParam<std::vector<Real>>(
      55             :       "revolving_angles",
      56             :       "revolving_angles<=360.0 & revolving_angles>0.0",
      57             :       "The angles delineating each azimuthal section of revolution around the axis in degrees");
      58             : 
      59         860 :   params.addParam<std::vector<std::vector<subdomain_id_type>>>(
      60             :       "subdomain_swaps",
      61             :       {},
      62             :       "For each row, every two entries are interpreted as a pair of "
      63             :       "'from' and 'to' to remap the subdomains for that azimuthal section");
      64             : 
      65         860 :   params.addParam<std::vector<std::vector<boundary_id_type>>>(
      66             :       "boundary_swaps",
      67             :       {},
      68             :       "For each row, every two entries are interpreted as a pair of "
      69             :       "'from' and 'to' to remap the boundaries for that elevation");
      70             : 
      71         860 :   params.addParam<std::vector<std::string>>(
      72             :       "elem_integer_names_to_swap",
      73             :       {},
      74             :       "Array of element extra integer names that need to be swapped during revolving.");
      75             : 
      76         860 :   params.addParam<std::vector<std::vector<std::vector<dof_id_type>>>>(
      77             :       "elem_integers_swaps",
      78             :       {},
      79             :       "For each row, every two entries are interpreted as a pair of 'from' and 'to' to remap the "
      80             :       "element extra integer for that elevation. If multiple element extra integers need to be "
      81             :       "swapped, the enties are stacked based on the order provided in "
      82             :       "'elem_integer_names_to_swap' to form the third dimension.");
      83             : 
      84         860 :   params.addParam<boundary_id_type>(
      85             :       "start_boundary",
      86             :       "The boundary ID to set on the starting boundary for a partial revolution.");
      87             : 
      88         860 :   params.addParam<boundary_id_type>(
      89             :       "end_boundary", "The boundary ID to set on the ending boundary for partial revolving.");
      90             : 
      91         860 :   params.addParam<bool>(
      92         860 :       "clockwise", true, "Revolve clockwise around the axis or not (i.e., counterclockwise)");
      93             : 
      94         860 :   params.addRequiredParam<std::vector<unsigned int>>(
      95             :       "nums_azimuthal_intervals",
      96             :       "List of the numbers of azimuthal interval discretization for each azimuthal section");
      97             : 
      98         860 :   params.addParam<bool>("preserve_volumes",
      99         860 :                         false,
     100             :                         "Whether the volume of the revolved mesh is preserving the circular area "
     101             :                         "by modifying (expanding) the radius to account for polygonization.");
     102             : 
     103         860 :   params.addParamNamesToGroup("start_boundary end_boundary", "Boundary Assignment");
     104         860 :   params.addParamNamesToGroup(
     105             :       "subdomain_swaps boundary_swaps elem_integer_names_to_swap elem_integers_swaps", "ID Swap");
     106             : 
     107         430 :   return params;
     108           0 : }
     109             : 
     110         215 : RevolveGenerator::RevolveGenerator(const InputParameters & parameters)
     111             :   : PolygonMeshGeneratorBase(parameters),
     112         215 :     _input(getMesh("input")),
     113         430 :     _axis_point(getParam<Point>("axis_point")),
     114         430 :     _axis_direction(getParam<Point>("axis_direction")),
     115         524 :     _revolving_angles(isParamValid("revolving_angles")
     116         215 :                           ? getParam<std::vector<Real>>("revolving_angles")
     117         215 :                           : std::vector<Real>(1, 360.0)),
     118         430 :     _subdomain_swaps(getParam<std::vector<std::vector<subdomain_id_type>>>("subdomain_swaps")),
     119         430 :     _boundary_swaps(getParam<std::vector<std::vector<boundary_id_type>>>("boundary_swaps")),
     120         430 :     _elem_integer_names_to_swap(getParam<std::vector<std::string>>("elem_integer_names_to_swap")),
     121         215 :     _elem_integers_swaps(
     122         215 :         getParam<std::vector<std::vector<std::vector<dof_id_type>>>>("elem_integers_swaps")),
     123         430 :     _clockwise(getParam<bool>("clockwise")),
     124         430 :     _nums_azimuthal_intervals(getParam<std::vector<unsigned int>>("nums_azimuthal_intervals")),
     125         430 :     _preserve_volumes(getParam<bool>("preserve_volumes")),
     126         430 :     _has_start_boundary(isParamValid("start_boundary")),
     127         448 :     _start_boundary(isParamValid("start_boundary") ? getParam<boundary_id_type>("start_boundary")
     128             :                                                    : 0),
     129         430 :     _has_end_boundary(isParamValid("end_boundary")),
     130         448 :     _end_boundary(isParamValid("end_boundary") ? getParam<boundary_id_type>("end_boundary") : 0),
     131         430 :     _radius_correction_factor(1.0)
     132             : {
     133         215 :   if (_revolving_angles.size() != _nums_azimuthal_intervals.size())
     134           0 :     paramError("nums_azimuthal_intervals",
     135             :                "The number of azimuthal intervals should be the same as the number of revolving "
     136             :                "angles.");
     137         215 :   if (_subdomain_swaps.size() && (_subdomain_swaps.size() != _nums_azimuthal_intervals.size()))
     138           0 :     paramError(
     139             :         "subdomain_swaps",
     140             :         "If specified, 'subdomain_swaps' must be the same length as 'nums_azimuthal_intervals'.");
     141             : 
     142         215 :   if (_boundary_swaps.size() && (_boundary_swaps.size() != _nums_azimuthal_intervals.size()))
     143           0 :     paramError(
     144             :         "boundary_swaps",
     145             :         "If specified, 'boundary_swaps' must be the same length as 'nums_azimuthal_intervals'.");
     146             : 
     147         233 :   for (const auto & unit_elem_integers_swaps : _elem_integers_swaps)
     148          18 :     if (unit_elem_integers_swaps.size() != _nums_azimuthal_intervals.size())
     149           0 :       paramError("elem_integers_swaps",
     150             :                  "If specified, each element of 'elem_integers_swaps' must have the same length as "
     151             :                  "the length of 'nums_azimuthal_intervals'.");
     152             : 
     153         215 :   if (_elem_integers_swaps.size() &&
     154           9 :       _elem_integers_swaps.size() != _elem_integer_names_to_swap.size())
     155           0 :     paramError("elem_integers_swaps",
     156             :                "If specified, 'elem_integers_swaps' must have the same length as the length of "
     157             :                "'elem_integer_names_to_swap'.");
     158             : 
     159         215 :   _full_circle_revolving =
     160             :       MooseUtils::absoluteFuzzyEqual(
     161             :           std::accumulate(_revolving_angles.begin(), _revolving_angles.end(), 0), 360.0)
     162             :           ? true
     163             :           : false;
     164         215 :   if (MooseUtils::absoluteFuzzyGreaterThan(
     165             :           std::accumulate(_revolving_angles.begin(), _revolving_angles.end(), 0), 360.0))
     166           0 :     paramError("revolving_angles",
     167             :                "The sum of revolving angles should be less than or equal to 360.");
     168             : 
     169         215 :   if ((_has_start_boundary && _full_circle_revolving) ||
     170         206 :       (_has_end_boundary && _full_circle_revolving))
     171           0 :     paramError("full_circle_revolving",
     172             :                "starting or ending boundaries can only be assigned for partial revolving.");
     173             : 
     174             :   try
     175             :   {
     176         215 :     MooseMeshUtils::idSwapParametersProcessor(
     177         215 :         name(), "subdomain_swaps", _subdomain_swaps, _subdomain_swap_pairs);
     178             :   }
     179           0 :   catch (const MooseException & e)
     180             :   {
     181           0 :     paramError("subdomain_swaps", e.what());
     182           0 :   }
     183             : 
     184             :   try
     185             :   {
     186         215 :     MooseMeshUtils::idSwapParametersProcessor(
     187         215 :         name(), "boundary_swaps", _boundary_swaps, _boundary_swap_pairs);
     188             :   }
     189           0 :   catch (const MooseException & e)
     190             :   {
     191           0 :     paramError("boundary_swaps", e.what());
     192           0 :   }
     193             : 
     194             :   try
     195             :   {
     196         215 :     MooseMeshUtils::extraElemIntegerSwapParametersProcessor(name(),
     197         215 :                                                             _nums_azimuthal_intervals.size(),
     198         215 :                                                             _elem_integer_names_to_swap.size(),
     199             :                                                             _elem_integers_swaps,
     200         215 :                                                             _elem_integers_swap_pairs);
     201             :   }
     202           0 :   catch (const MooseException & e)
     203             :   {
     204           0 :     paramError("elem_integers_swaps", e.what());
     205           0 :   }
     206         215 : }
     207             : 
     208             : std::unique_ptr<MeshBase>
     209         215 : RevolveGenerator::generate()
     210             : {
     211             :   // Note: Inspired by AdvancedExtruderGenerator::generate()
     212             : 
     213         215 :   auto mesh = buildMeshBaseObject();
     214             : 
     215             :   // Only works for 1D and 2D input meshes
     216         215 :   if (_input->mesh_dimension() > 2)
     217           2 :     paramError("input", "This mesh generator only works for 1D and 2D input meshes.");
     218             : 
     219         213 :   mesh->set_mesh_dimension(_input->mesh_dimension() + 1);
     220             : 
     221             :   // Check if the element integer names are existent in the input mesh.
     222         231 :   for (const auto i : index_range(_elem_integer_names_to_swap))
     223          18 :     if (_input->has_elem_integer(_elem_integer_names_to_swap[i]))
     224          18 :       _elem_integer_indices_to_swap.push_back(
     225          18 :           _input->get_elem_integer_index(_elem_integer_names_to_swap[i]));
     226             :     else
     227           0 :       paramError("elem_integer_names_to_swap",
     228             :                  "Element ",
     229             :                  i + 1,
     230             :                  " of 'elem_integer_names_to_swap' is not a valid extra element integer of the "
     231             :                  "input mesh.");
     232             : 
     233             :   // prepare for transferring extra element integers from original mesh to the revolved mesh.
     234         213 :   const unsigned int num_extra_elem_integers = _input->n_elem_integers();
     235             :   std::vector<std::string> id_names;
     236             : 
     237         231 :   for (const auto i : make_range(num_extra_elem_integers))
     238             :   {
     239          18 :     id_names.push_back(_input->get_elem_integer_name(i));
     240          18 :     if (!mesh->has_elem_integer(id_names[i]))
     241          36 :       mesh->add_elem_integer(id_names[i]);
     242             :   }
     243             : 
     244             :   // retrieve subdomain/sideset/nodeset name maps
     245         213 :   const auto & input_subdomain_map = _input->get_subdomain_name_map();
     246             :   const auto & input_sideset_map = _input->get_boundary_info().get_sideset_name_map();
     247             :   const auto & input_nodeset_map = _input->get_boundary_info().get_nodeset_name_map();
     248             : 
     249             :   std::unique_ptr<MeshBase> input = std::move(_input);
     250             : 
     251             :   // If we're using a distributed mesh... then make sure we don't have any remote elements hanging
     252             :   // around
     253         213 :   if (!input->is_serial())
     254          36 :     mesh->delete_remote_elements();
     255             : 
     256             :   // check that subdomain swap sources exist in the mesh
     257             :   std::set<subdomain_id_type> blocks;
     258         213 :   input->subdomain_ids(blocks, true);
     259         251 :   for (const auto & swap_map : _subdomain_swap_pairs)
     260          76 :     for (const auto & [bid, tbid] : swap_map)
     261             :     {
     262             :       libmesh_ignore(tbid);
     263             :       if (blocks.count(bid) == 0)
     264           2 :         paramError("subdomain_swaps",
     265           2 :                    "Source subdomain " + std::to_string(bid) + " was not found in the mesh");
     266             :     }
     267             : 
     268             :   // Subdomain IDs for on-axis elements must be new
     269             :   std::set<subdomain_id_type> subdomain_ids_set;
     270         211 :   input->subdomain_ids(subdomain_ids_set);
     271         211 :   const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
     272             :   const subdomain_id_type tri_to_pyramid_subdomain_id_shift =
     273         211 :       std::max((int)max_subdomain_id, 1) + 1;
     274             :   const subdomain_id_type tri_to_tet_subdomain_id_shift =
     275         211 :       std::max((int)max_subdomain_id, 1) * 2 + 1;
     276         211 :   const subdomain_id_type quad_to_prism_subdomain_id_shift = std::max((int)max_subdomain_id, 1) + 1;
     277             :   const subdomain_id_type quad_to_pyramid_subdomain_id_shift =
     278         211 :       std::max((int)max_subdomain_id, 1) * 2 + 1;
     279             :   const subdomain_id_type quad_to_hi_pyramid_subdomain_id_shift =
     280         211 :       std::max((int)max_subdomain_id, 1) * 3 + 1;
     281         211 :   const subdomain_id_type edge_to_tri_subdomain_id_shift = std::max((int)max_subdomain_id, 1) + 1;
     282             : 
     283             :   // Get the centroid of the input mesh
     284         211 :   const auto input_centroid = MooseMeshUtils::meshCentroidCalculator(*input);
     285         211 :   const Point axis_centroid_cross = (input_centroid - _axis_point).cross(_axis_direction);
     286             : 
     287         211 :   if (MooseUtils::absoluteFuzzyEqual(axis_centroid_cross.norm(), 0.0))
     288           2 :     mooseError("The input mesh is either across the axis or overlapped with the axis!");
     289             : 
     290             :   Real inner_product_1d(0.0);
     291             :   bool inner_product_1d_initialized(false);
     292             :   // record ids of nodes on the axis
     293             :   std::vector<dof_id_type> node_ids_on_axis;
     294        7086 :   for (const auto & node : input->node_ptr_range())
     295             :   {
     296        3342 :     const Point axis_node_cross = (*node - _axis_point).cross(_axis_direction);
     297             :     // if the cross product is zero, then the node is on the axis
     298        3342 :     if (!MooseUtils::absoluteFuzzyEqual(axis_node_cross.norm(), 0.0))
     299             :     {
     300        3066 :       if (MooseUtils::absoluteFuzzyLessThan(axis_node_cross * axis_centroid_cross, 0.0))
     301           4 :         mooseError("The input mesh is across the axis.");
     302        3062 :       else if (MooseUtils::absoluteFuzzyLessThan(axis_node_cross * axis_centroid_cross,
     303        6124 :                                                  axis_centroid_cross.norm() *
     304        3062 :                                                      axis_node_cross.norm()))
     305           2 :         mooseError("The input mesh is not in the same plane with the rotation axis.");
     306             :     }
     307             :     else
     308         276 :       node_ids_on_axis.push_back(node->id());
     309             : 
     310             :     // Only for 1D input mesh, we need to check if the axis is perpendicular to the input mesh
     311        3336 :     if (input->mesh_dimension() == 1)
     312             :     {
     313         106 :       const Real temp_inner_product = (*node - _axis_point) * _axis_direction.unit();
     314         106 :       if (inner_product_1d_initialized)
     315             :       {
     316          74 :         if (!MooseUtils::absoluteFuzzyEqual(temp_inner_product, inner_product_1d))
     317           2 :           mooseError("The 1D input mesh is not perpendicular to the rotation axis.");
     318             :       }
     319             :       else
     320             :       {
     321             :         inner_product_1d_initialized = true;
     322             :         inner_product_1d = temp_inner_product;
     323             :       }
     324             :     }
     325         201 :   }
     326             : 
     327             :   // If there are any on-axis nodes, we need to check if there are any QUAD8 elements with one
     328             :   // vertex on the axis. If so, we need to replace it with a QUAD9 element.
     329         201 :   if (!node_ids_on_axis.empty())
     330             :   {
     331             :     // Sort the vector for using set_intersection
     332         120 :     std::sort(node_ids_on_axis.begin(), node_ids_on_axis.end());
     333             :     // For QUAD8 elements with one vertex on the axis, we need to replace it with a QUAD9 element
     334             :     std::set<subdomain_id_type> converted_quad8_subdomain_ids;
     335        1184 :     for (const auto & elem : input->element_ptr_range())
     336             :     {
     337         472 :       if (elem->type() == QUAD8)
     338             :       {
     339             :         std::vector<dof_id_type> elem_vertex_node_ids;
     340         360 :         for (unsigned int i = 0; i < 4; i++)
     341             :         {
     342         288 :           elem_vertex_node_ids.push_back(elem->node_id(i));
     343             :         }
     344          72 :         std::sort(elem_vertex_node_ids.begin(), elem_vertex_node_ids.end());
     345             :         std::vector<dof_id_type> common_node_ids;
     346          72 :         std::set_intersection(node_ids_on_axis.begin(),
     347             :                               node_ids_on_axis.end(),
     348             :                               elem_vertex_node_ids.begin(),
     349             :                               elem_vertex_node_ids.end(),
     350             :                               std::back_inserter(common_node_ids));
     351             :         // Temporarily shift the subdomain ID to mark the element
     352          72 :         if (common_node_ids.size() == 1)
     353             :         {
     354             :           // we borrow quad_to_hi_pyramid_subdomain_id_shift here
     355           9 :           elem->subdomain_id() += quad_to_hi_pyramid_subdomain_id_shift;
     356           9 :           converted_quad8_subdomain_ids.emplace(elem->subdomain_id());
     357             :         }
     358          72 :       }
     359         120 :     }
     360             :     // Convert the recorded subdomains
     361         120 :     input->all_second_order_range(
     362         240 :         input->active_subdomain_set_elements_ptr_range(converted_quad8_subdomain_ids));
     363             :     // Restore the subdomain ID; we do not worry about repeated subdomain IDs because those QUAD9
     364             :     // will become PYRAMID and PRISM elements with new shifts
     365         369 :     for (auto elem : input->active_subdomain_set_elements_ptr_range(converted_quad8_subdomain_ids))
     366         129 :       elem->subdomain_id() -= quad_to_hi_pyramid_subdomain_id_shift;
     367             :   }
     368             : 
     369             :   // We should only record this info after QUAD8->QUAD9 conversion
     370         201 :   dof_id_type orig_elem = input->n_elem();
     371         201 :   dof_id_type orig_nodes = input->n_nodes();
     372             : 
     373             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     374             :   // Add the number of original elements as revolving may create two elements per layer for one
     375             :   // original element
     376         201 :   unique_id_type orig_unique_ids = input->parallel_max_unique_id() + orig_elem;
     377             : #endif
     378             : 
     379             :   // get rotation vectors
     380         201 :   const auto rotation_vectors = rotationVectors(_axis_point, _axis_direction, input_centroid);
     381             : 
     382         201 :   unsigned int order = 1;
     383             : 
     384             :   BoundaryInfo & boundary_info = mesh->get_boundary_info();
     385             :   const BoundaryInfo & input_boundary_info = input->get_boundary_info();
     386             : 
     387             :   const unsigned int total_num_azimuthal_intervals =
     388         201 :       std::accumulate(_nums_azimuthal_intervals.begin(), _nums_azimuthal_intervals.end(), 0);
     389             :   // We know a priori how many elements we'll need
     390             :   // In the worst case, all quad elements will become two elements per layer
     391         201 :   mesh->reserve_elem(total_num_azimuthal_intervals * orig_elem * 2);
     392             :   const dof_id_type elem_id_shift = total_num_azimuthal_intervals * orig_elem;
     393             : 
     394             :   // Look for higher order elements which introduce an extra layer
     395         201 :   std::set<ElemType> higher_orders = {EDGE3, TRI6, TRI7, QUAD8, QUAD9};
     396             :   std::vector<ElemType> types;
     397         201 :   MeshTools::elem_types(*input, types);
     398         438 :   for (const auto elem_type : types)
     399             :     if (higher_orders.count(elem_type))
     400          78 :       order = 2;
     401         201 :   mesh->comm().max(order);
     402             : 
     403             :   // Collect azimuthal angles and use them to calculate the correction factor if applicable
     404             :   std::vector<Real> azi_array;
     405         429 :   for (const auto & i : index_range(_revolving_angles))
     406             :   {
     407             :     const Real section_start_angle =
     408         228 :         azi_array.empty() ? 0.0 : (azi_array.back() + _unit_angles.back());
     409         228 :     _unit_angles.push_back(_revolving_angles[i] / _nums_azimuthal_intervals[i] / order);
     410        1956 :     for (unsigned int j = 0; j < _nums_azimuthal_intervals[i] * order; j++)
     411        1728 :       azi_array.push_back(section_start_angle + _unit_angles.back() * (Real)j);
     412             :   }
     413         201 :   if (_preserve_volumes)
     414             :   {
     415          36 :     _radius_correction_factor = PolygonalMeshGenerationUtils::radiusCorrectionFactor(
     416          18 :         azi_array, _full_circle_revolving, order);
     417             : 
     418             :     // In the meanwhile, modify the input mesh for radius correction if applicable
     419         288 :     for (const auto & node : input->node_ptr_range())
     420         144 :       nodeModification(*node);
     421             :   }
     422             : 
     423         201 :   mesh->reserve_nodes(
     424         201 :       (order * total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
     425             :       orig_nodes);
     426             : 
     427             :   // Container to catch the boundary IDs handed back by the BoundaryInfo object
     428             :   std::vector<boundary_id_type> ids_to_copy;
     429             : 
     430             :   Point old_distance;
     431             :   Point current_distance;
     432         201 :   if (!_clockwise)
     433             :     std::transform(_unit_angles.begin(),
     434             :                    _unit_angles.end(),
     435             :                    _unit_angles.begin(),
     436           9 :                    [](auto & c) { return c * (-1.0) * M_PI / 180.0; });
     437             :   else
     438             :     std::transform(_unit_angles.begin(),
     439             :                    _unit_angles.end(),
     440             :                    _unit_angles.begin(),
     441         219 :                    [](auto & c) { return c * M_PI / 180.0; });
     442             :   std::vector<dof_id_type> nodes_on_axis;
     443             : 
     444        7084 :   for (const auto & node : input->node_ptr_range())
     445             :   {
     446             :     // Calculate the radius and corresponding center point on the rotation axis
     447             :     // If the radius is 0, then the node is on the axis
     448        3341 :     const auto radius_and_center = getRotationCenterAndRadius(*node, _axis_point, _axis_direction);
     449             :     const bool isOnAxis = MooseUtils::absoluteFuzzyEqual(radius_and_center.first, 0.0);
     450        3341 :     if (isOnAxis)
     451             :     {
     452         274 :       nodes_on_axis.push_back(node->id());
     453             :     }
     454             : 
     455             :     unsigned int current_node_layer = 0;
     456             : 
     457             :     old_distance.zero();
     458             : 
     459        3341 :     const unsigned int num_rotations = _revolving_angles.size();
     460        7933 :     for (unsigned int e = 0; e < num_rotations; e++)
     461             :     {
     462        4592 :       auto num_layers = _nums_azimuthal_intervals[e];
     463             : 
     464        4592 :       auto angle = _unit_angles[e];
     465             : 
     466             :       const auto base_angle =
     467        4592 :           std::accumulate(_revolving_angles.begin(), _revolving_angles.begin() + e, 0.0) / 180.0 *
     468        4592 :           M_PI;
     469             : 
     470        4592 :       for (unsigned int k = 0;
     471       71332 :            k < order * num_layers + (e == 0 ? 1 : 0) -
     472       35666 :                    (e == num_rotations - 1 ? (unsigned int)_full_circle_revolving : 0);
     473             :            ++k)
     474             :       {
     475             :         bool is_node_created(false);
     476       31074 :         if (!isOnAxis)
     477             :         {
     478             :           // For the first layer we don't need to move
     479       28200 :           if (e == 0 && k == 0)
     480             :             current_distance.zero();
     481             :           else
     482             :           {
     483       25133 :             auto layer_index = (k - (e == 0 ? 1 : 0)) + 1;
     484             : 
     485             :             // Calculate the rotation angle in XY Plane
     486             :             const Point vector_xy =
     487             :                 Point(-2.0 * radius_and_center.first *
     488             :                           std::sin((base_angle + angle * (Real)layer_index) / 2.0) *
     489             :                           std::sin((base_angle + angle * (Real)layer_index) / 2.0),
     490       25133 :                       2.0 * radius_and_center.first *
     491       25133 :                           std::sin((base_angle + angle * (Real)layer_index) / 2.0) *
     492       25133 :                           std::cos((base_angle + angle * (Real)layer_index) / 2.0),
     493       25133 :                       0.0);
     494       25133 :             current_distance = Point(rotation_vectors[0] * vector_xy,
     495             :                                      rotation_vectors[1] * vector_xy,
     496             :                                      rotation_vectors[2] * vector_xy);
     497             :           }
     498             : 
     499             :           is_node_created = true;
     500             :         }
     501        2874 :         else if (e == 0 && k == 0)
     502             :         {
     503             :           // On-axis nodes are only added once
     504             :           current_distance.zero();
     505             :           is_node_created = true;
     506             :         }
     507             : 
     508             :         if (is_node_created)
     509             :         {
     510           0 :           Node * new_node = mesh->add_point(*node + current_distance,
     511       28474 :                                             node->id() + (current_node_layer * orig_nodes),
     512       28474 :                                             node->processor_id());
     513             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     514             :           // Let's give the base nodes of the revolved mesh the same
     515             :           // unique_ids as the source mesh, in case anyone finds that
     516             :           // a useful map to preserve.
     517             :           const unique_id_type uid =
     518             :               (current_node_layer == 0)
     519       28474 :                   ? node->unique_id()
     520       25133 :                   : (orig_unique_ids + (current_node_layer - 1) * (orig_nodes + orig_elem * 2) +
     521       25133 :                      node->id());
     522             :           new_node->set_unique_id(uid);
     523             : #endif
     524             : 
     525       28474 :           input_boundary_info.boundary_ids(node, ids_to_copy);
     526       28474 :           if (_boundary_swap_pairs.empty())
     527       25549 :             boundary_info.add_node(new_node, ids_to_copy);
     528             :           else
     529        2925 :             for (const auto & id_to_copy : ids_to_copy)
     530           0 :               boundary_info.add_node(new_node,
     531             :                                      _boundary_swap_pairs[e].count(id_to_copy)
     532           0 :                                          ? _boundary_swap_pairs[e][id_to_copy]
     533           0 :                                          : id_to_copy);
     534             :         }
     535             : 
     536       31074 :         current_node_layer++;
     537             :       }
     538             :     }
     539         201 :   }
     540             : 
     541        4190 :   for (const auto & elem : input->element_ptr_range())
     542             :   {
     543        1894 :     const ElemType etype = elem->type();
     544             : 
     545             :     // revolving currently only works on coarse meshes
     546             :     mooseAssert(!elem->parent(), "RevolveGenerator only works on coarse meshes.");
     547             : 
     548             :     unsigned int current_layer = 0;
     549             : 
     550        1894 :     const unsigned int num_rotations = _revolving_angles.size();
     551             : 
     552        4868 :     for (unsigned int e = 0; e < num_rotations; e++)
     553             :     {
     554        2974 :       auto num_layers = _nums_azimuthal_intervals[e];
     555             : 
     556       15634 :       for (unsigned int k = 0; k < num_layers; ++k)
     557             :       {
     558       12660 :         std::unique_ptr<Elem> new_elem;
     559       12660 :         std::unique_ptr<Elem> new_elem_1;
     560       12660 :         bool is_flipped(false);
     561             :         // In some cases, two elements per layer are generated by revolving one element. So we
     562             :         // reserve an additional flag for the potential second element.
     563       12660 :         bool is_flipped_additional(false);
     564       12660 :         dof_id_type axis_node_case(-1);
     565             :         std::vector<std::pair<dof_id_type, dof_id_type>> side_pairs;
     566       12660 :         switch (etype)
     567             :         {
     568         144 :           case EDGE2:
     569             :           {
     570             :             // Possible scenarios:
     571             :             // 1. None of the nodes are on the axis
     572             :             //    Then a quad4 element is created
     573             :             // 2. One of the nodes is on the axis
     574             :             //    Then a tri3 element is created
     575         144 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     576         144 :             if (nodes_cates.first.empty())
     577             :             {
     578          54 :               createQUADfromEDGE(QUAD4,
     579             :                                  elem,
     580             :                                  mesh,
     581             :                                  new_elem,
     582             :                                  current_layer,
     583             :                                  orig_nodes,
     584             :                                  total_num_azimuthal_intervals,
     585             :                                  side_pairs,
     586             :                                  is_flipped);
     587             :             }
     588             :             else
     589             :             {
     590          90 :               createTRIfromEDGE(nodes_cates,
     591             :                                 TRI3,
     592             :                                 elem,
     593             :                                 mesh,
     594             :                                 new_elem,
     595             :                                 current_layer,
     596             :                                 orig_nodes,
     597             :                                 total_num_azimuthal_intervals,
     598             :                                 side_pairs,
     599             :                                 axis_node_case,
     600             :                                 is_flipped);
     601             :             }
     602             :             break;
     603             :           }
     604         144 :           case EDGE3:
     605             :           {
     606             :             // Possible scenarios:
     607             :             // 1. None of the nodes are on the axis
     608             :             //    Then a QUAD9 element is created
     609             :             // 2. One of the nodes is on the axis
     610             :             //    Then a TRI7 element is created
     611         144 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     612         144 :             if (nodes_cates.first.empty())
     613             :             {
     614          54 :               createQUADfromEDGE(QUAD9,
     615             :                                  elem,
     616             :                                  mesh,
     617             :                                  new_elem,
     618             :                                  current_layer,
     619             :                                  orig_nodes,
     620             :                                  total_num_azimuthal_intervals,
     621             :                                  side_pairs,
     622             :                                  is_flipped);
     623             :             }
     624             :             else
     625             :             {
     626          90 :               createTRIfromEDGE(nodes_cates,
     627             :                                 TRI7,
     628             :                                 elem,
     629             :                                 mesh,
     630             :                                 new_elem,
     631             :                                 current_layer,
     632             :                                 orig_nodes,
     633             :                                 total_num_azimuthal_intervals,
     634             :                                 side_pairs,
     635             :                                 axis_node_case,
     636             :                                 is_flipped);
     637             :             }
     638             :             break;
     639             :           }
     640        3564 :           case TRI3:
     641             :           {
     642             :             // Possible scenarios:
     643             :             // 1. None of the nodes are on the axis
     644             :             //    Then a prism6 element is created
     645             :             // 2. One of the nodes is on the axis
     646             :             //    Then a pyramid5 element is created
     647             :             // 3. Two of the nodes are on the axis
     648             :             //    Then a tet4 element is created
     649        3564 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     650        3564 :             if (nodes_cates.first.empty())
     651             :             {
     652        3294 :               createPRISMfromTRI(PRISM6,
     653             :                                  elem,
     654             :                                  mesh,
     655             :                                  new_elem,
     656             :                                  current_layer,
     657             :                                  orig_nodes,
     658             :                                  total_num_azimuthal_intervals,
     659             :                                  side_pairs,
     660             :                                  is_flipped);
     661             :             }
     662         270 :             else if (nodes_cates.first.size() == 1)
     663             :             {
     664         216 :               createPYRAMIDfromTRI(nodes_cates,
     665             :                                    PYRAMID5,
     666             :                                    elem,
     667             :                                    mesh,
     668             :                                    new_elem,
     669             :                                    current_layer,
     670             :                                    orig_nodes,
     671             :                                    total_num_azimuthal_intervals,
     672             :                                    side_pairs,
     673             :                                    axis_node_case,
     674             :                                    is_flipped);
     675             :             }
     676          54 :             else if (nodes_cates.first.size() == 2)
     677             :             {
     678          54 :               createTETfromTRI(nodes_cates,
     679             :                                TET4,
     680             :                                elem,
     681             :                                mesh,
     682             :                                new_elem,
     683             :                                current_layer,
     684             :                                orig_nodes,
     685             :                                total_num_azimuthal_intervals,
     686             :                                side_pairs,
     687             :                                axis_node_case,
     688             :                                is_flipped);
     689             :             }
     690             :             else
     691           0 :               mooseError("A degenerate TRI3 elements overlapped with the rotation axis cannot be "
     692             :                          "revolved.");
     693             : 
     694             :             break;
     695             :           }
     696         408 :           case TRI6:
     697             :           {
     698             :             // Possible scenarios:
     699             :             // 1. None of the nodes are on the axis
     700             :             //    Then a prism18 element is created
     701             :             // 2. One of the nodes is on the axis
     702             :             //    Then a pyramid13 element is created
     703             :             // 3. Three of the nodes are on the axis
     704             :             //    Then a tet10 element is created
     705             :             // NOTE: We do not support two nodes on the axis for tri6 elements
     706         408 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     707         408 :             if (nodes_cates.first.empty())
     708             :             {
     709         204 :               createPRISMfromTRI(PRISM18,
     710             :                                  elem,
     711             :                                  mesh,
     712             :                                  new_elem,
     713             :                                  current_layer,
     714             :                                  orig_nodes,
     715             :                                  total_num_azimuthal_intervals,
     716             :                                  side_pairs,
     717             :                                  is_flipped);
     718             :             }
     719         204 :             else if (nodes_cates.first.size() == 1)
     720             :             {
     721         108 :               createPYRAMIDfromTRI(nodes_cates,
     722             :                                    PYRAMID13,
     723             :                                    elem,
     724             :                                    mesh,
     725             :                                    new_elem,
     726             :                                    current_layer,
     727             :                                    orig_nodes,
     728             :                                    total_num_azimuthal_intervals,
     729             :                                    side_pairs,
     730             :                                    axis_node_case,
     731             :                                    is_flipped);
     732             :             }
     733          96 :             else if (nodes_cates.first.size() == 3)
     734             :             {
     735          96 :               createTETfromTRI(nodes_cates,
     736             :                                TET10,
     737             :                                elem,
     738             :                                mesh,
     739             :                                new_elem,
     740             :                                current_layer,
     741             :                                orig_nodes,
     742             :                                total_num_azimuthal_intervals,
     743             :                                side_pairs,
     744             :                                axis_node_case,
     745             :                                is_flipped);
     746             :             }
     747             :             else
     748           0 :               mooseError(
     749             :                   "You either have a degenerate TRI6 element, or the mid-point of the "
     750             :                   "on-axis edge is not colinear with the two vertices, which is not supported.");
     751             :             break;
     752             :           }
     753         408 :           case TRI7:
     754             :           {
     755             :             // Possible scenarios:
     756             :             // 1. None of the nodes are on the axis
     757             :             //    Then a prism21 element is created
     758             :             // 2. One of the nodes is on the axis
     759             :             //    Then a pyramid18 element is created
     760             :             // 3. Three of the nodes are on the axis
     761             :             //    Then a tet14 element is created
     762             :             // NOTE: We do not support two nodes on the axis for tri7 elements
     763         408 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     764         408 :             if (nodes_cates.first.empty())
     765             :             {
     766         204 :               createPRISMfromTRI(PRISM21,
     767             :                                  elem,
     768             :                                  mesh,
     769             :                                  new_elem,
     770             :                                  current_layer,
     771             :                                  orig_nodes,
     772             :                                  total_num_azimuthal_intervals,
     773             :                                  side_pairs,
     774             :                                  is_flipped);
     775             :             }
     776         204 :             else if (nodes_cates.first.size() == 1)
     777             :             {
     778         108 :               createPYRAMIDfromTRI(nodes_cates,
     779             :                                    PYRAMID18,
     780             :                                    elem,
     781             :                                    mesh,
     782             :                                    new_elem,
     783             :                                    current_layer,
     784             :                                    orig_nodes,
     785             :                                    total_num_azimuthal_intervals,
     786             :                                    side_pairs,
     787             :                                    axis_node_case,
     788             :                                    is_flipped);
     789             :             }
     790          96 :             else if (nodes_cates.first.size() == 3)
     791             :             {
     792          96 :               createTETfromTRI(nodes_cates,
     793             :                                TET14,
     794             :                                elem,
     795             :                                mesh,
     796             :                                new_elem,
     797             :                                current_layer,
     798             :                                orig_nodes,
     799             :                                total_num_azimuthal_intervals,
     800             :                                side_pairs,
     801             :                                axis_node_case,
     802             :                                is_flipped);
     803             :             }
     804             :             else
     805           0 :               mooseError("You either have a degenerate TRI6 element, or the mid-point of the "
     806             :                          "on-axis edge of the TRI6 element is not colinear with the two vertices, "
     807             :                          "which is not supported.");
     808             :             break;
     809             :           }
     810        7128 :           case QUAD4:
     811             :           {
     812             :             // Possible scenarios:
     813             :             // 1. None of the nodes are on the axis
     814             :             //    Then a hex8 element is created
     815             :             // 2. One of the nodes is on the axis
     816             :             //    Then a pyramid5 element and a prism6 element are created
     817             :             // 3. Two of the nodes are on the axis
     818             :             //    Then a prism6 is created
     819        7128 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     820        7128 :             if (nodes_cates.first.empty())
     821             :             {
     822        6966 :               createHEXfromQUAD(HEX8,
     823             :                                 elem,
     824             :                                 mesh,
     825             :                                 new_elem,
     826             :                                 current_layer,
     827             :                                 orig_nodes,
     828             :                                 total_num_azimuthal_intervals,
     829             :                                 side_pairs,
     830             :                                 is_flipped);
     831             :             }
     832         162 :             else if (nodes_cates.first.size() == 1)
     833             :             {
     834         108 :               createPYRAMIDPRISMfromQUAD(nodes_cates,
     835             :                                          PYRAMID5,
     836             :                                          PRISM6,
     837             :                                          elem,
     838             :                                          mesh,
     839             :                                          new_elem,
     840             :                                          new_elem_1,
     841             :                                          current_layer,
     842             :                                          orig_nodes,
     843             :                                          total_num_azimuthal_intervals,
     844             :                                          side_pairs,
     845             :                                          axis_node_case,
     846             :                                          is_flipped,
     847             :                                          is_flipped_additional);
     848             :             }
     849          54 :             else if (nodes_cates.first.size() == 2)
     850             :             {
     851          54 :               createPRISMfromQUAD(nodes_cates,
     852             :                                   PRISM6,
     853             :                                   elem,
     854             :                                   mesh,
     855             :                                   new_elem,
     856             :                                   current_layer,
     857             :                                   orig_nodes,
     858             :                                   total_num_azimuthal_intervals,
     859             :                                   side_pairs,
     860             :                                   axis_node_case,
     861             :                                   is_flipped);
     862             :             }
     863             : 
     864             :             else
     865           0 :               mooseError("Degenerate QUAD4 element with 3 or more aligned nodes cannot be "
     866             :                          "azimuthally revolved");
     867             : 
     868             :             break;
     869             :           }
     870         378 :           case QUAD8:
     871             :           {
     872             :             // Possible scenarios:
     873             :             // 1. None of the nodes are on the axis
     874             :             //    Then a hex20 element is created
     875             :             // 2. One of the nodes is on the axis
     876             :             //    In that case, it is already converted to a QUAD9 element before,
     877             :             //    SO we do not need to worry about this case
     878             :             // 3. Three of the nodes are on the axis
     879             :             //    Then a prism15 is created
     880             :             // NOTE: We do not support two nodes on the axis for quad8 elements
     881         378 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     882         378 :             if (nodes_cates.first.empty())
     883             :             {
     884         270 :               createHEXfromQUAD(HEX20,
     885             :                                 elem,
     886             :                                 mesh,
     887             :                                 new_elem,
     888             :                                 current_layer,
     889             :                                 orig_nodes,
     890             :                                 total_num_azimuthal_intervals,
     891             :                                 side_pairs,
     892             :                                 is_flipped);
     893             :             }
     894         108 :             else if (nodes_cates.first.size() == 3)
     895             :             {
     896         108 :               createPRISMfromQUAD(nodes_cates,
     897             :                                   PRISM15,
     898             :                                   elem,
     899             :                                   mesh,
     900             :                                   new_elem,
     901             :                                   current_layer,
     902             :                                   orig_nodes,
     903             :                                   total_num_azimuthal_intervals,
     904             :                                   side_pairs,
     905             :                                   axis_node_case,
     906             :                                   is_flipped);
     907             :             }
     908             :             else
     909           0 :               mooseError("You either have a degenerate QUAD8 element, or the mid-point of the "
     910             :                          "on-axis edge of the QUAD8 element is not colinear with the two vertices, "
     911             :                          "which is not supported.");
     912             : 
     913             :             break;
     914             :           }
     915         486 :           case QUAD9:
     916             :           {
     917             :             // Possible scenarios:
     918             :             // 1. None of the nodes are on the axis
     919             :             //    Then a hex27 element is created
     920             :             // 2. One of the nodes is on the axis
     921             :             //    Then a pyramid14 element and a prism18 element are created
     922             :             // 3. Two of the nodes are on the axis
     923             :             //    Then a prism18 is created
     924             :             // (we do not create prism20/21 here just to make prism18 the only possible prism
     925             :             // elements for simplicity)
     926         486 :             const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
     927         486 :             if (nodes_cates.first.empty())
     928             :             {
     929         270 :               createHEXfromQUAD(HEX27,
     930             :                                 elem,
     931             :                                 mesh,
     932             :                                 new_elem,
     933             :                                 current_layer,
     934             :                                 orig_nodes,
     935             :                                 total_num_azimuthal_intervals,
     936             :                                 side_pairs,
     937             :                                 is_flipped);
     938             :             }
     939         216 :             else if (nodes_cates.first.size() == 1)
     940             :             {
     941         108 :               createPYRAMIDPRISMfromQUAD(nodes_cates,
     942             :                                          PYRAMID14,
     943             :                                          PRISM18,
     944             :                                          elem,
     945             :                                          mesh,
     946             :                                          new_elem,
     947             :                                          new_elem_1,
     948             :                                          current_layer,
     949             :                                          orig_nodes,
     950             :                                          total_num_azimuthal_intervals,
     951             :                                          side_pairs,
     952             :                                          axis_node_case,
     953             :                                          is_flipped,
     954             :                                          is_flipped_additional);
     955             :             }
     956         108 :             else if (nodes_cates.first.size() == 3)
     957             :             {
     958         108 :               createPRISMfromQUAD(nodes_cates,
     959             :                                   PRISM18,
     960             :                                   elem,
     961             :                                   mesh,
     962             :                                   new_elem,
     963             :                                   current_layer,
     964             :                                   orig_nodes,
     965             :                                   total_num_azimuthal_intervals,
     966             :                                   side_pairs,
     967             :                                   axis_node_case,
     968             :                                   is_flipped);
     969             :             }
     970             :             else
     971           0 :               mooseError("You either have a degenerate QUAD9 element, or the mid-point of the "
     972             :                          "on-axis edge of the QUAD9 element is not colinear with the two vertices, "
     973             :                          "which is not supported.");
     974             :             break;
     975             :           }
     976           0 :           default:
     977           0 :             mooseError("The input mesh contains unsupported element type(s).");
     978             :         }
     979       12660 :         new_elem->set_id(elem->id() + (current_layer * orig_elem));
     980       12660 :         new_elem->processor_id() = elem->processor_id();
     981       12660 :         if (new_elem_1)
     982             :         {
     983         216 :           new_elem_1->set_id(elem->id() + (current_layer * orig_elem) + elem_id_shift);
     984         216 :           new_elem_1->processor_id() = elem->processor_id();
     985             :         }
     986             : 
     987             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     988             :         // Let's give the base elements of the revolved mesh the same
     989             :         // unique_ids as the source mesh, in case anyone finds that
     990             :         // a useful map to preserve.
     991             :         const unique_id_type uid =
     992             :             (current_layer == 0)
     993       12660 :                 ? elem->unique_id()
     994       10766 :                 : (orig_unique_ids + (current_layer - 1) * (orig_nodes + orig_elem * 2) +
     995             :                    orig_nodes + elem->id());
     996             : 
     997             :         new_elem->set_unique_id(uid);
     998             : 
     999             :         // Special case for extra elements
    1000       12660 :         if (new_elem_1)
    1001             :         {
    1002             :           const unique_id_type uid_1 =
    1003             :               (current_layer == 0)
    1004         216 :                   ? (elem->id() + orig_unique_ids - orig_elem)
    1005         180 :                   : (orig_unique_ids + (current_layer - 1) * (orig_nodes + orig_elem * 2) +
    1006         180 :                      orig_nodes + orig_elem + elem->id());
    1007             : 
    1008             :           new_elem_1->set_unique_id(uid_1);
    1009             :         }
    1010             : #endif
    1011             : 
    1012             :         // maintain the subdomain_id
    1013       12660 :         switch (etype)
    1014             :         {
    1015             :           case EDGE2:
    1016         144 :             switch (new_elem->type())
    1017             :             {
    1018          54 :               case QUAD4:
    1019          54 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1020          54 :                 break;
    1021          90 :               case TRI3:
    1022          90 :                 new_elem->subdomain_id() = edge_to_tri_subdomain_id_shift + elem->subdomain_id();
    1023          90 :                 break;
    1024             :               default:
    1025             :                 mooseAssert(false,
    1026             :                             "impossible element type generated by revolving an EDGE2 element");
    1027             :             }
    1028             :             break;
    1029             :           case EDGE3:
    1030         144 :             switch (new_elem->type())
    1031             :             {
    1032          54 :               case QUAD9:
    1033          54 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1034          54 :                 break;
    1035          90 :               case TRI7:
    1036          90 :                 new_elem->subdomain_id() = edge_to_tri_subdomain_id_shift + elem->subdomain_id();
    1037          90 :                 break;
    1038             :               default:
    1039             :                 mooseAssert(false,
    1040             :                             "impossible element type generated by revolving an EDGE3 element");
    1041             :             }
    1042             :             break;
    1043             :           case TRI3:
    1044        3564 :             switch (new_elem->type())
    1045             :             {
    1046        3294 :               case PRISM6:
    1047        3294 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1048        3294 :                 break;
    1049         216 :               case PYRAMID5:
    1050         216 :                 new_elem->subdomain_id() = tri_to_pyramid_subdomain_id_shift + elem->subdomain_id();
    1051         216 :                 break;
    1052          54 :               case TET4:
    1053          54 :                 new_elem->subdomain_id() = tri_to_tet_subdomain_id_shift + elem->subdomain_id();
    1054          54 :                 break;
    1055             :               default:
    1056             :                 mooseAssert(false, "impossible element type generated by revolving a TRI3 element");
    1057             :             }
    1058             :             break;
    1059             :           case TRI6:
    1060         408 :             switch (new_elem->type())
    1061             :             {
    1062         204 :               case PRISM18:
    1063         204 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1064         204 :                 break;
    1065         108 :               case PYRAMID13:
    1066         108 :                 new_elem->subdomain_id() = tri_to_pyramid_subdomain_id_shift + elem->subdomain_id();
    1067         108 :                 break;
    1068          96 :               case TET10:
    1069          96 :                 new_elem->subdomain_id() = tri_to_tet_subdomain_id_shift + elem->subdomain_id();
    1070          96 :                 break;
    1071             :               default:
    1072             :                 mooseAssert(false, "impossible element type generated by revolving a TRI6 element");
    1073             :             }
    1074             :             break;
    1075             :           case TRI7:
    1076         408 :             switch (new_elem->type())
    1077             :             {
    1078         204 :               case PRISM21:
    1079         204 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1080         204 :                 break;
    1081         108 :               case PYRAMID18:
    1082         108 :                 new_elem->subdomain_id() = tri_to_pyramid_subdomain_id_shift + elem->subdomain_id();
    1083         108 :                 break;
    1084          96 :               case TET14:
    1085          96 :                 new_elem->subdomain_id() = tri_to_tet_subdomain_id_shift + elem->subdomain_id();
    1086          96 :                 break;
    1087             :               default:
    1088             :                 mooseAssert(false, "impossible element type generated by revolving a TRI7 element");
    1089             :             }
    1090             :             break;
    1091             :           case QUAD4:
    1092        7128 :             switch (new_elem->type())
    1093             :             {
    1094        6966 :               case HEX8:
    1095        6966 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1096        6966 :                 break;
    1097          54 :               case PRISM6:
    1098          54 :                 new_elem->subdomain_id() = quad_to_prism_subdomain_id_shift + elem->subdomain_id();
    1099          54 :                 break;
    1100         108 :               case PYRAMID5:
    1101         108 :                 new_elem->subdomain_id() =
    1102         108 :                     quad_to_pyramid_subdomain_id_shift + elem->subdomain_id();
    1103         108 :                 new_elem_1->subdomain_id() =
    1104         108 :                     quad_to_prism_subdomain_id_shift + elem->subdomain_id();
    1105         108 :                 break;
    1106             :               default:
    1107             :                 mooseAssert(false,
    1108             :                             "impossible element type generated by revolving a QUAD4 element");
    1109             :             }
    1110             :             break;
    1111             :           case QUAD8:
    1112         378 :             switch (new_elem->type())
    1113             :             {
    1114         270 :               case HEX20:
    1115         270 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1116         270 :                 break;
    1117         108 :               case PRISM15:
    1118         108 :                 new_elem->subdomain_id() = quad_to_prism_subdomain_id_shift + elem->subdomain_id();
    1119         108 :                 break;
    1120             :               default:
    1121             :                 mooseAssert(false,
    1122             :                             "impossible element type generated by revolving a QUAD8 element");
    1123             :             }
    1124             :             break;
    1125             :           case QUAD9:
    1126         486 :             switch (new_elem->type())
    1127             :             {
    1128         270 :               case HEX27:
    1129         270 :                 new_elem->subdomain_id() = elem->subdomain_id();
    1130         270 :                 break;
    1131         108 :               case PRISM18:
    1132         108 :                 new_elem->subdomain_id() =
    1133         108 :                     quad_to_hi_pyramid_subdomain_id_shift + elem->subdomain_id();
    1134         108 :                 break;
    1135         108 :               case PYRAMID14:
    1136         108 :                 new_elem->subdomain_id() =
    1137         108 :                     quad_to_pyramid_subdomain_id_shift + elem->subdomain_id();
    1138         108 :                 new_elem_1->subdomain_id() =
    1139         108 :                     quad_to_hi_pyramid_subdomain_id_shift + elem->subdomain_id();
    1140         108 :                 break;
    1141             :               default:
    1142             :                 mooseAssert(false,
    1143             :                             "impossible element type generated by revolving a QUAD9 element");
    1144             :             }
    1145             :             break;
    1146       12660 :           default:
    1147             :             mooseAssert(false,
    1148             :                         "The input mesh contains unsupported element type(s), which should have "
    1149             :                         "been checked in prior steps in this code.");
    1150             :         }
    1151             : 
    1152       12660 :         if (_subdomain_swap_pairs.size())
    1153             :         {
    1154             :           auto & revolving_swap_pairs = _subdomain_swap_pairs[e];
    1155             : 
    1156        2592 :           auto new_id_it = revolving_swap_pairs.find(elem->subdomain_id());
    1157             : 
    1158        2592 :           if (new_id_it != revolving_swap_pairs.end())
    1159             :           {
    1160        1296 :             new_elem->subdomain_id() =
    1161        1296 :                 new_elem->subdomain_id() - elem->subdomain_id() + new_id_it->second;
    1162        1296 :             if (new_elem_1)
    1163           0 :               new_elem_1->subdomain_id() =
    1164           0 :                   new_elem_1->subdomain_id() - elem->subdomain_id() + new_id_it->second;
    1165             :           }
    1166             :         }
    1167             : 
    1168       12660 :         Elem * added_elem = mesh->add_elem(std::move(new_elem));
    1169             :         Elem * added_elem_1 = NULL;
    1170             : 
    1171       12660 :         if (new_elem_1)
    1172         216 :           added_elem_1 = mesh->add_elem(std::move(new_elem_1));
    1173             : 
    1174             :         // maintain extra integers
    1175       23028 :         for (unsigned int i = 0; i < num_extra_elem_integers; i++)
    1176             :         {
    1177       10368 :           added_elem->set_extra_integer(i, elem->get_extra_integer(i));
    1178       10368 :           if (added_elem_1)
    1179           0 :             added_elem_1->set_extra_integer(i, elem->get_extra_integer(i));
    1180             :         }
    1181             : 
    1182       12660 :         if (_elem_integers_swap_pairs.size())
    1183             :         {
    1184       15552 :           for (unsigned int i = 0; i < _elem_integer_indices_to_swap.size(); i++)
    1185             :           {
    1186             :             auto & elevation_extra_swap_pairs =
    1187       10368 :                 _elem_integers_swap_pairs[i * _nums_azimuthal_intervals.size() + e];
    1188             : 
    1189             :             auto new_extra_id_it = elevation_extra_swap_pairs.find(
    1190       10368 :                 elem->get_extra_integer(_elem_integer_indices_to_swap[i]));
    1191             : 
    1192       10368 :             if (new_extra_id_it != elevation_extra_swap_pairs.end())
    1193             :             {
    1194        6912 :               added_elem->set_extra_integer(_elem_integer_indices_to_swap[i],
    1195             :                                             new_extra_id_it->second);
    1196        6912 :               if (added_elem_1)
    1197           0 :                 added_elem_1->set_extra_integer(_elem_integer_indices_to_swap[i],
    1198             :                                                 new_extra_id_it->second);
    1199             :             }
    1200             :           }
    1201             :         }
    1202             : 
    1203             :         // Copy any old boundary ids on all sides
    1204       58344 :         for (auto s : elem->side_index_range())
    1205             :         {
    1206       45684 :           input_boundary_info.boundary_ids(elem, s, ids_to_copy);
    1207             :           std::vector<boundary_id_type> ids_to_copy_swapped;
    1208       45684 :           if (_boundary_swap_pairs.empty())
    1209       36612 :             ids_to_copy_swapped = ids_to_copy;
    1210             :           else
    1211       11664 :             for (const auto & id_to_copy : ids_to_copy)
    1212        2592 :               ids_to_copy_swapped.push_back(_boundary_swap_pairs[e].count(id_to_copy)
    1213             :                                                 ? _boundary_swap_pairs[e][id_to_copy]
    1214             :                                                 : id_to_copy);
    1215             : 
    1216       45684 :           switch (etype)
    1217             :           {
    1218         288 :             case EDGE2:
    1219         288 :               switch (added_elem->type())
    1220             :               {
    1221         108 :                 case QUAD4:
    1222         108 :                   boundary_info.add_side(
    1223         108 :                       added_elem, cast_int<unsigned short>(s == 0 ? 3 : 1), ids_to_copy_swapped);
    1224             :                   break;
    1225         180 :                 case TRI3:
    1226         180 :                   if (s != axis_node_case)
    1227          90 :                     boundary_info.add_side(
    1228             :                         added_elem, cast_int<unsigned short>(s), ids_to_copy_swapped);
    1229             :                   break;
    1230             :                 default:
    1231             :                   mooseAssert(false,
    1232             :                               "impossible element type generated by revolving an EDGE2 element");
    1233             :               }
    1234             :               break;
    1235         288 :             case EDGE3:
    1236         288 :               switch (added_elem->type())
    1237             :               {
    1238         108 :                 case QUAD9:
    1239         108 :                   boundary_info.add_side(
    1240         108 :                       added_elem, cast_int<unsigned short>(s == 0 ? 3 : 1), ids_to_copy_swapped);
    1241             :                   break;
    1242         180 :                 case TRI7:
    1243         180 :                   if (s != axis_node_case)
    1244          90 :                     boundary_info.add_side(
    1245             :                         added_elem, cast_int<unsigned short>(s), ids_to_copy_swapped);
    1246             :                   break;
    1247             :                 default:
    1248             :                   mooseAssert(false,
    1249             :                               "impossible element type generated by revolving an EDGE3 element");
    1250             :               }
    1251             :               break;
    1252       10692 :             case TRI3:
    1253       10692 :               switch (added_elem->type())
    1254             :               {
    1255        9882 :                 case PRISM6:
    1256        9882 :                   boundary_info.add_side(
    1257             :                       added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
    1258             :                   break;
    1259         648 :                 case PYRAMID5:
    1260         648 :                   if ((s + 3 - axis_node_case) % 3 == 0)
    1261         216 :                     boundary_info.add_side(
    1262             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1263         432 :                   else if ((s + 3 - axis_node_case) % 3 == 1)
    1264         216 :                     boundary_info.add_side(
    1265             :                         added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
    1266             :                   else
    1267         216 :                     boundary_info.add_side(
    1268             :                         added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
    1269             :                   break;
    1270         162 :                 case TET4:
    1271         162 :                   if ((s + 3 - axis_node_case) % 3 == 0)
    1272          54 :                     boundary_info.add_side(
    1273             :                         added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1274         108 :                   else if ((s + 3 - axis_node_case) % 3 == 2)
    1275          54 :                     boundary_info.add_side(
    1276             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1277             :                   break;
    1278             :                 default:
    1279             :                   mooseAssert(false,
    1280             :                               "impossible element type generated by revolving a TRI3 element");
    1281             :               }
    1282             :               break;
    1283        1224 :             case TRI6:
    1284        1224 :               switch (added_elem->type())
    1285             :               {
    1286         612 :                 case PRISM18:
    1287         612 :                   boundary_info.add_side(
    1288             :                       added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
    1289             :                   break;
    1290         324 :                 case PYRAMID13:
    1291         324 :                   if ((s + 3 - axis_node_case) % 3 == 0)
    1292         108 :                     boundary_info.add_side(
    1293             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1294         216 :                   else if ((s + 3 - axis_node_case) % 3 == 1)
    1295         108 :                     boundary_info.add_side(
    1296             :                         added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
    1297             :                   else
    1298         108 :                     boundary_info.add_side(
    1299             :                         added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
    1300             :                   break;
    1301         288 :                 case TET10:
    1302         288 :                   if ((s + 3 - axis_node_case) % 3 == 0)
    1303          96 :                     boundary_info.add_side(
    1304             :                         added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1305         192 :                   else if ((s + 3 - axis_node_case) % 3 == 2)
    1306          96 :                     boundary_info.add_side(
    1307             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1308             :                   break;
    1309             :                 default:
    1310             :                   mooseAssert(false,
    1311             :                               "impossible element type generated by revolving a TRI6 element");
    1312             :               }
    1313             :               break;
    1314        1224 :             case TRI7:
    1315        1224 :               switch (added_elem->type())
    1316             :               {
    1317         612 :                 case PRISM21:
    1318         612 :                   boundary_info.add_side(
    1319             :                       added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
    1320             :                   break;
    1321         324 :                 case PYRAMID18:
    1322         324 :                   if ((s + 3 - axis_node_case) % 3 == 0)
    1323         108 :                     boundary_info.add_side(
    1324             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1325         216 :                   else if ((s + 3 - axis_node_case) % 3 == 1)
    1326         108 :                     boundary_info.add_side(
    1327             :                         added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
    1328             :                   else
    1329         108 :                     boundary_info.add_side(
    1330             :                         added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
    1331             :                   break;
    1332         288 :                 case TET14:
    1333         288 :                   if ((s + 3 - axis_node_case) % 3 == 0)
    1334          96 :                     boundary_info.add_side(
    1335             :                         added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1336         192 :                   else if ((s + 3 - axis_node_case) % 3 == 2)
    1337          96 :                     boundary_info.add_side(
    1338             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1339             :                   break;
    1340             :                 default:
    1341             :                   mooseAssert(false,
    1342             :                               "impossible element type generated by revolving a TRI7 element");
    1343             :               }
    1344             :               break;
    1345       28512 :             case QUAD4:
    1346       28512 :               switch (added_elem->type())
    1347             :               {
    1348       27864 :                 case HEX8:
    1349       27864 :                   boundary_info.add_side(
    1350             :                       added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
    1351             :                   break;
    1352         216 :                 case PRISM6:
    1353         216 :                   if ((s + 4 - axis_node_case) % 4 == 1)
    1354          54 :                     boundary_info.add_side(
    1355             :                         added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
    1356         162 :                   else if ((s + 4 - axis_node_case) % 4 == 2)
    1357          54 :                     boundary_info.add_side(
    1358             :                         added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1359         108 :                   else if ((s + 4 - axis_node_case) % 4 == 3)
    1360          54 :                     boundary_info.add_side(
    1361             :                         added_elem, cast_int<unsigned short>(0), ids_to_copy_swapped);
    1362             :                   break;
    1363         432 :                 case PYRAMID5:
    1364         432 :                   if ((s + 4 - axis_node_case) % 4 == 3)
    1365         108 :                     boundary_info.add_side(
    1366             :                         added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
    1367         324 :                   else if ((s + 4 - axis_node_case) % 4 == 0)
    1368         108 :                     boundary_info.add_side(
    1369             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1370         216 :                   else if ((s + 4 - axis_node_case) % 4 == 1)
    1371         108 :                     boundary_info.add_side(
    1372             :                         added_elem_1, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1373             :                   else
    1374         108 :                     boundary_info.add_side(
    1375             :                         added_elem_1, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1376             :                   break;
    1377             :                 default:
    1378             :                   mooseAssert(false,
    1379             :                               "impossible element type generated by revolving a QUAD4 element");
    1380             :               }
    1381             :               break;
    1382        1512 :             case QUAD8:
    1383        1512 :               switch (added_elem->type())
    1384             :               {
    1385        1080 :                 case HEX20:
    1386        1080 :                   boundary_info.add_side(
    1387             :                       added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
    1388             :                   break;
    1389         432 :                 case PRISM15:
    1390         432 :                   if ((s + 4 - axis_node_case) % 4 == 1)
    1391         108 :                     boundary_info.add_side(
    1392             :                         added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
    1393         324 :                   else if ((s + 4 - axis_node_case) % 4 == 2)
    1394         108 :                     boundary_info.add_side(
    1395             :                         added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1396         216 :                   else if ((s + 4 - axis_node_case) % 4 == 3)
    1397         108 :                     boundary_info.add_side(
    1398             :                         added_elem, cast_int<unsigned short>(0), ids_to_copy_swapped);
    1399             :                   break;
    1400             :                 default:
    1401             :                   mooseAssert(false,
    1402             :                               "impossible element type generated by revolving a QUAD8 element");
    1403             :               }
    1404             :               break;
    1405        1944 :             case QUAD9:
    1406        1944 :               switch (added_elem->type())
    1407             :               {
    1408        1080 :                 case HEX27:
    1409        1080 :                   boundary_info.add_side(
    1410             :                       added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
    1411             :                   break;
    1412         432 :                 case PRISM18:
    1413         432 :                   if ((s + 4 - axis_node_case) % 4 == 1)
    1414         108 :                     boundary_info.add_side(
    1415             :                         added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
    1416         324 :                   else if ((s + 4 - axis_node_case) % 4 == 2)
    1417         108 :                     boundary_info.add_side(
    1418             :                         added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1419         216 :                   else if ((s + 4 - axis_node_case) % 4 == 3)
    1420         108 :                     boundary_info.add_side(
    1421             :                         added_elem, cast_int<unsigned short>(0), ids_to_copy_swapped);
    1422             :                   break;
    1423         432 :                 case PYRAMID14:
    1424         432 :                   if ((s + 4 - axis_node_case) % 4 == 3)
    1425         108 :                     boundary_info.add_side(
    1426             :                         added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
    1427         324 :                   else if ((s + 4 - axis_node_case) % 4 == 0)
    1428         108 :                     boundary_info.add_side(
    1429             :                         added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1430         216 :                   else if ((s + 4 - axis_node_case) % 4 == 1)
    1431         108 :                     boundary_info.add_side(
    1432             :                         added_elem_1, cast_int<unsigned short>(3), ids_to_copy_swapped);
    1433             :                   else
    1434         108 :                     boundary_info.add_side(
    1435             :                         added_elem_1, cast_int<unsigned short>(2), ids_to_copy_swapped);
    1436             :                   break;
    1437             :                 default:
    1438             :                   mooseAssert(false,
    1439             :                               "impossible element type generated by revolving a QUAD9 element");
    1440             :               }
    1441             :               break;
    1442       45684 :             default:
    1443             :               mooseAssert(false,
    1444             :                           "The input mesh contains unsupported element type(s), which should have "
    1445             :                           "been checked in prior steps in this code.");
    1446             :           }
    1447       45684 :         }
    1448             : 
    1449       12660 :         if (current_layer == 0 && _has_start_boundary)
    1450             :         {
    1451          54 :           boundary_info.add_side(
    1452          54 :               added_elem, is_flipped ? side_pairs[0].second : side_pairs[0].first, _start_boundary);
    1453          54 :           if (side_pairs.size() > 1)
    1454           0 :             boundary_info.add_side(added_elem_1,
    1455           0 :                                    is_flipped_additional ? side_pairs[1].second
    1456           0 :                                                          : side_pairs[1].first,
    1457           0 :                                    _start_boundary);
    1458             :         }
    1459             : 
    1460       12660 :         if (current_layer == num_layers - 1 && _has_end_boundary)
    1461             :         {
    1462          54 :           boundary_info.add_side(
    1463          54 :               added_elem, is_flipped ? side_pairs[0].first : side_pairs[0].second, _end_boundary);
    1464          54 :           if (side_pairs.size() > 1)
    1465           0 :             boundary_info.add_side(added_elem_1,
    1466           0 :                                    is_flipped_additional ? side_pairs[1].first
    1467           0 :                                                          : side_pairs[1].second,
    1468           0 :                                    _end_boundary);
    1469             :         }
    1470       12660 :         current_layer++;
    1471       12660 :       }
    1472             :     }
    1473         201 :   }
    1474             : 
    1475             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1476             :   // Update the value of next_unique_id based on newly created nodes and elements
    1477             :   // Note: the calculation here is quite conservative to ensure uniqueness
    1478         201 :   unsigned int total_new_node_layers = total_num_azimuthal_intervals * order;
    1479         201 :   unsigned int new_unique_ids = orig_unique_ids + (total_new_node_layers - 1) * orig_elem * 2 +
    1480             :                                 total_new_node_layers * orig_nodes;
    1481         201 :   mesh->set_next_unique_id(new_unique_ids);
    1482             : #endif
    1483             : 
    1484             :   // Copy all the subdomain/sideset/nodeset name maps to the revolved mesh
    1485         201 :   if (!input_subdomain_map.empty())
    1486         108 :     mesh->set_subdomain_name_map().insert(input_subdomain_map.begin(), input_subdomain_map.end());
    1487         201 :   if (!input_sideset_map.empty())
    1488         201 :     mesh->get_boundary_info().set_sideset_name_map().insert(input_sideset_map.begin(),
    1489             :                                                             input_sideset_map.end());
    1490         201 :   if (!input_nodeset_map.empty())
    1491          84 :     mesh->get_boundary_info().set_nodeset_name_map().insert(input_nodeset_map.begin(),
    1492             :                                                             input_nodeset_map.end());
    1493             : 
    1494         201 :   mesh->remove_orphaned_nodes();
    1495         201 :   mesh->renumber_nodes_and_elements();
    1496             :   mesh->set_isnt_prepared();
    1497             : 
    1498         201 :   return mesh;
    1499         603 : }
    1500             : 
    1501             : std::pair<Real, Point>
    1502        3341 : RevolveGenerator::getRotationCenterAndRadius(const Point & p_ext,
    1503             :                                              const Point & p_axis,
    1504             :                                              const Point & dir_axis) const
    1505             : {
    1506             :   // First use point product to get the distance between the axis point and the projection of the
    1507             :   // external point on the axis
    1508        3341 :   const Real dist = (p_ext - p_axis) * dir_axis.unit();
    1509        3341 :   const Point center_pt = p_axis + dist * dir_axis.unit();
    1510             :   // Then get the radius
    1511        3341 :   const Real radius = (p_ext - center_pt).norm();
    1512        3341 :   return std::make_pair(radius, center_pt);
    1513             : }
    1514             : 
    1515             : std::vector<Point>
    1516         201 : RevolveGenerator::rotationVectors(const Point & p_axis,
    1517             :                                   const Point & dir_axis,
    1518             :                                   const Point & p_input) const
    1519             : {
    1520             :   // To make the rotation mathematically simple, we perform rotation in a coordination system
    1521             :   // (x',y',z') defined by rotation axis and the mesh to be rotated.
    1522             :   // z' is the rotation axis, which is trivial dir_axis.unit()
    1523         201 :   const Point z_prime = dir_axis.unit();
    1524             :   // the x' and z' should form the plane that accommodates input mesh
    1525         201 :   const Point x_prime = ((p_input - p_axis) - ((p_input - p_axis) * z_prime) * z_prime).unit();
    1526         201 :   const Point y_prime = z_prime.cross(x_prime);
    1527             :   // Then we transform things back to the original coordination system (x,y,z), which is trivial
    1528             :   // (1,0,0), (0,1,0), (0,0,1)
    1529             :   return {{x_prime(0), y_prime(0), z_prime(0)},
    1530             :           {x_prime(1), y_prime(1), z_prime(1)},
    1531         201 :           {x_prime(2), y_prime(2), z_prime(2)}};
    1532             : }
    1533             : 
    1534             : std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>>
    1535       12660 : RevolveGenerator::onAxisNodesIdentifier(const Elem & elem,
    1536             :                                         const std::vector<dof_id_type> & nodes_on_axis) const
    1537             : {
    1538             :   std::vector<dof_id_type> nodes_on_axis_in_elem;
    1539             :   std::vector<dof_id_type> nodes_not_on_axis_in_elem;
    1540       65286 :   for (unsigned int i = 0; i < elem.n_nodes(); i++)
    1541             :   {
    1542       52626 :     const auto node_id = elem.node_id(i);
    1543       52626 :     if (std::find(nodes_on_axis.begin(), nodes_on_axis.end(), node_id) != nodes_on_axis.end())
    1544             :     {
    1545        2268 :       nodes_on_axis_in_elem.push_back(i);
    1546             :     }
    1547             :     else
    1548             :     {
    1549       50358 :       nodes_not_on_axis_in_elem.push_back(i);
    1550             :     }
    1551             :   }
    1552       12660 :   return std::make_pair(nodes_on_axis_in_elem, nodes_not_on_axis_in_elem);
    1553       12660 : }
    1554             : 
    1555             : void
    1556         126 : RevolveGenerator::nodeModification(Node & node)
    1557             : {
    1558             :   const Point axis_component =
    1559         126 :       ((node - _axis_point) * _axis_direction.unit()) * _axis_direction.unit();
    1560             :   const Point rad_component = ((node - _axis_point) - axis_component) * _radius_correction_factor;
    1561             :   node = _axis_point + axis_component + rad_component;
    1562         126 : }
    1563             : 
    1564             : void
    1565         108 : RevolveGenerator::createQUADfromEDGE(const ElemType quad_elem_type,
    1566             :                                      const Elem * elem,
    1567             :                                      const std::unique_ptr<MeshBase> & mesh,
    1568             :                                      std::unique_ptr<Elem> & new_elem,
    1569             :                                      const int current_layer,
    1570             :                                      const unsigned int orig_nodes,
    1571             :                                      const unsigned int total_num_azimuthal_intervals,
    1572             :                                      std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    1573             :                                      bool & is_flipped) const
    1574             : {
    1575         108 :   if (quad_elem_type != QUAD4 && quad_elem_type != QUAD9)
    1576           0 :     mooseError("Unsupported element type", quad_elem_type);
    1577             : 
    1578         108 :   side_pairs.push_back(std::make_pair(0, 2));
    1579         108 :   const unsigned int order = quad_elem_type == QUAD4 ? 1 : 2;
    1580             : 
    1581         108 :   new_elem = std::make_unique<Quad4>();
    1582         108 :   if (quad_elem_type == QUAD9)
    1583             :   {
    1584          54 :     new_elem = std::make_unique<Quad9>();
    1585          54 :     new_elem->set_node(4,
    1586          54 :                        mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * 2 * orig_nodes)));
    1587          54 :     new_elem->set_node(
    1588          54 :         5, mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1589          54 :     new_elem->set_node(
    1590             :         6,
    1591          54 :         mesh->node_ptr(elem->node_ptr(2)->id() +
    1592          54 :                        ((current_layer + 1) %
    1593          54 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1594          54 :                         2 * orig_nodes)));
    1595          54 :     new_elem->set_node(
    1596          54 :         7, mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1597          54 :     new_elem->set_node(
    1598          54 :         8, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1599             :   }
    1600             : 
    1601         108 :   new_elem->set_node(
    1602         108 :       0, mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * order * orig_nodes)));
    1603         108 :   new_elem->set_node(
    1604         108 :       1, mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * order * orig_nodes)));
    1605         108 :   new_elem->set_node(
    1606             :       3,
    1607         108 :       mesh->node_ptr(elem->node_ptr(0)->id() +
    1608         108 :                      ((current_layer + 1) %
    1609         108 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1610         108 :                       order * orig_nodes)));
    1611         108 :   new_elem->set_node(
    1612             :       2,
    1613         108 :       mesh->node_ptr(elem->node_ptr(1)->id() +
    1614         108 :                      ((current_layer + 1) %
    1615         108 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1616         108 :                       order * orig_nodes)));
    1617             : 
    1618         108 :   if (new_elem->volume() < 0.0)
    1619             :   {
    1620           0 :     MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
    1621           0 :     MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
    1622           0 :     if (quad_elem_type == QUAD9)
    1623           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 4, 6);
    1624           0 :     is_flipped = true;
    1625             :   }
    1626         108 : }
    1627             : 
    1628             : void
    1629         180 : RevolveGenerator::createTRIfromEDGE(
    1630             :     const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
    1631             :     const ElemType tri_elem_type,
    1632             :     const Elem * elem,
    1633             :     const std::unique_ptr<MeshBase> & mesh,
    1634             :     std::unique_ptr<Elem> & new_elem,
    1635             :     const int current_layer,
    1636             :     const unsigned int orig_nodes,
    1637             :     const unsigned int total_num_azimuthal_intervals,
    1638             :     std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    1639             :     dof_id_type & axis_node_case,
    1640             :     bool & is_flipped) const
    1641             : {
    1642         180 :   if (tri_elem_type != TRI3 && tri_elem_type != TRI7)
    1643           0 :     mooseError("Unsupported element type", tri_elem_type);
    1644             : 
    1645         180 :   side_pairs.push_back(std::make_pair(0, 2));
    1646         180 :   const unsigned int order = tri_elem_type == TRI3 ? 1 : 2;
    1647         180 :   axis_node_case = nodes_cates.first.front();
    1648             : 
    1649         180 :   new_elem = std::make_unique<Tri3>();
    1650         180 :   if (tri_elem_type == TRI7)
    1651             :   {
    1652          90 :     new_elem = std::make_unique<Tri7>();
    1653          90 :     new_elem->set_node(3,
    1654          90 :                        mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * 2 * orig_nodes)));
    1655          90 :     new_elem->set_node(4,
    1656          90 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 2)->id() +
    1657          90 :                                       ((current_layer * 2 + 1) * orig_nodes)));
    1658          90 :     new_elem->set_node(
    1659             :         5,
    1660          90 :         mesh->node_ptr(elem->node_ptr(2)->id() +
    1661          90 :                        ((current_layer + 1) %
    1662          90 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1663          90 :                         2 * orig_nodes)));
    1664          90 :     new_elem->set_node(
    1665          90 :         6, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1666             :   }
    1667             : 
    1668         180 :   new_elem->set_node(0, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
    1669         180 :   new_elem->set_node(1,
    1670         180 :                      mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 2)->id() +
    1671         180 :                                     (current_layer * order * orig_nodes)));
    1672         180 :   new_elem->set_node(
    1673             :       2,
    1674         180 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 2)->id() +
    1675         180 :                      ((current_layer + 1) %
    1676         180 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1677         180 :                       order * orig_nodes)));
    1678             : 
    1679         180 :   if (new_elem->volume() < 0.0)
    1680             :   {
    1681           0 :     MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
    1682           0 :     if (tri_elem_type == TRI7)
    1683           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 3, 5);
    1684           0 :     is_flipped = true;
    1685             :   }
    1686         180 : }
    1687             : 
    1688             : void
    1689        3702 : RevolveGenerator::createPRISMfromTRI(const ElemType prism_elem_type,
    1690             :                                      const Elem * elem,
    1691             :                                      const std::unique_ptr<MeshBase> & mesh,
    1692             :                                      std::unique_ptr<Elem> & new_elem,
    1693             :                                      const int current_layer,
    1694             :                                      const unsigned int orig_nodes,
    1695             :                                      const unsigned int total_num_azimuthal_intervals,
    1696             :                                      std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    1697             :                                      bool & is_flipped) const
    1698             : {
    1699        3702 :   if (prism_elem_type != PRISM6 && prism_elem_type != PRISM18 && prism_elem_type != PRISM21)
    1700           0 :     mooseError("unsupported situation");
    1701             : 
    1702        3702 :   side_pairs.push_back(std::make_pair(0, 4));
    1703        3702 :   const unsigned int order = prism_elem_type == PRISM6 ? 1 : 2;
    1704             : 
    1705        3702 :   new_elem = std::make_unique<Prism6>();
    1706             : 
    1707        3702 :   if (order == 2)
    1708             :   {
    1709         408 :     new_elem = std::make_unique<Prism18>();
    1710         408 :     if (prism_elem_type == PRISM21)
    1711             :     {
    1712         408 :       new_elem = std::make_unique<Prism21>();
    1713         204 :       new_elem->set_node(
    1714         204 :           18, mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
    1715         204 :       new_elem->set_node(
    1716             :           19,
    1717         204 :           mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer + 1) %
    1718         204 :                                                     (total_num_azimuthal_intervals + 1 -
    1719         204 :                                                      (unsigned int)_full_circle_revolving) *
    1720         204 :                                                     2 * orig_nodes)));
    1721         204 :       new_elem->set_node(
    1722         204 :           20, mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1723             :     }
    1724         408 :     new_elem->set_node(6,
    1725         408 :                        mesh->node_ptr(elem->node_ptr(3)->id() + (current_layer * 2 * orig_nodes)));
    1726         408 :     new_elem->set_node(7,
    1727         408 :                        mesh->node_ptr(elem->node_ptr(4)->id() + (current_layer * 2 * orig_nodes)));
    1728         408 :     new_elem->set_node(8,
    1729         408 :                        mesh->node_ptr(elem->node_ptr(5)->id() + (current_layer * 2 * orig_nodes)));
    1730         408 :     new_elem->set_node(
    1731         408 :         9, mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1732         408 :     new_elem->set_node(
    1733         408 :         10, mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1734         408 :     new_elem->set_node(
    1735         408 :         11, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1736         408 :     new_elem->set_node(
    1737             :         12,
    1738         408 :         mesh->node_ptr(elem->node_ptr(3)->id() +
    1739         408 :                        ((current_layer + 1) %
    1740         408 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1741         408 :                         2 * orig_nodes)));
    1742         408 :     new_elem->set_node(
    1743             :         13,
    1744         408 :         mesh->node_ptr(elem->node_ptr(4)->id() +
    1745         408 :                        ((current_layer + 1) %
    1746         408 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1747         408 :                         2 * orig_nodes)));
    1748         408 :     new_elem->set_node(
    1749             :         14,
    1750         408 :         mesh->node_ptr(elem->node_ptr(5)->id() +
    1751         408 :                        ((current_layer + 1) %
    1752         408 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1753         408 :                         2 * orig_nodes)));
    1754         408 :     new_elem->set_node(
    1755         408 :         15, mesh->node_ptr(elem->node_ptr(3)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1756         408 :     new_elem->set_node(
    1757         408 :         16, mesh->node_ptr(elem->node_ptr(4)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1758         408 :     new_elem->set_node(
    1759         408 :         17, mesh->node_ptr(elem->node_ptr(5)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    1760             :   }
    1761        3702 :   new_elem->set_node(
    1762        3702 :       0, mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * order * orig_nodes)));
    1763        3702 :   new_elem->set_node(
    1764        3702 :       1, mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * order * orig_nodes)));
    1765        3702 :   new_elem->set_node(
    1766        3702 :       2, mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * order * orig_nodes)));
    1767        3702 :   new_elem->set_node(
    1768             :       3,
    1769        3702 :       mesh->node_ptr(elem->node_ptr(0)->id() +
    1770        3702 :                      ((current_layer + 1) %
    1771        3702 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1772        3702 :                       order * orig_nodes)));
    1773        3702 :   new_elem->set_node(
    1774             :       4,
    1775        3702 :       mesh->node_ptr(elem->node_ptr(1)->id() +
    1776        3702 :                      ((current_layer + 1) %
    1777        3702 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1778        3702 :                       order * orig_nodes)));
    1779        3702 :   new_elem->set_node(
    1780             :       5,
    1781        3702 :       mesh->node_ptr(elem->node_ptr(2)->id() +
    1782        3702 :                      ((current_layer + 1) %
    1783        3702 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1784        3702 :                       order * orig_nodes)));
    1785             : 
    1786        3702 :   if (new_elem->volume() < 0.0)
    1787             :   {
    1788        1110 :     MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
    1789        1110 :     MooseMeshUtils::swapNodesInElem(*new_elem, 1, 4);
    1790        1110 :     MooseMeshUtils::swapNodesInElem(*new_elem, 2, 5);
    1791        1110 :     if (prism_elem_type != PRISM6)
    1792             :     {
    1793         408 :       MooseMeshUtils::swapNodesInElem(*new_elem, 6, 12);
    1794         408 :       MooseMeshUtils::swapNodesInElem(*new_elem, 7, 13);
    1795         408 :       MooseMeshUtils::swapNodesInElem(*new_elem, 8, 14);
    1796         408 :       if (prism_elem_type == PRISM21)
    1797             :       {
    1798         204 :         MooseMeshUtils::swapNodesInElem(*new_elem, 18, 19);
    1799             :       }
    1800             :     }
    1801        1110 :     is_flipped = true;
    1802             :   }
    1803        3702 : }
    1804             : 
    1805             : void
    1806         432 : RevolveGenerator::createPYRAMIDfromTRI(
    1807             :     const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
    1808             :     const ElemType pyramid_elem_type,
    1809             :     const Elem * elem,
    1810             :     const std::unique_ptr<MeshBase> & mesh,
    1811             :     std::unique_ptr<Elem> & new_elem,
    1812             :     const int current_layer,
    1813             :     const unsigned int orig_nodes,
    1814             :     const unsigned int total_num_azimuthal_intervals,
    1815             :     std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    1816             :     dof_id_type & axis_node_case,
    1817             :     bool & is_flipped) const
    1818             : {
    1819         432 :   if (pyramid_elem_type != PYRAMID5 && pyramid_elem_type != PYRAMID13 &&
    1820         432 :       pyramid_elem_type != PYRAMID18)
    1821           0 :     mooseError("unsupported situation");
    1822             : 
    1823         432 :   side_pairs.push_back(std::make_pair(0, 2));
    1824         432 :   const unsigned int order = pyramid_elem_type == PYRAMID5 ? 1 : 2;
    1825         432 :   axis_node_case = nodes_cates.first.front();
    1826             : 
    1827         432 :   new_elem = std::make_unique<Pyramid5>();
    1828             : 
    1829         432 :   if (order == 2)
    1830             :   {
    1831         216 :     new_elem = std::make_unique<Pyramid13>();
    1832         216 :     if (pyramid_elem_type == PYRAMID18)
    1833             :     {
    1834         216 :       new_elem = std::make_unique<Pyramid18>();
    1835         108 :       new_elem->set_node(13,
    1836         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3 + 3)->id() +
    1837         108 :                                         ((current_layer * 2 + 1) * orig_nodes)));
    1838         108 :       new_elem->set_node(15,
    1839         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3 + 3)->id() +
    1840             :                                         ((current_layer * 2 + 1) * orig_nodes)));
    1841         108 :       new_elem->set_node(17,
    1842         108 :                          mesh->node_ptr(elem->node_ptr(axis_node_case + 3)->id() +
    1843             :                                         ((current_layer * 2 + 1) * orig_nodes)));
    1844         108 :       new_elem->set_node(
    1845         108 :           14, mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
    1846         108 :       new_elem->set_node(
    1847             :           16,
    1848         108 :           mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer + 1) %
    1849         108 :                                                     (total_num_azimuthal_intervals + 1 -
    1850         108 :                                                      (unsigned int)_full_circle_revolving) *
    1851         108 :                                                     2 * orig_nodes)));
    1852             :     }
    1853         216 :     new_elem->set_node(6,
    1854         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3)->id() +
    1855         216 :                                       ((current_layer * 2 + 1) * orig_nodes)));
    1856         216 :     new_elem->set_node(8,
    1857         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3)->id() +
    1858             :                                       ((current_layer * 2 + 1) * orig_nodes)));
    1859         216 :     new_elem->set_node(5,
    1860         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3 + 3)->id() +
    1861         216 :                                       (current_layer * 2 * orig_nodes)));
    1862         216 :     new_elem->set_node(
    1863             :         7,
    1864         216 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3 + 3)->id() +
    1865         216 :                        ((current_layer + 1) %
    1866         216 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1867         216 :                         2 * orig_nodes)));
    1868         216 :     new_elem->set_node(9,
    1869         216 :                        mesh->node_ptr(elem->node_ptr(axis_node_case + 3)->id() +
    1870             :                                       (current_layer * 2 * orig_nodes)));
    1871         216 :     new_elem->set_node(10,
    1872         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3 + 3)->id() +
    1873             :                                       (current_layer * 2 * orig_nodes)));
    1874         216 :     new_elem->set_node(
    1875             :         12,
    1876         216 :         mesh->node_ptr(elem->node_ptr(axis_node_case + 3)->id() +
    1877         216 :                        ((current_layer + 1) %
    1878         216 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1879         216 :                         2 * orig_nodes)));
    1880         216 :     new_elem->set_node(
    1881             :         11,
    1882         216 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3 + 3)->id() +
    1883         216 :                        ((current_layer + 1) %
    1884         216 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1885         216 :                         2 * orig_nodes)));
    1886             :   }
    1887         432 :   new_elem->set_node(4, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
    1888         432 :   new_elem->set_node(0,
    1889         432 :                      mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3)->id() +
    1890         432 :                                     (current_layer * order * orig_nodes)));
    1891         432 :   new_elem->set_node(1,
    1892         432 :                      mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3)->id() +
    1893             :                                     (current_layer * order * orig_nodes)));
    1894         432 :   new_elem->set_node(
    1895             :       2,
    1896         432 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3)->id() +
    1897         432 :                      ((current_layer + 1) %
    1898         432 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1899         432 :                       order * orig_nodes)));
    1900         432 :   new_elem->set_node(
    1901             :       3,
    1902         432 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3)->id() +
    1903         432 :                      ((current_layer + 1) %
    1904         432 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    1905         432 :                       order * orig_nodes)));
    1906             : 
    1907         432 :   if (new_elem->volume() < 0.0)
    1908             :   {
    1909           0 :     MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
    1910           0 :     MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
    1911           0 :     if (order == 2)
    1912             :     {
    1913           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 5, 7);
    1914           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
    1915           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 9, 12);
    1916           0 :       if (pyramid_elem_type == PYRAMID18)
    1917             :       {
    1918           0 :         MooseMeshUtils::swapNodesInElem(*new_elem, 14, 16);
    1919             :       }
    1920             :     }
    1921           0 :     is_flipped = true;
    1922             :   }
    1923         432 : }
    1924             : 
    1925             : void
    1926         246 : RevolveGenerator::createTETfromTRI(
    1927             :     const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
    1928             :     const ElemType tet_elem_type,
    1929             :     const Elem * elem,
    1930             :     const std::unique_ptr<MeshBase> & mesh,
    1931             :     std::unique_ptr<Elem> & new_elem,
    1932             :     const int current_layer,
    1933             :     const unsigned int orig_nodes,
    1934             :     const unsigned int total_num_azimuthal_intervals,
    1935             :     std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    1936             :     dof_id_type & axis_node_case,
    1937             :     bool & is_flipped) const
    1938             : {
    1939         246 :   if (tet_elem_type != TET4 && tet_elem_type != TET10 && tet_elem_type != TET14)
    1940           0 :     mooseError("unsupported situation");
    1941             : 
    1942         246 :   side_pairs.push_back(std::make_pair(0, 1));
    1943         246 :   const unsigned int order = tet_elem_type == TET4 ? 1 : 2;
    1944             :   if (order == 2)
    1945             :   {
    1946             :     // Sanity check to filter unsupported cases
    1947         192 :     if (nodes_cates.first[0] > 2 || nodes_cates.first[1] > 2 || nodes_cates.first[2] < 3)
    1948           0 :       mooseError("unsupported situation 2");
    1949             :   }
    1950         246 :   axis_node_case = nodes_cates.second.front();
    1951             : 
    1952         246 :   new_elem = std::make_unique<Tet4>();
    1953         246 :   if (order == 2)
    1954             :   {
    1955         192 :     const bool node_order = nodes_cates.first[1] - nodes_cates.first[0] == 1;
    1956         192 :     new_elem = std::make_unique<Tet10>();
    1957         192 :     if (tet_elem_type == TET14)
    1958             :     {
    1959         192 :       new_elem = std::make_unique<Tet14>();
    1960          96 :       new_elem->set_node(
    1961             :           12,
    1962          96 :           mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[1] + 3)
    1963          96 :                                                    : (nodes_cates.second.front() + 3))
    1964             :                              ->id() +
    1965          96 :                          ((current_layer * 2 + 1) * orig_nodes)));
    1966          96 :       new_elem->set_node(13,
    1967          96 :                          mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.second.front() + 3)
    1968          96 :                                                                   : (nodes_cates.first[0] + 3))
    1969             :                                             ->id() +
    1970             :                                         ((current_layer * 2 + 1) * orig_nodes)));
    1971          96 :       new_elem->set_node(
    1972          96 :           10, mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
    1973          96 :       new_elem->set_node(
    1974             :           11,
    1975          96 :           mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer + 1) %
    1976          96 :                                                     (total_num_azimuthal_intervals + 1 -
    1977          96 :                                                      (unsigned int)_full_circle_revolving) *
    1978          96 :                                                     2 * orig_nodes)));
    1979             :     }
    1980         192 :     new_elem->set_node(4,
    1981         192 :                        mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[0] + 3)
    1982         192 :                                                                 : (nodes_cates.first[1] + 3))
    1983             :                                           ->id()));
    1984         192 :     new_elem->set_node(5,
    1985         192 :                        mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[1] + 3)
    1986         192 :                                                                 : (nodes_cates.second.front() + 3))
    1987             :                                           ->id() +
    1988         192 :                                       (current_layer * 2 * orig_nodes)));
    1989         192 :     new_elem->set_node(6,
    1990         192 :                        mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.second.front() + 3)
    1991         192 :                                                                 : (nodes_cates.first[0] + 3))
    1992             :                                           ->id() +
    1993             :                                       (current_layer * 2 * orig_nodes)));
    1994         192 :     new_elem->set_node(
    1995             :         8,
    1996         192 :         mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[1] + 3)
    1997         192 :                                                  : (nodes_cates.second.front() + 3))
    1998             :                            ->id() +
    1999         192 :                        ((current_layer + 1) %
    2000         192 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2001         192 :                         2 * orig_nodes)));
    2002         192 :     new_elem->set_node(
    2003             :         7,
    2004         192 :         mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.second.front() + 3)
    2005         192 :                                                  : (nodes_cates.first[0] + 3))
    2006             :                            ->id() +
    2007         192 :                        ((current_layer + 1) %
    2008         192 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2009         192 :                         2 * orig_nodes)));
    2010         192 :     new_elem->set_node(9,
    2011         192 :                        mesh->node_ptr(elem->node_ptr(nodes_cates.second.front())->id() +
    2012         192 :                                       ((current_layer * 2 + 1) * orig_nodes)));
    2013             :   }
    2014         246 :   new_elem->set_node(0, mesh->node_ptr(elem->node_ptr(nodes_cates.first[0])->id()));
    2015         246 :   new_elem->set_node(1, mesh->node_ptr(elem->node_ptr(nodes_cates.first[1])->id()));
    2016         246 :   new_elem->set_node(2,
    2017         246 :                      mesh->node_ptr(elem->node_ptr(nodes_cates.second.front())->id() +
    2018         246 :                                     (current_layer * order * orig_nodes)));
    2019         246 :   new_elem->set_node(
    2020             :       3,
    2021         246 :       mesh->node_ptr(elem->node_ptr(nodes_cates.second.front())->id() +
    2022         246 :                      ((current_layer + 1) %
    2023         246 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2024         246 :                       order * orig_nodes)));
    2025             : 
    2026         246 :   if (new_elem->volume() < 0.0)
    2027             :   {
    2028          54 :     MooseMeshUtils::swapNodesInElem(*new_elem, 2, 3);
    2029          54 :     if (order == 2)
    2030             :     {
    2031           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 5, 8);
    2032           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 6, 7);
    2033           0 :       if (tet_elem_type == TET14)
    2034             :       {
    2035           0 :         MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
    2036             :       }
    2037             :     }
    2038          54 :     is_flipped = true;
    2039             :   }
    2040         246 : }
    2041             : 
    2042             : void
    2043        7506 : RevolveGenerator::createHEXfromQUAD(const ElemType hex_elem_type,
    2044             :                                     const Elem * elem,
    2045             :                                     const std::unique_ptr<MeshBase> & mesh,
    2046             :                                     std::unique_ptr<Elem> & new_elem,
    2047             :                                     const int current_layer,
    2048             :                                     const unsigned int orig_nodes,
    2049             :                                     const unsigned int total_num_azimuthal_intervals,
    2050             :                                     std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    2051             :                                     bool & is_flipped) const
    2052             : {
    2053        7506 :   if (hex_elem_type != HEX8 && hex_elem_type != HEX20 && hex_elem_type != HEX27)
    2054           0 :     mooseError("unsupported situation");
    2055             : 
    2056        7506 :   side_pairs.push_back(std::make_pair(0, 5));
    2057        7506 :   const unsigned int order = hex_elem_type == HEX8 ? 1 : 2;
    2058             : 
    2059        7506 :   new_elem = std::make_unique<Hex8>();
    2060        7506 :   if (order == 2)
    2061             :   {
    2062         540 :     new_elem = std::make_unique<Hex20>();
    2063         540 :     if (hex_elem_type == HEX27)
    2064             :     {
    2065         540 :       new_elem = std::make_unique<Hex27>();
    2066         270 :       new_elem->set_node(
    2067         270 :           20, mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
    2068         270 :       new_elem->set_node(
    2069             :           25,
    2070         270 :           mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer + 1) %
    2071         270 :                                                     (total_num_azimuthal_intervals + 1 -
    2072         270 :                                                      (unsigned int)_full_circle_revolving) *
    2073         270 :                                                     2 * orig_nodes)));
    2074         270 :       new_elem->set_node(
    2075         270 :           26, mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2076         270 :       new_elem->set_node(
    2077         270 :           21, mesh->node_ptr(elem->node_ptr(4)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2078         270 :       new_elem->set_node(
    2079         270 :           22, mesh->node_ptr(elem->node_ptr(5)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2080         270 :       new_elem->set_node(
    2081         270 :           23, mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2082         270 :       new_elem->set_node(
    2083         270 :           24, mesh->node_ptr(elem->node_ptr(7)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2084             :     }
    2085         540 :     new_elem->set_node(8,
    2086         540 :                        mesh->node_ptr(elem->node_ptr(4)->id() + (current_layer * 2 * orig_nodes)));
    2087         540 :     new_elem->set_node(9,
    2088         540 :                        mesh->node_ptr(elem->node_ptr(5)->id() + (current_layer * 2 * orig_nodes)));
    2089         540 :     new_elem->set_node(10,
    2090         540 :                        mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
    2091         540 :     new_elem->set_node(11,
    2092         540 :                        mesh->node_ptr(elem->node_ptr(7)->id() + (current_layer * 2 * orig_nodes)));
    2093         540 :     new_elem->set_node(
    2094             :         16,
    2095         540 :         mesh->node_ptr(elem->node_ptr(4)->id() +
    2096         540 :                        ((current_layer + 1) %
    2097         540 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2098         540 :                         2 * orig_nodes)));
    2099         540 :     new_elem->set_node(
    2100             :         17,
    2101         540 :         mesh->node_ptr(elem->node_ptr(5)->id() +
    2102         540 :                        ((current_layer + 1) %
    2103         540 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2104         540 :                         2 * orig_nodes)));
    2105         540 :     new_elem->set_node(
    2106             :         18,
    2107         540 :         mesh->node_ptr(elem->node_ptr(6)->id() +
    2108         540 :                        ((current_layer + 1) %
    2109         540 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2110         540 :                         2 * orig_nodes)));
    2111         540 :     new_elem->set_node(
    2112             :         19,
    2113         540 :         mesh->node_ptr(elem->node_ptr(7)->id() +
    2114         540 :                        ((current_layer + 1) %
    2115         540 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2116         540 :                         2 * orig_nodes)));
    2117         540 :     new_elem->set_node(
    2118         540 :         12, mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2119         540 :     new_elem->set_node(
    2120         540 :         13, mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2121         540 :     new_elem->set_node(
    2122         540 :         14, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2123         540 :     new_elem->set_node(
    2124         540 :         15, mesh->node_ptr(elem->node_ptr(3)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2125             :   }
    2126        7506 :   new_elem->set_node(
    2127        7506 :       0, mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * order * orig_nodes)));
    2128        7506 :   new_elem->set_node(
    2129        7506 :       1, mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * order * orig_nodes)));
    2130        7506 :   new_elem->set_node(
    2131        7506 :       2, mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * order * orig_nodes)));
    2132        7506 :   new_elem->set_node(
    2133        7506 :       3, mesh->node_ptr(elem->node_ptr(3)->id() + (current_layer * order * orig_nodes)));
    2134        7506 :   new_elem->set_node(
    2135             :       4,
    2136        7506 :       mesh->node_ptr(elem->node_ptr(0)->id() +
    2137        7506 :                      ((current_layer + 1) %
    2138        7506 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2139        7506 :                       order * orig_nodes)));
    2140        7506 :   new_elem->set_node(
    2141             :       5,
    2142        7506 :       mesh->node_ptr(elem->node_ptr(1)->id() +
    2143        7506 :                      ((current_layer + 1) %
    2144        7506 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2145        7506 :                       order * orig_nodes)));
    2146        7506 :   new_elem->set_node(
    2147             :       6,
    2148        7506 :       mesh->node_ptr(elem->node_ptr(2)->id() +
    2149        7506 :                      ((current_layer + 1) %
    2150        7506 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2151        7506 :                       order * orig_nodes)));
    2152        7506 :   new_elem->set_node(
    2153             :       7,
    2154        7506 :       mesh->node_ptr(elem->node_ptr(3)->id() +
    2155        7506 :                      ((current_layer + 1) %
    2156        7506 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2157        7506 :                       order * orig_nodes)));
    2158             : 
    2159        7506 :   if (new_elem->volume() < 0.0)
    2160             :   {
    2161        2214 :     MooseMeshUtils::swapNodesInElem(*new_elem, 0, 4);
    2162        2214 :     MooseMeshUtils::swapNodesInElem(*new_elem, 1, 5);
    2163        2214 :     MooseMeshUtils::swapNodesInElem(*new_elem, 2, 6);
    2164        2214 :     MooseMeshUtils::swapNodesInElem(*new_elem, 3, 7);
    2165        2214 :     if (order == 2)
    2166             :     {
    2167         540 :       MooseMeshUtils::swapNodesInElem(*new_elem, 8, 16);
    2168         540 :       MooseMeshUtils::swapNodesInElem(*new_elem, 9, 17);
    2169         540 :       MooseMeshUtils::swapNodesInElem(*new_elem, 10, 18);
    2170         540 :       MooseMeshUtils::swapNodesInElem(*new_elem, 11, 19);
    2171         540 :       if (hex_elem_type == HEX27)
    2172             :       {
    2173         270 :         MooseMeshUtils::swapNodesInElem(*new_elem, 20, 25);
    2174             :       }
    2175             :     }
    2176        2214 :     is_flipped = true;
    2177             :   }
    2178        7506 : }
    2179             : 
    2180             : void
    2181         270 : RevolveGenerator::createPRISMfromQUAD(
    2182             :     const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
    2183             :     const ElemType prism_elem_type,
    2184             :     const Elem * elem,
    2185             :     const std::unique_ptr<MeshBase> & mesh,
    2186             :     std::unique_ptr<Elem> & new_elem,
    2187             :     const int current_layer,
    2188             :     const unsigned int orig_nodes,
    2189             :     const unsigned int total_num_azimuthal_intervals,
    2190             :     std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    2191             :     dof_id_type & axis_node_case,
    2192             :     bool & is_flipped) const
    2193             : {
    2194         270 :   if (prism_elem_type != PRISM6 && prism_elem_type != PRISM15 && prism_elem_type != PRISM18)
    2195           0 :     mooseError("unsupported situation");
    2196             : 
    2197         270 :   side_pairs.push_back(std::make_pair(1, 3));
    2198         270 :   const unsigned int order = prism_elem_type == PRISM6 ? 1 : 2;
    2199             :   if (order == 2)
    2200             :   {
    2201             :     // Sanity check to filter unsupported cases
    2202         216 :     if (nodes_cates.first[0] > 3 || nodes_cates.first[1] > 3 || nodes_cates.first[2] < 4)
    2203           0 :       mooseError("unsupported situation 2");
    2204             :   }
    2205             :   // Can only be 0-1, 1-2, 2-3, 3-0, we only consider vetices here.
    2206             :   // nodes_cates are natually sorted
    2207         270 :   const dof_id_type min_on_axis = nodes_cates.first[0];
    2208         270 :   const dof_id_type max_on_axis = nodes_cates.first[1];
    2209         270 :   axis_node_case = max_on_axis - min_on_axis == 1 ? min_on_axis : max_on_axis;
    2210             : 
    2211         270 :   new_elem = std::make_unique<Prism6>();
    2212         270 :   if (order == 2)
    2213             :   {
    2214         216 :     new_elem = std::make_unique<Prism15>();
    2215         216 :     if (prism_elem_type == PRISM18)
    2216             :     {
    2217         216 :       new_elem = std::make_unique<Prism18>();
    2218         108 :       new_elem->set_node(
    2219         108 :           15, mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
    2220         108 :       new_elem->set_node(16,
    2221         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
    2222         108 :                                         ((current_layer * 2 + 1) * orig_nodes)));
    2223         108 :       new_elem->set_node(
    2224             :           17,
    2225         108 :           mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer + 1) %
    2226         108 :                                                     (total_num_azimuthal_intervals + 1 -
    2227         108 :                                                      (unsigned int)_full_circle_revolving) *
    2228         108 :                                                     2 * orig_nodes)));
    2229             :     }
    2230         216 :     new_elem->set_node(9, mesh->node_ptr(elem->node_ptr(axis_node_case + 4)->id()));
    2231         216 :     new_elem->set_node(10,
    2232         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
    2233         216 :                                       (current_layer * 2 * orig_nodes)));
    2234         216 :     new_elem->set_node(12,
    2235         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
    2236             :                                       (current_layer * 2 * orig_nodes)));
    2237         216 :     new_elem->set_node(6,
    2238         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
    2239             :                                       (current_layer * 2 * orig_nodes)));
    2240         216 :     new_elem->set_node(
    2241             :         14,
    2242         216 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
    2243         216 :                        ((current_layer + 1) %
    2244         216 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2245         216 :                         2 * orig_nodes)));
    2246         216 :     new_elem->set_node(
    2247             :         8,
    2248         216 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
    2249         216 :                        ((current_layer + 1) %
    2250         216 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2251         216 :                         2 * orig_nodes)));
    2252         216 :     new_elem->set_node(
    2253             :         11,
    2254         216 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
    2255         216 :                        ((current_layer + 1) %
    2256         216 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2257         216 :                         2 * orig_nodes)));
    2258         216 :     new_elem->set_node(7,
    2259         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2260         216 :                                       ((current_layer * 2 + 1) * orig_nodes)));
    2261         216 :     new_elem->set_node(13,
    2262         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
    2263             :                                       ((current_layer * 2 + 1) * orig_nodes)));
    2264             :   }
    2265         270 :   new_elem->set_node(0, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
    2266         270 :   new_elem->set_node(3, mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id()));
    2267         270 :   new_elem->set_node(4,
    2268         270 :                      mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
    2269         270 :                                     (current_layer * order * orig_nodes)));
    2270         270 :   new_elem->set_node(1,
    2271         270 :                      mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2272             :                                     (current_layer * order * orig_nodes)));
    2273         270 :   new_elem->set_node(
    2274             :       5,
    2275         270 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
    2276         270 :                      ((current_layer + 1) %
    2277         270 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2278         270 :                       order * orig_nodes)));
    2279         270 :   new_elem->set_node(
    2280             :       2,
    2281         270 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2282         270 :                      ((current_layer + 1) %
    2283         270 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2284         270 :                       order * orig_nodes)));
    2285             : 
    2286         270 :   if (new_elem->volume() < 0.0)
    2287             :   {
    2288         270 :     MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
    2289         270 :     MooseMeshUtils::swapNodesInElem(*new_elem, 4, 5);
    2290         270 :     if (order == 2)
    2291             :     {
    2292         216 :       MooseMeshUtils::swapNodesInElem(*new_elem, 12, 14);
    2293         216 :       MooseMeshUtils::swapNodesInElem(*new_elem, 6, 8);
    2294         216 :       MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
    2295         216 :       if (prism_elem_type == PRISM18)
    2296             :       {
    2297         108 :         MooseMeshUtils::swapNodesInElem(*new_elem, 15, 17);
    2298             :       }
    2299             :     }
    2300         270 :     is_flipped = true;
    2301             :   }
    2302         270 : }
    2303             : 
    2304             : void
    2305         216 : RevolveGenerator::createPYRAMIDPRISMfromQUAD(
    2306             :     const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
    2307             :     const ElemType pyramid_elem_type,
    2308             :     const ElemType prism_elem_type,
    2309             :     const Elem * elem,
    2310             :     const std::unique_ptr<MeshBase> & mesh,
    2311             :     std::unique_ptr<Elem> & new_elem,
    2312             :     std::unique_ptr<Elem> & new_elem_1,
    2313             :     const int current_layer,
    2314             :     const unsigned int orig_nodes,
    2315             :     const unsigned int total_num_azimuthal_intervals,
    2316             :     std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
    2317             :     dof_id_type & axis_node_case,
    2318             :     bool & is_flipped,
    2319             :     bool & is_flipped_additional) const
    2320             : {
    2321         216 :   if (!(pyramid_elem_type == PYRAMID5 && prism_elem_type == PRISM6) &&
    2322         108 :       !(pyramid_elem_type == PYRAMID14 && prism_elem_type == PRISM18))
    2323           0 :     mooseError("unsupported situation");
    2324             :   const unsigned int order = pyramid_elem_type == PYRAMID5 ? 1 : 2;
    2325             : 
    2326         216 :   side_pairs.push_back(std::make_pair(0, 2));
    2327         216 :   axis_node_case = nodes_cates.first.front();
    2328         216 :   new_elem = std::make_unique<Pyramid5>();
    2329         216 :   if (pyramid_elem_type == PYRAMID14)
    2330             :   {
    2331         216 :     new_elem = std::make_unique<Pyramid14>();
    2332         108 :     new_elem->set_node(9,
    2333         108 :                        mesh->node_ptr(elem->node_ptr(axis_node_case + 4)->id() +
    2334         108 :                                       (current_layer * 2 * orig_nodes)));
    2335         108 :     new_elem->set_node(10,
    2336         108 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
    2337             :                                       (current_layer * 2 * orig_nodes)));
    2338         108 :     new_elem->set_node(5,
    2339         108 :                        mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
    2340         108 :     new_elem->set_node(8,
    2341         108 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
    2342         108 :                                       ((current_layer * 2 + 1) * orig_nodes)));
    2343         108 :     new_elem->set_node(6,
    2344         108 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2345             :                                       ((current_layer * 2 + 1) * orig_nodes)));
    2346         108 :     new_elem->set_node(
    2347         108 :         13, mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2348         108 :     new_elem->set_node(
    2349             :         7,
    2350         108 :         mesh->node_ptr(elem->node_ptr(8)->id() +
    2351         108 :                        ((current_layer + 1) %
    2352         108 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2353         108 :                         2 * orig_nodes)));
    2354         108 :     new_elem->set_node(
    2355             :         11,
    2356         108 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
    2357         108 :                        ((current_layer + 1) %
    2358         108 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2359         108 :                         2 * orig_nodes)));
    2360         108 :     new_elem->set_node(
    2361             :         12,
    2362         108 :         mesh->node_ptr(elem->node_ptr(axis_node_case + 4)->id() +
    2363         108 :                        ((current_layer + 1) %
    2364         108 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2365         108 :                         2 * orig_nodes)));
    2366             :   }
    2367         216 :   new_elem->set_node(4, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
    2368         216 :   new_elem->set_node(0,
    2369         216 :                      mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
    2370         216 :                                     (current_layer * order * orig_nodes)));
    2371         216 :   new_elem->set_node(1,
    2372         216 :                      mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2373             :                                     (current_layer * order * orig_nodes)));
    2374         216 :   new_elem->set_node(
    2375             :       2,
    2376         216 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2377         216 :                      ((current_layer + 1) %
    2378         216 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2379         216 :                       order * orig_nodes)));
    2380         216 :   new_elem->set_node(
    2381             :       3,
    2382         216 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
    2383         216 :                      ((current_layer + 1) %
    2384         216 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2385         216 :                       order * orig_nodes)));
    2386             : 
    2387         216 :   if (new_elem->volume() < 0.0)
    2388             :   {
    2389           0 :     MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
    2390           0 :     MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
    2391           0 :     if (pyramid_elem_type == PYRAMID14)
    2392             :     {
    2393           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 5, 7);
    2394           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
    2395           0 :       MooseMeshUtils::swapNodesInElem(*new_elem, 9, 12);
    2396             :     }
    2397           0 :     is_flipped = true;
    2398             :   }
    2399             : 
    2400         216 :   side_pairs.push_back(std::make_pair(0, 4));
    2401         216 :   new_elem_1 = std::make_unique<Prism6>();
    2402         216 :   if (prism_elem_type == PRISM18)
    2403             :   {
    2404         216 :     new_elem_1 = std::make_unique<Prism18>();
    2405         108 :     new_elem_1->set_node(
    2406         108 :         6, mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
    2407         108 :     new_elem_1->set_node(8,
    2408         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
    2409             :                                         (current_layer * 2 * orig_nodes)));
    2410         108 :     new_elem_1->set_node(7,
    2411         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
    2412             :                                         (current_layer * 2 * orig_nodes)));
    2413         108 :     new_elem_1->set_node(9,
    2414         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
    2415         108 :                                         ((current_layer * 2 + 1) * orig_nodes)));
    2416         108 :     new_elem_1->set_node(10,
    2417         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2418             :                                         ((current_layer * 2 + 1) * orig_nodes)));
    2419         108 :     new_elem_1->set_node(11,
    2420         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
    2421             :                                         ((current_layer * 2 + 1) * orig_nodes)));
    2422         108 :     new_elem_1->set_node(
    2423         108 :         15, mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer * 2 + 1) * orig_nodes)));
    2424         108 :     new_elem_1->set_node(17,
    2425         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
    2426             :                                         ((current_layer * 2 + 1) * orig_nodes)));
    2427         108 :     new_elem_1->set_node(16,
    2428         108 :                          mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
    2429             :                                         ((current_layer * 2 + 1) * orig_nodes)));
    2430         108 :     new_elem_1->set_node(
    2431             :         12,
    2432         108 :         mesh->node_ptr(elem->node_ptr(8)->id() +
    2433         108 :                        ((current_layer + 1) %
    2434         108 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2435         108 :                         2 * orig_nodes)));
    2436         108 :     new_elem_1->set_node(
    2437             :         13,
    2438         108 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
    2439         108 :                        ((current_layer + 1) %
    2440         108 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2441         108 :                         2 * orig_nodes)));
    2442         108 :     new_elem_1->set_node(
    2443             :         14,
    2444         108 :         mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
    2445         108 :                        ((current_layer + 1) %
    2446         108 :                         (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2447         108 :                         2 * orig_nodes)));
    2448             :   }
    2449         216 :   new_elem_1->set_node(0,
    2450         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
    2451             :                                       (current_layer * order * orig_nodes)));
    2452         216 :   new_elem_1->set_node(1,
    2453         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2454             :                                       (current_layer * order * orig_nodes)));
    2455         216 :   new_elem_1->set_node(2,
    2456         216 :                        mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
    2457             :                                       (current_layer * order * orig_nodes)));
    2458         216 :   new_elem_1->set_node(
    2459             :       3,
    2460         216 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
    2461         216 :                      ((current_layer + 1) %
    2462         216 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2463         216 :                       order * orig_nodes)));
    2464         216 :   new_elem_1->set_node(
    2465             :       4,
    2466         216 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
    2467         216 :                      ((current_layer + 1) %
    2468         216 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2469         216 :                       order * orig_nodes)));
    2470         216 :   new_elem_1->set_node(
    2471             :       5,
    2472         216 :       mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
    2473         216 :                      ((current_layer + 1) %
    2474         216 :                       (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
    2475         216 :                       order * orig_nodes)));
    2476             : 
    2477         216 :   if (new_elem_1->volume() < 0.0)
    2478             :   {
    2479           0 :     MooseMeshUtils::swapNodesInElem(*new_elem_1, 0, 3);
    2480           0 :     MooseMeshUtils::swapNodesInElem(*new_elem_1, 1, 4);
    2481           0 :     MooseMeshUtils::swapNodesInElem(*new_elem_1, 2, 5);
    2482           0 :     if (prism_elem_type == PRISM18)
    2483             :     {
    2484           0 :       MooseMeshUtils::swapNodesInElem(*new_elem_1, 6, 12);
    2485           0 :       MooseMeshUtils::swapNodesInElem(*new_elem_1, 7, 13);
    2486           0 :       MooseMeshUtils::swapNodesInElem(*new_elem_1, 8, 14);
    2487             :     }
    2488           0 :     is_flipped_additional = true;
    2489             :   }
    2490         216 : }

Generated by: LCOV version 1.14