20#include "libmesh/elem.h"
29 params.addRequiredParam<MeshGeneratorName>(
31 "The ReactorMeshParams MeshGenerator that is the basis for this component conformal mesh.");
33 params.addRequiredParam<subdomain_id_type>(
"pin_type",
34 "The integer ID for this pin type definition");
36 params.addRequiredRangeCheckedParam<Real>(
37 "pitch",
"pitch>0.0",
"The pitch for the outermost boundary polygon");
39 params.addRangeCheckedParam<
unsigned int>(
40 "num_sectors",
"num_sectors>0",
"Number of azimuthal sectors in each quadrant");
42 params.addRangeCheckedParam<std::vector<Real>>(
45 "Radii of major concentric circles of the pin. If unspecified, no pin is present.");
47 params.addRangeCheckedParam<std::vector<Real>>(
50 "Apothem of the ducts. If unspecified, no duct is present.");
52 params.addRangeCheckedParam<std::vector<unsigned int>>(
54 std::vector<unsigned int>{1},
56 "The number of meshing intervals for each region starting at the center. Parameter should be "
58 "((length(ring_radii) + length(duct_halfpitch) + 1");
60 params.addParam<std::vector<std::vector<std::string>>>(
62 "Block names for each radial and axial zone. "
63 "Inner indexing is radial zones (pin/background/duct), outer indexing is axial");
65 params.addParam<std::vector<std::vector<subdomain_id_type>>>(
67 "IDs for each radial and axial zone for assignment of region_id extra element "
69 "Inner indexing is radial zones (pin/background/duct), outer indexing is axial");
71 params.addParam<
bool>(
"extrude",
73 "Determines if this is the final step in the geometry construction"
74 " and extrudes the 2D geometry to 3D. If this is true then this mesh "
75 "cannot be used in further mesh building in the Reactor workflow");
76 params.addParam<
bool>(
77 "homogenized",
false,
"Determines whether homogenized pin mesh should be generated");
78 params.addParam<
bool>(
79 "use_as_assembly",
false,
"Determines whether pin mesh should be used as an assembly mesh");
81 params.addParam<
bool>(
82 "quad_center_elements",
true,
"Whether the center elements are quad or triangular.");
83 params.addParamNamesToGroup(
"region_ids pin_type",
"ID assigment");
84 params.addParamNamesToGroup(
85 "mesh_intervals ring_radii num_sectors pin_type homogenized use_as_assembly",
86 "Pin specifications");
87 params.addParamNamesToGroup(
"mesh_intervals duct_halfpitch num_sectors",
"Duct specifications");
89 params.addClassDescription(
"This PinMeshGenerator object is designed to generate pin-like "
90 "structures, with IDs, from a reactor geometry. "
91 "Whether it be a square or hexagonal pin, they are divided into three "
92 "substructures - the innermost "
93 "radial pin regions, the single bridging background region, and the "
94 "square or hexagonal ducts regions.");
104 _pin_type(getParam<subdomain_id_type>(
"pin_type")),
105 _pitch(getParam<Real>(
"pitch")),
106 _num_sectors(isParamValid(
"num_sectors") ? getParam<unsigned
int>(
"num_sectors") : 0),
107 _ring_radii(isParamValid(
"ring_radii") ? getParam<
std::vector<Real>>(
"ring_radii")
108 :
std::vector<Real>()),
109 _duct_halfpitch(isParamValid(
"duct_halfpitch") ? getParam<
std::vector<Real>>(
"duct_halfpitch")
110 :
std::vector<Real>()),
111 _intervals(getParam<
std::vector<unsigned
int>>(
"mesh_intervals")),
112 _region_ids(isParamValid(
"region_ids")
113 ? getParam<
std::vector<
std::vector<subdomain_id_type>>>(
"region_ids")
114 :
std::vector<
std::vector<subdomain_id_type>>()),
115 _extrude(getParam<bool>(
"extrude")),
116 _quad_center(getParam<bool>(
"quad_center_elements")),
117 _homogenized(getParam<bool>(
"homogenized")),
118 _is_assembly(getParam<bool>(
"use_as_assembly"))
129 if (assembly_pitch !=
_pitch)
130 mooseError(
"Pitch defined in PinMeshGenerator must match assembly_pitch defined in "
131 "ReactorMeshParams if use_as_assembly is set to true");
136 "In order to extrude this mesh, ReactorMeshParams/dim needs to be set to 3\n");
139 mooseError(
"Both top_boundary_id and bottom_boundary_id must be provided in ReactorMeshParams "
140 "if using extruded geometry");
145 mooseError(
"Homogenization in PinMeshGenerator is only supported for hexagonal geometries");
146 const std::vector<std::string> disallowed_parameters = {
147 "num_sectors",
"ring_radii",
"duct_halfpitch",
"mesh_intervals"};
148 for (
const auto & parameter : disallowed_parameters)
151 "Parameter " + parameter +
" should not be defined for a homogenized pin mesh");
157 "Number of sectors must be assigned with parameter num_sectors for non-homogenized pins");
160 "The number of mesh intervals must be equal to the number of annular regions + the "
161 "number of duct regions + 1"
162 " for the region between the rings and ducts\n");
167 unsigned int n_axial_levels =
172 mooseError(
"The size of region IDs must be equal to the number of axial levels as defined in "
173 "the ReactorMeshParams object");
175 mooseError(
"The number of region IDs given needs to be one more than the number of "
176 "ring_radii + the number of duct_radii\n");
180 mooseError(
"Region IDs must be assigned with parameter region_ids");
186 "If ReactorMeshParams/region_id_as_block_name is set, block_names should not be "
187 "specified in PinMeshGenerator");
189 _block_names = getParam<std::vector<std::vector<std::string>>>(
"block_names");
191 mooseError(
"The size of block_names must match the size of region_ids");
194 mooseError(
"The size of block_names must match the size of region_ids");
200 std::string build_mesh_name;
210 bool skip_assembly_generation =
_is_assembly && use_flexible_stitching;
214 params.
set<Real>(
"hexagon_size") =
_pitch / 2.0;
215 params.set<boundary_id_type>(
"external_boundary_id") =
217 const auto boundary_name =
220 params.set<BoundaryName>(
"external_boundary_name") = boundary_name;
221 params.set<std::vector<subdomain_id_type>>(
"block_id") = {
227 params.set<std::vector<SubdomainName>>(
"block_name") = {block_name};
229 if (!skip_assembly_generation)
231 build_mesh_name =
name() +
"_2D";
238 std::vector<unsigned int> ring_intervals;
239 std::vector<subdomain_id_type> ring_blk_ids;
240 std::vector<SubdomainName> ring_blk_names;
241 unsigned int background_intervals = 1;
242 std::vector<subdomain_id_type> background_blk_ids;
243 std::vector<SubdomainName> background_blk_names;
244 std::vector<unsigned int> duct_intervals;
245 std::vector<subdomain_id_type> duct_blk_ids;
246 std::vector<SubdomainName> duct_blk_names;
250 const auto block_name =
257 ring_blk_ids.push_back(block_id);
258 ring_blk_names.push_back(block_name);
263 duct_blk_ids.push_back(block_id);
264 duct_blk_names.push_back(block_name);
269 background_blk_ids.push_back(block_id);
270 background_blk_names.push_back(block_name);
273 if (ring_intervals.size() > 0)
275 if (ring_intervals.front() != 1)
282 ring_blk_ids.insert(ring_blk_ids.begin(), ring_blk_ids.front());
283 ring_blk_names.insert(ring_blk_names.begin(), ring_blk_names.front());
289 ring_blk_ids.insert(ring_blk_ids.begin(), block_id);
290 ring_blk_names.insert(ring_blk_names.begin(), block_name);
302 if (background_intervals > 1)
309 background_blk_ids.insert(background_blk_ids.begin(), background_blk_ids.front());
310 background_blk_names.insert(background_blk_names.begin(), background_blk_names.front());
316 background_blk_ids.insert(background_blk_ids.begin(), block_id);
317 background_blk_names.insert(background_blk_names.begin(), block_name);
332 bool skip_assembly_generation =
335 if (!skip_assembly_generation)
342 params.
set<
bool>(
"preserve_volumes") =
true;
343 params.set<
bool>(
"quad_center_elements") =
_quad_center;
344 params.set<
MooseEnum>(
"polygon_size_style") =
"apothem";
345 params.set<Real>(
"polygon_size") =
_pitch / 2.0;
346 params.set<boundary_id_type>(
"external_boundary_id") =
351 params.set<BoundaryName>(
"external_boundary_name") = boundary_name;
353 params.set<
bool>(
"flat_side_up") = flat_side_up;
354 params.set<
bool>(
"create_outward_interface_boundaries") =
false;
357 params.set<
unsigned int>(
"num_sides") = num_sides;
358 params.set<std::vector<unsigned int>>(
"num_sectors_per_side") =
361 if (ring_intervals.size() > 0)
363 params.set<std::vector<Real>>(
"ring_radii") =
_ring_radii;
364 params.set<std::vector<subdomain_id_type>>(
"ring_block_ids") = ring_blk_ids;
365 params.set<std::vector<SubdomainName>>(
"ring_block_names") = ring_blk_names;
366 params.set<std::vector<unsigned int>>(
"ring_intervals") = ring_intervals;
369 params.set<std::vector<subdomain_id_type>>(
"background_block_ids") = background_blk_ids;
370 params.set<std::vector<SubdomainName>>(
"background_block_names") = background_blk_names;
371 params.set<
unsigned int>(
"background_intervals") = background_intervals;
373 if (duct_intervals.size() > 0)
375 params.set<
MooseEnum>(
"duct_sizes_style") =
"apothem";
377 params.set<std::vector<subdomain_id_type>>(
"duct_block_ids") = duct_blk_ids;
378 params.set<std::vector<SubdomainName>>(
"duct_block_names") = duct_blk_names;
379 params.set<std::vector<unsigned int>>(
"duct_intervals") = duct_intervals;
389 params.
set<MeshGeneratorName>(
"input") =
name() +
"_2D";
392 std::vector<BoundaryName> boundaries_to_delete = {};
393 for (
const auto i : make_range(num_sides))
394 boundaries_to_delete.insert(boundaries_to_delete.end(),
395 {std::to_string(10001 + i), std::to_string(15001 + i)});
396 params.set<std::vector<BoundaryName>>(
"boundary_names") = boundaries_to_delete;
398 build_mesh_name =
name() +
"_delbds";
409 build_mesh_name =
name() +
"_fpg_delbds";
413 if (hasMeshProperty<Real>(
"pitch_meta",
name() +
"_2D"))
414 copyMeshProperty<Real>(
"pitch_meta",
name() +
"_2D");
415 if (
hasMeshProperty<std::vector<unsigned int>>(
"num_sectors_per_side_meta",
name() +
"_2D"))
416 copyMeshProperty<std::vector<unsigned int>>(
"num_sectors_per_side_meta",
name() +
"_2D");
417 if (hasMeshProperty<Real>(
"max_radius_meta",
name() +
"_2D"))
418 copyMeshProperty<Real>(
"max_radius_meta",
name() +
"_2D");
419 if (hasMeshProperty<unsigned int>(
"background_intervals_meta",
name() +
"_2D"))
420 copyMeshProperty<unsigned int>(
"background_intervals_meta",
name() +
"_2D");
421 if (hasMeshProperty<dof_id_type>(
"node_id_background_meta",
name() +
"_2D"))
422 copyMeshProperty<dof_id_type>(
"node_id_background_meta",
name() +
"_2D");
426 else if (hasMeshProperty<Real>(
"pattern_pitch_meta",
name() +
"_2D"))
427 copyMeshProperty<Real>(
"pattern_pitch_meta",
name() +
"_2D");
443 SubdomainName outermost_block_name;
444 bool has_single_mesh_interval;
451 has_single_mesh_interval =
true;
457 has_single_mesh_interval =
false;
462 params.
set<std::vector<SubdomainName>>(
"block") = {outermost_block_name};
472 if (has_single_mesh_interval)
473 params.
set<std::vector<MeshGeneratorName>>(
"inputs") = {};
476 params.set<std::vector<MeshGeneratorName>>(
"inputs") = {
name() +
"_del_outer"};
477 params.set<std::vector<libMesh::Point>>(
"extra_positions") = {
libMesh::Point(0, 0, 0)};
478 params.set<std::vector<unsigned int>>(
"extra_positions_mg_indices") = {0};
480 params.set<
bool>(
"use_auto_area_func") =
true;
481 params.set<
bool>(
"verify_holes") =
false;
483 params.set<
unsigned int>(
"boundary_sectors") =
487 params.set<BoundaryName>(
"external_boundary_name") =
489 params.set<SubdomainName>(
"background_subdomain_name") =
499 params.
set<MeshGeneratorName>(
"input") =
name() +
"_fpg";
500 std::vector<BoundaryName> boundaries_to_delete = {};
501 if (!has_single_mesh_interval)
502 boundaries_to_delete.push_back(std::to_string(1));
503 params.set<std::vector<BoundaryName>>(
"boundary_names") = boundaries_to_delete;
514 std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>> region_id_map{
529 std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>> pin_region_id_map;
530 pin_region_id_map.insert(
531 std::pair<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>(
532 region_id_map.begin()->first, region_id_map.begin()->second));
534 std::map<subdomain_id_type, std::vector<std::vector<std::string>>> pin_block_name_map;
535 pin_block_name_map.insert(std::pair<subdomain_id_type, std::vector<std::vector<std::string>>>(
555 unsigned int n_axial_levels =
559 std::vector<std::vector<subdomain_id_type>> ring_region_ids(
560 n_axial_levels, std::vector<subdomain_id_type>(
_ring_radii.size()));
561 std::vector<std::vector<subdomain_id_type>> duct_region_ids(
562 n_axial_levels, std::vector<subdomain_id_type>(
_duct_halfpitch.size()));
563 std::vector<subdomain_id_type> background_region_ids(n_axial_levels);
565 for (
const auto axial_idx : make_range(n_axial_levels))
567 for (
const auto ring_idx : index_range(
_ring_radii))
568 ring_region_ids[axial_idx][ring_idx] =
_region_ids[axial_idx][ring_idx];
572 for (
unsigned int duct_idx =
_ring_radii.size() + 1;
575 duct_region_ids[axial_idx][duct_idx -
_ring_radii.size() - 1] =
585std::unique_ptr<MeshBase>
596 auto null_mesh =
nullptr;
602 if (hasMeshProperty<Real>(
"max_radius_meta",
name() +
"_2D"))
604 const auto max_radius_meta = getMeshProperty<Real>(
"max_radius_meta",
name() +
"_2D");
607 if (hasMeshProperty<unsigned int>(
"background_intervals_meta",
name() +
"_2D"))
609 const auto background_intervals_meta =
610 getMeshProperty<unsigned int>(
"background_intervals_meta",
name() +
"_2D");
611 setMeshProperty(
"background_intervals_meta", background_intervals_meta);
613 if (hasMeshProperty<dof_id_type>(
"node_id_background_meta",
name() +
"_2D"))
615 const auto node_id_background_meta =
616 getMeshProperty<dof_id_type>(
"node_id_background_meta",
name() +
"_2D");
626 std::string region_id_name =
"region_id";
627 std::string pin_type_id_name =
"pin_type_id";
628 std::string assembly_type_id_name =
"assembly_type_id";
629 std::string plane_id_name =
"plane_id";
630 std::string radial_id_name =
"radial_id";
631 const std::string default_block_name =
638 unsigned int plane_id_int = 0;
639 unsigned int assembly_type_id_int = 0;
647 std::map<std::string, SubdomainID> rgmb_name_id_map;
652 for (
auto & elem : (*_build_mesh)->active_element_ptr_range())
654 const auto base_block_id = elem->subdomain_id();
655 const auto base_block_name = (*_build_mesh)->subdomain_name(base_block_id);
659 if (!(base_block_name.find(prefix, 0) == 0))
662 std::string radial_str = base_block_name.substr(prefix.length());
666 const std::size_t found = radial_str.find(suffix);
667 if (found != std::string::npos)
668 radial_str.replace(found, suffix.length(),
"");
669 const unsigned int radial_idx = std::stoi(radial_str);
672 dof_id_type z_id =
_extrude ? elem->get_extra_integer(plane_id_int) : 0;
673 const subdomain_id_type elem_region_id =
_region_ids[std::size_t(z_id)][radial_idx];
676 elem->set_extra_integer(region_id_int, elem_region_id);
677 elem->set_extra_integer(pin_type_id_int,
_pin_type);
678 elem->set_extra_integer(radial_id_int, radial_idx);
680 elem->set_extra_integer(assembly_type_id_int,
_pin_type);
683 auto elem_block_name = default_block_name;
685 elem_block_name +=
"_" +
_block_names[std::size_t(z_id)][radial_idx];
687 elem_block_name +=
"_REG" + std::to_string(elem_region_id);
688 if (elem->type() == TRI3 || elem->type() == PRISM6)
691 *(*
_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
695 (*_build_mesh)->unset_is_prepared();
700std::unique_ptr<CSG::CSGBase>
706 auto csg_obj = std::make_unique<CSG::CSGBase>();
709 std::vector<std::vector<std::string>> region_names(
_region_ids.size());
714 region_names[i][j] =
"rgmb_region_" + std::to_string(
_region_ids[i][j]);
717 std::vector<Real> axial_plane_levels;
718 std::vector<std::string> axial_plane_names;
719 Real top_axial_level = 0.;
723 for (
const auto i : make_range(axial_boundaries.size()))
725 top_axial_level += axial_boundaries[i];
728 if (i != axial_boundaries.size() - 1)
730 axial_plane_levels.push_back(top_axial_level);
737 std::unique_ptr<CSG::DuctedPinEngUnit> pin_ptr =
738 std::make_unique<CSG::DuctedPinEngUnit>(
name() +
"_ducted_pin_unit",
745 auto & pin_unit = csg_obj->addEngUnit(std::move(pin_ptr));
748 const auto unit_name =
_name +
"_radial_boundary";
750 std::unique_ptr<CSG::CSGNPolygonUnit> radial_boundary_ptr =
751 std::make_unique<CSG::CSGNPolygonUnit>(unit_name, n_sides,
_pitch / 2.);
752 auto & radial_boundary_unit = csg_obj->addEngUnit(std::move(radial_boundary_ptr));
753 auto pin_region = -radial_boundary_unit;
757 std::unique_ptr<CSG::CSGSurface> bottom_surf_ptr =
758 std::make_unique<CSG::CSGPlane>(bottom_surf_name, 0, 0, 1, 0.);
759 const auto & bottom_plane_surf = csg_obj->addSurface(std::move(bottom_surf_ptr));
762 std::unique_ptr<CSG::CSGSurface> top_surf_ptr =
763 std::make_unique<CSG::CSGPlane>(top_surf_name, 0, 0, 1, top_axial_level);
764 const auto & top_plane_surf = csg_obj->addSurface(std::move(top_surf_ptr));
766 auto axial_region = +bottom_plane_surf & -top_plane_surf;
767 pin_region &= axial_region;
772 csg_obj->createCell(
_name +
"_root_cell", pin_unit, pin_region);
775 csg_obj->expandAllEngUnits();
registerMooseObject("ReactorApp", PinMeshGenerator)
void ErrorVector unsigned int
InputParameters getValidParams(const std::string &name) const
void addMeshSubgenerator(const std::string &type, const std::string &name, Ts... extra_input_parameters)
std::unique_ptr< MeshBase > & getMeshByName(const MeshGeneratorName &mesh_generator_name)
static void setHasGenerateCSG(InputParameters ¶ms)
T & setMeshProperty(const std::string &data_name, Args &&... args)
T & declareMeshProperty(const std::string &data_name, Args &&... args)
const InputParameters & parameters() const
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
const std::string & _name
bool isParamValid(const std::string &name) const
Mesh generator for defining a reactor pin with background and duct regions, with the option to be 2-D...
std::vector< unsigned int > _intervals
The number of mesh intervals in a radial division starting from the center.
const std::vector< Real > _duct_halfpitch
The inner apothem of any surrounding ducts in the pin.
std::unique_ptr< MeshBase > generate() override
bool _homogenized
Whether the resulting pin mesh should be homogenized.
PinMeshGenerator(const InputParameters ¶meters)
unsigned int _mesh_dimensions
The number of dimensions the mesh is ultimately going to have (2 or 3, declared in the ReactorMeshPar...
static InputParameters validParams()
std::unique_ptr< CSG::CSGBase > generateCSG() override
void generateFlexibleAssemblyBoundaries()
const unsigned int _num_sectors
The number of azimuthal divisions.
std::vector< Real > _ring_radii
The outer radii of concentric rings in the pin.
bool _quad_center
Whether the centermost elements in the pin should be quad elements as opposed to tri elements.
std::unique_ptr< MeshBase > * _build_mesh
The final mesh that is generated by the subgenerators; This mesh is generated by the subgenerators wi...
const bool _extrude
Whether this mesh should be extruded to 3-D, making it the final structure in the reactor mesh.
bool _has_block_names
Whether block names have been provided by user.
std::vector< std::vector< subdomain_id_type > > _region_ids
2-D vector (axial outer indexing, radial inner indexing) used to set "region_id" extra-element intege...
const Real _pitch
The face-to-face size of this pin.
std::vector< std::vector< std::string > > _block_names
2-D vector (axial outer indexing, radial inner indexing) used to set block names of pin mesh elements
std::string _mesh_geometry
The type of geometry that is being described (Square or Hex, declared in the ReactorMeshParams object...
const subdomain_id_type _pin_type
The id number for this pin type.
bool _is_assembly
Whether the resulting pin mesh should also be used as an assembly mesh.
A base class that contains common members for Reactor Geometry Mesh Builder mesh generators.
const T & getReactorParam(const std::string ¶m_name)
Returns reference of parameter in ReactorMeshParams object.
void initializeReactorMeshParams(const std::string reactor_param_name)
Initializes and checks validity of ReactorMeshParams mesh generator object.
MeshGeneratorName callExtrusionMeshSubgenerators(const MeshGeneratorName input_mesh_name)
Calls mesh subgenerators related to extrusion, renaming of top / bottom boundaries,...
void freeReactorParamsMesh()
Releases the mesh obtained in _reactor_params_mesh.
static InputParameters validParams()
void updateElementBlockNameId(MeshBase &input_mesh, Elem *elem, std::map< std::string, SubdomainID > &name_id_map, std::string elem_block_name, SubdomainID &next_free_id)
Updates the block names and ids of the element in an input mesh according to a map of block name to b...
void freeReactorParamsCSG()
Releases the CSG base object obtained in _reactor_params_csg.
unsigned int getElemIntegerFromMesh(MeshBase &input_mesh, std::string extra_int_name, bool should_exist=false)
Initializes extra element integer from id name for a given mesh and throws an error if it should exis...
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
static const std::string bottom_boundary_id
static const std::string is_single_pin
const SubdomainName ASSEMBLY_BLOCK_NAME_PREFIX
static const std::string pin_region_id_map
const BoundaryName PIN_BOUNDARY_NAME_PREFIX
const subdomain_id_type PIN_BLOCK_ID_TRI_FLEXIBLE
static const std::string expand_units
static const std::string is_control_drum
static const std::string bypass_meshgen
const subdomain_id_type PIN_BLOCK_ID_START
static const std::string ring_radii
static const std::string top_boundary_id
const subdomain_id_type PIN_BLOCK_ID_TRI
static const std::string assembly_type
static const std::string pin_block_name_map
static const std::string duct_block_names
static const std::string duct_halfpitches
const SubdomainName TRI_BLOCK_NAME_SUFFIX
const BoundaryName ASSEMBLY_BOUNDARY_NAME_PREFIX
static const std::string assembly_pitch
static const std::string mesh_dimensions
static const std::string duct_region_ids
static const std::string pin_region_ids
static const std::string extruded
static constexpr boundary_id_type PIN_BOUNDARY_ID_START
static const std::string num_sectors_flexible_stitching
static const std::string background_region_id
static const std::string ring_region_ids
static const std::string flexible_assembly_stitching
static const std::string is_homogenized
static const std::string axial_mesh_sizes
static const std::string CSG_AXIAL_PLANE_PREFIX
static const std::string region_id_as_block_name
static const std::string background_block_name
static const std::string axial_mesh_intervals
static const std::string pitch
static const std::string pin_block_names
static const std::string mesh_geometry
static const std::string pin_type
const SubdomainName PIN_BLOCK_NAME_PREFIX