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