15 #include "libmesh/elem.h" 24 params.addRequiredParam<std::vector<MeshGeneratorName>>(
26 "The AssemblyMeshGenerator and ControlDrumMeshGenerator objects that form the components of " 29 params.addParam<std::string>(
30 "dummy_assembly_name",
32 "The place holder name in \"inputs\" that indicates an empty position.");
34 params.addRequiredParam<std::vector<std::vector<unsigned int>>>(
36 "A double-indexed array starting with the upper-left corner where the index" 37 "represents the layout of input assemblies in the core lattice.");
38 params.addParam<
bool>(
39 "mesh_periphery",
false,
"Determines if the core periphery should be meshed.");
40 MooseEnum periphery_mesher(
"triangle quad_ring",
"triangle");
41 params.addParam<
MooseEnum>(
"periphery_generator",
43 "The meshgenerator to use when meshing the core boundary.");
46 params.addRangeCheckedParam<
Real>(
47 "outer_circle_radius", 0,
"outer_circle_radius>=0",
"Radius of outer circle boundary.");
48 params.addRangeCheckedParam<
unsigned int>(
49 "outer_circle_num_segments",
51 "outer_circle_num_segments>=0",
52 "Number of radial segments to subdivide outer circle boundary.");
53 params.addRangeCheckedParam<
unsigned int>(
54 "periphery_num_layers",
56 "periphery_num_layers>0",
57 "Number of layers to subdivide the periphery boundary.");
58 params.addParam<std::string>(
61 "periphery_region_id",
63 "ID for periphery zone for assignment of region_id extra element id.");
64 params.addRangeCheckedParam<
Real>(
68 "Desired (maximum) triangle area, or 0 to skip uniform refinement");
69 params.addParam<std::string>(
72 "Desired (local) triangle area as a function of x,y; omit to skip non-uniform refinement");
73 params.addParam<
bool>(
"assign_control_drum_id",
75 "Whether control drum id is assigned to the mesh as an extra integer.");
76 params.addParamNamesToGroup(
"periphery_block_name periphery_region_id outer_circle_radius " 77 "mesh_periphery periphery_generator",
79 params.addParamNamesToGroup(
"outer_circle_num_segments desired_area desired_area_func",
80 "Periphery Meshing: PTMG specific");
81 params.addParamNamesToGroup(
"periphery_num_layers",
"Periphery Meshing: PRMG specific");
84 params.addParam<
bool>(
"extrude",
86 "Determines if this is the final step in the geometry construction" 87 " and extrudes the 2D geometry to 3D. If this is true then this mesh " 88 "cannot be used in further mesh building in the Reactor workflow");
90 params.addClassDescription(
91 "This CoreMeshGenerator object is designed to generate a core-like " 92 "structure, with IDs, from a reactor geometry. " 93 "The core-like structure consists of a pattern of assembly-like " 94 "structures generated with AssemblyMeshGenerator and/or ControlDrumMeshGenerator " 95 "and is permitted to have \"empty\" locations. The size and spacing " 96 "of the assembly-like structures is defined, and " 97 "enforced by declaration in the ReactorMeshParams.");
106 _inputs(getParam<
std::vector<MeshGeneratorName>>(
"inputs")),
107 _empty_key(getParam<
std::string>(
"dummy_assembly_name")),
108 _pattern(getParam<
std::vector<
std::vector<unsigned
int>>>(
"pattern")),
109 _extrude(getParam<bool>(
"extrude")),
110 _mesh_periphery(getParam<bool>(
"mesh_periphery")),
111 _periphery_meshgenerator(getParam<
MooseEnum>(
"periphery_generator")),
113 _outer_circle_radius(getParam<
Real>(
"outer_circle_radius")),
114 _outer_circle_num_segments(getParam<unsigned
int>(
"outer_circle_num_segments")),
115 _periphery_block_name(getParam<
std::string>(
"periphery_block_name")),
116 _periphery_num_layers(getParam<unsigned
int>(
"periphery_num_layers")),
117 _desired_area(getParam<
Real>(
"desired_area")),
118 _desired_area_func(getParam<
std::string>(
"desired_area_func"))
133 "Outer circle radius must be specified when using periphery meshing.");
138 "Periphery region id must be specified when using periphery meshing.");
146 "outer_circle_num_segments cannot be used with PRMG periphery mesher.");
151 "extra_circle_radii cannot be used with PRMG periphery mesher.");
156 "extra_circle_num_segments cannot be used with PRMG periphery mesher.");
165 "periphery_num_layers cannot be used with PTMG periphery mesher.");
170 "Provided periphery meshgenerator has not been implemented.");
173 MeshGeneratorName first_nondummy_assembly =
"";
174 MeshGeneratorName reactor_params =
"";
175 bool assembly_homogenization =
false;
176 bool pin_as_assembly =
false;
177 std::map<subdomain_id_type, std::string> global_pin_map_type_to_name;
178 std::map<subdomain_id_type, std::string> assembly_map_type_to_name;
188 if (first_nondummy_assembly ==
"")
190 first_nondummy_assembly = MeshGeneratorName(
_inputs[i]);
197 mooseError(
"The name of all reactor_params objects should be identical across all pins in " 198 "the input assemblies.\n");
201 mooseError(
"In order to stitch heterogeneous assemblies with homogeneous assemblies in " 202 "CoreMeshGenerator, ReactorMeshParams/flexible_assembly_stitching should be set " 207 if (assembly_map_type_to_name.find(
assembly_type) != assembly_map_type_to_name.end() &&
210 "Constituent assemblies have shared assembly_type ids but different names. Each uniquely " 211 "defined assembly in AssemblyMeshGenerator must have its own assembly_type id.");
219 for (
const auto & input_pin_name :
pin_names)
222 if (global_pin_map_type_to_name.find(
pin_type) != global_pin_map_type_to_name.end() &&
223 global_pin_map_type_to_name[
pin_type] != input_pin_name)
225 "Constituent pins within assemblies have shared pin_type ids but different names. " 226 "Each uniquely defined pin in AssemblyMeshGenerator must have its own pin_type id.");
227 global_pin_map_type_to_name[
pin_type] = input_pin_name;
233 if (first_nondummy_assembly ==
"")
234 paramError(
"inputs",
"At least one non-dummy assembly must be defined in input assembly names");
244 "In order to extrude this mesh, ReactorMeshParams/dim needs to be set to 3\n");
247 mooseError(
"Both top_boundary_id and bottom_boundary_id must be provided in ReactorMeshParams " 248 "if using extruded geometry");
250 mooseError(
"radial_boundary_id must be provided in ReactorMeshParams for CoreMeshGenerators");
255 "If ReactorMeshParams/region_id_as_block_name is set, periphery_block_name should " 256 "not be specified in CoreMeshGenerator");
258 std::size_t empty_pattern_loc = 0;
259 bool make_empty =
false;
266 mooseError(
"Assemblies that have already been extruded cannot be used in CoreMeshGenerator " 292 mooseWarning(
"Constituent assemblies do not share the same number of nodes at the outer " 293 "boundary. In order to ensure that output mesh does not having hanging nodes, a " 294 "flexible stitching approach should be used by setting " 295 "ReactorMeshParams/flexible_assembly_stitching = true.");
307 if (assembly_homogenization)
312 params.set<std::vector<subdomain_id_type>>(
"block_id") = {
319 const auto adaptive_mg_name =
320 _geom_type ==
"Hex" ?
"HexagonConcentricCircleAdaptiveBoundaryMeshGenerator" 321 :
"CartesianConcentricCircleAdaptiveBoundaryMeshGenerator";
328 params.set<std::vector<unsigned int>>(
"num_sectors_per_side") =
329 std::vector<unsigned int>(6, 2);
334 params.set<std::vector<unsigned int>>(
"num_sectors_per_side") =
335 std::vector<unsigned int>(4, 2);
337 params.set<std::vector<unsigned int>>(
"sides_to_adapt") = std::vector<unsigned int>{0};
338 params.set<std::vector<MeshGeneratorName>>(
"meshes_to_adapt_to") =
339 std::vector<MeshGeneratorName>{first_nondummy_assembly};
340 params.set<std::vector<subdomain_id_type>>(
"background_block_ids") =
348 const auto patterned_mg_name =
349 _geom_type ==
"Hex" ?
"PatternedHexMeshGenerator" :
"PatternedCartesianMeshGenerator";
352 params.
set<std::vector<std::string>>(
"id_name") = {
"assembly_id"};
353 params.set<std::vector<MooseEnum>>(
"assign_type") = {
355 params.set<std::vector<MeshGeneratorName>>(
"inputs") =
_inputs;
356 params.set<std::vector<std::vector<unsigned int>>>(
"pattern") =
_pattern;
357 params.set<
MooseEnum>(
"pattern_boundary") =
"none";
358 params.set<
bool>(
"generate_core_metadata") = !pin_as_assembly;
359 params.set<
bool>(
"create_outward_interface_boundaries") =
false;
360 params.set<
bool>(
"assign_control_drum_id") = getParam<bool>(
"assign_control_drum_id");
363 params.set<std::vector<MeshGeneratorName>>(
"exclude_id") =
370 params.set<
double>(
"rotate_angle") = 0.0;
371 params.set<
bool>(
"allow_unused_inputs") =
true;
380 params.
set<std::vector<SubdomainName>>(
"block") = {
382 params.set<MeshGeneratorName>(
"input") =
name() +
"_pattern";
388 std::string build_mesh_name;
394 std::vector<BoundaryName> boundaries_to_delete = {};
395 for (
const auto & pattern_x :
_pattern)
397 for (
const auto & pattern_idx : pattern_x)
399 const auto assembly_name =
_inputs[pattern_idx];
402 const auto assembly_id =
404 const BoundaryName boundary_name =
406 if (!std::count(boundaries_to_delete.begin(), boundaries_to_delete.end(), boundary_name))
407 boundaries_to_delete.push_back(boundary_name);
412 params.
set<MeshGeneratorName>(
"input") =
414 params.set<std::vector<BoundaryName>>(
"boundary_names") = boundaries_to_delete;
416 build_mesh_name =
name() +
"_delbds";
431 std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>>(
436 pin->first, pin->second));
439 getMeshProperty<std::map<subdomain_id_type, std::vector<std::vector<std::string>>>>(
452 std::vector<subdomain_id_type> background_region_ids =
465 std::vector<std::string> background_block_names =
472 background_block_names));
501 ?
"PeripheralTriangleMeshGenerator" 502 :
"PeripheralRingMeshGenerator";
506 params.
set<MeshGeneratorName>(
"input") =
name() +
"_delbds";
508 params.set<BoundaryName>(
"external_boundary_name") =
"outside_periphery";
526 build_mesh_name =
name() +
"_periphery";
555 std::vector<std::vector<int>> assembly_name_lattice;
556 std::vector<std::string> input_assembly_names;
557 std::vector<std::string> input_pin_names;
562 const auto input_assembly_name =
_inputs[i];
565 input_assembly_names.push_back(input_assembly_name);
570 getMeshProperty<std::vector<std::string>>(
RGMB::pin_names, input_assembly_name);
572 if (std::find(input_pin_names.begin(), input_pin_names.end(), pin_name) ==
573 input_pin_names.end())
574 input_pin_names.push_back(pin_name);
582 std::vector<int> assembly_name_idx(
_pattern[i].size());
588 assembly_name_idx[
j] = -1;
592 const auto it = std::find(
593 input_assembly_names.begin(), input_assembly_names.end(), input_assembly_name);
594 assembly_name_idx[
j] = it - input_assembly_names.begin();
597 assembly_name_lattice.push_back(assembly_name_idx);
609 MeshGeneratorName first_nondummy_assembly =
"";
610 bool assembly_homogenization =
false;
611 unsigned int n_constituent_pins = 0;
612 unsigned int n_pin_sectors = 0;
629 unsigned int total_pins = 0;
630 unsigned int pin_sectors_per_side = 0;
633 const auto first_pin_name =
635 pin_sectors_per_side = getMeshProperty<std::vector<unsigned int>>(
"num_sectors_per_side_meta",
636 first_pin_name +
"_2D")[0];
648 pin_sectors_per_side = 0;
654 pin_sectors_per_side = getMeshProperty<std::vector<unsigned int>>(
655 "num_sectors_per_side_meta",
_inputs[i] +
"_2D")[0];
659 if (first_nondummy_assembly ==
"")
661 first_nondummy_assembly = MeshGeneratorName(
_inputs[i]);
663 n_constituent_pins = total_pins;
664 n_pin_sectors = pin_sectors_per_side;
670 mooseWarning(
"Detected mix of homogenized and heterogeneous assemblies between " +
671 first_nondummy_assembly +
" and " +
_inputs[i]);
674 if (total_pins != n_constituent_pins)
677 "Detected assemblies with different number of total constituent pins between " +
678 first_nondummy_assembly +
" and " +
_inputs[i]);
681 if (pin_sectors_per_side != n_pin_sectors)
684 " differ in terms of number of sectors per side");
692 std::unique_ptr<MeshBase>
703 auto null_mesh =
nullptr;
712 std::string pin_type_id_name =
"pin_type_id";
713 std::string assembly_type_id_name =
"assembly_type_id";
714 std::string plane_id_name =
"plane_id";
715 std::string region_id_name =
"region_id";
716 std::string radial_id_name =
"radial_id";
723 unsigned int plane_id_int = 0;
729 std::map<std::string, SubdomainID> rgmb_name_id_map;
733 for (
auto & elem : (*_build_mesh)->active_element_ptr_range())
736 dof_id_type pin_type_id = elem->get_extra_integer(pin_type_id_int);
741 const dof_id_type radial_idx = elem->get_extra_integer(radial_id_int);
743 elem->set_extra_integer(region_id_int, elem_rid);
747 auto elem_block_name = default_block_name;
751 elem_block_name +=
"_REG" + std::to_string(elem_rid);
752 if (elem->type() ==
TRI3 || elem->type() ==
PRISM6)
755 *(*
_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
757 else if ((*_build_mesh)->subdomain_name(elem->subdomain_id()) ==
767 if (elem->type() ==
TRI3 || elem->type() ==
PRISM6)
770 *(*
_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
774 dof_id_type assembly_type_id = elem->get_extra_integer(assembly_type_id_int);
785 elem->set_extra_integer(region_id_int, elem_rid);
788 auto elem_block_name = default_block_name;
790 elem_block_name +=
"_REG" + std::to_string(elem_rid);
794 if (has_drum_block_name)
797 if (elem->type() ==
TRI3 || elem->type() ==
PRISM6)
800 *(*
_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
807 bool is_background_region = peripheral_idx == 0;
808 const auto elem_rid =
809 (is_background_region
812 elem->set_extra_integer(region_id_int, elem_rid);
815 auto elem_block_name = default_block_name;
817 elem_block_name +=
"_REG" + std::to_string(elem_rid);
820 if (is_background_region)
823 if (has_background_block_name)
829 if (has_duct_block_names)
834 if (elem->type() ==
TRI3 || elem->type() ==
PRISM6)
837 *(*
_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
845 BoundaryInfo & boundary_info = (*_build_mesh)->get_boundary_info();
849 const auto sideset_map = boundary_info.get_sideset_map();
851 for (
const auto & [elem, id_pair] : sideset_map)
853 const auto side_id = id_pair.first;
854 const auto sideset_id = id_pair.second;
857 if (sideset_id == source_id)
859 auto mm_it = sideset_map.equal_range(elem);
862 for (
auto it = mm_it.first; it != mm_it.second; it++)
864 if (it->second.first ==
side_id && it->second.second == target_id)
869 boundary_info.add_side(elem,
side_id, target_id);
873 if (getParam<bool>(
"generate_depletion_id"))
875 const MooseEnum option = getParam<MooseEnum>(
"depletion_id_type");
880 (*_build_mesh)->set_isnt_prepared();
std::unique_ptr< MeshBase > & getMeshByName(const MeshGeneratorName &mesh_generator_name)
static void addDepletionIDParams(InputParameters ¶meters)
static InputParameters validParams()
const bool _mesh_periphery
Whether the core periphery should be meshed.
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...
static const std::string duct_block_names
static const std::string background_region_id
static const std::string assembly_type
static const std::string region_id_as_block_name
std::map< subdomain_id_type, std::vector< std::vector< subdomain_id_type > > > _duct_region_id_map
A mapping from assembly-type IDs to region IDs in the assembly duct regions used when assigning regio...
static const std::string assembly_lattice
const SubdomainName PERIPHERAL_RING_BLOCK_NAME
static const std::string is_single_pin
Mesh generator for defining a reactor core using a Cartesian or hexagonal lattice with the option to ...
static const std::string peripheral_ring_radius
const subdomain_id_type DUMMY_ASSEMBLY_BLOCK_ID
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...
const boundary_id_type side_id
static const std::string reactor_params_name
static const std::string mesh_geometry
void initializeReactorMeshParams(const std::string reactor_param_name)
Initializes and checks validity of ReactorMeshParams mesh generator object.
InputParameters getValidParams(const std::string &name) const
static const std::string assembly_names
static const std::string background_block_name
void addDepletionId(MeshBase &input_mesh, const MooseEnum &option, const DepletionIDGenerationLevel generation_level, const bool extrude)
add depletion IDs
static const std::string peripheral_ring_region_id
static const std::string assembly_pitch
static const std::string radial_boundary_id
static const std::string pin_type
const Real _outer_circle_radius
outer circle boundary radius
static InputParameters validParams()
const SubdomainName TRI_BLOCK_NAME_SUFFIX
virtual const std::string & name() const
void mooseWarning(Args &&... args) const
bool _empty_pos
Whether empty positions are to be used in the pattern.
std::string _desired_area_func
Desired (local) triangle area as a function of (x,y)
static const std::string drum_block_names
const std::vector< MeshGeneratorName > _inputs
The names of the assemblies that compose the core.
static const std::string pin_region_id_map
std::map< subdomain_id_type, std::vector< subdomain_id_type > > _background_region_id_map
A mapping from assembly-type IDs to region IDs in the assembly background regions used when assigning...
static const std::string extruded
const subdomain_id_type PERIPHERAL_RING_BLOCK_ID
const bool _extrude
Whether this mesh should be extruded to 3-D, the core is always assumed to be the last...
const MooseEnum _periphery_meshgenerator
Which periphery meshgenerator to use.
std::map< subdomain_id_type, std::vector< std::vector< std::string > > > _pin_block_name_map
A mapping from pin-type IDs to block names used when assigning block names during the assembly stitch...
static const std::string mesh_dimensions
const unsigned int _outer_circle_num_segments
Number of segments in the outer circle boundary.
void addMeshSubgenerator(const std::string &type, const std::string &name, Ts... extra_input_parameters)
MeshGeneratorName callExtrusionMeshSubgenerators(const MeshGeneratorName input_mesh_name)
Calls mesh subgenerators related to extrusion, renaming of top / bottom boundaries, and defining plane IDs.
registerMooseObject("ReactorApp", CoreMeshGenerator)
const unsigned int _periphery_num_layers
Number of periphery layers.
std::string _geom_type
The geometry type for the reactor that is stored on the ReactorMeshParams object. ...
const SubdomainName CORE_BLOCK_NAME_PREFIX
bool constituentAssembliesNeedFlexibleStiching()
static const std::string top_boundary_id
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
std::vector< std::unique_ptr< MeshBase > *> getMeshes(const std::string ¶m_name)
void paramError(const std::string ¶m, Args... args) const
std::map< subdomain_id_type, std::vector< std::vector< subdomain_id_type > > > _pin_region_id_map
A mapping from pin-type IDs to region IDs used when assigning region IDs during the assembly stitchin...
std::map< subdomain_id_type, std::vector< std::vector< std::string > > > _duct_block_name_map
A mapping from assembly-type IDs to block names in the assembly duct regions used when assigning bloc...
static const std::string is_homogenized
static const std::string is_control_drum
std::map< subdomain_id_type, std::vector< std::string > > _background_block_name_map
A mapping from assembly-type IDs to block names in the assembly background regions used when assignin...
static const std::string flexible_assembly_stitching
static const std::string pin_lattice
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const BoundaryName CORE_BOUNDARY_NAME
std::unique_ptr< MeshBase > generate() override
const std::string _periphery_block_name
The subdomain name for the generated mesh outer boundary.
const MeshGeneratorName _empty_key
The name of "filler" assembly given in the input to represent an empty space in the core pattern...
A base class that contains common members for Reactor Geometry Mesh Builder mesh generators.
const BoundaryName ASSEMBLY_BOUNDARY_NAME_PREFIX
void mooseError(Args &&... args) const
void freeReactorMeshParams()
Releases the mesh obtained in _reactor_params_mesh.
const Real _desired_area
Desired (maximum) triangle area.
const InputParameters & parameters() const
T & declareMeshProperty(const std::string &data_name, Args &&... args)
static const std::string drum_region_ids
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
const subdomain_id_type _periphery_region_id
"region_id" extra-element integer of the periphery mesh elements
static const std::string bypass_meshgen
static const std::string pin_names
std::map< subdomain_id_type, std::vector< std::vector< subdomain_id_type > > > _drum_region_id_map
A mapping from assembly-type IDs to region IDs in the drum regions used when assigning region IDs dur...
void declareMeshesForSub(const std::string ¶m_name)
void declareNullMeshName(const MeshGeneratorName &name)
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
std::unique_ptr< MeshBase > * _build_mesh
The final mesh that is generated by the subgenerators; This mesh is generated by the subgenerators wi...
const std::vector< std::vector< unsigned int > > _pattern
The 2D assembly layout of the core.
CoreMeshGenerator(const InputParameters ¶meters)
static const std::string duct_region_ids
void ErrorVector unsigned int
const subdomain_id_type MAX_PIN_TYPE_ID
auto index_range(const T &sizable)
std::map< subdomain_id_type, std::vector< std::vector< std::string > > > _drum_block_name_map
A mapping from assembly-type IDs to block names in the drum regions used when assigning block names d...
static const std::string bottom_boundary_id
static const std::string pin_block_name_map
unsigned int _mesh_dimensions
The number of dimensions the mesh is ultimately going to have (2 or 3, declared in the ReactorMeshPar...