https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PolygonConcentricCircleMeshGeneratorBase.C
Go to the documentation of this file.
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
11#include "libmesh/mesh_smoother_laplace.h"
12#include "MooseUtils.h"
14#include "MooseMeshUtils.h"
15
16#include "libmesh/parsed_function.h"
17#include "libmesh/poly2tri_triangulator.h"
18
19#include <cmath>
20
23{
25 params.addRequiredRangeCheckedParam<std::vector<unsigned int>>(
26 "num_sectors_per_side",
27 "num_sectors_per_side>0",
28 "Number of azimuthal sectors per polygon side (rotating counterclockwise from top right "
29 "face).");
30 params.addRangeCheckedParam<unsigned int>(
31 "background_intervals",
32 1,
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.");
36 params.addRangeCheckedParam<Real>(
37 "background_radial_bias",
38 1.0,
39 "background_radial_bias>0",
40 "Value used to create biasing in radial meshing for background region.");
41 params.addRangeCheckedParam<Real>(
42 "background_inner_boundary_layer_width",
43 0.0,
44 "background_inner_boundary_layer_width>=0",
45 "Width of background region that is assigned to be the inner boundary layer.");
46 params.addRangeCheckedParam<unsigned int>(
47 "background_inner_boundary_layer_intervals",
48 1,
49 "background_inner_boundary_layer_intervals>0",
50 "Number of radial intervals of the background inner boundary layer");
51 params.addRangeCheckedParam<Real>(
52 "background_inner_boundary_layer_bias",
53 1.0,
54 "background_inner_boundary_layer_bias>0",
55 "Growth factor used for mesh biasing of the background inner boundary layer.");
56 params.addRangeCheckedParam<Real>(
57 "background_outer_boundary_layer_width",
58 0.0,
59 "background_outer_boundary_layer_width>=0",
60 "Width of background region that is assigned to be the outer boundary layer.");
61 params.addRangeCheckedParam<unsigned int>(
62 "background_outer_boundary_layer_intervals",
63 1,
64 "background_outer_boundary_layer_intervals>0",
65 "Number of radial intervals of the background outer boundary layer");
66 params.addRangeCheckedParam<Real>(
67 "background_outer_boundary_layer_bias",
68 1.0,
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.");
75 params.addParam<std::vector<Real>>(
76 "duct_sizes", "Distance(s) from polygon center to duct(s) inner boundaries.");
77 MooseEnum duct_sizes_style("apothem radius", "radius");
78 params.addParam<MooseEnum>(
79 "duct_sizes_style",
80 duct_sizes_style,
81 "Style in which polygon center to duct inner boundary distance is "
82 "given (apothem = center to face, radius = center to vertex). Options: " +
83 duct_sizes_style.getRawNames());
84 params.addRangeCheckedParam<std::vector<unsigned int>>(
85 "duct_intervals",
86 "duct_intervals>0",
87 "Number of meshing intervals in each enclosing duct excluding duct boundary layers.");
88 params.addRangeCheckedParam<std::vector<Real>>(
89 "duct_radial_biases",
90 "duct_radial_biases>0",
91 "Values used to create biasing in radial meshing for duct regions.");
92 params.addRangeCheckedParam<std::vector<Real>>(
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");
99 params.addRangeCheckedParam<std::vector<Real>>(
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.");
103 params.addRangeCheckedParam<std::vector<Real>>(
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");
110 params.addRangeCheckedParam<std::vector<Real>>(
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",
119 false,
120 "Whether the side elements are reorganized to have a uniform size.");
121 params.addParam<unsigned int>("smoothing_max_it",
122 0,
123 "Number of Laplacian smoothing iterations. This number is "
124 "disregarded when duct_sizes is present.");
125 params.addParam<bool>(
126 "flat_side_up",
127 false,
128 "Whether to rotate the generated polygon mesh to ensure that one flat side faces up.");
129
130 params.addParam<bool>(
131 "quad_center_elements", false, "Whether the center elements are quad or triangular.");
132 params.addRangeCheckedParam<Real>(
133 "center_quad_factor",
134 "center_quad_factor>0&center_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",
138 false,
139 "True to replace the inner ring mesh with a Delaunay unstructured mesh");
140 params.addParam<std::string>(
141 "inner_ring_desired_area",
142 std::string(),
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)");
145
147 "background_block_ids background_block_names duct_block_ids duct_block_names",
148 "Customized Subdomain/Boundary");
149 params.addParamNamesToGroup("num_sectors_per_side background_intervals duct_intervals "
150 "uniform_mesh_on_sides",
151 "General Mesh Density");
152 params.addParamNamesToGroup("quad_center_elements center_quad_factor "
153 "replace_inner_ring_with_delaunay_mesh inner_ring_desired_area ",
154 "Inner ring");
155
157 params.addClassDescription("This PolygonConcentricCircleMeshGeneratorBase object is a base class "
158 "to be inherited for polygon mesh generators.");
159
160 return params;
161}
162
164 const InputParameters & parameters)
165 : ConcentricCircleGeneratorBase(parameters),
166 _num_sides(isParamValid("num_sides")
167 ? getParam<unsigned int>("num_sides")
168 : (isParamValid("hexagon_size") ? (unsigned int)HEXAGON_NUM_SIDES
169 : (unsigned int)SQUARE_NUM_SIDES)),
170 _duct_sizes_style(getParam<MooseEnum>("duct_sizes_style").template getEnum<PolygonSizeStyle>()),
171 _duct_sizes(isParamValid("duct_sizes") ? getParam<std::vector<Real>>("duct_sizes")
172 : std::vector<Real>()),
173 _duct_intervals(isParamValid("duct_intervals")
174 ? getParam<std::vector<unsigned int>>("duct_intervals")
175 : std::vector<unsigned int>()),
176 _duct_radial_biases(isParamValid("duct_radial_biases")
177 ? getParam<std::vector<Real>>("duct_radial_biases")
178 : std::vector<Real>(_duct_intervals.size(), 1.0)),
179 _duct_inner_boundary_layer_params(
180 {isParamValid("duct_inner_boundary_layer_widths")
181 ? getParam<std::vector<Real>>("duct_inner_boundary_layer_widths")
182 : std::vector<Real>(_duct_intervals.size(), 0.0),
183 std::vector<Real>(),
184 isParamValid("duct_inner_boundary_layer_intervals")
185 ? getParam<std::vector<unsigned int>>("duct_inner_boundary_layer_intervals")
186 : std::vector<unsigned int>(_duct_intervals.size(), 0),
187 isParamValid("duct_inner_boundary_layer_biases")
188 ? getParam<std::vector<Real>>("duct_inner_boundary_layer_biases")
189 : std::vector<Real>(_duct_intervals.size(), 0.0)}),
190 _duct_outer_boundary_layer_params(
191 {isParamValid("duct_outer_boundary_layer_widths")
192 ? getParam<std::vector<Real>>("duct_outer_boundary_layer_widths")
193 : std::vector<Real>(_duct_intervals.size(), 0.0),
194 std::vector<Real>(),
195 isParamValid("duct_outer_boundary_layer_intervals")
196 ? getParam<std::vector<unsigned int>>("duct_outer_boundary_layer_intervals")
197 : std::vector<unsigned int>(_duct_intervals.size(), 0),
198 isParamValid("duct_outer_boundary_layer_biases")
199 ? getParam<std::vector<Real>>("duct_outer_boundary_layer_biases")
200 : std::vector<Real>(_duct_intervals.size(), 0.0)}),
201 _duct_block_ids(isParamValid("duct_block_ids")
202 ? getParam<std::vector<subdomain_id_type>>("duct_block_ids")
203 : std::vector<subdomain_id_type>()),
204 _duct_block_names(isParamValid("duct_block_names")
205 ? getParam<std::vector<SubdomainName>>("duct_block_names")
206 : std::vector<SubdomainName>()),
207 _has_rings(isParamValid("ring_radii")),
208 _has_ducts(isParamValid("duct_sizes")),
209 _polygon_size_style(
210 isParamValid("polygon_size_style")
211 ? getParam<MooseEnum>("polygon_size_style").template getEnum<PolygonSizeStyle>()
212 : (isParamValid("hexagon_size_style")
213 ? getParam<MooseEnum>("hexagon_size_style").template getEnum<PolygonSizeStyle>()
214 : getParam<MooseEnum>("square_size_style")
215 .template getEnum<PolygonSizeStyle>())),
216 _polygon_size(isParamValid("polygon_size")
217 ? getParam<Real>("polygon_size")
218 : (isParamValid("hexagon_size") ? getParam<Real>("hexagon_size")
219 : (getParam<Real>("square_size") /
220 2.0))), // square size is twice as apothem
221 _num_sectors_per_side(getParam<std::vector<unsigned int>>("num_sectors_per_side")),
222 _background_intervals(getParam<unsigned int>("background_intervals")),
223 // background is usually a single block; however, when there are no rings, background has two
224 // blocks.
225 _background_radial_bias(getParam<Real>("background_radial_bias")),
226 _background_inner_boundary_layer_params(
227 {getParam<Real>("background_inner_boundary_layer_width"),
228 0.0,
229 getParam<Real>("background_inner_boundary_layer_width") > 0.0
230 ? getParam<unsigned int>("background_inner_boundary_layer_intervals")
231 : 0,
232 getParam<Real>("background_inner_boundary_layer_bias")}),
234 {getParam<Real>("background_outer_boundary_layer_width"),
235 0.0,
236 getParam<Real>("background_outer_boundary_layer_width") > 0.0
237 ? getParam<unsigned int>("background_outer_boundary_layer_intervals")
238 : 0,
239 getParam<Real>("background_outer_boundary_layer_bias")}),
240 _background_block_ids(isParamValid("background_block_ids")
241 ? getParam<std::vector<subdomain_id_type>>("background_block_ids")
242 : std::vector<subdomain_id_type>()),
243 _background_block_names(isParamValid("background_block_names")
244 ? getParam<std::vector<SubdomainName>>("background_block_names")
245 : std::vector<SubdomainName>()),
246 _uniform_mesh_on_sides(getParam<bool>("uniform_mesh_on_sides")),
247 _quad_center_elements(getParam<bool>("quad_center_elements")),
248 _center_quad_factor(isParamValid("center_quad_factor") ? getParam<Real>("center_quad_factor")
249 : 0.0),
250 _smoothing_max_it(getParam<unsigned int>("smoothing_max_it")),
251 _sides_to_adapt(isParamValid("sides_to_adapt")
252 ? getParam<std::vector<unsigned int>>("sides_to_adapt")
253 : std::vector<unsigned int>()),
254 _node_id_background_meta(declareMeshProperty<dof_id_type>("node_id_background_meta", 0)),
255 _is_control_drum_meta(declareMeshProperty<bool>("is_control_drum_meta", false))
256{
257 declareMeshProperty<bool>("flat_side_up", getParam<bool>("flat_side_up"));
258 declareMeshProperty<unsigned int>("background_intervals_meta", 0);
259 declareMeshProperty<Real>("pattern_pitch_meta", 0.0);
260 declareMeshProperty<std::vector<Real>>("azimuthal_angle_meta", std::vector<Real>());
261 declareMeshProperty<Real>("max_radius_meta", 0.0);
262
263 const unsigned short tri_order = _tri_elem_type == TRI_ELEM_TYPE::TRI3 ? 1 : 2;
264 const unsigned short quad_order = _quad_elem_type == QUAD_ELEM_TYPE::QUAD4 ? 1 : 2;
265 // 1. If the central elements are quad, then no triangular elements are generated;
266 // 2. If the generated mesh has only one radial layer of triangular elements, then no
267 // quad elements are generated; (For PCCMG, that layer must be background)
268 // 3. Otherwise, both types of elements are generated.
269 _order = quad_order;
271 {
272 if (tri_order != quad_order)
274 }
275 else if (_ring_radii.empty() && _background_intervals == 1 &&
278 {
279 _order = tri_order;
280 if (tri_order != quad_order)
282 }
283 else if (tri_order != quad_order)
284 paramError("tri_element_type",
285 "the element types of triangular and quadrilateral elements must be compatible if "
286 "both types of elements are generated.");
287
288 // This error message is only reserved for future derived classes. Neither of the current derived
289 // classes will trigger this error.
291 paramError("sides_to_adapt", "If provided, the generated mesh must be a hexagon or a square.");
294 : _polygon_size * std::cos(M_PI / Real(_num_sides)));
295 declareMeshProperty<Real>("pitch_meta", _pitch);
296 if (_inward_interface_boundary_names.size() > 0 &&
298 paramError("inward_interface_boundary_names",
299 "If provided, the length of this parameter must be identical to the total number of "
300 "interfaces.");
301 if (_outward_interface_boundary_names.size() > 0 &&
303 paramError("outward_interface_boundary_names",
304 "If provided, the length of this parameter must be identical to the total number of "
305 "interfaces.");
306 const unsigned int num_total_background_layers =
309 if ((_has_rings || num_total_background_layers == 1) && _background_block_ids.size() > 1)
311 "background_block_ids",
312 "This parameter must be either unset or have a unity length when ring_radii is "
313 "provided or the number of background intervals (including boundary layers) is unity.");
314 if ((_has_rings || num_total_background_layers == 1) && _background_block_names.size() > 1)
316 "background_block_names",
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 && _quad_center_elements &&
320 _background_block_ids.size() == 1)
322 if ((!_has_rings && _background_intervals > 1) &&
323 (!_background_block_ids.empty() && _background_block_ids.size() != 2))
324 paramError("background_block_ids",
325 "This parameter must be either unset or have a length of two when ring_radii is not "
326 "provided and background intervals (including boundary layers) is not unity. It can "
327 "optionally to have a unity length if `quad_center_elements` is enabled.");
328 if (!_has_rings && num_total_background_layers > 1 && _quad_center_elements &&
329 _background_block_names.size() == 1)
332 if ((!_has_rings && _background_intervals > 1) &&
333 (!_background_block_names.empty() && _background_block_names.size() != 2))
334 paramError("background_block_names",
335 "This parameter must be either unset or have a length of two when ring_radii is not "
336 "provided and background intervals (including boundary layers) is not unity. It can "
337 "optionally have a unity length if `quad_center_elements` is enabled.");
338 if (_num_sectors_per_side.size() != _num_sides)
339 paramError("num_sectors_per_side",
340 "This parameter must have a length that is consistent with num_sides.");
341 for (auto it = _num_sectors_per_side.begin(); it != _num_sectors_per_side.end(); ++it)
342 if (*it % 2 == 1)
343 paramError("num_sectors_per_side", "This parameter must be even.");
344 declareMeshProperty("num_sectors_per_side_meta", _num_sectors_per_side);
345
346 if (!getParam<bool>("replace_inner_ring_with_delaunay_mesh") &&
347 isParamSetByUser("inner_ring_desired_area"))
349 "inner_ring_desired_area",
350 "This parameter should be set only when 'replace_inner_ring_with_delaunay_mesh=true'");
351
352 if (_has_rings)
353 {
354 const unsigned int num_innermost_ring_layers =
357 // If conditions are met, duplicate the first element of _ring_block_ids at the start.
358 if (!_ring_block_ids.empty() && _quad_center_elements && num_innermost_ring_layers > 1 &&
359 _ring_block_ids.size() == _ring_intervals.size())
360 _ring_block_ids.insert(_ring_block_ids.begin(), _ring_block_ids.front());
361 // check if the number of ring block ids is appropiate
362 if (!_ring_block_ids.empty() &&
363 _ring_block_ids.size() !=
364 (_ring_intervals.size() + (unsigned int)(num_innermost_ring_layers != 1)))
365 {
366 // Create an ostringstream for the debug information
367 std::ostringstream debug_info;
368 debug_info << "quad_center_elements is : " << (_quad_center_elements ? "true" : "false")
369 << std::endl;
370 debug_info << "ring_block_ids size is : " << _ring_block_ids.size() << std::endl;
371 debug_info << "ring_intervals size is : " << _ring_intervals.size() << std::endl;
372 debug_info << "number of innermost ring layers is : " << num_innermost_ring_layers
373 << std::endl;
374
375 // error message
377 {
379 "ring_block_ids",
380 "This parameter must have the appropriate size if it is provided: "
381 "Since the number of the innermost ring layers (" +
382 std::to_string(num_innermost_ring_layers) +
383 " :first ring interval and inner/outer boundaries of the first ring) is more than "
384 "one, and we have non-quad central elements, the size of 'ring_block_ids' must be "
385 "equal to the size of 'ring_intervals' + 1.\n",
386 debug_info.str());
387 }
388 else
389 {
391 "ring_block_ids",
392 "This parameter must have the appropriate size if it is provided: "
393 "Since the number of the innermost ring layers (" +
394 std::to_string(num_innermost_ring_layers) +
395 " :first ring interval and inner/outer boundaries of the first ring) is more than "
396 "one, and we have quad central elements, the size of 'ring_block_ids' can be either"
397 "equal to the size of 'ring_intervals' or 'ring_intervals' + 1.\n",
398 debug_info.str());
399 }
400 }
401 // If conditions are met, duplicate the first element of _ring_block_names at the start.
402 if (!_ring_block_names.empty() && _quad_center_elements && num_innermost_ring_layers > 1 &&
403 _ring_block_names.size() == _ring_intervals.size())
405 // check if the number of ring block names is appropiate
406 if (!_ring_block_names.empty() &&
407 _ring_block_names.size() !=
408 (_ring_intervals.size() + (unsigned int)(num_innermost_ring_layers != 1)))
409 {
410 // Create an ostringstream for the debug information
411 std::ostringstream debug_info;
412 debug_info << "quad_center_elements is : " << (_quad_center_elements ? "true" : "false")
413 << std::endl;
414 debug_info << "ring_block_names size is : " << _ring_block_names.size() << std::endl;
415 debug_info << "ring_intervals size is : " << _ring_intervals.size() << std::endl;
416 debug_info << "number of innermost ring layers is : " << num_innermost_ring_layers
417 << std::endl;
418
419 // error message
421 {
423 "ring_block_names",
424 "This parameter must have the appropriate size if it is provided: "
425 "Since the number of the innermost ring layers (" +
426 std::to_string(num_innermost_ring_layers) +
427 " :first ring interval and inner/outer boundaries of the first ring) is more than "
428 "one, and we have non-quad central elements, the size of 'ring_block_names' must "
429 "be equal to the size of 'ring_intervals' + 1.\n",
430 debug_info.str());
431 }
432 else
433 {
435 "ring_block_names",
436 "This parameter must have the appropriate size if it is provided: "
437 "Since the number of the innermost ring layers (" +
438 std::to_string(num_innermost_ring_layers) +
439 " :first ring interval and inner/outer boundaries of the first ring) is more than "
440 "one, and we have quad central elements, the size of 'ring_block_names' can be "
441 "either equal to the size of 'ring_intervals' or 'ring_intervals' + 1.\n",
442 debug_info.str());
443 }
444 }
445 for (unsigned int i = 0; i < _ring_radii.size(); i++)
446 {
447 const Real layer_width = _ring_radii[i] - (i == 0 ? 0.0 : _ring_radii[i - 1]);
452 }
453 for (unsigned int i = 0; i < _ring_inner_boundary_layer_params.fractions.size(); i++)
454 if (MooseUtils::absoluteFuzzyEqual(_ring_inner_boundary_layer_params.fractions[i], 0.0) &&
456 paramError("ring_inner_boundary_layer_intervals",
457 "Ring inner boundary layer must have zero interval if its thickness is zero.");
458 else if (MooseUtils::absoluteFuzzyGreaterThan(_ring_inner_boundary_layer_params.fractions[i],
459 0.0) &&
461 paramError("ring_inner_boundary_layer_intervals",
462 "Ring inner boundary layer must have non-zero interval if its thickness is "
463 "not zero.");
464 for (unsigned int i = 0; i < _ring_outer_boundary_layer_params.fractions.size(); i++)
465 {
466 if (MooseUtils::absoluteFuzzyEqual(_ring_outer_boundary_layer_params.fractions[i], 0.0) &&
468 paramError("ring_outer_boundary_layer_intervals",
469 "Ring outer boundary layer must have zero interval if its thickness is zero.");
470 else if (MooseUtils::absoluteFuzzyGreaterThan(_ring_outer_boundary_layer_params.fractions[i],
471 0.0) &&
473 paramError("ring_outer_boundary_layer_intervals",
474 "Ring outer boundary layer must have non-zero interval if its thickness is "
475 "not zero.");
478 1.0)
479 paramError("ring_inner_boundary_layer_widths",
480 "Summation of ring_inner_boundary_layer_widths and "
481 "ring_outer_boundary_layer_widths cannot exceeds the ring layer width.");
482 }
483 }
484 // Ducts related error messages
485 if (_duct_sizes.size() != _duct_intervals.size())
486 paramError("duct_sizes", "This parameter and duct_intervals must have the same length.");
487 if (_duct_sizes.size() != _duct_radial_biases.size())
488 paramError("duct_sizes", "This parameter and duct_radial_biases must have the same length.");
489 if (!_duct_block_ids.empty() && _duct_block_ids.size() != _duct_intervals.size())
490 paramError("duct_block_ids",
491 "This parameter must have the same length as duct_intervals if set.");
492 if (!_duct_block_names.empty() && _duct_block_names.size() != _duct_intervals.size())
493 paramError("duct_block_names",
494 "This parameter must have the same length as duct_intervals if set.");
501 paramError("duct_sizes",
502 "The inner and outer duct boundary layer parameters must have the same sizes as "
503 "duct_sizes.");
504 if (_has_ducts)
505 {
507 for (unsigned int i = 0; i < _duct_sizes.size(); i++)
508 _duct_sizes[i] /= std::cos(M_PI / Real(_num_sides));
509 for (unsigned int i = 1; i < _duct_sizes.size(); i++)
510 if (_duct_sizes[i] <= _duct_sizes[i - 1])
511 paramError("duct_sizes", "This parameter must be strictly ascending.");
512 if (_duct_sizes.front() <=
513 (_has_rings ? _ring_radii.back() / std::cos(M_PI / Real(_num_sides)) : 0.0))
514 paramError("duct_sizes",
515 "This parameter must be positive and ensures no overlapping with rings.");
516 if (_duct_sizes.back() >= _pitch / 2.0 / std::cos(M_PI / Real(_num_sides)))
517 paramError("duct_sizes",
518 "This parameter must ensure that ducts are smaller than the polygon size.");
519 if (*std::min_element(_duct_intervals.begin(), _duct_intervals.end()) <= 0)
520 paramError("duct_intervals", "Elements of this parameter must be positive.");
522 for (unsigned int i = 0; i < _duct_sizes.size(); i++)
523 {
526 }
527 for (unsigned int i = 0; i < _duct_sizes.size(); i++)
528 {
529 const Real layer_width =
530 (i == _duct_sizes.size() - 1 ? _pitch / 2.0 / std::cos(M_PI / Real(_num_sides))
531 : _duct_sizes[i + 1]) -
532 _duct_sizes[i];
537 }
538 for (unsigned int i = 0; i < _duct_inner_boundary_layer_params.fractions.size(); i++)
539 if (MooseUtils::absoluteFuzzyEqual(_duct_inner_boundary_layer_params.fractions[i], 0.0) &&
541 paramError("duct_inner_boundary_layer_intervals",
542 "Duct inner boundary layer must have zero interval if its thickness is zero.");
543 else if (MooseUtils::absoluteFuzzyGreaterThan(_duct_inner_boundary_layer_params.fractions[i],
544 0.0) &&
546 paramError("duct_inner_boundary_layer_intervals",
547 "Duct inner boundary layer must have non-zero interval if its thickness is "
548 "not zero.");
549 for (unsigned int i = 0; i < _duct_outer_boundary_layer_params.fractions.size(); i++)
550 {
551 if (MooseUtils::absoluteFuzzyEqual(_duct_outer_boundary_layer_params.fractions[i], 0.0) &&
553 paramError("duct_outer_boundary_layer_intervals",
554 "Duct outer boundary layer must have zero interval if its thickness is zero.");
555 else if (MooseUtils::absoluteFuzzyGreaterThan(_duct_outer_boundary_layer_params.fractions[i],
556 0.0) &&
558 paramError("duct_outer_boundary_layer_intervals",
559 "Duct outer boundary layer must have non-zero interval if its thickness is "
560 "not zero.");
563 1.0)
564 paramError("duct_inner_boundary_layer_widths",
565 "Summation of duct_inner_boundary_layer_widths and "
566 "duct_outer_boundary_layer_widths cannot exceeds the duct layer width.");
567 }
568 }
569 if (MooseUtils::absoluteFuzzyGreaterThan(_background_inner_boundary_layer_params.width +
571 0.0))
572 {
573 const Real min_background_thickness =
574 (_has_ducts ? (_duct_sizes.front() * std::cos(M_PI / Real(_num_sides))) : (_pitch / 2.0)) -
575 (_has_rings ? _ring_radii.back() : 0.0);
579 ? 1.0
580 : std::cos(M_PI / Real(_num_sides))) >=
581 min_background_thickness)
582 paramError("background_inner_boundary_layer_width",
583 "The summation of background_inner_boundary_layer_width and "
584 "background_outer_boundary_layer_width must be less than the minimum thickness of "
585 "the background region.");
588 }
590 paramError("center_quad_factor",
591 "this parameter is only applicable if quad_center_elements is set true.");
593 declareMeshProperty<subdomain_id_type>(
594 "quad_center_block_id",
597 : _background_block_ids.front()));
598 else
599 declareMeshProperty<subdomain_id_type>("quad_center_block_id",
600 libMesh::Elem::invalid_subdomain_id);
601
602 // declare metadata for internal interface boundaries
603 declareMeshProperty<bool>("interface_boundaries", false);
604 declareMeshProperty<std::set<boundary_id_type>>("interface_boundary_ids", {});
605}
606
607std::unique_ptr<MeshBase>
609{
610 std::vector<std::unique_ptr<ReplicatedMesh>> input(_input_ptrs.size());
611 for (const auto i : index_range(_input_ptrs))
612 {
613 input[i] = dynamic_pointer_cast<ReplicatedMesh>(std::move(*_input_ptrs[i]));
614 if (!input[i])
615 mooseError("A non-replicated mesh input was supplied but replicated meshes are required.");
616 if ((_order == 1 && (*input[i]->elements_begin())->default_order() != FIRST) ||
617 (_order == 2 && (*input[i]->elements_begin())->default_order() == FIRST))
618 paramError("tri_element_type",
619 "The order of the input mesh to be adapted to does not match the order of the "
620 "mesh to be generated.");
621 }
622
623 unsigned int mesh_input_counter = 0;
624 // azimuthal array used for radius radius_correction
625 std::vector<Real> azimuthal_list;
626 // loop over all sides of the polygon to collect azimuthal angles of all nodes
627 for (unsigned int mesh_index = 0; mesh_index < _num_sides; mesh_index++)
628 {
629 // When adaptive boundaries exist (only possible for hexagon meshes thru
630 // `HexagonConcentricCircleAdaptiveBoundaryMeshGenerator` or square meshes thru
631 // `CartesianConcentricCircleAdaptiveBoundaryMeshGenerator`), nodes' azimuthal angle cannot be
632 // arithmetically obtained. Instead, `azimuthalAnglesCollector() is used to get this
633 // information from the mesh directly.`
634 if (std::find(_sides_to_adapt.begin(), _sides_to_adapt.end(), mesh_index) !=
635 _sides_to_adapt.end())
636 {
637 // The following lines only work for hexagon and square; and only a hexagon or a square needs
638 // such functionality.
639 Real lower_azi =
640 _num_sides == 6 ? ((Real)mesh_index * 60.0 - 150.0) : ((Real)mesh_index * 90.0 - 135.0);
641 Real upper_azi = _num_sides == 6 ? ((Real)((mesh_index + 1) % 6) * 60.0 - 150.0)
642 : ((Real)((mesh_index + 1) % 4) * 90.0 - 135.0);
644 *input[mesh_input_counter], lower_azi, upper_azi, ANGLE_TANGENT, _num_sides));
645 // loop over the _azimuthal_angles_array just collected to convert tangent to azimuthal
646 // angles.
647 for (unsigned int i = 1; i < _azimuthal_angles_array.back().size(); i++)
648 {
649 azimuthal_list.push_back(
650 _num_sides == 6
651 ? ((Real)mesh_index * 60.0 - 150.0 +
652 std::atan((_azimuthal_angles_array.back()[i - 1] - 1.0) / std::sqrt(3.0)) *
653 180.0 / M_PI)
654 : ((Real)mesh_index * 90.0 - 135.0 +
655 std::atan((_azimuthal_angles_array.back()[i - 1] - 1.0)) * 180.0 / M_PI));
656 }
657 mesh_input_counter++;
658 }
659 else
660 {
661 _azimuthal_angles_array.push_back(std::vector<Real>());
662 for (unsigned int i = 0; i < _num_sectors_per_side[mesh_index] * _order; i++)
663 {
664 azimuthal_list.push_back(
665 std::atan(
666 std::tan(M_PI / _num_sides) *
667 (2.0 * (Real)i / (Real)_num_sectors_per_side[mesh_index] / (Real)_order - 1.0)) *
668 180.0 / M_PI +
669 (Real)mesh_index * (360.0 / (Real)_num_sides) - (180.0 - 180.0 / (Real)_num_sides));
670 }
671 }
672 }
673 std::vector<Real> ring_radii_corr;
674 if (_has_rings)
675 {
677 {
678 Real corr_factor =
680 for (unsigned int i = 0; i < _ring_radii.size(); i++)
681 ring_radii_corr.push_back(_ring_radii[i] * corr_factor);
682 }
683 else
684 ring_radii_corr = _ring_radii;
685 if (ring_radii_corr.back() >= _pitch / 2.0)
686 paramError("ring_radii",
687 "Elements of this parameter must be smaller than polygon apothem (after volume "
688 "preserve correction if applicable).");
689 setMeshProperty("max_radius_meta", ring_radii_corr.back());
690 }
691 // build the first slice of the polygon.
692 auto mesh0 = buildSimpleSlice(ring_radii_corr,
702 _pitch,
710 1,
721 // This loop builds add-on slices and stitches them to the first slice
722 for (unsigned int mesh_index = 1; mesh_index < _num_sides; mesh_index++)
723 {
724 auto mesh_tmp = buildSimpleSlice(ring_radii_corr,
734 _pitch,
735 _num_sectors_per_side[mesh_index],
742 mesh_index + 1,
743 _azimuthal_angles_array[mesh_index],
753
754 ReplicatedMesh other_mesh(*mesh_tmp);
755 MeshTools::Modification::rotate(other_mesh, 360.0 / _num_sides * mesh_index, 0, 0);
756 mesh0->prepare_for_use();
757 other_mesh.prepare_for_use();
758 mesh0->stitch_meshes(other_mesh, SLICE_BEGIN, SLICE_END, TOLERANCE, true, false);
759 other_mesh.clear();
760 }
761
762 // An extra step to stich the first and last slices together
763 mesh0->stitch_surfaces(SLICE_BEGIN, SLICE_END, TOLERANCE, true, false);
764
766 MooseMesh::changeBoundaryId(*mesh0, 1 + _interface_boundary_id_shift, OUTER_SIDESET_ID, false);
767
769 {
770 setMeshProperty("azimuthal_angle_meta",
771 azimuthalAnglesCollector(*mesh0, -180.0, 180.0, ANGLE_DEGREE));
772 setMeshProperty("pattern_pitch_meta", _pitch);
773 }
774
775 // Move nodes on the external boundary for force uniform spacing.
777 {
778 const Real angle_tol = 1.0e-5;
779 std::vector<std::pair<Real, unsigned int>> node_azi_list;
780 MeshTools::Modification::rotate(*mesh0, -(270.0 - 360.0 / (Real)_num_sides), 0.0, 0.0);
781 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> side_list =
782 mesh0->get_boundary_info().build_side_list();
783 mesh0->get_boundary_info().build_node_list_from_side_list();
784 std::vector<std::tuple<dof_id_type, boundary_id_type>> node_list =
785 mesh0->get_boundary_info().build_node_list();
786
787 for (unsigned int i = 0; i < node_list.size(); ++i)
788 {
789 if (std::get<1>(node_list[i]) == OUTER_SIDESET_ID)
790 {
791 node_azi_list.push_back(
792 std::make_pair(atan2((*mesh0->node_ptr(std::get<0>(node_list[i])))(1),
793 (*mesh0->node_ptr(std::get<0>(node_list[i])))(0)) *
794 180.0 / M_PI,
795 std::get<0>(node_list[i])));
796 if (std::abs(node_azi_list.back().first + 180.0) <= angle_tol)
797 node_azi_list.back().first = 180.0;
798 }
799 }
800 std::sort(node_azi_list.begin(), node_azi_list.end());
801 for (unsigned int i = 0; i < _num_sides; i++)
802 {
803 for (unsigned int j = 1; j <= _num_sectors_per_side[i]; j++)
804 {
805 Real azi_corr_tmp = atan2((Real)j * 2.0 / (Real)_num_sectors_per_side[i] - 1.0,
806 1.0 / std::tan(M_PI / (Real)_num_sides));
807 Real x_tmp = _pitch / 2.0;
808 Real y_tmp = x_tmp * std::tan(azi_corr_tmp);
810 x_tmp, y_tmp, (Real)i * 360.0 / (Real)_num_sides - (180.0 - 180.0 / (Real)_num_sides));
811 Point p_tmp = Point(x_tmp, y_tmp, 0.0);
812 mesh0->add_point(
813 p_tmp,
814 node_azi_list[std::accumulate(
815 _num_sectors_per_side.begin(), _num_sectors_per_side.begin() + i, 0) +
816 j - 1]
817 .second);
818 }
819 }
820 MeshTools::Modification::rotate(*mesh0, (270.0 - 360.0 / (Real)_num_sides), 0.0, 0.0);
821 }
822
823 setMeshProperty("background_intervals_meta", _background_intervals);
824
825 if (!_has_ducts && _sides_to_adapt.empty())
826 {
828 lms.smooth();
829 }
830
831 // Set up customized Block Names and/or IDs
832 unsigned int block_it = 0;
833 unsigned ring_block_num = 0;
834 std::vector<subdomain_id_type> block_ids_old;
835 std::vector<subdomain_id_type> block_ids_new;
836 std::vector<SubdomainName> block_names;
837 if (_has_rings)
838 {
839 ringBlockIdsNamesPreparer(block_it, ring_block_num, block_ids_old, block_ids_new, block_names);
840 }
841 else
842 {
843 if (_background_intervals > 1)
844 {
845 block_ids_old.push_back(_block_id_shift + 1 + block_it);
846 block_ids_new.push_back(_background_block_ids.empty() ? block_ids_old.back()
847 : _background_block_ids.front());
848 block_names.push_back(_background_block_names.empty()
849 ? (SubdomainName)std::to_string(block_ids_new.back())
850 : _background_block_names.front());
851 block_it++;
852 }
853 }
854 block_ids_old.push_back(_block_id_shift + 1 + block_it);
855 block_ids_new.push_back(_background_block_ids.empty() ? block_ids_old.back()
856 : _background_block_ids.back());
857 block_names.push_back(_background_block_names.empty()
858 ? (SubdomainName)std::to_string(block_ids_new.back())
859 : _background_block_names.back());
860 block_it++;
861 if (_has_ducts)
862 {
863 for (unsigned int i = 0; i < _duct_intervals.size(); i++)
864 {
865 block_ids_old.push_back(_block_id_shift + 1 + block_it);
866 block_ids_new.push_back(_duct_block_ids.empty() ? block_ids_old.back() : _duct_block_ids[i]);
867 block_names.push_back(_duct_block_names.empty()
868 ? (SubdomainName)std::to_string(block_ids_new.back())
869 : _duct_block_names[i]);
870 block_it++;
871 }
872 }
873
875 *mesh0, block_ids_old, block_ids_new, block_names, "ConcentricCircleMeshGenerator");
876
877 if (_external_boundary_id > 0)
878 MooseMesh::changeBoundaryId(*mesh0, OUTER_SIDESET_ID, _external_boundary_id, false);
879 if (!_external_boundary_name.empty())
880 {
881 mesh0->get_boundary_info().sideset_name(
884 mesh0->get_boundary_info().nodeset_name(
887 }
888
890
891 // add sector ids
892 if (isParamValid("sector_id_name"))
894 *mesh0, getParam<std::string>("sector_id_name"), _num_sides, _num_sectors_per_side);
895
896 // add ring ids
897 if (isParamValid("ring_id_name"))
898 setRingExtraIDs(*mesh0,
899 getParam<std::string>("ring_id_name"),
903 getParam<MooseEnum>("ring_id_assign_type") == "ring_wise",
905
906 // add internal side set info to metadata
908 {
909 setMeshProperty("interface_boundaries", true);
910 // lists boundary ids assigned to interfaces
911 std::set<boundary_id_type> boundary_ids = mesh0->get_boundary_info().get_boundary_ids();
912 std::set<boundary_id_type> interface_boundary_ids;
914 {
915 const unsigned int num_boundary_ids = boundary_ids.size();
916 for (const auto i : make_range(num_boundary_ids))
917 {
918 const unsigned int id = i * 2 + 1 + _interface_boundary_id_shift;
919 auto it = boundary_ids.find(id);
920 if (it != boundary_ids.end())
921 {
922 boundary_ids.erase(it);
923 interface_boundary_ids.insert(id);
924 }
925 }
926 }
928 {
929 const unsigned int num_boundary_ids = boundary_ids.size();
930 for (const auto i : make_range(num_boundary_ids))
931 {
932 const unsigned int id = i * 2 + 2 + _interface_boundary_id_shift;
933 auto it = boundary_ids.find(id);
934 if (it != boundary_ids.end())
935 {
936 boundary_ids.erase(it);
937 interface_boundary_ids.insert(id);
938 }
939 }
940 }
941 setMeshProperty("interface_boundary_ids", interface_boundary_ids);
942 }
943
944 bool flat_side_up = getMeshProperty<bool>("flat_side_up", name());
945 if (flat_side_up)
946 MeshTools::Modification::rotate(*mesh0, 180.0 / (Real)_num_sides, 0.0, 0.0);
947 mesh0->unset_is_prepared();
948
949 if (_has_rings && getParam<bool>("replace_inner_ring_with_delaunay_mesh"))
950 {
951 if (isParamSetByUser("quad_center_elements"))
952 paramError("quad_center_elements",
953 "Should not be set because the center elements of the inner ring will be replaced "
954 "by a Delaunay mesh with 'replace_inner_ring_with_delaunay_mesh=true'");
955
956 // remove elements of the inner ring and create an inner-ring external boundary side set
957 std::set<Elem *> deleteable_elems;
958 for (auto & elem : mesh0->element_ptr_range())
959 if (elem->vertex_average().norm() < ring_radii_corr[0])
960 deleteable_elems.insert(elem);
961
962 const boundary_id_type boundary_id = MooseMeshUtils::getBoundaryIDs(*mesh0, {"_foo"}, true)[0];
963 BoundaryInfo & boundary_info = mesh0->get_boundary_info();
964 for (auto & elem : deleteable_elems)
965 {
966 unsigned int n_sides = elem->n_sides();
967 for (unsigned int n = 0; n != n_sides; ++n)
968 {
969 Elem * neighbor = elem->neighbor_ptr(n);
970 if (!neighbor)
971 continue;
972
973 const unsigned int return_side = neighbor->which_neighbor_am_i(elem);
974
975 if (neighbor->neighbor_ptr(return_side) == elem)
976 {
977 neighbor->set_neighbor(return_side, nullptr);
978 boundary_info.add_side(neighbor, return_side, boundary_id);
979 }
980 }
981
982 mesh0->delete_elem(elem);
983 }
984
985 // build the 1d mesh from the new boundary
986 auto poly_mesh = MooseMeshUtils::buildBoundaryMesh(*mesh0, boundary_id);
987 Real min_side = std::numeric_limits<Real>::max();
988 for (auto & elem : poly_mesh->element_ptr_range())
989 {
990 Real l = elem->volume();
991 if (l < min_side)
992 min_side = l;
993 }
994
995 // triangulate with the 1d mesh
996 libMesh::Poly2TriTriangulator poly2tri(*poly_mesh);
997 poly2tri.triangulation_type() = libMesh::TriangulatorInterface::PSLG;
999 poly2tri.set_refine_boundary_allowed(false);
1000 poly2tri.set_verify_hole_boundaries(false);
1001 const auto desired_area = getParam<std::string>("inner_ring_desired_area");
1002 if (desired_area != "")
1003 {
1004 poly2tri.desired_area() = 0;
1005 libMesh::ParsedFunction<Real> area_func{desired_area};
1006 poly2tri.set_desired_area_function(&area_func);
1007 }
1008 else
1009 poly2tri.desired_area() = min_side * min_side;
1010 poly2tri.minimum_angle() = 0;
1011 poly2tri.smooth_after_generating() = true;
1012 // poly2tri.elem_type() is TRI3 by default
1014 poly2tri.elem_type() = libMesh::ElemType::TRI6;
1016 {
1017 poly2tri.elem_type() = libMesh::ElemType::TRI7;
1018 // Move the TRI7 interior node to the curved-mapping centroid after the
1019 // boundary mid-edge nodes are snapped; see MeshTriangulationUtils.C.
1020 poly2tri.set_fixup_tri7_center_nodes(true);
1021 }
1022 // let us keep the center point
1023 poly_mesh->add_point(libMesh::Point());
1024 poly2tri.triangulate();
1025 // keep the old subdomain id
1026 for (auto elem : poly_mesh->element_ptr_range())
1027 elem->subdomain_id() = block_ids_new[0];
1028
1029 if (isParamValid("ring_id_name"))
1030 {
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);
1042 }
1043 if (isParamValid("sector_id_name"))
1044 {
1045 // we will assign all elements in the inner ring with zero sector id
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);
1050 }
1051
1052 // stitch the triangulated mesh and the original mesh without the inner ring
1053 mesh0->stitch_meshes(*poly_mesh, boundary_id, 0, TOLERANCE, true, false);
1054 }
1055
1056 return dynamic_pointer_cast<MeshBase>(mesh0);
1057}
void ErrorVector unsigned int
This ConcentricCircleGeneratorBase object is a base class to be inherited for mesh generators that in...
unsigned short _order
Order of the elements to be generated.
const std::vector< Real > _ring_radial_biases
Bias values used to induce biasing to radial meshing in ring regions.
const boundary_id_type _interface_boundary_id_shift
Shift in default boundary IDs of interfaces to avert potential conflicts.
QUAD_ELEM_TYPE _quad_elem_type
Type of quadrilateral elements to be generated.
std::vector< subdomain_id_type > _ring_block_ids
Subdomain IDs of the ring regions.
const BoundaryName _external_boundary_name
Boundary Name of the mesh's external boundary.
multiBdryLayerParams _ring_inner_boundary_layer_params
Widths, fractions, radial sectors and growth factors of the inner boundary layers of the ring regions...
const std::vector< std::string > _inward_interface_boundary_names
Boundary Names of the mesh's inward interface boundaries.
const boundary_id_type _external_boundary_id
Boundary ID of the mesh's external boundary.
const bool _preserve_volumes
Volume preserving function is optional.
std::vector< SubdomainName > _ring_block_names
Subdomain Names of the ring regions.
const subdomain_id_type _block_id_shift
Shift in default subdomain IDs to avert potential conflicts with other meshes.
const std::vector< std::string > _outward_interface_boundary_names
Boundary Names of the mesh's outward interface boundaries.
multiBdryLayerParams _ring_outer_boundary_layer_params
Widths, fractions, radial sectors and growth factors of the outer boundary layers of the ring regions...
const std::vector< unsigned int > _ring_intervals
Number of rings in each circle or in the enclosing square.
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.
const std::vector< Real > _ring_radii
Radii of concentric circles.
const bool _generate_side_specific_boundaries
Whether the side-specific external boundaries are generated or not.
void assignInterfaceBoundaryNames(ReplicatedMesh &mesh) const
Assign interface boundary names to the mesh if applicable.
const bool _create_inward_interface_boundaries
Whether inward interface boundaries are created.
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.
const bool _create_outward_interface_boundaries
Whether outward interface boundaries are created.
TRI_ELEM_TYPE _tri_elem_type
Type of triangular elements to be generated.
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
T & setMeshProperty(const std::string &data_name, Args &&... args)
T & declareMeshProperty(const std::string &data_name, Args &&... args)
const std::string & name() const
void paramError(const std::string &param, Args... args) const
bool isParamSetByUser(const std::string &name) const
void mooseError(Args &&... args) const
const T & getParam(const std::string &name) const
bool isParamValid(const std::string &name) const
const std::vector< SubdomainName > _duct_block_names
Subdomain Names of the duct regions.
const bool _quad_center_elements
Whether the central elements need to be QUAD4.
const bool _has_ducts
Whether the generated mesh contains duct regions.
multiBdryLayerParams _duct_outer_boundary_layer_params
Widths, fractions, radial sectors and growth factors of the inner boundary layers of the duct regions...
bool _is_general_polygon
MeshMetaData: whether this produced mesh is a general polygon (or a hexagon)
const Real _center_quad_factor
A fractional radius factor used to determine the radial positions of transition nodes in the center r...
const std::vector< subdomain_id_type > _duct_block_ids
Subdomain IDs of the duct regions.
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...
std::vector< Real > _duct_sizes
Size parameters of the duct regions.
const bool _uniform_mesh_on_sides
Whether the nodes on the external boundary needs to be uniformly distributed.
const bool _has_rings
Whether the generated mesh contains ring regions.
singleBdryLayerParams _background_outer_boundary_layer_params
Width, fraction, radiation sectors and growth factor of the outer boundary layer of the background re...
std::vector< subdomain_id_type > _background_block_ids
Subdomain IDs of the background regions.
const Real _background_radial_bias
Bias value used to induce biasing to radial meshing in background region.
const PolygonSizeStyle _duct_sizes_style
Thickness of each enclosing duct.
const PolygonSizeStyle _polygon_size_style
Type of polygon size parameter.
const std::vector< unsigned int > _num_sectors_per_side
Mesh sector number of each polygon side.
const std::vector< unsigned int > _duct_intervals
Number of layers in each enclosing duct.
dof_id_type & _node_id_background_meta
MeshMetaData: maximum node id of the background region.
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< Real > _duct_radial_biases
Bias values used to induce biasing to radial meshing in duct regions.
std::vector< std::unique_ptr< MeshBase > * > _input_ptrs
Pointers to input mesh pointers.
const unsigned int _background_intervals
Numbers of radial intervals of the background regions.
bool & _is_control_drum_meta
MeshMetaData: whether this produced mesh is a control drum.
const unsigned int _smoothing_max_it
Maximum smooth iteration number.
std::vector< std::vector< Real > > _azimuthal_angles_array
Azimuthal angles of all radial nodes for volume preservation.
const std::vector< unsigned int > _sides_to_adapt
Indices of the hexagon sides that need to adapt.
PolygonConcentricCircleMeshGeneratorBase(const InputParameters &parameters)
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.
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
PolygonSizeStyle
An enum class for style of input polygon size.
static void addRingAndSectorIDParams(InputParameters &params)
Add InputParameters which are used by ring and sector IDs.
void nodeCoordRotate(Real &x, Real &y, const Real theta) const
Calculates x and y coordinates after rotating by theta angle.
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
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.
virtual void smooth() override
virtual void set_refine_boundary_allowed(bool refine_bdy_allowed) override
virtual void set_desired_area_function(FunctionBase< Real > *desired) override
virtual void triangulate() override
TriangulationType & triangulation_type()
void set_verify_hole_boundaries(bool v)
void set_fixup_tri7_center_nodes(bool v)
void set_interpolate_boundary_points(int n_points)
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template cos(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(cos
std::unique_ptr< ReplicatedMesh > buildBoundaryMesh(const MeshBase &input_mesh, const boundary_id_type boundary_id)
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
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.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real