LCOV - code coverage report
Current view: top level - src/meshgenerators - XYMeshLineCutter.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 85 97 87.6 %
Date: 2026-05-29 20:35:17 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 "XYMeshLineCutter.h"
      11             : #include "MooseMeshXYCuttingUtils.h"
      12             : #include "MooseMeshUtils.h"
      13             : 
      14             : #include "libmesh/mesh_modification.h"
      15             : 
      16             : // C++ includes
      17             : #include <cmath>
      18             : 
      19             : registerMooseObject("MooseApp", XYMeshLineCutter);
      20             : 
      21             : InputParameters
      22        3231 : XYMeshLineCutter::validParams()
      23             : {
      24        3231 :   InputParameters params = MeshGenerator::validParams();
      25             : 
      26       12924 :   MooseEnum cutting_type("CUT_ELEM_TRI MOV_NODE", "CUT_ELEM_TRI");
      27       12924 :   params.addParam<MooseEnum>(
      28             :       "cutting_type",
      29             :       cutting_type,
      30             :       "Which method is to be used to cut the input mesh. 'CUT_ELEM_TRI' is the recommended method "
      31             :       "but it may cause fine elements near the cutting line, while 'MOV_NODE' deforms subdomain "
      32             :       "boundaries if they are not perpendicular to the cutting line.");
      33             : 
      34       12924 :   params.addRequiredParam<MeshGeneratorName>("input", "The input mesh that needs to be trimmed.");
      35       12924 :   params.addRequiredParam<std::vector<Real>>(
      36             :       "cut_line_params",
      37             :       "Cutting line parameters, which are a, b, and c in line equation a*x+b*y+c=0. Note that "
      38             :       "a*x+b*y+c>0 part is being removed.");
      39       12924 :   params.addRequiredParam<boundary_id_type>(
      40             :       "new_boundary_id", "Boundary id to be assigned to the boundary formed by the cutting.");
      41       12924 :   params.addParam<boundary_id_type>("input_mesh_external_boundary_id",
      42             :                                     "Boundary id of the external boundary of the input mesh.");
      43       12924 :   params.addParam<std::vector<boundary_id_type>>(
      44             :       "other_boundaries_to_conform",
      45             :       "IDs of the other boundaries that need to be conformed to during nodes moving.");
      46             : 
      47       12924 :   params.addParam<SubdomainName>(
      48             :       "tri_elem_subdomain_name_suffix",
      49             :       "trimmer_tri",
      50             :       "Suffix to the block name used for quad elements that are trimmed/converted into "
      51             :       "triangular elements to avert degenerate quad elements");
      52       12924 :   params.addParam<subdomain_id_type>(
      53             :       "tri_elem_subdomain_shift",
      54             :       "Customized id shift to define subdomain ids of the converted triangular elements.");
      55        9693 :   params.addParam<bool>(
      56        6462 :       "improve_tri_elements", false, "Whether to improve TRI3 elements after CUT_ELEM_TRI method.");
      57             : 
      58        3231 :   params.addClassDescription(
      59             :       "This XYMeshLineCutter object is designed to trim the input mesh by removing all the "
      60             :       "elements on one side of a given straight line with special processing on the elements "
      61             :       "crossed by the cutting line to ensure a smooth cross-section.");
      62             : 
      63        6462 :   return params;
      64        3231 : }
      65             : 
      66          91 : XYMeshLineCutter::XYMeshLineCutter(const InputParameters & parameters)
      67             :   : MeshGenerator(parameters),
      68          91 :     _cutting_type(getParam<MooseEnum>("cutting_type").template getEnum<CutType>()),
      69         182 :     _input_name(getParam<MeshGeneratorName>("input")),
      70         182 :     _cut_line_params(getParam<std::vector<Real>>("cut_line_params")),
      71         182 :     _new_boundary_id(getParam<boundary_id_type>("new_boundary_id")),
      72          91 :     _input_mesh_external_boundary_id(
      73         182 :         isParamValid("input_mesh_external_boundary_id")
      74         189 :             ? getParam<boundary_id_type>("input_mesh_external_boundary_id")
      75             :             : Moose::INVALID_BOUNDARY_ID),
      76         102 :     _other_boundaries_to_conform(
      77         273 :         isParamValid("other_boundaries_to_conform")
      78          91 :             ? getParam<std::vector<boundary_id_type>>("other_boundaries_to_conform")
      79             :             : std::vector<boundary_id_type>()),
      80         182 :     _tri_elem_subdomain_name_suffix(getParam<SubdomainName>("tri_elem_subdomain_name_suffix")),
      81         182 :     _tri_elem_subdomain_shift(isParamValid("tri_elem_subdomain_shift")
      82          91 :                                   ? getParam<subdomain_id_type>("tri_elem_subdomain_shift")
      83             :                                   : Moose::INVALID_BLOCK_ID),
      84         182 :     _improve_tri_elements(getParam<bool>("improve_tri_elements")),
      85         182 :     _input(getMeshByName(_input_name))
      86             : {
      87          91 :   if (_cut_line_params.size() != 3)
      88           9 :     paramError("cut_line_params", "this parameter must have three elements.");
      89          99 :   if (MooseUtils::absoluteFuzzyEqual(_cut_line_params[0], 0.0) &&
      90          99 :       MooseUtils::absoluteFuzzyEqual(_cut_line_params[1], 0.0))
      91           6 :     paramError("cut_line_params", "At lease one of the first two elements must be non-zero.");
      92          85 :   if (_cutting_type == CutType::MOV_NODE && _improve_tri_elements)
      93           6 :     paramError("improve_tri_elements",
      94             :                "This parameter is not supported when 'MOV_NODE' method is selected as "
      95             :                "'cutting_type'.");
      96          82 :   if (_input_mesh_external_boundary_id == Moose::INVALID_BOUNDARY_ID &&
      97          33 :       _cutting_type == CutType::MOV_NODE)
      98           6 :     paramError(
      99             :         "input_mesh_external_boundary_id",
     100             :         "This parameter must be provided if 'MOV_NODE' method is selected as 'cutting_type'.");
     101          79 : }
     102             : 
     103             : std::unique_ptr<MeshBase>
     104          79 : XYMeshLineCutter::generate()
     105             : {
     106             :   // We're querying elem dim caches from our input mesh
     107          79 :   if (!_input->preparation().has_cached_elem_data)
     108          79 :     _input->cache_elem_data();
     109             : 
     110          79 :   auto replicated_mesh_ptr = dynamic_cast<ReplicatedMesh *>(_input.get());
     111          79 :   if (!replicated_mesh_ptr)
     112           0 :     paramError("input", "Input is not a replicated mesh, which is required");
     113         155 :   if (*(replicated_mesh_ptr->elem_dimensions().begin()) != 2 ||
     114         155 :       *(replicated_mesh_ptr->elem_dimensions().rbegin()) != 2)
     115           6 :     paramError("input", "Only 2D meshes are supported.");
     116             : 
     117             :   // Check that the input boundaries are part of the mesh
     118         228 :   if (isParamValid("input_mesh_external_boundary_id"))
     119          49 :     if (!MooseMeshUtils::hasBoundaryID(*replicated_mesh_ptr, _input_mesh_external_boundary_id))
     120           6 :       paramError("input_mesh_external_boundary_id", "Boundary must exist in input mesh");
     121             : 
     122             :   // Check that the other boundaries to conform to are part of the mesh
     123         219 :   if (isParamValid("other_boundaries_to_conform"))
     124          43 :     for (const auto bid : _other_boundaries_to_conform)
     125          35 :       if (!MooseMeshUtils::hasBoundaryID(*replicated_mesh_ptr, bid))
     126           3 :         paramError("other_boundaries_to_conform",
     127           3 :                    "Boundary '" + std::to_string(bid) + "' must exist in input mesh");
     128             : 
     129          70 :   ReplicatedMesh & mesh = *replicated_mesh_ptr;
     130             :   // Subdomain ID for TRI elements arising of QUAD element cuts must be new
     131          70 :   std::set<subdomain_id_type> subdomain_ids_set;
     132          70 :   mesh.subdomain_ids(subdomain_ids_set);
     133          70 :   const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
     134          70 :   const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
     135          70 :   const subdomain_id_type tri_subdomain_id_shift =
     136          70 :       _tri_elem_subdomain_shift == Moose::INVALID_BLOCK_ID ? max_subdomain_id + 2
     137             :                                                            : _tri_elem_subdomain_shift;
     138             : 
     139             :   // Use a unique new boundary id as the temporary boundary id for _new_boundary_id
     140             :   // This help prevent issues when _new_boundary_id is already used in the mesh
     141          70 :   boundary_id_type new_boundary_id_tmp = MooseMeshUtils::getNextFreeBoundaryID(mesh);
     142             : 
     143          70 :   if (_cutting_type == CutType::CUT_ELEM_TRI)
     144             :   {
     145             :     try
     146             :     {
     147          46 :       MooseMeshXYCuttingUtils::lineRemoverCutElem(mesh,
     148          43 :                                                   _cut_line_params,
     149             :                                                   tri_subdomain_id_shift,
     150          43 :                                                   _tri_elem_subdomain_name_suffix,
     151             :                                                   block_id_to_remove,
     152             :                                                   new_boundary_id_tmp,
     153          43 :                                                   _improve_tri_elements);
     154             :     }
     155           3 :     catch (MooseException & e)
     156             :     {
     157           6 :       if (((std::string)e.what()).compare("The new subdomain name already exists in the mesh.") ==
     158             :           0)
     159           6 :         paramError("tri_elem_subdomain_name_suffix", e.what());
     160             :       else
     161           0 :         mooseError("In XYMeshLineCutter with 'CUT_ELEM_TRI' mode, " + (std::string)e.what());
     162           0 :     }
     163             :   }
     164             :   else
     165             :   {
     166             :     try
     167             :     {
     168          27 :       MooseMeshXYCuttingUtils::lineRemoverMoveNode(mesh,
     169          27 :                                                    _cut_line_params,
     170             :                                                    block_id_to_remove,
     171             :                                                    subdomain_ids_set,
     172             :                                                    new_boundary_id_tmp,
     173          27 :                                                    _input_mesh_external_boundary_id,
     174          27 :                                                    _other_boundaries_to_conform);
     175             :     }
     176           0 :     catch (MooseException & e)
     177             :     {
     178           0 :       if (((std::string)e.what())
     179           0 :               .compare("The input mesh has degenerate quad element before trimming.") == 0)
     180           0 :         paramError("input", e.what());
     181           0 :       else if (((std::string)e.what())
     182           0 :                    .compare("The new subdomain name already exists in the mesh.") == 0)
     183           0 :         paramError("tri_elem_subdomain_name_suffix", e.what());
     184             :       else
     185           0 :         mooseError("In XYMeshLineCutter with 'MOV_NODE' mode, " + (std::string)e.what());
     186           0 :     }
     187          30 :     MooseMeshXYCuttingUtils::quasiTriElementsFixer(
     188          27 :         mesh, subdomain_ids_set, tri_subdomain_id_shift, _tri_elem_subdomain_name_suffix);
     189             :   }
     190             : 
     191             :   // Then rename the temporary boundary id to _new_boundary_id
     192          64 :   MeshTools::Modification::change_boundary_id(mesh, new_boundary_id_tmp, _new_boundary_id);
     193             : 
     194          64 :   mesh.prepare_for_use();
     195         128 :   return std::move(_input);
     196          67 : }

Generated by: LCOV version 1.14