LCOV - code coverage report
Current view: top level - src/meshgenerators - XYMeshLineCutter.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 83 95 87.4 %
Date: 2025-07-17 01:28:37 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       14449 : XYMeshLineCutter::validParams()
      23             : {
      24       14449 :   InputParameters params = MeshGenerator::validParams();
      25             : 
      26       14449 :   MooseEnum cutting_type("CUT_ELEM_TRI MOV_NODE", "CUT_ELEM_TRI");
      27       14449 :   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       14449 :   params.addRequiredParam<MeshGeneratorName>("input", "The input mesh that needs to be trimmed.");
      35       14449 :   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       14449 :   params.addRequiredParam<boundary_id_type>(
      40             :       "new_boundary_id", "Boundary id to be assigned to the boundary formed by the cutting.");
      41       14449 :   params.addParam<boundary_id_type>("input_mesh_external_boundary_id",
      42             :                                     "Boundary id of the external boundary of the input mesh.");
      43       14449 :   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       14449 :   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       14449 :   params.addParam<subdomain_id_type>(
      53             :       "tri_elem_subdomain_shift",
      54             :       "Customized id shift to define subdomain ids of the converted triangular elements.");
      55       43347 :   params.addParam<bool>(
      56       28898 :       "improve_tri_elements", false, "Whether to improve TRI3 elements after CUT_ELEM_TRI method.");
      57             : 
      58       14449 :   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       28898 :   return params;
      64       14449 : }
      65             : 
      66         100 : XYMeshLineCutter::XYMeshLineCutter(const InputParameters & parameters)
      67             :   : MeshGenerator(parameters),
      68         100 :     _cutting_type(getParam<MooseEnum>("cutting_type").template getEnum<CutType>()),
      69         100 :     _input_name(getParam<MeshGeneratorName>("input")),
      70         100 :     _cut_line_params(getParam<std::vector<Real>>("cut_line_params")),
      71         100 :     _new_boundary_id(getParam<boundary_id_type>("new_boundary_id")),
      72         100 :     _input_mesh_external_boundary_id(
      73         200 :         isParamValid("input_mesh_external_boundary_id")
      74         100 :             ? getParam<boundary_id_type>("input_mesh_external_boundary_id")
      75             :             : Moose::INVALID_BOUNDARY_ID),
      76         100 :     _other_boundaries_to_conform(
      77         200 :         isParamValid("other_boundaries_to_conform")
      78         100 :             ? getParam<std::vector<boundary_id_type>>("other_boundaries_to_conform")
      79             :             : std::vector<boundary_id_type>()),
      80         100 :     _tri_elem_subdomain_name_suffix(getParam<SubdomainName>("tri_elem_subdomain_name_suffix")),
      81         200 :     _tri_elem_subdomain_shift(isParamValid("tri_elem_subdomain_shift")
      82         100 :                                   ? getParam<subdomain_id_type>("tri_elem_subdomain_shift")
      83             :                                   : Moose::INVALID_BLOCK_ID),
      84         100 :     _improve_tri_elements(getParam<bool>("improve_tri_elements")),
      85         200 :     _input(getMeshByName(_input_name))
      86             : {
      87         100 :   if (_cut_line_params.size() != 3)
      88           4 :     paramError("cut_line_params", "this parameter must have three elements.");
      89         108 :   if (MooseUtils::absoluteFuzzyEqual(_cut_line_params[0], 0.0) &&
      90         108 :       MooseUtils::absoluteFuzzyEqual(_cut_line_params[1], 0.0))
      91           4 :     paramError("cut_line_params", "At lease one of the first two elements must be non-zero.");
      92          92 :   if (_cutting_type == CutType::MOV_NODE && _improve_tri_elements)
      93           4 :     paramError("improve_tri_elements",
      94             :                "This parameter is not supported when 'MOV_NODE' method is selected as "
      95             :                "'cutting_type'.");
      96          88 :   if (_input_mesh_external_boundary_id == Moose::INVALID_BOUNDARY_ID &&
      97          36 :       _cutting_type == CutType::MOV_NODE)
      98           4 :     paramError(
      99             :         "input_mesh_external_boundary_id",
     100             :         "This parameter must be provided if 'MOV_NODE' method is selected as 'cutting_type'.");
     101          84 : }
     102             : 
     103             : std::unique_ptr<MeshBase>
     104          84 : XYMeshLineCutter::generate()
     105             : {
     106          84 :   auto replicated_mesh_ptr = dynamic_cast<ReplicatedMesh *>(_input.get());
     107          84 :   if (!replicated_mesh_ptr)
     108           0 :     paramError("input", "Input is not a replicated mesh, which is required");
     109         164 :   if (*(replicated_mesh_ptr->elem_dimensions().begin()) != 2 ||
     110         164 :       *(replicated_mesh_ptr->elem_dimensions().rbegin()) != 2)
     111           4 :     paramError("input", "Only 2D meshes are supported.");
     112             : 
     113             :   // Check that the input boundaries are part of the mesh
     114          80 :   if (isParamValid("input_mesh_external_boundary_id"))
     115          52 :     if (!MooseMeshUtils::hasBoundaryID(*replicated_mesh_ptr, _input_mesh_external_boundary_id))
     116           4 :       paramError("input_mesh_external_boundary_id", "Boundary must exist in input mesh");
     117             : 
     118             :   // Check that the other boundaries to conform to are part of the mesh
     119          76 :   if (isParamValid("other_boundaries_to_conform"))
     120          44 :     for (const auto bid : _other_boundaries_to_conform)
     121          36 :       if (!MooseMeshUtils::hasBoundaryID(*replicated_mesh_ptr, bid))
     122           4 :         paramError("other_boundaries_to_conform",
     123           4 :                    "Boundary '" + std::to_string(bid) + "' must exist in input mesh");
     124             : 
     125          72 :   ReplicatedMesh & mesh = *replicated_mesh_ptr;
     126             :   // Subdomain ID for TRI elements arising of QUAD element cuts must be new
     127          72 :   std::set<subdomain_id_type> subdomain_ids_set;
     128          72 :   mesh.subdomain_ids(subdomain_ids_set);
     129          72 :   const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
     130          72 :   const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
     131          72 :   const subdomain_id_type tri_subdomain_id_shift =
     132          72 :       _tri_elem_subdomain_shift == Moose::INVALID_BLOCK_ID ? max_subdomain_id + 2
     133             :                                                            : _tri_elem_subdomain_shift;
     134             : 
     135             :   // Use a unique new boundary id as the temporary boundary id for _new_boundary_id
     136             :   // This help prevent issues when _new_boundary_id is already used in the mesh
     137          72 :   boundary_id_type new_boundary_id_tmp = MooseMeshUtils::getNextFreeBoundaryID(mesh);
     138             : 
     139          72 :   if (_cutting_type == CutType::CUT_ELEM_TRI)
     140             :   {
     141             :     try
     142             :     {
     143          48 :       MooseMeshXYCuttingUtils::lineRemoverCutElem(mesh,
     144          44 :                                                   _cut_line_params,
     145             :                                                   tri_subdomain_id_shift,
     146          44 :                                                   _tri_elem_subdomain_name_suffix,
     147             :                                                   block_id_to_remove,
     148             :                                                   new_boundary_id_tmp,
     149          44 :                                                   _improve_tri_elements);
     150             :     }
     151           4 :     catch (MooseException & e)
     152             :     {
     153           4 :       if (((std::string)e.what()).compare("The new subdomain name already exists in the mesh.") ==
     154             :           0)
     155           4 :         paramError("tri_elem_subdomain_name_suffix", e.what());
     156             :       else
     157           0 :         mooseError("In XYMeshLineCutter with 'CUT_ELEM_TRI' mode, " + (std::string)e.what());
     158           0 :     }
     159             :   }
     160             :   else
     161             :   {
     162             :     try
     163             :     {
     164          28 :       MooseMeshXYCuttingUtils::lineRemoverMoveNode(mesh,
     165          28 :                                                    _cut_line_params,
     166             :                                                    block_id_to_remove,
     167             :                                                    subdomain_ids_set,
     168             :                                                    new_boundary_id_tmp,
     169          28 :                                                    _input_mesh_external_boundary_id,
     170          28 :                                                    _other_boundaries_to_conform);
     171             :     }
     172           0 :     catch (MooseException & e)
     173             :     {
     174           0 :       if (((std::string)e.what())
     175           0 :               .compare("The input mesh has degenerate quad element before trimming.") == 0)
     176           0 :         paramError("input", e.what());
     177           0 :       else if (((std::string)e.what())
     178           0 :                    .compare("The new subdomain name already exists in the mesh.") == 0)
     179           0 :         paramError("tri_elem_subdomain_name_suffix", e.what());
     180             :       else
     181           0 :         mooseError("In XYMeshLineCutter with 'MOV_NODE' mode, " + (std::string)e.what());
     182           0 :     }
     183          32 :     MooseMeshXYCuttingUtils::quasiTriElementsFixer(
     184          28 :         mesh, subdomain_ids_set, tri_subdomain_id_shift, _tri_elem_subdomain_name_suffix);
     185             :   }
     186             : 
     187             :   // Then rename the temporary boundary id to _new_boundary_id
     188          64 :   MeshTools::Modification::change_boundary_id(mesh, new_boundary_id_tmp, _new_boundary_id);
     189             : 
     190          64 :   mesh.prepare_for_use();
     191         128 :   return std::move(_input);
     192          68 : }

Generated by: LCOV version 1.14