LCOV - code coverage report
Current view: top level - src/meshgenerators - FlexiblePatternGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #32971 (54bef8) with base c6cf66 Lines: 349 361 96.7 %
Date: 2026-05-29 20:39: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         662 : FlexiblePatternGenerator::validParams()
      19             : {
      20         662 :   InputParameters params = PolygonMeshGeneratorBase::validParams();
      21             : 
      22        1324 :   params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs", "The input MeshGenerators.");
      23        1324 :   MooseEnum boundary_type("HEXAGON CARTESIAN CIRCLE CUSTOM", "CUSTOM");
      24        1324 :   params.addParam<MooseEnum>("boundary_type",
      25             :                              boundary_type,
      26             :                              "what type of boundary is used as background for patterning.");
      27        1324 :   params.addParam<MeshGeneratorName>(
      28             :       "boundary_mesh",
      29             :       "The boundary mesh consisting of EDGE2 elements to be used as the 'CUSTOM' boundary.");
      30        1324 :   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        1324 :   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        1324 :   params.addParam<std::vector<Point>>(
      41             :       "extra_positions", {}, "The extra non-patterned positions to set the input MeshGenerators.");
      42        1324 :   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        1324 :   params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns",
      48             :                                                                        "Hexagonal patterns set.");
      49        1324 :   params.addRangeCheckedParam<std::vector<Real>>(
      50             :       "hex_pitches", "hex_pitches>0", "pitch sizes used to generate the hexagonal patterns.");
      51        1324 :   params.addParam<std::vector<Point>>("hex_origins",
      52             :                                       "the origin positions of the hexagonal patterns,");
      53        1324 :   params.addParam<std::vector<Real>>("hex_rotations",
      54             :                                      "the rotation angles of the hexagonal patterns,");
      55             : 
      56        1324 :   params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns",
      57             :                                                                        "Rectangular patterns set.");
      58        1324 :   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        1324 :   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        1324 :   params.addParam<std::vector<Point>>("rect_origins",
      67             :                                       "the origin positions of the rectangular patterns,");
      68        1324 :   params.addParam<std::vector<Real>>("rect_rotations",
      69             :                                      "the rotation angles of the rectangular patterns.");
      70             : 
      71        1324 :   params.addParam<std::vector<std::vector<unsigned int>>>("circular_patterns",
      72             :                                                           "Circular patterns set.");
      73        1324 :   params.addRangeCheckedParam<std::vector<Real>>(
      74             :       "circular_radii", "circular_radii>0", "the radii of the circular patterns.");
      75        1324 :   params.addParam<std::vector<Point>>("circular_origins",
      76             :                                       "the origin positions of the circular patterns,");
      77        1324 :   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        1324 :   params.addParam<Real>("desired_area", 0.0, "Desired are for the background area meshing.");
      83        1324 :   params.addParam<std::string>(
      84             :       "desired_area_func",
      85         662 :       std::string(),
      86             :       "Desired area as a function of x,y; omit to skip non-uniform refinement");
      87             : 
      88        1324 :   params.addParam<bool>("use_auto_area_func",
      89        1324 :                         false,
      90             :                         "Use the automatic area function for triangle-meshing in the background.");
      91        1324 :   params.addParam<Real>(
      92             :       "auto_area_func_default_size",
      93        1324 :       0,
      94             :       "Background size for automatic area function, or 0 to use non background size");
      95        1324 :   params.addParam<Real>("auto_area_func_default_size_dist",
      96        1324 :                         -1.0,
      97             :                         "Effective distance of background size for automatic area "
      98             :                         "function, or negative to use non background size");
      99        1324 :   params.addParam<unsigned int>("auto_area_function_num_points",
     100        1324 :                                 10,
     101             :                                 "Maximum number of nearest points used for the inverse distance "
     102             :                                 "interpolation algorithm for automatic area function calculation.");
     103        1986 :   params.addRangeCheckedParam<Real>(
     104             :       "auto_area_function_power",
     105        1324 :       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        1324 :   params.addParam<bool>("verify_holes", true, "Whether the holes are verified.");
     111        1324 :   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        1324 :   params.addParam<SubdomainName>(
     116             :       "background_subdomain_name",
     117             :       "Subdomain name to set on the background area meshed by Delaunay algorithm.");
     118        1324 :   MooseEnum tri_elem_type("TRI3 TRI6 TRI7 DEFAULT", "DEFAULT");
     119        1324 :   params.addParam<MooseEnum>(
     120             :       "tri_element_type", tri_elem_type, "Type of the triangular elements to be generated.");
     121             : 
     122        1324 :   params.addParam<boundary_id_type>(
     123             :       "external_boundary_id",
     124             :       "The boundary id of the external boundary in addition to the default 10000.");
     125        1324 :   params.addParam<BoundaryName>("external_boundary_name",
     126             :                                 "Optional boundary name for the external boundary.");
     127             : 
     128        1324 :   params.addParam<bool>("delete_default_external_boundary_from_inputs",
     129        1324 :                         true,
     130             :                         "Whether to delete the default external boundary from the input meshes.");
     131             : 
     132        1324 :   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        1324 :   params.addParam<dof_id_type>(
     138             :       "cell_id_shift",
     139        1324 :       0,
     140             :       "The shift value to be added to the cell id to avoid conflicts with ids in other meshes.");
     141             : 
     142        1324 :   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        1324 :   params.addParam<dof_id_type>(
     148             :       "pattern_id_shift",
     149        1324 :       0,
     150             :       "The shift value to be added to the pattern id to avoid conflicts with ids in other meshes.");
     151             : 
     152         662 :   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        1324 :   params.addParamNamesToGroup("hex_patterns hex_pitches hex_origins hex_rotations",
     157             :                               "Hexagonal Pattern");
     158        1324 :   params.addParamNamesToGroup(
     159             :       "rect_patterns rect_pitches_x rect_pitches_y rect_origins rect_rotations",
     160             :       "Rectangular Pattern");
     161        1324 :   params.addParamNamesToGroup(
     162             :       "circular_patterns circular_radii circular_origins circular_rotations", "Circular Pattern");
     163        1324 :   params.addParamNamesToGroup("extra_positions extra_positions_mg_indices",
     164             :                               "Extra Positions (Free-Style Patterns)");
     165        1324 :   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        1324 :   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        1324 :   params.addParamNamesToGroup("cell_id_name cell_id_shift pattern_id_name pattern_id_shift",
     175             :                               "Reporting Id");
     176             : 
     177         662 :   return params;
     178         662 : }
     179             : 
     180         360 : FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & parameters)
     181             :   : PolygonMeshGeneratorBase(parameters),
     182         360 :     _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
     183         720 :     _boundary_type(getParam<MooseEnum>("boundary_type").template getEnum<BdryType>()),
     184        1080 :     _boundary_mesh_name(isParamValid("boundary_mesh") ? getParam<MeshGeneratorName>("boundary_mesh")
     185             :                                                       : MeshGeneratorName()),
     186        1414 :     _boundary_sectors(isParamValid("boundary_sectors") ? getParam<unsigned int>("boundary_sectors")
     187             :                                                        : 0),
     188        1414 :     _boundary_size(isParamValid("boundary_size") ? getParam<Real>("boundary_size") : 0.0),
     189         524 :     _hex_patterns(
     190         360 :         isParamValid("hex_patterns")
     191         360 :             ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns")
     192             :             : std::vector<std::vector<std::vector<unsigned int>>>()),
     193        1162 :     _hex_pitches(isParamValid("hex_pitches") ? getParam<std::vector<Real>>("hex_pitches")
     194             :                                              : std::vector<Real>()),
     195        1093 :     _hex_origins(isParamValid("hex_origins")
     196         360 :                      ? getParam<std::vector<Point>>("hex_origins")
     197         360 :                      : std::vector<Point>(_hex_patterns.size(), Point(0.0, 0.0, 0.0))),
     198        1089 :     _hex_rotations(isParamValid("hex_rotations") ? getParam<std::vector<Real>>("hex_rotations")
     199         360 :                                                  : std::vector<Real>(_hex_patterns.size(), 0.0)),
     200         412 :     _rect_patterns(
     201         360 :         isParamValid("rect_patterns")
     202         360 :             ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns")
     203             :             : std::vector<std::vector<std::vector<unsigned int>>>()),
     204        1106 :     _rect_pitches_x(isParamValid("rect_pitches_x") ? getParam<std::vector<Real>>("rect_pitches_x")
     205             :                                                    : std::vector<Real>()),
     206        1106 :     _rect_pitches_y(isParamValid("rect_pitches_y") ? getParam<std::vector<Real>>("rect_pitches_y")
     207             :                                                    : std::vector<Real>()),
     208        1082 :     _rect_origins(isParamValid("rect_origins")
     209         360 :                       ? getParam<std::vector<Point>>("rect_origins")
     210         360 :                       : std::vector<Point>(_rect_patterns.size(), Point(0.0, 0.0, 0.0))),
     211        1082 :     _rect_rotations(isParamValid("rect_rotations") ? getParam<std::vector<Real>>("rect_rotations")
     212         360 :                                                    : std::vector<Real>(_rect_patterns.size(), 0.0)),
     213         760 :     _circ_patterns(isParamValid("circular_patterns")
     214         360 :                        ? getParam<std::vector<std::vector<unsigned int>>>("circular_patterns")
     215             :                        : std::vector<std::vector<unsigned int>>()),
     216        1100 :     _circ_radii(isParamValid("circular_radii") ? getParam<std::vector<Real>>("circular_radii")
     217             :                                                : std::vector<Real>()),
     218        1082 :     _circ_origins(isParamValid("circular_origins")
     219         360 :                       ? getParam<std::vector<Point>>("circular_origins")
     220         360 :                       : std::vector<Point>(_circ_patterns.size(), Point(0.0, 0.0, 0.0))),
     221         738 :     _circ_rotations(isParamValid("circular_rotations")
     222         360 :                         ? getParam<std::vector<Real>>("circular_rotations")
     223         360 :                         : std::vector<Real>(_circ_patterns.size(), 0.0)),
     224         360 :     _background_subdomain_id(isParamValid("background_subdomain_id")
     225         842 :                                  ? getParam<subdomain_id_type>("background_subdomain_id")
     226             :                                  : Moose::INVALID_BLOCK_ID),
     227         956 :     _background_subdomain_name(isParamValid("background_subdomain_name")
     228         360 :                                    ? getParam<SubdomainName>("background_subdomain_name")
     229             :                                    : SubdomainName()),
     230         360 :     _delete_default_external_boundary_from_inputs(
     231         720 :         getParam<bool>("delete_default_external_boundary_from_inputs")),
     232        1080 :     _cell_id_name(isParamValid("cell_id_name") ? getParam<ExtraElementIDName>("cell_id_name")
     233             :                                                : ExtraElementIDName()),
     234         720 :     _cell_id_shift(getParam<dof_id_type>("cell_id_shift")),
     235         729 :     _pattern_id_name(isParamValid("pattern_id_name")
     236         360 :                          ? getParam<ExtraElementIDName>("pattern_id_name")
     237             :                          : ExtraElementIDName()),
     238         720 :     _pattern_id_shift(getParam<dof_id_type>("pattern_id_shift")),
     239         360 :     _external_boundary_id(isParamValid("external_boundary_id")
     240         758 :                               ? getParam<boundary_id_type>("external_boundary_id")
     241             :                               : (boundary_id_type)OUTER_SIDESET_ID),
     242         912 :     _external_boundary_name(isParamValid("external_boundary_name")
     243         360 :                                 ? getParam<BoundaryName>("external_boundary_name")
     244         360 :                                 : BoundaryName())
     245             : 
     246             : {
     247         720 :   declareMeshesForSub("inputs");
     248             : 
     249        1066 :   if (_cell_id_name.empty() && isParamSetByUser("cell_id_name"))
     250           2 :     paramError("cell_id_name", "This parameter must be non empty if provided.");
     251        1060 :   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        1054 :   if (_pattern_id_name.empty() && isParamSetByUser("pattern_id_name"))
     254           2 :     paramError("pattern_id_name", "This parameter must be non empty if provided.");
     255        1048 :   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         704 :   const std::vector<Point> extra_positions(getParam<std::vector<Point>>("extra_positions"));
     259             :   const std::vector<unsigned int> extra_positions_mg_indices(
     260        1056 :       getParam<std::vector<unsigned int>>("extra_positions_mg_indices"));
     261         352 :   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         350 :   std::vector<unsigned int> input_usage_count(_input_names.size(), 0);
     265         614 :   for (unsigned int i = 0; i < extra_positions.size(); i++)
     266             :   {
     267         266 :     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         264 :     input_usage_count[extra_positions_mg_indices[i]]++;
     271         264 :     _positions.push_back(std::make_pair(extra_positions[i], extra_positions_mg_indices[i]));
     272             :   }
     273             : 
     274         348 :   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         346 :   if (_boundary_type == BdryType::CUSTOM)
     279             :   {
     280          13 :     if (_boundary_mesh_name.empty())
     281           2 :       paramError("boundary_mesh", "boundary_mesh must be specified for CUSTOM boundary_type.");
     282          11 :     declareMeshForSub("boundary_mesh");
     283          11 :     if (_boundary_sectors > 0)
     284           2 :       paramError("boundary_sectors",
     285             :                  "this parameter should not be provided for CUSTOM boundary_type.");
     286           9 :     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         333 :     if (!_boundary_mesh_name.empty())
     293           2 :       paramError("boundary_mesh",
     294             :                  "this parameter should not be provided for non-CUSTOM "
     295             :                  "boundary_type.");
     296         331 :     if (_boundary_sectors == 0)
     297           2 :       paramError("boundary_sectors",
     298             :                  "this parameter must be provided for non-CUSTOM "
     299             :                  "boundary_type.");
     300         329 :     if (_boundary_size == 0.0)
     301           2 :       paramError("boundary_size", "this parameter must be provided for non-CUSTOM boundary_type.");
     302             : 
     303         327 :     if (_boundary_type == BdryType::HEXAGON)
     304             :     {
     305         263 :       _boundary_mesh_name = name() + "_hexagon_boundary";
     306             :       // create a submeshgenerator for the hexagon boundary
     307         263 :       auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
     308         263 :       params.set<bool>("loop") = true;
     309         263 :       params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
     310         263 :       params.set<std::vector<Point>>("points") = {
     311         263 :           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         526 :           Point(-_boundary_size / 2.0, _boundary_size / std::sqrt(3.0) / 2.0, 0.0)};
     317             : 
     318         526 :       addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
     319         263 :     }
     320          64 :     else if (_boundary_type == BdryType::CARTESIAN)
     321             :     {
     322          57 :       _boundary_mesh_name = name() + "_cartesian_boundary";
     323             :       // create a submeshgenerator for the cartesian boundary
     324          57 :       auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
     325          57 :       params.set<bool>("loop") = true;
     326          57 :       params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
     327          57 :       params.set<std::vector<Point>>("points") = {
     328          57 :           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         114 :           Point(-_boundary_size / 2.0, _boundary_size / 2.0, 0.0)};
     332             : 
     333         114 :       addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
     334          57 :     }
     335             :     else
     336             :     {
     337           7 :       _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           7 :       auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
     341           7 :       params.set<bool>("loop") = true;
     342           7 :       params.set<unsigned int>("num_edges_between_points") = 1;
     343             :       // We enforce radius correction here for area preservation
     344           7 :       const Real corr_factor = std::sqrt(2 * M_PI / (Real)_boundary_sectors /
     345           7 :                                          std::sin(2 * M_PI / (Real)_boundary_sectors));
     346             :       std::vector<Point> circular_points;
     347         259 :       for (unsigned int i = 0; i < _boundary_sectors; i++)
     348             :       {
     349         252 :         const Real angle = 2.0 * M_PI * (Real)i / (Real)_boundary_sectors;
     350         252 :         circular_points.push_back(Point(_boundary_size * corr_factor * std::cos(angle) / 2.0,
     351         252 :                                         _boundary_size * corr_factor * std::sin(angle) / 2.0,
     352             :                                         0.0));
     353             :       }
     354           7 :       params.set<std::vector<Point>>("points") = circular_points;
     355             : 
     356          14 :       addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
     357           7 :     }
     358             :     // Set metadata of an assembly mesh
     359         327 :     declareMeshProperty("pattern_pitch_meta", _boundary_size);
     360         654 :     declareMeshProperty<bool>("is_control_drum_meta", false);
     361             :   }
     362             : 
     363             :   // Hexagonal Pattern
     364         334 :   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         332 :   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         330 :   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         328 :   if (!_hex_patterns.empty())
     377             :   {
     378             :     unsigned int hex_index = 0;
     379         127 :     for (const auto & hex_pattern : _hex_patterns)
     380             :     {
     381          71 :       const unsigned int n_hex_pattern_layers = hex_pattern.size();
     382          71 :       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          69 :       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         199 :       for (unsigned int i = 0; i <= n_hex_pattern_layers / 2; i++)
     391             :       {
     392         134 :         if (hex_pattern[i].size() != n_hex_pattern_layers / 2 + i + 1 ||
     393         132 :             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          65 :       const Point unit_shift_1 = Point(_hex_pitches[hex_index], 0.0, 0.0);
     400             :       const Point unit_shift_2 =
     401          65 :           Point(_hex_pitches[hex_index] / 2.0, _hex_pitches[hex_index] / 2.0 * std::sqrt(3.0), 0.0);
     402             : 
     403         260 :       for (unsigned int i = 0; i < hex_pattern.size(); i++)
     404             :       {
     405         195 :         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         195 :                                   ((i <= (hex_pattern.size() - 1) / 2)
     408         195 :                                        ? 0.0
     409          65 :                                        : (((Real)(hex_pattern.size() - 1) / 2) - (Real)i));
     410         650 :         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         455 :           if (hex_pattern[i][j] < _input_names.size())
     414             :           {
     415         441 :             input_usage_count[hex_pattern[i][j]]++;
     416         441 :             Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
     417         441 :             nodeCoordRotate(pt_buffer(0), pt_buffer(1), _hex_rotations[hex_index]);
     418         441 :             _positions.push_back(
     419             :                 std::make_pair(pt_buffer + _hex_origins[hex_index], hex_pattern[i][j]));
     420             :           }
     421             :         }
     422             :       }
     423          65 :       hex_index++;
     424             :     }
     425             :   }
     426             : 
     427             :   // Rectangular Pattern
     428         322 :   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         320 :   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         318 :   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         316 :   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         314 :   if (!_rect_patterns.empty())
     443             :   {
     444             :     unsigned int rect_index = 0;
     445          32 :     for (const auto & rect_pattern : _rect_patterns)
     446             :     {
     447             :       std::set<unsigned int> rect_pattern_elem_size;
     448          63 :       for (const auto & rect_pattern_elem : rect_pattern)
     449             :       {
     450          47 :         if (rect_pattern_elem.empty())
     451           2 :           paramError("rect_patterns", "Each row of the element pattern must not be empty.");
     452          45 :         rect_pattern_elem_size.emplace(rect_pattern_elem.size());
     453             :       }
     454          16 :       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          14 :       const Point unit_shift_1 = Point(_rect_pitches_x[rect_index], 0.0, 0.0);
     460          14 :       const Point unit_shift_2 = Point(0.0, _rect_pitches_y[rect_index], 0.0);
     461             : 
     462          49 :       for (unsigned int i = 0; i < rect_pattern.size(); i++)
     463             :       {
     464          35 :         const Real param_2 = ((Real)rect_pattern.size() - 1.0) / 2.0 - (Real)i;
     465          35 :         const Real param_1_init = -((Real)rect_pattern[i].size() - 1.0) / 2.0;
     466         126 :         for (unsigned int j = 0; j < rect_pattern[i].size(); j++)
     467             :         {
     468          91 :           if (rect_pattern[i][j] < _input_names.size())
     469             :           {
     470          91 :             input_usage_count[rect_pattern[i][j]]++;
     471          91 :             Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
     472          91 :             nodeCoordRotate(pt_buffer(0), pt_buffer(1), _rect_rotations[rect_index]);
     473          91 :             _positions.push_back(
     474             :                 std::make_pair(pt_buffer + _rect_origins[rect_index], rect_pattern[i][j]));
     475             :           }
     476             :         }
     477             :       }
     478          14 :       rect_index++;
     479             :     }
     480             :   }
     481             : 
     482             :   // Circular Pattern
     483         310 :   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         308 :   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         306 :   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         304 :   if (!_circ_patterns.empty())
     495             :   {
     496             :     unsigned int circ_index = 0;
     497          35 :     for (const auto & circ_pattern : _circ_patterns)
     498             :     {
     499          21 :       const Real angle_step = 2.0 * M_PI / (Real)circ_pattern.size();
     500             : 
     501         189 :       for (unsigned int i = 0; i < circ_pattern.size(); i++)
     502             :       {
     503         168 :         if (circ_pattern[i] < _input_names.size())
     504             :         {
     505         168 :           input_usage_count[circ_pattern[i]]++;
     506         168 :           Point pt_buffer = Point(_circ_radii[circ_index] * std::cos((Real)i * angle_step),
     507         168 :                                   _circ_radii[circ_index] * std::sin((Real)i * angle_step),
     508         168 :                                   0.0);
     509         168 :           nodeCoordRotate(pt_buffer(0), pt_buffer(1), _circ_rotations[circ_index]);
     510         168 :           _positions.push_back(
     511             :               std::make_pair(pt_buffer + _circ_origins[circ_index], circ_pattern[i]));
     512             :         }
     513             :       }
     514          21 :       circ_index++;
     515             :     }
     516             :   }
     517             : 
     518         304 :   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         302 :   if (_delete_default_external_boundary_from_inputs)
     522             :   {
     523         606 :     for (const auto & input_name : _input_names)
     524             :     {
     525         304 :       auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
     526         304 :       params.set<MeshGeneratorName>("input") = input_name;
     527        1216 :       params.set<std::vector<BoundaryName>>("boundary_names") = {std::to_string(OUTER_SIDESET_ID)};
     528             : 
     529         912 :       addMeshSubgenerator("BoundaryDeletionGenerator",
     530         304 :                           input_name +
     531         608 :                               static_cast<MeshGeneratorName>("_" + name() + "_del_ext_bdry"),
     532             :                           params);
     533         304 :     }
     534             :   }
     535             : 
     536             :   std::vector<MeshGeneratorName> patterned_pin_mg_series;
     537        1238 :   for (unsigned int i = 0; i < _positions.size(); i++)
     538             :   {
     539         936 :     auto params = _app.getFactory().getValidParams("TransformGenerator");
     540        1872 :     params.set<MeshGeneratorName>("input") =
     541         936 :         _input_names[_positions[i].second] +
     542         936 :         static_cast<MeshGeneratorName>(
     543        1872 :             _delete_default_external_boundary_from_inputs ? ("_" + name() + "_del_ext_bdry") : "");
     544        1872 :     params.set<MooseEnum>("transform") = 1;
     545         936 :     params.set<RealVectorValue>("vector_value") = _positions[i].first;
     546             : 
     547        1872 :     patterned_pin_mg_series.push_back(name() + "_pos_" + std::to_string(i));
     548             : 
     549        1872 :     addMeshSubgenerator("TransformGenerator", patterned_pin_mg_series.back(), params);
     550             : 
     551         936 :     if (_cell_id_name.size())
     552             :     {
     553          42 :       auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
     554          21 :       params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
     555          42 :       params.set<std::string>("expression") = std::to_string(i + _cell_id_shift);
     556          21 :       params.set<std::string>("extra_elem_integer_name") = _cell_id_name;
     557             : 
     558          42 :       patterned_pin_mg_series.back() = name() + "_ceeid_" + std::to_string(i);
     559          42 :       addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
     560          21 :     }
     561         936 :     if (_pattern_id_name.size())
     562             :     {
     563          42 :       auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
     564          42 :       params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
     565          42 :       params.set<std::string>("expression") =
     566          42 :           std::to_string(_positions[i].second + _pattern_id_shift);
     567          21 :       params.set<std::string>("extra_elem_integer_name") = _pattern_id_name;
     568             : 
     569          42 :       patterned_pin_mg_series.back() = name() + "_peeid_" + std::to_string(i);
     570          42 :       addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
     571          21 :     }
     572         936 :   }
     573             : 
     574         302 :   auto params = _app.getFactory().getValidParams("XYDelaunayGenerator");
     575         302 :   params.set<MeshGeneratorName>("boundary") = _boundary_mesh_name;
     576         302 :   params.set<std::vector<MeshGeneratorName>>("holes") = patterned_pin_mg_series;
     577         302 :   params.set<bool>("refine_boundary") = false;
     578             :   // XYDelaunay's intrinsic checks
     579         604 :   params.set<bool>("verify_holes") = getParam<bool>("verify_holes");
     580         604 :   params.set<std::vector<bool>>("stitch_holes") =
     581         604 :       std::vector<bool>(patterned_pin_mg_series.size(), true);
     582         604 :   params.set<std::vector<bool>>("refine_holes") =
     583         604 :       std::vector<bool>(patterned_pin_mg_series.size(), false);
     584         604 :   params.set<Real>("desired_area") = getParam<Real>("desired_area");
     585         906 :   params.set<std::string>("desired_area_func") = getParam<std::string>("desired_area_func");
     586         604 :   params.set<bool>("use_auto_area_func") = getParam<bool>("use_auto_area_func");
     587         604 :   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         604 :   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         604 :   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         604 :   if (isParamSetByUser("auto_area_function_power"))
     596           0 :     params.set<Real>("auto_area_function_power") = getParam<Real>("auto_area_function_power");
     597         906 :   params.set<BoundaryName>("output_boundary") = std::to_string(OUTER_SIDESET_ID);
     598         906 :   params.set<MooseEnum>("tri_element_type") = getParam<MooseEnum>("tri_element_type");
     599         604 :   addMeshSubgenerator("XYDelaunayGenerator", name() + "_pattern", params);
     600             : 
     601         302 :   MeshGeneratorName final_mg_name(name() + "_pattern");
     602         302 :   if (_background_subdomain_id != Moose::INVALID_BLOCK_ID)
     603             :   {
     604         454 :     auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
     605         908 :     params.set<MeshGeneratorName>("input") = name() + "_pattern";
     606         681 :     params.set<std::vector<SubdomainName>>("old_block") = {"0"};
     607         454 :     params.set<std::vector<SubdomainName>>("new_block") = {
     608        1135 :         std::to_string(_background_subdomain_id)};
     609         454 :     addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_1", params);
     610         227 :     if (_background_subdomain_name.size())
     611             :     {
     612         440 :       auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
     613         660 :       params.set<MeshGeneratorName>("input") = name() + "_back_rename_1";
     614         440 :       params.set<std::vector<SubdomainName>>("old_block") = {
     615        1320 :           std::to_string(_background_subdomain_id)};
     616         660 :       params.set<std::vector<SubdomainName>>("new_block") = {_background_subdomain_name};
     617         440 :       addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_2", params);
     618         220 :       final_mg_name = name() + "_back_rename_2";
     619         220 :     }
     620             :     else
     621          14 :       final_mg_name = name() + "_back_rename_1";
     622         227 :   }
     623             : 
     624         302 :   _build_mesh = &getMeshByName(final_mg_name);
     625         302 : }
     626             : 
     627             : std::unique_ptr<MeshBase>
     628         302 : FlexiblePatternGenerator::generate()
     629             : {
     630         302 :   if (_external_boundary_id != OUTER_SIDESET_ID)
     631         199 :     MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
     632         302 :   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         302 :   (*_build_mesh)->find_neighbors();
     651         302 :   (*_build_mesh)->unset_is_prepared();
     652         302 :   return std::move(*_build_mesh);
     653             : }

Generated by: LCOV version 1.14