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 "PolygonMeshTrimmerBase.h"
11 : #include "MooseMeshXYCuttingUtils.h"
12 : #include "MooseMeshUtils.h"
13 : #include "MathUtils.h"
14 :
15 : // C++ includes
16 : #include <cmath> // provides round, not std::round (see http://www.cplusplus.com/reference/cmath/round/)
17 :
18 : InputParameters
19 540 : PolygonMeshTrimmerBase::validParams()
20 : {
21 540 : InputParameters params = PolygonMeshGeneratorBase::validParams();
22 1080 : params.addRequiredParam<MeshGeneratorName>("input", "The input mesh that needs to be trimmed.");
23 1080 : params.addParam<BoundaryName>("peripheral_trimming_section_boundary",
24 : "Boundary formed by peripheral trimming.");
25 1080 : params.addRangeCheckedParam<short>(
26 : "center_trim_starting_index",
27 : "center_trim_starting_index>=0 & center_trim_starting_index<12",
28 : "Index of the starting center trimming position.");
29 1080 : params.addRangeCheckedParam<short>("center_trim_ending_index",
30 : "center_trim_ending_index>=0 & center_trim_ending_index<12",
31 : "Index of the ending center trimming position.");
32 1080 : params.addParam<BoundaryName>("center_trimming_section_boundary",
33 : "Boundary formed by center trimming (external_boundary will be "
34 : "assigned if this parameter is not provided).");
35 1080 : params.addParam<BoundaryName>("external_boundary",
36 : "External boundary of the input mesh prior to the trimming.");
37 1080 : params.addParam<SubdomainName>(
38 : "tri_elem_subdomain_name_suffix",
39 : "trimmer_tri",
40 : "Suffix to the block name used for quad elements that are trimmed/converted into "
41 : "triangular elements to avert degenerate quad elements");
42 1080 : params.addParam<subdomain_id_type>(
43 : "tri_elem_subdomain_shift",
44 : "Customized id shift to define subdomain ids of the converted triangular elements.");
45 :
46 1080 : params.addParamNamesToGroup(
47 : "center_trim_starting_index center_trim_ending_index center_trimming_section_boundary",
48 : "Center Trimming");
49 1080 : params.addParamNamesToGroup("peripheral_trimming_section_boundary", "Peripheral Trimming");
50 1080 : params.addParamNamesToGroup("tri_elem_subdomain_name_suffix tri_elem_subdomain_shift",
51 : "Trimmed Boundary Repair");
52 :
53 540 : params.addClassDescription("This PolygonMeshTrimmerBase is the base class for "
54 : "CartesianMeshTrimmer and HexagonMeshTrimmer.");
55 :
56 540 : return params;
57 0 : }
58 :
59 278 : PolygonMeshTrimmerBase::PolygonMeshTrimmerBase(const InputParameters & parameters)
60 : : PolygonMeshGeneratorBase(parameters),
61 0 : _input_name(getParam<MeshGeneratorName>("input")),
62 556 : _trim_peripheral_region(getParam<std::vector<unsigned short>>("trim_peripheral_region")),
63 440 : _peripheral_trimming_section_boundary(
64 278 : isParamValid("peripheral_trimming_section_boundary")
65 278 : ? getParam<BoundaryName>("peripheral_trimming_section_boundary")
66 : : BoundaryName()),
67 382 : _center_trimming_section_boundary(
68 278 : isParamValid("center_trimming_section_boundary")
69 278 : ? getParam<BoundaryName>("center_trimming_section_boundary")
70 : : BoundaryName()),
71 560 : _external_boundary_name(isParamValid("external_boundary")
72 278 : ? getParam<BoundaryName>("external_boundary")
73 : : BoundaryName()),
74 278 : _tri_elem_subdomain_name_suffix(getParam<SubdomainName>("tri_elem_subdomain_name_suffix")),
75 278 : _tri_elem_subdomain_shift(isParamValid("tri_elem_subdomain_shift")
76 278 : ? getParam<subdomain_id_type>("tri_elem_subdomain_shift")
77 : : Moose::INVALID_BLOCK_ID),
78 556 : _input(getMeshByName(_input_name))
79 : {
80 278 : declareMeshProperty("pattern_pitch_meta", 0.0);
81 278 : declareMeshProperty("input_pitch_meta", 0.0);
82 556 : declareMeshProperty("is_control_drum_meta", false);
83 278 : if (std::accumulate(_trim_peripheral_region.begin(), _trim_peripheral_region.end(), 0) == 0 &&
84 : !_peripheral_trimming_section_boundary.empty())
85 4 : paramError("peripheral_trimming_section_boundary",
86 : "this input parameter is not used if peripheral trimming is not performed.");
87 274 : }
88 :
89 : std::unique_ptr<MeshBase>
90 250 : PolygonMeshTrimmerBase::generate()
91 : {
92 250 : auto replicated_mesh_ptr = dynamic_cast<ReplicatedMesh *>(_input.get());
93 250 : if (!replicated_mesh_ptr)
94 0 : paramError("input", "Input is not a replicated mesh, which is required");
95 :
96 : ReplicatedMesh & mesh = *replicated_mesh_ptr;
97 :
98 : // Passing metadata
99 500 : if (hasMeshProperty<Real>("input_pitch_meta", _input_name))
100 444 : setMeshProperty("input_pitch_meta", getMeshProperty<Real>("input_pitch_meta", _input_name));
101 500 : if (hasMeshProperty<bool>("is_control_drum_meta", _input_name))
102 472 : setMeshProperty("is_control_drum_meta",
103 : getMeshProperty<bool>("is_control_drum_meta", _input_name));
104 :
105 : const boundary_id_type external_boundary_id =
106 : _external_boundary_name.empty()
107 250 : ? (boundary_id_type)OUTER_SIDESET_ID
108 4 : : MooseMeshUtils::getBoundaryID(_external_boundary_name, mesh);
109 250 : if (external_boundary_id == libMesh::BoundaryInfo::invalid_id)
110 4 : paramError("external_boundary",
111 : "the provided external boundary does not exist in the input mesh.");
112 :
113 246 : if (!mesh.preparation().has_cached_elem_data)
114 232 : mesh.cache_elem_data();
115 : std::set<subdomain_id_type> subdomain_ids_set;
116 246 : mesh.subdomain_ids(subdomain_ids_set);
117 :
118 246 : if (*max_element(_trim_peripheral_region.begin(), _trim_peripheral_region.end()))
119 : {
120 : const boundary_id_type peripheral_trimming_section_boundary_id =
121 : _peripheral_trimming_section_boundary.empty()
122 310 : ? external_boundary_id
123 464 : : (MooseMeshUtils::getBoundaryIDs(mesh, {_peripheral_trimming_section_boundary}, true))
124 : .front();
125 156 : peripheralTrimmer(mesh,
126 156 : _trim_peripheral_region,
127 : external_boundary_id,
128 : peripheral_trimming_section_boundary_id,
129 : subdomain_ids_set);
130 156 : mesh.get_boundary_info().sideset_name(peripheral_trimming_section_boundary_id) =
131 156 : _peripheral_trimming_section_boundary;
132 : }
133 180 : else if (hasMeshProperty<Real>("pattern_pitch_meta", _input_name))
134 152 : setMeshProperty("pattern_pitch_meta", getMeshProperty<Real>("pattern_pitch_meta", _input_name));
135 :
136 246 : if (_center_trim_sector_number < _num_sides * 2)
137 : {
138 : const boundary_id_type center_trimming_section_boundary_id =
139 : _center_trimming_section_boundary.empty()
140 204 : ? external_boundary_id
141 304 : : (MooseMeshUtils::getBoundaryIDs(mesh, {_center_trimming_section_boundary}, true))
142 : .front();
143 212 : centerTrimmer(mesh,
144 : _num_sides,
145 104 : _center_trim_sector_number,
146 104 : _trimming_start_sector,
147 : external_boundary_id,
148 : center_trimming_section_boundary_id,
149 : subdomain_ids_set);
150 104 : mesh.get_boundary_info().sideset_name(center_trimming_section_boundary_id) =
151 104 : _center_trimming_section_boundary;
152 : }
153 :
154 242 : if (MooseMeshXYCuttingUtils::quasiTriElementsFixer(
155 246 : mesh, subdomain_ids_set, _tri_elem_subdomain_shift, _tri_elem_subdomain_name_suffix))
156 63 : mesh.prepare_for_use();
157 :
158 238 : return std::move(_input);
159 : }
160 :
161 : void
162 104 : PolygonMeshTrimmerBase::centerTrimmer(ReplicatedMesh & mesh,
163 : const unsigned int num_sides,
164 : const unsigned int center_trim_sector_number,
165 : const unsigned int trimming_start_sector,
166 : const boundary_id_type external_boundary_id,
167 : const boundary_id_type center_trimming_section_boundary_id,
168 : const std::set<subdomain_id_type> subdomain_ids_set)
169 : {
170 104 : const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
171 104 : const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
172 :
173 : std::vector<std::vector<Real>> bdry_pars = {
174 104 : {std::cos((Real)trimming_start_sector * M_PI / (Real)num_sides),
175 104 : std::sin((Real)trimming_start_sector * M_PI / (Real)num_sides),
176 : 0.0},
177 104 : {-std::cos((Real)(trimming_start_sector + center_trim_sector_number) * M_PI /
178 : (Real)num_sides),
179 104 : -std::sin((Real)(trimming_start_sector + center_trim_sector_number) * M_PI /
180 : (Real)num_sides),
181 312 : 0.0}};
182 :
183 312 : for (unsigned int i = 0; i < bdry_pars.size(); i++)
184 : try
185 : {
186 208 : MooseMeshXYCuttingUtils::lineRemoverMoveNode(mesh,
187 : bdry_pars[i],
188 : block_id_to_remove,
189 : subdomain_ids_set,
190 : center_trimming_section_boundary_id,
191 : external_boundary_id);
192 : }
193 0 : catch (MooseException & e)
194 : {
195 0 : if (((std::string)e.what())
196 0 : .compare("The input mesh has degenerate quad element before trimming.") == 0)
197 0 : paramError("input", "The input mesh has degenerate quad element before trimming.");
198 0 : else if (((std::string)e.what())
199 0 : .compare("The new subdomain name already exists in the mesh.") == 0)
200 0 : paramError("tri_elem_subdomain_name_suffix",
201 : "The new subdomain name already exists in the mesh.");
202 0 : }
203 312 : }
204 :
205 : void
206 156 : PolygonMeshTrimmerBase::peripheralTrimmer(
207 : ReplicatedMesh & mesh,
208 : const std::vector<unsigned short> trim_peripheral_region,
209 : const boundary_id_type external_boundary_id,
210 : const boundary_id_type peripheral_trimming_section_boundary_id,
211 : const std::set<subdomain_id_type> subdomain_ids_set)
212 : {
213 156 : const unsigned int num_sides = trim_peripheral_region.size();
214 156 : const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
215 156 : const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
216 :
217 156 : const Real unit_length = getMeshProperty<Real>("input_pitch_meta", _input_name) /
218 240 : (num_sides == 6 ? std::sqrt(3.0) : 2.0);
219 : // Add metadata to input
220 156 : const Real multiplier = ((Real)getMeshProperty<unsigned int>("pattern_size", _input_name) - 1.0) *
221 240 : (num_sides == 6 ? 0.75 : 1.0);
222 156 : const Real ch_length = multiplier * unit_length;
223 312 : setMeshProperty("pattern_pitch_meta", ch_length * 2.0);
224 :
225 : std::vector<std::vector<Real>> bdry_pars;
226 156 : if (num_sides == 6)
227 504 : bdry_pars = {{1.0 / std::sqrt(3.0), 1.0, -ch_length / std::sqrt(3.0) * 2.0},
228 : {-1.0 / std::sqrt(3.0), 1.0, -ch_length / std::sqrt(3.0) * 2.0},
229 : {-1.0, 0.0, -ch_length},
230 : {-1.0 / std::sqrt(3.0), -1.0, -ch_length / std::sqrt(3.0) * 2.0},
231 : {1.0 / std::sqrt(3.0), -1.0, -ch_length / std::sqrt(3.0) * 2.0},
232 504 : {1.0, 0.0, -ch_length}};
233 : else
234 420 : bdry_pars = {{1.0, 0.0, -ch_length},
235 : {0.0, 1.0, -ch_length},
236 : {-1.0, 0.0, -ch_length},
237 420 : {0.0, -1.0, -ch_length}};
238 :
239 924 : for (unsigned int i = 0; i < bdry_pars.size(); i++)
240 768 : if (trim_peripheral_region[i])
241 : try
242 : {
243 517 : MooseMeshXYCuttingUtils::lineRemoverMoveNode(mesh,
244 : bdry_pars[i],
245 : block_id_to_remove,
246 : subdomain_ids_set,
247 : peripheral_trimming_section_boundary_id,
248 : external_boundary_id,
249 517 : std::vector<boundary_id_type>(),
250 : true);
251 : }
252 0 : catch (MooseException & e)
253 : {
254 0 : if (((std::string)e.what())
255 0 : .compare("The input mesh has degenerate quad element before trimming.") == 0)
256 0 : paramError("input", "The input mesh has degenerate quad element before trimming.");
257 0 : else if (((std::string)e.what())
258 0 : .compare("The new subdomain name already exists in the mesh.") == 0)
259 0 : paramError("tri_elem_subdomain_name_suffix",
260 : "The new subdomain name already exists in the mesh.");
261 0 : }
262 468 : }
|