25 params.
addRequiredParam<std::vector<MeshGeneratorName>>(
"inputs",
"The input MeshGenerators.");
29 "A double-indexed hexagonal-shaped array starting with the upper-left corner.");
30 MooseEnum pattern_boundary(
"none hexagon",
"hexagon");
32 "pattern_boundary", pattern_boundary,
"The boundary shape of the patterned mesh.");
34 "generate_core_metadata",
36 "A Boolean parameter that controls whether the core related metadata " 37 "is generated for other MOOSE objects such as 'MultiControlDrumFunction' or not.");
40 "background_intervals>0",
41 "Radial intervals in the assembly peripheral region.");
44 "Size of the outmost hexagon boundary to be generated; this is " 45 "required only when pattern type is 'hexagon'.");
46 MooseEnum hexagon_size_style(
"apothem radius",
"apothem");
50 "Style in which the hexagon size is given (default: apothem i.e. half-pitch).");
52 "duct_sizes",
"duct_sizes>0.0",
"Distance(s) from center to duct(s) inner boundaries.");
53 MooseEnum duct_sizes_style(
"apothem radius",
"apothem");
56 "Style in which hexagon center to duct distance(s) is given (apothem " 57 "= center-to-face, radius = center-to-vertex).");
59 "duct_intervals",
"duct_intervals>0",
"Number of meshing intervals in each enclosing duct.");
60 params.
addParam<
bool>(
"uniform_mesh_on_sides",
62 "Whether the side elements are reorganized to have a uniform size.");
63 params.
addParam<
bool>(
"generate_control_drum_positions_file",
65 "Whether a positions file is generated in the core mesh mode.");
66 params.
addParam<
bool>(
"assign_control_drum_id",
68 "Whether control drum id is assigned to the mesh as an extra integer.");
69 std::string position_file_default =
"positions_meta.data";
71 "position_file", position_file_default,
"Data file name to store control drum positions.");
77 "Rotate the entire patterned mesh by a certain degrees that is defined here.");
79 "background_block_id",
80 "Optional customized block id for the background block in 'assembly' mode; must be provided " 81 "along with 'duct_block_ids' if 'duct_sizes' is provided.");
83 "background_block_name",
84 "Optional customized block name for the background block in 'assembly' mode; must be " 85 "provided along with 'duct_block_names' if 'duct_sizes' is provided.");
86 params.
addParam<std::vector<subdomain_id_type>>(
88 "Optional customized block ids for each duct geometry block in 'assembly' mode; must be " 89 "provided along with 'background_block_id'.");
90 params.
addParam<std::vector<SubdomainName>>(
92 std::vector<SubdomainName>(),
93 "Optional customized block names for each duct geometry block in 'assembly' mode; must be " 94 "provided along with 'background_block_name'.");
96 "external_boundary_id>0",
97 "Optional customized external boundary id.");
98 params.
addParam<
bool>(
"create_inward_interface_boundaries",
100 "Whether the inward interface boundary sidesets are created.");
101 params.
addParam<
bool>(
"create_outward_interface_boundaries",
103 "Whether the outward interface boundary sidesets are created.");
105 "external_boundary_name", BoundaryName(),
"Optional customized external boundary name.");
106 params.
addParam<
bool>(
"deform_non_circular_region",
108 "Whether the non-circular region (outside the rings) can be deformed.");
109 params.
addParam<std::vector<std::string>>(
"id_name",
"List of extra integer ID set names");
110 params.
addParam<std::vector<MeshGeneratorName>>(
111 "exclude_id",
"Name of input meshes to be excluded in ID generation");
112 std::vector<MooseEnum> option = {
MooseEnum(
"cell pattern manual",
"cell")};
113 params.
addParam<std::vector<MooseEnum>>(
114 "assign_type", option,
"List of integer ID assignment types");
115 params.
addParam<std::vector<std::vector<std::vector<dof_id_type>>>>(
117 "User-defined element IDs. A double-indexed array starting with the upper-left corner. When " 118 "providing multiple patterns, each pattern should be separated using '|'");
119 params.
addParam<std::vector<std::vector<boundary_id_type>>>(
120 "interface_boundary_id_shift_pattern",
121 "User-defined shift values for each pattern cell. A double-indexed array starting with the " 122 "upper-left corner.");
123 MooseEnum quad_elem_type(
"QUAD4 QUAD8 QUAD9",
"QUAD4");
125 "boundary_region_element_type",
127 "Type of the quadrilateral elements to be generated in the boundary region.");
129 "allow_unused_inputs",
131 "Whether additional input assemblies can be part of inputs without being used in lattice");
133 "background_block_id background_block_name duct_block_ids boundary_region_element_type " 134 "duct_block_names external_boundary_id external_boundary_name " 135 "create_inward_interface_boundaries create_outward_interface_boundaries",
136 "Customized Subdomain/Boundary");
138 "generate_control_drum_positions_file assign_control_drum_id position_file",
"Control Drum");
140 "background_intervals duct_intervals uniform_mesh_on_sides deform_non_circular_region",
144 "This PatternedHexMeshGenerator source code assembles hexagonal meshes into a hexagonal grid " 145 "and optionally forces the outer boundary to be hexagonal and/or adds a duct.");
152 _mesh_ptrs(getMeshes(
"inputs")),
153 _input_names(getParam<
std::vector<MeshGeneratorName>>(
"inputs")),
154 _pattern(getParam<
std::vector<
std::vector<unsigned
int>>>(
"pattern")),
155 _pattern_boundary(getParam<
MooseEnum>(
"pattern_boundary")),
156 _generate_core_metadata(getParam<bool>(
"generate_core_metadata")),
157 _background_intervals(getParam<unsigned
int>(
"background_intervals")),
158 _has_assembly_duct(isParamValid(
"duct_sizes")),
159 _duct_sizes(isParamValid(
"duct_sizes") ? getParam<
std::vector<
Real>>(
"duct_sizes")
162 _duct_intervals(isParamValid(
"duct_intervals")
163 ? getParam<
std::vector<unsigned
int>>(
"duct_intervals")
164 :
std::vector<unsigned
int>()),
165 _uniform_mesh_on_sides(getParam<bool>(
"uniform_mesh_on_sides")),
166 _generate_control_drum_positions_file(getParam<bool>(
"generate_control_drum_positions_file")),
167 _assign_control_drum_id(getParam<bool>(
"assign_control_drum_id")),
168 _rotate_angle(getParam<
Real>(
"rotate_angle")),
169 _duct_block_ids(isParamValid(
"duct_block_ids")
172 _duct_block_names(getParam<
std::vector<SubdomainName>>(
"duct_block_names")),
173 _external_boundary_id(isParamValid(
"external_boundary_id")
176 _external_boundary_name(getParam<BoundaryName>(
"external_boundary_name")),
177 _create_inward_interface_boundaries(getParam<bool>(
"create_inward_interface_boundaries")),
178 _create_outward_interface_boundaries(getParam<bool>(
"create_outward_interface_boundaries")),
181 _deform_non_circular_region(getParam<bool>(
"deform_non_circular_region")),
182 _use_reporting_id(isParamValid(
"id_name")),
183 _use_exclude_id(isParamValid(
"exclude_id")),
184 _use_interface_boundary_id_shift(isParamValid(
"interface_boundary_id_shift_pattern")),
185 _boundary_quad_elem_type(
187 _allow_unused_inputs(getParam<bool>(
"allow_unused_inputs"))
191 declareMeshProperty<bool>(
"is_control_drum_meta",
false);
192 declareMeshProperty<std::vector<Point>>(
"control_drum_positions", std::vector<Point>());
193 declareMeshProperty<std::vector<Real>>(
"control_drum_angles", std::vector<Real>());
194 declareMeshProperty<std::vector<std::vector<Real>>>(
"control_drums_azimuthal_meta",
195 std::vector<std::vector<Real>>());
196 declareMeshProperty<std::string>(
"position_file_name", getParam<std::string>(
"position_file"));
198 declareMeshProperty<bool>(
"hexagon_center_trimmability",
true);
199 declareMeshProperty<bool>(
"peripheral_modifier_compatible",
_pattern_boundary ==
"hexagon");
201 const unsigned int n_pattern_layers =
_pattern.size();
203 if (n_pattern_layers % 2 == 0)
206 "The length (layer number) of this parameter must be odd to ensure a hexagonal shape.");
207 if (n_pattern_layers == 1)
208 paramError(
"pattern",
"The length (layer number) of this parameter must be larger than unity.");
209 std::vector<unsigned int> pattern_max_array;
210 std::vector<unsigned int> pattern_1d;
211 for (
unsigned int i = 0; i <= n_pattern_layers / 2; i++)
213 pattern_max_array.push_back(*std::max_element(
_pattern[i].begin(),
_pattern[i].end()));
214 pattern_max_array.push_back(*std::max_element(
_pattern[n_pattern_layers - 1 - i].begin(),
215 _pattern[n_pattern_layers - 1 - i].end()));
216 pattern_1d.insert(pattern_1d.end(),
_pattern[i].begin(),
_pattern[i].end());
217 pattern_1d.insert(pattern_1d.end(),
218 _pattern[n_pattern_layers - 1 - i].begin(),
219 _pattern[n_pattern_layers - 1 - i].end());
220 if (
_pattern[i].size() != n_pattern_layers / 2 + i + 1 ||
221 _pattern[n_pattern_layers - 1 - i].size() != n_pattern_layers / 2 + i + 1)
224 "The two-dimentional array parameter pattern must have a correct hexagonal shape.");
226 if (*std::max_element(pattern_max_array.begin(), pattern_max_array.end()) >=
_input_names.size())
228 "Elements of this parameter must be smaller than the length of input_name.");
229 if (std::set<unsigned int>(pattern_1d.begin(), pattern_1d.end()).size() <
_input_names.size() &&
232 "All the meshes provided in inputs must be used in the lattice pattern. To bypass " 233 "this requirement, set 'allow_unused_inputs = true'");
243 "This parameter and duct_block_ids must be " 244 "provided simultaneously.");
253 "This parameter and duct_block_names must be provided simultaneously.");
257 for (
unsigned int i = 1; i <
_duct_sizes.size(); i++)
259 paramError(
"duct_sizes",
"This parameter must be strictly ascending.");
262 "This parameter, if provided, must have a length equal to length of duct_sizes.");
266 "This parameter, if provided, must have a length equal to length of duct_sizes.");
272 "This parameter and background_block_name must not be set when the " 273 "pattern_boundary is none.");
280 getParam<std::vector<std::vector<boundary_id_type>>>(
"interface_boundary_id_shift_pattern");
282 paramError(
"interface_boundary_id_shift_pattern",
283 "This parameter, if provided, should have the same two-dimensional array shape as " 284 "the 'pattern' parameter. First dimension does not match");
287 paramError(
"interface_boundary_id_shift_pattern",
288 "This parameter, if provided, should have the same two-dimensional array shape " 289 "as the 'pattern' parameter.");
292 declareMeshProperty<bool>(
"interface_boundaries",
false);
293 declareMeshProperty<std::set<boundary_id_type>>(
"interface_boundary_ids", {});
301 const auto input_assign_types = getParam<std::vector<MooseEnum>>(
"assign_type");
302 if (input_assign_types.size() != num_reporting_ids)
303 paramError(
"assign_type",
"This parameter must have a length equal to length of id_name.");
305 std::vector<std::string> manual_ids;
306 for (
const auto i :
make_range(num_reporting_ids))
309 input_assign_types[i].getEnum<ReportingIDGeneratorUtils::AssignType>());
314 if (manual_ids.size() > 0 && !
isParamValid(
"id_pattern"))
315 paramError(
"id_pattern",
"required when 'manual' is defined in \"assign_type\"");
318 const auto input_id_patterns =
319 getParam<std::vector<std::vector<std::vector<dof_id_type>>>>(
"id_pattern");
320 if (input_id_patterns.size() != manual_ids.size())
322 "The number of patterns must be equal to the number of 'manual' types defined " 323 "in \"assign_type\".");
324 for (
unsigned int i = 0; i < manual_ids.size(); ++i)
331 std::vector<MeshGeneratorName> exclude_id_name =
332 getParam<std::vector<MeshGeneratorName>>(
"exclude_id");
336 for (
auto input_name : exclude_id_name)
350 std::unique_ptr<MeshBase>
353 std::vector<std::unique_ptr<ReplicatedMesh>> meshes(
_input_names.size());
361 "' is not a replicated mesh. Only replicated meshes are supported");
364 if (hasMeshProperty<bool>(
"flat_side_up",
_input_names[i]))
365 if (getMeshProperty<bool>(
"flat_side_up",
_input_names[i]))
369 "' has a flat side facing up, which is not supported.");
372 std::vector<Real> pitch_array;
373 std::vector<unsigned int> num_sectors_per_side_array;
374 std::vector<unsigned int> num_sectors_per_side_array_tmp;
375 std::vector<std::vector<Real>> control_drum_azimuthal_array;
376 std::vector<unsigned int> background_intervals_array;
377 std::vector<dof_id_type> node_id_background_array;
378 std::vector<Real> max_radius_array;
379 std::vector<bool> is_control_drum_array;
380 Real max_radius_global(0.0);
381 std::vector<Real> pattern_pitch_array;
388 if (!hasMeshProperty<Real>(
"pattern_pitch_meta",
_input_names[i]))
390 "In PatternedHexMeshGenerator ",
392 ": the unit hexagonal input mesh does not contain appropriate meta data " 393 "required for generating a core mesh. Involved input mesh: ",
395 "; metadata issue: 'pattern_pitch_meta' is missing. Note that " 396 "'generate_core_metadata' is set to true, which" 397 "means that the mesh generator is producing a core mesh by stitching the input " 398 "assembly meshes together. Therefore," 399 "the input meshes must contain the metadata of assembly meshes, which can " 400 "usually be either automatically assigned " 401 "by using another PatternedHexMeshGenerator with 'generate_core_metadata' set as " 402 "false and 'pattern_boundary' set as hexagon, or manually assigned by " 403 "AddMetaDataGenerator.");
404 pattern_pitch_array.push_back(getMeshProperty<Real>(
"pattern_pitch_meta",
_input_names[i]));
406 if (pattern_pitch_array.back() == 0.0)
408 "In PatternedHexMeshGenerator ",
410 ": the unit hexagonal input mesh does not contain appropriate meta data " 411 "required for generating a core mesh. Involved input mesh: ",
413 "; metadata issue: 'pattern_pitch_meta' is zero. Note that " 414 "'generate_core_metadata' is set to true, which" 415 "means that the mesh generator is producing a core mesh by stitching the input " 416 "assembly meshes together. Therefore," 417 "the input meshes must contain the metadata of assembly meshes, which can " 418 "usually be either automatically assigned " 419 "by using another PatternedHexMeshGenerator with 'generate_core_metadata' set as " 420 "false and 'pattern_boundary' set as hexagon, or manually assigned by " 421 "AddMetaDataGenerator.");
422 is_control_drum_array.push_back(
423 getMeshProperty<bool>(
"is_control_drum_meta",
_input_names[i]));
424 control_drum_azimuthal_array.push_back(
425 getMeshProperty<bool>(
"is_control_drum_meta",
_input_names[i])
427 : std::vector<Real>());
430 *std::max_element(pattern_pitch_array.begin(), pattern_pitch_array.end()),
431 *std::min_element(pattern_pitch_array.begin(), pattern_pitch_array.end())))
433 "In PatternedHexMeshGenerator ",
435 ": pattern_pitch metadata values of all input mesh generators must be identical " 436 "when pattern_boundary is 'none' and generate_core_metadata is true. Please check the " 437 "parameters of the mesh generators that produce the input meshes." 438 "Note that some of these mesh generators, such as " 439 "HexagonConcentricCircleAdaptiveBoundaryMeshGenerator and FlexiblePatternGenerator," 440 "may have different definitions of hexagon size in their input parameters. Please refer " 441 "to the documentation of these mesh generators.",
455 "This parameter must be provided when pattern_boundary is hexagon.");
458 ? getParam<Real>(
"hexagon_size")
459 : getParam<Real>(
"hexagon_size") * std::cos(M_PI / 6.0));
464 if (!hasMeshProperty<Real>(
"pitch_meta",
_input_names[i]))
467 ": the unit hexagonal input mesh does not contain appropriate meta data " 468 "required for generating an assembly. Involved input mesh: ",
470 "; metadata issue: 'pitch_meta' is missing");
471 pitch_array.push_back(getMeshProperty<Real>(
"pitch_meta",
_input_names[i]));
473 num_sectors_per_side_array_tmp =
474 getMeshProperty<std::vector<unsigned int>>(
"num_sectors_per_side_meta",
_input_names[i]);
475 if (*std::max_element(num_sectors_per_side_array_tmp.begin(),
476 num_sectors_per_side_array_tmp.end()) !=
477 *std::min_element(num_sectors_per_side_array_tmp.begin(),
478 num_sectors_per_side_array_tmp.end()))
481 ": num_sectors_per_side metadata values of all six sides of each input mesh " 482 "generator must be identical.");
483 if (num_sectors_per_side_array_tmp.front() == 1 &&
_pattern_boundary ==
"hexagon")
486 "for each input mesh, the number of sectors on each side must be greater than unity.");
487 num_sectors_per_side_array.push_back(*num_sectors_per_side_array_tmp.begin());
488 background_intervals_array.push_back(
489 getMeshProperty<unsigned int>(
"background_intervals_meta",
_input_names[i]));
490 node_id_background_array.push_back(
491 getMeshProperty<dof_id_type>(
"node_id_background_meta",
_input_names[i]));
492 max_radius_array.push_back(getMeshProperty<Real>(
"max_radius_meta",
_input_names[i]));
494 max_radius_global = *max_element(max_radius_array.begin(), max_radius_array.end());
496 *std::min_element(pitch_array.begin(), pitch_array.end())))
499 ": pitch metadata values of all input mesh generators must be identical. Please " 501 "parameters of the mesh generators that produce the input meshes.",
504 if (*std::max_element(num_sectors_per_side_array.begin(), num_sectors_per_side_array.end()) !=
505 *std::min_element(num_sectors_per_side_array.begin(), num_sectors_per_side_array.end()))
507 "In PatternedHexMeshGenerator ",
509 ": num_sectors_per_side metadata values of all input mesh generators must be identical.");
512 std::vector<Real> extra_dist;
513 Real extra_dist_shift(0.0);
519 std::vector<unsigned int> peripheral_duct_intervals;
524 for (
unsigned int i = 0; i <
_duct_sizes.size(); i++)
528 extra_dist.push_back(0.5 *
529 (
_duct_sizes[i] * 2.0 - pitch_array.front() / std::sqrt(3.0) *
535 "The duct sizes should not exceed the size of the hexagonal boundary.");
540 extra_dist.push_back(0.5 * (
_pattern_pitch - pitch_array.front() / std::sqrt(3.0) *
549 if (extra_dist.front() <= extra_dist_tol)
551 extra_dist_shift = extra_dist_shift_0 - extra_dist.front();
552 for (
Real &
d : extra_dist)
553 d += extra_dist_shift;
557 : (pitch_array.front() / std::sqrt(3.0));
558 y_max_0 = pitch_array.front() / std::sqrt(3.0) + extra_dist.front();
559 y_max_n = y_max_0 - extra_dist_shift;
560 if (y_max_n <= y_min)
563 ": the assembly is cut off so much that the internal structure that should not " 564 "be altered is compromised.");
572 std::vector<std::set<boundary_id_type>> input_interface_boundary_ids;
573 input_interface_boundary_ids.resize(
_input_names.size());
578 if (!hasMeshProperty<bool>(
"interface_boundaries",
_input_names[i]))
579 mooseError(
"Metadata 'interface_boundaries' could not be found on the input mesh: ",
581 if (!getMeshProperty<bool>(
"interface_boundaries",
_input_names[i]))
582 mooseError(
"Interface boundary ids were not constructed in the input mesh",
585 mooseError(
"Metadata 'interface_boundary_ids' could not be found on the input mesh: ",
592 input_interface_boundary_ids[i] =
598 ? pitch_array.front()
600 std::vector<Real> control_drum_positions_x;
601 std::vector<Real> control_drum_positions_y;
602 std::vector<std::vector<Real>> control_drum_azimuthals;
604 std::unique_ptr<ReplicatedMesh> out_mesh;
606 for (
unsigned i = 0; i <
_pattern.size(); i++)
608 Real deltax = -x_mov * input_pitch / 2;
615 Real deltay = -(
Real)(i)*input_pitch * std::sin(M_PI / 3);
617 for (
unsigned int j = 0;
j <
_pattern[i].size();
j++)
620 ReplicatedMesh & pattern_mesh = *meshes[pattern];
628 control_drum_positions_x.push_back(deltax +
j * input_pitch);
629 control_drum_positions_y.push_back(deltay);
630 control_drum_azimuthals.push_back(control_drum_azimuthal_array[pattern]);
633 if (
j == 0 && i == 0)
637 out_mesh->add_elem_integer(
640 is_control_drum_array[pattern] ? control_drum_azimuthals.size() : 0);
645 input_interface_boundary_ids[pattern]);
652 Real rotation_angle = std::numeric_limits<Real>::max();
653 Real orientation = std::numeric_limits<Real>::max();
654 unsigned int mesh_type = std::numeric_limits<unsigned int>::max();
655 bool on_periphery =
true;
657 if (
j == 0 && i == 0)
659 rotation_angle = 60.;
663 else if (
j == 0 && i ==
_pattern.size() - 1)
665 rotation_angle = 180.;
669 else if (
j == 0 && i == (
_pattern.size() - 1) / 2)
671 rotation_angle = 120.;
675 else if (
j ==
_pattern[i].size() - 1 && i == 0)
683 rotation_angle = -120.;
689 rotation_angle = -60.;
701 rotation_angle = 180.;
705 else if (
j == 0 && i < (
_pattern.size() - 1) / 2)
707 rotation_angle = 60.;
711 else if (
j == 0 && i > (
_pattern.size() - 1) / 2)
713 rotation_angle = 120.;
719 rotation_angle = -60.;
725 rotation_angle = -120.;
730 on_periphery =
false;
739 num_sectors_per_side_array,
740 peripheral_duct_intervals,
744 if (extra_dist_shift != 0)
745 cutOffPolyDeform(*tmp_peripheral_mesh, orientation, y_max_0, y_max_n, y_min, mesh_type);
751 input_interface_boundary_ids[pattern]);
753 if (i == 0 &&
j == 0)
754 out_mesh = std::move(tmp_peripheral_mesh);
759 const auto & increment_subdomain_map = tmp_peripheral_mesh->get_subdomain_name_map();
760 out_mesh->set_subdomain_name_map().insert(increment_subdomain_map.begin(),
761 increment_subdomain_map.end());
763 MeshTools::Modification::translate(
764 *tmp_peripheral_mesh, deltax +
j * input_pitch, deltay, 0);
765 out_mesh->stitch_meshes(*tmp_peripheral_mesh,
778 pattern_mesh.add_elem_integer(
781 is_control_drum_array[pattern] ? control_drum_azimuthals.size() : 0);
784 MeshTools::Modification::translate(pattern_mesh, deltax +
j * input_pitch, deltay, 0);
787 auto & main_subdomain_map = out_mesh->set_subdomain_name_map();
790 const auto & increment_subdomain_map = pattern_mesh.get_subdomain_name_map();
791 main_subdomain_map.insert(increment_subdomain_map.begin(), increment_subdomain_map.end());
793 std::set<SubdomainName> main_subdomain_map_name_list;
794 for (
auto const & id_name_pair : main_subdomain_map)
795 main_subdomain_map_name_list.emplace(id_name_pair.second);
796 if (main_subdomain_map.size() != main_subdomain_map_name_list.size())
797 paramError(
"inputs",
"The input meshes contain subdomain name maps with conflicts.");
802 input_interface_boundary_ids[pattern]);
804 out_mesh->stitch_meshes(pattern_mesh,
813 MeshTools::Modification::translate(pattern_mesh, -(deltax +
j * input_pitch), -deltay, 0);
818 input_interface_boundary_ids[pattern],
824 auto side_list = out_mesh->get_boundary_info().build_side_list();
825 for (
auto & sl : side_list)
828 if (out_mesh->elem_ptr(std::get<0>(sl))->neighbor_ptr(std::get<1>(sl)) !=
nullptr)
829 out_mesh->get_boundary_info().remove_side(
830 out_mesh->elem_ptr(std::get<0>(sl)), std::get<1>(sl), std::get<2>(sl));
832 out_mesh->get_boundary_info().clear_boundary_node_ids();
834 out_mesh->get_boundary_info().build_node_list_from_side_list();
835 const auto node_list = out_mesh->get_boundary_info().build_node_list();
837 std::vector<Real> bd_x_list;
838 std::vector<Real> bd_y_list;
839 std::vector<std::pair<Real, dof_id_type>> node_azi_list;
841 const Real origin_x = origin_pt(0);
842 const Real origin_y = origin_pt(1);
844 MeshTools::Modification::translate(*out_mesh, -origin_x, -origin_y, 0);
848 const Real azi_tol = 1E-8;
849 for (
unsigned int i = 0; i < node_list.size(); ++i)
853 node_azi_list.push_back(
854 std::make_pair(atan2(out_mesh->node_ref(std::get<0>(node_list[i]))(1),
855 out_mesh->node_ref(std::get<0>(node_list[i]))(0)) *
857 std::get<0>(node_list[i])));
859 if (node_azi_list.back().first + 180.0 <= azi_tol)
860 node_azi_list.back().first = 180;
863 std::sort(node_azi_list.begin(), node_azi_list.end());
867 for (
unsigned int j = 1;
j <= side_intervals;
j++)
869 Real azi_corr_tmp = atan2((
Real)
j * 2.0 / (
Real)side_intervals - 1.0, std::sqrt(3.0));
871 Real y_tmp = x_tmp * std::tan(azi_corr_tmp);
873 Point p_tmp = Point(x_tmp, y_tmp, 0.0);
874 out_mesh->add_point(p_tmp, node_azi_list[i * side_intervals +
j - 1].second);
885 MeshTools::Modification::rotate(*out_mesh,
_rotate_angle, 0.0, 0.0);
891 const Real azi_tol = 1E-8;
892 std::vector<std::tuple<Real, Point, std::vector<Real>,
dof_id_type>> control_drum_tmp;
893 std::vector<dof_id_type> control_drum_id_sorted;
894 for (
unsigned int i = 0; i < control_drum_positions_x.size(); ++i)
896 control_drum_positions_x[i] -= origin_x;
897 control_drum_positions_y[i] -= origin_y;
899 Real cd_angle = atan2(control_drum_positions_y[i], control_drum_positions_x[i]);
901 for (
unsigned int j = 0;
j < control_drum_azimuthals[i].size();
j++)
904 control_drum_azimuthals[i][
j] =
905 atan2(std::sin(control_drum_azimuthals[i][
j] / 180.0 * M_PI),
906 std::cos(control_drum_azimuthals[i][
j] / 180.0 * M_PI)) /
909 std::sort(control_drum_azimuthals[i].begin(), control_drum_azimuthals[i].end());
911 if (std::abs(cd_angle) < azi_tol)
913 else if (cd_angle < 0.0)
914 cd_angle += 2 * M_PI;
915 control_drum_tmp.push_back(
916 std::make_tuple(cd_angle,
917 Point(control_drum_positions_x[i], control_drum_positions_y[i], 0.0),
918 control_drum_azimuthals[i],
921 std::sort(control_drum_tmp.begin(), control_drum_tmp.end());
922 std::vector<Point> control_drum_positions;
923 std::vector<Real> control_drum_angles;
924 std::vector<std::vector<Real>> control_drums_azimuthal_meta;
925 for (
unsigned int i = 0; i < control_drum_tmp.size(); ++i)
927 control_drum_positions.push_back(std::get<1>(control_drum_tmp[i]));
928 control_drum_angles.push_back(std::get<0>(control_drum_tmp[i]));
929 control_drums_azimuthal_meta.push_back(std::get<2>(control_drum_tmp[i]));
930 control_drum_id_sorted.push_back(std::get<3>(control_drum_tmp[i]));
934 setMeshProperty(
"control_drums_azimuthal_meta", control_drums_azimuthal_meta);
938 unsigned int id = out_mesh->get_elem_integer_index(
"control_drum_id");
939 for (
const auto & elem : out_mesh->element_ptr_range())
941 dof_id_type unsorted_control_drum_id = elem->get_extra_integer(
id);
942 if (unsorted_control_drum_id != 0)
944 auto sorted_iter = std::find(control_drum_id_sorted.begin(),
945 control_drum_id_sorted.end(),
946 unsorted_control_drum_id);
947 elem->set_extra_integer(
id,
948 std::distance(control_drum_id_sorted.begin(), sorted_iter) + 1);
955 std::string position_file_name = getMeshProperty<std::string>(
"position_file_name",
name());
956 std::ofstream pos_file(position_file_name);
957 for (
unsigned int i = 0; i < control_drum_positions.size(); ++i)
958 pos_file << control_drum_positions[i](0) <<
" " << control_drum_positions[i](1) <<
" 0.0\n";
969 for (
const auto & elem : out_mesh->active_element_ptr_range())
972 if (elem->subdomain_id() == i)
989 out_mesh->get_boundary_info().sideset_name(
992 out_mesh->get_boundary_info().nodeset_name(
998 auto & new_sideset_map = out_mesh->get_boundary_info().set_sideset_name_map();
999 auto & new_nodeset_map = out_mesh->get_boundary_info().set_nodeset_name_map();
1000 for (
unsigned int i = 0; i < meshes.size(); i++)
1002 const auto input_sideset_map = meshes[i]->get_boundary_info().get_sideset_name_map();
1003 new_sideset_map.insert(input_sideset_map.begin(), input_sideset_map.end());
1004 const auto input_nodeset_map = meshes[i]->get_boundary_info().get_nodeset_name_map();
1005 new_nodeset_map.insert(input_nodeset_map.begin(), input_nodeset_map.end());
1009 const std::set<boundary_id_type> boundary_ids = out_mesh->get_boundary_info().get_boundary_ids();
1014 input_interface_boundary_ids,
1018 if (interface_boundary_ids.size() > 0)
1024 out_mesh->set_isnt_prepared();
1031 ReplicatedMesh & mesh,
1032 const unsigned int pattern,
1034 const std::vector<Real> & extra_dist,
1035 const std::vector<unsigned int> & num_sectors_per_side_array,
1036 const std::vector<unsigned int> & peripheral_duct_intervals,
1037 const Real rotation_angle,
1038 const unsigned int mesh_type)
1040 std::vector<std::pair<Real, Real>> positions_inner;
1041 std::vector<std::pair<Real, Real>> d_positions_outer;
1043 std::vector<std::vector<unsigned int>> peripheral_point_index;
1044 std::vector<std::pair<Real, Real>> sub_positions_inner;
1045 std::vector<std::pair<Real, Real>> sub_d_positions_outer;
1051 peripheral_point_index = {{0, 1, 2}, {2, 3, 4}, {4, 5, 6}};
1054 peripheral_point_index = {{0, 1, 2}, {2, 7, 8}};
1058 for (
unsigned int i = 0; i < extra_dist.size(); i++)
1062 i == 0 ? 0.0 : extra_dist[i - 1],
1068 for (
unsigned int peripheral_index = 0; peripheral_index < peripheral_point_index.size();
1072 for (
unsigned int vector_index = 0; vector_index < 3; vector_index++)
1074 sub_positions_inner.push_back(
1075 positions_inner[peripheral_point_index[peripheral_index][vector_index]]);
1076 sub_d_positions_outer.push_back(
1077 d_positions_outer[peripheral_point_index[peripheral_index][vector_index]]);
1080 peripheral_duct_intervals[i],
1081 sub_positions_inner,
1082 sub_d_positions_outer,
1086 (i != extra_dist.size() - 1) &&
1090 meshp0->prepare_for_use();
1093 MeshTools::Modification::rotate(*meshp0, rotation_angle, 0, 0);
1095 sub_positions_inner.resize(0);
1096 sub_d_positions_outer.resize(0);
1103 std::vector<std::pair<Real, Real>> & d_positions_outer,
1104 const Real extra_dist_in,
1105 const Real extra_dist_out,
1107 const unsigned int radial_index)
const 1109 positions_inner.resize(0);
1110 d_positions_outer.resize(0);
1139 positions_inner.push_back(
1140 std::make_pair(-
pitch / 2.0,
1141 std::sqrt(3.0) *
pitch / 6.0 +
1142 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 6.0 + extra_dist_in : 0.0)));
1143 positions_inner.push_back(std::make_pair(
1145 std::sqrt(3.0) *
pitch / 4.0 +
1146 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 12.0 + extra_dist_in : 0.0)));
1147 positions_inner.push_back(std::make_pair(
1148 0.0, std::sqrt(3.0) *
pitch / 3.0 + (radial_index != 0 ? extra_dist_in : 0.0)));
1149 positions_inner.push_back(std::make_pair(
1150 pitch / 4.0 + (radial_index != 0 ?
pitch / 12.0 + std::sqrt(3.0) * extra_dist_in / 3.0 : 0.0),
1151 std::sqrt(3.0) *
pitch / 4.0 +
1152 (radial_index != 0 ?
pitch * std::sqrt(3.0) / 12.0 + extra_dist_in : 0.0)));
1153 positions_inner.push_back(std::make_pair(
1154 pitch / 2.0 + (radial_index != 0 ? std::sqrt(3.0) * extra_dist_in / 2.0 : 0.0),
1155 std::sqrt(3.0) *
pitch / 6.0 + (radial_index != 0 ? extra_dist_in / 2.0 : 0.0)));
1156 positions_inner.push_back(std::make_pair(
1157 pitch / 2.0 + (radial_index != 0 ?
pitch / 8.0 + std::sqrt(3.0) * extra_dist_in / 2.0 : 0.0),
1158 0.0 + (radial_index != 0 ? std::sqrt(3.0) *
pitch / 24.0 + extra_dist_in / 2.0 : 0.0)));
1159 positions_inner.push_back(std::make_pair(
1160 pitch / 2.0 + (radial_index != 0 ?
pitch / 4.0 + std::sqrt(3.0) * extra_dist_in / 2.0 : 0.0),
1161 -std::sqrt(3.0) *
pitch / 6.0 +
1162 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 12.0 + extra_dist_in / 2.0 : 0.0)));
1163 positions_inner.push_back(std::make_pair(
1165 std::sqrt(3.0) *
pitch / 4.0 +
1166 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 12.0 + extra_dist_in : 0.0)));
1167 positions_inner.push_back(
1168 std::make_pair(
pitch / 2.0,
1169 std::sqrt(3.0) *
pitch / 6.0 +
1170 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 6.0 + extra_dist_in : 0.0)));
1172 d_positions_outer.push_back(
1174 std::sqrt(3.0) *
pitch / 6.0 + extra_dist_out -
1175 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 6.0 + extra_dist_in : 0.0)));
1176 d_positions_outer.push_back(std::make_pair(
1178 std::sqrt(3.0) *
pitch / 12.0 + extra_dist_out -
1179 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 12.0 + extra_dist_in : 0.0)));
1180 d_positions_outer.push_back(
1181 std::make_pair(0.0, extra_dist_out - (radial_index != 0 ? extra_dist_in : 0.0)));
1182 d_positions_outer.push_back(std::make_pair(
1183 pitch / 12.0 + std::sqrt(3.0) * extra_dist_out / 3.0 -
1184 (radial_index != 0 ?
pitch / 12.0 + std::sqrt(3.0) * extra_dist_in / 3.0 : 0.0),
1185 pitch * std::sqrt(3.0) / 12.0 + extra_dist_out -
1186 (radial_index != 0 ?
pitch * std::sqrt(3.0) / 12.0 + extra_dist_in : 0.0)));
1187 d_positions_outer.push_back(
1188 std::make_pair(std::sqrt(3.0) * extra_dist_out / 2.0 -
1189 (radial_index != 0 ? std::sqrt(3.0) * extra_dist_in / 2.0 : 0.0),
1190 extra_dist_out / 2.0 - (radial_index != 0 ? extra_dist_in / 2.0 : 0.0)));
1191 d_positions_outer.push_back(std::make_pair(
1192 pitch / 8.0 + std::sqrt(3.0) * extra_dist_out / 2.0 -
1193 (radial_index != 0 ?
pitch / 8.0 + std::sqrt(3.0) * extra_dist_in / 2.0 : 0.0),
1194 std::sqrt(3.0) *
pitch / 24.0 + extra_dist_out / 2.0 -
1195 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 24.0 + extra_dist_in / 2.0 : 0.0)));
1196 d_positions_outer.push_back(std::make_pair(
1197 pitch / 4.0 + std::sqrt(3.0) * extra_dist_out / 2.0 -
1198 (radial_index != 0 ?
pitch / 4.0 + std::sqrt(3.0) * extra_dist_in / 2.0 : 0.0),
1199 std::sqrt(3.0) *
pitch / 12.0 + extra_dist_out / 2.0 -
1200 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 12.0 + extra_dist_in / 2.0 : 0.0)));
1201 d_positions_outer.push_back(std::make_pair(
1203 std::sqrt(3.0) *
pitch / 12.0 + extra_dist_out -
1204 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 12.0 + extra_dist_in : 0.0)));
1205 d_positions_outer.push_back(
1207 std::sqrt(3.0) *
pitch / 6.0 + extra_dist_out -
1208 (radial_index != 0 ? std::sqrt(3.0) *
pitch / 6.0 + extra_dist_in : 0.0)));
1213 MeshBase & mesh,
const std::vector<std::unique_ptr<ReplicatedMesh>> & from_meshes)
const 1216 for (
unsigned int i = 0; i < num_reporting_ids; ++i)
1219 unsigned int extra_id_index;
1220 if (!
mesh.has_elem_integer(element_id_name))
1221 extra_id_index =
mesh.add_elem_integer(element_id_name);
1224 extra_id_index =
mesh.get_elem_integer_index(element_id_name);
1226 "id_name",
"An element integer with the name '", element_id_name,
"' already exists");
1232 std::set<subdomain_id_type> background_block_ids =
1234 : std::set<subdomain_id_type>();
1236 const bool using_manual_id =
1244 background_block_ids,
1249 : std::vector<std::vector<dof_id_type>>());
const bool _use_reporting_id
Whether reporting ID is added to mesh.
const PolygonSizeStyle _duct_sizes_style
Style of the duct size parameter(s)
void positionSetup(std::vector< std::pair< Real, Real >> &positions_inner, std::vector< std::pair< Real, Real >> &d_positions_outer, const Real extra_dist_in, const Real extra_dist_out, const Real pitch, const unsigned int radial_index) const
Computes the inner and outer node positions of the peripheral region for a single layer...
const std::vector< unsigned int > _duct_intervals
Number(s) of radial intervals of duct layer(s)
std::vector< std::string > _reporting_id_names
names of reporting ID
const bool _allow_unused_inputs
Whether to allow additional assembly types to be passed to "inputs" parameter without being used in l...
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 MooseEnum _pattern_boundary
Type of the external boundary shape.
const bool _has_assembly_duct
Whether the hexagonal pattern has external duct(s)
const unsigned int _background_intervals
Number of radial intervals in the background region.
void assignReportingIDs(MeshBase &mesh, const unsigned int extra_id_index, const ReportingIDGeneratorUtils::AssignType assign_type, const bool use_exclude_id, const std::vector< bool > &exclude_ids, const bool has_assembly_boundary, const std::set< subdomain_id_type > background_block_ids, const std::vector< std::unique_ptr< libMesh::ReplicatedMesh >> &input_meshes, const std::vector< std::vector< unsigned int >> &pattern, const std::vector< std::vector< dof_id_type >> &id_pattern)
assign the reporting IDs to the output mesh from the cartesian or hexagonal patterned mesh generator ...
assign IDs based on user-defined mapping
std::vector< SubdomainName > _peripheral_block_names
Subdomain Names of the peripheral regions.
const bool _assign_control_drum_id
Wheter control drum IDs are assigned as an extra element integer.
const std::vector< std::vector< unsigned int > > & _pattern
2D vector of the hexagonal pattern
const PolygonSizeStyle _hexagon_size_style
Style of the polygon size parameter.
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
const bool _create_inward_interface_boundaries
Whether inward interface boundaries are created.
const bool _create_outward_interface_boundaries
Whether outward interface boundaries are created.
void changeBoundaryId(const boundary_id_type old_id, const boundary_id_type new_id, bool delete_prev)
virtual const std::string & name() const
void nodeCoordRotate(Real &x, Real &y, const Real theta) const
Calculates x and y coordinates after rotating by theta angle.
std::vector< std::vector< boundary_id_type > > _interface_boundary_id_shift_pattern
hold user-defined shift values for each pattern cell
const std::vector< MeshGeneratorName > & _input_names
Names of input meshes.
bool isParamValid(const std::string &name) const
const Real _rotate_angle
The mesh rotation angle after mesh generation.
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...
static InputParameters validParams()
registerMooseObject("ReactorApp", PatternedHexMeshGenerator)
const std::vector< SubdomainName > _duct_block_names
Subdomain Names of the duct layers.
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...
std::vector< ReportingIDGeneratorUtils::AssignType > _assign_types
reporting ID assignment type
const bool _uniform_mesh_on_sides
Whether the nodes on the external boundary are uniformly distributed.
static const std::string pitch
QUAD_ELEM_TYPE _boundary_quad_elem_type
Type of quadrilateral elements to be generated in the periphery region.
std::vector< Real > _duct_sizes
Size parameter(s) of duct(s)
const std::vector< std::unique_ptr< MeshBase > * > _mesh_ptrs
The input meshes.
const bool _use_exclude_id
flag to indicate if exclude_id is defined
const std::vector< subdomain_id_type > _duct_block_ids
Subdomain IDs of the duct layers.
const boundary_id_type _external_boundary_id
Boundary ID of mesh's external boundary.
const bool _deform_non_circular_region
Whether the non-circular region (outside the rings) can be deformed.
const bool _generate_control_drum_positions_file
Whether a text file containing control drum positions is generated.
void paramError(const std::string ¶m, Args... args) const
std::vector< subdomain_id_type > _peripheral_block_ids
Subdomain IDs of the peripheral regions.
std::unique_ptr< MeshBase > generate() override
const bool _use_interface_boundary_id_shift
whether the interface boundary ids from input meshes are shifted, using a user-defined pattern of val...
PatternedHexMeshGenerator(const InputParameters ¶meters)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void addPeripheralMesh(ReplicatedMesh &mesh, const unsigned int pattern, const Real pitch, const std::vector< Real > &extra_dist, const std::vector< unsigned int > &num_sectors_per_side_array, const std::vector< unsigned int > &peripheral_duct_intervals, const Real rotation_angle, const unsigned int mesh_type)
Adds background and duct region mesh to stitched hexagon meshes.
This PatternedHexMeshGenerator source code assembles hexagonal meshes into a hexagonal grid and optio...
void addReportingIDs(MeshBase &mesh, const std::vector< std::unique_ptr< ReplicatedMesh >> &from_meshes) const
Adds the reporting IDs onto the input mesh.
A base class that contains common members for Reactor module mesh generators.
Real _pattern_pitch
Pitch size of the input assembly mesh.
static InputParameters validParams()
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
T & declareMeshProperty(const std::string &data_name, Args &&... args)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
const BoundaryName _external_boundary_name
Boundary name of mesh's external boundary.
void paramWarning(const std::string ¶m, Args... args) const
Point meshCentroidCalculator(const MeshBase &mesh)
std::vector< bool > _exclude_ids
vector indicating which ids in the pattern to exclude (true at pattern positions to exclude) ...
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 ...
void ErrorVector unsigned int
auto index_range(const T &sizable)
std::map< std::string, std::vector< std::vector< dof_id_type > > > _id_patterns
hold ID patterns for each manual reporting ID. Individual ID pattern contains ID values for each patt...
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.
const bool _generate_core_metadata
Whether a reactor core mesh with core metadata is generated.
PolygonSizeStyle
An enum class for style of input polygon size.
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...