17 #include "libmesh/int_range.h" 28 params.
addRequiredParam<MeshGeneratorName>(
"input",
"The input mesh to be modified.");
30 "force_input_centroid_as_center",
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.");
36 "peripheral_layer_num",
38 "peripheral_layer_num>0",
39 "The radial layers of the peripheral ring to be added.");
41 "peripheral_radial_bias",
43 "peripheral_radial_bias>0",
44 "Value used to create biasing in radial meshing for peripheral ring region.");
46 "peripheral_inner_boundary_layer_width",
48 "peripheral_inner_boundary_layer_width>=0",
49 "Width of peripheral ring region that is assigned to be the inner boundary layer.");
51 "peripheral_inner_boundary_layer_intervals",
53 "peripheral_inner_boundary_layer_intervals>0",
54 "Number of radial intervals of the peripheral ring inner boundary layer");
56 "peripheral_inner_boundary_layer_bias",
58 "peripheral_inner_boundary_layer_bias>0",
59 "Growth factor used for mesh biasing of the peripheral ring inner boundary layer.");
61 "peripheral_outer_boundary_layer_width",
63 "peripheral_outer_boundary_layer_width>=0",
64 "Width of peripheral ring region that is assigned to be the outer boundary layer.");
66 "peripheral_outer_boundary_layer_intervals",
68 "peripheral_outer_boundary_layer_intervals>0",
69 "Number of radial intervals of the peripheral ring outer boundary layer");
71 "peripheral_outer_boundary_layer_bias",
73 "peripheral_outer_boundary_layer_bias>0",
74 "Growth factor used for mesh biasing of the peripheral ring outer boundary layer.");
76 "peripheral_ring_radius>0",
77 "Radius of the peripheral ring to be added.");
81 "Whether the volume of the peripheral region is preserved by fixing the radius.");
83 "The external boundary of the input mesh.");
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.");
89 "external_boundary_id>0",
90 "Optional customized external boundary id.");
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.");
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);
144 std::unique_ptr<MeshBase>
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;
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);
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();
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];
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sin(_arg) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tan
const SubdomainName _peripheral_ring_block_name
Subdomain name of the added peripheral region.
virtual const char * what() const
T & setMeshProperty(const std::string &data_name, Args &&... args)
const BoundaryName _input_mesh_external_boundary
Name of the external boundary of the input mesh.
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
void paramError(const std::string ¶m, Args... args) const
std::unique_ptr< MeshBase > & _input
Reference to input mesh pointer.
static InputParameters validParams()
This PeripheralRingMeshGenerator object adds a circular peripheral region to the input mesh...
const subdomain_id_type _peripheral_ring_block_id
Subdomain ID of the added peripheral region.
const BoundaryName _external_boundary_name
Name of the new external boundary.
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
void changeBoundaryId(const boundary_id_type old_id, const boundary_id_type new_id, bool delete_prev)
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...
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
const Real _peripheral_ring_radius
Radius of the peripheral region's outer circular boundary.
std::unique_ptr< MeshBase > generate() override
PeripheralRingMeshGenerator(const InputParameters ¶meters)
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.
std::size_t euclideanMod(T1 dividend, T2 divisor)
static InputParameters validParams()
singleBdryLayerParams _peripheral_inner_boundary_layer_params
Width, fraction, radiation sectors and growth factor of the inner boundary layer of the peripheral re...
boundary_id_type _input_mesh_external_bid
ID of the external boundary of the input mesh.
Real _peripheral_radial_bias
Bias value used to induce biasing to radial meshing in peripheral ring region.
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 boundary_id_type _external_boundary_id
ID of the new external boundary.
const bool _preserve_volumes
Volume preserving function is optional.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
A base class that contains common members for Reactor module mesh generators.
singleBdryLayerParams _peripheral_outer_boundary_layer_params
Width, fraction, radiation sectors and growth factor of the outer boundary layer of the peripheral re...
IntRange< T > make_range(T beg, T end)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
bool isParamValid(const std::string &name) const
Point meshCentroidCalculator(const MeshBase &mesh)
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.
const MeshGeneratorName _input_name
Name of the mesh generator to get the input mesh.
void ErrorVector unsigned int
auto index_range(const T &sizable)
const unsigned int _peripheral_layer_num
Number of layers of elements of the peripheral region in radial direction.
registerMooseObject("ReactorApp", PeripheralRingMeshGenerator)