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 : }
|