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 14465 : XYMeshLineCutter::validParams()
23 : {
24 14465 : InputParameters params = MeshGenerator::validParams();
25 :
26 14465 : MooseEnum cutting_type("CUT_ELEM_TRI MOV_NODE", "CUT_ELEM_TRI");
27 14465 : 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 14465 : params.addRequiredParam<MeshGeneratorName>("input", "The input mesh that needs to be trimmed.");
35 14465 : 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 14465 : params.addRequiredParam<boundary_id_type>(
40 : "new_boundary_id", "Boundary id to be assigned to the boundary formed by the cutting.");
41 14465 : params.addParam<boundary_id_type>("input_mesh_external_boundary_id",
42 : "Boundary id of the external boundary of the input mesh.");
43 14465 : 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 14465 : 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 14465 : params.addParam<subdomain_id_type>(
53 : "tri_elem_subdomain_shift",
54 : "Customized id shift to define subdomain ids of the converted triangular elements.");
55 43395 : params.addParam<bool>(
56 28930 : "improve_tri_elements", false, "Whether to improve TRI3 elements after CUT_ELEM_TRI method.");
57 :
58 14465 : 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 28930 : return params;
64 14465 : }
65 :
66 108 : XYMeshLineCutter::XYMeshLineCutter(const InputParameters & parameters)
67 : : MeshGenerator(parameters),
68 108 : _cutting_type(getParam<MooseEnum>("cutting_type").template getEnum<CutType>()),
69 108 : _input_name(getParam<MeshGeneratorName>("input")),
70 108 : _cut_line_params(getParam<std::vector<Real>>("cut_line_params")),
71 108 : _new_boundary_id(getParam<boundary_id_type>("new_boundary_id")),
72 108 : _input_mesh_external_boundary_id(
73 216 : isParamValid("input_mesh_external_boundary_id")
74 108 : ? getParam<boundary_id_type>("input_mesh_external_boundary_id")
75 : : Moose::INVALID_BOUNDARY_ID),
76 108 : _other_boundaries_to_conform(
77 216 : isParamValid("other_boundaries_to_conform")
78 108 : ? getParam<std::vector<boundary_id_type>>("other_boundaries_to_conform")
79 : : std::vector<boundary_id_type>()),
80 108 : _tri_elem_subdomain_name_suffix(getParam<SubdomainName>("tri_elem_subdomain_name_suffix")),
81 216 : _tri_elem_subdomain_shift(isParamValid("tri_elem_subdomain_shift")
82 108 : ? getParam<subdomain_id_type>("tri_elem_subdomain_shift")
83 : : Moose::INVALID_BLOCK_ID),
84 108 : _improve_tri_elements(getParam<bool>("improve_tri_elements")),
85 216 : _input(getMeshByName(_input_name))
86 : {
87 108 : if (_cut_line_params.size() != 3)
88 4 : paramError("cut_line_params", "this parameter must have three elements.");
89 117 : if (MooseUtils::absoluteFuzzyEqual(_cut_line_params[0], 0.0) &&
90 117 : 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 100 : 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 96 : if (_input_mesh_external_boundary_id == Moose::INVALID_BOUNDARY_ID &&
97 39 : _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 92 : }
102 :
103 : std::unique_ptr<MeshBase>
104 92 : XYMeshLineCutter::generate()
105 : {
106 92 : auto replicated_mesh_ptr = dynamic_cast<ReplicatedMesh *>(_input.get());
107 92 : if (!replicated_mesh_ptr)
108 0 : paramError("input", "Input is not a replicated mesh, which is required");
109 180 : if (*(replicated_mesh_ptr->elem_dimensions().begin()) != 2 ||
110 180 : *(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 88 : if (isParamValid("input_mesh_external_boundary_id"))
115 57 : 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 84 : if (isParamValid("other_boundaries_to_conform"))
120 49 : for (const auto bid : _other_boundaries_to_conform)
121 40 : 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 80 : ReplicatedMesh & mesh = *replicated_mesh_ptr;
126 : // Subdomain ID for TRI elements arising of QUAD element cuts must be new
127 80 : std::set<subdomain_id_type> subdomain_ids_set;
128 80 : mesh.subdomain_ids(subdomain_ids_set);
129 80 : const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
130 80 : const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
131 80 : const subdomain_id_type tri_subdomain_id_shift =
132 80 : _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 80 : boundary_id_type new_boundary_id_tmp = MooseMeshUtils::getNextFreeBoundaryID(mesh);
138 :
139 80 : if (_cutting_type == CutType::CUT_ELEM_TRI)
140 : {
141 : try
142 : {
143 53 : MooseMeshXYCuttingUtils::lineRemoverCutElem(mesh,
144 49 : _cut_line_params,
145 : tri_subdomain_id_shift,
146 49 : _tri_elem_subdomain_name_suffix,
147 : block_id_to_remove,
148 : new_boundary_id_tmp,
149 49 : _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 31 : MooseMeshXYCuttingUtils::lineRemoverMoveNode(mesh,
165 31 : _cut_line_params,
166 : block_id_to_remove,
167 : subdomain_ids_set,
168 : new_boundary_id_tmp,
169 31 : _input_mesh_external_boundary_id,
170 31 : _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 35 : MooseMeshXYCuttingUtils::quasiTriElementsFixer(
184 31 : 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 72 : MeshTools::Modification::change_boundary_id(mesh, new_boundary_id_tmp, _new_boundary_id);
189 :
190 72 : mesh.prepare_for_use();
191 144 : return std::move(_input);
192 76 : }
|