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 "FlexiblePatternGenerator.h"
11 :
12 : // C++ includes
13 : #include <cmath>
14 :
15 : registerMooseObject("ReactorApp", FlexiblePatternGenerator);
16 :
17 : InputParameters
18 722 : FlexiblePatternGenerator::validParams()
19 : {
20 722 : InputParameters params = PolygonMeshGeneratorBase::validParams();
21 :
22 1444 : params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs", "The input MeshGenerators.");
23 1444 : MooseEnum boundary_type("HEXAGON CARTESIAN CIRCLE CUSTOM", "CUSTOM");
24 1444 : params.addParam<MooseEnum>("boundary_type",
25 : boundary_type,
26 : "what type of boundary is used as background for patterning.");
27 1444 : params.addParam<MeshGeneratorName>(
28 : "boundary_mesh",
29 : "The boundary mesh consisting of EDGE2 elements to be used as the 'CUSTOM' boundary.");
30 1444 : params.addRangeCheckedParam<unsigned int>(
31 : "boundary_sectors",
32 : "boundary_sectors>0",
33 : "The number of sectors on each side of the HEXAGON or CARTESIAN boundary mesh or on the "
34 : "circular boundary of the CIRCLE boundary mesh.");
35 1444 : params.addRangeCheckedParam<Real>("boundary_size",
36 : "boundary_size>0",
37 : "The pitch size of the HEXAGON or CARTESIAN boundary mesh; or "
38 : "the diameter of the CIRCLE boundary mesh.");
39 :
40 1444 : params.addParam<std::vector<Point>>(
41 : "extra_positions", {}, "The extra non-patterned positions to set the input MeshGenerators.");
42 1444 : params.addParam<std::vector<unsigned int>>(
43 : "extra_positions_mg_indices",
44 : {},
45 : "the indices of the input mesh generators for the extra position.");
46 :
47 1444 : params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns",
48 : "Hexagonal patterns set.");
49 1444 : params.addRangeCheckedParam<std::vector<Real>>(
50 : "hex_pitches", "hex_pitches>0", "pitch sizes used to generate the hexagonal patterns.");
51 1444 : params.addParam<std::vector<Point>>("hex_origins",
52 : "the origin positions of the hexagonal patterns,");
53 1444 : params.addParam<std::vector<Real>>("hex_rotations",
54 : "the rotation angles of the hexagonal patterns,");
55 :
56 1444 : params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns",
57 : "Rectangular patterns set.");
58 1444 : params.addRangeCheckedParam<std::vector<Real>>(
59 : "rect_pitches_x",
60 : "rect_pitches_x>0",
61 : "pitch sizes in x direction used to generate the rectangular patterns.");
62 1444 : params.addRangeCheckedParam<std::vector<Real>>(
63 : "rect_pitches_y",
64 : "rect_pitches_y>0",
65 : "pitch sizes in y direction used to generate the rectangular patterns.");
66 1444 : params.addParam<std::vector<Point>>("rect_origins",
67 : "the origin positions of the rectangular patterns,");
68 1444 : params.addParam<std::vector<Real>>("rect_rotations",
69 : "the rotation angles of the rectangular patterns.");
70 :
71 1444 : params.addParam<std::vector<std::vector<unsigned int>>>("circular_patterns",
72 : "Circular patterns set.");
73 1444 : params.addRangeCheckedParam<std::vector<Real>>(
74 : "circular_radii", "circular_radii>0", "the radii of the circular patterns.");
75 1444 : params.addParam<std::vector<Point>>("circular_origins",
76 : "the origin positions of the circular patterns,");
77 1444 : params.addParam<std::vector<Real>>(
78 : "circular_rotations",
79 : "the rotation angles of the circular patterns (the azimuthal angle of the first unit mesh).");
80 :
81 : // Parameters directly passed to XYDelaunayMeshGenerator
82 1444 : params.addParam<Real>("desired_area", 0.0, "Desired are for the background area meshing.");
83 1444 : params.addParam<std::string>(
84 : "desired_area_func",
85 722 : std::string(),
86 : "Desired area as a function of x,y; omit to skip non-uniform refinement");
87 :
88 1444 : params.addParam<bool>("use_auto_area_func",
89 1444 : false,
90 : "Use the automatic area function for triangle-meshing in the background.");
91 1444 : params.addParam<Real>(
92 : "auto_area_func_default_size",
93 1444 : 0,
94 : "Background size for automatic area function, or 0 to use non background size");
95 1444 : params.addParam<Real>("auto_area_func_default_size_dist",
96 1444 : -1.0,
97 : "Effective distance of background size for automatic area "
98 : "function, or negative to use non background size");
99 1444 : params.addParam<unsigned int>("auto_area_function_num_points",
100 1444 : 10,
101 : "Maximum number of nearest points used for the inverse distance "
102 : "interpolation algorithm for automatic area function calculation.");
103 2166 : params.addRangeCheckedParam<Real>(
104 : "auto_area_function_power",
105 1444 : 1.0,
106 : "auto_area_function_power>0",
107 : "Polynomial power of the inverse distance interpolation algorithm for automatic area "
108 : "function calculation.");
109 :
110 1444 : params.addParam<bool>("verify_holes", true, "Whether the holes are verified.");
111 1444 : params.addRangeCheckedParam<subdomain_id_type>(
112 : "background_subdomain_id",
113 : "background_subdomain_id>0",
114 : "Subdomain id to set on the background area meshed by Delaunay algorithm.");
115 1444 : params.addParam<SubdomainName>(
116 : "background_subdomain_name",
117 : "Subdomain name to set on the background area meshed by Delaunay algorithm.");
118 1444 : MooseEnum tri_elem_type("TRI3 TRI6 TRI7 DEFAULT", "DEFAULT");
119 1444 : params.addParam<MooseEnum>(
120 : "tri_element_type", tri_elem_type, "Type of the triangular elements to be generated.");
121 :
122 1444 : params.addParam<boundary_id_type>(
123 : "external_boundary_id",
124 : "The boundary id of the external boundary in addition to the default 10000.");
125 1444 : params.addParam<BoundaryName>("external_boundary_name",
126 : "Optional boundary name for the external boundary.");
127 :
128 1444 : params.addParam<bool>("delete_default_external_boundary_from_inputs",
129 1444 : true,
130 : "Whether to delete the default external boundary from the input meshes.");
131 :
132 1444 : params.addParam<ExtraElementIDName>(
133 : "cell_id_name",
134 : "The name of the extra element id to be assigned for each component "
135 : "unit mesh in sequential order.");
136 :
137 1444 : params.addParam<dof_id_type>(
138 : "cell_id_shift",
139 1444 : 0,
140 : "The shift value to be added to the cell id to avoid conflicts with ids in other meshes.");
141 :
142 1444 : params.addParam<ExtraElementIDName>(
143 : "pattern_id_name",
144 : "The name of the extra element id to be assigned based on the ID of "
145 : "the input meshes in sequential order.");
146 :
147 1444 : params.addParam<dof_id_type>(
148 : "pattern_id_shift",
149 1444 : 0,
150 : "The shift value to be added to the pattern id to avoid conflicts with ids in other meshes.");
151 :
152 722 : params.addClassDescription("This FlexiblePatternGenerator object is designed to generate a "
153 : "mesh with a background region with dispersed unit meshes in "
154 : "it and distributed based on a series of flexible patterns.");
155 :
156 1444 : params.addParamNamesToGroup("hex_patterns hex_pitches hex_origins hex_rotations",
157 : "Hexagonal Pattern");
158 1444 : params.addParamNamesToGroup(
159 : "rect_patterns rect_pitches_x rect_pitches_y rect_origins rect_rotations",
160 : "Rectangular Pattern");
161 1444 : params.addParamNamesToGroup(
162 : "circular_patterns circular_radii circular_origins circular_rotations", "Circular Pattern");
163 1444 : params.addParamNamesToGroup("extra_positions extra_positions_mg_indices",
164 : "Extra Positions (Free-Style Patterns)");
165 1444 : params.addParamNamesToGroup("desired_area desired_area_func verify_holes background_subdomain_id "
166 : "background_subdomain_name use_auto_area_func "
167 : "auto_area_func_default_size auto_area_func_default_size_dist "
168 : "auto_area_function_num_points auto_area_function_power",
169 : "Background Area Delaunay");
170 1444 : params.addParamNamesToGroup(
171 : "boundary_type boundary_mesh boundary_sectors boundary_size "
172 : "delete_default_external_boundary_from_inputs external_boundary_id external_boundary_name",
173 : "Boundary");
174 1444 : params.addParamNamesToGroup("cell_id_name cell_id_shift pattern_id_name pattern_id_shift",
175 : "Reporting Id");
176 :
177 722 : return params;
178 722 : }
179 :
180 390 : FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & parameters)
181 : : PolygonMeshGeneratorBase(parameters),
182 390 : _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
183 780 : _boundary_type(getParam<MooseEnum>("boundary_type").template getEnum<BdryType>()),
184 1170 : _boundary_mesh_name(isParamValid("boundary_mesh") ? getParam<MeshGeneratorName>("boundary_mesh")
185 : : MeshGeneratorName()),
186 1530 : _boundary_sectors(isParamValid("boundary_sectors") ? getParam<unsigned int>("boundary_sectors")
187 : : 0),
188 1530 : _boundary_size(isParamValid("boundary_size") ? getParam<Real>("boundary_size") : 0.0),
189 582 : _hex_patterns(
190 390 : isParamValid("hex_patterns")
191 390 : ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns")
192 : : std::vector<std::vector<std::vector<unsigned int>>>()),
193 1266 : _hex_pitches(isParamValid("hex_pitches") ? getParam<std::vector<Real>>("hex_pitches")
194 : : std::vector<Real>()),
195 1185 : _hex_origins(isParamValid("hex_origins")
196 390 : ? getParam<std::vector<Point>>("hex_origins")
197 390 : : std::vector<Point>(_hex_patterns.size(), Point(0.0, 0.0, 0.0))),
198 1181 : _hex_rotations(isParamValid("hex_rotations") ? getParam<std::vector<Real>>("hex_rotations")
199 390 : : std::vector<Real>(_hex_patterns.size(), 0.0)),
200 450 : _rect_patterns(
201 390 : isParamValid("rect_patterns")
202 390 : ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns")
203 : : std::vector<std::vector<std::vector<unsigned int>>>()),
204 1200 : _rect_pitches_x(isParamValid("rect_pitches_x") ? getParam<std::vector<Real>>("rect_pitches_x")
205 : : std::vector<Real>()),
206 1200 : _rect_pitches_y(isParamValid("rect_pitches_y") ? getParam<std::vector<Real>>("rect_pitches_y")
207 : : std::vector<Real>()),
208 1172 : _rect_origins(isParamValid("rect_origins")
209 390 : ? getParam<std::vector<Point>>("rect_origins")
210 390 : : std::vector<Point>(_rect_patterns.size(), Point(0.0, 0.0, 0.0))),
211 1172 : _rect_rotations(isParamValid("rect_rotations") ? getParam<std::vector<Real>>("rect_rotations")
212 390 : : std::vector<Real>(_rect_patterns.size(), 0.0)),
213 828 : _circ_patterns(isParamValid("circular_patterns")
214 390 : ? getParam<std::vector<std::vector<unsigned int>>>("circular_patterns")
215 : : std::vector<std::vector<unsigned int>>()),
216 1194 : _circ_radii(isParamValid("circular_radii") ? getParam<std::vector<Real>>("circular_radii")
217 : : std::vector<Real>()),
218 1172 : _circ_origins(isParamValid("circular_origins")
219 390 : ? getParam<std::vector<Point>>("circular_origins")
220 390 : : std::vector<Point>(_circ_patterns.size(), Point(0.0, 0.0, 0.0))),
221 802 : _circ_rotations(isParamValid("circular_rotations")
222 390 : ? getParam<std::vector<Real>>("circular_rotations")
223 390 : : std::vector<Real>(_circ_patterns.size(), 0.0)),
224 390 : _background_subdomain_id(isParamValid("background_subdomain_id")
225 892 : ? getParam<subdomain_id_type>("background_subdomain_id")
226 : : Moose::INVALID_BLOCK_ID),
227 1024 : _background_subdomain_name(isParamValid("background_subdomain_name")
228 390 : ? getParam<SubdomainName>("background_subdomain_name")
229 : : SubdomainName()),
230 390 : _delete_default_external_boundary_from_inputs(
231 780 : getParam<bool>("delete_default_external_boundary_from_inputs")),
232 1170 : _cell_id_name(isParamValid("cell_id_name") ? getParam<ExtraElementIDName>("cell_id_name")
233 : : ExtraElementIDName()),
234 780 : _cell_id_shift(getParam<dof_id_type>("cell_id_shift")),
235 791 : _pattern_id_name(isParamValid("pattern_id_name")
236 390 : ? getParam<ExtraElementIDName>("pattern_id_name")
237 : : ExtraElementIDName()),
238 780 : _pattern_id_shift(getParam<dof_id_type>("pattern_id_shift")),
239 390 : _external_boundary_id(isParamValid("external_boundary_id")
240 792 : ? getParam<boundary_id_type>("external_boundary_id")
241 : : (boundary_id_type)OUTER_SIDESET_ID),
242 972 : _external_boundary_name(isParamValid("external_boundary_name")
243 390 : ? getParam<BoundaryName>("external_boundary_name")
244 390 : : BoundaryName())
245 :
246 : {
247 780 : declareMeshesForSub("inputs");
248 :
249 1152 : if (_cell_id_name.empty() && isParamSetByUser("cell_id_name"))
250 2 : paramError("cell_id_name", "This parameter must be non empty if provided.");
251 1146 : if (_cell_id_name.empty() && isParamSetByUser("cell_id_shift"))
252 2 : paramError("cell_id_name", "This parameter must be provided if cell_id_shift is set.");
253 1140 : if (_pattern_id_name.empty() && isParamSetByUser("pattern_id_name"))
254 2 : paramError("pattern_id_name", "This parameter must be non empty if provided.");
255 1134 : if (_pattern_id_name.empty() && isParamSetByUser("pattern_id_shift"))
256 2 : paramError("pattern_id_name", "This parameter must be provided if pattern_id_shift is set.");
257 :
258 764 : const std::vector<Point> extra_positions(getParam<std::vector<Point>>("extra_positions"));
259 : const std::vector<unsigned int> extra_positions_mg_indices(
260 1146 : getParam<std::vector<unsigned int>>("extra_positions_mg_indices"));
261 382 : if (extra_positions.size() != extra_positions_mg_indices.size())
262 2 : paramError("extra_positions_mg_indices",
263 : "This parameter must have the same size as extra_positions.");
264 380 : std::vector<unsigned int> input_usage_count(_input_names.size(), 0);
265 676 : for (unsigned int i = 0; i < extra_positions.size(); i++)
266 : {
267 298 : if (extra_positions_mg_indices[i] >= _input_names.size())
268 2 : paramError("extra_positions_mg_indices",
269 : "the index used for extra positions must be available in 'inputs'.");
270 296 : input_usage_count[extra_positions_mg_indices[i]]++;
271 296 : _positions.push_back(std::make_pair(extra_positions[i], extra_positions_mg_indices[i]));
272 : }
273 :
274 378 : if (_background_subdomain_name.size() && _background_subdomain_id == Moose::INVALID_BLOCK_ID)
275 2 : paramError("background_subdomain_id",
276 : "This parameter must be provided if background_subdomain_name is provided.");
277 :
278 376 : if (_boundary_type == BdryType::CUSTOM)
279 : {
280 15 : if (_boundary_mesh_name.empty())
281 2 : paramError("boundary_mesh", "boundary_mesh must be specified for CUSTOM boundary_type.");
282 13 : declareMeshForSub("boundary_mesh");
283 13 : if (_boundary_sectors > 0)
284 2 : paramError("boundary_sectors",
285 : "this parameter should not be provided for CUSTOM boundary_type.");
286 11 : if (_boundary_size > 0.0)
287 2 : paramError("boundary_size",
288 : "this parameter should not be provided for CUSTOM boundary_type.");
289 : }
290 : else
291 : {
292 361 : if (!_boundary_mesh_name.empty())
293 2 : paramError("boundary_mesh",
294 : "this parameter should not be provided for non-CUSTOM "
295 : "boundary_type.");
296 359 : if (_boundary_sectors == 0)
297 2 : paramError("boundary_sectors",
298 : "this parameter must be provided for non-CUSTOM "
299 : "boundary_type.");
300 357 : if (_boundary_size == 0.0)
301 2 : paramError("boundary_size", "this parameter must be provided for non-CUSTOM boundary_type.");
302 :
303 355 : if (_boundary_type == BdryType::HEXAGON)
304 : {
305 287 : _boundary_mesh_name = name() + "_hexagon_boundary";
306 : // create a submeshgenerator for the hexagon boundary
307 287 : auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
308 287 : params.set<bool>("loop") = true;
309 287 : params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
310 287 : params.set<std::vector<Point>>("points") = {
311 287 : Point(0.0, _boundary_size / std::sqrt(3.0), 0.0),
312 : Point(_boundary_size / 2.0, _boundary_size / std::sqrt(3.0) / 2.0, 0.0),
313 : Point(_boundary_size / 2.0, -_boundary_size / std::sqrt(3.0) / 2.0, 0.0),
314 : Point(0.0, -_boundary_size / std::sqrt(3.0), 0.0),
315 : Point(-_boundary_size / 2.0, -_boundary_size / std::sqrt(3.0) / 2.0, 0.0),
316 574 : Point(-_boundary_size / 2.0, _boundary_size / std::sqrt(3.0) / 2.0, 0.0)};
317 :
318 574 : addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
319 287 : }
320 68 : else if (_boundary_type == BdryType::CARTESIAN)
321 : {
322 59 : _boundary_mesh_name = name() + "_cartesian_boundary";
323 : // create a submeshgenerator for the cartesian boundary
324 59 : auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
325 59 : params.set<bool>("loop") = true;
326 59 : params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
327 59 : params.set<std::vector<Point>>("points") = {
328 59 : Point(_boundary_size / 2.0, _boundary_size / 2.0, 0.0),
329 : Point(_boundary_size / 2.0, -_boundary_size / 2.0, 0.0),
330 : Point(-_boundary_size / 2.0, -_boundary_size / 2.0, 0.0),
331 118 : Point(-_boundary_size / 2.0, _boundary_size / 2.0, 0.0)};
332 :
333 118 : addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
334 59 : }
335 : else
336 : {
337 9 : _boundary_mesh_name = name() + "_circle_boundary";
338 : // create a submeshgenerator for the circle boundary
339 : // As we are inducing polygonization anyway, PolyLineMeshGenerator is used
340 9 : auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
341 9 : params.set<bool>("loop") = true;
342 9 : params.set<unsigned int>("num_edges_between_points") = 1;
343 : // We enforce radius correction here for area preservation
344 9 : const Real corr_factor = std::sqrt(2 * M_PI / (Real)_boundary_sectors /
345 9 : std::sin(2 * M_PI / (Real)_boundary_sectors));
346 : std::vector<Point> circular_points;
347 333 : for (unsigned int i = 0; i < _boundary_sectors; i++)
348 : {
349 324 : const Real angle = 2.0 * M_PI * (Real)i / (Real)_boundary_sectors;
350 324 : circular_points.push_back(Point(_boundary_size * corr_factor * std::cos(angle) / 2.0,
351 324 : _boundary_size * corr_factor * std::sin(angle) / 2.0,
352 : 0.0));
353 : }
354 9 : params.set<std::vector<Point>>("points") = circular_points;
355 :
356 18 : addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
357 9 : }
358 : // Set metadata of an assembly mesh
359 355 : declareMeshProperty("pattern_pitch_meta", _boundary_size);
360 710 : declareMeshProperty<bool>("is_control_drum_meta", false);
361 : }
362 :
363 : // Hexagonal Pattern
364 364 : if (_hex_pitches.size() != _hex_patterns.size())
365 2 : paramError("hex_pitches",
366 : "The length of this parameter must be the same as that of hex_patterns.");
367 362 : if (_hex_origins.size() != _hex_patterns.size())
368 2 : paramError(
369 : "hex_origins",
370 : "if provided, the length of this parameter must be the same as that of hex_patterns.");
371 360 : if (_hex_rotations.size() != _hex_patterns.size())
372 2 : paramError(
373 : "hex_rotations",
374 : "if provided, the length of this parameter must be the same as that of hex_patterns.");
375 : std::vector<Point> hex_positions;
376 358 : if (!_hex_patterns.empty())
377 : {
378 : unsigned int hex_index = 0;
379 157 : for (const auto & hex_pattern : _hex_patterns)
380 : {
381 87 : const unsigned int n_hex_pattern_layers = hex_pattern.size();
382 87 : if (n_hex_pattern_layers % 2 == 0)
383 2 : paramError("hex_patterns",
384 : "The length (layer number) of each element of this parameter must be odd to "
385 : "ensure hexagonal shapes.");
386 85 : if (n_hex_pattern_layers == 1)
387 2 : paramError("hex_patterns",
388 : "The length (layer number) of each element of this parameter must be larger "
389 : "than unity.");
390 247 : for (unsigned int i = 0; i <= n_hex_pattern_layers / 2; i++)
391 : {
392 166 : if (hex_pattern[i].size() != n_hex_pattern_layers / 2 + i + 1 ||
393 164 : hex_pattern[n_hex_pattern_layers - 1 - i].size() != n_hex_pattern_layers / 2 + i + 1)
394 2 : paramError("hex_patterns",
395 : "The two-dimentional array element of this parameter must have a correct "
396 : "hexagonal shape.");
397 : }
398 :
399 81 : const Point unit_shift_1 = Point(_hex_pitches[hex_index], 0.0, 0.0);
400 : const Point unit_shift_2 =
401 81 : Point(_hex_pitches[hex_index] / 2.0, _hex_pitches[hex_index] / 2.0 * std::sqrt(3.0), 0.0);
402 :
403 324 : for (unsigned int i = 0; i < hex_pattern.size(); i++)
404 : {
405 243 : const Real param_2 = ((Real)hex_pattern.size() - 1.0) / 2.0 - (Real)i;
406 : const Real param_1_init = -((Real)hex_pattern.size() - 1.0) / 2.0 -
407 243 : ((i <= (hex_pattern.size() - 1) / 2)
408 243 : ? 0.0
409 81 : : (((Real)(hex_pattern.size() - 1) / 2) - (Real)i));
410 810 : for (unsigned int j = 0; j < hex_pattern[i].size(); j++)
411 : {
412 : // Any numbers exceeding the size of inputs are used as dummy units
413 567 : if (hex_pattern[i][j] < _input_names.size())
414 : {
415 549 : input_usage_count[hex_pattern[i][j]]++;
416 549 : Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
417 549 : nodeCoordRotate(pt_buffer(0), pt_buffer(1), _hex_rotations[hex_index]);
418 549 : _positions.push_back(
419 : std::make_pair(pt_buffer + _hex_origins[hex_index], hex_pattern[i][j]));
420 : }
421 : }
422 : }
423 81 : hex_index++;
424 : }
425 : }
426 :
427 : // Rectangular Pattern
428 352 : if (_rect_pitches_x.size() != _rect_patterns.size())
429 2 : paramError("rect_pitches_x",
430 : "The length of this parameter must be the same as that of rect_patterns.");
431 350 : if (_rect_pitches_y.size() != _rect_patterns.size())
432 2 : paramError("rect_pitches_y",
433 : "The length of this parameter must be the same as that of rect_patterns.");
434 348 : if (_rect_origins.size() != _rect_patterns.size())
435 2 : paramError(
436 : "rect_origins",
437 : "if provided, the length of this parameter must be the same as that of rect_patterns.");
438 346 : if (_rect_rotations.size() != _rect_patterns.size())
439 2 : paramError(
440 : "rect_rotations",
441 : "if provided, the length of this parameter must be the same as that of rect_patterns.");
442 344 : if (!_rect_patterns.empty())
443 : {
444 : unsigned int rect_index = 0;
445 40 : for (const auto & rect_pattern : _rect_patterns)
446 : {
447 : std::set<unsigned int> rect_pattern_elem_size;
448 77 : for (const auto & rect_pattern_elem : rect_pattern)
449 : {
450 57 : if (rect_pattern_elem.empty())
451 2 : paramError("rect_patterns", "Each row of the element pattern must not be empty.");
452 55 : rect_pattern_elem_size.emplace(rect_pattern_elem.size());
453 : }
454 20 : if (rect_pattern_elem_size.size() > 1)
455 2 : paramError("rect_patterns",
456 : "The two-dimensional array element of this parameter must have a correct "
457 : "rectangular shape.");
458 :
459 18 : const Point unit_shift_1 = Point(_rect_pitches_x[rect_index], 0.0, 0.0);
460 18 : const Point unit_shift_2 = Point(0.0, _rect_pitches_y[rect_index], 0.0);
461 :
462 63 : for (unsigned int i = 0; i < rect_pattern.size(); i++)
463 : {
464 45 : const Real param_2 = ((Real)rect_pattern.size() - 1.0) / 2.0 - (Real)i;
465 45 : const Real param_1_init = -((Real)rect_pattern[i].size() - 1.0) / 2.0;
466 162 : for (unsigned int j = 0; j < rect_pattern[i].size(); j++)
467 : {
468 117 : if (rect_pattern[i][j] < _input_names.size())
469 : {
470 117 : input_usage_count[rect_pattern[i][j]]++;
471 117 : Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
472 117 : nodeCoordRotate(pt_buffer(0), pt_buffer(1), _rect_rotations[rect_index]);
473 117 : _positions.push_back(
474 : std::make_pair(pt_buffer + _rect_origins[rect_index], rect_pattern[i][j]));
475 : }
476 : }
477 : }
478 18 : rect_index++;
479 : }
480 : }
481 :
482 : // Circular Pattern
483 340 : if (_circ_radii.size() != _circ_patterns.size())
484 2 : paramError("circular_radii",
485 : "The length of this parameter must be the same as that of circular_patterns.");
486 338 : if (_circ_origins.size() != _circ_patterns.size())
487 2 : paramError(
488 : "circular_origins",
489 : "if provided, the length of this parameter must be the same as that of circular_patterns.");
490 336 : if (_circ_rotations.size() != _circ_patterns.size())
491 2 : paramError(
492 : "circular_rotations",
493 : "if provided, the length of this parameter must be the same as that of circular_patterns.");
494 334 : if (!_circ_patterns.empty())
495 : {
496 : unsigned int circ_index = 0;
497 45 : for (const auto & circ_pattern : _circ_patterns)
498 : {
499 27 : const Real angle_step = 2.0 * M_PI / (Real)circ_pattern.size();
500 :
501 243 : for (unsigned int i = 0; i < circ_pattern.size(); i++)
502 : {
503 216 : if (circ_pattern[i] < _input_names.size())
504 : {
505 216 : input_usage_count[circ_pattern[i]]++;
506 216 : Point pt_buffer = Point(_circ_radii[circ_index] * std::cos((Real)i * angle_step),
507 216 : _circ_radii[circ_index] * std::sin((Real)i * angle_step),
508 216 : 0.0);
509 216 : nodeCoordRotate(pt_buffer(0), pt_buffer(1), _circ_rotations[circ_index]);
510 216 : _positions.push_back(
511 : std::make_pair(pt_buffer + _circ_origins[circ_index], circ_pattern[i]));
512 : }
513 : }
514 27 : circ_index++;
515 : }
516 : }
517 :
518 334 : if (std::count(input_usage_count.begin(), input_usage_count.end(), 0))
519 2 : paramError("inputs", "All the input mesh generator names are not used.");
520 :
521 332 : if (_delete_default_external_boundary_from_inputs)
522 : {
523 678 : for (const auto & input_name : _input_names)
524 : {
525 346 : auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
526 346 : params.set<MeshGeneratorName>("input") = input_name;
527 1384 : params.set<std::vector<BoundaryName>>("boundary_names") = {std::to_string(OUTER_SIDESET_ID)};
528 :
529 1038 : addMeshSubgenerator("BoundaryDeletionGenerator",
530 346 : input_name +
531 692 : static_cast<MeshGeneratorName>("_" + name() + "_del_ext_bdry"),
532 : params);
533 346 : }
534 : }
535 :
536 : std::vector<MeshGeneratorName> patterned_pin_mg_series;
537 1482 : for (unsigned int i = 0; i < _positions.size(); i++)
538 : {
539 1150 : auto params = _app.getFactory().getValidParams("TransformGenerator");
540 2300 : params.set<MeshGeneratorName>("input") =
541 1150 : _input_names[_positions[i].second] +
542 1150 : static_cast<MeshGeneratorName>(
543 2300 : _delete_default_external_boundary_from_inputs ? ("_" + name() + "_del_ext_bdry") : "");
544 2300 : params.set<MooseEnum>("transform") = 1;
545 1150 : params.set<RealVectorValue>("vector_value") = _positions[i].first;
546 :
547 2300 : patterned_pin_mg_series.push_back(name() + "_pos_" + std::to_string(i));
548 :
549 2300 : addMeshSubgenerator("TransformGenerator", patterned_pin_mg_series.back(), params);
550 :
551 1150 : if (_cell_id_name.size())
552 : {
553 54 : auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
554 27 : params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
555 54 : params.set<std::string>("expression") = std::to_string(i + _cell_id_shift);
556 27 : params.set<std::string>("extra_elem_integer_name") = _cell_id_name;
557 :
558 54 : patterned_pin_mg_series.back() = name() + "_ceeid_" + std::to_string(i);
559 54 : addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
560 27 : }
561 1150 : if (_pattern_id_name.size())
562 : {
563 54 : auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
564 54 : params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
565 54 : params.set<std::string>("expression") =
566 54 : std::to_string(_positions[i].second + _pattern_id_shift);
567 27 : params.set<std::string>("extra_elem_integer_name") = _pattern_id_name;
568 :
569 54 : patterned_pin_mg_series.back() = name() + "_peeid_" + std::to_string(i);
570 54 : addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
571 27 : }
572 1150 : }
573 :
574 332 : auto params = _app.getFactory().getValidParams("XYDelaunayGenerator");
575 332 : params.set<MeshGeneratorName>("boundary") = _boundary_mesh_name;
576 332 : params.set<std::vector<MeshGeneratorName>>("holes") = patterned_pin_mg_series;
577 332 : params.set<bool>("refine_boundary") = false;
578 : // XYDelaunay's intrinsic checks
579 664 : params.set<bool>("verify_holes") = getParam<bool>("verify_holes");
580 664 : params.set<std::vector<bool>>("stitch_holes") =
581 664 : std::vector<bool>(patterned_pin_mg_series.size(), true);
582 664 : params.set<std::vector<bool>>("refine_holes") =
583 664 : std::vector<bool>(patterned_pin_mg_series.size(), false);
584 664 : params.set<Real>("desired_area") = getParam<Real>("desired_area");
585 996 : params.set<std::string>("desired_area_func") = getParam<std::string>("desired_area_func");
586 664 : params.set<bool>("use_auto_area_func") = getParam<bool>("use_auto_area_func");
587 664 : if (isParamSetByUser("auto_area_func_default_size"))
588 0 : params.set<Real>("auto_area_func_default_size") = getParam<Real>("auto_area_func_default_size");
589 664 : if (isParamSetByUser("auto_area_func_default_size_dist"))
590 0 : params.set<Real>("auto_area_func_default_size_dist") =
591 0 : getParam<Real>("auto_area_func_default_size_dist");
592 664 : if (isParamSetByUser("auto_area_function_num_points"))
593 0 : params.set<unsigned int>("auto_area_function_num_points") =
594 0 : getParam<unsigned int>("auto_area_function_num_points");
595 664 : if (isParamSetByUser("auto_area_function_power"))
596 0 : params.set<Real>("auto_area_function_power") = getParam<Real>("auto_area_function_power");
597 996 : params.set<BoundaryName>("output_boundary") = std::to_string(OUTER_SIDESET_ID);
598 996 : params.set<MooseEnum>("tri_element_type") = getParam<MooseEnum>("tri_element_type");
599 664 : addMeshSubgenerator("XYDelaunayGenerator", name() + "_pattern", params);
600 :
601 332 : MeshGeneratorName final_mg_name(name() + "_pattern");
602 332 : if (_background_subdomain_id != Moose::INVALID_BLOCK_ID)
603 : {
604 474 : auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
605 948 : params.set<MeshGeneratorName>("input") = name() + "_pattern";
606 711 : params.set<std::vector<SubdomainName>>("old_block") = {"0"};
607 474 : params.set<std::vector<SubdomainName>>("new_block") = {
608 1185 : std::to_string(_background_subdomain_id)};
609 474 : addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_1", params);
610 237 : if (_background_subdomain_name.size())
611 : {
612 456 : auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
613 684 : params.set<MeshGeneratorName>("input") = name() + "_back_rename_1";
614 456 : params.set<std::vector<SubdomainName>>("old_block") = {
615 1368 : std::to_string(_background_subdomain_id)};
616 684 : params.set<std::vector<SubdomainName>>("new_block") = {_background_subdomain_name};
617 456 : addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_2", params);
618 228 : final_mg_name = name() + "_back_rename_2";
619 228 : }
620 : else
621 18 : final_mg_name = name() + "_back_rename_1";
622 237 : }
623 :
624 332 : _build_mesh = &getMeshByName(final_mg_name);
625 332 : }
626 :
627 : std::unique_ptr<MeshBase>
628 332 : FlexiblePatternGenerator::generate()
629 : {
630 332 : if (_external_boundary_id != OUTER_SIDESET_ID)
631 201 : MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
632 332 : if (!_external_boundary_name.empty())
633 : {
634 : // Check if _external_boundary_name has been assigned to another boundary id
635 : const auto external_id_by_name =
636 192 : (*_build_mesh)->get_boundary_info().get_id_by_name(_external_boundary_name);
637 192 : if ((external_id_by_name != Moose::INVALID_BOUNDARY_ID) &&
638 0 : (external_id_by_name != _external_boundary_id))
639 0 : paramError("external_boundary_name",
640 0 : "External boundary name " + _external_boundary_name +
641 0 : " is already associated with id " + std::to_string(external_id_by_name) +
642 0 : ", which differs from the user-specified external_boundary_id " +
643 0 : std::to_string(_external_boundary_id));
644 :
645 192 : (*_build_mesh)->get_boundary_info().sideset_name(_external_boundary_id) =
646 192 : _external_boundary_name;
647 192 : (*_build_mesh)->get_boundary_info().nodeset_name(_external_boundary_id) =
648 : _external_boundary_name;
649 : }
650 332 : (*_build_mesh)->find_neighbors();
651 332 : (*_build_mesh)->set_isnt_prepared();
652 332 : return std::move(*_build_mesh);
653 : }
|