https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PeripheralRingMeshGenerator.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
12#include "MooseMeshUtils.h"
13#include "MooseUtils.h"
14#include "LinearInterpolation.h"
17#include "libmesh/int_range.h"
18
19// C++ includes
20#include <cmath> // for atan2
21
23
26{
28 params.addRequiredParam<MeshGeneratorName>("input", "The input mesh to be modified.");
29 params.addParam<bool>(
30 "force_input_centroid_as_center",
31 false,
32 "Whether to enforce use of the centroid position of the input mesh as the "
33 "center of the peripheral ring by translating the input mesh to the origin.");
34
35 params.addRangeCheckedParam<unsigned int>(
36 "peripheral_layer_num",
37 3,
38 "peripheral_layer_num>0",
39 "The radial layers of the peripheral ring to be added.");
40 params.addRangeCheckedParam<Real>(
41 "peripheral_radial_bias",
42 1.0,
43 "peripheral_radial_bias>0",
44 "Value used to create biasing in radial meshing for peripheral ring region.");
45 params.addRangeCheckedParam<Real>(
46 "peripheral_inner_boundary_layer_width",
47 0.0,
48 "peripheral_inner_boundary_layer_width>=0",
49 "Width of peripheral ring region that is assigned to be the inner boundary layer.");
50 params.addRangeCheckedParam<unsigned int>(
51 "peripheral_inner_boundary_layer_intervals",
52 1,
53 "peripheral_inner_boundary_layer_intervals>0",
54 "Number of radial intervals of the peripheral ring inner boundary layer");
55 params.addRangeCheckedParam<Real>(
56 "peripheral_inner_boundary_layer_bias",
57 1.0,
58 "peripheral_inner_boundary_layer_bias>0",
59 "Growth factor used for mesh biasing of the peripheral ring inner boundary layer.");
60 params.addRangeCheckedParam<Real>(
61 "peripheral_outer_boundary_layer_width",
62 0.0,
63 "peripheral_outer_boundary_layer_width>=0",
64 "Width of peripheral ring region that is assigned to be the outer boundary layer.");
65 params.addRangeCheckedParam<unsigned int>(
66 "peripheral_outer_boundary_layer_intervals",
67 1,
68 "peripheral_outer_boundary_layer_intervals>0",
69 "Number of radial intervals of the peripheral ring outer boundary layer");
70 params.addRangeCheckedParam<Real>(
71 "peripheral_outer_boundary_layer_bias",
72 1.0,
73 "peripheral_outer_boundary_layer_bias>0",
74 "Growth factor used for mesh biasing of the peripheral ring outer boundary layer.");
75 params.addRequiredRangeCheckedParam<Real>("peripheral_ring_radius",
76 "peripheral_ring_radius>0",
77 "Radius of the peripheral ring to be added.");
78 params.addParam<bool>(
79 "preserve_volumes",
80 true,
81 "Whether the volume of the peripheral region is preserved by fixing the radius.");
82 params.addRequiredParam<BoundaryName>("input_mesh_external_boundary",
83 "The external boundary of the input mesh.");
84 params.addRequiredParam<subdomain_id_type>(
85 "peripheral_ring_block_id", "The block id assigned to the created peripheral layer.");
86 params.addParam<SubdomainName>("peripheral_ring_block_name",
87 "The block name assigned to the created peripheral layer.");
88 params.addRangeCheckedParam<boundary_id_type>("external_boundary_id",
89 "external_boundary_id>0",
90 "Optional customized external boundary id.");
91 params.addParam<BoundaryName>(
92 "external_boundary_name", "", "Optional customized external boundary name.");
94 "peripheral_radial_bias peripheral_inner_boundary_layer_width "
95 "peripheral_inner_boundary_layer_intervals peripheral_inner_boundary_layer_bias "
96 "peripheral_outer_boundary_layer_width peripheral_outer_boundary_layer_intervals "
97 "peripheral_outer_boundary_layer_bias",
98 "Mesh Boundary Layer and Biasing Options");
99 params.addClassDescription("This PeripheralRingMeshGenerator object adds a circular peripheral "
100 "region to the input mesh.");
101
102 return params;
103}
104
106 : PolygonMeshGeneratorBase(parameters),
107 _input_name(getParam<MeshGeneratorName>("input")),
108 _force_input_centroid_as_center(getParam<bool>("force_input_centroid_as_center")),
109 _peripheral_layer_num(getParam<unsigned int>("peripheral_layer_num")),
110 _peripheral_radial_bias(getParam<Real>("peripheral_radial_bias")),
111 _peripheral_inner_boundary_layer_params(
112 {getParam<Real>("peripheral_inner_boundary_layer_width"),
113 0.0,
114 getParam<Real>("peripheral_inner_boundary_layer_width") > 0.0
115 ? getParam<unsigned int>("peripheral_inner_boundary_layer_intervals")
116 : 0,
117 getParam<Real>("peripheral_inner_boundary_layer_bias")}),
118 _peripheral_outer_boundary_layer_params(
119 {getParam<Real>("peripheral_outer_boundary_layer_width"),
120 0.0,
121 getParam<Real>("peripheral_outer_boundary_layer_width") > 0.0
122 ? getParam<unsigned int>("peripheral_outer_boundary_layer_intervals")
123 : 0,
124 getParam<Real>("peripheral_outer_boundary_layer_bias")}),
125 _peripheral_ring_radius(getParam<Real>("peripheral_ring_radius")),
126 _preserve_volumes(getParam<bool>("preserve_volumes")),
127 _input_mesh_external_boundary(getParam<BoundaryName>("input_mesh_external_boundary")),
128 _peripheral_ring_block_id(getParam<subdomain_id_type>("peripheral_ring_block_id")),
129 _peripheral_ring_block_name(isParamValid("peripheral_ring_block_name")
130 ? getParam<SubdomainName>("peripheral_ring_block_name")
131 : (SubdomainName) ""),
132 _external_boundary_id(isParamValid("external_boundary_id")
133 ? getParam<boundary_id_type>("external_boundary_id")
134 : 0),
135 _external_boundary_name(getParam<BoundaryName>("external_boundary_name")),
136 _input(getMeshByName(_input_name))
137{
138 declareMeshProperty<bool>("hexagon_peripheral_trimmability", false);
139 declareMeshProperty<bool>("hexagon_center_trimmability", false);
140 declareMeshProperty<bool>("square_peripheral_trimmability", false);
141 declareMeshProperty<bool>("square_center_trimmability", false);
142}
143
144std::unique_ptr<MeshBase>
146{
147 if (hasMeshProperty<bool>("hexagon_center_trimmability", _input_name))
148 setMeshProperty("hexagon_center_trimmability",
149 getMeshProperty<bool>("hexagon_center_trimmability", _input_name));
150 if (hasMeshProperty<bool>("square_center_trimmability", _input_name))
151 setMeshProperty("square_center_trimmability",
152 getMeshProperty<bool>("square_center_trimmability", _input_name));
153
154 // Need ReplicatedMesh for stitching
155 auto input_mesh = dynamic_cast<ReplicatedMesh *>(_input.get());
156 if (!input_mesh)
157 paramError("input", "Input is not a replicated mesh, which is required.");
158
159 if (!input_mesh->preparation().has_cached_elem_data)
160 input_mesh->cache_elem_data();
161 if (*(input_mesh->elem_dimensions().begin()) != 2 ||
162 *(input_mesh->elem_dimensions().rbegin()) != 2)
163 paramError("input", "Only 2D meshes are supported.");
164
168 paramError("input_mesh_external_boundary",
169 "External boundary does not exist in the input mesh");
170 // We check the element types of input mesh's external boundary here.
171 // We support both linear and quadratic sides (i.e., EDGE2 and EDGE3), but we cannot support mixed
172 // sides
173 auto side_list_tmp = input_mesh->get_boundary_info().build_side_list();
174 bool linear_side = false;
175 bool quadratic_side = false;
176 for (const auto & side : side_list_tmp)
177 {
178 if (std::get<2>(side) == _input_mesh_external_bid)
179 {
180 const auto etype = input_mesh->elem_ptr(std::get<0>(side))->side_type(std::get<1>(side));
181 if (etype == EDGE2)
182 linear_side = true;
183 else if (etype == EDGE3)
184 quadratic_side = true;
185 else
186 paramError("input", "Input contains elements that are not supported by this generator.");
187 }
188 }
189 if (linear_side && quadratic_side)
190 paramError("input", "Input contains mixed element types on the external boundary.");
191 const unsigned int order = linear_side ? 1 : 2;
192 if (order == 2)
193 {
201 }
202
203 // Move the centroid of the mesh to (0, 0, 0) if input centroid is enforced to be the ring center.
204 const Point input_mesh_centroid = MooseMeshUtils::meshCentroidCalculator(*input_mesh);
206 MeshTools::Modification::translate(
207 *input_mesh, -input_mesh_centroid(0), -input_mesh_centroid(1), -input_mesh_centroid(2));
208
209 // Use CoM of the input mesh as its origin for azimuthal calculation
210 const Point origin_pt =
211 _force_input_centroid_as_center ? Point(0.0, 0.0, 0.0) : input_mesh_centroid;
212 // Vessel for containing maximum radius of the boundary nodes
213 Real max_input_mesh_node_radius;
214
215 // Calculate biasing terms
216 // For 2nd order mesh, as we need the mid points, the bias factor is square rooted.
217 const auto main_peripheral_bias_terms =
219 const auto inner_peripheral_bias_terms =
222 // It is easier to create outer boundary layer inversely (inwards). Thus, 1.0 / bias is used here.
223 // However, the input parameter definition is not affected.
224 const auto outer_peripheral_bias_terms =
227
228 const unsigned int total_peripheral_layer_num =
231
232 // Collect the external boundary nodes of the input mesh using the utility function
233 std::vector<dof_id_type> boundary_ordered_node_list;
234 try
235 {
237 max_input_mesh_node_radius,
238 boundary_ordered_node_list,
239 origin_pt,
241 }
242 catch (MooseException & e)
243 {
244 if (((std::string)e.what()).compare("The node list provided has more than one segments.") == 0)
245 paramError("input_mesh_external_boundary",
246 "This mesh generator does not work for the provided external boundary as it has "
247 "more than one segments.");
248 else
249 paramError("input_mesh_external_boundary", e.what());
250 }
251
252 if (max_input_mesh_node_radius >= _peripheral_ring_radius)
254 "peripheral_ring_radius",
255 "The peripheral ring to be generated must be large enough to cover the entire input mesh.");
257 paramError("input_mesh_external_boundary",
258 "The boundary provided is not an external boundary.");
259
260 std::vector<Point> input_ext_bd_pts;
261 std::vector<Point> output_ext_bd_pts;
262 std::vector<std::tuple<Real, Point, Point>> azi_points;
263 std::vector<Real> azi_array;
264 Real tmp_azi(0.0);
265 auto mesh = buildReplicatedMesh(2);
266
267 // Node counter for the external boundary
268 unsigned int input_ext_node_num = 0;
269
270 // As the node list collected before is a simple closed loop, the last node is the same as the
271 // first node. We remove it here.
272 boundary_ordered_node_list.pop_back();
273 // Loop over all the boundary nodes
274 // For quadratic sides, the middle points are included automatically
275 for (const auto i : index_range(boundary_ordered_node_list))
276 {
277 input_ext_node_num++;
278 // Define nodes on the inner and outer boundaries of the peripheral region.
279 input_ext_bd_pts.push_back(input_mesh->point(boundary_ordered_node_list[i]));
280 tmp_azi =
281 atan2(input_ext_bd_pts.back()(1) - origin_pt(1), input_ext_bd_pts.back()(0) - origin_pt(0));
282 output_ext_bd_pts.push_back(Point(_peripheral_ring_radius * std::cos(tmp_azi),
283 _peripheral_ring_radius * std::sin(tmp_azi),
284 origin_pt(2)));
285 // a vector of tuples using azimuthal angle as the key to facilitate sorting
286 azi_points.push_back(
287 std::make_tuple(tmp_azi, input_ext_bd_pts.back(), output_ext_bd_pts.back()));
288 // a simple vector of azimuthal angles for radius correction purposes (in degree)
289 azi_array.push_back(tmp_azi / M_PI * 180.0);
290 }
291 // Only for quadratic sides, if the index of the first node after sorting is even, it is a vertex
292 // node; otherwise, it is a midpoint node.
293 const bool is_first_node_vertex =
294 order == 1 ||
295 !(std::distance(azi_array.begin(), std::min_element(azi_array.begin(), azi_array.end())) % 2);
296 std::sort(azi_points.begin(), azi_points.end());
297 std::sort(azi_array.begin(), azi_array.end());
298
299 // Angles defined by three neighboring nodes on input mesh's external boundary
300 std::vector<Real> input_bdry_angles;
301 // Normal directions of input boundary nodes
302 std::vector<Point> input_bdry_nd;
303 for (const auto i : index_range(azi_points))
304 {
305 Point p1, p2;
306 const Point pn = Point(0.0, 0.0, 1.0);
307 if (i == 0)
308 {
309 p1 = std::get<1>(azi_points[i + 1]) - std::get<1>(azi_points[i]);
310 p2 = std::get<1>(azi_points.back()) - std::get<1>(azi_points[i]);
311 }
312 else if (i == azi_points.size() - 1)
313 {
314 p1 = std::get<1>(azi_points.front()) - std::get<1>(azi_points.back());
315 p2 = std::get<1>(azi_points[i - 1]) - std::get<1>(azi_points.back());
316 }
317 else
318 {
319 p1 = std::get<1>(azi_points[i + 1]) - std::get<1>(azi_points[i]);
320 p2 = std::get<1>(azi_points[i - 1]) - std::get<1>(azi_points[i]);
321 }
322 // Use cross point to get perpendicular direction
323 const Point p1n = (p1.cross(pn)).unit();
324 const Point p2n = -(p2.cross(pn)).unit();
325 Real tmp = p1 * p2 / p1.norm() / p2.norm();
326 // Make sure acos() gets valid input
327 tmp = tmp > 1.0 ? 1.0 : (tmp < -1.0 ? -1.0 : tmp);
328 input_bdry_angles.push_back(acos(tmp) / 2.0);
329 input_bdry_nd.push_back((p1n + p2n).unit());
330 }
331
332 // 2D vector containing all the node positions of the peripheral region
333 std::vector<std::vector<Point>> points_array(total_peripheral_layer_num + 1,
334 std::vector<Point>(input_ext_node_num));
335 // 2D vector containing all the node ids of the peripheral region
336 std::vector<std::vector<dof_id_type>> node_id_array(total_peripheral_layer_num + 1,
337 std::vector<dof_id_type>(input_ext_node_num));
338 // Reference outmost layer of inner boundary layer
339 std::vector<Point> ref_inner_bdry_surf;
340 // First loop
341 for (const auto i : make_range(input_ext_node_num))
342 {
343 // Inner boundary nodes of the peripheral region
344 points_array[0][i] = std::get<1>(azi_points[i]);
345 // Define outer layer of inner boundary layer
347 {
348 // Outside point of the inner boundary layer
349 const Point ref_inner_boundary_shift =
350 (_peripheral_inner_boundary_layer_params.width / sin(input_bdry_angles[i])) *
351 input_bdry_nd[i];
352 ref_inner_bdry_surf.push_back(points_array[0][i] + ref_inner_boundary_shift);
353 }
354 }
355
357 innerBdryLayerNodesDefiner(input_ext_node_num,
358 input_bdry_angles,
359 ref_inner_bdry_surf,
360 inner_peripheral_bias_terms,
361 azi_array,
362 origin_pt,
363 points_array);
364 const Real correction_factor = _preserve_volumes
366 azi_array, true, order, is_first_node_vertex)
367 : 1.0;
368 // Loop to handle outer boundary layer and main region
369 for (const auto i : make_range(input_ext_node_num))
370 {
371 // Outer boundary nodes of the peripheral region
372 points_array[total_peripheral_layer_num][i] = std::get<2>(azi_points[i]) * correction_factor;
373 // Outer boundary layer points
375 {
376 // Inner point of the outer boundary layer
377 const Point outer_boundary_shift =
378 -Point(std::cos(std::get<0>(azi_points[i])), std::sin(std::get<0>(azi_points[i])), 0.0) *
380 for (const auto j :
381 make_range(uint(1), _peripheral_outer_boundary_layer_params.intervals + 1))
382 points_array[total_peripheral_layer_num - j][i] =
383 points_array[total_peripheral_layer_num][i] +
384 outer_boundary_shift * outer_peripheral_bias_terms[j - 1];
385 }
386 // Use interpolation to get main region
387 if (MooseUtils::absoluteFuzzyGreaterEqual(
388 (points_array[_peripheral_inner_boundary_layer_params.intervals][i] - origin_pt).norm(),
390 _peripheral_layer_num * order][i] -
391 origin_pt)
392 .norm()))
393 {
394 paramError("peripheral_inner_boundary_layer_width",
395 "The summation of peripheral_inner_boundary_layer_width and "
396 "peripheral_outer_boundary_layer_width must be smaller than the thickness of "
397 "peripheral ring region.");
398 }
399
400 for (const auto j : make_range(uint(1), _peripheral_layer_num * order))
403 (1.0 - main_peripheral_bias_terms[j - 1]) +
405 _peripheral_layer_num * order][i] *
406 main_peripheral_bias_terms[j - 1];
407 }
408 unsigned int num_total_nodes = (total_peripheral_layer_num + 1) * input_ext_node_num;
409 std::vector<Node *> nodes(num_total_nodes); // reserve nodes pointers
410 dof_id_type node_id = 0;
411
412 // Add nodes to the new mesh
413 for (const auto i : make_range(total_peripheral_layer_num + 1))
414 for (const auto j : make_range(input_ext_node_num))
415 {
416 nodes[node_id] = mesh->add_point(points_array[i][j], node_id);
417 node_id_array[i][j] = node_id;
418 node_id++;
419 }
420 // Add elements to the new mesh
421 BoundaryInfo & boundary_info = mesh->get_boundary_info();
422 const unsigned int index_shift = is_first_node_vertex ? 0 : 1;
423 for (const auto i : make_range(total_peripheral_layer_num / order))
424 for (const auto j : make_range(input_ext_node_num / order))
425 {
426 std::unique_ptr<Elem> new_elem;
427 new_elem = std::make_unique<Quad4>();
428 if (order == 2)
429 {
430 new_elem = std::make_unique<Quad9>();
431 new_elem->set_node(4, nodes[node_id_array[i * order + 1][j * order + index_shift]]);
432 new_elem->set_node(5,
433 nodes[node_id_array[(i + 1) * order][(j * order + 1 + index_shift) %
434 input_ext_node_num]]);
435 new_elem->set_node(6,
436 nodes[node_id_array[i * order + 1][((j + 1) * order + index_shift) %
437 input_ext_node_num]]);
438 new_elem->set_node(
439 7, nodes[node_id_array[i * order][(j * order + 1 + index_shift) % input_ext_node_num]]);
440 new_elem->set_node(8,
441 nodes[node_id_array[i * order + 1][(j * order + 1 + index_shift) %
442 input_ext_node_num]]);
443 }
444 new_elem->set_node(0, nodes[node_id_array[i * order][j * order + index_shift]]);
445 new_elem->set_node(1, nodes[node_id_array[(i + 1) * order][j * order + index_shift]]);
446 new_elem->set_node(2,
447 nodes[node_id_array[(i + 1) * order][((j + 1) * order + index_shift) %
448 input_ext_node_num]]);
449 new_elem->set_node(
450 3, nodes[node_id_array[i * order][((j + 1) * order + index_shift) % input_ext_node_num]]);
451 new_elem->subdomain_id() = _peripheral_ring_block_id;
452
453 Elem * added_elem = mesh->add_elem(std::move(new_elem));
454
455 if (i == 0)
456 boundary_info.add_side(added_elem, 3, OUTER_SIDESET_ID_ALT);
457 if (i == total_peripheral_layer_num / order - 1)
458 boundary_info.add_side(added_elem, 1, OUTER_SIDESET_ID);
459 }
460
461 // This would make sure that the boundary OUTER_SIDESET_ID is deleted after stitching.
463 MooseMesh::changeBoundaryId(*input_mesh, _input_mesh_external_bid, OUTER_SIDESET_ID, false);
464 mesh->prepare_for_use();
465 // Use input_mesh here to retain the subdomain name map
466 input_mesh->stitch_meshes(*mesh, OUTER_SIDESET_ID, OUTER_SIDESET_ID_ALT, TOLERANCE, true, false);
467
468 // Assign subdomain name to the new block if applicable
469 if (isParamValid("peripheral_ring_block_name"))
470 input_mesh->set_subdomain_name(_peripheral_ring_block_id, _peripheral_ring_block_name, true);
471 // Assign customized external boundary id
472 if (_external_boundary_id > 0)
473 MooseMesh::changeBoundaryId(*input_mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
474 // Assign customized external boundary name
475 if (!_external_boundary_name.empty())
476 {
477 input_mesh->get_boundary_info().sideset_name(
480 input_mesh->get_boundary_info().nodeset_name(
483 }
484
485 _input->unset_is_prepared();
486 return dynamic_pointer_cast<MeshBase>(_input);
487}
488
489void
491 const unsigned int input_ext_node_num,
492 const std::vector<Real> input_bdry_angles,
493 const std::vector<Point> ref_inner_bdry_surf,
494 const std::vector<Real> inner_peripheral_bias_terms,
495 const std::vector<Real> azi_array,
496 const Point origin_pt,
497 std::vector<std::vector<Point>> & points_array) const
498{
499 // Check if any azimuthal angles are messed after inner boundary layer addition
500 std::vector<bool> delete_mark(input_ext_node_num, false);
501 std::vector<Real> interp_azi_data, interp_x_data, interp_y_data;
502 std::unique_ptr<LinearInterpolation> linterp_x, linterp_y;
503 // Mark the to-be-deleted elements
504 for (const auto i : make_range(input_ext_node_num))
505 {
506 // For a zig-zag external boundary, when we add a conformal layer onto it by translating the
507 // nodes in the surface normal direction, it is possible that the azimuthal order is flipped.
508 // As shown below, o's are the original boundary nodes, and *'s are the nodes after
509 // translation by the boundary layer thickness.
510 // * *
511 // | | | /
512 // o o-------/--*
513 // | | / |
514 // | outside --> | / |
515 // | | / |
516 // o--------o-- o-------o--
517 // To mitigate this flipping issue, we check the node flipping here using the cross product of
518 // neighboring node-to-origin vectors. Flipped nodes are marked and excluded during the
519 // follow-up interpolation.
520 if (!MooseUtils::absoluteFuzzyEqual(input_bdry_angles[i], M_PI / 2.0, 1.0e-4))
521 {
522 unsigned int index_shift = 1;
523 bool minus_shift_flag = true;
524 bool plus_shift_flag = true;
525 // Need to check both directions for multiple shifts
526 // Half of the external boundary nodes are used as an upper limit to avert infinite loops
527 while (index_shift < input_ext_node_num / 2 && (minus_shift_flag || plus_shift_flag))
528 {
529 if (((ref_inner_bdry_surf[MathUtils::euclideanMod(((int)i - (int)index_shift),
530 (int)input_ext_node_num)] -
531 origin_pt)
532 .cross(ref_inner_bdry_surf[i] - origin_pt))(2) <= 0.0 &&
533 minus_shift_flag)
534 delete_mark[MathUtils::euclideanMod(((int)i - (int)index_shift),
535 (int)input_ext_node_num)] = true;
536 else
537 minus_shift_flag = false;
538 if (((ref_inner_bdry_surf[(i + index_shift) % input_ext_node_num] - origin_pt)
539 .cross(ref_inner_bdry_surf[i] - origin_pt))(2) >= 0.0 &&
540 plus_shift_flag)
541 delete_mark[(i + index_shift) % input_ext_node_num] = true;
542 else
543 plus_shift_flag = false;
544 index_shift++;
545 }
546 }
547 }
548 // Create vectors for interpolation
549 // Due to the flip issue, linear interpolation is used here to mark the location of the boundary
550 // layer's outer boundary.
551 for (const auto i : make_range(input_ext_node_num))
552 {
553 if (!delete_mark[i])
554 {
555 interp_azi_data.push_back(atan2(ref_inner_bdry_surf[i](1) - origin_pt(1),
556 ref_inner_bdry_surf[i](0) - origin_pt(0)));
557 interp_x_data.push_back(ref_inner_bdry_surf[i](0));
558 interp_y_data.push_back(ref_inner_bdry_surf[i](1));
559 if (interp_azi_data.size() > 1)
560 if (interp_azi_data.back() < interp_azi_data[interp_azi_data.size() - 2])
561 interp_azi_data.back() += 2.0 * M_PI;
562 }
563 }
564 const Real interp_x0 = interp_x_data.front();
565 const Real interp_xt = interp_x_data.back();
566 const Real interp_y0 = interp_y_data.front();
567 const Real interp_yt = interp_y_data.back();
568 const Real incept_azi0 = interp_azi_data.front();
569 const Real incept_azit = interp_azi_data.back();
570
571 if (MooseUtils::absoluteFuzzyGreaterThan(incept_azi0, -M_PI))
572 {
573 interp_azi_data.insert(interp_azi_data.begin(), incept_azit - 2.0 * M_PI);
574 interp_x_data.insert(interp_x_data.begin(), interp_xt);
575 interp_y_data.insert(interp_y_data.begin(), interp_yt);
576 }
577 else
578 interp_azi_data.front() = -M_PI;
579 if (MooseUtils::absoluteFuzzyLessThan(incept_azit, M_PI))
580 {
581 interp_azi_data.push_back(incept_azi0 + 2 * M_PI);
582 interp_x_data.push_back(interp_x0);
583 interp_y_data.push_back(interp_y0);
584 }
585 else
586 interp_azi_data.back() = M_PI;
587
588 // Establish interpolation
589 linterp_x = std::make_unique<LinearInterpolation>(interp_azi_data, interp_x_data);
590 linterp_y = std::make_unique<LinearInterpolation>(interp_azi_data, interp_y_data);
591 // Loop to handle inner boundary layer
592 for (const auto i : make_range(input_ext_node_num))
593 {
594 // Outside point of the inner boundary layer
595 // Using interpolation, the azimuthal angles do not need to be changed.
596 const Point inner_boundary_shift = Point(linterp_x->sample(azi_array[i] / 180.0 * M_PI),
597 linterp_y->sample(azi_array[i] / 180.0 * M_PI),
598 origin_pt(2)) -
599 points_array[0][i];
600 for (const auto j : make_range(uint(1), _peripheral_inner_boundary_layer_params.intervals + 1))
601 points_array[j][i] =
602 points_array[0][i] + inner_boundary_shift * inner_peripheral_bias_terms[j - 1];
603 }
604}
std::pair< const Elem *, unsigned int > side_type
registerMooseObject("ReactorApp", PeripheralRingMeshGenerator)
void ErrorVector unsigned int
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
T & setMeshProperty(const std::string &data_name, Args &&... args)
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
void paramError(const std::string &param, Args... args) const
bool isParamValid(const std::string &name) const
virtual const char * what() const
This PeripheralRingMeshGenerator object adds a circular peripheral region to the input mesh.
const boundary_id_type _external_boundary_id
ID of the new external boundary.
const subdomain_id_type _peripheral_ring_block_id
Subdomain ID of the added peripheral region.
Real _peripheral_radial_bias
Bias value used to induce biasing to radial meshing in peripheral ring region.
const SubdomainName _peripheral_ring_block_name
Subdomain name of the added peripheral region.
const bool _force_input_centroid_as_center
Whether to enforce use of the centroid position of the input mesh as the center of the peripheral rin...
boundary_id_type _input_mesh_external_bid
ID of the external boundary of the input mesh.
const BoundaryName _input_mesh_external_boundary
Name of the external boundary of the input mesh.
singleBdryLayerParams _peripheral_outer_boundary_layer_params
Width, fraction, radiation sectors and growth factor of the outer boundary layer of the peripheral re...
std::unique_ptr< MeshBase > generate() override
const unsigned int _peripheral_layer_num
Number of layers of elements of the peripheral region in radial direction.
void innerBdryLayerNodesDefiner(const unsigned int input_ext_node_num, const std::vector< Real > input_bdry_angles, const std::vector< Point > ref_inner_bdry_surf, const std::vector< Real > inner_peripheral_bias_terms, const std::vector< Real > azi_array, const Point origin_pt, std::vector< std::vector< Point > > &points_array) const
Define node positions of the inner boundary layer that is conformal to the input mesh's external boun...
const bool _preserve_volumes
Volume preserving function is optional.
std::unique_ptr< MeshBase > & _input
Reference to input mesh pointer.
PeripheralRingMeshGenerator(const InputParameters &parameters)
const Real _peripheral_ring_radius
Radius of the peripheral region's outer circular boundary.
singleBdryLayerParams _peripheral_inner_boundary_layer_params
Width, fraction, radiation sectors and growth factor of the inner boundary layer of the peripheral re...
const MeshGeneratorName _input_name
Name of the mesh generator to get the input mesh.
const BoundaryName _external_boundary_name
Name of the new external boundary.
A base class that contains common members for Reactor module mesh generators.
static InputParameters validParams()
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.
MeshBase & mesh
bool isBoundarySimpleClosedLoop(MeshBase &mesh, Real &max_node_radius, std::vector< dof_id_type > &boundary_ordered_node_list, const Point origin_pt, const boundary_id_type bid)
bool isExternalBoundary(MeshBase &mesh, const boundary_id_type bid)
std::size_t euclideanMod(T1 dividend, T2 divisor)
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Point meshCentroidCalculator(const MeshBase &mesh)
bool hasBoundaryNameOrID(const MeshBase &mesh, const BoundaryName &name_or_id)
Real radiusCorrectionFactor(const std::vector< Real > &azimuthal_list, const bool full_circle=true, const unsigned int order=1, const bool is_first_value_vertex=true)
Makes radial correction to preserve ring area.