LCOV - code coverage report
Current view: top level - src/meshgenerators - PolygonMeshTrimmerBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #31405 (292dce) with base fef103 Lines: 99 118 83.9 %
Date: 2025-09-04 07:56:24 Functions: 5 5 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 "PolygonMeshTrimmerBase.h"
      11             : #include "MooseMeshXYCuttingUtils.h"
      12             : #include "MooseMeshUtils.h"
      13             : #include "MathUtils.h"
      14             : 
      15             : // C++ includes
      16             : #include <cmath> // provides round, not std::round (see http://www.cplusplus.com/reference/cmath/round/)
      17             : 
      18             : InputParameters
      19         676 : PolygonMeshTrimmerBase::validParams()
      20             : {
      21         676 :   InputParameters params = PolygonMeshGeneratorBase::validParams();
      22        1352 :   params.addRequiredParam<MeshGeneratorName>("input", "The input mesh that needs to be trimmed.");
      23        1352 :   params.addParam<BoundaryName>("peripheral_trimming_section_boundary",
      24             :                                 "Boundary formed by peripheral trimming.");
      25        1352 :   params.addRangeCheckedParam<short>(
      26             :       "center_trim_starting_index",
      27             :       "center_trim_starting_index>=0 & center_trim_starting_index<12",
      28             :       "Index of the starting center trimming position.");
      29        1352 :   params.addRangeCheckedParam<short>("center_trim_ending_index",
      30             :                                      "center_trim_ending_index>=0 & center_trim_ending_index<12",
      31             :                                      "Index of the ending center trimming position.");
      32        1352 :   params.addParam<BoundaryName>("center_trimming_section_boundary",
      33             :                                 "Boundary formed by center trimming (external_boundary will be "
      34             :                                 "assigned if this parameter is not provided).");
      35        1352 :   params.addParam<BoundaryName>("external_boundary",
      36             :                                 "External boundary of the input mesh prior to the trimming.");
      37        1352 :   params.addParam<SubdomainName>(
      38             :       "tri_elem_subdomain_name_suffix",
      39             :       "trimmer_tri",
      40             :       "Suffix to the block name used for quad elements that are trimmed/converted into "
      41             :       "triangular elements to avert degenerate quad elements");
      42        1352 :   params.addParam<subdomain_id_type>(
      43             :       "tri_elem_subdomain_shift",
      44             :       "Customized id shift to define subdomain ids of the converted triangular elements.");
      45             : 
      46        1352 :   params.addParamNamesToGroup(
      47             :       "center_trim_starting_index center_trim_ending_index center_trimming_section_boundary",
      48             :       "Center Trimming");
      49        1352 :   params.addParamNamesToGroup("peripheral_trimming_section_boundary", "Peripheral Trimming");
      50        1352 :   params.addParamNamesToGroup("tri_elem_subdomain_name_suffix tri_elem_subdomain_shift",
      51             :                               "Trimmed Boundary Repair");
      52             : 
      53         676 :   params.addClassDescription("This PolygonMeshTrimmerBase is the base class for "
      54             :                              "CartesianMeshTrimmer and HexagonMeshTrimmer.");
      55             : 
      56         676 :   return params;
      57           0 : }
      58             : 
      59         346 : PolygonMeshTrimmerBase::PolygonMeshTrimmerBase(const InputParameters & parameters)
      60             :   : PolygonMeshGeneratorBase(parameters),
      61           0 :     _input_name(getParam<MeshGeneratorName>("input")),
      62         692 :     _trim_peripheral_region(getParam<std::vector<unsigned short>>("trim_peripheral_region")),
      63         552 :     _peripheral_trimming_section_boundary(
      64         346 :         isParamValid("peripheral_trimming_section_boundary")
      65         346 :             ? getParam<BoundaryName>("peripheral_trimming_section_boundary")
      66             :             : BoundaryName()),
      67         478 :     _center_trimming_section_boundary(
      68         346 :         isParamValid("center_trimming_section_boundary")
      69         346 :             ? getParam<BoundaryName>("center_trimming_section_boundary")
      70             :             : BoundaryName()),
      71         696 :     _external_boundary_name(isParamValid("external_boundary")
      72         346 :                                 ? getParam<BoundaryName>("external_boundary")
      73             :                                 : BoundaryName()),
      74         346 :     _tri_elem_subdomain_name_suffix(getParam<SubdomainName>("tri_elem_subdomain_name_suffix")),
      75         346 :     _tri_elem_subdomain_shift(isParamValid("tri_elem_subdomain_shift")
      76         346 :                                   ? getParam<subdomain_id_type>("tri_elem_subdomain_shift")
      77             :                                   : Moose::INVALID_BLOCK_ID),
      78         692 :     _input(getMeshByName(_input_name))
      79             : {
      80         346 :   declareMeshProperty("pattern_pitch_meta", 0.0);
      81         346 :   declareMeshProperty("input_pitch_meta", 0.0);
      82         692 :   declareMeshProperty("is_control_drum_meta", false);
      83         346 :   if (std::accumulate(_trim_peripheral_region.begin(), _trim_peripheral_region.end(), 0) == 0 &&
      84             :       !_peripheral_trimming_section_boundary.empty())
      85           4 :     paramError("peripheral_trimming_section_boundary",
      86             :                "this input parameter is not used if peripheral trimming is not performed.");
      87         342 : }
      88             : 
      89             : std::unique_ptr<MeshBase>
      90         318 : PolygonMeshTrimmerBase::generate()
      91             : {
      92         318 :   auto replicated_mesh_ptr = dynamic_cast<ReplicatedMesh *>(_input.get());
      93         318 :   if (!replicated_mesh_ptr)
      94           0 :     paramError("input", "Input is not a replicated mesh, which is required");
      95             : 
      96             :   ReplicatedMesh & mesh = *replicated_mesh_ptr;
      97             : 
      98             :   // Passing metadata
      99         636 :   if (hasMeshProperty<Real>("input_pitch_meta", _input_name))
     100         564 :     setMeshProperty("input_pitch_meta", getMeshProperty<Real>("input_pitch_meta", _input_name));
     101         636 :   if (hasMeshProperty<bool>("is_control_drum_meta", _input_name))
     102         600 :     setMeshProperty("is_control_drum_meta",
     103             :                     getMeshProperty<bool>("is_control_drum_meta", _input_name));
     104             : 
     105             :   const boundary_id_type external_boundary_id =
     106             :       _external_boundary_name.empty()
     107         318 :           ? (boundary_id_type)OUTER_SIDESET_ID
     108           4 :           : MooseMeshUtils::getBoundaryID(_external_boundary_name, mesh);
     109         318 :   if (external_boundary_id == libMesh::BoundaryInfo::invalid_id)
     110           4 :     paramError("external_boundary",
     111             :                "the provided external boundary does not exist in the input mesh.");
     112             : 
     113             :   std::set<subdomain_id_type> subdomain_ids_set;
     114         314 :   mesh.subdomain_ids(subdomain_ids_set);
     115             : 
     116         314 :   if (*max_element(_trim_peripheral_region.begin(), _trim_peripheral_region.end()))
     117             :   {
     118             :     const boundary_id_type peripheral_trimming_section_boundary_id =
     119             :         _peripheral_trimming_section_boundary.empty()
     120         398 :             ? external_boundary_id
     121         596 :             : (MooseMeshUtils::getBoundaryIDs(mesh, {_peripheral_trimming_section_boundary}, true))
     122             :                   .front();
     123         200 :     peripheralTrimmer(mesh,
     124         200 :                       _trim_peripheral_region,
     125             :                       external_boundary_id,
     126             :                       peripheral_trimming_section_boundary_id,
     127             :                       subdomain_ids_set);
     128         200 :     mesh.get_boundary_info().sideset_name(peripheral_trimming_section_boundary_id) =
     129         200 :         _peripheral_trimming_section_boundary;
     130             :   }
     131         228 :   else if (hasMeshProperty<Real>("pattern_pitch_meta", _input_name))
     132         192 :     setMeshProperty("pattern_pitch_meta", getMeshProperty<Real>("pattern_pitch_meta", _input_name));
     133             : 
     134         314 :   if (_center_trim_sector_number < _num_sides * 2)
     135             :   {
     136             :     const boundary_id_type center_trimming_section_boundary_id =
     137             :         _center_trimming_section_boundary.empty()
     138         260 :             ? external_boundary_id
     139         388 :             : (MooseMeshUtils::getBoundaryIDs(mesh, {_center_trimming_section_boundary}, true))
     140             :                   .front();
     141         268 :     centerTrimmer(mesh,
     142             :                   _num_sides,
     143         132 :                   _center_trim_sector_number,
     144         132 :                   _trimming_start_sector,
     145             :                   external_boundary_id,
     146             :                   center_trimming_section_boundary_id,
     147             :                   subdomain_ids_set);
     148         132 :     mesh.get_boundary_info().sideset_name(center_trimming_section_boundary_id) =
     149         132 :         _center_trimming_section_boundary;
     150             :   }
     151             : 
     152         310 :   if (MooseMeshXYCuttingUtils::quasiTriElementsFixer(
     153         314 :           mesh, subdomain_ids_set, _tri_elem_subdomain_shift, _tri_elem_subdomain_name_suffix))
     154          81 :     mesh.prepare_for_use();
     155             : 
     156         306 :   return std::move(_input);
     157             : }
     158             : 
     159             : void
     160         132 : PolygonMeshTrimmerBase::centerTrimmer(ReplicatedMesh & mesh,
     161             :                                       const unsigned int num_sides,
     162             :                                       const unsigned int center_trim_sector_number,
     163             :                                       const unsigned int trimming_start_sector,
     164             :                                       const boundary_id_type external_boundary_id,
     165             :                                       const boundary_id_type center_trimming_section_boundary_id,
     166             :                                       const std::set<subdomain_id_type> subdomain_ids_set)
     167             : {
     168         132 :   const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
     169         132 :   const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
     170             : 
     171             :   std::vector<std::vector<Real>> bdry_pars = {
     172         132 :       {std::cos((Real)trimming_start_sector * M_PI / (Real)num_sides),
     173         132 :        std::sin((Real)trimming_start_sector * M_PI / (Real)num_sides),
     174             :        0.0},
     175         132 :       {-std::cos((Real)(trimming_start_sector + center_trim_sector_number) * M_PI /
     176             :                  (Real)num_sides),
     177         132 :        -std::sin((Real)(trimming_start_sector + center_trim_sector_number) * M_PI /
     178             :                  (Real)num_sides),
     179         396 :        0.0}};
     180             : 
     181         396 :   for (unsigned int i = 0; i < bdry_pars.size(); i++)
     182             :     try
     183             :     {
     184         264 :       MooseMeshXYCuttingUtils::lineRemoverMoveNode(mesh,
     185             :                                                    bdry_pars[i],
     186             :                                                    block_id_to_remove,
     187             :                                                    subdomain_ids_set,
     188             :                                                    center_trimming_section_boundary_id,
     189             :                                                    external_boundary_id);
     190             :     }
     191           0 :     catch (MooseException & e)
     192             :     {
     193           0 :       if (((std::string)e.what())
     194           0 :               .compare("The input mesh has degenerate quad element before trimming.") == 0)
     195           0 :         paramError("input", "The input mesh has degenerate quad element before trimming.");
     196           0 :       else if (((std::string)e.what())
     197           0 :                    .compare("The new subdomain name already exists in the mesh.") == 0)
     198           0 :         paramError("tri_elem_subdomain_name_suffix",
     199             :                    "The new subdomain name already exists in the mesh.");
     200           0 :     }
     201         396 : }
     202             : 
     203             : void
     204         200 : PolygonMeshTrimmerBase::peripheralTrimmer(
     205             :     ReplicatedMesh & mesh,
     206             :     const std::vector<unsigned short> trim_peripheral_region,
     207             :     const boundary_id_type external_boundary_id,
     208             :     const boundary_id_type peripheral_trimming_section_boundary_id,
     209             :     const std::set<subdomain_id_type> subdomain_ids_set)
     210             : {
     211         200 :   const unsigned int num_sides = trim_peripheral_region.size();
     212         200 :   const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
     213         200 :   const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
     214             : 
     215         200 :   const Real unit_length = getMeshProperty<Real>("input_pitch_meta", _input_name) /
     216         308 :                            (num_sides == 6 ? std::sqrt(3.0) : 2.0);
     217             :   // Add metadata to input
     218         200 :   const Real multiplier = ((Real)getMeshProperty<unsigned int>("pattern_size", _input_name) - 1.0) *
     219         308 :                           (num_sides == 6 ? 0.75 : 1.0);
     220         200 :   const Real ch_length = multiplier * unit_length;
     221         400 :   setMeshProperty("pattern_pitch_meta", ch_length * 2.0);
     222             : 
     223             :   std::vector<std::vector<Real>> bdry_pars;
     224         200 :   if (num_sides == 6)
     225         644 :     bdry_pars = {{1.0 / std::sqrt(3.0), 1.0, -ch_length / std::sqrt(3.0) * 2.0},
     226             :                  {-1.0 / std::sqrt(3.0), 1.0, -ch_length / std::sqrt(3.0) * 2.0},
     227             :                  {-1.0, 0.0, -ch_length},
     228             :                  {-1.0 / std::sqrt(3.0), -1.0, -ch_length / std::sqrt(3.0) * 2.0},
     229             :                  {1.0 / std::sqrt(3.0), -1.0, -ch_length / std::sqrt(3.0) * 2.0},
     230         644 :                  {1.0, 0.0, -ch_length}};
     231             :   else
     232         540 :     bdry_pars = {{1.0, 0.0, -ch_length},
     233             :                  {0.0, 1.0, -ch_length},
     234             :                  {-1.0, 0.0, -ch_length},
     235         540 :                  {0.0, -1.0, -ch_length}};
     236             : 
     237        1184 :   for (unsigned int i = 0; i < bdry_pars.size(); i++)
     238         984 :     if (trim_peripheral_region[i])
     239             :       try
     240             :       {
     241         663 :         MooseMeshXYCuttingUtils::lineRemoverMoveNode(mesh,
     242             :                                                      bdry_pars[i],
     243             :                                                      block_id_to_remove,
     244             :                                                      subdomain_ids_set,
     245             :                                                      peripheral_trimming_section_boundary_id,
     246             :                                                      external_boundary_id,
     247         663 :                                                      std::vector<boundary_id_type>(),
     248             :                                                      true);
     249             :       }
     250           0 :       catch (MooseException & e)
     251             :       {
     252           0 :         if (((std::string)e.what())
     253           0 :                 .compare("The input mesh has degenerate quad element before trimming.") == 0)
     254           0 :           paramError("input", "The input mesh has degenerate quad element before trimming.");
     255           0 :         else if (((std::string)e.what())
     256           0 :                      .compare("The new subdomain name already exists in the mesh.") == 0)
     257           0 :           paramError("tri_elem_subdomain_name_suffix",
     258             :                      "The new subdomain name already exists in the mesh.");
     259           0 :       }
     260         600 : }

Generated by: LCOV version 1.14