LCOV - code coverage report
Current view: top level - src/meshgenerators - TriPinHexAssemblyGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #31405 (292dce) with base fef103 Lines: 243 246 98.8 %
Date: 2025-09-04 07:56:24 Functions: 4 4 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 "TriPinHexAssemblyGenerator.h"
      11             : #include "PolygonalMeshGenerationUtils.h"
      12             : #include "libmesh/mesh_smoother_laplace.h"
      13             : 
      14             : #include <cmath>
      15             : 
      16             : registerMooseObject("ReactorApp", TriPinHexAssemblyGenerator);
      17             : 
      18             : InputParameters
      19         132 : TriPinHexAssemblyGenerator::validParams()
      20             : {
      21         132 :   InputParameters params = PolygonMeshGeneratorBase::validParams();
      22         264 :   params.addRequiredRangeCheckedParam<unsigned int>(
      23             :       "num_sectors_per_side", "num_sectors_per_side>0", "Number of azimuthal sectors per side.");
      24         396 :   params.addRangeCheckedParam<unsigned int>(
      25             :       "background_intervals",
      26         264 :       1,
      27             :       "background_intervals>0",
      28             :       "Number of radial meshing intervals in background "
      29             :       "region (region around the rings/pins in the assembly).");
      30         264 :   params.addRangeCheckedParam<std::vector<subdomain_id_type>>(
      31             :       "background_block_ids",
      32             :       "background_block_ids>0",
      33             :       "Optional block ids for the background regions in the pins.");
      34         264 :   params.addParam<std::vector<SubdomainName>>(
      35             :       "background_block_names", "Optional block names for the background regions in the pins.");
      36         264 :   params.addRangeCheckedParam<std::vector<std::vector<Real>>>(
      37             :       "ring_radii", "ring_radii>0", "Radii of the three sets of major concentric circles (pins).");
      38         264 :   params.addRangeCheckedParam<std::vector<std::vector<unsigned int>>>(
      39             :       "ring_intervals",
      40             :       "ring_intervals>0",
      41             :       "Number of radial mesh intervals within each set of major concentric circles (pins).");
      42         264 :   params.addRangeCheckedParam<std::vector<std::vector<subdomain_id_type>>>(
      43             :       "ring_block_ids", "ring_block_ids>0", "Optional block ids for the ring (pin) regions.");
      44         264 :   params.addParam<std::vector<std::vector<SubdomainName>>>(
      45             :       "ring_block_names", "Optional block names for the ring (pin) regions.");
      46         264 :   MooseEnum hexagon_size_style("apothem radius", "radius");
      47         264 :   params.addParam<MooseEnum>("hexagon_size_style",
      48             :                              hexagon_size_style,
      49             :                              "Style in which hexagon size is given (apothem = center to face, "
      50             :                              "radius = center to vertex).");
      51         264 :   params.addRequiredRangeCheckedParam<Real>(
      52             :       "hexagon_size", "hexagon_size>0", "Size parameter of the hexagon assembly to be generated.");
      53         264 :   params.addParam<Real>(
      54         264 :       "ring_offset", 0.0, "Offset of the ring (pin) center, shared by all three.");
      55         264 :   params.addParam<bool>(
      56             :       "preserve_volumes",
      57         264 :       true,
      58             :       "Volume of concentric circles (pins) can be preserved using this function.");
      59         264 :   MooseEnum assembly_orientation("pin_up pin_down", "pin_up");
      60         264 :   params.addParam<MooseEnum>(
      61             :       "assembly_orientation", assembly_orientation, "Orientation of the generated assembly.");
      62         264 :   params.addRangeCheckedParam<boundary_id_type>("external_boundary_id",
      63             :                                                 "external_boundary_id>0",
      64             :                                                 "Optional customized external boundary id.");
      65         264 :   params.addParam<std::string>("external_boundary_name",
      66             :                                "Optional customized external boundary name.");
      67         264 :   params.addParam<std::string>(
      68             :       "pin_id_name", "Name of extra integer ID to be assigned to each of the three pin domains.");
      69         264 :   params.addParam<std::vector<dof_id_type>>(
      70             :       "pin_id_values",
      71             :       "Values of extra integer ID to be assigned to each of the three pin domains.");
      72         264 :   params.addParamNamesToGroup("ring_block_ids ring_block_names background_block_ids "
      73             :                               "background_block_names external_boundary_id external_boundary_name",
      74             :                               "Customized Subdomain/Boundary ids/names");
      75         132 :   addRingAndSectorIDParams(params);
      76         132 :   params.addClassDescription(
      77             :       "This TriPinHexAssemblyGenerator object generates a hexagonal assembly "
      78             :       "mesh with three circular pins in a triangle at the center.");
      79         132 :   return params;
      80         132 : }
      81             : 
      82          83 : TriPinHexAssemblyGenerator::TriPinHexAssemblyGenerator(const InputParameters & parameters)
      83             :   : PolygonMeshGeneratorBase(parameters),
      84          83 :     _ring_radii(getRingParamValues<Real>("ring_radii")),
      85          81 :     _has_rings({!_ring_radii[0].empty(), !_ring_radii[1].empty(), !_ring_radii[2].empty()}),
      86          81 :     _ring_intervals(getRingParamValues<unsigned int>("ring_intervals")),
      87          79 :     _ring_block_ids(getRingParamValues<subdomain_id_type>("ring_block_ids")),
      88         101 :     _ring_block_names(
      89          77 :         isParamValid("ring_block_names")
      90         154 :             ? (getParam<std::vector<std::vector<SubdomainName>>>("ring_block_names").size() == 1
      91          24 :                    ? std::vector<std::vector<SubdomainName>>(
      92             :                          3,
      93          77 :                          getParam<std::vector<std::vector<SubdomainName>>>("ring_block_names")
      94             :                              .front())
      95             :                    : getParam<std::vector<std::vector<SubdomainName>>>("ring_block_names"))
      96          77 :             : std::vector<std::vector<SubdomainName>>(3, std::vector<SubdomainName>())),
      97          77 :     _hexagon_size_style(
      98          77 :         getParam<MooseEnum>("hexagon_size_style").template getEnum<PolygonSizeStyle>()),
      99         154 :     _side_length(_hexagon_size_style == PolygonSizeStyle::radius
     100         145 :                      ? getParam<Real>("hexagon_size")
     101          95 :                      : (getParam<Real>("hexagon_size") / cos(M_PI / 6.0))),
     102         154 :     _ring_offset(getParam<Real>("ring_offset")),
     103         154 :     _preserve_volumes(getParam<bool>("preserve_volumes")),
     104          77 :     _assembly_orientation(
     105          77 :         getParam<MooseEnum>("assembly_orientation").template getEnum<AssmOrient>()),
     106         154 :     _num_sectors_per_side(getParam<unsigned int>("num_sectors_per_side")),
     107         154 :     _background_intervals(getParam<unsigned int>("background_intervals")),
     108         308 :     _background_block_ids(isParamValid("background_block_ids")
     109          77 :                               ? getParam<std::vector<subdomain_id_type>>("background_block_ids")
     110             :                               : std::vector<subdomain_id_type>()),
     111         202 :     _background_block_names(isParamValid("background_block_names")
     112          77 :                                 ? getParam<std::vector<SubdomainName>>("background_block_names")
     113             :                                 : std::vector<SubdomainName>()),
     114         209 :     _external_boundary_id(isParamValid("external_boundary_id")
     115         187 :                               ? getParam<boundary_id_type>("external_boundary_id")
     116             :                               : 0),
     117         264 :     _external_boundary_name(isParamValid("external_boundary_name")
     118          77 :                                 ? getParam<std::string>("external_boundary_name")
     119             :                                 : std::string()),
     120         251 :     _pin_id_name(isParamValid("pin_id_name") ? getParam<std::string>("pin_id_name")
     121             :                                              : std::string()),
     122         198 :     _pin_id_values(isParamValid("pin_id_values")
     123          77 :                        ? getParam<std::vector<dof_id_type>>("pin_id_values")
     124             :                        : std::vector<dof_id_type>()),
     125         160 :     _node_id_background_meta(declareMeshProperty<dof_id_type>("node_id_background_meta", 0))
     126             : {
     127          77 :   declareMeshProperty<Real>("pitch_meta", _side_length * std::sqrt(3.0));
     128          77 :   declareMeshProperty<Real>("pattern_pitch_meta", _side_length * std::sqrt(3.0));
     129          77 :   declareMeshProperty<bool>("is_control_drum_meta", false);
     130          77 :   declareMeshProperty<unsigned int>("background_intervals_meta", _background_intervals);
     131          77 :   declareMeshProperty<Real>("max_radius_meta", 0.0);
     132         154 :   declareMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta",
     133          77 :                                                  {_num_sectors_per_side,
     134             :                                                   _num_sectors_per_side,
     135             :                                                   _num_sectors_per_side,
     136             :                                                   _num_sectors_per_side,
     137             :                                                   _num_sectors_per_side,
     138             :                                                   _num_sectors_per_side});
     139             : 
     140             :   /* Parameter checks */
     141         306 :   for (unsigned int i = 0; i < 3; i++)
     142         231 :     if (_ring_intervals[i].size() != _ring_radii[i].size())
     143           2 :       paramError("ring_intervals", "The parameter must be consistent with ring_radii.");
     144         292 :   for (unsigned int i = 0; i < 3; i++)
     145             :   {
     146         225 :     if (!_has_rings[i] && !_ring_block_ids[i].empty())
     147           2 :       paramError("ring_block_ids", "The parameter must be consistent with ring_radii if provided.");
     148         223 :     else if (!_ring_block_ids[i].empty() &&
     149         166 :              _ring_block_ids[i].size() != (_ring_radii[i].size() + (_ring_intervals[i][0] > 1)))
     150           2 :       paramError("ring_block_ids", "The parameter must be consistent with ring_radii if provided.");
     151         221 :     if (!_has_rings[i] && !_ring_block_names[i].empty())
     152           2 :       paramError("ring_block_names",
     153             :                  "The parameter must be consistent with ring_radii if provided.");
     154         219 :     else if (!_ring_block_names[i].empty() &&
     155          50 :              _ring_block_names[i].size() != (_ring_radii[i].size() + (_ring_intervals[i][0] > 1)))
     156           2 :       paramError("ring_block_names",
     157             :                  "The parameter must be consistent with ring_radii if provided.");
     158             :   }
     159          67 :   if (!_background_block_ids.empty())
     160             :   {
     161          67 :     if (_has_rings[0] && _has_rings[1] && _has_rings[2] && _background_block_ids.size() != 1)
     162           2 :       paramError("background_block_ids",
     163             :                  "If provided, the size of this parameter must be one if all sections have rings.");
     164          65 :     else if (!_has_rings[0] && !_has_rings[1] && !_has_rings[2] && _background_intervals == 1 &&
     165             :              _background_block_ids.size() != 1)
     166           4 :       paramError("background_block_ids",
     167             :                  "If provided, the size of this parameter must be one if no sections have rings "
     168             :                  "and background_intervals is one.");
     169          61 :     else if ((!_has_rings[0] || !_has_rings[1] || !_has_rings[2]) &&
     170             :              _background_block_ids.size() != 2)
     171           2 :       paramError(
     172             :           "background_block_ids",
     173             :           "If provided, the size of this parameter must be two if ring-free section exists.");
     174             :   }
     175          59 :   if (!_background_block_names.empty())
     176             :   {
     177          22 :     if (_has_rings[0] && _has_rings[1] && _has_rings[2] && _background_block_names.size() != 1)
     178           2 :       paramError("background_block_names",
     179             :                  "If provided, the size of this parameter must be one if all sections have rings.");
     180          20 :     else if (!_has_rings[0] && !_has_rings[1] && !_has_rings[2] && _background_intervals == 1 &&
     181             :              _background_block_names.size() != 1)
     182           0 :       paramError("background_block_names",
     183             :                  "If provided, the size of this parameter must be one if no sections have rings "
     184             :                  "and background_intervals is one.");
     185          20 :     else if ((!_has_rings[0] || !_has_rings[1] || !_has_rings[2]) &&
     186             :              _background_block_names.size() != 2)
     187           2 :       paramError(
     188             :           "background_block_names",
     189             :           "If provided, the size of this parameter must be two if ring-free section exists.");
     190             :   }
     191          55 :   if (_pin_id_name.empty())
     192             :   {
     193          35 :     if (!_pin_id_values.empty())
     194           2 :       paramError("pin_id_values",
     195             :                  "This parameter cannot be used when pin_id_name is not provided.");
     196             :   }
     197          20 :   else if (_pin_id_values.size() != 3)
     198           2 :     paramError(
     199             :         "pin_id_values",
     200             :         "If pin_id_name is provided, this parameter must be provided with a length of three.");
     201             : 
     202             :   // Just perform a simple and straightforward check for `ring_offset` here.
     203             :   // A more comprehensive check for both `ring_offset` and `ring_radii` is done later.
     204          51 :   if (std::abs(_ring_offset) >= _side_length / 2.0)
     205           2 :     paramError(
     206             :         "ring_offset",
     207             :         "This parameter cannot translate the ring center out of the hexagon assembly region.");
     208          49 : }
     209             : 
     210             : std::unique_ptr<MeshBase>
     211          49 : TriPinHexAssemblyGenerator::generate()
     212             : {
     213             :   /* Pair specified block names and ids */
     214             :   std::set<subdomain_id_type> tmp_block_ids;
     215             :   std::set<SubdomainName> tmp_block_names;
     216             :   std::vector<std::pair<subdomain_id_type, SubdomainName>> block_info;
     217         192 :   for (unsigned int i = 0; i < 3; i++)
     218         241 :     for (unsigned int j = 0; j < _ring_block_names[i].size(); j++)
     219             :     {
     220          98 :       tmp_block_names.emplace(_ring_block_names[i][j]);
     221          98 :       tmp_block_ids.emplace(_ring_block_ids[i].empty() ? (j + 1) : _ring_block_ids[i][j]);
     222          98 :       if (tmp_block_names.size() != tmp_block_ids.size())
     223           2 :         paramError("ring_block_names",
     224             :                    "The block name assignment must be compatible with the existing block ids.");
     225             :       else
     226          96 :         block_info.push_back(std::make_pair(
     227          96 :             _ring_block_ids[i].empty() ? (j + 1) : _ring_block_ids[i][j], _ring_block_names[i][j]));
     228             :     }
     229             :   const subdomain_id_type max_ring_radii_size =
     230          47 :       std::max({_ring_radii[0].size(), _ring_radii[1].size(), _ring_radii[2].size()});
     231          74 :   for (unsigned int i = 0; i < _background_block_names.size(); i++)
     232             :   {
     233          27 :     tmp_block_names.emplace(_background_block_names[i]);
     234          27 :     tmp_block_ids.emplace(_background_block_ids.empty() ? (max_ring_radii_size + i)
     235             :                                                         : _background_block_ids[i]);
     236          27 :     if (tmp_block_names.size() != tmp_block_ids.size())
     237           0 :       paramError("background_block_names",
     238             :                  "The block name assignment must be compatible with the existing block ids.");
     239             :     else
     240          54 :       block_info.push_back(std::make_pair(_background_block_ids.empty() ? (max_ring_radii_size + i)
     241             :                                                                         : _background_block_ids[i],
     242             :                                           _background_block_names[i]));
     243             :   }
     244          47 :   std::vector<std::vector<subdomain_id_type>> block_ids_new(3, std::vector<subdomain_id_type>());
     245         188 :   for (unsigned int i = 0; i < 3; i++)
     246             :   {
     247         141 :     if (_has_rings[i])
     248             :     {
     249         392 :       for (unsigned int j = 0; j < (_ring_radii[i].size() + (_ring_intervals[i][0] > 1)); j++)
     250         280 :         block_ids_new[i].push_back(_ring_block_ids[i].empty() ? j + 1 : _ring_block_ids[i][j]);
     251         112 :       block_ids_new[i].push_back(_background_block_ids.empty() ? max_ring_radii_size + 1
     252             :                                                                : _background_block_ids.back());
     253             :     }
     254             :     else
     255             :     {
     256          29 :       block_ids_new[i].push_back(_background_block_ids.empty() ? (max_ring_radii_size + 1)
     257             :                                                                : _background_block_ids.front());
     258          29 :       block_ids_new[i].push_back(_background_block_ids.empty() ? (max_ring_radii_size + 2)
     259             :                                                                : _background_block_ids.back());
     260             :     }
     261             :   }
     262             :   std::vector<std::unique_ptr<ReplicatedMesh>> meshes;
     263         182 :   for (unsigned int i = 0; i < 3; i++)
     264             :   {
     265         272 :     meshes.push_back(buildSinglePinSection(_side_length,
     266         137 :                                            _ring_offset,
     267             :                                            _ring_radii[i],
     268             :                                            _ring_intervals[i],
     269             :                                            _has_rings[i],
     270         137 :                                            _preserve_volumes,
     271         137 :                                            _num_sectors_per_side,
     272         137 :                                            _background_intervals,
     273         137 :                                            block_ids_new[i],
     274             :                                            _node_id_background_meta));
     275             :     // add sector ids
     276         270 :     if (isParamValid("sector_id_name"))
     277          54 :       setSectorExtraIDs(*meshes[i],
     278             :                         getParam<std::string>("sector_id_name"),
     279             :                         4,
     280          54 :                         std::vector<unsigned int>(4, _num_sectors_per_side));
     281             :     // add ring ids
     282         405 :     if (isParamValid("ring_id_name") && _has_rings[i])
     283          72 :       setRingExtraIDs(*meshes[i],
     284             :                       getParam<std::string>("ring_id_name"),
     285             :                       4,
     286          36 :                       std::vector<unsigned int>(4, _num_sectors_per_side),
     287             :                       _ring_intervals[i],
     288          54 :                       getParam<MooseEnum>("ring_id_assign_type") == "ring_wise",
     289             :                       false);
     290             : 
     291         135 :     if (!_pin_id_name.empty())
     292         108 :       meshes[i]->add_elem_integer(_pin_id_name, true, _pin_id_values[i]);
     293         135 :     if (i > 0)
     294             :     {
     295          90 :       MeshTools::Modification::rotate(*meshes[i], 120.0 * (Real)i, 0, 0);
     296          90 :       meshes[0]->stitch_meshes(*std::move(meshes[i]),
     297             :                                OUTER_SIDESET_ID,
     298             :                                OUTER_SIDESET_ID,
     299             :                                TOLERANCE,
     300             :                                /*clear_stitched_boundary_ids=*/true);
     301             :     }
     302             :   }
     303             : 
     304          45 :   if (_assembly_orientation == AssmOrient::pin_up)
     305          36 :     MeshTools::Modification::rotate(*meshes[0], 90, 0, 0);
     306             :   else
     307           9 :     MeshTools::Modification::rotate(*meshes[0], 270, 0, 0);
     308             :   /* Add subdomain names */
     309         162 :   for (const auto & block_info_pair : block_info)
     310         117 :     meshes[0]->subdomain_name(block_info_pair.first) = block_info_pair.second;
     311          45 :   if (_external_boundary_id > 0)
     312          27 :     MooseMesh::changeBoundaryId(*meshes[0], OUTER_SIDESET_ID, _external_boundary_id, false);
     313          45 :   if (!_external_boundary_name.empty())
     314             :   {
     315          27 :     meshes[0]->get_boundary_info().sideset_name(
     316          27 :         _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
     317          27 :         _external_boundary_name;
     318          27 :     meshes[0]->get_boundary_info().nodeset_name(
     319          27 :         _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
     320             :         _external_boundary_name;
     321             :   }
     322             :   meshes[0]->set_isnt_prepared();
     323          90 :   return dynamic_pointer_cast<MeshBase>(meshes[0]);
     324          45 : }
     325             : 
     326             : std::unique_ptr<ReplicatedMesh>
     327         137 : TriPinHexAssemblyGenerator::buildSinglePinSection(
     328             :     const Real side_length,
     329             :     const Real ring_offset,
     330             :     const std::vector<Real> ring_radii,
     331             :     const std::vector<unsigned int> ring_intervals,
     332             :     const bool has_rings,
     333             :     const bool preserve_volumes,
     334             :     const unsigned int num_sectors_per_side,
     335             :     const unsigned int background_intervals,
     336             :     const std::vector<subdomain_id_type> block_ids_new,
     337             :     dof_id_type & node_id_background_meta)
     338             : {
     339             :   // Each SinglePinSection, which has a diamond shape, is composed of four general slices.
     340             :   // Considering symmetry, two unique general slices (0 and 1) need to be generated.
     341             :   // For each slice, the center of the pin is one of its vertices; primary and secondary sides are
     342             :   // the two sides that contain the pin center.
     343         137 :   const Real secondary_side_length_0(side_length / 2.0 - ring_offset);
     344             :   const Real secondary_side_length_1(
     345         137 :       std::sqrt(side_length * side_length / 4.0 * 3.0 + ring_offset * ring_offset));
     346             :   const Real primary_side_length_0(
     347         137 :       std::sqrt(side_length * side_length / 4.0 * 3.0 + ring_offset * ring_offset));
     348         137 :   const Real primary_side_length_1(side_length / 2.0 + ring_offset);
     349             :   // Azimuthal angle is the included angle defined by the primary and secondary sides
     350             :   const Real azimuthal_angle_0(
     351         137 :       acos((secondary_side_length_0 * secondary_side_length_0 +
     352         137 :             primary_side_length_0 * primary_side_length_0 - side_length * side_length) /
     353         137 :            2.0 / primary_side_length_0 / secondary_side_length_0) /
     354         137 :       M_PI * 180.0);
     355             :   const Real azimuthal_angle_1(
     356         137 :       acos((secondary_side_length_1 * secondary_side_length_1 +
     357         137 :             primary_side_length_1 * primary_side_length_1 - side_length * side_length) /
     358         137 :            2.0 / primary_side_length_1 / secondary_side_length_1) /
     359         137 :       M_PI * 180.0);
     360             :   // The primary side is parallel to y-axis by default (i.e., rotation_angle is zero). So the
     361             :   // general slices need to be rotated before stitching,
     362         137 :   const Real rotation_angle_0(azimuthal_angle_0 - 90.0);
     363         137 :   const Real rotation_angle_1(azimuthal_angle_0 + azimuthal_angle_1 - 90.0);
     364             :   // Alpha angle is the other included angle of the slice defined by the primary side and the third
     365             :   // side.
     366             :   const Real alpha_angle_0(
     367         137 :       acos((primary_side_length_0 * primary_side_length_0 + side_length * side_length -
     368         137 :             secondary_side_length_0 * secondary_side_length_0) /
     369         137 :            2.0 / primary_side_length_0 / side_length) /
     370         137 :       M_PI * 180.0);
     371             :   const Real alpha_angle_1(
     372         137 :       acos((primary_side_length_1 * primary_side_length_1 + side_length * side_length -
     373         137 :             secondary_side_length_1 * secondary_side_length_1) /
     374         137 :            2.0 / primary_side_length_1 / side_length) /
     375         137 :       M_PI * 180.0);
     376             : 
     377             :   // azimuthal_list is a list of azimuthal intervals of the mesh to support radius correction to
     378             :   // ensure preserved volume.
     379             :   std::vector<Real> azimuthal_list;
     380        1175 :   for (unsigned int i = 0; i < num_sectors_per_side; i++)
     381             :   {
     382             :     azimuthal_list.push_back(
     383        1038 :         atan((Real)i * side_length / num_sectors_per_side * sin(alpha_angle_0 / 180.0 * M_PI) /
     384        1038 :              (primary_side_length_0 -
     385        1038 :               (Real)i * side_length / num_sectors_per_side * cos(alpha_angle_0 / 180.0 * M_PI))) /
     386        1038 :         M_PI * 180.0);
     387             :   }
     388        1175 :   for (unsigned int i = 0; i < num_sectors_per_side; i++)
     389             :   {
     390             :     azimuthal_list.push_back(
     391        1038 :         azimuthal_angle_0 +
     392        1038 :         atan((Real)i * side_length / num_sectors_per_side * sin(alpha_angle_1 / 180.0 * M_PI) /
     393        1038 :              (primary_side_length_1 -
     394        1038 :               (Real)i * side_length / num_sectors_per_side * cos(alpha_angle_1 / 180.0 * M_PI))) /
     395        1038 :             M_PI * 180.0);
     396             :   }
     397        2213 :   for (unsigned int i = 0; i < num_sectors_per_side * 2; i++)
     398             :   {
     399        2076 :     azimuthal_list.push_back(azimuthal_list[i] + 180.0);
     400             :   }
     401             : 
     402             :   std::vector<Real> ring_radii_corr;
     403         137 :   if (has_rings)
     404             :   {
     405         110 :     if (preserve_volumes)
     406             :     {
     407         110 :       const Real corr_factor = PolygonalMeshGenerationUtils::radiusCorrectionFactor(azimuthal_list);
     408         330 :       for (unsigned int i = 0; i < ring_radii.size(); i++)
     409         220 :         ring_radii_corr.push_back(ring_radii[i] * corr_factor);
     410             :     }
     411             :     else
     412           0 :       ring_radii_corr = ring_radii;
     413         110 :     if (ring_radii_corr.back() > (side_length / 2.0 - std::abs(ring_offset)) * std::sqrt(3.0) / 2.0)
     414           2 :       paramError("ring_radii",
     415             :                  "The radii of the rings cannot exceed the boundary of the diamond section.");
     416             :   }
     417             : 
     418             :   // build the first slice of the polygon.
     419             :   auto mesh0 = buildGeneralSlice(
     420             :       ring_radii_corr,
     421             :       ring_intervals,
     422         135 :       std::vector<Real>(ring_radii_corr.size(), 1.0),
     423         135 :       {std::vector<Real>(ring_radii_corr.size(), 0.0),
     424         135 :        std::vector<Real>(ring_radii_corr.size(), 0.0),
     425         135 :        std::vector<unsigned int>(ring_radii_corr.size(), 0),
     426         135 :        std::vector<Real>(ring_radii_corr.size(), 1.0)},
     427         135 :       {std::vector<Real>(ring_radii_corr.size(), 0.0),
     428         135 :        std::vector<Real>(ring_radii_corr.size(), 0.0),
     429         135 :        std::vector<unsigned int>(ring_radii_corr.size(), 0),
     430         135 :        std::vector<Real>(ring_radii_corr.size(), 1.0)},
     431         270 :       std::vector<Real>(),
     432         135 :       std::vector<unsigned int>(),
     433         135 :       std::vector<Real>(),
     434             :       {std::vector<Real>(), std::vector<Real>(), std::vector<unsigned int>(), std::vector<Real>()},
     435             :       {std::vector<Real>(), std::vector<Real>(), std::vector<unsigned int>(), std::vector<Real>()},
     436             :       primary_side_length_0,
     437             :       secondary_side_length_0,
     438             :       num_sectors_per_side,
     439             :       background_intervals,
     440             :       1.0,
     441             :       {0.0, 0.0, 0, 1.0},
     442             :       {0.0, 0.0, 0, 1.0},
     443             :       node_id_background_meta,
     444             :       azimuthal_angle_0,
     445         135 :       std::vector<Real>(),
     446             :       /* side_index = */ 1,
     447             :       false,
     448             :       0.0,
     449             :       rotation_angle_0,
     450         405 :       false);
     451             : 
     452             :   auto mesh1 = buildGeneralSlice(
     453             :       ring_radii_corr,
     454             :       ring_intervals,
     455         135 :       std::vector<Real>(ring_radii_corr.size(), 1.0),
     456         135 :       {std::vector<Real>(ring_radii_corr.size(), 0.0),
     457         135 :        std::vector<Real>(ring_radii_corr.size(), 0.0),
     458         135 :        std::vector<unsigned int>(ring_radii_corr.size(), 0),
     459         135 :        std::vector<Real>(ring_radii_corr.size(), 1.0)},
     460         270 :       {std::vector<Real>(ring_radii_corr.size(), 0.0),
     461         135 :        std::vector<Real>(ring_radii_corr.size(), 0.0),
     462         135 :        std::vector<unsigned int>(ring_radii_corr.size(), 0),
     463         135 :        std::vector<Real>(ring_radii_corr.size(), 1.0)},
     464         270 :       std::vector<Real>(),
     465         135 :       std::vector<unsigned int>(),
     466         135 :       std::vector<Real>(),
     467             :       {std::vector<Real>(), std::vector<Real>(), std::vector<unsigned int>(), std::vector<Real>()},
     468             :       {std::vector<Real>(), std::vector<Real>(), std::vector<unsigned int>(), std::vector<Real>()},
     469             :       primary_side_length_1,
     470             :       secondary_side_length_1,
     471             :       num_sectors_per_side,
     472             :       background_intervals,
     473             :       1.0,
     474             :       {0.0, 0.0, 0, 1.0},
     475             :       {0.0, 0.0, 0, 1.0},
     476             :       node_id_background_meta,
     477             :       azimuthal_angle_1,
     478         135 :       std::vector<Real>(),
     479             :       /* side_index = */ 1,
     480             :       false,
     481             :       0.0,
     482             :       rotation_angle_1,
     483         405 :       false);
     484             : 
     485         135 :   mesh0->stitch_meshes(*mesh1,
     486             :                        SLICE_BEGIN,
     487             :                        SLICE_END,
     488             :                        TOLERANCE,
     489             :                        /*clear_stitched_boundary_ids=*/true);
     490         135 :   MooseMesh::changeBoundaryId(*mesh0, SLICE_BEGIN, SLICE_END, true);
     491             : 
     492         135 :   auto mesh2 = dynamic_pointer_cast<ReplicatedMesh>(mesh0->clone());
     493         135 :   MeshTools::Modification::rotate(*mesh2, 0, 180.0, 0);
     494         135 :   mesh0->stitch_meshes(*mesh2,
     495             :                        SLICE_END,
     496             :                        SLICE_END,
     497             :                        TOLERANCE,
     498             :                        /*clear_stitched_boundary_ids=*/true);
     499         135 :   MeshTools::Modification::translate(*mesh0, side_length / 2.0 + ring_offset, 0, 0);
     500             : 
     501       33102 :   for (const auto & elem : mesh0->element_ptr_range())
     502       16551 :     elem->subdomain_id() = block_ids_new[elem->subdomain_id() - 1];
     503             : 
     504         135 :   return mesh0;
     505         675 : }

Generated by: LCOV version 1.14