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