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.");
158 if (*(input_mesh->elem_dimensions().begin()) != 2 ||
159 *(input_mesh->elem_dimensions().rbegin()) != 2)
160 paramError(
"input",
"Only 2D meshes are supported.");
166 "External boundary does not exist in the input mesh");
170 auto side_list_tmp = input_mesh->get_boundary_info().build_side_list();
171 bool linear_side =
false;
172 bool quadratic_side =
false;
173 for (
const auto & side : side_list_tmp)
177 const auto etype = input_mesh->elem_ptr(std::get<0>(side))->side_type(std::get<1>(side));
180 else if (etype ==
EDGE3)
181 quadratic_side =
true;
183 paramError(
"input",
"Input contains elements that are not supported by this generator.");
186 if (linear_side && quadratic_side)
187 paramError(
"input",
"Input contains mixed element types on the external boundary.");
188 const unsigned int order = linear_side ? 1 : 2;
203 MeshTools::Modification::translate(
204 *input_mesh, -input_mesh_centroid(0), -input_mesh_centroid(1), -input_mesh_centroid(2));
207 const Point origin_pt =
210 Real max_input_mesh_node_radius;
214 const auto main_peripheral_bias_terms =
216 const auto inner_peripheral_bias_terms =
221 const auto outer_peripheral_bias_terms =
225 const unsigned int total_peripheral_layer_num =
230 std::vector<dof_id_type> boundary_ordered_node_list;
234 max_input_mesh_node_radius,
235 boundary_ordered_node_list,
241 if (((std::string)e.
what()).compare(
"The node list provided has more than one segments.") == 0)
243 "This mesh generator does not work for the provided external boundary as it has " 244 "more than one segments.");
251 "peripheral_ring_radius",
252 "The peripheral ring to be generated must be large enough to cover the entire input mesh.");
255 "The boundary provided is not an external boundary.");
257 std::vector<Point> input_ext_bd_pts;
258 std::vector<Point> output_ext_bd_pts;
259 std::vector<std::tuple<Real, Point, Point>> azi_points;
260 std::vector<Real> azi_array;
265 unsigned int input_ext_node_num = 0;
269 boundary_ordered_node_list.pop_back();
272 for (
const auto i :
index_range(boundary_ordered_node_list))
274 input_ext_node_num++;
276 input_ext_bd_pts.push_back(input_mesh->point(boundary_ordered_node_list[i]));
278 atan2(input_ext_bd_pts.back()(1) - origin_pt(1), input_ext_bd_pts.back()(0) - origin_pt(0));
283 azi_points.push_back(
284 std::make_tuple(tmp_azi, input_ext_bd_pts.back(), output_ext_bd_pts.back()));
286 azi_array.push_back(tmp_azi / M_PI * 180.0);
290 const bool is_first_node_vertex =
292 !(std::distance(azi_array.begin(), std::min_element(azi_array.begin(), azi_array.end())) % 2);
293 std::sort(azi_points.begin(), azi_points.end());
294 std::sort(azi_array.begin(), azi_array.end());
297 std::vector<Real> input_bdry_angles;
299 std::vector<Point> input_bdry_nd;
303 const Point pn = Point(0.0, 0.0, 1.0);
306 p1 = std::get<1>(azi_points[i + 1]) - std::get<1>(azi_points[i]);
307 p2 = std::get<1>(azi_points.back()) - std::get<1>(azi_points[i]);
309 else if (i == azi_points.size() - 1)
311 p1 = std::get<1>(azi_points.front()) - std::get<1>(azi_points.back());
312 p2 = std::get<1>(azi_points[i - 1]) - std::get<1>(azi_points.back());
316 p1 = std::get<1>(azi_points[i + 1]) - std::get<1>(azi_points[i]);
317 p2 = std::get<1>(azi_points[i - 1]) - std::get<1>(azi_points[i]);
320 const Point p1n = (p1.cross(pn)).unit();
321 const Point p2n = -(p2.cross(pn)).unit();
322 Real tmp = p1 * p2 / p1.norm() / p2.norm();
324 tmp = tmp > 1.0 ? 1.0 : (tmp < -1.0 ? -1.0 : tmp);
325 input_bdry_angles.push_back(acos(tmp) / 2.0);
326 input_bdry_nd.push_back((p1n + p2n).unit());
330 std::vector<std::vector<Point>> points_array(total_peripheral_layer_num + 1,
331 std::vector<Point>(input_ext_node_num));
333 std::vector<std::vector<dof_id_type>> node_id_array(total_peripheral_layer_num + 1,
334 std::vector<dof_id_type>(input_ext_node_num));
336 std::vector<Point> ref_inner_bdry_surf;
338 for (
const auto i :
make_range(input_ext_node_num))
341 points_array[0][i] = std::get<1>(azi_points[i]);
346 const Point ref_inner_boundary_shift =
349 ref_inner_bdry_surf.push_back(points_array[0][i] + ref_inner_boundary_shift);
357 inner_peripheral_bias_terms,
363 azi_array,
true, order, is_first_node_vertex)
366 for (
const auto i :
make_range(input_ext_node_num))
369 points_array[total_peripheral_layer_num][i] = std::get<2>(azi_points[i]) * correction_factor;
374 const Point outer_boundary_shift =
375 -Point(std::cos(std::get<0>(azi_points[i])), std::sin(std::get<0>(azi_points[i])), 0.0) *
379 points_array[total_peripheral_layer_num -
j][i] =
380 points_array[total_peripheral_layer_num][i] +
381 outer_boundary_shift * outer_peripheral_bias_terms[
j - 1];
391 paramError(
"peripheral_inner_boundary_layer_width",
392 "The summation of peripheral_inner_boundary_layer_width and " 393 "peripheral_outer_boundary_layer_width must be smaller than the thickness of " 394 "peripheral ring region.");
400 (1.0 - main_peripheral_bias_terms[
j - 1]) +
403 main_peripheral_bias_terms[
j - 1];
405 unsigned int num_total_nodes = (total_peripheral_layer_num + 1) * input_ext_node_num;
406 std::vector<Node *> nodes(num_total_nodes);
410 for (
const auto i :
make_range(total_peripheral_layer_num + 1))
411 for (
const auto j :
make_range(input_ext_node_num))
413 nodes[node_id] =
mesh->add_point(points_array[i][
j], node_id);
414 node_id_array[i][
j] = node_id;
418 BoundaryInfo & boundary_info =
mesh->get_boundary_info();
419 const unsigned int index_shift = is_first_node_vertex ? 0 : 1;
420 for (
const auto i :
make_range(total_peripheral_layer_num / order))
421 for (
const auto j :
make_range(input_ext_node_num / order))
423 std::unique_ptr<Elem> new_elem;
424 new_elem = std::make_unique<Quad4>();
427 new_elem = std::make_unique<Quad9>();
428 new_elem->set_node(4, nodes[node_id_array[i * order + 1][
j * order + index_shift]]);
429 new_elem->set_node(5,
430 nodes[node_id_array[(i + 1) * order][(
j * order + 1 + index_shift) %
431 input_ext_node_num]]);
432 new_elem->set_node(6,
433 nodes[node_id_array[i * order + 1][((
j + 1) * order + index_shift) %
434 input_ext_node_num]]);
436 7, nodes[node_id_array[i * order][(
j * order + 1 + index_shift) % input_ext_node_num]]);
437 new_elem->set_node(8,
438 nodes[node_id_array[i * order + 1][(
j * order + 1 + index_shift) %
439 input_ext_node_num]]);
441 new_elem->set_node(0, nodes[node_id_array[i * order][
j * order + index_shift]]);
442 new_elem->set_node(1, nodes[node_id_array[(i + 1) * order][
j * order + index_shift]]);
443 new_elem->set_node(2,
444 nodes[node_id_array[(i + 1) * order][((
j + 1) * order + index_shift) %
445 input_ext_node_num]]);
447 3, nodes[node_id_array[i * order][((
j + 1) * order + index_shift) % input_ext_node_num]]);
450 Elem * added_elem =
mesh->add_elem(std::move(new_elem));
454 if (i == total_peripheral_layer_num / order - 1)
461 mesh->prepare_for_use();
474 input_mesh->get_boundary_info().sideset_name(
477 input_mesh->get_boundary_info().nodeset_name(
482 _input->set_isnt_prepared();
488 const unsigned int input_ext_node_num,
489 const std::vector<Real> input_bdry_angles,
490 const std::vector<Point> ref_inner_bdry_surf,
491 const std::vector<Real> inner_peripheral_bias_terms,
492 const std::vector<Real> azi_array,
493 const Point origin_pt,
494 std::vector<std::vector<Point>> & points_array)
const 497 std::vector<bool> delete_mark(input_ext_node_num,
false);
498 std::vector<Real> interp_azi_data, interp_x_data, interp_y_data;
499 std::unique_ptr<LinearInterpolation> linterp_x, linterp_y;
501 for (
const auto i :
make_range(input_ext_node_num))
519 unsigned int index_shift = 1;
520 bool minus_shift_flag =
true;
521 bool plus_shift_flag =
true;
524 while (index_shift < input_ext_node_num / 2 && (minus_shift_flag || plus_shift_flag))
527 (
int)input_ext_node_num)] -
529 .cross(ref_inner_bdry_surf[i] - origin_pt))(2) <= 0.0 &&
532 (
int)input_ext_node_num)] =
true;
534 minus_shift_flag =
false;
535 if (((ref_inner_bdry_surf[(i + index_shift) % input_ext_node_num] - origin_pt)
536 .cross(ref_inner_bdry_surf[i] - origin_pt))(2) >= 0.0 &&
538 delete_mark[(i + index_shift) % input_ext_node_num] =
true;
540 plus_shift_flag =
false;
548 for (
const auto i :
make_range(input_ext_node_num))
552 interp_azi_data.push_back(atan2(ref_inner_bdry_surf[i](1) - origin_pt(1),
553 ref_inner_bdry_surf[i](0) - origin_pt(0)));
554 interp_x_data.push_back(ref_inner_bdry_surf[i](0));
555 interp_y_data.push_back(ref_inner_bdry_surf[i](1));
556 if (interp_azi_data.size() > 1)
557 if (interp_azi_data.back() < interp_azi_data[interp_azi_data.size() - 2])
558 interp_azi_data.back() += 2.0 * M_PI;
561 const Real interp_x0 = interp_x_data.front();
562 const Real interp_xt = interp_x_data.back();
563 const Real interp_y0 = interp_y_data.front();
564 const Real interp_yt = interp_y_data.back();
565 const Real incept_azi0 = interp_azi_data.front();
566 const Real incept_azit = interp_azi_data.back();
570 interp_azi_data.insert(interp_azi_data.begin(), incept_azit - 2.0 * M_PI);
571 interp_x_data.insert(interp_x_data.begin(), interp_xt);
572 interp_y_data.insert(interp_y_data.begin(), interp_yt);
575 interp_azi_data.front() = -M_PI;
578 interp_azi_data.push_back(incept_azi0 + 2 * M_PI);
579 interp_x_data.push_back(interp_x0);
580 interp_y_data.push_back(interp_y0);
583 interp_azi_data.back() = M_PI;
586 linterp_x = std::make_unique<LinearInterpolation>(interp_azi_data, interp_x_data);
587 linterp_y = std::make_unique<LinearInterpolation>(interp_azi_data, interp_y_data);
589 for (
const auto i :
make_range(input_ext_node_num))
593 const Point inner_boundary_shift = Point(linterp_x->sample(azi_array[i] / 180.0 * M_PI),
594 linterp_y->sample(azi_array[i] / 180.0 * M_PI),
599 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)
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
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)
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...
bool isParamValid(const std::string &name) const
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.
bool absoluteFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
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...
void paramError(const std::string ¶m, Args... args) const
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)
bool absoluteFuzzyGreaterEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
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)
bool absoluteFuzzyGreaterThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
const unsigned int _peripheral_layer_num
Number of layers of elements of the peripheral region in radial direction.
registerMooseObject("ReactorApp", PeripheralRingMeshGenerator)