https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PolygonMeshGeneratorBase.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 "MooseUtils.h"
12#include "FormattedTable.h"
13
14#include <cmath>
15#include <iomanip>
16
19{
22 "A base class that contains common members for Reactor module mesh generators.");
23
24 return params;
25}
26
31
32std::unique_ptr<MeshBase>
34{
35 auto mesh = buildReplicatedMesh(2); // initiate a 2D mesh
36 return dynamic_pointer_cast<MeshBase>(mesh);
37}
38
39std::unique_ptr<ReplicatedMesh>
41 std::vector<Real> ring_radii,
42 const std::vector<unsigned int> ring_layers,
43 const std::vector<Real> ring_radial_biases,
44 const multiBdryLayerParams & ring_inner_boundary_layer_params,
45 const multiBdryLayerParams & ring_outer_boundary_layer_params,
46 std::vector<Real> ducts_center_dist,
47 const std::vector<unsigned int> ducts_layers,
48 const std::vector<Real> duct_radial_biases,
49 const multiBdryLayerParams & duct_inner_boundary_layer_params,
50 const multiBdryLayerParams & duct_outer_boundary_layer_params,
51 const Real primary_side_length,
52 const Real secondary_side_length,
53 const unsigned int num_sectors_per_side,
54 const unsigned int background_intervals,
55 const Real background_radial_bias,
56 const singleBdryLayerParams & background_inner_boundary_layer_params,
57 const singleBdryLayerParams & background_outer_boundary_layer_params,
58 dof_id_type & node_id_background_meta,
59 const Real azimuthal_angle,
60 const std::vector<Real> azimuthal_tangent,
61 const unsigned int side_index,
62 const bool quad_center_elements,
63 const Real center_quad_factor,
64 const Real rotation_angle,
65 const bool generate_side_specific_boundaries)
66{
67 const Real virtual_pitch = 2.0 * primary_side_length * cos(azimuthal_angle / 360.0 * M_PI);
68 const Real virtual_side_number = 360.0 / azimuthal_angle;
69 const Real pitch_scale_factor = secondary_side_length / primary_side_length;
70
71 auto mesh = buildSlice(ring_radii,
72 ring_layers,
73 ring_radial_biases,
74 ring_inner_boundary_layer_params,
75 ring_outer_boundary_layer_params,
76 ducts_center_dist,
77 ducts_layers,
78 duct_radial_biases,
79 duct_inner_boundary_layer_params,
80 duct_outer_boundary_layer_params,
81 virtual_pitch,
82 num_sectors_per_side,
83 background_intervals,
84 background_radial_bias,
85 background_inner_boundary_layer_params,
86 background_outer_boundary_layer_params,
87 node_id_background_meta,
88 virtual_side_number,
89 side_index,
90 azimuthal_tangent,
91 0,
92 quad_center_elements,
93 center_quad_factor,
94 false,
95 true,
96 0,
97 pitch_scale_factor,
98 generate_side_specific_boundaries);
99 MeshTools::Modification::rotate(*mesh, rotation_angle, 0, 0);
100 return mesh;
101}
102
103std::unique_ptr<ReplicatedMesh>
105 std::vector<Real> ring_radii,
106 const std::vector<unsigned int> ring_layers,
107 const std::vector<Real> ring_radial_biases,
108 const multiBdryLayerParams & ring_inner_boundary_layer_params,
109 const multiBdryLayerParams & ring_outer_boundary_layer_params,
110 std::vector<Real> ducts_center_dist,
111 const std::vector<unsigned int> ducts_layers,
112 const std::vector<Real> duct_radial_biases,
113 const multiBdryLayerParams & duct_inner_boundary_layer_params,
114 const multiBdryLayerParams & duct_outer_boundary_layer_params,
115 const Real pitch,
116 const unsigned int num_sectors_per_side,
117 const unsigned int background_intervals,
118 const Real background_radial_bias,
119 const singleBdryLayerParams & background_inner_boundary_layer_params,
120 const singleBdryLayerParams & background_outer_boundary_layer_params,
121 dof_id_type & node_id_background_meta,
122 const unsigned int side_number,
123 const unsigned int side_index,
124 const std::vector<Real> azimuthal_tangent,
125 const subdomain_id_type block_id_shift,
126 const bool quad_center_elements,
127 const Real center_quad_factor,
128 const bool create_inward_interface_boundaries,
129 const bool create_outward_interface_boundaries,
130 const boundary_id_type boundary_id_shift,
131 const bool generate_side_specific_boundaries,
132 const TRI_ELEM_TYPE tri_elem_type,
133 const QUAD_ELEM_TYPE quad_elem_type)
134{
135 return buildSlice(ring_radii,
136 ring_layers,
137 ring_radial_biases,
138 ring_inner_boundary_layer_params,
139 ring_outer_boundary_layer_params,
140 ducts_center_dist,
141 ducts_layers,
142 duct_radial_biases,
143 duct_inner_boundary_layer_params,
144 duct_outer_boundary_layer_params,
145 pitch,
146 num_sectors_per_side,
147 background_intervals,
148 background_radial_bias,
149 background_inner_boundary_layer_params,
150 background_outer_boundary_layer_params,
151 node_id_background_meta,
152 side_number,
153 side_index,
154 azimuthal_tangent,
155 block_id_shift,
156 quad_center_elements,
157 center_quad_factor,
158 create_inward_interface_boundaries,
159 create_outward_interface_boundaries,
160 boundary_id_shift,
161 1.0,
162 generate_side_specific_boundaries,
163 tri_elem_type,
164 quad_elem_type);
165}
166
167std::unique_ptr<ReplicatedMesh>
169 std::vector<Real> ring_radii,
170 const std::vector<unsigned int> ring_layers,
171 const std::vector<Real> ring_radial_biases,
172 const multiBdryLayerParams & ring_inner_boundary_layer_params,
173 const multiBdryLayerParams & ring_outer_boundary_layer_params,
174 std::vector<Real> ducts_center_dist,
175 const std::vector<unsigned int> ducts_layers,
176 const std::vector<Real> duct_radial_biases,
177 const multiBdryLayerParams & duct_inner_boundary_layer_params,
178 const multiBdryLayerParams & duct_outer_boundary_layer_params,
179 const Real pitch,
180 const unsigned int num_sectors_per_side,
181 const unsigned int background_intervals,
182 const Real background_radial_bias,
183 const singleBdryLayerParams & background_inner_boundary_layer_params,
184 const singleBdryLayerParams & background_outer_boundary_layer_params,
185 dof_id_type & node_id_background_meta,
186 const Real virtual_side_number,
187 const unsigned int side_index,
188 const std::vector<Real> azimuthal_tangent,
189 const subdomain_id_type block_id_shift,
190 const bool quad_center_elements,
191 const Real center_quad_factor,
192 const bool create_inward_interface_boundaries,
193 const bool create_outward_interface_boundaries,
194 const boundary_id_type boundary_id_shift,
195 const Real pitch_scale_factor,
196 const bool generate_side_specific_boundaries,
197 const TRI_ELEM_TYPE tri_elem_type,
198 const QUAD_ELEM_TYPE quad_elem_type)
199{
200 const unsigned short order = quad_elem_type == QUAD_ELEM_TYPE::QUAD4 ? 1 : 2;
201 if (order != (tri_elem_type == TRI_ELEM_TYPE::TRI3 ? 1 : 2))
202 mooseError("In mesh generator ",
203 this->name(),
204 ", an incompatible elements type combination is used when calling "
205 "PolygonMeshGeneratorBase::buildSlice().");
206 // In order to create quadratic elements (i.e., order = 2), we creates nodes with double mesh
207 // density. Thus, the related parameters need to be modified accordingly. A prefix "mod_" is used
208 // to indicate the modified parameters.
209
210 // For ring_layers, modification is to double the number of layers for order = 2
211 std::vector<unsigned int> mod_ring_layers(ring_layers);
212 std::for_each(
213 mod_ring_layers.begin(), mod_ring_layers.end(), [&order](unsigned int & n) { n *= order; });
214 // For ring_radial_biases, modification is to take the square root of the original biases for
215 // order = 2
216 std::vector<Real> mod_ring_radial_biases(ring_radial_biases);
217 std::for_each(mod_ring_radial_biases.begin(),
218 mod_ring_radial_biases.end(),
219 [&order](Real & n) { n = std::pow(n, 1.0 / order); });
220 // ducts_layers is similar to ring_layers
221 std::vector<unsigned int> mod_ducts_layers(ducts_layers);
222 std::for_each(
223 mod_ducts_layers.begin(), mod_ducts_layers.end(), [&order](unsigned int & n) { n *= order; });
224 // duct_radial_biases is similar to ring_radial_biases
225 std::vector<Real> mod_duct_radial_biases(duct_radial_biases);
226 std::for_each(mod_duct_radial_biases.begin(),
227 mod_duct_radial_biases.end(),
228 [&order](Real & n) { n = std::pow(n, 1.0 / order); });
229 // Azimuthal mesh density is also doubled for order = 2
230 const unsigned int mod_num_sectors_per_side = num_sectors_per_side * order;
231 const unsigned int mod_background_intervals = background_intervals * order;
232 // background_radial_bias is similar to ring_radial_biases
233 const Real mod_background_radial_bias = std::pow(background_radial_bias, 1.0 / order);
234 // Perform similar modifications for boundary layer parameters
235 const auto mod_ring_inner_boundary_layer_params =
236 modifiedMultiBdryLayerParamsCreator(ring_inner_boundary_layer_params, order);
237 const auto mod_ring_outer_boundary_layer_params =
238 modifiedMultiBdryLayerParamsCreator(ring_outer_boundary_layer_params, order);
239 const auto mod_duct_inner_boundary_layer_params =
240 modifiedMultiBdryLayerParamsCreator(duct_inner_boundary_layer_params, order);
241 const auto mod_duct_outer_boundary_layer_params =
242 modifiedMultiBdryLayerParamsCreator(duct_outer_boundary_layer_params, order);
243
244 const auto mod_background_inner_boundary_layer_params =
245 modifiedSingleBdryLayerParamsCreator(background_inner_boundary_layer_params, order);
246 const auto mod_background_outer_boundary_layer_params =
247 modifiedSingleBdryLayerParamsCreator(background_outer_boundary_layer_params, order);
248
249 // The distance parameters of the rings and duct need to be modified too as they may be involved
250 // in the boundary layer cases.
251 std::vector<Real> mod_ducts_center_dist(ducts_center_dist);
252 std::vector<Real> mod_ring_radii(ring_radii);
253 bool has_rings(ring_radii.size());
254 bool has_ducts(ducts_center_dist.size());
255 bool has_background(background_intervals);
256 auto mesh = buildReplicatedMesh(2);
257
258 // Calculate biasing terms
259 // background region needs to be split into three parts
260 const auto main_background_bias_terms =
261 biasTermsCalculator(background_radial_bias, background_intervals);
262 const auto inner_background_bias_terms =
263 biasTermsCalculator(background_inner_boundary_layer_params.bias,
264 background_inner_boundary_layer_params.intervals);
265 const auto outer_background_bias_terms =
266 biasTermsCalculator(background_outer_boundary_layer_params.bias,
267 background_outer_boundary_layer_params.intervals);
268 auto rings_bias_terms = biasTermsCalculator(ring_radial_biases,
269 ring_layers,
270 ring_inner_boundary_layer_params,
271 ring_outer_boundary_layer_params);
272 auto duct_bias_terms = biasTermsCalculator(duct_radial_biases,
273 ducts_layers,
274 duct_inner_boundary_layer_params,
275 duct_outer_boundary_layer_params);
276 // Equivalent "mod_" parts
277 const auto mod_main_background_bias_terms =
278 biasTermsCalculator(mod_background_radial_bias, mod_background_intervals);
279 const auto mod_inner_background_bias_terms =
280 biasTermsCalculator(mod_background_inner_boundary_layer_params.bias,
281 mod_background_inner_boundary_layer_params.intervals);
282 const auto mod_outer_background_bias_terms =
283 biasTermsCalculator(mod_background_outer_boundary_layer_params.bias,
284 mod_background_outer_boundary_layer_params.intervals);
285 auto mod_rings_bias_terms = biasTermsCalculator(mod_ring_radial_biases,
286 mod_ring_layers,
287 mod_ring_inner_boundary_layer_params,
288 mod_ring_outer_boundary_layer_params);
289 auto mod_duct_bias_terms = biasTermsCalculator(mod_duct_radial_biases,
290 mod_ducts_layers,
291 mod_duct_inner_boundary_layer_params,
292 mod_duct_outer_boundary_layer_params);
293
294 std::vector<unsigned int> total_ring_layers;
295 for (unsigned int i = 0; i < ring_layers.size(); i++)
296 total_ring_layers.push_back(ring_layers[i] + ring_inner_boundary_layer_params.intervals[i] +
297 ring_outer_boundary_layer_params.intervals[i]);
298
299 if (background_inner_boundary_layer_params.intervals)
300 {
301 total_ring_layers.push_back(background_inner_boundary_layer_params.intervals);
302 rings_bias_terms.push_back(inner_background_bias_terms);
303 ring_radii.push_back((ring_radii.empty() ? 0.0 : ring_radii.back()) +
304 background_inner_boundary_layer_params.width);
305 has_rings = true;
306 }
307 std::vector<unsigned int> mod_total_ring_layers;
308 for (unsigned int i = 0; i < mod_ring_layers.size(); i++)
309 mod_total_ring_layers.push_back(mod_ring_layers[i] +
310 mod_ring_inner_boundary_layer_params.intervals[i] +
311 mod_ring_outer_boundary_layer_params.intervals[i]);
312
313 if (mod_background_inner_boundary_layer_params.intervals)
314 {
315 mod_total_ring_layers.push_back(mod_background_inner_boundary_layer_params.intervals);
316 mod_rings_bias_terms.push_back(mod_inner_background_bias_terms);
317 mod_ring_radii.push_back((mod_ring_radii.empty() ? 0.0 : mod_ring_radii.back()) +
318 mod_background_inner_boundary_layer_params.width);
319 // has_rings should be modified before in the none "mod_" part
320 }
321
322 std::vector<unsigned int> total_ducts_layers;
323 if (background_outer_boundary_layer_params.intervals)
324 {
325 total_ducts_layers.push_back(background_outer_boundary_layer_params.intervals);
326 duct_bias_terms.insert(duct_bias_terms.begin(), outer_background_bias_terms);
327 ducts_center_dist.insert(ducts_center_dist.begin(),
328 (ducts_center_dist.empty()
329 ? pitch / 2.0 / std::cos(M_PI / virtual_side_number)
330 : ducts_center_dist.front()) -
331 background_outer_boundary_layer_params.width);
332 has_ducts = true;
333 }
334 for (unsigned int i = 0; i < ducts_layers.size(); i++)
335 total_ducts_layers.push_back(ducts_layers[i] + duct_inner_boundary_layer_params.intervals[i] +
336 duct_outer_boundary_layer_params.intervals[i]);
337
338 std::vector<unsigned int> mod_total_ducts_layers;
339 if (mod_background_outer_boundary_layer_params.intervals)
340 {
341 mod_total_ducts_layers.push_back(mod_background_outer_boundary_layer_params.intervals);
342 mod_duct_bias_terms.insert(mod_duct_bias_terms.begin(), mod_outer_background_bias_terms);
343 mod_ducts_center_dist.insert(mod_ducts_center_dist.begin(),
344 (mod_ducts_center_dist.empty()
345 ? pitch / 2.0 / std::cos(M_PI / virtual_side_number)
346 : mod_ducts_center_dist.front()) -
347 mod_background_outer_boundary_layer_params.width);
348 // has_ducts should be modified before in the none "mod_" part
349 }
350 for (unsigned int i = 0; i < mod_ducts_layers.size(); i++)
351 mod_total_ducts_layers.push_back(mod_ducts_layers[i] +
352 mod_duct_inner_boundary_layer_params.intervals[i] +
353 mod_duct_outer_boundary_layer_params.intervals[i]);
354
355 unsigned int angle_number = azimuthal_tangent.size() == 0
356 ? num_sectors_per_side
357 : ((azimuthal_tangent.size() - 1) / order);
358 unsigned int mod_angle_number =
359 azimuthal_tangent.size() == 0 ? mod_num_sectors_per_side : (azimuthal_tangent.size() - 1);
360
361 // Geometries
362 const Real corner_to_corner =
363 pitch / std::cos(M_PI / virtual_side_number); // distance of bin center to cell corner
364 const Real corner_p[2][2] = {
365 {0.0, 0.5 * corner_to_corner},
366 {0.5 * corner_to_corner * pitch_scale_factor * std::sin(2.0 * M_PI / virtual_side_number),
367 0.5 * corner_to_corner * pitch_scale_factor * std::cos(2.0 * M_PI / virtual_side_number)}};
368 const unsigned int div_num = angle_number / 2 + 1;
369 const unsigned int mod_div_num = mod_angle_number / 2 + 1;
370
371 // From now on, we work on the nodes, which need the "mod_" parameters
372 std::vector<std::vector<Node *>> nodes(mod_div_num, std::vector<Node *>(mod_div_num));
373 if (quad_center_elements)
374 {
375 Real ring_radii_0;
376
377 if (has_rings)
378 ring_radii_0 = ring_radii.front() * mod_rings_bias_terms.front()[order - 1];
379 else if (has_ducts)
380 ring_radii_0 = mod_ducts_center_dist.front() * std::cos(M_PI / virtual_side_number) *
381 mod_main_background_bias_terms[order - 1];
382 else
383 ring_radii_0 = pitch / 2.0 * mod_main_background_bias_terms[order - 1];
384 // If center_quad_factor is zero, default value (div_num - 1)/div_num is used.
385 // We use div_num instead of mod_div_num because we are dealing wth elements here
386 // This approach ensures that the order = 2 mesh elements are consistent with the order = 1
387 ring_radii_0 *=
388 center_quad_factor == 0.0 ? (((Real)div_num - 1.0) / (Real)div_num) : center_quad_factor;
389
390 centerNodes(*mesh, virtual_side_number, mod_div_num, ring_radii_0, nodes);
391 }
392 else // pin-cell center
393 mesh->add_point(Point(0.0, 0.0, 0.0));
394
395 // create nodes for the ring regions
396 if (has_rings)
398 ring_radii,
399 mod_total_ring_layers,
400 mod_rings_bias_terms,
401 mod_num_sectors_per_side,
402 corner_p,
403 corner_to_corner,
404 azimuthal_tangent);
405
406 if (has_background)
407 {
408 // add nodes in background region; the background region is defined as the area between the
409 // outermost pin (if there is a pin; if no pin, the center) and the innermost hex/duct; if
410 // _has_ducts is false, the background region is the area between the pin and enclosing hexagon
411 Real background_corner_radial_interval_length;
412 Real background_corner_distance;
413 Real background_in;
414 Real background_out; // background outer frontier
415 if (has_rings)
416 background_in = ring_radii.back();
417 else
418 background_in = 0;
419
420 if (has_ducts)
421 {
422 background_out = mod_ducts_center_dist.front();
423 background_corner_distance =
424 mod_ducts_center_dist
425 .front(); // it is the center to duct (innermost duct) corner distance
426 }
427 else
428 {
429 background_out = 0.5 * corner_to_corner;
430 background_corner_distance =
431 0.5 * corner_to_corner; // it is the center to hex corner distance
432 }
433
434 background_corner_radial_interval_length =
435 (background_out - background_in) / mod_background_intervals;
436
437 node_id_background_meta = mesh->n_nodes();
438
439 // create nodes for background region
441 mod_num_sectors_per_side,
442 mod_background_intervals,
443 mod_main_background_bias_terms,
444 background_corner_distance,
445 background_corner_radial_interval_length,
446 corner_p,
447 corner_to_corner,
448 background_in,
449 azimuthal_tangent);
450 }
451
452 // create nodes for duct regions
453 if (has_ducts)
455 &mod_ducts_center_dist,
456 mod_total_ducts_layers,
457 mod_duct_bias_terms,
458 mod_num_sectors_per_side,
459 corner_p,
460 corner_to_corner,
461 azimuthal_tangent);
462
463 // See if the central region is the only part of the innermost part
464 // The central region of the slice is special.
465 // Unlike the outer regions, which are layered quad elements,
466 // the central region is either a layer of tri elements or a specially-patterned quad elements.
467 // If there is at least one `ring` defined in the slice,
468 // the central region must belong to the innermost (first) ring.
469 // Otherwise the central region belongs to the `background`
470 // In either case, if the innermost ring or background has only one radial interval,
471 // the central region is an independent ring or background
472 // Otherwise, the central region and one or several quad element layers together form the
473 // innermost ring or background
474 bool is_central_region_independent;
475 if (ring_layers.empty())
476 is_central_region_independent = mod_background_inner_boundary_layer_params.intervals +
477 mod_background_intervals +
478 mod_background_outer_boundary_layer_params.intervals ==
479 1;
480 else
481 is_central_region_independent = mod_ring_layers[0] +
482 mod_ring_inner_boundary_layer_params.intervals[0] +
483 mod_ring_outer_boundary_layer_params.intervals[0] ==
484 1;
485
486 // From now on, we work on the elements, which need the none "mod_" parameters
487 // Assign elements, boundaries, and subdomains;
488 // Add Tri3/Tri6/Tri7 or Quad4/Quad8/Quad9 mesh into innermost (central) region
489 if (quad_center_elements)
491 div_num,
492 block_id_shift,
493 create_outward_interface_boundaries && is_central_region_independent,
494 boundary_id_shift,
495 nodes,
496 (!has_rings) && (!has_ducts) && (background_intervals == 1),
497 // Note here, has_ring means either there are ring regions or background inner
498 // boundary layer; has_ducts means either there are duct regions or background
499 // outer boundary layer. Same in cenTriElemDef()
500 side_index,
501 generate_side_specific_boundaries,
502 quad_elem_type);
503 else
505 *mesh,
506 num_sectors_per_side,
507 azimuthal_tangent,
508 block_id_shift,
509 create_outward_interface_boundaries && is_central_region_independent,
510 boundary_id_shift,
511 ((!has_rings) && (!has_ducts) && (background_intervals == 1)) ||
512 ((!has_background) &&
513 (std::accumulate(total_ring_layers.begin(), total_ring_layers.end(), 0) == 1)),
514 // Only for ACCG, it is possible that the entire mesh is a single-layer ring.
515 // cenQuadElemDef() does not need this as it does not work for ACCG.
516 side_index,
517 generate_side_specific_boundaries,
518 tri_elem_type);
519
520 // Add Quad4 mesh into outer circle
521 // total number of mesh should be all the rings for pin regions + background regions;
522 // total number of quad mesh should be total number of mesh -1 (-1 is because the inner circle for
523 // tri/quad mesh has been added above)
524
525 std::vector<unsigned int> subdomain_rings;
526 if (has_rings) // define the rings in each subdomain
527 {
528 subdomain_rings = total_ring_layers;
529 subdomain_rings.front() -= 1; // remove the inner TRI mesh subdomain
530 if (background_inner_boundary_layer_params.intervals)
531 {
532 subdomain_rings.back() =
533 background_inner_boundary_layer_params.intervals + background_intervals +
534 background_outer_boundary_layer_params.intervals; // add the background region
535 if (ring_radii.size() == 1)
536 subdomain_rings.back() -= 1; // remove the inner TRI mesh subdomain
537 }
538 else if (has_background)
539 subdomain_rings.push_back(background_inner_boundary_layer_params.intervals +
540 background_intervals +
541 background_outer_boundary_layer_params.intervals);
542 }
543 else
544 {
545 subdomain_rings.push_back(
546 background_inner_boundary_layer_params.intervals + background_intervals +
547 background_outer_boundary_layer_params.intervals); // add the background region
548 subdomain_rings[0] -= 1; // remove the inner TRI mesh subdomain
549 }
550
551 if (has_ducts)
552 for (unsigned int i = (background_outer_boundary_layer_params.intervals > 0);
553 i < total_ducts_layers.size();
554 i++)
555 subdomain_rings.push_back(total_ducts_layers[i]);
556
558 num_sectors_per_side,
559 subdomain_rings,
560 side_index,
561 azimuthal_tangent,
562 block_id_shift,
563 quad_center_elements ? (mod_div_num * mod_div_num - 1) : 0,
564 create_inward_interface_boundaries,
565 create_outward_interface_boundaries,
566 boundary_id_shift,
567 generate_side_specific_boundaries,
568 quad_elem_type);
569 if (tri_elem_type == TRI_ELEM_TYPE::TRI6 || quad_elem_type == QUAD_ELEM_TYPE::QUAD8)
570 mesh->remove_orphaned_nodes();
571 return mesh;
572}
573
574void
576 const Real virtual_side_number,
577 const unsigned int div_num,
578 const Real ring_radii_0,
579 std::vector<std::vector<Node *>> & nodes) const
580{
581 const std::pair<Real, Real> p_origin = std::make_pair(0.0, 0.0);
582 const std::pair<Real, Real> p_bottom =
583 std::make_pair(0.0, ring_radii_0 * std::cos(M_PI / virtual_side_number));
584 const std::pair<Real, Real> p_top =
585 std::make_pair(p_bottom.second * std::sin(2.0 * M_PI / virtual_side_number),
586 p_bottom.second * std::cos(2.0 * M_PI / virtual_side_number));
587 const std::pair<Real, Real> p_diag =
588 std::make_pair(ring_radii_0 * std::sin(M_PI / virtual_side_number),
589 ring_radii_0 * std::cos(M_PI / virtual_side_number));
590
591 // The four vertices of the central quad region are defined above.
592 // The following loops transverse all the nodes within this central quad region by moving p1 thru
593 // p4 and calculate the four-point intercept (pc).
594 // p_top------o-------p4--------o-----p_diag
595 // | | | | |
596 // | | | | |
597 // o--------o--------o--------o--------o
598 // | | | | |
599 // | | | | |
600 // p1--------o-------pc--------o-------p2
601 // | | | | |
602 // | | | | |
603 // o--------o--------o--------o--------o
604 // | | | | |
605 // | | | | |
606 // p_origin-----o-------p3--------o----p_bottom
607 //
608 // The loops are designed to transverse the nodes as shown below to facilitate elements
609 // and sides creation.
610 //
611 // 25-------24-------23-------22-------21
612 // | | | | |
613 // | | | | |
614 // 16-------15-------14-------13-------20
615 // | | | | |
616 // | | | | |
617 // 9--------8------- 7-------12-------19
618 // | | | | |
619 // | | | | |
620 // 4--------3--------6-------11-------18
621 // | | | | |
622 // | | | | |
623 // 1--------2--------5-------10-------17
624
625 for (unsigned int i = 0; i < div_num; i++)
626 {
627 unsigned int id_x = 0;
628 unsigned int id_y = i;
629 for (unsigned int j = 0; j < 2 * i + 1; j++)
630 {
631 std::pair<Real, Real> p1 = std::make_pair(
632 (p_origin.first * (div_num - 1 - id_x) + p_top.first * id_x) / (div_num - 1),
633 (p_origin.second * (div_num - 1 - id_x) + p_top.second * id_x) / (div_num - 1));
634 std::pair<Real, Real> p2 = std::make_pair(
635 (p_bottom.first * (div_num - 1 - id_x) + p_diag.first * id_x) / (div_num - 1),
636 (p_bottom.second * (div_num - 1 - id_x) + p_diag.second * id_x) / (div_num - 1));
637 std::pair<Real, Real> p3 = std::make_pair(
638 (p_origin.first * (div_num - 1 - id_y) + p_bottom.first * id_y) / (div_num - 1),
639 (p_origin.second * (div_num - 1 - id_y) + p_bottom.second * id_y) / (div_num - 1));
640 std::pair<Real, Real> p4 = std::make_pair(
641 (p_top.first * (div_num - 1 - id_y) + p_diag.first * id_y) / (div_num - 1),
642 (p_top.second * (div_num - 1 - id_y) + p_diag.second * id_y) / (div_num - 1));
643 std::pair<Real, Real> pc = fourPointIntercept(p1, p2, p3, p4);
644 nodes[id_x][id_y] = mesh.add_point(Point(pc.first, pc.second, 0.0));
645 if (j < i)
646 id_x++;
647 if (j >= i)
648 id_y--;
649 }
650 }
651}
652
653void
655 const std::vector<Real> ring_radii,
656 const std::vector<unsigned int> ring_layers,
657 const std::vector<std::vector<Real>> biased_terms,
658 const unsigned int num_sectors_per_side,
659 const Real corner_p[2][2],
660 const Real corner_to_corner,
661 const std::vector<Real> azimuthal_tangent) const
662{
663 const unsigned int angle_number =
664 azimuthal_tangent.size() == 0 ? num_sectors_per_side : (azimuthal_tangent.size() - 1);
665
666 // Add nodes in pins regions
667 for (unsigned int l = 0; l < ring_layers.size(); l++)
668 {
669 // the pin radius interval for each ring_radii/subdomain
670 const Real pin_radius_interval_length =
671 l == 0 ? ring_radii[l] / ring_layers[l]
672 : (ring_radii[l] - ring_radii[l - 1]) / ring_layers[l];
673
674 // add rings in each pin subdomain
675 for (unsigned int k = 0; k < ring_layers[l]; k++)
676 {
677 const Real bin_radial_distance =
678 l == 0 ? (biased_terms[l][k] * ring_layers[l] *
679 pin_radius_interval_length) // this is from the cell/pin center to
680 // the first circle
681 : (ring_radii[l - 1] +
682 biased_terms[l][k] * ring_layers[l] * pin_radius_interval_length);
683 const Real pin_corner_p_x = corner_p[0][0] * bin_radial_distance / (0.5 * corner_to_corner);
684 const Real pin_corner_p_y = corner_p[0][1] * bin_radial_distance / (0.5 * corner_to_corner);
685
686 // pin_corner_p(s) are the points in the pin region, on the bins towards the six corners,
687 // at different intervals
688 mesh.add_point(Point(pin_corner_p_x, pin_corner_p_y, 0.0));
689
690 for (unsigned int j = 1; j <= angle_number; j++)
691 {
692 const Real cell_boundary_p_x =
693 corner_p[0][0] + (corner_p[1][0] - corner_p[0][0]) *
694 (azimuthal_tangent.size() == 0 ? ((Real)j / (Real)angle_number)
695 : (azimuthal_tangent[j] / 2.0));
696 const Real cell_boundary_p_y =
697 corner_p[0][1] + (corner_p[1][1] - corner_p[0][1]) *
698 (azimuthal_tangent.size() == 0 ? ((Real)j / (Real)angle_number)
699 : (azimuthal_tangent[j] / 2.0));
700 // cell_boundary_p(s) are the points on the cell's six boundaries (flat sides) at
701 // different azimuthal angles
702 const Real pin_azimuthal_p_x =
703 cell_boundary_p_x * bin_radial_distance /
704 std::sqrt(Utility::pow<2>(cell_boundary_p_x) + Utility::pow<2>(cell_boundary_p_y));
705 const Real pin_azimuthal_p_y =
706 cell_boundary_p_y * bin_radial_distance /
707 std::sqrt(Utility::pow<2>(cell_boundary_p_x) + Utility::pow<2>(cell_boundary_p_y));
708
709 // pin_azimuthal_p are the points on the bins towards different azimuthal angles, at
710 // different intervals; excluding the ones produced by pin_corner_p
711 mesh.add_point(Point(pin_azimuthal_p_x, pin_azimuthal_p_y, 0.0));
712 }
713 }
714 }
715}
716
717void
719 const unsigned int num_sectors_per_side,
720 const unsigned int background_intervals,
721 const std::vector<Real> biased_terms,
722 const Real background_corner_distance,
723 const Real background_corner_radial_interval_length,
724 const Real corner_p[2][2],
725 const Real corner_to_corner,
726 const Real background_in,
727 const std::vector<Real> azimuthal_tangent) const
728{
729 unsigned int angle_number =
730 azimuthal_tangent.size() == 0 ? num_sectors_per_side : (azimuthal_tangent.size() - 1);
731 for (unsigned int k = 0; k < (background_intervals); k++)
732 {
733 const Real background_corner_p_x =
734 background_corner_distance / (0.5 * corner_to_corner) * corner_p[0][0] *
735 (background_in +
736 biased_terms[k] * background_intervals * background_corner_radial_interval_length) /
737 background_corner_distance;
738 const Real background_corner_p_y =
739 background_corner_distance / (0.5 * corner_to_corner) * corner_p[0][1] *
740 (background_in +
741 biased_terms[k] * background_intervals * background_corner_radial_interval_length) /
742 background_corner_distance;
743
744 // background_corner_p(s) are the points in the background region, on the bins towards the six
745 // corners, at different intervals
746 mesh.add_point(Point(background_corner_p_x, background_corner_p_y, 0.0));
747
748 for (unsigned int j = 1; j <= angle_number; j++)
749 {
750 const Real cell_boundary_p_x =
751 background_corner_distance / (0.5 * corner_to_corner) *
752 (corner_p[0][0] + (corner_p[1][0] - corner_p[0][0]) *
753 (azimuthal_tangent.size() == 0 ? ((Real)j / (Real)angle_number)
754 : (azimuthal_tangent[j] / 2.0)));
755 const Real cell_boundary_p_y =
756 background_corner_distance / (0.5 * corner_to_corner) *
757 (corner_p[0][1] + (corner_p[1][1] - corner_p[0][1]) *
758 (azimuthal_tangent.size() == 0 ? ((Real)j / (Real)angle_number)
759 : (azimuthal_tangent[j] / 2.0)));
760 // cell_boundary_p(s) are the points on the cell's six boundaries (flat sides) at different
761 // azimuthal angles
762 const Real pin_boundary_p_x =
763 cell_boundary_p_x * background_in /
764 std::sqrt(Utility::pow<2>(cell_boundary_p_x) + Utility::pow<2>(cell_boundary_p_y));
765 const Real pin_boundary_p_y =
766 cell_boundary_p_y * background_in /
767 std::sqrt(Utility::pow<2>(cell_boundary_p_x) + Utility::pow<2>(cell_boundary_p_y));
768 // pin_boundary_p(s) are the points on pin boundary (outside ring) at different azimuthal
769 // angles
770 const Real background_radial_interval =
771 std::sqrt(Utility::pow<2>(cell_boundary_p_x - pin_boundary_p_x) +
772 Utility::pow<2>(cell_boundary_p_y - pin_boundary_p_y)) /
773 background_intervals;
774 const Real background_azimuthal_p_x =
775 cell_boundary_p_x *
776 (background_in + biased_terms[k] * background_intervals * background_radial_interval) /
777 std::sqrt(Utility::pow<2>(cell_boundary_p_x) + Utility::pow<2>(cell_boundary_p_y));
778 const Real background_azimuthal_p_y =
779 cell_boundary_p_y *
780 (background_in + biased_terms[k] * background_intervals * background_radial_interval) /
781 std::sqrt(Utility::pow<2>(cell_boundary_p_x) + Utility::pow<2>(cell_boundary_p_y));
782 // background_azimuthal_p are the points on the bins towards different azimuthal angles, at
783 // different intervals; excluding the ones produced by background_corner_p
784 mesh.add_point(Point(background_azimuthal_p_x, background_azimuthal_p_y, 0.0));
785 }
786 }
787}
788
789void
791 std::vector<Real> * const ducts_center_dist,
792 const std::vector<unsigned int> ducts_layers,
793 const std::vector<std::vector<Real>> biased_terms,
794 const unsigned int num_sectors_per_side,
795 const Real corner_p[2][2],
796 const Real corner_to_corner,
797 const std::vector<Real> azimuthal_tangent) const
798{
799 unsigned int angle_number =
800 azimuthal_tangent.size() == 0 ? num_sectors_per_side : (azimuthal_tangent.size() - 1);
801 // Add nodes in ducts regions
802 (*ducts_center_dist)
803 .push_back(0.5 * corner_to_corner); // add hex boundary as the last element in this vector
804 std::vector<Real> duct_radius_interval_length(ducts_layers.size());
805
806 Real bin_radial_distance;
807 for (unsigned int l = 0; l < ducts_layers.size(); l++)
808 {
809 duct_radius_interval_length[l] =
810 ((*ducts_center_dist)[l + 1] - (*ducts_center_dist)[l]) /
811 ducts_layers[l]; // the pin radius interval for each ring_radii/subdomain
812
813 // add rings in each pin subdomain
814 for (unsigned int k = 0; k < ducts_layers[l]; k++)
815 {
816 bin_radial_distance = ((*ducts_center_dist)[l] +
817 biased_terms[l][k] * ducts_layers[l] * duct_radius_interval_length[l]);
818 const Real pin_corner_p_x = corner_p[0][0] * bin_radial_distance / (0.5 * corner_to_corner);
819 const Real pin_corner_p_y = corner_p[0][1] * bin_radial_distance / (0.5 * corner_to_corner);
820
821 // pin_corner_p(s) are the points in the pin region, on the bins towards the six corners,
822 // at different intervals
823 mesh.add_point(Point(pin_corner_p_x, pin_corner_p_y, 0.0));
824
825 for (unsigned int j = 1; j <= angle_number; j++)
826 {
827 const Real cell_boundary_p_x =
828 corner_p[0][0] + (corner_p[1][0] - corner_p[0][0]) *
829 (azimuthal_tangent.size() == 0 ? ((Real)j / (Real)angle_number)
830 : (azimuthal_tangent[j] / 2.0));
831 const Real cell_boundary_p_y =
832 corner_p[0][1] + (corner_p[1][1] - corner_p[0][1]) *
833 (azimuthal_tangent.size() == 0 ? ((Real)j / (Real)angle_number)
834 : (azimuthal_tangent[j] / 2.0));
835 // cell_boundary_p(s) are the points on the cell's six boundaries (flat sides) at
836 // different azimuthal angles
837 const Real pin_azimuthal_p_x =
838 cell_boundary_p_x * bin_radial_distance / (0.5 * corner_to_corner);
839 const Real pin_azimuthal_p_y =
840 cell_boundary_p_y * bin_radial_distance / (0.5 * corner_to_corner);
841
842 // pin_azimuthal_p are the points on the bins towards different azimuthal angles, at
843 // different intervals; excluding the ones produced by pin_corner_p
844 mesh.add_point(Point(pin_azimuthal_p_x, pin_azimuthal_p_y, 0.0));
845 }
846 }
847 }
848}
849
850void
852 const unsigned int div_num,
853 const subdomain_id_type block_id_shift,
854 const bool create_outward_interface_boundaries,
855 const boundary_id_type boundary_id_shift,
856 std::vector<std::vector<Node *>> & nodes,
857 const bool assign_external_boundary,
858 const unsigned int side_index,
859 const bool generate_side_specific_boundaries,
860 const QUAD_ELEM_TYPE quad_elem_type) const
861{
862
863 BoundaryInfo & boundary_info = mesh.get_boundary_info();
864
865 // This loop defines quad elements for the central regions except for the outermost layer
866 for (unsigned int i = 0; i < div_num - 1; i++)
867 {
868 unsigned int id_x = 0;
869 unsigned int id_y = i;
870 for (unsigned int j = 0; j < 2 * i + 1; j++)
871 {
872 std::unique_ptr<Elem> new_elem;
873 if (quad_elem_type == QUAD_ELEM_TYPE::QUAD4)
874 {
875 new_elem = std::make_unique<Quad4>();
876 new_elem->set_node(0, nodes[id_x][id_y]);
877 new_elem->set_node(3, nodes[id_x][id_y + 1]);
878 new_elem->set_node(2, nodes[id_x + 1][id_y + 1]);
879 new_elem->set_node(1, nodes[id_x + 1][id_y]);
880 new_elem->subdomain_id() = 1 + block_id_shift;
881 }
882 else // QUAD8/QUAD9
883 {
884 new_elem = std::make_unique<Quad8>();
885 if (quad_elem_type == QUAD_ELEM_TYPE::QUAD9)
886 {
887 new_elem = std::make_unique<Quad9>();
888 new_elem->set_node(8, nodes[id_x * 2 + 1][id_y * 2 + 1]);
889 }
890 new_elem->set_node(0, nodes[id_x * 2][id_y * 2]);
891 new_elem->set_node(3, nodes[id_x * 2][id_y * 2 + 2]);
892 new_elem->set_node(2, nodes[id_x * 2 + 2][id_y * 2 + 2]);
893 new_elem->set_node(1, nodes[id_x * 2 + 2][id_y * 2]);
894 new_elem->set_node(4, nodes[id_x * 2 + 1][id_y * 2]);
895 new_elem->set_node(5, nodes[id_x * 2 + 2][id_y * 2 + 1]);
896 new_elem->set_node(6, nodes[id_x * 2 + 1][id_y * 2 + 2]);
897 new_elem->set_node(7, nodes[id_x * 2][id_y * 2 + 1]);
898 new_elem->subdomain_id() = 1 + block_id_shift;
899 }
900 Elem * elem_Quad = mesh.add_elem(std::move(new_elem));
901
902 if (id_x == 0)
903 boundary_info.add_side(elem_Quad, 3, SLICE_BEGIN);
904 if (id_y == 0)
905 boundary_info.add_side(elem_Quad, 0, SLICE_END);
906 if (j < i)
907 id_x++;
908 if (j >= i)
909 id_y--;
910 }
911 }
912 // This loop defines the outermost layer quad elements of the central region
913 for (unsigned int i = (div_num - 1) * (div_num - 1); i < div_num * div_num - 1; i++)
914 {
915 std::unique_ptr<Elem> new_elem;
916 if (quad_elem_type == QUAD_ELEM_TYPE::QUAD4)
917 {
918 new_elem = std::make_unique<Quad4>();
919 new_elem->set_node(0, mesh.node_ptr(i));
920 new_elem->set_node(3, mesh.node_ptr(i + 2 * div_num - 1));
921 new_elem->set_node(2, mesh.node_ptr(i + 2 * div_num));
922 new_elem->set_node(1, mesh.node_ptr(i + 1));
923 }
924 else // QUAD8/QUAD9
925 {
926 new_elem = std::make_unique<Quad8>();
927 if (quad_elem_type == QUAD_ELEM_TYPE::QUAD9)
928 {
929 new_elem = std::make_unique<Quad9>();
930 new_elem->set_node(8,
931 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
932 (i - (div_num - 1) * (div_num - 1)) * 2 + 1 +
933 ((div_num - 1) * 4 + 1)));
934 }
935 new_elem->set_node(0,
936 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
937 (i - (div_num - 1) * (div_num - 1)) * 2));
938 new_elem->set_node(3,
939 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
940 (i - (div_num - 1) * (div_num - 1)) * 2 +
941 ((div_num - 1) * 4 + 1) * 2));
942 new_elem->set_node(2,
943 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
944 (i - (div_num - 1) * (div_num - 1)) * 2 + 2 +
945 ((div_num - 1) * 4 + 1) * 2));
946 new_elem->set_node(1,
947 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
948 (i - (div_num - 1) * (div_num - 1)) * 2 + 2));
949 new_elem->set_node(4,
950 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
951 (i - (div_num - 1) * (div_num - 1)) * 2 + 1));
952 new_elem->set_node(5,
953 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
954 (i - (div_num - 1) * (div_num - 1)) * 2 + 2 +
955 ((div_num - 1) * 4 + 1)));
956 new_elem->set_node(6,
957 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
958 (i - (div_num - 1) * (div_num - 1)) * 2 + 1 +
959 ((div_num - 1) * 4 + 1) * 2));
960 new_elem->set_node(7,
961 mesh.node_ptr((div_num - 1) * (div_num - 1) * 4 +
962 (i - (div_num - 1) * (div_num - 1)) * 2 +
963 ((div_num - 1) * 4 + 1)));
964 }
965
966 Elem * elem_Quad = mesh.add_elem(std::move(new_elem));
967 elem_Quad->subdomain_id() = 1 + block_id_shift;
968 if (create_outward_interface_boundaries)
969 boundary_info.add_side(elem_Quad, 2, 1 + boundary_id_shift);
970 if (i == (div_num - 1) * (div_num - 1))
971 boundary_info.add_side(elem_Quad, 3, SLICE_BEGIN);
972 if (i == div_num * div_num - 2)
973 boundary_info.add_side(elem_Quad, 1, SLICE_END);
974 if (assign_external_boundary)
975 {
976 boundary_info.add_side(elem_Quad, 2, OUTER_SIDESET_ID);
977 if (generate_side_specific_boundaries)
978 boundary_info.add_side(
979 elem_Quad,
980 2,
981 (i < div_num * (div_num - 1) ? OUTER_SIDESET_ID : OUTER_SIDESET_ID_ALT) + side_index);
982 }
983 }
984}
985
986void
988 const unsigned int num_sectors_per_side,
989 const std::vector<Real> azimuthal_tangent,
990 const subdomain_id_type block_id_shift,
991 const bool create_outward_interface_boundaries,
992 const boundary_id_type boundary_id_shift,
993 const bool assign_external_boundary,
994 const unsigned int side_index,
995 const bool generate_side_specific_boundaries,
996 const TRI_ELEM_TYPE tri_elem_type) const
997{
998 const unsigned short order = tri_elem_type == TRI_ELEM_TYPE::TRI3 ? 1 : 2;
999 unsigned int angle_number = azimuthal_tangent.size() == 0
1000 ? num_sectors_per_side
1001 : ((azimuthal_tangent.size() - 1) / order);
1002
1003 BoundaryInfo & boundary_info = mesh.get_boundary_info();
1004 for (unsigned int i = 1; i <= angle_number; i++)
1005 {
1006 std::unique_ptr<Elem> new_elem;
1007 if (tri_elem_type == TRI_ELEM_TYPE::TRI3)
1008 {
1009 new_elem = std::make_unique<Tri3>();
1010 new_elem->set_node(0, mesh.node_ptr(0));
1011 new_elem->set_node(2, mesh.node_ptr(i));
1012 new_elem->set_node(1, mesh.node_ptr(i + 1));
1013 }
1014 else // TRI6/TRI7
1015 {
1016 new_elem = std::make_unique<Tri6>();
1017 if (tri_elem_type == TRI_ELEM_TYPE::TRI7)
1018 {
1019 new_elem = std::make_unique<Tri7>();
1020 new_elem->set_node(6, mesh.node_ptr(i * 2));
1021 }
1022 new_elem->set_node(0, mesh.node_ptr(0));
1023 new_elem->set_node(2, mesh.node_ptr(i * 2 + angle_number * order));
1024 new_elem->set_node(1, mesh.node_ptr((i + 1) * 2 + angle_number * order));
1025 new_elem->set_node(3, mesh.node_ptr(i * 2 + 1));
1026 new_elem->set_node(5, mesh.node_ptr(i * 2 - 1));
1027 new_elem->set_node(4, mesh.node_ptr(i * 2 + 1 + angle_number * order));
1028 }
1029
1030 Elem * elem = mesh.add_elem(std::move(new_elem));
1031 if (create_outward_interface_boundaries)
1032 boundary_info.add_side(elem, 1, 1 + boundary_id_shift);
1033 elem->subdomain_id() = 1 + block_id_shift;
1034 if (i == 1)
1035 boundary_info.add_side(elem, 2, SLICE_BEGIN);
1036 if (i == angle_number)
1037 boundary_info.add_side(elem, 0, SLICE_END);
1038 if (assign_external_boundary)
1039 {
1040 boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
1041 if (generate_side_specific_boundaries)
1042 boundary_info.add_side(elem,
1043 1,
1044 (i <= angle_number / 2 ? OUTER_SIDESET_ID : OUTER_SIDESET_ID_ALT) +
1045 side_index);
1046 }
1047 }
1048}
1049
1050void
1052 const unsigned int num_sectors_per_side,
1053 const std::vector<unsigned int> subdomain_rings,
1054 const unsigned int side_index,
1055 const std::vector<Real> azimuthal_tangent,
1056 const subdomain_id_type block_id_shift,
1057 const dof_id_type nodeid_shift,
1058 const bool create_inward_interface_boundaries,
1059 const bool create_outward_interface_boundaries,
1060 const boundary_id_type boundary_id_shift,
1061 const bool generate_side_specific_boundaries,
1062 const QUAD_ELEM_TYPE quad_elem_type) const
1063{
1064 const unsigned short order = quad_elem_type == QUAD_ELEM_TYPE::QUAD4 ? 1 : 2;
1065 unsigned int angle_number = azimuthal_tangent.size() == 0
1066 ? num_sectors_per_side
1067 : ((azimuthal_tangent.size() - 1) / order);
1068
1069 BoundaryInfo & boundary_info = mesh.get_boundary_info();
1070 unsigned int j = 0;
1071 for (unsigned int k = 0; k < (subdomain_rings.size()); k++)
1072 {
1073 for (unsigned int m = 0; m < subdomain_rings[k]; m++)
1074 {
1075 for (unsigned int i = 1; i <= angle_number; i++)
1076 {
1077 std::unique_ptr<Elem> new_elem;
1078 if (quad_elem_type == QUAD_ELEM_TYPE::QUAD4)
1079 {
1080 new_elem = std::make_unique<Quad4>();
1081 new_elem->set_node(0, mesh.node_ptr(nodeid_shift + i + (angle_number + 1) * j));
1082 new_elem->set_node(1, mesh.node_ptr(nodeid_shift + i + 1 + (angle_number + 1) * j));
1083 new_elem->set_node(2, mesh.node_ptr(nodeid_shift + i + (angle_number + 1) * (j + 1) + 1));
1084 new_elem->set_node(3, mesh.node_ptr(nodeid_shift + i + (angle_number + 1) * (j + 1)));
1085 }
1086 else // QUAD8/QUAD9
1087 {
1088 new_elem = std::make_unique<Quad8>();
1089 if (quad_elem_type == QUAD_ELEM_TYPE::QUAD9)
1090 {
1091 new_elem = std::make_unique<Quad9>();
1092 new_elem->set_node(
1093 8, mesh.node_ptr(nodeid_shift + i * 2 + (angle_number * 2 + 1) * (j * 2 + 2)));
1094 }
1095 new_elem->set_node(
1096 0,
1097 mesh.node_ptr(nodeid_shift + (i - 1) * 2 + 1 + (angle_number * 2 + 1) * (j * 2 + 1)));
1098 new_elem->set_node(
1099 1, mesh.node_ptr(nodeid_shift + i * 2 + 1 + (angle_number * 2 + 1) * (j * 2 + 1)));
1100 new_elem->set_node(
1101 2, mesh.node_ptr(nodeid_shift + i * 2 + 1 + (angle_number * 2 + 1) * (j * 2 + 3)));
1102 new_elem->set_node(
1103 3,
1104 mesh.node_ptr(nodeid_shift + (i - 1) * 2 + 1 + (angle_number * 2 + 1) * (j * 2 + 3)));
1105 new_elem->set_node(
1106 4, mesh.node_ptr(nodeid_shift + i * 2 + (angle_number * 2 + 1) * (j * 2 + 1)));
1107 new_elem->set_node(
1108 5, mesh.node_ptr(nodeid_shift + i * 2 + 1 + (angle_number * 2 + 1) * (j * 2 + 2)));
1109 new_elem->set_node(
1110 6, mesh.node_ptr(nodeid_shift + i * 2 + (angle_number * 2 + 1) * (j * 2 + 3)));
1111 new_elem->set_node(
1112 7,
1113 mesh.node_ptr(nodeid_shift + (i - 1) * 2 + 1 + (angle_number * 2 + 1) * (j * 2 + 2)));
1114 }
1115 Elem * elem = mesh.add_elem(std::move(new_elem));
1116 if (i == 1)
1117 boundary_info.add_side(elem, 3, SLICE_BEGIN);
1118 if (i == angle_number)
1119 boundary_info.add_side(elem, 1, SLICE_END);
1120
1121 if (subdomain_rings[0] == 0)
1122 elem->subdomain_id() = k + 1 + block_id_shift;
1123 else
1124 elem->subdomain_id() = k + 2 + block_id_shift;
1125
1126 if (m == 0 && create_inward_interface_boundaries && k > 0)
1127 boundary_info.add_side(elem, 0, k * 2 + boundary_id_shift);
1128 if (m == (subdomain_rings[k] - 1))
1129 {
1130 if (k == (subdomain_rings.size() - 1))
1131 {
1132 boundary_info.add_side(elem, 2, OUTER_SIDESET_ID);
1133 if (generate_side_specific_boundaries)
1134 {
1135 if (i <= angle_number / 2)
1136 boundary_info.add_side(elem, 2, OUTER_SIDESET_ID + side_index);
1137 else
1138 boundary_info.add_side(elem, 2, OUTER_SIDESET_ID_ALT + side_index);
1139 }
1140 }
1141 else if (create_outward_interface_boundaries)
1142 boundary_info.add_side(elem, 2, k * 2 + 1 + boundary_id_shift);
1143 }
1144 }
1145 j++;
1146 }
1147 }
1148}
1149
1150std::unique_ptr<ReplicatedMesh>
1152 const unsigned int num_sectors_per_side,
1153 const unsigned int peripheral_invervals,
1154 const std::vector<std::pair<Real, Real>> & positions_inner,
1155 const std::vector<std::pair<Real, Real>> & d_positions_outer,
1156 const subdomain_id_type id_shift,
1157 const QUAD_ELEM_TYPE quad_elem_type,
1158 const bool create_inward_interface_boundaries,
1159 const bool create_outward_interface_boundaries)
1160{
1161 auto mesh = buildReplicatedMesh(2);
1162 std::pair<Real, Real> positions_p;
1163
1164 // generate node positions
1165 for (unsigned int i = 0; i <= peripheral_invervals; i++)
1166 {
1167 for (unsigned int j = 0; j <= num_sectors_per_side / 2; j++)
1168 {
1169 positions_p = pointInterpolate(positions_inner[0].first,
1170 positions_inner[0].second,
1171 d_positions_outer[0].first,
1172 d_positions_outer[0].second,
1173 positions_inner[1].first,
1174 positions_inner[1].second,
1175 d_positions_outer[1].first,
1176 d_positions_outer[1].second,
1177 i,
1178 j,
1179 num_sectors_per_side,
1180 peripheral_invervals);
1181 mesh->add_point(Point(positions_p.first, positions_p.second, 0.0));
1182 }
1183 for (unsigned int j = 1; j <= num_sectors_per_side / 2; j++)
1184 {
1185 positions_p = pointInterpolate(positions_inner[1].first,
1186 positions_inner[1].second,
1187 d_positions_outer[1].first,
1188 d_positions_outer[1].second,
1189 positions_inner[2].first,
1190 positions_inner[2].second,
1191 d_positions_outer[2].first,
1192 d_positions_outer[2].second,
1193 i,
1194 j,
1195 num_sectors_per_side,
1196 peripheral_invervals);
1197 mesh->add_point(Point(positions_p.first, positions_p.second, 0.0));
1198 }
1199 }
1200
1201 // element definition
1202 BoundaryInfo & boundary_info = mesh->get_boundary_info();
1203
1204 for (unsigned int i = 0; i < peripheral_invervals; i++)
1205 {
1206 for (unsigned int j = 0; j < num_sectors_per_side; j++)
1207 {
1208 std::unique_ptr<Elem> new_elem;
1209
1210 new_elem = std::make_unique<Quad4>();
1211 new_elem->set_node(0, mesh->node_ptr(j + (num_sectors_per_side + 1) * (i)));
1212 new_elem->set_node(1, mesh->node_ptr(j + 1 + (num_sectors_per_side + 1) * (i)));
1213 new_elem->set_node(2, mesh->node_ptr(j + 1 + (num_sectors_per_side + 1) * (i + 1)));
1214 new_elem->set_node(3, mesh->node_ptr(j + (num_sectors_per_side + 1) * (i + 1)));
1215
1216 Elem * elem = mesh->add_elem(std::move(new_elem));
1217
1218 // add subdoamin and boundary IDs
1219 elem->subdomain_id() = PERIPHERAL_ID_SHIFT + id_shift;
1220 if (i == 0)
1221 {
1222 boundary_info.add_side(elem, 0, OUTER_SIDESET_ID);
1223 if (create_inward_interface_boundaries)
1224 boundary_info.add_side(elem, 0, SLICE_ALT + id_shift * 2);
1225 }
1226 if (i == peripheral_invervals - 1)
1227 {
1228 boundary_info.add_side(elem, 2, OUTER_SIDESET_ID);
1229 if (create_outward_interface_boundaries)
1230 boundary_info.add_side(elem, 2, SLICE_ALT + id_shift * 2 + 1);
1231 }
1232 if (j == 0)
1233 boundary_info.add_side(elem, 3, OUTER_SIDESET_ID);
1234 if (j == num_sectors_per_side - 1)
1235 boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
1236 }
1237 }
1238
1239 // convert element to second order if needed
1240 if (quad_elem_type != QUAD_ELEM_TYPE::QUAD4)
1241 {
1242 // full_ordered 2nd order element --> QUAD9, otherwise QUAD8
1243 const bool full_ordered = (quad_elem_type == QUAD_ELEM_TYPE::QUAD9);
1244 mesh->all_second_order(full_ordered);
1245 }
1246
1247 return mesh;
1248}
1249
1250void
1252 MeshBase & out_mesh, const QUAD_ELEM_TYPE boundary_quad_elem_type) const
1253{
1254 const auto side_list = out_mesh.get_boundary_info().build_side_list();
1255
1256 // select out elements on outer boundary
1257 // std::set used to filter duplicate elem_ids
1258 std::set<dof_id_type> elem_set;
1259 for (auto side_item : side_list)
1260 {
1261 boundary_id_type boundary_id = std::get<2>(side_item);
1262 dof_id_type elem_id = std::get<0>(side_item);
1263
1264 if (boundary_id == OUTER_SIDESET_ID)
1265 elem_set.insert(elem_id);
1266 }
1267
1268 // adjust nodes for outer boundary elements
1269 for (const auto elem_id : elem_set)
1270 {
1271 Elem * elem = out_mesh.elem_ptr(elem_id);
1272
1273 // adjust right side mid-edge node
1274 Point pt_5 = (elem->point(1) + elem->point(2)) / 2.0;
1275 out_mesh.add_point(pt_5, elem->node_ptr(5)->id());
1276
1277 // adjust left side mid-edge node
1278 Point pt_7 = (elem->point(0) + elem->point(3)) / 2.0;
1279 out_mesh.add_point(pt_7, elem->node_ptr(7)->id());
1280
1281 // adjust central node when using QUAD9
1282 if (boundary_quad_elem_type == QUAD_ELEM_TYPE::QUAD9)
1283 {
1284 Point pt_8 = elem->true_centroid();
1285 out_mesh.add_point(pt_8, elem->node_ptr(8)->id());
1286 }
1287 }
1288}
1289
1290std::pair<Real, Real>
1292 const Real pi_1_y,
1293 const Real d_po_1_x,
1294 const Real d_po_1_y,
1295 const Real pi_2_x,
1296 const Real pi_2_y,
1297 const Real d_po_2_x,
1298 const Real d_po_2_y,
1299 const unsigned int i,
1300 const unsigned int j,
1301 const unsigned int num_sectors_per_side,
1302 const unsigned int peripheral_intervals) const
1303{
1304 auto position_px_inner =
1305 (pi_1_x * (num_sectors_per_side / 2.0 - j) + pi_2_x * j) / (num_sectors_per_side / 2.0);
1306 auto position_py_inner =
1307 (pi_1_y * (num_sectors_per_side / 2.0 - j) + pi_2_y * j) / (num_sectors_per_side / 2.0);
1308 auto position_px_outer =
1309 (d_po_1_x * (num_sectors_per_side / 2.0 - j) + d_po_2_x * j) / (num_sectors_per_side / 2.0);
1310 auto position_py_outer =
1311 (d_po_1_y * (num_sectors_per_side / 2.0 - j) + d_po_2_y * j) / (num_sectors_per_side / 2.0);
1312 auto position_px = position_px_inner + position_px_outer * i / peripheral_intervals;
1313 auto position_py = position_py_inner + position_py_outer * i / peripheral_intervals;
1314 return std::make_pair(position_px, position_py);
1315}
1316
1317void
1318PolygonMeshGeneratorBase::nodeCoordRotate(Real & x, Real & y, const Real theta) const
1319{
1320 const Real x_tmp = x;
1321 const Real y_tmp = y;
1322 x = x_tmp * std::cos(theta * M_PI / 180.0) - y_tmp * std::sin(theta * M_PI / 180.0);
1323 y = x_tmp * std::sin(theta * M_PI / 180.0) + y_tmp * std::cos(theta * M_PI / 180.0);
1324}
1325
1326void
1328 const Real orientation,
1329 const Real y_max_0,
1330 const Real y_max_n,
1331 const Real y_min,
1332 const unsigned int mesh_type,
1333 const Real unit_angle,
1334 const Real tols) const
1335{
1336 for (auto & node_ptr : as_range(mesh.nodes_begin(), mesh.nodes_end()))
1337 {
1338 // This function can definitely be optimized in future for better efficiency.
1339 Real & x = (*node_ptr)(0);
1340 Real & y = (*node_ptr)(1);
1341 if (mesh_type == CORNER_MESH)
1342 {
1343 nodeCoordRotate(x, y, orientation);
1344 if (x >= 0.0 && y > y_max_0)
1345 y = y - y_max_0 + y_max_n;
1346 else if (x >= 0.0 && y >= y_min)
1347 y = (y - y_min) / (y_max_0 - y_min) * (y_max_n - y_min) + y_min;
1348 else if (y > -x / std::tan(unit_angle / 360.0 * M_PI) + tols && y > y_max_0)
1349 {
1350 x /= y;
1351 y = y - y_max_0 + y_max_n;
1352 x *= y;
1353 }
1354 else if (y > -x / std::tan(unit_angle / 360.0 * M_PI) + tols && y >= y_min)
1355 {
1356 x /= y;
1357 y = (y - y_min) / (y_max_0 - y_min) * (y_max_n - y_min) + y_min;
1358 x *= y;
1359 }
1360 nodeCoordRotate(x, y, -orientation);
1361
1362 nodeCoordRotate(x, y, orientation - unit_angle);
1363 if (x <= 0 && y > y_max_0)
1364 y = y - y_max_0 + y_max_n;
1365 else if (x <= 0 && y >= y_min)
1366 y = (y - y_min) / (y_max_0 - y_min) * (y_max_n - y_min) + y_min;
1367 else if (y >= x / std::tan(unit_angle / 360.0 * M_PI) - tols && y > y_max_0)
1368 {
1369 x /= y;
1370 y = y - y_max_0 + y_max_n;
1371 x *= y;
1372 }
1373 else if (y >= x / std::tan(unit_angle / 360.0 * M_PI) - tols && y >= y_min)
1374 {
1375 x /= y;
1376 y = (y - y_min) / (y_max_0 - y_min) * (y_max_n - y_min) + y_min;
1377 x *= y;
1378 }
1379 nodeCoordRotate(x, y, unit_angle - orientation);
1380 }
1381 else
1382 {
1383 nodeCoordRotate(x, y, orientation);
1384 if (y > y_max_0)
1385 y = y - y_max_0 + y_max_n;
1386 else if (y >= y_min)
1387 y = (y - y_min) / (y_max_0 - y_min) * (y_max_n - y_min) + y_min;
1388 nodeCoordRotate(x, y, -orientation);
1389 }
1390 }
1391}
1392
1393std::pair<Real, Real>
1394PolygonMeshGeneratorBase::fourPointIntercept(const std::pair<Real, Real> & p1,
1395 const std::pair<Real, Real> & p2,
1396 const std::pair<Real, Real> & p3,
1397 const std::pair<Real, Real> & p4) const
1398{
1399 const Real x1 = p1.first;
1400 const Real y1 = p1.second;
1401 const Real x2 = p2.first;
1402 const Real y2 = p2.second;
1403 const Real x3 = p3.first;
1404 const Real y3 = p3.second;
1405 const Real x4 = p4.first;
1406 const Real y4 = p4.second;
1407
1408 Real x = -((x1 - x2) * (y3 * x4 - x3 * y4) - (x3 - x4) * (y1 * x2 - x1 * y2)) /
1409 ((y1 - y2) * (x3 - x4) - (y3 - y4) * (x1 - x2));
1410 Real y = -((y1 - y2) * (y3 * x4 - x3 * y4) - (y3 - y4) * (y1 * x2 - x1 * y2)) /
1411 ((y1 - y2) * (x3 - x4) - (y3 - y4) * (x1 - x2));
1412
1413 return std::make_pair(x, y);
1414}
1415
1416std::vector<Real>
1418 std::vector<Point> & boundary_points,
1419 const Real lower_azi,
1420 const Real upper_azi,
1421 const unsigned int return_type,
1422 const unsigned int num_sides,
1423 const boundary_id_type bid,
1424 const bool calculate_origin,
1425 const Real input_origin_x,
1426 const Real input_origin_y,
1427 const Real tol) const
1428{
1429 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> side_list =
1430 mesh.get_boundary_info().build_side_list();
1431 mesh.get_boundary_info().build_node_list_from_side_list();
1432 std::vector<std::tuple<dof_id_type, boundary_id_type>> node_list =
1433 mesh.get_boundary_info().build_node_list();
1434
1435 std::vector<Real> bd_x_list;
1436 std::vector<Real> bd_y_list;
1437 std::vector<Point> bd_p_list;
1438 Real origin_x = 0.0;
1439 Real origin_y = 0.0;
1440 Real tmp_azi;
1441 const Real mid_azi = lower_azi <= upper_azi ? (lower_azi + upper_azi) / 2.0
1442 : (lower_azi + upper_azi + 360.0) / 2.0;
1443 for (unsigned int i = 0; i < node_list.size(); ++i)
1444 if (std::get<1>(node_list[i]) == bid)
1445 {
1446 bd_x_list.push_back((mesh.node_ref(std::get<0>(node_list[i])))(0));
1447 bd_y_list.push_back((mesh.node_ref(std::get<0>(node_list[i])))(1));
1448 bd_p_list.push_back((mesh.node_ref(std::get<0>(node_list[i]))));
1449 }
1450
1451 if (calculate_origin)
1452 {
1453 const Point origin_pt = MooseMeshUtils::meshCentroidCalculator(mesh);
1454 origin_x = origin_pt(0);
1455 origin_y = origin_pt(1);
1456 }
1457 else
1458 {
1459 origin_x = input_origin_x;
1460 origin_y = input_origin_y;
1461 }
1462
1463 std::vector<std::pair<Real, Point>> azi_point_pairs;
1464
1465 for (unsigned int i = 0; i < bd_x_list.size(); ++i)
1466 {
1467 tmp_azi = atan2(bd_y_list[i] - origin_y, bd_x_list[i] - origin_x) * 180.0 / M_PI;
1468 if ((lower_azi <= upper_azi && (tmp_azi >= lower_azi - tol && tmp_azi <= upper_azi + tol)) ||
1469 (lower_azi > upper_azi && (tmp_azi >= lower_azi - tol || tmp_azi <= upper_azi + tol)))
1470 {
1471 azi_point_pairs.push_back(
1472 std::make_pair(return_type == ANGLE_DEGREE
1473 ? (tmp_azi - mid_azi)
1474 : (1.0 + std::cos(M_PI / num_sides) / std::sin(M_PI / num_sides) *
1475 std::tan((tmp_azi - mid_azi) / 180.0 * M_PI)),
1476 bd_p_list[i]));
1477 }
1478 }
1479 std::sort(azi_point_pairs.begin(), azi_point_pairs.end());
1480
1481 std::vector<Real> azimuthal_output;
1482 for (auto it = std::make_move_iterator(azi_point_pairs.begin()),
1483 end = std::make_move_iterator(azi_point_pairs.end());
1484 it != end;
1485 it++)
1486 {
1487 azimuthal_output.push_back(std::move(it->first));
1488 boundary_points.push_back(std::move(it->second));
1489 }
1490
1491 return azimuthal_output;
1492}
1493
1494std::vector<Real>
1496 const Real lower_azi,
1497 const Real upper_azi,
1498 const unsigned int return_type,
1499 const unsigned int num_sides,
1500 const boundary_id_type bid,
1501 const bool calculate_origin,
1502 const Real input_origin_x,
1503 const Real input_origin_y,
1504 const Real tol) const
1505{
1506 std::vector<Point> boundary_points;
1508 boundary_points,
1509 lower_azi,
1510 upper_azi,
1511 return_type,
1512 num_sides,
1513 bid,
1514 calculate_origin,
1515 input_origin_x,
1516 input_origin_y,
1517 tol);
1518}
1519
1520std::vector<std::vector<Real>>
1522 const std::vector<Real> radial_biases,
1523 const std::vector<unsigned int> intervals,
1524 const multiBdryLayerParams inner_boundary_layer_params,
1525 const multiBdryLayerParams outer_boundary_layer_params) const
1526{
1527 std::vector<std::vector<Real>> bias_terms_vec;
1528 for (unsigned int i = 0; i < radial_biases.size(); i++)
1529 bias_terms_vec.push_back(biasTermsCalculator(radial_biases[i],
1530 intervals[i],
1531 {0.0,
1532 inner_boundary_layer_params.fractions[i],
1533 inner_boundary_layer_params.intervals[i],
1534 inner_boundary_layer_params.biases[i]},
1535 {0.0,
1536 outer_boundary_layer_params.fractions[i],
1537 outer_boundary_layer_params.intervals[i],
1538 outer_boundary_layer_params.biases[i]}));
1539 return bias_terms_vec;
1540}
1541
1542std::vector<Real>
1544 const Real radial_bias,
1545 const unsigned int intervals,
1546 const singleBdryLayerParams inner_boundary_layer_params,
1547 const singleBdryLayerParams outer_boundary_layer_params) const
1548{
1549 // To get biased indices:
1550 // If no bias is involved, namely bias factor = 1.0, the increment in indices is uniform.
1551 // Thus, (i + 1) is used to get such linearly increasing indices.
1552 // If a non-trivial bias factor q is used, the increment in the indices is geometric
1553 // progression. So, if first (i = 0) increment is 1.0, second (i = 1) is q, third (i = 2) is
1554 // q^2,..., last or n_interval'th is q^(n_interval - 1). Then, the summation of the first (i +
1555 // 1) increments over the summation of all n_interval increments is the (i + 1)th index The
1556 // summation of the first (i + 1) increments is (1.0 - q^(i + 1)) / (1 - q); The summation of
1557 // all n_interval increments is (1.0 - q^n_interval) / (1 - q); Thus, the index is (1.0 - q^(i +
1558 // 1)) / (1.0 - q^n_interval)
1559 // This approach is used by inner boundary layer, main region, outer boundary layer separately.
1560
1561 std::vector<Real> biased_terms;
1562 for (unsigned int i = 0; i < inner_boundary_layer_params.intervals; i++)
1563 biased_terms.push_back(
1564 MooseUtils::absoluteFuzzyEqual(inner_boundary_layer_params.bias, 1.0)
1565 ? ((Real)(i + 1) * inner_boundary_layer_params.fraction /
1566 (Real)inner_boundary_layer_params.intervals)
1567 : ((1.0 - std::pow(inner_boundary_layer_params.bias, (Real)(i + 1))) /
1568 (1.0 - std::pow(inner_boundary_layer_params.bias,
1569 (Real)(inner_boundary_layer_params.intervals))) *
1570 inner_boundary_layer_params.fraction));
1571 for (unsigned int i = 0; i < intervals; i++)
1572 biased_terms.push_back(inner_boundary_layer_params.fraction +
1573 (MooseUtils::absoluteFuzzyEqual(radial_bias, 1.0)
1574 ? ((Real)(i + 1) *
1575 (1.0 - inner_boundary_layer_params.fraction -
1576 outer_boundary_layer_params.fraction) /
1577 (Real)intervals)
1578 : ((1.0 - std::pow(radial_bias, (Real)(i + 1))) /
1579 (1.0 - std::pow(radial_bias, (Real)(intervals))) *
1580 (1.0 - inner_boundary_layer_params.fraction -
1581 outer_boundary_layer_params.fraction))));
1582 for (unsigned int i = 0; i < outer_boundary_layer_params.intervals; i++)
1583 biased_terms.push_back(
1584 1.0 - outer_boundary_layer_params.fraction +
1585 (MooseUtils::absoluteFuzzyEqual(outer_boundary_layer_params.bias, 1.0)
1586 ? ((Real)(i + 1) * outer_boundary_layer_params.fraction /
1587 (Real)outer_boundary_layer_params.intervals)
1588 : ((1.0 - std::pow(outer_boundary_layer_params.bias, (Real)(i + 1))) /
1589 (1.0 - std::pow(outer_boundary_layer_params.bias,
1590 (Real)(outer_boundary_layer_params.intervals))) *
1591 outer_boundary_layer_params.fraction)));
1592 return biased_terms;
1593}
1594
1595void
1597{
1598 params.addParam<std::string>("sector_id_name",
1599 "Name of integer (reporting) ID for sector regions to use the "
1600 "reporting ID for azimuthal sector regions of ring geometry block.");
1601 params.addParam<std::string>("ring_id_name",
1602 "Name of integer (reporting) ID for ring regions to use the "
1603 "reporting ID for annular regions of ring geometry block.");
1604 MooseEnum ring_id_option("block_wise ring_wise", "block_wise");
1605 params.addParam<MooseEnum>(
1606 "ring_id_assign_type", ring_id_option, "Type of ring ID assignment: block_wise or ring_wise");
1607 params.addParamNamesToGroup("sector_id_name ring_id_name ring_id_assign_type", "Ring/Sector IDs");
1608}
1609
1610void
1612 const std::string id_name,
1613 const unsigned int num_sides,
1614 const std::vector<unsigned int> num_sectors_per_side)
1615{
1616 const auto extra_id_index = mesh.add_elem_integer(id_name);
1617 // vector to store sector ids for each element
1618 auto elem_it = mesh.elements_begin();
1619 unsigned int id = 1;
1620 // starting element id of the current sector
1621 for (unsigned int is = 0; is < num_sides; ++is)
1622 {
1623 // number of elements in the current sector
1624 unsigned int nelem_sector =
1625 mesh.n_elem() * num_sectors_per_side[is] /
1626 (accumulate(num_sectors_per_side.begin(), num_sectors_per_side.end(), 0));
1627 // assign sector ids to mesh
1628 for (unsigned i = 0; i < nelem_sector; ++i, ++elem_it)
1629 (*elem_it)->set_extra_integer(extra_id_index, id);
1630 // update sector id
1631 ++id;
1632 }
1633}
1634
1635void
1637 const std::string id_name,
1638 const unsigned int num_sides,
1639 const std::vector<unsigned int> num_sectors_per_side,
1640 const std::vector<unsigned int> ring_intervals,
1641 const bool ring_wise_id,
1642 const bool quad_center_elements)
1643{
1644 // this function assumes that elements are ordered by rings (inner) then by sectors (outer
1645 // ordering)
1646 const auto extra_id_index = mesh.add_elem_integer(id_name);
1647 auto elem_it = mesh.elements_begin();
1648 for (unsigned int is = 0; is < num_sides; ++is)
1649 {
1650 // number of elements in the current sector
1651 unsigned int nelem = mesh.n_elem() * num_sectors_per_side[is] /
1652 (accumulate(num_sectors_per_side.begin(), num_sectors_per_side.end(), 0));
1653 if (!ring_wise_id)
1654 {
1655 for (unsigned int ir : index_range(ring_intervals))
1656 {
1657 // number of elements in the current ring and sector
1658 unsigned int nelem_annular_ring = num_sectors_per_side[is] * ring_intervals[ir];
1659 // if _quad_center_elements is true, the number of elements in center ring are
1660 // _num_sectors_per_side[is] * _num_sectors_per_side[is] / 4
1661 if (quad_center_elements && ir == 0)
1662 nelem_annular_ring = num_sectors_per_side[is] * (ring_intervals[ir] - 1) +
1663 num_sectors_per_side[is] * num_sectors_per_side[is] / 4;
1664 // assign ring id
1665 for (unsigned i = 0; i < nelem_annular_ring; ++i, ++elem_it)
1666 (*elem_it)->set_extra_integer(extra_id_index, ir + 1);
1667 // update number of elements in background region of current side.
1668 nelem -= nelem_annular_ring;
1669 }
1670 }
1671 else
1672 {
1673 unsigned int ir = 0;
1674 for (unsigned int ir0 : index_range(ring_intervals))
1675 {
1676 for (unsigned int ir1 = 0; ir1 < ring_intervals[ir0]; ++ir1)
1677 {
1678 // number of elements in the current ring and sector
1679 unsigned int nelem_annular_ring = num_sectors_per_side[is];
1680 // if _quad_center_elements is true, the number of elements in center ring are
1681 // _num_sectors_per_side[is] * _num_sectors_per_side[is] / 4
1682 if (quad_center_elements && ir == 0)
1683 nelem_annular_ring = num_sectors_per_side[is] * num_sectors_per_side[is] / 4;
1684 // assign ring id
1685 for (unsigned i = 0; i < nelem_annular_ring; ++i, ++elem_it)
1686 (*elem_it)->set_extra_integer(extra_id_index, ir + 1);
1687 // update ring id
1688 ++ir;
1689 // update number of elements in background region of current side.
1690 nelem -= nelem_annular_ring;
1691 }
1692 }
1693 }
1694 // assign ring id of 0 to the background region
1695 for (unsigned i = 0; i < nelem; ++i, ++elem_it)
1696 (*elem_it)->set_extra_integer(extra_id_index, 0);
1697 }
1698}
1699
1700void
1702 const boundary_id_type id_shift,
1703 const std::set<boundary_id_type> & boundary_ids,
1704 const bool reverse)
1705{
1706 const std::set<boundary_id_type> existing_boundary_ids =
1707 mesh.get_boundary_info().get_boundary_ids();
1708 for (const auto id : boundary_ids)
1709 {
1710
1711 const boundary_id_type old_id = (!reverse) ? id : id + id_shift;
1712 const boundary_id_type new_id = (!reverse) ? id + id_shift : id;
1713 auto it = existing_boundary_ids.find(old_id);
1714 if (it != existing_boundary_ids.end())
1715 MooseMesh::changeBoundaryId(mesh, old_id, new_id, true);
1716 }
1717}
1718
1719std::set<boundary_id_type>
1721 const std::vector<std::vector<unsigned int>> & pattern,
1722 const std::vector<std::vector<boundary_id_type>> & interface_boundary_id_shift_pattern,
1723 const std::set<boundary_id_type> & boundary_ids,
1724 const std::vector<std::set<boundary_id_type>> & input_interface_boundary_ids,
1725 const bool use_interface_boundary_id_shift,
1726 const bool create_interface_boundary_id,
1727 const unsigned int num_extra_layers) const
1728{
1729 std::set<boundary_id_type> interface_boundary_ids;
1730 // add existing interface boundary ids from input meshes
1731 if (use_interface_boundary_id_shift)
1732 {
1733 for (const auto i : make_range(pattern.size()))
1734 for (const auto j : make_range(pattern[i].size()))
1735 {
1736 const auto & ids = input_interface_boundary_ids[pattern[i][j]];
1737 for (const auto & id : ids)
1738 {
1739 const boundary_id_type new_id = id + interface_boundary_id_shift_pattern[i][j];
1740 auto it = boundary_ids.find(new_id);
1741 if (it != boundary_ids.end())
1742 interface_boundary_ids.insert(new_id);
1743 }
1744 }
1745 }
1746 else
1747 {
1748 for (const auto & ids : input_interface_boundary_ids)
1749 for (const auto & id : ids)
1750 {
1751 auto it = boundary_ids.find(id);
1752 if (it != boundary_ids.end())
1753 interface_boundary_ids.insert(id);
1754 }
1755 }
1756 // add unshifted interface boundary ids for the duct & background regions
1757 if (create_interface_boundary_id)
1758 for (const auto i : make_range(num_extra_layers))
1759 {
1760 boundary_id_type id = SLICE_ALT + i * 2 + 1;
1761 auto it = boundary_ids.find(id);
1762 if (it != boundary_ids.end())
1763 interface_boundary_ids.insert(id);
1764 id = SLICE_ALT + i * 2;
1765 it = boundary_ids.find(id);
1766 if (it != boundary_ids.end())
1767 interface_boundary_ids.insert(id);
1768 }
1769 return interface_boundary_ids;
1770}
1771
1774 const multiBdryLayerParams & original_multi_bdry_layer_params, const unsigned int order) const
1775{
1776 multiBdryLayerParams mod_multi_bdry_layer_params(original_multi_bdry_layer_params);
1777 std::for_each(mod_multi_bdry_layer_params.intervals.begin(),
1778 mod_multi_bdry_layer_params.intervals.end(),
1779 [&order](unsigned int & n) { n *= order; });
1780 std::for_each(mod_multi_bdry_layer_params.biases.begin(),
1781 mod_multi_bdry_layer_params.biases.end(),
1782 [&order](Real & n) { n = std::pow(n, 1.0 / order); });
1783 return mod_multi_bdry_layer_params;
1784}
1785
1788 const singleBdryLayerParams & original_single_bdry_layer_params, const unsigned int order) const
1789{
1790 singleBdryLayerParams mod_single_bdry_layer_params(original_single_bdry_layer_params);
1791 mod_single_bdry_layer_params.intervals *= order;
1792 mod_single_bdry_layer_params.bias = std::pow(mod_single_bdry_layer_params.bias, 1.0 / order);
1793 return mod_single_bdry_layer_params;
1794}
1795
1796std::string
1798 const std::vector<MeshGeneratorName> & input_names,
1799 const std::vector<Real> & metadata_vals,
1800 const std::string & metadata_name) const
1801{
1802 FormattedTable table;
1803 for (unsigned int i = 0; i < input_names.size(); i++)
1804 {
1805 table.addRow(i);
1806 table.addData<std::string>("input name", (std::string)input_names[i]);
1807 table.addData<Real>(metadata_name, metadata_vals[i]);
1808 }
1809 table.outputTimeColumn(false);
1810 std::stringstream detailed_error;
1811 table.printTable(detailed_error);
1812 return "\n" + detailed_error.str();
1813}
const std::vector< double > y
const double tol
const std::vector< double > x
void printTable(std::ostream &out, unsigned int last_n_entries=0)
void addData(const std::string &name, const T &value)
void addRow(Real time)
void outputTimeColumn(bool output_time)
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
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)
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
static InputParameters validParams()
const std::string & name() const
void mooseError(Args &&... args) const
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 cenTriElemDef(ReplicatedMesh &mesh, const unsigned int num_sectors_per_side, const std::vector< Real > azimuthal_tangent=std::vector< Real >(), const subdomain_id_type block_id_shift=0, const bool create_outward_interface_boundaries=true, const boundary_id_type boundary_id_shift=0, const bool assign_external_boundary=false, const unsigned int side_index=0, const bool generate_side_specific_boundaries=true, const TRI_ELEM_TYPE tri_elem_type=TRI_ELEM_TYPE::TRI3) const
Defines triangular elements in the very central region of the polygon.
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
std::set< boundary_id_type > getInterfaceBoundaryIDs(const std::vector< std::vector< unsigned int > > &pattern, const std::vector< std::vector< boundary_id_type > > &interface_boundary_id_shift_pattern, const std::set< boundary_id_type > &boundary_ids, const std::vector< std::set< boundary_id_type > > &input_interface_boundary_ids, const bool use_interface_boundary_id_shift, const bool create_interface_boundary_id, const unsigned int num_extra_layers) const
returns a list of interface boundary IDs on the mesh generated by this mesh generator
PolygonMeshGeneratorBase(const InputParameters &parameters)
void cutOffPolyDeform(MeshBase &mesh, const Real orientation, const Real y_max_0, const Real y_max_n, const Real y_min, const unsigned int mesh_type, const Real unit_angle=60.0, const Real tols=1E-5) const
Deforms peripheral region when the external side of a polygon assembly of stitched meshes cuts off th...
static void addRingAndSectorIDParams(InputParameters &params)
Add InputParameters which are used by ring and sector IDs.
void backgroundNodes(ReplicatedMesh &mesh, const unsigned int num_sectors_per_side, const unsigned int background_intervals, const std::vector< Real > biased_terms, const Real background_corner_distance, const Real background_corner_radial_interval_length, const Real corner_p[2][2], const Real corner_to_corner, const Real background_in, const std::vector< Real > azimuthal_tangent=std::vector< Real >()) const
Creates nodes for the ring-to-polygon transition region (i.e., background) of a single slice.
std::unique_ptr< ReplicatedMesh > buildSimplePeripheral(const unsigned int num_sectors_per_side, const unsigned int peripheral_invervals, const std::vector< std::pair< Real, Real > > &position_inner, const std::vector< std::pair< Real, Real > > &d_position_outer, const subdomain_id_type id_shift, const QUAD_ELEM_TYPE quad_elem_type, const bool create_inward_interface_boundaries=false, const bool create_outward_interface_boundaries=true)
Creates peripheral area mesh for the patterned hexagon mesh.
std::unique_ptr< ReplicatedMesh > buildSlice(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 Real virtual_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 Real pitch_scale_factor=1.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)
Generates a mesh of a polygon slice, which is the foundation of both buildGeneralSlice and buildSimpl...
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
virtual std::unique_ptr< MeshBase > generate() override
std::unique_ptr< ReplicatedMesh > buildGeneralSlice(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 primary_side_length, const Real secondary_side_length, 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 Real azimuthal_angle, const std::vector< Real > azimuthal_tangent, const unsigned int side_index, const bool quad_center_elements, const Real center_quad_factor, const Real rotation_angle, const bool generate_side_specific_boundaries=true)
Creates a mesh of a general polygon slice with a triangular shape and circular regions on one of its ...
singleBdryLayerParams modifiedSingleBdryLayerParamsCreator(const singleBdryLayerParams &original_single_bdry_layer_params, const unsigned int order) const
Modifies the input single boundary layer parameters for node generation, especially for the quadratic...
static InputParameters validParams()
multiBdryLayerParams modifiedMultiBdryLayerParamsCreator(const multiBdryLayerParams &original_multi_bdry_layer_params, const unsigned int order) const
Modifies the input multi boundary layer parameters for node generation, especially for the quadratic ...
std::pair< Real, Real > fourPointIntercept(const std::pair< Real, Real > &p1, const std::pair< Real, Real > &p2, const std::pair< Real, Real > &p3, const std::pair< Real, Real > &p4) const
Finds the center of a quadrilateral based on four vertices.
void ringNodes(ReplicatedMesh &mesh, const std::vector< Real > ring_radii, const std::vector< unsigned int > ring_layers, const std::vector< std::vector< Real > > biased_terms, const unsigned int num_sectors_per_side, const Real corner_p[2][2], const Real corner_to_corner, const std::vector< Real > azimuthal_tangent=std::vector< Real >()) const
Creates nodes for the ring-geometry region of a single slice.
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.
void reassignBoundaryIDs(MeshBase &mesh, const boundary_id_type id_shift, const std::set< boundary_id_type > &boundary_ids, const bool reverse=false)
reassign interface boundary IDs on the input mesh by applying the boundary ID shift
std::pair< Real, Real > pointInterpolate(const Real pi_1_x, const Real pi_1_y, const Real po_1_x, const Real po_1_y, const Real pi_2_x, const Real pi_2_y, const Real po_2_x, const Real po_2_y, const unsigned int i, const unsigned int j, const unsigned int num_sectors_per_side, const unsigned int peripheral_intervals) const
Calculates the point coordinates of within a parallelogram region using linear interpolation.
void quadElemDef(ReplicatedMesh &mesh, const unsigned int num_sectors_per_side, const std::vector< unsigned int > subdomain_rings, const unsigned int side_index, const std::vector< Real > azimuthal_tangent=std::vector< Real >(), const subdomain_id_type block_id_shift=0, const dof_id_type nodeid_shift=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 QUAD_ELEM_TYPE quad_elem_type=QUAD_ELEM_TYPE::QUAD4) const
Defines general quad elements for the polygon.
void adjustPeripheralQuadraticElements(MeshBase &out_mesh, const QUAD_ELEM_TYPE boundary_quad_elem_type) const
Adjusts the mid-edge node locations in boundary regions when using quadratic elements with uniform bo...
std::vector< std::vector< Real > > biasTermsCalculator(const std::vector< Real > radial_biases, const std::vector< unsigned int > intervals, const multiBdryLayerParams inner_boundary_layer_params, const multiBdryLayerParams outer_boundary_layer_params) const
Creates bias terms for multiple blocks.
void centerNodes(ReplicatedMesh &mesh, const Real virtual_side_number, const unsigned int div_num, const Real ring_radii_0, std::vector< std::vector< Node * > > &nodes) const
Creates nodes of the very central mesh layer of the polygon for quad central elements.
std::string pitchMetaDataErrorGenerator(const std::vector< MeshGeneratorName > &input_names, const std::vector< Real > &metadata_vals, const std::string &metadata_name) const
Generate a string that contains the detailed metadata information for inconsistent input mesh metadat...
void ductNodes(ReplicatedMesh &mesh, std::vector< Real > *const ducts_center_dist, const std::vector< unsigned int > ducts_layers, const std::vector< std::vector< Real > > biased_terms, const unsigned int num_sectors_per_side, const Real corner_p[2][2], const Real corner_to_corner, const std::vector< Real > azimuthal_tangent=std::vector< Real >()) const
Creates nodes for the duct-geometry region of a single slice.
void cenQuadElemDef(ReplicatedMesh &mesh, const unsigned int div_num, const subdomain_id_type block_id_shift, const bool create_outward_interface_boundaries, const boundary_id_type boundary_id_shift, std::vector< std::vector< Node * > > &nodes, const bool assign_external_boundary=false, const unsigned int side_index=0, const bool generate_side_specific_boundaries=true, const QUAD_ELEM_TYPE quad_elem_type=QUAD_ELEM_TYPE::QUAD4) const
Defines quad elements in the very central region of the polygon.
MeshBase & mesh
Point meshCentroidCalculator(const MeshBase &mesh)
Contains multiple blocks's boundary layer related parameters.
Contains a single block's boundary layer related parameters.