LCOV - code coverage report
Current view: top level - src/meshgenerators - FlexiblePatternGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #31405 (292dce) with base fef103 Lines: 349 361 96.7 %
Date: 2025-09-04 07:56:24 Functions: 3 3 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 "FlexiblePatternGenerator.h"
      11             : 
      12             : // C++ includes
      13             : #include <cmath>
      14             : 
      15             : registerMooseObject("ReactorApp", FlexiblePatternGenerator);
      16             : 
      17             : InputParameters
      18         722 : FlexiblePatternGenerator::validParams()
      19             : {
      20         722 :   InputParameters params = PolygonMeshGeneratorBase::validParams();
      21             : 
      22        1444 :   params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs", "The input MeshGenerators.");
      23        1444 :   MooseEnum boundary_type("HEXAGON CARTESIAN CIRCLE CUSTOM", "CUSTOM");
      24        1444 :   params.addParam<MooseEnum>("boundary_type",
      25             :                              boundary_type,
      26             :                              "what type of boundary is used as background for patterning.");
      27        1444 :   params.addParam<MeshGeneratorName>(
      28             :       "boundary_mesh",
      29             :       "The boundary mesh consisting of EDGE2 elements to be used as the 'CUSTOM' boundary.");
      30        1444 :   params.addRangeCheckedParam<unsigned int>(
      31             :       "boundary_sectors",
      32             :       "boundary_sectors>0",
      33             :       "The number of sectors on each side of the HEXAGON or CARTESIAN boundary mesh or on the "
      34             :       "circular boundary of the CIRCLE boundary mesh.");
      35        1444 :   params.addRangeCheckedParam<Real>("boundary_size",
      36             :                                     "boundary_size>0",
      37             :                                     "The pitch size of the HEXAGON or CARTESIAN boundary mesh; or "
      38             :                                     "the diameter of the CIRCLE boundary mesh.");
      39             : 
      40        1444 :   params.addParam<std::vector<Point>>(
      41             :       "extra_positions", {}, "The extra non-patterned positions to set the input MeshGenerators.");
      42        1444 :   params.addParam<std::vector<unsigned int>>(
      43             :       "extra_positions_mg_indices",
      44             :       {},
      45             :       "the indices of the input mesh generators for the extra position.");
      46             : 
      47        1444 :   params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns",
      48             :                                                                        "Hexagonal patterns set.");
      49        1444 :   params.addRangeCheckedParam<std::vector<Real>>(
      50             :       "hex_pitches", "hex_pitches>0", "pitch sizes used to generate the hexagonal patterns.");
      51        1444 :   params.addParam<std::vector<Point>>("hex_origins",
      52             :                                       "the origin positions of the hexagonal patterns,");
      53        1444 :   params.addParam<std::vector<Real>>("hex_rotations",
      54             :                                      "the rotation angles of the hexagonal patterns,");
      55             : 
      56        1444 :   params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns",
      57             :                                                                        "Rectangular patterns set.");
      58        1444 :   params.addRangeCheckedParam<std::vector<Real>>(
      59             :       "rect_pitches_x",
      60             :       "rect_pitches_x>0",
      61             :       "pitch sizes in x direction used to generate the rectangular patterns.");
      62        1444 :   params.addRangeCheckedParam<std::vector<Real>>(
      63             :       "rect_pitches_y",
      64             :       "rect_pitches_y>0",
      65             :       "pitch sizes in y direction used to generate the rectangular patterns.");
      66        1444 :   params.addParam<std::vector<Point>>("rect_origins",
      67             :                                       "the origin positions of the rectangular patterns,");
      68        1444 :   params.addParam<std::vector<Real>>("rect_rotations",
      69             :                                      "the rotation angles of the rectangular patterns.");
      70             : 
      71        1444 :   params.addParam<std::vector<std::vector<unsigned int>>>("circular_patterns",
      72             :                                                           "Circular patterns set.");
      73        1444 :   params.addRangeCheckedParam<std::vector<Real>>(
      74             :       "circular_radii", "circular_radii>0", "the radii of the circular patterns.");
      75        1444 :   params.addParam<std::vector<Point>>("circular_origins",
      76             :                                       "the origin positions of the circular patterns,");
      77        1444 :   params.addParam<std::vector<Real>>(
      78             :       "circular_rotations",
      79             :       "the rotation angles of the circular patterns (the azimuthal angle of the first unit mesh).");
      80             : 
      81             :   // Parameters directly passed to XYDelaunayMeshGenerator
      82        1444 :   params.addParam<Real>("desired_area", 0.0, "Desired are for the background area meshing.");
      83        1444 :   params.addParam<std::string>(
      84             :       "desired_area_func",
      85         722 :       std::string(),
      86             :       "Desired area as a function of x,y; omit to skip non-uniform refinement");
      87             : 
      88        1444 :   params.addParam<bool>("use_auto_area_func",
      89        1444 :                         false,
      90             :                         "Use the automatic area function for triangle-meshing in the background.");
      91        1444 :   params.addParam<Real>(
      92             :       "auto_area_func_default_size",
      93        1444 :       0,
      94             :       "Background size for automatic area function, or 0 to use non background size");
      95        1444 :   params.addParam<Real>("auto_area_func_default_size_dist",
      96        1444 :                         -1.0,
      97             :                         "Effective distance of background size for automatic area "
      98             :                         "function, or negative to use non background size");
      99        1444 :   params.addParam<unsigned int>("auto_area_function_num_points",
     100        1444 :                                 10,
     101             :                                 "Maximum number of nearest points used for the inverse distance "
     102             :                                 "interpolation algorithm for automatic area function calculation.");
     103        2166 :   params.addRangeCheckedParam<Real>(
     104             :       "auto_area_function_power",
     105        1444 :       1.0,
     106             :       "auto_area_function_power>0",
     107             :       "Polynomial power of the inverse distance interpolation algorithm for automatic area "
     108             :       "function calculation.");
     109             : 
     110        1444 :   params.addParam<bool>("verify_holes", true, "Whether the holes are verified.");
     111        1444 :   params.addRangeCheckedParam<subdomain_id_type>(
     112             :       "background_subdomain_id",
     113             :       "background_subdomain_id>0",
     114             :       "Subdomain id to set on the background area meshed by Delaunay algorithm.");
     115        1444 :   params.addParam<SubdomainName>(
     116             :       "background_subdomain_name",
     117             :       "Subdomain name to set on the background area meshed by Delaunay algorithm.");
     118        1444 :   MooseEnum tri_elem_type("TRI3 TRI6 TRI7 DEFAULT", "DEFAULT");
     119        1444 :   params.addParam<MooseEnum>(
     120             :       "tri_element_type", tri_elem_type, "Type of the triangular elements to be generated.");
     121             : 
     122        1444 :   params.addParam<boundary_id_type>(
     123             :       "external_boundary_id",
     124             :       "The boundary id of the external boundary in addition to the default 10000.");
     125        1444 :   params.addParam<BoundaryName>("external_boundary_name",
     126             :                                 "Optional boundary name for the external boundary.");
     127             : 
     128        1444 :   params.addParam<bool>("delete_default_external_boundary_from_inputs",
     129        1444 :                         true,
     130             :                         "Whether to delete the default external boundary from the input meshes.");
     131             : 
     132        1444 :   params.addParam<ExtraElementIDName>(
     133             :       "cell_id_name",
     134             :       "The name of the extra element id to be assigned for each component "
     135             :       "unit mesh in sequential order.");
     136             : 
     137        1444 :   params.addParam<dof_id_type>(
     138             :       "cell_id_shift",
     139        1444 :       0,
     140             :       "The shift value to be added to the cell id to avoid conflicts with ids in other meshes.");
     141             : 
     142        1444 :   params.addParam<ExtraElementIDName>(
     143             :       "pattern_id_name",
     144             :       "The name of the extra element id to be assigned based on the ID of "
     145             :       "the input meshes in sequential order.");
     146             : 
     147        1444 :   params.addParam<dof_id_type>(
     148             :       "pattern_id_shift",
     149        1444 :       0,
     150             :       "The shift value to be added to the pattern id to avoid conflicts with ids in other meshes.");
     151             : 
     152         722 :   params.addClassDescription("This FlexiblePatternGenerator object is designed to generate a "
     153             :                              "mesh with a background region with dispersed unit meshes in "
     154             :                              "it and distributed based on a series of flexible patterns.");
     155             : 
     156        1444 :   params.addParamNamesToGroup("hex_patterns hex_pitches hex_origins hex_rotations",
     157             :                               "Hexagonal Pattern");
     158        1444 :   params.addParamNamesToGroup(
     159             :       "rect_patterns rect_pitches_x rect_pitches_y rect_origins rect_rotations",
     160             :       "Rectangular Pattern");
     161        1444 :   params.addParamNamesToGroup(
     162             :       "circular_patterns circular_radii circular_origins circular_rotations", "Circular Pattern");
     163        1444 :   params.addParamNamesToGroup("extra_positions extra_positions_mg_indices",
     164             :                               "Extra Positions (Free-Style Patterns)");
     165        1444 :   params.addParamNamesToGroup("desired_area desired_area_func verify_holes background_subdomain_id "
     166             :                               "background_subdomain_name use_auto_area_func "
     167             :                               "auto_area_func_default_size auto_area_func_default_size_dist "
     168             :                               "auto_area_function_num_points auto_area_function_power",
     169             :                               "Background Area Delaunay");
     170        1444 :   params.addParamNamesToGroup(
     171             :       "boundary_type boundary_mesh boundary_sectors boundary_size "
     172             :       "delete_default_external_boundary_from_inputs external_boundary_id external_boundary_name",
     173             :       "Boundary");
     174        1444 :   params.addParamNamesToGroup("cell_id_name cell_id_shift pattern_id_name pattern_id_shift",
     175             :                               "Reporting Id");
     176             : 
     177         722 :   return params;
     178         722 : }
     179             : 
     180         390 : FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & parameters)
     181             :   : PolygonMeshGeneratorBase(parameters),
     182         390 :     _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
     183         780 :     _boundary_type(getParam<MooseEnum>("boundary_type").template getEnum<BdryType>()),
     184        1170 :     _boundary_mesh_name(isParamValid("boundary_mesh") ? getParam<MeshGeneratorName>("boundary_mesh")
     185             :                                                       : MeshGeneratorName()),
     186        1530 :     _boundary_sectors(isParamValid("boundary_sectors") ? getParam<unsigned int>("boundary_sectors")
     187             :                                                        : 0),
     188        1530 :     _boundary_size(isParamValid("boundary_size") ? getParam<Real>("boundary_size") : 0.0),
     189         582 :     _hex_patterns(
     190         390 :         isParamValid("hex_patterns")
     191         390 :             ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns")
     192             :             : std::vector<std::vector<std::vector<unsigned int>>>()),
     193        1266 :     _hex_pitches(isParamValid("hex_pitches") ? getParam<std::vector<Real>>("hex_pitches")
     194             :                                              : std::vector<Real>()),
     195        1185 :     _hex_origins(isParamValid("hex_origins")
     196         390 :                      ? getParam<std::vector<Point>>("hex_origins")
     197         390 :                      : std::vector<Point>(_hex_patterns.size(), Point(0.0, 0.0, 0.0))),
     198        1181 :     _hex_rotations(isParamValid("hex_rotations") ? getParam<std::vector<Real>>("hex_rotations")
     199         390 :                                                  : std::vector<Real>(_hex_patterns.size(), 0.0)),
     200         450 :     _rect_patterns(
     201         390 :         isParamValid("rect_patterns")
     202         390 :             ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns")
     203             :             : std::vector<std::vector<std::vector<unsigned int>>>()),
     204        1200 :     _rect_pitches_x(isParamValid("rect_pitches_x") ? getParam<std::vector<Real>>("rect_pitches_x")
     205             :                                                    : std::vector<Real>()),
     206        1200 :     _rect_pitches_y(isParamValid("rect_pitches_y") ? getParam<std::vector<Real>>("rect_pitches_y")
     207             :                                                    : std::vector<Real>()),
     208        1172 :     _rect_origins(isParamValid("rect_origins")
     209         390 :                       ? getParam<std::vector<Point>>("rect_origins")
     210         390 :                       : std::vector<Point>(_rect_patterns.size(), Point(0.0, 0.0, 0.0))),
     211        1172 :     _rect_rotations(isParamValid("rect_rotations") ? getParam<std::vector<Real>>("rect_rotations")
     212         390 :                                                    : std::vector<Real>(_rect_patterns.size(), 0.0)),
     213         828 :     _circ_patterns(isParamValid("circular_patterns")
     214         390 :                        ? getParam<std::vector<std::vector<unsigned int>>>("circular_patterns")
     215             :                        : std::vector<std::vector<unsigned int>>()),
     216        1194 :     _circ_radii(isParamValid("circular_radii") ? getParam<std::vector<Real>>("circular_radii")
     217             :                                                : std::vector<Real>()),
     218        1172 :     _circ_origins(isParamValid("circular_origins")
     219         390 :                       ? getParam<std::vector<Point>>("circular_origins")
     220         390 :                       : std::vector<Point>(_circ_patterns.size(), Point(0.0, 0.0, 0.0))),
     221         802 :     _circ_rotations(isParamValid("circular_rotations")
     222         390 :                         ? getParam<std::vector<Real>>("circular_rotations")
     223         390 :                         : std::vector<Real>(_circ_patterns.size(), 0.0)),
     224         390 :     _background_subdomain_id(isParamValid("background_subdomain_id")
     225         892 :                                  ? getParam<subdomain_id_type>("background_subdomain_id")
     226             :                                  : Moose::INVALID_BLOCK_ID),
     227        1024 :     _background_subdomain_name(isParamValid("background_subdomain_name")
     228         390 :                                    ? getParam<SubdomainName>("background_subdomain_name")
     229             :                                    : SubdomainName()),
     230         390 :     _delete_default_external_boundary_from_inputs(
     231         780 :         getParam<bool>("delete_default_external_boundary_from_inputs")),
     232        1170 :     _cell_id_name(isParamValid("cell_id_name") ? getParam<ExtraElementIDName>("cell_id_name")
     233             :                                                : ExtraElementIDName()),
     234         780 :     _cell_id_shift(getParam<dof_id_type>("cell_id_shift")),
     235         791 :     _pattern_id_name(isParamValid("pattern_id_name")
     236         390 :                          ? getParam<ExtraElementIDName>("pattern_id_name")
     237             :                          : ExtraElementIDName()),
     238         780 :     _pattern_id_shift(getParam<dof_id_type>("pattern_id_shift")),
     239         390 :     _external_boundary_id(isParamValid("external_boundary_id")
     240         792 :                               ? getParam<boundary_id_type>("external_boundary_id")
     241             :                               : (boundary_id_type)OUTER_SIDESET_ID),
     242         972 :     _external_boundary_name(isParamValid("external_boundary_name")
     243         390 :                                 ? getParam<BoundaryName>("external_boundary_name")
     244         390 :                                 : BoundaryName())
     245             : 
     246             : {
     247         780 :   declareMeshesForSub("inputs");
     248             : 
     249        1152 :   if (_cell_id_name.empty() && isParamSetByUser("cell_id_name"))
     250           2 :     paramError("cell_id_name", "This parameter must be non empty if provided.");
     251        1146 :   if (_cell_id_name.empty() && isParamSetByUser("cell_id_shift"))
     252           2 :     paramError("cell_id_name", "This parameter must be provided if cell_id_shift is set.");
     253        1140 :   if (_pattern_id_name.empty() && isParamSetByUser("pattern_id_name"))
     254           2 :     paramError("pattern_id_name", "This parameter must be non empty if provided.");
     255        1134 :   if (_pattern_id_name.empty() && isParamSetByUser("pattern_id_shift"))
     256           2 :     paramError("pattern_id_name", "This parameter must be provided if pattern_id_shift is set.");
     257             : 
     258         764 :   const std::vector<Point> extra_positions(getParam<std::vector<Point>>("extra_positions"));
     259             :   const std::vector<unsigned int> extra_positions_mg_indices(
     260        1146 :       getParam<std::vector<unsigned int>>("extra_positions_mg_indices"));
     261         382 :   if (extra_positions.size() != extra_positions_mg_indices.size())
     262           2 :     paramError("extra_positions_mg_indices",
     263             :                "This parameter must have the same size as extra_positions.");
     264         380 :   std::vector<unsigned int> input_usage_count(_input_names.size(), 0);
     265         676 :   for (unsigned int i = 0; i < extra_positions.size(); i++)
     266             :   {
     267         298 :     if (extra_positions_mg_indices[i] >= _input_names.size())
     268           2 :       paramError("extra_positions_mg_indices",
     269             :                  "the index used for extra positions must be available in 'inputs'.");
     270         296 :     input_usage_count[extra_positions_mg_indices[i]]++;
     271         296 :     _positions.push_back(std::make_pair(extra_positions[i], extra_positions_mg_indices[i]));
     272             :   }
     273             : 
     274         378 :   if (_background_subdomain_name.size() && _background_subdomain_id == Moose::INVALID_BLOCK_ID)
     275           2 :     paramError("background_subdomain_id",
     276             :                "This parameter must be provided if background_subdomain_name is provided.");
     277             : 
     278         376 :   if (_boundary_type == BdryType::CUSTOM)
     279             :   {
     280          15 :     if (_boundary_mesh_name.empty())
     281           2 :       paramError("boundary_mesh", "boundary_mesh must be specified for CUSTOM boundary_type.");
     282          13 :     declareMeshForSub("boundary_mesh");
     283          13 :     if (_boundary_sectors > 0)
     284           2 :       paramError("boundary_sectors",
     285             :                  "this parameter should not be provided for CUSTOM boundary_type.");
     286          11 :     if (_boundary_size > 0.0)
     287           2 :       paramError("boundary_size",
     288             :                  "this parameter should not be provided for CUSTOM boundary_type.");
     289             :   }
     290             :   else
     291             :   {
     292         361 :     if (!_boundary_mesh_name.empty())
     293           2 :       paramError("boundary_mesh",
     294             :                  "this parameter should not be provided for non-CUSTOM "
     295             :                  "boundary_type.");
     296         359 :     if (_boundary_sectors == 0)
     297           2 :       paramError("boundary_sectors",
     298             :                  "this parameter must be provided for non-CUSTOM "
     299             :                  "boundary_type.");
     300         357 :     if (_boundary_size == 0.0)
     301           2 :       paramError("boundary_size", "this parameter must be provided for non-CUSTOM boundary_type.");
     302             : 
     303         355 :     if (_boundary_type == BdryType::HEXAGON)
     304             :     {
     305         287 :       _boundary_mesh_name = name() + "_hexagon_boundary";
     306             :       // create a submeshgenerator for the hexagon boundary
     307         287 :       auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
     308         287 :       params.set<bool>("loop") = true;
     309         287 :       params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
     310         287 :       params.set<std::vector<Point>>("points") = {
     311         287 :           Point(0.0, _boundary_size / std::sqrt(3.0), 0.0),
     312             :           Point(_boundary_size / 2.0, _boundary_size / std::sqrt(3.0) / 2.0, 0.0),
     313             :           Point(_boundary_size / 2.0, -_boundary_size / std::sqrt(3.0) / 2.0, 0.0),
     314             :           Point(0.0, -_boundary_size / std::sqrt(3.0), 0.0),
     315             :           Point(-_boundary_size / 2.0, -_boundary_size / std::sqrt(3.0) / 2.0, 0.0),
     316         574 :           Point(-_boundary_size / 2.0, _boundary_size / std::sqrt(3.0) / 2.0, 0.0)};
     317             : 
     318         574 :       addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
     319         287 :     }
     320          68 :     else if (_boundary_type == BdryType::CARTESIAN)
     321             :     {
     322          59 :       _boundary_mesh_name = name() + "_cartesian_boundary";
     323             :       // create a submeshgenerator for the cartesian boundary
     324          59 :       auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
     325          59 :       params.set<bool>("loop") = true;
     326          59 :       params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
     327          59 :       params.set<std::vector<Point>>("points") = {
     328          59 :           Point(_boundary_size / 2.0, _boundary_size / 2.0, 0.0),
     329             :           Point(_boundary_size / 2.0, -_boundary_size / 2.0, 0.0),
     330             :           Point(-_boundary_size / 2.0, -_boundary_size / 2.0, 0.0),
     331         118 :           Point(-_boundary_size / 2.0, _boundary_size / 2.0, 0.0)};
     332             : 
     333         118 :       addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
     334          59 :     }
     335             :     else
     336             :     {
     337           9 :       _boundary_mesh_name = name() + "_circle_boundary";
     338             :       // create a submeshgenerator for the circle boundary
     339             :       // As we are inducing polygonization anyway, PolyLineMeshGenerator is used
     340           9 :       auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
     341           9 :       params.set<bool>("loop") = true;
     342           9 :       params.set<unsigned int>("num_edges_between_points") = 1;
     343             :       // We enforce radius correction here for area preservation
     344           9 :       const Real corr_factor = std::sqrt(2 * M_PI / (Real)_boundary_sectors /
     345           9 :                                          std::sin(2 * M_PI / (Real)_boundary_sectors));
     346             :       std::vector<Point> circular_points;
     347         333 :       for (unsigned int i = 0; i < _boundary_sectors; i++)
     348             :       {
     349         324 :         const Real angle = 2.0 * M_PI * (Real)i / (Real)_boundary_sectors;
     350         324 :         circular_points.push_back(Point(_boundary_size * corr_factor * std::cos(angle) / 2.0,
     351         324 :                                         _boundary_size * corr_factor * std::sin(angle) / 2.0,
     352             :                                         0.0));
     353             :       }
     354           9 :       params.set<std::vector<Point>>("points") = circular_points;
     355             : 
     356          18 :       addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
     357           9 :     }
     358             :     // Set metadata of an assembly mesh
     359         355 :     declareMeshProperty("pattern_pitch_meta", _boundary_size);
     360         710 :     declareMeshProperty<bool>("is_control_drum_meta", false);
     361             :   }
     362             : 
     363             :   // Hexagonal Pattern
     364         364 :   if (_hex_pitches.size() != _hex_patterns.size())
     365           2 :     paramError("hex_pitches",
     366             :                "The length of this parameter must be the same as that of hex_patterns.");
     367         362 :   if (_hex_origins.size() != _hex_patterns.size())
     368           2 :     paramError(
     369             :         "hex_origins",
     370             :         "if provided, the length of this parameter must be the same as that of hex_patterns.");
     371         360 :   if (_hex_rotations.size() != _hex_patterns.size())
     372           2 :     paramError(
     373             :         "hex_rotations",
     374             :         "if provided, the length of this parameter must be the same as that of hex_patterns.");
     375             :   std::vector<Point> hex_positions;
     376         358 :   if (!_hex_patterns.empty())
     377             :   {
     378             :     unsigned int hex_index = 0;
     379         157 :     for (const auto & hex_pattern : _hex_patterns)
     380             :     {
     381          87 :       const unsigned int n_hex_pattern_layers = hex_pattern.size();
     382          87 :       if (n_hex_pattern_layers % 2 == 0)
     383           2 :         paramError("hex_patterns",
     384             :                    "The length (layer number) of each element of this parameter must be odd to "
     385             :                    "ensure hexagonal shapes.");
     386          85 :       if (n_hex_pattern_layers == 1)
     387           2 :         paramError("hex_patterns",
     388             :                    "The length (layer number) of each element of this parameter must be larger "
     389             :                    "than unity.");
     390         247 :       for (unsigned int i = 0; i <= n_hex_pattern_layers / 2; i++)
     391             :       {
     392         166 :         if (hex_pattern[i].size() != n_hex_pattern_layers / 2 + i + 1 ||
     393         164 :             hex_pattern[n_hex_pattern_layers - 1 - i].size() != n_hex_pattern_layers / 2 + i + 1)
     394           2 :           paramError("hex_patterns",
     395             :                      "The two-dimentional array element of this parameter must have a correct "
     396             :                      "hexagonal shape.");
     397             :       }
     398             : 
     399          81 :       const Point unit_shift_1 = Point(_hex_pitches[hex_index], 0.0, 0.0);
     400             :       const Point unit_shift_2 =
     401          81 :           Point(_hex_pitches[hex_index] / 2.0, _hex_pitches[hex_index] / 2.0 * std::sqrt(3.0), 0.0);
     402             : 
     403         324 :       for (unsigned int i = 0; i < hex_pattern.size(); i++)
     404             :       {
     405         243 :         const Real param_2 = ((Real)hex_pattern.size() - 1.0) / 2.0 - (Real)i;
     406             :         const Real param_1_init = -((Real)hex_pattern.size() - 1.0) / 2.0 -
     407         243 :                                   ((i <= (hex_pattern.size() - 1) / 2)
     408         243 :                                        ? 0.0
     409          81 :                                        : (((Real)(hex_pattern.size() - 1) / 2) - (Real)i));
     410         810 :         for (unsigned int j = 0; j < hex_pattern[i].size(); j++)
     411             :         {
     412             :           // Any numbers exceeding the size of inputs are used as dummy units
     413         567 :           if (hex_pattern[i][j] < _input_names.size())
     414             :           {
     415         549 :             input_usage_count[hex_pattern[i][j]]++;
     416         549 :             Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
     417         549 :             nodeCoordRotate(pt_buffer(0), pt_buffer(1), _hex_rotations[hex_index]);
     418         549 :             _positions.push_back(
     419             :                 std::make_pair(pt_buffer + _hex_origins[hex_index], hex_pattern[i][j]));
     420             :           }
     421             :         }
     422             :       }
     423          81 :       hex_index++;
     424             :     }
     425             :   }
     426             : 
     427             :   // Rectangular Pattern
     428         352 :   if (_rect_pitches_x.size() != _rect_patterns.size())
     429           2 :     paramError("rect_pitches_x",
     430             :                "The length of this parameter must be the same as that of rect_patterns.");
     431         350 :   if (_rect_pitches_y.size() != _rect_patterns.size())
     432           2 :     paramError("rect_pitches_y",
     433             :                "The length of this parameter must be the same as that of rect_patterns.");
     434         348 :   if (_rect_origins.size() != _rect_patterns.size())
     435           2 :     paramError(
     436             :         "rect_origins",
     437             :         "if provided, the length of this parameter must be the same as that of rect_patterns.");
     438         346 :   if (_rect_rotations.size() != _rect_patterns.size())
     439           2 :     paramError(
     440             :         "rect_rotations",
     441             :         "if provided, the length of this parameter must be the same as that of rect_patterns.");
     442         344 :   if (!_rect_patterns.empty())
     443             :   {
     444             :     unsigned int rect_index = 0;
     445          40 :     for (const auto & rect_pattern : _rect_patterns)
     446             :     {
     447             :       std::set<unsigned int> rect_pattern_elem_size;
     448          77 :       for (const auto & rect_pattern_elem : rect_pattern)
     449             :       {
     450          57 :         if (rect_pattern_elem.empty())
     451           2 :           paramError("rect_patterns", "Each row of the element pattern must not be empty.");
     452          55 :         rect_pattern_elem_size.emplace(rect_pattern_elem.size());
     453             :       }
     454          20 :       if (rect_pattern_elem_size.size() > 1)
     455           2 :         paramError("rect_patterns",
     456             :                    "The two-dimensional array element of this parameter must have a correct "
     457             :                    "rectangular shape.");
     458             : 
     459          18 :       const Point unit_shift_1 = Point(_rect_pitches_x[rect_index], 0.0, 0.0);
     460          18 :       const Point unit_shift_2 = Point(0.0, _rect_pitches_y[rect_index], 0.0);
     461             : 
     462          63 :       for (unsigned int i = 0; i < rect_pattern.size(); i++)
     463             :       {
     464          45 :         const Real param_2 = ((Real)rect_pattern.size() - 1.0) / 2.0 - (Real)i;
     465          45 :         const Real param_1_init = -((Real)rect_pattern[i].size() - 1.0) / 2.0;
     466         162 :         for (unsigned int j = 0; j < rect_pattern[i].size(); j++)
     467             :         {
     468         117 :           if (rect_pattern[i][j] < _input_names.size())
     469             :           {
     470         117 :             input_usage_count[rect_pattern[i][j]]++;
     471         117 :             Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
     472         117 :             nodeCoordRotate(pt_buffer(0), pt_buffer(1), _rect_rotations[rect_index]);
     473         117 :             _positions.push_back(
     474             :                 std::make_pair(pt_buffer + _rect_origins[rect_index], rect_pattern[i][j]));
     475             :           }
     476             :         }
     477             :       }
     478          18 :       rect_index++;
     479             :     }
     480             :   }
     481             : 
     482             :   // Circular Pattern
     483         340 :   if (_circ_radii.size() != _circ_patterns.size())
     484           2 :     paramError("circular_radii",
     485             :                "The length of this parameter must be the same as that of circular_patterns.");
     486         338 :   if (_circ_origins.size() != _circ_patterns.size())
     487           2 :     paramError(
     488             :         "circular_origins",
     489             :         "if provided, the length of this parameter must be the same as that of circular_patterns.");
     490         336 :   if (_circ_rotations.size() != _circ_patterns.size())
     491           2 :     paramError(
     492             :         "circular_rotations",
     493             :         "if provided, the length of this parameter must be the same as that of circular_patterns.");
     494         334 :   if (!_circ_patterns.empty())
     495             :   {
     496             :     unsigned int circ_index = 0;
     497          45 :     for (const auto & circ_pattern : _circ_patterns)
     498             :     {
     499          27 :       const Real angle_step = 2.0 * M_PI / (Real)circ_pattern.size();
     500             : 
     501         243 :       for (unsigned int i = 0; i < circ_pattern.size(); i++)
     502             :       {
     503         216 :         if (circ_pattern[i] < _input_names.size())
     504             :         {
     505         216 :           input_usage_count[circ_pattern[i]]++;
     506         216 :           Point pt_buffer = Point(_circ_radii[circ_index] * std::cos((Real)i * angle_step),
     507         216 :                                   _circ_radii[circ_index] * std::sin((Real)i * angle_step),
     508         216 :                                   0.0);
     509         216 :           nodeCoordRotate(pt_buffer(0), pt_buffer(1), _circ_rotations[circ_index]);
     510         216 :           _positions.push_back(
     511             :               std::make_pair(pt_buffer + _circ_origins[circ_index], circ_pattern[i]));
     512             :         }
     513             :       }
     514          27 :       circ_index++;
     515             :     }
     516             :   }
     517             : 
     518         334 :   if (std::count(input_usage_count.begin(), input_usage_count.end(), 0))
     519           2 :     paramError("inputs", "All the input mesh generator names are not used.");
     520             : 
     521         332 :   if (_delete_default_external_boundary_from_inputs)
     522             :   {
     523         678 :     for (const auto & input_name : _input_names)
     524             :     {
     525         346 :       auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
     526         346 :       params.set<MeshGeneratorName>("input") = input_name;
     527        1384 :       params.set<std::vector<BoundaryName>>("boundary_names") = {std::to_string(OUTER_SIDESET_ID)};
     528             : 
     529        1038 :       addMeshSubgenerator("BoundaryDeletionGenerator",
     530         346 :                           input_name +
     531         692 :                               static_cast<MeshGeneratorName>("_" + name() + "_del_ext_bdry"),
     532             :                           params);
     533         346 :     }
     534             :   }
     535             : 
     536             :   std::vector<MeshGeneratorName> patterned_pin_mg_series;
     537        1482 :   for (unsigned int i = 0; i < _positions.size(); i++)
     538             :   {
     539        1150 :     auto params = _app.getFactory().getValidParams("TransformGenerator");
     540        2300 :     params.set<MeshGeneratorName>("input") =
     541        1150 :         _input_names[_positions[i].second] +
     542        1150 :         static_cast<MeshGeneratorName>(
     543        2300 :             _delete_default_external_boundary_from_inputs ? ("_" + name() + "_del_ext_bdry") : "");
     544        2300 :     params.set<MooseEnum>("transform") = 1;
     545        1150 :     params.set<RealVectorValue>("vector_value") = _positions[i].first;
     546             : 
     547        2300 :     patterned_pin_mg_series.push_back(name() + "_pos_" + std::to_string(i));
     548             : 
     549        2300 :     addMeshSubgenerator("TransformGenerator", patterned_pin_mg_series.back(), params);
     550             : 
     551        1150 :     if (_cell_id_name.size())
     552             :     {
     553          54 :       auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
     554          27 :       params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
     555          54 :       params.set<std::string>("expression") = std::to_string(i + _cell_id_shift);
     556          27 :       params.set<std::string>("extra_elem_integer_name") = _cell_id_name;
     557             : 
     558          54 :       patterned_pin_mg_series.back() = name() + "_ceeid_" + std::to_string(i);
     559          54 :       addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
     560          27 :     }
     561        1150 :     if (_pattern_id_name.size())
     562             :     {
     563          54 :       auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
     564          54 :       params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
     565          54 :       params.set<std::string>("expression") =
     566          54 :           std::to_string(_positions[i].second + _pattern_id_shift);
     567          27 :       params.set<std::string>("extra_elem_integer_name") = _pattern_id_name;
     568             : 
     569          54 :       patterned_pin_mg_series.back() = name() + "_peeid_" + std::to_string(i);
     570          54 :       addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
     571          27 :     }
     572        1150 :   }
     573             : 
     574         332 :   auto params = _app.getFactory().getValidParams("XYDelaunayGenerator");
     575         332 :   params.set<MeshGeneratorName>("boundary") = _boundary_mesh_name;
     576         332 :   params.set<std::vector<MeshGeneratorName>>("holes") = patterned_pin_mg_series;
     577         332 :   params.set<bool>("refine_boundary") = false;
     578             :   // XYDelaunay's intrinsic checks
     579         664 :   params.set<bool>("verify_holes") = getParam<bool>("verify_holes");
     580         664 :   params.set<std::vector<bool>>("stitch_holes") =
     581         664 :       std::vector<bool>(patterned_pin_mg_series.size(), true);
     582         664 :   params.set<std::vector<bool>>("refine_holes") =
     583         664 :       std::vector<bool>(patterned_pin_mg_series.size(), false);
     584         664 :   params.set<Real>("desired_area") = getParam<Real>("desired_area");
     585         996 :   params.set<std::string>("desired_area_func") = getParam<std::string>("desired_area_func");
     586         664 :   params.set<bool>("use_auto_area_func") = getParam<bool>("use_auto_area_func");
     587         664 :   if (isParamSetByUser("auto_area_func_default_size"))
     588           0 :     params.set<Real>("auto_area_func_default_size") = getParam<Real>("auto_area_func_default_size");
     589         664 :   if (isParamSetByUser("auto_area_func_default_size_dist"))
     590           0 :     params.set<Real>("auto_area_func_default_size_dist") =
     591           0 :         getParam<Real>("auto_area_func_default_size_dist");
     592         664 :   if (isParamSetByUser("auto_area_function_num_points"))
     593           0 :     params.set<unsigned int>("auto_area_function_num_points") =
     594           0 :         getParam<unsigned int>("auto_area_function_num_points");
     595         664 :   if (isParamSetByUser("auto_area_function_power"))
     596           0 :     params.set<Real>("auto_area_function_power") = getParam<Real>("auto_area_function_power");
     597         996 :   params.set<BoundaryName>("output_boundary") = std::to_string(OUTER_SIDESET_ID);
     598         996 :   params.set<MooseEnum>("tri_element_type") = getParam<MooseEnum>("tri_element_type");
     599         664 :   addMeshSubgenerator("XYDelaunayGenerator", name() + "_pattern", params);
     600             : 
     601         332 :   MeshGeneratorName final_mg_name(name() + "_pattern");
     602         332 :   if (_background_subdomain_id != Moose::INVALID_BLOCK_ID)
     603             :   {
     604         474 :     auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
     605         948 :     params.set<MeshGeneratorName>("input") = name() + "_pattern";
     606         711 :     params.set<std::vector<SubdomainName>>("old_block") = {"0"};
     607         474 :     params.set<std::vector<SubdomainName>>("new_block") = {
     608        1185 :         std::to_string(_background_subdomain_id)};
     609         474 :     addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_1", params);
     610         237 :     if (_background_subdomain_name.size())
     611             :     {
     612         456 :       auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
     613         684 :       params.set<MeshGeneratorName>("input") = name() + "_back_rename_1";
     614         456 :       params.set<std::vector<SubdomainName>>("old_block") = {
     615        1368 :           std::to_string(_background_subdomain_id)};
     616         684 :       params.set<std::vector<SubdomainName>>("new_block") = {_background_subdomain_name};
     617         456 :       addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_2", params);
     618         228 :       final_mg_name = name() + "_back_rename_2";
     619         228 :     }
     620             :     else
     621          18 :       final_mg_name = name() + "_back_rename_1";
     622         237 :   }
     623             : 
     624         332 :   _build_mesh = &getMeshByName(final_mg_name);
     625         332 : }
     626             : 
     627             : std::unique_ptr<MeshBase>
     628         332 : FlexiblePatternGenerator::generate()
     629             : {
     630         332 :   if (_external_boundary_id != OUTER_SIDESET_ID)
     631         201 :     MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
     632         332 :   if (!_external_boundary_name.empty())
     633             :   {
     634             :     // Check if _external_boundary_name has been assigned to another boundary id
     635             :     const auto external_id_by_name =
     636         192 :         (*_build_mesh)->get_boundary_info().get_id_by_name(_external_boundary_name);
     637         192 :     if ((external_id_by_name != Moose::INVALID_BOUNDARY_ID) &&
     638           0 :         (external_id_by_name != _external_boundary_id))
     639           0 :       paramError("external_boundary_name",
     640           0 :                  "External boundary name " + _external_boundary_name +
     641           0 :                      " is already associated with id " + std::to_string(external_id_by_name) +
     642           0 :                      ", which differs from the user-specified external_boundary_id " +
     643           0 :                      std::to_string(_external_boundary_id));
     644             : 
     645         192 :     (*_build_mesh)->get_boundary_info().sideset_name(_external_boundary_id) =
     646         192 :         _external_boundary_name;
     647         192 :     (*_build_mesh)->get_boundary_info().nodeset_name(_external_boundary_id) =
     648             :         _external_boundary_name;
     649             :   }
     650         332 :   (*_build_mesh)->find_neighbors();
     651         332 :   (*_build_mesh)->set_isnt_prepared();
     652         332 :   return std::move(*_build_mesh);
     653             : }

Generated by: LCOV version 1.14