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 662 : FlexiblePatternGenerator::validParams()
19 : {
20 662 : InputParameters params = PolygonMeshGeneratorBase::validParams();
21 :
22 1324 : params.addRequiredParam<std::vector<MeshGeneratorName>>("inputs", "The input MeshGenerators.");
23 1324 : MooseEnum boundary_type("HEXAGON CARTESIAN CIRCLE CUSTOM", "CUSTOM");
24 1324 : params.addParam<MooseEnum>("boundary_type",
25 : boundary_type,
26 : "what type of boundary is used as background for patterning.");
27 1324 : params.addParam<MeshGeneratorName>(
28 : "boundary_mesh",
29 : "The boundary mesh consisting of EDGE2 elements to be used as the 'CUSTOM' boundary.");
30 1324 : 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 1324 : 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 1324 : params.addParam<std::vector<Point>>(
41 : "extra_positions", {}, "The extra non-patterned positions to set the input MeshGenerators.");
42 1324 : 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 1324 : params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns",
48 : "Hexagonal patterns set.");
49 1324 : params.addRangeCheckedParam<std::vector<Real>>(
50 : "hex_pitches", "hex_pitches>0", "pitch sizes used to generate the hexagonal patterns.");
51 1324 : params.addParam<std::vector<Point>>("hex_origins",
52 : "the origin positions of the hexagonal patterns,");
53 1324 : params.addParam<std::vector<Real>>("hex_rotations",
54 : "the rotation angles of the hexagonal patterns,");
55 :
56 1324 : params.addParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns",
57 : "Rectangular patterns set.");
58 1324 : 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 1324 : 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 1324 : params.addParam<std::vector<Point>>("rect_origins",
67 : "the origin positions of the rectangular patterns,");
68 1324 : params.addParam<std::vector<Real>>("rect_rotations",
69 : "the rotation angles of the rectangular patterns.");
70 :
71 1324 : params.addParam<std::vector<std::vector<unsigned int>>>("circular_patterns",
72 : "Circular patterns set.");
73 1324 : params.addRangeCheckedParam<std::vector<Real>>(
74 : "circular_radii", "circular_radii>0", "the radii of the circular patterns.");
75 1324 : params.addParam<std::vector<Point>>("circular_origins",
76 : "the origin positions of the circular patterns,");
77 1324 : 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 1324 : params.addParam<Real>("desired_area", 0.0, "Desired are for the background area meshing.");
83 1324 : params.addParam<std::string>(
84 : "desired_area_func",
85 662 : std::string(),
86 : "Desired area as a function of x,y; omit to skip non-uniform refinement");
87 :
88 1324 : params.addParam<bool>("use_auto_area_func",
89 1324 : false,
90 : "Use the automatic area function for triangle-meshing in the background.");
91 1324 : params.addParam<Real>(
92 : "auto_area_func_default_size",
93 1324 : 0,
94 : "Background size for automatic area function, or 0 to use non background size");
95 1324 : params.addParam<Real>("auto_area_func_default_size_dist",
96 1324 : -1.0,
97 : "Effective distance of background size for automatic area "
98 : "function, or negative to use non background size");
99 1324 : params.addParam<unsigned int>("auto_area_function_num_points",
100 1324 : 10,
101 : "Maximum number of nearest points used for the inverse distance "
102 : "interpolation algorithm for automatic area function calculation.");
103 1986 : params.addRangeCheckedParam<Real>(
104 : "auto_area_function_power",
105 1324 : 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 1324 : params.addParam<bool>("verify_holes", true, "Whether the holes are verified.");
111 1324 : 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 1324 : params.addParam<SubdomainName>(
116 : "background_subdomain_name",
117 : "Subdomain name to set on the background area meshed by Delaunay algorithm.");
118 1324 : MooseEnum tri_elem_type("TRI3 TRI6 TRI7 DEFAULT", "DEFAULT");
119 1324 : params.addParam<MooseEnum>(
120 : "tri_element_type", tri_elem_type, "Type of the triangular elements to be generated.");
121 :
122 1324 : params.addParam<boundary_id_type>(
123 : "external_boundary_id",
124 : "The boundary id of the external boundary in addition to the default 10000.");
125 1324 : params.addParam<BoundaryName>("external_boundary_name",
126 : "Optional boundary name for the external boundary.");
127 :
128 1324 : params.addParam<bool>("delete_default_external_boundary_from_inputs",
129 1324 : true,
130 : "Whether to delete the default external boundary from the input meshes.");
131 :
132 1324 : 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 1324 : params.addParam<dof_id_type>(
138 : "cell_id_shift",
139 1324 : 0,
140 : "The shift value to be added to the cell id to avoid conflicts with ids in other meshes.");
141 :
142 1324 : 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 1324 : params.addParam<dof_id_type>(
148 : "pattern_id_shift",
149 1324 : 0,
150 : "The shift value to be added to the pattern id to avoid conflicts with ids in other meshes.");
151 :
152 662 : 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 1324 : params.addParamNamesToGroup("hex_patterns hex_pitches hex_origins hex_rotations",
157 : "Hexagonal Pattern");
158 1324 : params.addParamNamesToGroup(
159 : "rect_patterns rect_pitches_x rect_pitches_y rect_origins rect_rotations",
160 : "Rectangular Pattern");
161 1324 : params.addParamNamesToGroup(
162 : "circular_patterns circular_radii circular_origins circular_rotations", "Circular Pattern");
163 1324 : params.addParamNamesToGroup("extra_positions extra_positions_mg_indices",
164 : "Extra Positions (Free-Style Patterns)");
165 1324 : 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 1324 : 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 1324 : params.addParamNamesToGroup("cell_id_name cell_id_shift pattern_id_name pattern_id_shift",
175 : "Reporting Id");
176 :
177 662 : return params;
178 662 : }
179 :
180 360 : FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & parameters)
181 : : PolygonMeshGeneratorBase(parameters),
182 360 : _input_names(getParam<std::vector<MeshGeneratorName>>("inputs")),
183 720 : _boundary_type(getParam<MooseEnum>("boundary_type").template getEnum<BdryType>()),
184 1080 : _boundary_mesh_name(isParamValid("boundary_mesh") ? getParam<MeshGeneratorName>("boundary_mesh")
185 : : MeshGeneratorName()),
186 1414 : _boundary_sectors(isParamValid("boundary_sectors") ? getParam<unsigned int>("boundary_sectors")
187 : : 0),
188 1414 : _boundary_size(isParamValid("boundary_size") ? getParam<Real>("boundary_size") : 0.0),
189 524 : _hex_patterns(
190 360 : isParamValid("hex_patterns")
191 360 : ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("hex_patterns")
192 : : std::vector<std::vector<std::vector<unsigned int>>>()),
193 1162 : _hex_pitches(isParamValid("hex_pitches") ? getParam<std::vector<Real>>("hex_pitches")
194 : : std::vector<Real>()),
195 1093 : _hex_origins(isParamValid("hex_origins")
196 360 : ? getParam<std::vector<Point>>("hex_origins")
197 360 : : std::vector<Point>(_hex_patterns.size(), Point(0.0, 0.0, 0.0))),
198 1089 : _hex_rotations(isParamValid("hex_rotations") ? getParam<std::vector<Real>>("hex_rotations")
199 360 : : std::vector<Real>(_hex_patterns.size(), 0.0)),
200 412 : _rect_patterns(
201 360 : isParamValid("rect_patterns")
202 360 : ? getParam<std::vector<std::vector<std::vector<unsigned int>>>>("rect_patterns")
203 : : std::vector<std::vector<std::vector<unsigned int>>>()),
204 1106 : _rect_pitches_x(isParamValid("rect_pitches_x") ? getParam<std::vector<Real>>("rect_pitches_x")
205 : : std::vector<Real>()),
206 1106 : _rect_pitches_y(isParamValid("rect_pitches_y") ? getParam<std::vector<Real>>("rect_pitches_y")
207 : : std::vector<Real>()),
208 1082 : _rect_origins(isParamValid("rect_origins")
209 360 : ? getParam<std::vector<Point>>("rect_origins")
210 360 : : std::vector<Point>(_rect_patterns.size(), Point(0.0, 0.0, 0.0))),
211 1082 : _rect_rotations(isParamValid("rect_rotations") ? getParam<std::vector<Real>>("rect_rotations")
212 360 : : std::vector<Real>(_rect_patterns.size(), 0.0)),
213 760 : _circ_patterns(isParamValid("circular_patterns")
214 360 : ? getParam<std::vector<std::vector<unsigned int>>>("circular_patterns")
215 : : std::vector<std::vector<unsigned int>>()),
216 1100 : _circ_radii(isParamValid("circular_radii") ? getParam<std::vector<Real>>("circular_radii")
217 : : std::vector<Real>()),
218 1082 : _circ_origins(isParamValid("circular_origins")
219 360 : ? getParam<std::vector<Point>>("circular_origins")
220 360 : : std::vector<Point>(_circ_patterns.size(), Point(0.0, 0.0, 0.0))),
221 738 : _circ_rotations(isParamValid("circular_rotations")
222 360 : ? getParam<std::vector<Real>>("circular_rotations")
223 360 : : std::vector<Real>(_circ_patterns.size(), 0.0)),
224 360 : _background_subdomain_id(isParamValid("background_subdomain_id")
225 842 : ? getParam<subdomain_id_type>("background_subdomain_id")
226 : : Moose::INVALID_BLOCK_ID),
227 956 : _background_subdomain_name(isParamValid("background_subdomain_name")
228 360 : ? getParam<SubdomainName>("background_subdomain_name")
229 : : SubdomainName()),
230 360 : _delete_default_external_boundary_from_inputs(
231 720 : getParam<bool>("delete_default_external_boundary_from_inputs")),
232 1080 : _cell_id_name(isParamValid("cell_id_name") ? getParam<ExtraElementIDName>("cell_id_name")
233 : : ExtraElementIDName()),
234 720 : _cell_id_shift(getParam<dof_id_type>("cell_id_shift")),
235 729 : _pattern_id_name(isParamValid("pattern_id_name")
236 360 : ? getParam<ExtraElementIDName>("pattern_id_name")
237 : : ExtraElementIDName()),
238 720 : _pattern_id_shift(getParam<dof_id_type>("pattern_id_shift")),
239 360 : _external_boundary_id(isParamValid("external_boundary_id")
240 758 : ? getParam<boundary_id_type>("external_boundary_id")
241 : : (boundary_id_type)OUTER_SIDESET_ID),
242 912 : _external_boundary_name(isParamValid("external_boundary_name")
243 360 : ? getParam<BoundaryName>("external_boundary_name")
244 360 : : BoundaryName())
245 :
246 : {
247 720 : declareMeshesForSub("inputs");
248 :
249 1066 : if (_cell_id_name.empty() && isParamSetByUser("cell_id_name"))
250 2 : paramError("cell_id_name", "This parameter must be non empty if provided.");
251 1060 : 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 1054 : if (_pattern_id_name.empty() && isParamSetByUser("pattern_id_name"))
254 2 : paramError("pattern_id_name", "This parameter must be non empty if provided.");
255 1048 : 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 704 : const std::vector<Point> extra_positions(getParam<std::vector<Point>>("extra_positions"));
259 : const std::vector<unsigned int> extra_positions_mg_indices(
260 1056 : getParam<std::vector<unsigned int>>("extra_positions_mg_indices"));
261 352 : 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 350 : std::vector<unsigned int> input_usage_count(_input_names.size(), 0);
265 614 : for (unsigned int i = 0; i < extra_positions.size(); i++)
266 : {
267 266 : 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 264 : input_usage_count[extra_positions_mg_indices[i]]++;
271 264 : _positions.push_back(std::make_pair(extra_positions[i], extra_positions_mg_indices[i]));
272 : }
273 :
274 348 : 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 346 : if (_boundary_type == BdryType::CUSTOM)
279 : {
280 13 : if (_boundary_mesh_name.empty())
281 2 : paramError("boundary_mesh", "boundary_mesh must be specified for CUSTOM boundary_type.");
282 11 : declareMeshForSub("boundary_mesh");
283 11 : if (_boundary_sectors > 0)
284 2 : paramError("boundary_sectors",
285 : "this parameter should not be provided for CUSTOM boundary_type.");
286 9 : 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 333 : if (!_boundary_mesh_name.empty())
293 2 : paramError("boundary_mesh",
294 : "this parameter should not be provided for non-CUSTOM "
295 : "boundary_type.");
296 331 : if (_boundary_sectors == 0)
297 2 : paramError("boundary_sectors",
298 : "this parameter must be provided for non-CUSTOM "
299 : "boundary_type.");
300 329 : if (_boundary_size == 0.0)
301 2 : paramError("boundary_size", "this parameter must be provided for non-CUSTOM boundary_type.");
302 :
303 327 : if (_boundary_type == BdryType::HEXAGON)
304 : {
305 263 : _boundary_mesh_name = name() + "_hexagon_boundary";
306 : // create a submeshgenerator for the hexagon boundary
307 263 : auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
308 263 : params.set<bool>("loop") = true;
309 263 : params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
310 263 : params.set<std::vector<Point>>("points") = {
311 263 : 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 526 : Point(-_boundary_size / 2.0, _boundary_size / std::sqrt(3.0) / 2.0, 0.0)};
317 :
318 526 : addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
319 263 : }
320 64 : else if (_boundary_type == BdryType::CARTESIAN)
321 : {
322 57 : _boundary_mesh_name = name() + "_cartesian_boundary";
323 : // create a submeshgenerator for the cartesian boundary
324 57 : auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
325 57 : params.set<bool>("loop") = true;
326 57 : params.set<unsigned int>("num_edges_between_points") = _boundary_sectors;
327 57 : params.set<std::vector<Point>>("points") = {
328 57 : 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 114 : Point(-_boundary_size / 2.0, _boundary_size / 2.0, 0.0)};
332 :
333 114 : addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
334 57 : }
335 : else
336 : {
337 7 : _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 7 : auto params = _app.getFactory().getValidParams("PolyLineMeshGenerator");
341 7 : params.set<bool>("loop") = true;
342 7 : params.set<unsigned int>("num_edges_between_points") = 1;
343 : // We enforce radius correction here for area preservation
344 7 : const Real corr_factor = std::sqrt(2 * M_PI / (Real)_boundary_sectors /
345 7 : std::sin(2 * M_PI / (Real)_boundary_sectors));
346 : std::vector<Point> circular_points;
347 259 : for (unsigned int i = 0; i < _boundary_sectors; i++)
348 : {
349 252 : const Real angle = 2.0 * M_PI * (Real)i / (Real)_boundary_sectors;
350 252 : circular_points.push_back(Point(_boundary_size * corr_factor * std::cos(angle) / 2.0,
351 252 : _boundary_size * corr_factor * std::sin(angle) / 2.0,
352 : 0.0));
353 : }
354 7 : params.set<std::vector<Point>>("points") = circular_points;
355 :
356 14 : addMeshSubgenerator("PolyLineMeshGenerator", _boundary_mesh_name, params);
357 7 : }
358 : // Set metadata of an assembly mesh
359 327 : declareMeshProperty("pattern_pitch_meta", _boundary_size);
360 654 : declareMeshProperty<bool>("is_control_drum_meta", false);
361 : }
362 :
363 : // Hexagonal Pattern
364 334 : 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 332 : 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 330 : 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 328 : if (!_hex_patterns.empty())
377 : {
378 : unsigned int hex_index = 0;
379 127 : for (const auto & hex_pattern : _hex_patterns)
380 : {
381 71 : const unsigned int n_hex_pattern_layers = hex_pattern.size();
382 71 : 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 69 : 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 199 : for (unsigned int i = 0; i <= n_hex_pattern_layers / 2; i++)
391 : {
392 134 : if (hex_pattern[i].size() != n_hex_pattern_layers / 2 + i + 1 ||
393 132 : 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 65 : const Point unit_shift_1 = Point(_hex_pitches[hex_index], 0.0, 0.0);
400 : const Point unit_shift_2 =
401 65 : Point(_hex_pitches[hex_index] / 2.0, _hex_pitches[hex_index] / 2.0 * std::sqrt(3.0), 0.0);
402 :
403 260 : for (unsigned int i = 0; i < hex_pattern.size(); i++)
404 : {
405 195 : 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 195 : ((i <= (hex_pattern.size() - 1) / 2)
408 195 : ? 0.0
409 65 : : (((Real)(hex_pattern.size() - 1) / 2) - (Real)i));
410 650 : 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 455 : if (hex_pattern[i][j] < _input_names.size())
414 : {
415 441 : input_usage_count[hex_pattern[i][j]]++;
416 441 : Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
417 441 : nodeCoordRotate(pt_buffer(0), pt_buffer(1), _hex_rotations[hex_index]);
418 441 : _positions.push_back(
419 : std::make_pair(pt_buffer + _hex_origins[hex_index], hex_pattern[i][j]));
420 : }
421 : }
422 : }
423 65 : hex_index++;
424 : }
425 : }
426 :
427 : // Rectangular Pattern
428 322 : 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 320 : 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 318 : 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 316 : 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 314 : if (!_rect_patterns.empty())
443 : {
444 : unsigned int rect_index = 0;
445 32 : for (const auto & rect_pattern : _rect_patterns)
446 : {
447 : std::set<unsigned int> rect_pattern_elem_size;
448 63 : for (const auto & rect_pattern_elem : rect_pattern)
449 : {
450 47 : if (rect_pattern_elem.empty())
451 2 : paramError("rect_patterns", "Each row of the element pattern must not be empty.");
452 45 : rect_pattern_elem_size.emplace(rect_pattern_elem.size());
453 : }
454 16 : 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 14 : const Point unit_shift_1 = Point(_rect_pitches_x[rect_index], 0.0, 0.0);
460 14 : const Point unit_shift_2 = Point(0.0, _rect_pitches_y[rect_index], 0.0);
461 :
462 49 : for (unsigned int i = 0; i < rect_pattern.size(); i++)
463 : {
464 35 : const Real param_2 = ((Real)rect_pattern.size() - 1.0) / 2.0 - (Real)i;
465 35 : const Real param_1_init = -((Real)rect_pattern[i].size() - 1.0) / 2.0;
466 126 : for (unsigned int j = 0; j < rect_pattern[i].size(); j++)
467 : {
468 91 : if (rect_pattern[i][j] < _input_names.size())
469 : {
470 91 : input_usage_count[rect_pattern[i][j]]++;
471 91 : Point pt_buffer = unit_shift_1 * (param_1_init + (Real)j) + unit_shift_2 * param_2;
472 91 : nodeCoordRotate(pt_buffer(0), pt_buffer(1), _rect_rotations[rect_index]);
473 91 : _positions.push_back(
474 : std::make_pair(pt_buffer + _rect_origins[rect_index], rect_pattern[i][j]));
475 : }
476 : }
477 : }
478 14 : rect_index++;
479 : }
480 : }
481 :
482 : // Circular Pattern
483 310 : 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 308 : 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 306 : 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 304 : if (!_circ_patterns.empty())
495 : {
496 : unsigned int circ_index = 0;
497 35 : for (const auto & circ_pattern : _circ_patterns)
498 : {
499 21 : const Real angle_step = 2.0 * M_PI / (Real)circ_pattern.size();
500 :
501 189 : for (unsigned int i = 0; i < circ_pattern.size(); i++)
502 : {
503 168 : if (circ_pattern[i] < _input_names.size())
504 : {
505 168 : input_usage_count[circ_pattern[i]]++;
506 168 : Point pt_buffer = Point(_circ_radii[circ_index] * std::cos((Real)i * angle_step),
507 168 : _circ_radii[circ_index] * std::sin((Real)i * angle_step),
508 168 : 0.0);
509 168 : nodeCoordRotate(pt_buffer(0), pt_buffer(1), _circ_rotations[circ_index]);
510 168 : _positions.push_back(
511 : std::make_pair(pt_buffer + _circ_origins[circ_index], circ_pattern[i]));
512 : }
513 : }
514 21 : circ_index++;
515 : }
516 : }
517 :
518 304 : 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 302 : if (_delete_default_external_boundary_from_inputs)
522 : {
523 606 : for (const auto & input_name : _input_names)
524 : {
525 304 : auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
526 304 : params.set<MeshGeneratorName>("input") = input_name;
527 1216 : params.set<std::vector<BoundaryName>>("boundary_names") = {std::to_string(OUTER_SIDESET_ID)};
528 :
529 912 : addMeshSubgenerator("BoundaryDeletionGenerator",
530 304 : input_name +
531 608 : static_cast<MeshGeneratorName>("_" + name() + "_del_ext_bdry"),
532 : params);
533 304 : }
534 : }
535 :
536 : std::vector<MeshGeneratorName> patterned_pin_mg_series;
537 1238 : for (unsigned int i = 0; i < _positions.size(); i++)
538 : {
539 936 : auto params = _app.getFactory().getValidParams("TransformGenerator");
540 1872 : params.set<MeshGeneratorName>("input") =
541 936 : _input_names[_positions[i].second] +
542 936 : static_cast<MeshGeneratorName>(
543 1872 : _delete_default_external_boundary_from_inputs ? ("_" + name() + "_del_ext_bdry") : "");
544 1872 : params.set<MooseEnum>("transform") = 1;
545 936 : params.set<RealVectorValue>("vector_value") = _positions[i].first;
546 :
547 1872 : patterned_pin_mg_series.push_back(name() + "_pos_" + std::to_string(i));
548 :
549 1872 : addMeshSubgenerator("TransformGenerator", patterned_pin_mg_series.back(), params);
550 :
551 936 : if (_cell_id_name.size())
552 : {
553 42 : auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
554 21 : params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
555 42 : params.set<std::string>("expression") = std::to_string(i + _cell_id_shift);
556 21 : params.set<std::string>("extra_elem_integer_name") = _cell_id_name;
557 :
558 42 : patterned_pin_mg_series.back() = name() + "_ceeid_" + std::to_string(i);
559 42 : addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
560 21 : }
561 936 : if (_pattern_id_name.size())
562 : {
563 42 : auto params = _app.getFactory().getValidParams("ParsedExtraElementIDGenerator");
564 42 : params.set<MeshGeneratorName>("input") = patterned_pin_mg_series.back();
565 42 : params.set<std::string>("expression") =
566 42 : std::to_string(_positions[i].second + _pattern_id_shift);
567 21 : params.set<std::string>("extra_elem_integer_name") = _pattern_id_name;
568 :
569 42 : patterned_pin_mg_series.back() = name() + "_peeid_" + std::to_string(i);
570 42 : addMeshSubgenerator("ParsedExtraElementIDGenerator", patterned_pin_mg_series.back(), params);
571 21 : }
572 936 : }
573 :
574 302 : auto params = _app.getFactory().getValidParams("XYDelaunayGenerator");
575 302 : params.set<MeshGeneratorName>("boundary") = _boundary_mesh_name;
576 302 : params.set<std::vector<MeshGeneratorName>>("holes") = patterned_pin_mg_series;
577 302 : params.set<bool>("refine_boundary") = false;
578 : // XYDelaunay's intrinsic checks
579 604 : params.set<bool>("verify_holes") = getParam<bool>("verify_holes");
580 604 : params.set<std::vector<bool>>("stitch_holes") =
581 604 : std::vector<bool>(patterned_pin_mg_series.size(), true);
582 604 : params.set<std::vector<bool>>("refine_holes") =
583 604 : std::vector<bool>(patterned_pin_mg_series.size(), false);
584 604 : params.set<Real>("desired_area") = getParam<Real>("desired_area");
585 906 : params.set<std::string>("desired_area_func") = getParam<std::string>("desired_area_func");
586 604 : params.set<bool>("use_auto_area_func") = getParam<bool>("use_auto_area_func");
587 604 : 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 604 : 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 604 : 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 604 : if (isParamSetByUser("auto_area_function_power"))
596 0 : params.set<Real>("auto_area_function_power") = getParam<Real>("auto_area_function_power");
597 906 : params.set<BoundaryName>("output_boundary") = std::to_string(OUTER_SIDESET_ID);
598 906 : params.set<MooseEnum>("tri_element_type") = getParam<MooseEnum>("tri_element_type");
599 604 : addMeshSubgenerator("XYDelaunayGenerator", name() + "_pattern", params);
600 :
601 302 : MeshGeneratorName final_mg_name(name() + "_pattern");
602 302 : if (_background_subdomain_id != Moose::INVALID_BLOCK_ID)
603 : {
604 454 : auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
605 908 : params.set<MeshGeneratorName>("input") = name() + "_pattern";
606 681 : params.set<std::vector<SubdomainName>>("old_block") = {"0"};
607 454 : params.set<std::vector<SubdomainName>>("new_block") = {
608 1135 : std::to_string(_background_subdomain_id)};
609 454 : addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_1", params);
610 227 : if (_background_subdomain_name.size())
611 : {
612 440 : auto params = _app.getFactory().getValidParams("RenameBlockGenerator");
613 660 : params.set<MeshGeneratorName>("input") = name() + "_back_rename_1";
614 440 : params.set<std::vector<SubdomainName>>("old_block") = {
615 1320 : std::to_string(_background_subdomain_id)};
616 660 : params.set<std::vector<SubdomainName>>("new_block") = {_background_subdomain_name};
617 440 : addMeshSubgenerator("RenameBlockGenerator", name() + "_back_rename_2", params);
618 220 : final_mg_name = name() + "_back_rename_2";
619 220 : }
620 : else
621 14 : final_mg_name = name() + "_back_rename_1";
622 227 : }
623 :
624 302 : _build_mesh = &getMeshByName(final_mg_name);
625 302 : }
626 :
627 : std::unique_ptr<MeshBase>
628 302 : FlexiblePatternGenerator::generate()
629 : {
630 302 : if (_external_boundary_id != OUTER_SIDESET_ID)
631 199 : MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
632 302 : 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 302 : (*_build_mesh)->find_neighbors();
651 302 : (*_build_mesh)->unset_is_prepared();
652 302 : return std::move(*_build_mesh);
653 : }
|