LCOV - code coverage report
Current view: top level - src/meshgenerators - SimpleHexagonGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #31405 (292dce) with base fef103 Lines: 116 117 99.1 %
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 "SimpleHexagonGenerator.h"
      11             : 
      12             : // C++ includes
      13             : #include <cmath>
      14             : 
      15             : registerMooseObject("ReactorApp", SimpleHexagonGenerator);
      16             : 
      17             : InputParameters
      18         514 : SimpleHexagonGenerator::validParams()
      19             : {
      20         514 :   InputParameters params = PolygonMeshGeneratorBase::validParams();
      21        1028 :   MooseEnum element_type("TRI QUAD HYBRID", "TRI");
      22        1028 :   params.addParam<MooseEnum>("element_type",
      23             :                              element_type,
      24             :                              "Whether the simple hexagon mesh is made of TRI or QUAD elements.");
      25        1028 :   params.addRequiredRangeCheckedParam<Real>(
      26             :       "hexagon_size", "hexagon_size>0.0", "Size of the hexagon to be generated.");
      27        1028 :   MooseEnum hexagon_size_style("apothem radius", "apothem");
      28        1028 :   params.addParam<MooseEnum>(
      29             :       "hexagon_size_style",
      30             :       hexagon_size_style,
      31         514 :       "Style in which the hexagon size is given (default: apothem i.e. half-pitch). Option: " +
      32         514 :           hexagon_size_style.getRawNames());
      33        1028 :   params.addRangeCheckedParam<unsigned int>(
      34             :       "radial_intervals",
      35             :       "radial_intervals>1",
      36             :       "Number of pin radial meshing rings (only applicable when 'element_type' is 'HYBRID').");
      37        1028 :   params.addRangeCheckedParam<std::vector<subdomain_id_type>>(
      38             :       "block_id",
      39             :       "block_id>=0",
      40             :       "Optional customized block id; two ids are needed for HYBRID 'element_type'.");
      41        1028 :   params.addParam<std::vector<SubdomainName>>(
      42             :       "block_name",
      43             :       "Optional customized block name; two names are needed for HYBRID 'element_type'.");
      44        1028 :   params.addRangeCheckedParam<boundary_id_type>("external_boundary_id",
      45             :                                                 "external_boundary_id>=0",
      46             :                                                 "Optional customized external boundary id.");
      47        1028 :   params.addParam<BoundaryName>("external_boundary_name",
      48             :                                 "Optional customized external boundary name.");
      49        1028 :   params.addParamNamesToGroup("block_id block_name external_boundary_id external_boundary_name",
      50             :                               "Customized Subdomain/Boundary");
      51         514 :   params.addClassDescription(
      52             :       "This SimpleHexagonGenerator object is designed to generate a simple hexagonal mesh that "
      53             :       "only contains six simple azimuthal triangular elements, two quadrilateral elements, or six "
      54             :       "central azimuthal triangular elements plus a several layers of quadrilateral elements.");
      55             : 
      56         514 :   return params;
      57         514 : }
      58             : 
      59         246 : SimpleHexagonGenerator::SimpleHexagonGenerator(const InputParameters & parameters)
      60             :   : PolygonMeshGeneratorBase(parameters),
      61         246 :     _element_type(getParam<MooseEnum>("element_type").template getEnum<ElemType>()),
      62         492 :     _hexagon_size(getParam<Real>("hexagon_size")),
      63         246 :     _hexagon_size_style(
      64         246 :         getParam<MooseEnum>("hexagon_size_style").template getEnum<PolygonSizeStyle>()),
      65         246 :     _radial_intervals(isParamValid("radial_intervals")
      66         523 :                           ? getParam<unsigned int>("radial_intervals")
      67         215 :                           : (_element_type == ElemType::HYBRID ? 2 : 1)),
      68         984 :     _block_id(isParamValid("block_id") ? getParam<std::vector<subdomain_id_type>>("block_id")
      69             :                                        : std::vector<subdomain_id_type>()),
      70         948 :     _block_name(isParamValid("block_name") ? getParam<std::vector<SubdomainName>>("block_name")
      71             :                                            : std::vector<SubdomainName>()),
      72         492 :     _boundary_id_valid(isParamValid("external_boundary_id")),
      73         691 :     _external_boundary_id(isParamValid("external_boundary_id")
      74         644 :                               ? getParam<boundary_id_type>("external_boundary_id")
      75             :                               : 0),
      76         691 :     _external_boundary_name(isParamValid("external_boundary_name")
      77         246 :                                 ? getParam<BoundaryName>("external_boundary_name")
      78         246 :                                 : BoundaryName())
      79             : {
      80         246 :   if (_radial_intervals > 1 && _element_type != ElemType::HYBRID)
      81           2 :     paramError(
      82             :         "radial_intervals",
      83             :         "A non-unity 'radial_intervals' value is only supported when 'element_type' is 'HYBRID'.");
      84         244 :   _pitch = 2.0 * (_hexagon_size_style == PolygonSizeStyle::apothem
      85         244 :                       ? _hexagon_size
      86           0 :                       : _hexagon_size * std::cos(M_PI / (Real)HEXAGON_NUM_SIDES));
      87         244 :   if ((_block_id.size() > 1) && _element_type != ElemType::HYBRID)
      88           2 :     paramError(
      89             :         "block_id",
      90             :         "if provided, the size of this parameter must be one if 'element_type' is TRI or QUAD.");
      91         242 :   if ((_block_id.size() != 0 && _block_id.size() != 2) && _element_type == ElemType::HYBRID)
      92           2 :     paramError("block_id",
      93             :                "if provided, the size of this parameter must be two if 'element_type' is HYBRID.");
      94         240 :   if (_block_name.size() != 0 && _block_name.size() != _block_id.size())
      95           2 :     paramError("block_name", "if provided, this parameter must have the same size as 'block_id'.");
      96         238 :   declareMeshProperty<unsigned int>("background_intervals_meta", _radial_intervals);
      97         238 :   declareMeshProperty<dof_id_type>("node_id_background_meta",
      98         238 :                                    _radial_intervals * HEXAGON_NUM_SIDES);
      99         238 :   declareMeshProperty<Real>("max_radius_meta", 0.0);
     100         476 :   declareMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta", {1, 1, 1, 1, 1, 1});
     101         238 :   declareMeshProperty<Real>("pitch_meta", _pitch);
     102         238 : }
     103             : 
     104             : std::unique_ptr<MeshBase>
     105         238 : SimpleHexagonGenerator::generate()
     106             : {
     107         238 :   const Real radius = _pitch / std::sqrt(3.0);
     108         238 :   auto mesh = buildReplicatedMesh(2);
     109             :   BoundaryInfo & boundary_info = mesh->get_boundary_info();
     110             :   // In the ElemType::TRI mode, total nodes number is 6 * _radial_intervals + 1, while
     111             :   // _radial_intervals must be trivial (1);
     112             :   // In the ElemType::QUAD model, total nodes number is 6 * _radial_intervals, while
     113             :   // _radial_intervals must be trivial (1);
     114             :   // In the ElemType::HYBRID mode, total nodes number is 6 * _radial_intervals + 1.
     115         238 :   std::vector<Node *> nodes(HEXAGON_NUM_SIDES * _radial_intervals +
     116         238 :                             (_element_type != ElemType::QUAD));
     117         238 :   if (_element_type != ElemType::QUAD)
     118             :   {
     119             :     // The trivial center node with node_id = 6 (HEXAGON_NUM_SIDES) * _radial_intervals
     120             :     Point center_p = Point(0.0, 0.0, 0.0);
     121         157 :     nodes[HEXAGON_NUM_SIDES * _radial_intervals] =
     122         157 :         mesh->add_point(center_p, HEXAGON_NUM_SIDES * _radial_intervals);
     123             :   }
     124             :   // loop to create nodes by radial layers
     125         514 :   for (unsigned int j = 0; j < _radial_intervals; j++)
     126             :     // loop to create the six nodes in each layer
     127        1932 :     for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
     128             :     {
     129             :       Point side_p = Point(radius * (Real)(_radial_intervals - j) / (Real)_radial_intervals *
     130        1656 :                                sin(M_PI / ((Real)HEXAGON_NUM_SIDES / 2.0) * (Real)i),
     131        1656 :                            radius * (Real)(_radial_intervals - j) / (Real)_radial_intervals *
     132        1656 :                                cos(M_PI / ((Real)HEXAGON_NUM_SIDES / 2.0) * (Real)i),
     133        1656 :                            0.0);
     134        1656 :       nodes[j * HEXAGON_NUM_SIDES + i] = mesh->add_point(side_p, j * HEXAGON_NUM_SIDES + i);
     135             :     }
     136             : 
     137         238 :   if (_element_type != ElemType::QUAD)
     138             :   {
     139             :     // loop to create outer layer QUAD elements
     140             :     // Note that the direction is from outer to inner
     141         195 :     for (unsigned int j = 0; j < _radial_intervals - 1; j++)
     142             :     {
     143             :       // loop to create the six QUAD elements for each layer
     144         266 :       for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
     145             :       {
     146         456 :         Elem * elem = mesh->add_elem(new Quad4);
     147         228 :         elem->set_node(0, nodes[HEXAGON_NUM_SIDES * j + i]);
     148         228 :         elem->set_node(1, nodes[HEXAGON_NUM_SIDES * j + (i + 1) % HEXAGON_NUM_SIDES]);
     149         228 :         elem->set_node(2, nodes[HEXAGON_NUM_SIDES * (j + 1) + (i + 1) % HEXAGON_NUM_SIDES]);
     150         228 :         elem->set_node(3, nodes[HEXAGON_NUM_SIDES * (j + 1) + i]);
     151             :         // Assign the default external boundary id if applicable so that the mesh can be used as
     152             :         // input of `PatterneHexMeshGenerator`.
     153         228 :         if (j == 0)
     154         228 :           boundary_info.add_side(elem, 0, OUTER_SIDESET_ID);
     155             :         // Default subdomain id
     156         228 :         elem->subdomain_id() = 2;
     157             :       }
     158             :     }
     159             :     // loop to create the six TRI elements
     160        1099 :     for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
     161             :     {
     162        1884 :       Elem * elem = mesh->add_elem(new Tri3);
     163         942 :       elem->set_node(0, nodes[HEXAGON_NUM_SIDES * _radial_intervals]);
     164         942 :       elem->set_node(2, nodes[HEXAGON_NUM_SIDES * (_radial_intervals - 1) + i]);
     165         942 :       elem->set_node(
     166         942 :           1, nodes[HEXAGON_NUM_SIDES * (_radial_intervals - 1) + (i + 1) % HEXAGON_NUM_SIDES]);
     167             :       // Assign the default external boundary id if applicable so that the mesh can be used as input
     168             :       // of `PatterneHexMeshGenerator`.
     169         942 :       if (_element_type != ElemType::HYBRID)
     170         714 :         boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
     171             :       // Default subdomain id
     172         942 :       elem->subdomain_id() = 1;
     173             :     }
     174             :   }
     175             :   else
     176             :     // loop to create the two elements
     177         243 :     for (unsigned int i = 0; i < HEXAGON_NUM_SIDES / 3; i++)
     178             :     {
     179         324 :       Elem * elem = mesh->add_elem(new Quad4);
     180         162 :       elem->set_node(0, nodes[i * 3]);
     181         162 :       elem->set_node(1, nodes[(i * 3 + 3) % HEXAGON_NUM_SIDES]);
     182         162 :       elem->set_node(2, nodes[i * 3 + 2]);
     183         162 :       elem->set_node(3, nodes[i * 3 + 1]);
     184             :       // Assign the default external boundary id so that the mesh can be used as input of
     185             :       // `PatterneHexMeshGenerator`.
     186         162 :       boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
     187         162 :       boundary_info.add_side(elem, 2, OUTER_SIDESET_ID);
     188         162 :       boundary_info.add_side(elem, 3, OUTER_SIDESET_ID);
     189             :       // Default subdomain id
     190         162 :       elem->subdomain_id() = 1;
     191             :     }
     192             : 
     193             :   // Assign customized (optional) subdomain id/name and external boundary id/name.
     194         238 :   if (!_block_id.empty())
     195        3140 :     for (const auto & elem : mesh->active_element_ptr_range())
     196             :     {
     197        1332 :       if (elem->subdomain_id() == 1)
     198        1104 :         elem->subdomain_id() = _block_id.front();
     199             :       else
     200         228 :         elem->subdomain_id() = _block_id.back();
     201         238 :     }
     202         238 :   if (!_block_name.empty())
     203         442 :     for (unsigned int i = 0; i < _block_name.size(); i++)
     204         240 :       mesh->subdomain_name(_block_id[i]) = _block_name[i];
     205             : 
     206         238 :   if (_boundary_id_valid)
     207         191 :     MooseMesh::changeBoundaryId(*mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
     208         238 :   if (!_external_boundary_name.empty())
     209             :   {
     210         191 :     mesh->get_boundary_info().sideset_name(
     211         191 :         _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
     212         191 :         _external_boundary_name;
     213         191 :     mesh->get_boundary_info().nodeset_name(
     214         191 :         _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
     215             :         _external_boundary_name;
     216             :   }
     217             : 
     218         238 :   mesh->prepare_for_use();
     219         476 :   return dynamic_pointer_cast<MeshBase>(mesh);
     220         238 : }

Generated by: LCOV version 1.14