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"),
114 getParam<Real>(
"peripheral_inner_boundary_layer_width") > 0.0
115 ? getParam<unsigned int>(
"peripheral_inner_boundary_layer_intervals")
117 getParam<Real>(
"peripheral_inner_boundary_layer_bias")}),
118 _peripheral_outer_boundary_layer_params(
119 {getParam<Real>(
"peripheral_outer_boundary_layer_width"),
121 getParam<Real>(
"peripheral_outer_boundary_layer_width") > 0.0
122 ? getParam<unsigned int>(
"peripheral_outer_boundary_layer_intervals")
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")
135 _external_boundary_name(getParam<BoundaryName>(
"external_boundary_name")),
136 _input(getMeshByName(_input_name))
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);
147 if (hasMeshProperty<bool>(
"hexagon_center_trimmability",
_input_name))
149 getMeshProperty<bool>(
"hexagon_center_trimmability",
_input_name));
150 if (hasMeshProperty<bool>(
"square_center_trimmability",
_input_name))
152 getMeshProperty<bool>(
"square_center_trimmability",
_input_name));
155 auto input_mesh =
dynamic_cast<ReplicatedMesh *
>(
_input.get());
157 paramError(
"input",
"Input is not a replicated mesh, which is required.");
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.");
169 "External boundary does not exist in the input mesh");
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)
180 const auto etype = input_mesh->elem_ptr(std::get<0>(side))->
side_type(std::get<1>(side));
183 else if (etype == EDGE3)
184 quadratic_side =
true;
186 paramError(
"input",
"Input contains elements that are not supported by this generator.");
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;
206 MeshTools::Modification::translate(
207 *input_mesh, -input_mesh_centroid(0), -input_mesh_centroid(1), -input_mesh_centroid(2));
210 const Point origin_pt =
213 Real max_input_mesh_node_radius;
217 const auto main_peripheral_bias_terms =
219 const auto inner_peripheral_bias_terms =
224 const auto outer_peripheral_bias_terms =
228 const unsigned int total_peripheral_layer_num =
233 std::vector<dof_id_type> boundary_ordered_node_list;
237 max_input_mesh_node_radius,
238 boundary_ordered_node_list,
244 if (((std::string)e.
what()).compare(
"The node list provided has more than one segments.") == 0)
246 "This mesh generator does not work for the provided external boundary as it has "
247 "more than one segments.");
254 "peripheral_ring_radius",
255 "The peripheral ring to be generated must be large enough to cover the entire input mesh.");
258 "The boundary provided is not an external boundary.");
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;
268 unsigned int input_ext_node_num = 0;
272 boundary_ordered_node_list.pop_back();
275 for (
const auto i : index_range(boundary_ordered_node_list))
277 input_ext_node_num++;
279 input_ext_bd_pts.push_back(input_mesh->point(boundary_ordered_node_list[i]));
281 atan2(input_ext_bd_pts.back()(1) - origin_pt(1), input_ext_bd_pts.back()(0) - origin_pt(0));
286 azi_points.push_back(
287 std::make_tuple(tmp_azi, input_ext_bd_pts.back(), output_ext_bd_pts.back()));
289 azi_array.push_back(tmp_azi / M_PI * 180.0);
293 const bool is_first_node_vertex =
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());
300 std::vector<Real> input_bdry_angles;
302 std::vector<Point> input_bdry_nd;
303 for (
const auto i : index_range(azi_points))
306 const Point pn = Point(0.0, 0.0, 1.0);
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]);
312 else if (i == azi_points.size() - 1)
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());
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]);
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();
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());
333 std::vector<std::vector<Point>> points_array(total_peripheral_layer_num + 1,
334 std::vector<Point>(input_ext_node_num));
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));
339 std::vector<Point> ref_inner_bdry_surf;
341 for (
const auto i : make_range(input_ext_node_num))
344 points_array[0][i] = std::get<1>(azi_points[i]);
349 const Point ref_inner_boundary_shift =
352 ref_inner_bdry_surf.push_back(points_array[0][i] + ref_inner_boundary_shift);
360 inner_peripheral_bias_terms,
366 azi_array,
true, order, is_first_node_vertex)
369 for (
const auto i : make_range(input_ext_node_num))
372 points_array[total_peripheral_layer_num][i] = std::get<2>(azi_points[i]) * correction_factor;
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) *
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];
387 if (MooseUtils::absoluteFuzzyGreaterEqual(
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.");
403 (1.0 - main_peripheral_bias_terms[j - 1]) +
406 main_peripheral_bias_terms[j - 1];
408 unsigned int num_total_nodes = (total_peripheral_layer_num + 1) * input_ext_node_num;
409 std::vector<Node *> nodes(num_total_nodes);
410 dof_id_type node_id = 0;
413 for (
const auto i : make_range(total_peripheral_layer_num + 1))
414 for (
const auto j : make_range(input_ext_node_num))
416 nodes[node_id] =
mesh->add_point(points_array[i][j], node_id);
417 node_id_array[i][j] = node_id;
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))
426 std::unique_ptr<Elem> new_elem;
427 new_elem = std::make_unique<Quad4>();
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]]);
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]]);
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]]);
450 3, nodes[node_id_array[i * order][((j + 1) * order + index_shift) % input_ext_node_num]]);
453 Elem * added_elem =
mesh->add_elem(std::move(new_elem));
457 if (i == total_peripheral_layer_num / order - 1)
464 mesh->prepare_for_use();
477 input_mesh->get_boundary_info().sideset_name(
480 input_mesh->get_boundary_info().nodeset_name(
485 _input->unset_is_prepared();
486 return dynamic_pointer_cast<MeshBase>(
_input);
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
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;
504 for (
const auto i : make_range(input_ext_node_num))
520 if (!MooseUtils::absoluteFuzzyEqual(input_bdry_angles[i], M_PI / 2.0, 1.0e-4))
522 unsigned int index_shift = 1;
523 bool minus_shift_flag =
true;
524 bool plus_shift_flag =
true;
527 while (index_shift < input_ext_node_num / 2 && (minus_shift_flag || plus_shift_flag))
530 (
int)input_ext_node_num)] -
532 .cross(ref_inner_bdry_surf[i] - origin_pt))(2) <= 0.0 &&
535 (
int)input_ext_node_num)] =
true;
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 &&
541 delete_mark[(i + index_shift) % input_ext_node_num] =
true;
543 plus_shift_flag =
false;
551 for (
const auto i : make_range(input_ext_node_num))
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;
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();
571 if (MooseUtils::absoluteFuzzyGreaterThan(incept_azi0, -M_PI))
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);
578 interp_azi_data.front() = -M_PI;
579 if (MooseUtils::absoluteFuzzyLessThan(incept_azit, M_PI))
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);
586 interp_azi_data.back() = M_PI;
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);
592 for (
const auto i : make_range(input_ext_node_num))
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),
602 points_array[0][i] + inner_boundary_shift * inner_peripheral_bias_terms[j - 1];