11 #include "libmesh/mesh_smoother_laplace.h" 16 #include "libmesh/parsed_function.h" 17 #include "libmesh/poly2tri_triangulator.h" 26 "num_sectors_per_side",
27 "num_sectors_per_side>0",
28 "Number of azimuthal sectors per polygon side (rotating counterclockwise from top right " 31 "background_intervals",
33 "background_intervals>0",
34 "Number of radial meshing intervals in background region (area " 35 "between rings and ducts) excluding the background's boundary layers.");
37 "background_radial_bias",
39 "background_radial_bias>0",
40 "Value used to create biasing in radial meshing for background region.");
42 "background_inner_boundary_layer_width",
44 "background_inner_boundary_layer_width>=0",
45 "Width of background region that is assigned to be the inner boundary layer.");
47 "background_inner_boundary_layer_intervals",
49 "background_inner_boundary_layer_intervals>0",
50 "Number of radial intervals of the background inner boundary layer");
52 "background_inner_boundary_layer_bias",
54 "background_inner_boundary_layer_bias>0",
55 "Growth factor used for mesh biasing of the background inner boundary layer.");
57 "background_outer_boundary_layer_width",
59 "background_outer_boundary_layer_width>=0",
60 "Width of background region that is assigned to be the outer boundary layer.");
62 "background_outer_boundary_layer_intervals",
64 "background_outer_boundary_layer_intervals>0",
65 "Number of radial intervals of the background outer boundary layer");
67 "background_outer_boundary_layer_bias",
69 "background_outer_boundary_layer_bias>0",
70 "Growth factor used for mesh biasing of the background outer boundary layer.");
71 params.
addParam<std::vector<subdomain_id_type>>(
72 "background_block_ids",
"Optional customized block id for the background block.");
73 params.
addParam<std::vector<SubdomainName>>(
74 "background_block_names",
"Optional customized block names for the background block.");
76 "duct_sizes",
"Distance(s) from polygon center to duct(s) inner boundaries.");
77 MooseEnum duct_sizes_style(
"apothem radius",
"radius");
81 "Style in which polygon center to duct inner boundary distance is " 82 "given (apothem = center to face, radius = center to vertex). Options: " +
87 "Number of meshing intervals in each enclosing duct excluding duct boundary layers.");
90 "duct_radial_biases>0",
91 "Values used to create biasing in radial meshing for duct regions.");
93 "duct_inner_boundary_layer_widths",
94 "duct_inner_boundary_layer_widths>=0",
95 "Widths of duct regions that are assigned to be the inner boundary layers.");
96 params.
addParam<std::vector<unsigned int>>(
97 "duct_inner_boundary_layer_intervals",
98 "Number of radial intervals of the duct inner boundary layers");
100 "duct_inner_boundary_layer_biases",
101 "duct_inner_boundary_layer_biases>0",
102 "Growth factors used for mesh biasing of the duct inner boundary layers.");
104 "duct_outer_boundary_layer_widths",
105 "duct_outer_boundary_layer_widths>=0",
106 "Widths of duct regions that are assigned to be the outer boundary layers.");
107 params.
addParam<std::vector<unsigned int>>(
108 "duct_outer_boundary_layer_intervals",
109 "Number of radial intervals of the duct outer boundary layers");
111 "duct_outer_boundary_layer_biases",
112 "duct_outer_boundary_layer_biases>0",
113 "Growth factors used for mesh biasing of the duct outer boundary layers.");
114 params.
addParam<std::vector<subdomain_id_type>>(
115 "duct_block_ids",
"Optional customized block ids for each duct geometry block.");
116 params.
addParam<std::vector<SubdomainName>>(
117 "duct_block_names",
"Optional customized block names for each duct geometry block.");
118 params.
addParam<
bool>(
"uniform_mesh_on_sides",
120 "Whether the side elements are reorganized to have a uniform size.");
121 params.
addParam<
unsigned int>(
"smoothing_max_it",
123 "Number of Laplacian smoothing iterations. This number is " 124 "disregarded when duct_sizes is present.");
128 "Whether to rotate the generated polygon mesh to ensure that one flat side faces up.");
131 "quad_center_elements",
false,
"Whether the center elements are quad or triangular.");
133 "center_quad_factor",
134 "center_quad_factor>0¢er_quad_factor<1",
135 "A fractional radius factor used to determine the radial positions of transition nodes in " 136 "the center region meshed by quad elements.");
137 params.
addParam<
bool>(
"replace_inner_ring_with_delaunay_mesh",
139 "True to replace the inner ring mesh with a Delaunay unstructured mesh");
141 "inner_ring_desired_area",
143 "Desired area as a function of x,y; omit to use the default constant area (square of the " 144 "smallest side length on the ring circle)");
147 "background_block_ids background_block_names duct_block_ids duct_block_names",
148 "Customized Subdomain/Boundary");
150 "uniform_mesh_on_sides",
151 "General Mesh Density");
153 "ring_radial_biases ring_inner_boundary_layer_biases ring_inner_boundary_layer_widths " 154 "ring_inner_boundary_layer_intervals ring_outer_boundary_layer_biases " 155 "ring_outer_boundary_layer_widths ring_outer_boundary_layer_intervals",
156 "Mesh Boundary Layers and Biasing Options");
158 "replace_inner_ring_with_delaunay_mesh inner_ring_desired_area ",
162 params.
addClassDescription(
"This PolygonConcentricCircleMeshGeneratorBase object is a base class " 163 "to be inherited for polygon mesh generators.");
171 _num_sides(isParamValid(
"num_sides")
172 ? getParam<unsigned
int>(
"num_sides")
173 : (isParamValid(
"hexagon_size") ? (unsigned
int)HEXAGON_NUM_SIDES
174 : (unsigned
int)SQUARE_NUM_SIDES)),
176 _duct_sizes(isParamValid(
"duct_sizes") ? getParam<
std::vector<
Real>>(
"duct_sizes")
178 _duct_intervals(isParamValid(
"duct_intervals")
179 ? getParam<
std::vector<unsigned
int>>(
"duct_intervals")
180 :
std::vector<unsigned
int>()),
181 _duct_radial_biases(isParamValid(
"duct_radial_biases")
182 ? getParam<
std::vector<
Real>>(
"duct_radial_biases")
183 :
std::vector<
Real>(_duct_intervals.size(), 1.0)),
184 _duct_inner_boundary_layer_params(
186 ? getParam<std::vector<Real>>(
"duct_inner_boundary_layer_widths")
190 ? getParam<std::vector<unsigned int>>(
"duct_inner_boundary_layer_intervals")
193 ? getParam<std::vector<Real>>(
"duct_inner_boundary_layer_biases")
195 _duct_outer_boundary_layer_params(
196 {isParamValid(
"duct_outer_boundary_layer_widths")
197 ? getParam<std::vector<Real>>(
"duct_outer_boundary_layer_widths")
198 : std::vector<Real>(_duct_intervals.size(), 0.0),
200 isParamValid(
"duct_outer_boundary_layer_intervals")
201 ? getParam<std::vector<unsigned int>>(
"duct_outer_boundary_layer_intervals")
202 : std::vector<unsigned int>(_duct_intervals.size(), 0),
203 isParamValid(
"duct_outer_boundary_layer_biases")
204 ? getParam<std::vector<Real>>(
"duct_outer_boundary_layer_biases")
205 : std::vector<Real>(_duct_intervals.size(), 0.0)}),
206 _duct_block_ids(isParamValid(
"duct_block_ids")
207 ? getParam<std::vector<subdomain_id_type>>(
"duct_block_ids")
208 : std::vector<subdomain_id_type>()),
209 _duct_block_names(isParamValid(
"duct_block_names")
210 ? getParam<std::vector<SubdomainName>>(
"duct_block_names")
211 : std::vector<SubdomainName>()),
212 _has_rings(isParamValid(
"ring_radii")),
213 _has_ducts(isParamValid(
"duct_sizes")),
215 isParamValid(
"polygon_size_style")
216 ? getParam<MooseEnum>(
"polygon_size_style").
template getEnum<PolygonSizeStyle>()
217 : (isParamValid(
"hexagon_size_style")
218 ? getParam<
MooseEnum>(
"hexagon_size_style").template getEnum<PolygonSizeStyle>()
219 : getParam<
MooseEnum>(
"square_size_style")
220 .template getEnum<PolygonSizeStyle>())),
221 _polygon_size(isParamValid(
"polygon_size")
222 ? getParam<
Real>(
"polygon_size")
223 : (isParamValid(
"hexagon_size") ? getParam<
Real>(
"hexagon_size")
224 : (getParam<
Real>(
"square_size") /
226 _num_sectors_per_side(getParam<
std::vector<unsigned
int>>(
"num_sectors_per_side")),
227 _background_intervals(getParam<unsigned
int>(
"background_intervals")),
230 _background_radial_bias(getParam<
Real>(
"background_radial_bias")),
231 _background_inner_boundary_layer_params(
232 {getParam<Real>(
"background_inner_boundary_layer_width"),
234 getParam<Real>(
"background_inner_boundary_layer_width") > 0.0
235 ? getParam<unsigned int>(
"background_inner_boundary_layer_intervals")
237 getParam<Real>(
"background_inner_boundary_layer_bias")}),
238 _background_outer_boundary_layer_params(
239 {getParam<Real>(
"background_outer_boundary_layer_width"),
241 getParam<Real>(
"background_outer_boundary_layer_width") > 0.0
242 ? getParam<unsigned int>(
"background_outer_boundary_layer_intervals")
244 getParam<Real>(
"background_outer_boundary_layer_bias")}),
245 _background_block_ids(isParamValid(
"background_block_ids")
246 ? getParam<std::vector<subdomain_id_type>>(
"background_block_ids")
247 : std::vector<subdomain_id_type>()),
248 _background_block_names(isParamValid(
"background_block_names")
249 ? getParam<std::vector<SubdomainName>>(
"background_block_names")
250 : std::vector<SubdomainName>()),
251 _uniform_mesh_on_sides(getParam<bool>(
"uniform_mesh_on_sides")),
252 _quad_center_elements(getParam<bool>(
"quad_center_elements")),
253 _center_quad_factor(isParamValid(
"center_quad_factor") ? getParam<Real>(
"center_quad_factor")
255 _smoothing_max_it(getParam<unsigned int>(
"smoothing_max_it")),
256 _sides_to_adapt(isParamValid(
"sides_to_adapt")
257 ? getParam<std::vector<unsigned int>>(
"sides_to_adapt")
258 : std::vector<unsigned int>()),
259 _node_id_background_meta(declareMeshProperty<dof_id_type>(
"node_id_background_meta", 0)),
260 _is_control_drum_meta(declareMeshProperty<bool>(
"is_control_drum_meta",
false))
262 declareMeshProperty<bool>(
"flat_side_up", getParam<bool>(
"flat_side_up"));
263 declareMeshProperty<unsigned int>(
"background_intervals_meta", 0);
264 declareMeshProperty<Real>(
"pattern_pitch_meta", 0.0);
265 declareMeshProperty<std::vector<Real>>(
"azimuthal_angle_meta", std::vector<Real>());
266 declareMeshProperty<Real>(
"max_radius_meta", 0.0);
268 const unsigned short tri_order = _tri_elem_type == TRI_ELEM_TYPE::TRI3 ? 1 : 2;
269 const unsigned short quad_order = _quad_elem_type == QUAD_ELEM_TYPE::QUAD4 ? 1 : 2;
275 if (_quad_center_elements)
277 if (tri_order != quad_order)
278 _tri_elem_type = quad_order == 1 ? TRI_ELEM_TYPE::TRI3 : TRI_ELEM_TYPE::TRI6;
280 else if (_ring_radii.empty() && _background_intervals == 1 &&
281 _background_inner_boundary_layer_params.intervals == 0 &&
282 _background_outer_boundary_layer_params.intervals == 0 && _duct_sizes.empty())
285 if (tri_order != quad_order)
286 _quad_elem_type = tri_order == 1 ? QUAD_ELEM_TYPE::QUAD4 : QUAD_ELEM_TYPE::QUAD9;
288 else if (tri_order != quad_order)
289 paramError(
"tri_element_type",
290 "the element types of triangular and quadrilateral elements must be compatible if " 291 "both types of elements are generated.");
295 if (!_sides_to_adapt.empty() && _num_sides != HEXAGON_NUM_SIDES && _num_sides != SQUARE_NUM_SIDES)
296 paramError(
"sides_to_adapt",
"If provided, the generated mesh must be a hexagon or a square.");
297 _pitch = 2.0 * (_polygon_size_style == PolygonSizeStyle::apothem
299 : _polygon_size * std::cos(M_PI /
Real(_num_sides)));
300 declareMeshProperty<Real>(
"pitch_meta", _pitch);
301 if (_inward_interface_boundary_names.size() > 0 &&
302 _inward_interface_boundary_names.size() != _duct_sizes.size() + _ring_radii.size())
303 paramError(
"inward_interface_boundary_names",
304 "If provided, the length of this parameter must be identical to the total number of " 306 if (_outward_interface_boundary_names.size() > 0 &&
307 _outward_interface_boundary_names.size() != _duct_sizes.size() + _ring_radii.size())
308 paramError(
"outward_interface_boundary_names",
309 "If provided, the length of this parameter must be identical to the total number of " 311 const unsigned int num_total_background_layers =
312 _background_intervals + _background_inner_boundary_layer_params.intervals +
313 _background_outer_boundary_layer_params.intervals;
314 if ((_has_rings || num_total_background_layers == 1) && _background_block_ids.size() > 1)
316 "background_block_ids",
317 "This parameter must be either unset or have a unity length when ring_radii is " 318 "provided or the number of background intervals (including boundary layers) is unity.");
319 if ((_has_rings || num_total_background_layers == 1) && _background_block_names.size() > 1)
321 "background_block_names",
322 "This parameter must be either unset or have a unity length when ring_radii is " 323 "provided or the number of background intervals (including boundary layers) is unity.");
324 if (!_has_rings && num_total_background_layers > 1 && _quad_center_elements &&
325 _background_block_ids.size() == 1)
326 _background_block_ids.insert(_background_block_ids.begin(), _background_block_ids.front());
327 if ((!_has_rings && _background_intervals > 1) &&
328 (!_background_block_ids.empty() && _background_block_ids.size() != 2))
329 paramError(
"background_block_ids",
330 "This parameter must be either unset or have a length of two when ring_radii is not " 331 "provided and background intervals (including boundary layers) is not unity. It can " 332 "optionally to have a unity length if `quad_center_elements` is enabled.");
333 if (!_has_rings && num_total_background_layers > 1 && _quad_center_elements &&
334 _background_block_names.size() == 1)
335 _background_block_names.insert(_background_block_names.begin(),
336 _background_block_names.front());
337 if ((!_has_rings && _background_intervals > 1) &&
338 (!_background_block_names.empty() && _background_block_names.size() != 2))
339 paramError(
"background_block_names",
340 "This parameter must be either unset or have a length of two when ring_radii is not " 341 "provided and background intervals (including boundary layers) is not unity. It can " 342 "optionally have a unity length if `quad_center_elements` is enabled.");
343 if (_num_sectors_per_side.size() != _num_sides)
344 paramError(
"num_sectors_per_side",
345 "This parameter must have a length that is consistent with num_sides.");
346 for (
auto it = _num_sectors_per_side.begin(); it != _num_sectors_per_side.end(); ++it)
348 paramError(
"num_sectors_per_side",
"This parameter must be even.");
349 declareMeshProperty(
"num_sectors_per_side_meta", _num_sectors_per_side);
351 if (!getParam<bool>(
"replace_inner_ring_with_delaunay_mesh") &&
352 isParamSetByUser(
"inner_ring_desired_area"))
354 "inner_ring_desired_area",
355 "This parameter should be set only when 'replace_inner_ring_with_delaunay_mesh=true'");
359 const unsigned int num_innermost_ring_layers =
360 _ring_inner_boundary_layer_params.intervals.front() + _ring_intervals.front() +
361 _ring_outer_boundary_layer_params.intervals.front();
363 if (!_ring_block_ids.empty() && _quad_center_elements && num_innermost_ring_layers > 1 &&
364 _ring_block_ids.size() == _ring_intervals.size())
365 _ring_block_ids.insert(_ring_block_ids.begin(), _ring_block_ids.front());
367 if (!_ring_block_ids.empty() &&
368 _ring_block_ids.size() !=
369 (_ring_intervals.size() + (
unsigned int)(num_innermost_ring_layers != 1)))
372 std::ostringstream debug_info;
373 debug_info <<
"quad_center_elements is : " << (_quad_center_elements ?
"true" :
"false")
375 debug_info <<
"ring_block_ids size is : " << _ring_block_ids.size() << std::endl;
376 debug_info <<
"ring_intervals size is : " << _ring_intervals.size() << std::endl;
377 debug_info <<
"number of innermost ring layers is : " << num_innermost_ring_layers
381 if (!_quad_center_elements)
385 "This parameter must have the appropriate size if it is provided: " 386 "Since the number of the innermost ring layers (" +
387 std::to_string(num_innermost_ring_layers) +
388 " :first ring interval and inner/outer boundaries of the first ring) is more than " 389 "one, and we have non-quad central elements, the size of 'ring_block_ids' must be " 390 "equal to the size of 'ring_intervals' + 1.\n",
397 "This parameter must have the appropriate size if it is provided: " 398 "Since the number of the innermost ring layers (" +
399 std::to_string(num_innermost_ring_layers) +
400 " :first ring interval and inner/outer boundaries of the first ring) is more than " 401 "one, and we have quad central elements, the size of 'ring_block_ids' can be either" 402 "equal to the size of 'ring_intervals' or 'ring_intervals' + 1.\n",
407 if (!_ring_block_names.empty() && _quad_center_elements && num_innermost_ring_layers > 1 &&
408 _ring_block_names.size() == _ring_intervals.size())
409 _ring_block_names.insert(_ring_block_names.begin(), _ring_block_names.front());
411 if (!_ring_block_names.empty() &&
412 _ring_block_names.size() !=
413 (_ring_intervals.size() + (
unsigned int)(num_innermost_ring_layers != 1)))
416 std::ostringstream debug_info;
417 debug_info <<
"quad_center_elements is : " << (_quad_center_elements ?
"true" :
"false")
419 debug_info <<
"ring_block_names size is : " << _ring_block_names.size() << std::endl;
420 debug_info <<
"ring_intervals size is : " << _ring_intervals.size() << std::endl;
421 debug_info <<
"number of innermost ring layers is : " << num_innermost_ring_layers
425 if (!_quad_center_elements)
429 "This parameter must have the appropriate size if it is provided: " 430 "Since the number of the innermost ring layers (" +
431 std::to_string(num_innermost_ring_layers) +
432 " :first ring interval and inner/outer boundaries of the first ring) is more than " 433 "one, and we have non-quad central elements, the size of 'ring_block_names' must " 434 "be equal to the size of 'ring_intervals' + 1.\n",
441 "This parameter must have the appropriate size if it is provided: " 442 "Since the number of the innermost ring layers (" +
443 std::to_string(num_innermost_ring_layers) +
444 " :first ring interval and inner/outer boundaries of the first ring) is more than " 445 "one, and we have quad central elements, the size of 'ring_block_names' can be " 446 "either equal to the size of 'ring_intervals' or 'ring_intervals' + 1.\n",
450 for (
unsigned int i = 0; i < _ring_radii.size(); i++)
452 const Real layer_width = _ring_radii[i] - (i == 0 ? 0.0 : _ring_radii[i - 1]);
453 _ring_inner_boundary_layer_params.fractions.push_back(
454 _ring_inner_boundary_layer_params.widths[i] / layer_width);
455 _ring_outer_boundary_layer_params.fractions.push_back(
456 _ring_outer_boundary_layer_params.widths[i] / layer_width);
458 for (
unsigned int i = 0; i < _ring_inner_boundary_layer_params.fractions.size(); i++)
460 _ring_inner_boundary_layer_params.intervals[i] > 0)
461 paramError(
"ring_inner_boundary_layer_intervals",
462 "Ring inner boundary layer must have zero interval if its thickness is zero.");
465 _ring_inner_boundary_layer_params.intervals[i] == 0)
466 paramError(
"ring_inner_boundary_layer_intervals",
467 "Ring inner boundary layer must have non-zero interval if its thickness is " 469 for (
unsigned int i = 0; i < _ring_outer_boundary_layer_params.fractions.size(); i++)
472 _ring_outer_boundary_layer_params.intervals[i] > 0)
473 paramError(
"ring_outer_boundary_layer_intervals",
474 "Ring outer boundary layer must have zero interval if its thickness is zero.");
477 _ring_outer_boundary_layer_params.intervals[i] == 0)
478 paramError(
"ring_outer_boundary_layer_intervals",
479 "Ring outer boundary layer must have non-zero interval if its thickness is " 481 if (_ring_inner_boundary_layer_params.fractions[i] +
482 _ring_outer_boundary_layer_params.fractions[i] >=
484 paramError(
"ring_inner_boundary_layer_widths",
485 "Summation of ring_inner_boundary_layer_widths and " 486 "ring_outer_boundary_layer_widths cannot exceeds the ring layer width.");
490 if (_duct_sizes.size() != _duct_intervals.size())
491 paramError(
"duct_sizes",
"This parameter and duct_intervals must have the same length.");
492 if (_duct_sizes.size() != _duct_radial_biases.size())
493 paramError(
"duct_sizes",
"This parameter and duct_radial_biases must have the same length.");
494 if (!_duct_block_ids.empty() && _duct_block_ids.size() != _duct_intervals.size())
495 paramError(
"duct_block_ids",
496 "This parameter must have the same length as duct_intervals if set.");
497 if (!_duct_block_names.empty() && _duct_block_names.size() != _duct_intervals.size())
498 paramError(
"duct_block_names",
499 "This parameter must have the same length as duct_intervals if set.");
500 if (_duct_sizes.size() != _duct_inner_boundary_layer_params.widths.size() ||
501 _duct_sizes.size() != _duct_inner_boundary_layer_params.intervals.size() ||
502 _duct_sizes.size() != _duct_inner_boundary_layer_params.biases.size() ||
503 _duct_sizes.size() != _duct_outer_boundary_layer_params.widths.size() ||
504 _duct_sizes.size() != _duct_outer_boundary_layer_params.intervals.size() ||
505 _duct_sizes.size() != _duct_outer_boundary_layer_params.biases.size())
506 paramError(
"duct_sizes",
507 "The inner and outer duct boundary layer parameters must have the same sizes as " 511 if (_duct_sizes_style == PolygonSizeStyle::apothem)
512 for (
unsigned int i = 0; i < _duct_sizes.size(); i++)
513 _duct_sizes[i] /= std::cos(M_PI /
Real(_num_sides));
514 for (
unsigned int i = 1; i < _duct_sizes.size(); i++)
515 if (_duct_sizes[i] <= _duct_sizes[i - 1])
516 paramError(
"duct_sizes",
"This parameter must be strictly ascending.");
517 if (_duct_sizes.front() <=
518 (_has_rings ? _ring_radii.back() / std::cos(M_PI /
Real(_num_sides)) : 0.0))
519 paramError(
"duct_sizes",
520 "This parameter must be positive and ensures no overlapping with rings.");
521 if (_duct_sizes.back() >= _pitch / 2.0 / std::cos(M_PI /
Real(_num_sides)))
522 paramError(
"duct_sizes",
523 "This parameter must ensure that ducts are smaller than the polygon size.");
524 if (*std::min_element(_duct_intervals.begin(), _duct_intervals.end()) <= 0)
525 paramError(
"duct_intervals",
"Elements of this parameter must be positive.");
526 if (_duct_sizes_style == PolygonSizeStyle::apothem)
527 for (
unsigned int i = 0; i < _duct_sizes.size(); i++)
529 _duct_inner_boundary_layer_params.widths[i] /= std::cos(M_PI /
Real(_num_sides));
530 _duct_outer_boundary_layer_params.widths[i] /= std::cos(M_PI /
Real(_num_sides));
532 for (
unsigned int i = 0; i < _duct_sizes.size(); i++)
534 const Real layer_width =
535 (i == _duct_sizes.size() - 1 ? _pitch / 2.0 / std::cos(M_PI /
Real(_num_sides))
536 : _duct_sizes[i + 1]) -
538 _duct_inner_boundary_layer_params.fractions.push_back(
539 _duct_inner_boundary_layer_params.widths[i] / layer_width);
540 _duct_outer_boundary_layer_params.fractions.push_back(
541 _duct_outer_boundary_layer_params.widths[i] / layer_width);
543 for (
unsigned int i = 0; i < _duct_inner_boundary_layer_params.fractions.size(); i++)
545 _duct_inner_boundary_layer_params.intervals[i] > 0)
546 paramError(
"duct_inner_boundary_layer_intervals",
547 "Duct inner boundary layer must have zero interval if its thickness is zero.");
550 _duct_inner_boundary_layer_params.intervals[i] == 0)
551 paramError(
"duct_inner_boundary_layer_intervals",
552 "Duct inner boundary layer must have non-zero interval if its thickness is " 554 for (
unsigned int i = 0; i < _duct_outer_boundary_layer_params.fractions.size(); i++)
557 _duct_outer_boundary_layer_params.intervals[i] > 0)
558 paramError(
"duct_outer_boundary_layer_intervals",
559 "Duct outer boundary layer must have zero interval if its thickness is zero.");
562 _duct_outer_boundary_layer_params.intervals[i] == 0)
563 paramError(
"duct_outer_boundary_layer_intervals",
564 "Duct outer boundary layer must have non-zero interval if its thickness is " 566 if (_duct_inner_boundary_layer_params.fractions[i] +
567 _duct_outer_boundary_layer_params.fractions[i] >=
569 paramError(
"duct_inner_boundary_layer_widths",
570 "Summation of duct_inner_boundary_layer_widths and " 571 "duct_outer_boundary_layer_widths cannot exceeds the duct layer width.");
575 _background_outer_boundary_layer_params.width,
578 const Real min_background_thickness =
579 (_has_ducts ? (_duct_sizes.front() * std::cos(M_PI /
Real(_num_sides))) : (_pitch / 2.0)) -
580 (_has_rings ? _ring_radii.back() : 0.0);
581 if (_background_inner_boundary_layer_params.width +
582 _background_outer_boundary_layer_params.width *
583 (_duct_sizes_style == PolygonSizeStyle::apothem
585 : std::cos(M_PI /
Real(_num_sides))) >=
586 min_background_thickness)
587 paramError(
"background_inner_boundary_layer_width",
588 "The summation of background_inner_boundary_layer_width and " 589 "background_outer_boundary_layer_width must be less than the minimum thickness of " 590 "the background region.");
591 if (_duct_sizes_style == PolygonSizeStyle::apothem)
592 _background_outer_boundary_layer_params.width /= std::cos(M_PI /
Real(_num_sides));
594 if (!_quad_center_elements && _center_quad_factor)
595 paramError(
"center_quad_factor",
596 "this parameter is only applicable if quad_center_elements is set true.");
597 if (_quad_center_elements)
598 declareMeshProperty<subdomain_id_type>(
599 "quad_center_block_id",
600 _has_rings ? (_ring_block_ids.empty() ? _block_id_shift + 1 : _ring_block_ids.front())
601 : (_background_block_ids.empty() ? _block_id_shift + 1
602 : _background_block_ids.front()));
604 declareMeshProperty<subdomain_id_type>(
"quad_center_block_id",
608 declareMeshProperty<bool>(
"interface_boundaries",
false);
609 declareMeshProperty<std::set<boundary_id_type>>(
"interface_boundary_ids", {});
612 std::unique_ptr<MeshBase>
615 std::vector<std::unique_ptr<ReplicatedMesh>> input(
_input_ptrs.size());
620 mooseError(
"A non-replicated mesh input was supplied but replicated meshes are required.");
621 if ((
_order == 1 && (*input[i]->elements_begin())->default_order() !=
FIRST) ||
622 (
_order == 2 && (*input[i]->elements_begin())->default_order() ==
FIRST))
624 "The order of the input mesh to be adapted to does not match the order of the " 625 "mesh to be generated.");
628 unsigned int mesh_input_counter = 0;
630 std::vector<Real> azimuthal_list;
632 for (
unsigned int mesh_index = 0; mesh_index <
_num_sides; mesh_index++)
645 _num_sides == 6 ? ((
Real)mesh_index * 60.0 - 150.0) : ((
Real)mesh_index * 90.0 - 135.0);
647 : ((
Real)((mesh_index + 1) % 4) * 90.0 - 135.0);
654 azimuthal_list.push_back(
656 ? ((
Real)mesh_index * 60.0 - 150.0 +
659 : ((
Real)mesh_index * 90.0 - 135.0 +
662 mesh_input_counter++;
669 azimuthal_list.push_back(
678 std::vector<Real> ring_radii_corr;
685 for (
unsigned int i = 0; i <
_ring_radii.size(); i++)
686 ring_radii_corr.push_back(
_ring_radii[i] * corr_factor);
690 if (ring_radii_corr.back() >=
_pitch / 2.0)
692 "Elements of this parameter must be smaller than polygon apothem (after volume " 693 "preserve correction if applicable).");
727 for (
unsigned int mesh_index = 1; mesh_index <
_num_sides; mesh_index++)
759 ReplicatedMesh other_mesh(*mesh_tmp);
760 MeshTools::Modification::rotate(other_mesh, 360.0 /
_num_sides * mesh_index, 0, 0);
761 mesh0->prepare_for_use();
762 other_mesh.prepare_for_use();
783 const Real angle_tol = 1.0e-5;
784 std::vector<std::pair<Real, unsigned int>> node_azi_list;
785 MeshTools::Modification::rotate(*mesh0, -(270.0 - 360.0 / (
Real)
_num_sides), 0.0, 0.0);
786 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> side_list =
787 mesh0->get_boundary_info().build_side_list();
788 mesh0->get_boundary_info().build_node_list_from_side_list();
789 std::vector<std::tuple<dof_id_type, boundary_id_type>> node_list =
790 mesh0->get_boundary_info().build_node_list();
792 for (
unsigned int i = 0; i < node_list.size(); ++i)
796 node_azi_list.push_back(
797 std::make_pair(atan2((*mesh0->node_ptr(std::get<0>(node_list[i])))(1),
798 (*mesh0->node_ptr(std::get<0>(node_list[i])))(0)) *
800 std::get<0>(node_list[i])));
801 if (std::abs(node_azi_list.back().first + 180.0) <= angle_tol)
802 node_azi_list.back().first = 180.0;
805 std::sort(node_azi_list.begin(), node_azi_list.end());
813 Real y_tmp = x_tmp * std::tan(azi_corr_tmp);
816 Point p_tmp = Point(x_tmp, y_tmp, 0.0);
819 node_azi_list[std::accumulate(
825 MeshTools::Modification::rotate(*mesh0, (270.0 - 360.0 / (
Real)
_num_sides), 0.0, 0.0);
837 unsigned int block_it = 0;
838 unsigned ring_block_num = 0;
839 std::vector<subdomain_id_type> block_ids_old;
840 std::vector<subdomain_id_type> block_ids_new;
841 std::vector<SubdomainName> block_names;
854 ? (SubdomainName)std::to_string(block_ids_new.back())
863 ? (SubdomainName)std::to_string(block_ids_new.back())
873 ? (SubdomainName)std::to_string(block_ids_new.back())
880 *mesh0, block_ids_old, block_ids_new, block_names,
"ConcentricCircleMeshGenerator");
886 mesh0->get_boundary_info().sideset_name(
889 mesh0->get_boundary_info().nodeset_name(
904 getParam<std::string>(
"ring_id_name"),
908 getParam<MooseEnum>(
"ring_id_assign_type") ==
"ring_wise",
916 std::set<boundary_id_type> boundary_ids = mesh0->get_boundary_info().get_boundary_ids();
917 std::set<boundary_id_type> interface_boundary_ids;
920 const unsigned int num_boundary_ids = boundary_ids.size();
921 for (
const auto i :
make_range(num_boundary_ids))
924 auto it = boundary_ids.find(
id);
925 if (it != boundary_ids.end())
927 boundary_ids.erase(it);
928 interface_boundary_ids.insert(
id);
934 const unsigned int num_boundary_ids = boundary_ids.size();
935 for (
const auto i :
make_range(num_boundary_ids))
938 auto it = boundary_ids.find(
id);
939 if (it != boundary_ids.end())
941 boundary_ids.erase(it);
942 interface_boundary_ids.insert(
id);
949 bool flat_side_up = getMeshProperty<bool>(
"flat_side_up",
name());
951 MeshTools::Modification::rotate(*mesh0, 180.0 / (
Real)
_num_sides, 0.0, 0.0);
952 mesh0->set_isnt_prepared();
954 if (
_has_rings && getParam<bool>(
"replace_inner_ring_with_delaunay_mesh"))
958 "Should not be set because the center elements of the inner ring will be replaced " 959 "by a Delaunay mesh with 'replace_inner_ring_with_delaunay_mesh=true'");
962 std::set<Elem *> deleteable_elems;
963 for (
auto & elem : mesh0->element_ptr_range())
964 if (elem->vertex_average().norm() < ring_radii_corr[0])
965 deleteable_elems.insert(elem);
968 BoundaryInfo & boundary_info = mesh0->get_boundary_info();
969 for (
auto & elem : deleteable_elems)
971 unsigned int n_sides = elem->n_sides();
972 for (
unsigned int n = 0; n != n_sides; ++n)
974 Elem * neighbor = elem->neighbor_ptr(n);
978 const unsigned int return_side = neighbor->which_neighbor_am_i(elem);
980 if (neighbor->neighbor_ptr(return_side) == elem)
982 neighbor->set_neighbor(return_side,
nullptr);
983 boundary_info.add_side(neighbor, return_side, boundary_id);
987 mesh0->delete_elem(elem);
992 Real min_side = std::numeric_limits<Real>::max();
993 for (
auto & elem : poly_mesh->element_ptr_range())
995 Real l = elem->volume();
1006 const auto desired_area = getParam<std::string>(
"inner_ring_desired_area");
1007 if (desired_area !=
"")
1019 poly2tri.
elem_type() = libMesh::ElemType::TRI6;
1021 poly2tri.
elem_type() = libMesh::ElemType::TRI7;
1026 for (
auto elem : poly_mesh->element_ptr_range())
1027 elem->subdomain_id() = block_ids_new[0];
1031 if (
_ring_intervals[0] != 1 && getParam<MooseEnum>(
"ring_id_assign_type") ==
"ring_wise")
1032 paramError(
"replace_inner_ring_with_delaunay_mesh",
1033 "Inner ring has multple intervals with each being assigned with a different " 1034 "ring id, replacing inner ring with Delaunay mesh will remove this ring id " 1035 "assign type. Either change 'ring_id_assign_type' to block_wise or set the " 1036 "first element of 'ring_intervals' to 1 or set " 1037 "'replace_inner_ring_with_delaunay_mesh' to false to avoid this error.");
1038 auto id_name = getParam<std::string>(
"ring_id_name");
1039 const auto extra_id_index = poly_mesh->add_elem_integer(id_name);
1040 for (
auto elem : poly_mesh->element_ptr_range())
1041 elem->set_extra_integer(extra_id_index, 1);
1046 auto id_name = getParam<std::string>(
"sector_id_name");
1047 const auto extra_id_index = poly_mesh->add_elem_integer(id_name);
1048 for (
auto elem : poly_mesh->element_ptr_range())
1049 elem->set_extra_integer(extra_id_index, 0);
1053 mesh0->stitch_meshes(*poly_mesh, boundary_id, 0, TOLERANCE,
true,
false);
std::vector< Real > _duct_sizes
Size parameters of the duct regions.
std::vector< std::unique_ptr< MeshBase > * > _input_ptrs
Pointers to input mesh pointers.
const std::vector< unsigned int > _ring_intervals
Number of rings in each circle or in the enclosing square.
const boundary_id_type _interface_boundary_id_shift
Shift in default boundary IDs of interfaces to avert potential conflicts.
const std::vector< Real > _duct_radial_biases
Bias values used to induce biasing to radial meshing in duct regions.
dof_id_type & _node_id_background_meta
MeshMetaData: maximum node id of the background region.
const Real _center_quad_factor
A fractional radius factor used to determine the radial positions of transition nodes in the center r...
const unsigned int _smoothing_max_it
Maximum smooth iteration number.
std::unique_ptr< ReplicatedMesh > buildBoundaryMesh(const ReplicatedMesh &input_mesh, const boundary_id_type boundary_id)
T & setMeshProperty(const std::string &data_name, Args &&... args)
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
virtual void smooth() override
void setSectorExtraIDs(MeshBase &mesh, const std::string id_name, const unsigned int num_sides, const std::vector< unsigned int > num_sectors_per_side)
assign sector extra ids to polygon mesh
const bool _has_rings
Whether the generated mesh contains ring regions.
virtual void set_refine_boundary_allowed(bool refine_bdy_allowed) override
const subdomain_id_type _block_id_shift
Shift in default subdomain IDs to avert potential conflicts with other meshes.
QUAD_ELEM_TYPE _quad_elem_type
Type of quadrilateral elements to be generated.
const bool _preserve_volumes
Volume preserving function is optional.
const std::vector< unsigned int > _num_sectors_per_side
Mesh sector number of each polygon side.
void set_verify_hole_boundaries(bool v)
const boundary_id_type _external_boundary_id
Boundary ID of the mesh's external boundary.
const bool _uniform_mesh_on_sides
Whether the nodes on the external boundary needs to be uniformly distributed.
multiBdryLayerParams _ring_inner_boundary_layer_params
Widths, fractions, radial sectors and growth factors of the inner boundary layers of the ring regions...
Real _pitch
Pitch size of the produced polygon.
const std::vector< Real > _ring_radii
Radii of concentric circles.
void set_interpolate_boundary_points(int n_points)
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
static InputParameters validParams()
void assignBlockIdsNames(ReplicatedMesh &mesh, std::vector< subdomain_id_type > &block_ids_old, std::vector< subdomain_id_type > &block_ids_new, std::vector< SubdomainName > &block_names, const std::string &generator_name) const
Assign block IDs and names to the mesh if applicable.
void ringBlockIdsNamesPreparer(unsigned int &block_counter, unsigned int &ring_block_num, std::vector< subdomain_id_type > &block_ids_old, std::vector< subdomain_id_type > &block_ids_new, std::vector< SubdomainName > &block_names) const
Prepare user-defined ring block IDs and names to replace the default ones.
void changeBoundaryId(const boundary_id_type old_id, const boundary_id_type new_id, bool delete_prev)
std::vector< Real > azimuthalAnglesCollector(ReplicatedMesh &mesh, std::vector< Point > &boundary_points, const Real lower_azi=-30.0, const Real upper_azi=30.0, const unsigned int return_type=ANGLE_TANGENT, const unsigned int num_sides=6, const boundary_id_type bid=OUTER_SIDESET_ID, const bool calculate_origin=true, const Real input_origin_x=0.0, const Real input_origin_y=0.0, const Real tol=1.0E-10) const
Collects sorted azimuthal angles of the external boundary.
std::string getRawNames() const
const bool _create_outward_interface_boundaries
Whether outward interface boundaries are created.
virtual const std::string & name() const
std::vector< SubdomainName > _background_block_names
Subdomain Names of the background regions.
singleBdryLayerParams _background_inner_boundary_layer_params
Width, fraction, radiation sectors and growth factor of the inner boundary layer of the background re...
void nodeCoordRotate(Real &x, Real &y, const Real theta) const
Calculates x and y coordinates after rotating by theta angle.
TriangulationType & triangulation_type()
bool isParamValid(const std::string &name) const
static const subdomain_id_type invalid_subdomain_id
multiBdryLayerParams _ring_outer_boundary_layer_params
Widths, fractions, radial sectors and growth factors of the outer boundary layers of the ring regions...
const bool _quad_center_elements
Whether the central elements need to be QUAD4.
void setRingExtraIDs(MeshBase &mesh, const std::string id_name, const unsigned int num_sides, const std::vector< unsigned int > num_sectors_per_side, const std::vector< unsigned int > ring_intervals, const bool ring_wise_id, const bool quad_center_elements)
assign ring extra ids to polygon mesh
virtual void set_desired_area_function(FunctionBase< Real > *desired) override
const bool _create_inward_interface_boundaries
Whether inward interface boundaries are created.
std::unique_ptr< MeshBase > generate() override
singleBdryLayerParams _background_outer_boundary_layer_params
Width, fraction, radiation sectors and growth factor of the outer boundary layer of the background re...
multiBdryLayerParams _duct_outer_boundary_layer_params
Widths, fractions, radial sectors and growth factors of the inner boundary layers of the duct regions...
const std::vector< Real > _ring_radial_biases
Bias values used to induce biasing to radial meshing in ring regions.
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
void paramError(const std::string ¶m, Args... args) const
std::vector< subdomain_id_type > _background_block_ids
Subdomain IDs of the background regions.
std::vector< std::vector< Real > > _azimuthal_angles_array
Azimuthal angles of all radial nodes for volume preservation.
static void addRingAndSectorIDParams(InputParameters ¶ms)
Add InputParameters which are used by ring and sector IDs.
const std::vector< SubdomainName > _duct_block_names
Subdomain Names of the duct regions.
const unsigned int _num_sides
Number of polygon sides.
virtual void triangulate() override
bool isParamSetByUser(const std::string &nm) const
const std::vector< unsigned int > _duct_intervals
Number of layers in each enclosing duct.
const BoundaryName _external_boundary_name
Boundary Name of the mesh's external boundary.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real _background_radial_bias
Bias value used to induce biasing to radial meshing in background region.
std::unique_ptr< ReplicatedMesh > buildSimpleSlice(std::vector< Real > ring_radii, const std::vector< unsigned int > ring_layers, const std::vector< Real > ring_radial_biases, const multiBdryLayerParams &ring_inner_boundary_layer_params, const multiBdryLayerParams &ring_outer_boundary_layer_params, std::vector< Real > ducts_center_dist, const std::vector< unsigned int > ducts_layers, const std::vector< Real > duct_radial_biases, const multiBdryLayerParams &duct_inner_boundary_layer_params, const multiBdryLayerParams &duct_outer_boundary_layer_params, const Real pitch, const unsigned int num_sectors_per_side, const unsigned int background_intervals, const Real background_radial_bias, const singleBdryLayerParams &background_inner_boundary_layer_params, const singleBdryLayerParams &background_outer_boundary_layer_params, dof_id_type &node_id_background_meta, const unsigned int side_number, const unsigned int side_index, const std::vector< Real > azimuthal_tangent=std::vector< Real >(), const subdomain_id_type block_id_shift=0, const bool quad_center_elements=false, const Real center_quad_factor=0.0, const bool create_inward_interface_boundaries=false, const bool create_outward_interface_boundaries=true, const boundary_id_type boundary_id_shift=0, const bool generate_side_specific_boundaries=true, const TRI_ELEM_TYPE tri_elem_type=TRI_ELEM_TYPE::TRI3, const QUAD_ELEM_TYPE quad_elem_type=QUAD_ELEM_TYPE::QUAD4)
Creates a mesh of a slice that corresponds to a single side of the polygon to be generated.
const unsigned int _background_intervals
Numbers of radial intervals of the background regions.
bool _is_general_polygon
MeshMetaData: whether this produced mesh is a general polygon (or a hexagon)
IntRange< T > make_range(T beg, T end)
static InputParameters validParams()
void mooseError(Args &&... args) const
const bool _has_ducts
Whether the generated mesh contains duct regions.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
This ConcentricCircleGeneratorBase object is a base class to be inherited for mesh generators that in...
PolygonConcentricCircleMeshGeneratorBase(const InputParameters ¶meters)
TRI_ELEM_TYPE _tri_elem_type
Type of triangular elements to be generated.
const bool _generate_side_specific_boundaries
Whether the side-specific external boundaries are generated or not.
unsigned short _order
Order of the elements to be generated.
Real radiusCorrectionFactor(const std::vector< Real > &azimuthal_list, const bool full_circle=true, const unsigned int order=1, const bool is_first_value_vertex=true)
Makes radial correction to preserve ring area.
const std::vector< subdomain_id_type > _duct_block_ids
Subdomain IDs of the duct regions.
multiBdryLayerParams _duct_inner_boundary_layer_params
Widths, fractions, radial sectors and growth factors of the inner boundary layers of the duct regions...
const std::vector< unsigned int > _sides_to_adapt
Indices of the hexagon sides that need to adapt.
void ErrorVector unsigned int
auto index_range(const T &sizable)
bool absoluteFuzzyGreaterThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void assignInterfaceBoundaryNames(ReplicatedMesh &mesh) const
Assign interface boundary names to the mesh if applicable.
bool & smooth_after_generating()
PolygonSizeStyle
An enum class for style of input polygon size.