https://mooseframework.inl.gov
PinMeshGenerator.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "PinMeshGenerator.h"
11 
13 #include <cmath>
14 #include "MooseApp.h"
15 #include "MooseMeshUtils.h"
16 #include "Factory.h"
17 #include "libmesh/elem.h"
18 
20 
23 {
25 
26  params.addRequiredParam<MeshGeneratorName>(
27  "reactor_params",
28  "The ReactorMeshParams MeshGenerator that is the basis for this component conformal mesh.");
29 
30  params.addRequiredParam<subdomain_id_type>("pin_type",
31  "The integer ID for this pin type definition");
32 
33  params.addRequiredRangeCheckedParam<Real>(
34  "pitch", "pitch>0.0", "The pitch for the outermost boundary polygon");
35 
36  params.addRangeCheckedParam<unsigned int>(
37  "num_sectors", "num_sectors>0", "Number of azimuthal sectors in each quadrant");
38 
39  params.addRangeCheckedParam<std::vector<Real>>(
40  "ring_radii",
41  "ring_radii>0.0",
42  "Radii of major concentric circles of the pin. If unspecified, no pin is present.");
43 
44  params.addRangeCheckedParam<std::vector<Real>>(
45  "duct_halfpitch",
46  "duct_halfpitch>0.0",
47  "Apothem of the ducts. If unspecified, no duct is present.");
48 
49  params.addRangeCheckedParam<std::vector<unsigned int>>(
50  "mesh_intervals",
51  std::vector<unsigned int>{1},
52  "mesh_intervals>0",
53  "The number of meshing intervals for each region starting at the center. Parameter should be "
54  "size:"
55  "((length(ring_radii) + length(duct_halfpitch) + 1");
56 
57  params.addParam<std::vector<std::vector<std::string>>>(
58  "block_names",
59  "Block names for each radial and axial zone. "
60  "Inner indexing is radial zones (pin/background/duct), outer indexing is axial");
61 
62  params.addParam<std::vector<std::vector<subdomain_id_type>>>(
63  "region_ids",
64  "IDs for each radial and axial zone for assignment of region_id extra element "
65  "id. "
66  "Inner indexing is radial zones (pin/background/duct), outer indexing is axial");
67 
68  params.addParam<bool>("extrude",
69  false,
70  "Determines if this is the final step in the geometry construction"
71  " and extrudes the 2D geometry to 3D. If this is true then this mesh "
72  "cannot be used in further mesh building in the Reactor workflow");
73  params.addParam<bool>(
74  "homogenized", false, "Determines whether homogenized pin mesh should be generated");
75  params.addParam<bool>(
76  "use_as_assembly", false, "Determines whether pin mesh should be used as an assembly mesh");
77 
78  params.addParam<bool>(
79  "quad_center_elements", true, "Whether the center elements are quad or triangular.");
80  params.addParamNamesToGroup("region_ids pin_type", "ID assigment");
81  params.addParamNamesToGroup(
82  "mesh_intervals ring_radii num_sectors pin_type homogenized use_as_assembly",
83  "Pin specifications");
84  params.addParamNamesToGroup("mesh_intervals duct_halfpitch num_sectors", "Duct specifications");
85 
86  params.addClassDescription("This PinMeshGenerator object is designed to generate pin-like "
87  "structures, with IDs, from a reactor geometry. "
88  "Whether it be a square or hexagonal pin, they are divided into three "
89  "substructures - the innermost "
90  "radial pin regions, the single bridging background region, and the "
91  "square or hexagonal ducts regions.");
92 
93  return params;
94 }
95 
97  : ReactorGeometryMeshBuilderBase(parameters),
98  _pin_type(getParam<subdomain_id_type>("pin_type")),
99  _pitch(getParam<Real>("pitch")),
100  _num_sectors(isParamValid("num_sectors") ? getParam<unsigned int>("num_sectors") : 0),
101  _ring_radii(isParamValid("ring_radii") ? getParam<std::vector<Real>>("ring_radii")
102  : std::vector<Real>()),
103  _duct_halfpitch(isParamValid("duct_halfpitch") ? getParam<std::vector<Real>>("duct_halfpitch")
104  : std::vector<Real>()),
105  _intervals(getParam<std::vector<unsigned int>>("mesh_intervals")),
106  _region_ids(isParamValid("region_ids")
107  ? getParam<std::vector<std::vector<subdomain_id_type>>>("region_ids")
108  : std::vector<std::vector<subdomain_id_type>>()),
109  _extrude(getParam<bool>("extrude")),
110  _quad_center(getParam<bool>("quad_center_elements")),
111  _homogenized(getParam<bool>("homogenized")),
112  _is_assembly(getParam<bool>("use_as_assembly"))
113 {
114  // Initialize ReactorMeshParams object
115  initializeReactorMeshParams(getParam<MeshGeneratorName>("reactor_params"));
116 
117  _mesh_dimensions = getReactorParam<unsigned int>(RGMB::mesh_dimensions);
118  _mesh_geometry = getReactorParam<std::string>(RGMB::mesh_geometry);
119 
120  if (_is_assembly)
121  {
122  auto assembly_pitch = getReactorParam<Real>(RGMB::assembly_pitch);
123  if (assembly_pitch != _pitch)
124  mooseError("Pitch defined in PinMeshGenerator must match assembly_pitch defined in "
125  "ReactorMeshParams if use_as_assembly is set to true");
126  }
127 
128  if (_extrude && _mesh_dimensions != 3)
129  paramError("extrude",
130  "In order to extrude this mesh, ReactorMeshParams/dim needs to be set to 3\n");
131  if (_extrude && (!hasReactorParam<boundary_id_type>(RGMB::top_boundary_id) ||
132  !hasReactorParam<boundary_id_type>(RGMB::bottom_boundary_id)))
133  mooseError("Both top_boundary_id and bottom_boundary_id must be provided in ReactorMeshParams "
134  "if using extruded geometry");
135 
136  if (_homogenized)
137  {
138  if (_mesh_geometry == "Square")
139  mooseError("Homogenization in PinMeshGenerator is only supported for hexagonal geometries");
140  const std::vector<std::string> disallowed_parameters = {
141  "num_sectors", "ring_radii", "duct_halfpitch", "mesh_intervals"};
142  for (const auto & parameter : disallowed_parameters)
143  if (parameters.isParamSetByUser(parameter))
144  paramError(parameter,
145  "Parameter " + parameter + " should not be defined for a homogenized pin mesh");
146  }
147  else
148  {
149  if (_num_sectors == 0)
150  mooseError(
151  "Number of sectors must be assigned with parameter num_sectors for non-homogenized pins");
152  if (_intervals.size() != (_ring_radii.size() + _duct_halfpitch.size() + 1))
153  mooseError(
154  "The number of mesh intervals must be equal to the number of annular regions + the "
155  "number of duct regions + 1"
156  " for the region between the rings and ducts\n");
157  }
158 
159  if (isParamValid("region_ids"))
160  {
161  unsigned int n_axial_levels =
162  (_mesh_dimensions == 3)
163  ? getReactorParam<std::vector<unsigned int>>(RGMB::axial_mesh_intervals).size()
164  : 1;
165  if (_region_ids.size() != n_axial_levels)
166  mooseError("The size of region IDs must be equal to the number of axial levels as defined in "
167  "the ReactorMeshParams object");
168  if (_region_ids[0].size() != (_ring_radii.size() + _duct_halfpitch.size() + 1))
169  mooseError("The number of region IDs given needs to be one more than the number of "
170  "ring_radii + the number of duct_radii\n");
171  }
172  else
173  {
174  mooseError("Region IDs must be assigned with parameter region_ids");
175  }
176  if (isParamValid("block_names"))
177  {
178  if (getReactorParam<bool>(RGMB::region_id_as_block_name))
179  paramError("block_names",
180  "If ReactorMeshParams/region_id_as_block_name is set, block_names should not be "
181  "specified in PinMeshGenerator");
182  _has_block_names = true;
183  _block_names = getParam<std::vector<std::vector<std::string>>>("block_names");
184  if (_region_ids.size() != _block_names.size())
185  mooseError("The size of block_names must match the size of region_ids");
186  for (const auto i : index_range(_region_ids))
187  if (_region_ids[i].size() != _block_names[i].size())
188  mooseError("The size of block_names must match the size of region_ids");
189  }
190  else
191  _has_block_names = false;
192 
193  const auto use_flexible_stitching = getReactorParam<bool>(RGMB::flexible_assembly_stitching);
194  std::string build_mesh_name;
195 
196  // No subgenerators will be called if option to bypass mesh generators is enabled
197  if (!getReactorParam<bool>(RGMB::bypass_meshgen))
198  {
199  if (_homogenized)
200  {
201  // If flexible assembly stitching is invoked and this is a homogeneous assembly mesh, do not
202  // call mesh subgenerators here. The homogeneous assembly mesh should be created entirely in
203  // generateFlexibleAssemblyBoundaries()
204  bool skip_assembly_generation = _is_assembly && use_flexible_stitching;
205 
206  auto params = _app.getFactory().getValidParams("SimpleHexagonGenerator");
207 
208  params.set<Real>("hexagon_size") = _pitch / 2.0;
209  params.set<boundary_id_type>("external_boundary_id") =
211  const auto boundary_name =
213  std::to_string(_pin_type);
214  params.set<BoundaryName>("external_boundary_name") = boundary_name;
215  params.set<std::vector<subdomain_id_type>>("block_id") = {
217  params.set<MooseEnum>("element_type") = _quad_center ? "QUAD" : "TRI";
218  auto block_name = RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R0";
219  if (!_quad_center)
220  block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
221  params.set<std::vector<SubdomainName>>("block_name") = {block_name};
222 
223  if (!skip_assembly_generation)
224  {
225  build_mesh_name = name() + "_2D";
226  addMeshSubgenerator("SimpleHexagonGenerator", build_mesh_name, params);
227  }
228  }
229  else
230  {
231  // Define all id variables used in the pin
232  std::vector<unsigned int> ring_intervals;
233  std::vector<subdomain_id_type> ring_blk_ids;
234  std::vector<SubdomainName> ring_blk_names;
235  unsigned int background_intervals = 1;
236  std::vector<subdomain_id_type> background_blk_ids;
237  std::vector<SubdomainName> background_blk_names;
238  std::vector<unsigned int> duct_intervals;
239  std::vector<subdomain_id_type> duct_blk_ids;
240  std::vector<SubdomainName> duct_blk_names;
241 
242  for (const auto i : index_range(_intervals))
243  {
244  const auto block_name =
245  RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R" + std::to_string(i);
246  const auto block_id = RGMB::PIN_BLOCK_ID_START + i;
247 
248  if (i < _ring_radii.size())
249  {
250  ring_intervals.push_back(_intervals[i]);
251  ring_blk_ids.push_back(block_id);
252  ring_blk_names.push_back(block_name);
253  }
254  else if (i > _ring_radii.size())
255  {
256  duct_intervals.push_back(_intervals[i]);
257  duct_blk_ids.push_back(block_id);
258  duct_blk_names.push_back(block_name);
259  }
260  else
261  {
262  background_intervals = _intervals[i];
263  background_blk_ids.push_back(block_id);
264  background_blk_names.push_back(block_name);
265  }
266  }
267  if (ring_intervals.size() > 0)
268  {
269  if (ring_intervals.front() != 1)
270  {
271  // If quad center elements, copy element at beginning of block names and
272  // block ids. Otherwise add RGMB::TRI_BLOCK_NAME_SUFFIX to block names and generate new
273  // block id
274  if (_quad_center)
275  {
276  ring_blk_ids.insert(ring_blk_ids.begin(), ring_blk_ids.front());
277  ring_blk_names.insert(ring_blk_names.begin(), ring_blk_names.front());
278  }
279  else
280  {
281  const auto block_name = ring_blk_names.front() + RGMB::TRI_BLOCK_NAME_SUFFIX;
282  const auto block_id = RGMB::PIN_BLOCK_ID_TRI;
283  ring_blk_ids.insert(ring_blk_ids.begin(), block_id);
284  ring_blk_names.insert(ring_blk_names.begin(), block_name);
285  }
286  }
287  // Add RGMB::TRI_BLOCK_NAME_SUFFIX if only one radial region and tri center elements
288  else if (!_quad_center)
289  {
290  ring_blk_ids[0] = RGMB::PIN_BLOCK_ID_TRI;
291  ring_blk_names[0] += RGMB::TRI_BLOCK_NAME_SUFFIX;
292  }
293  }
294  else
295  {
296  if (background_intervals > 1)
297  {
298  // If quad center elements, copy element at beginning of block names and
299  // block ids. Otherwise add RGMB::TRI_BLOCK_NAME_SUFFIX to block names and generate new
300  // block id
301  if (_quad_center)
302  {
303  background_blk_ids.insert(background_blk_ids.begin(), background_blk_ids.front());
304  background_blk_names.insert(background_blk_names.begin(), background_blk_names.front());
305  }
306  else
307  {
308  const auto block_name = background_blk_names.front() + RGMB::TRI_BLOCK_NAME_SUFFIX;
309  const auto block_id = RGMB::PIN_BLOCK_ID_TRI;
310  background_blk_ids.insert(background_blk_ids.begin(), block_id);
311  background_blk_names.insert(background_blk_names.begin(), block_name);
312  }
313  }
314  // Add RGMB::TRI_BLOCK_NAME_SUFFIX if only one background region and tri center elements
315  // and no ring regions
316  else if (!_quad_center)
317  {
318  background_blk_ids[0] = RGMB::PIN_BLOCK_ID_TRI;
319  background_blk_names[0] += RGMB::TRI_BLOCK_NAME_SUFFIX;
320  }
321  }
322 
323  // If flexible assembly stitching is invoked and this is an assembly mesh with only a
324  // background region, do not call mesh subgenerators here. This assembly mesh should be
325  // created entirely in generateFlexibleAssemblyBoundaries()
326  bool skip_assembly_generation =
327  _is_assembly && use_flexible_stitching && _intervals.size() == 1;
328 
329  if (!skip_assembly_generation)
330  {
331  // Generate Cartesian/hex pin using PolygonConcentricCircleMeshGenerator
332  {
333  // Get and assign parameters for the main geometry feature of the Pin
334  // which is created with a PolygonConcentricCircleMeshGenerator subgenerator
335  auto params = _app.getFactory().getValidParams("PolygonConcentricCircleMeshGenerator");
336  params.set<bool>("preserve_volumes") = true;
337  params.set<bool>("quad_center_elements") = _quad_center;
338  params.set<MooseEnum>("polygon_size_style") = "apothem";
339  params.set<Real>("polygon_size") = _pitch / 2.0;
340  params.set<boundary_id_type>("external_boundary_id") =
342  const auto boundary_name = (_is_assembly ? RGMB::ASSEMBLY_BOUNDARY_NAME_PREFIX
344  std::to_string(_pin_type);
345  params.set<BoundaryName>("external_boundary_name") = boundary_name;
346  bool flat_side_up = (_mesh_geometry == "Square");
347  params.set<bool>("flat_side_up") = flat_side_up;
348  params.set<bool>("create_outward_interface_boundaries") = false;
349 
350  const auto num_sides = (_mesh_geometry == "Square") ? 4 : 6;
351  params.set<unsigned int>("num_sides") = num_sides;
352  params.set<std::vector<unsigned int>>("num_sectors_per_side") =
353  std::vector<unsigned int>(num_sides, _num_sectors);
354 
355  if (ring_intervals.size() > 0)
356  {
357  params.set<std::vector<Real>>("ring_radii") = _ring_radii;
358  params.set<std::vector<subdomain_id_type>>("ring_block_ids") = ring_blk_ids;
359  params.set<std::vector<SubdomainName>>("ring_block_names") = ring_blk_names;
360  params.set<std::vector<unsigned int>>("ring_intervals") = ring_intervals;
361  }
362 
363  params.set<std::vector<subdomain_id_type>>("background_block_ids") = background_blk_ids;
364  params.set<std::vector<SubdomainName>>("background_block_names") = background_blk_names;
365  params.set<unsigned int>("background_intervals") = background_intervals;
366 
367  if (duct_intervals.size() > 0)
368  {
369  params.set<MooseEnum>("duct_sizes_style") = "apothem";
370  params.set<std::vector<Real>>("duct_sizes") = _duct_halfpitch;
371  params.set<std::vector<subdomain_id_type>>("duct_block_ids") = duct_blk_ids;
372  params.set<std::vector<SubdomainName>>("duct_block_names") = duct_blk_names;
373  params.set<std::vector<unsigned int>>("duct_intervals") = duct_intervals;
374  }
375 
376  addMeshSubgenerator("PolygonConcentricCircleMeshGenerator", name() + "_2D", params);
377  }
378 
379  // Remove extra sidesets created by PolygonConcentricCircleMeshGenerator
380  {
381  auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
382 
383  params.set<MeshGeneratorName>("input") = name() + "_2D";
384 
385  auto num_sides = (_mesh_geometry == "Square") ? 4 : 6;
386  std::vector<BoundaryName> boundaries_to_delete = {};
387  for (const auto i : make_range(num_sides))
388  boundaries_to_delete.insert(boundaries_to_delete.end(),
389  {std::to_string(10001 + i), std::to_string(15001 + i)});
390  params.set<std::vector<BoundaryName>>("boundary_names") = boundaries_to_delete;
391 
392  build_mesh_name = name() + "_delbds";
393  addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params);
394  }
395  }
396  }
397 
398  // For pin acting as assembly, modify outermost mesh interval to enable flexible assembly
399  // stitching
400  if (_is_assembly && use_flexible_stitching)
401  {
403  build_mesh_name = name() + "_fpg_delbds";
404  }
405 
406  // Pass mesh meta-data defined in subgenerator constructor to this MeshGenerator
407  if (hasMeshProperty<Real>("pitch_meta", name() + "_2D"))
408  copyMeshProperty<Real>("pitch_meta", name() + "_2D");
409  if (hasMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta", name() + "_2D"))
410  copyMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta", name() + "_2D");
411  if (hasMeshProperty<Real>("max_radius_meta", name() + "_2D"))
412  copyMeshProperty<Real>("max_radius_meta", name() + "_2D");
413  if (hasMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D"))
414  copyMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D");
415  if (hasMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D"))
416  copyMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D");
417 
418  if (_is_assembly)
419  declareMeshProperty("pattern_pitch_meta", getReactorParam<Real>(RGMB::assembly_pitch));
420  else if (hasMeshProperty<Real>("pattern_pitch_meta", name() + "_2D"))
421  copyMeshProperty<Real>("pattern_pitch_meta", name() + "_2D");
422  declareMeshProperty("is_control_drum_meta", false);
423 
424  if (_extrude && _mesh_dimensions == 3)
425  build_mesh_name = callExtrusionMeshSubgenerators(build_mesh_name);
426 
427  // Store final mesh subgenerator
428  _build_mesh = &getMeshByName(build_mesh_name);
429  }
430 
432 }
433 
434 void
436 {
437  SubdomainName outermost_block_name;
438  bool has_single_mesh_interval;
439 
440  // Assemblies that invoke this method are either homogenized or have a single pin. First check if
441  // the assembly only has a single region. Otherwise, determine the outermost region for deletion
442  if (_homogenized || (_intervals.size() == 1))
443  {
444  outermost_block_name = RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R0";
445  has_single_mesh_interval = true;
446  }
447  else
448  {
449  outermost_block_name = RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R" +
450  std::to_string(_intervals.size() - 1);
451  has_single_mesh_interval = false;
452 
453  // Invoke BlockDeletionGenerator to delete outermost mesh interval of assembly
454  auto params = _app.getFactory().getValidParams("BlockDeletionGenerator");
455 
456  params.set<std::vector<SubdomainName>>("block") = {outermost_block_name};
457  params.set<MeshGeneratorName>("input") = _homogenized ? name() + "_2D" : name() + "_delbds";
458 
459  addMeshSubgenerator("BlockDeletionGenerator", name() + "_del_outer", params);
460  }
461 
462  {
463  // Invoke FlexiblePatternGenerator to triangulate deleted mesh interval
464  auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator");
465 
466  if (has_single_mesh_interval)
467  params.set<std::vector<MeshGeneratorName>>("inputs") = {};
468  else
469  {
470  params.set<std::vector<MeshGeneratorName>>("inputs") = {name() + "_del_outer"};
471  params.set<std::vector<libMesh::Point>>("extra_positions") = {libMesh::Point(0, 0, 0)};
472  params.set<std::vector<unsigned int>>("extra_positions_mg_indices") = {0};
473  }
474  params.set<bool>("use_auto_area_func") = true;
475  params.set<bool>("verify_holes") = false;
476  params.set<MooseEnum>("boundary_type") = (_mesh_geometry == "Hex") ? "HEXAGON" : "CARTESIAN";
477  params.set<unsigned int>("boundary_sectors") =
478  getReactorParam<unsigned int>(RGMB::num_sectors_flexible_stitching);
479  params.set<Real>("boundary_size") = getReactorParam<Real>(RGMB::assembly_pitch);
480  params.set<boundary_id_type>("external_boundary_id") = RGMB::PIN_BOUNDARY_ID_START + _pin_type;
481  params.set<BoundaryName>("external_boundary_name") =
483  params.set<SubdomainName>("background_subdomain_name") =
484  outermost_block_name + RGMB::TRI_BLOCK_NAME_SUFFIX;
485  params.set<unsigned short>("background_subdomain_id") = RGMB::PIN_BLOCK_ID_TRI_FLEXIBLE;
486 
487  addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params);
488  }
489  {
490  // Delete extra boundary created by FlexiblePatternGenerator
491  auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
492 
493  params.set<MeshGeneratorName>("input") = name() + "_fpg";
494  std::vector<BoundaryName> boundaries_to_delete = {};
495  if (!has_single_mesh_interval)
496  boundaries_to_delete.push_back(std::to_string(1));
497  params.set<std::vector<BoundaryName>>("boundary_names") = boundaries_to_delete;
498 
499  addMeshSubgenerator("BoundaryDeletionGenerator", name() + "_fpg_delbds", params);
500  }
501 }
502 
503 void
505 {
506  // Store pin region ids and block names for id swap after extrusion if needed
507  // by future mesh generators
508  std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>> region_id_map{
510 
511  // Declare mesh properties that need to be moved up to the assembly level
512  if (_is_assembly)
513  {
515  declareMeshProperty(RGMB::background_block_name, std::vector<std::string>());
516  declareMeshProperty(RGMB::duct_block_names, std::vector<std::vector<std::string>>());
519  // Following metadata is only relevant if an output mesh is generated by RGMB
520  // because it pertains to region & block ids of elements in the output mesh
521  if (!getReactorParam<bool>(RGMB::bypass_meshgen))
522  {
523  std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>> pin_region_id_map;
524  pin_region_id_map.insert(
525  std::pair<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>(
526  region_id_map.begin()->first, region_id_map.begin()->second));
528  std::map<subdomain_id_type, std::vector<std::vector<std::string>>> pin_block_name_map;
529  pin_block_name_map.insert(std::pair<subdomain_id_type, std::vector<std::vector<std::string>>>(
532  }
533  }
534  // Declare mesh properties that are only relevant to pin meshes
535  else
536  {
540  }
541 
542  // Set metadata to describe pin attributes
548 
549  unsigned int n_axial_levels =
550  (_mesh_dimensions == 3)
551  ? getReactorParam<std::vector<unsigned int>>(RGMB::axial_mesh_intervals).size()
552  : 1;
553  std::vector<std::vector<subdomain_id_type>> ring_region_ids(
554  n_axial_levels, std::vector<subdomain_id_type>(_ring_radii.size()));
555  std::vector<std::vector<subdomain_id_type>> duct_region_ids(
556  n_axial_levels, std::vector<subdomain_id_type>(_duct_halfpitch.size()));
557  std::vector<subdomain_id_type> background_region_ids(n_axial_levels);
558 
559  for (const auto axial_idx : make_range(n_axial_levels))
560  {
561  for (const auto ring_idx : index_range(_ring_radii))
562  ring_region_ids[axial_idx][ring_idx] = _region_ids[axial_idx][ring_idx];
563 
564  background_region_ids[axial_idx] = _region_ids[axial_idx][_ring_radii.size()];
565 
566  for (unsigned int duct_idx = _ring_radii.size() + 1;
567  duct_idx < _duct_halfpitch.size() + _ring_radii.size() + 1;
568  ++duct_idx)
569  duct_region_ids[axial_idx][duct_idx - _ring_radii.size() - 1] =
570  _region_ids[axial_idx][duct_idx];
571  }
572 
573  // Define mesh properties related to region ids
575  declareMeshProperty(RGMB::background_region_id, background_region_ids);
577 }
578 
579 std::unique_ptr<MeshBase>
581 {
582  // Must be called to free the ReactorMeshParams mesh
584 
585  // If bypass_mesh is true, return a null mesh. In this mode, an output mesh is not
586  // generated and only metadata is defined on the generator, so logic related to
587  // generation of output mesh will not be called
588  if (getReactorParam<bool>(RGMB::bypass_meshgen))
589  {
590  auto null_mesh = nullptr;
591  return null_mesh;
592  }
593 
594  // Update metadata at this point since values for these metadata only get set by PCCMG
595  // at generate() stage
596  if (hasMeshProperty<Real>("max_radius_meta", name() + "_2D"))
597  {
598  const auto max_radius_meta = getMeshProperty<Real>("max_radius_meta", name() + "_2D");
599  setMeshProperty("max_radius_meta", max_radius_meta);
600  }
601  if (hasMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D"))
602  {
603  const auto background_intervals_meta =
604  getMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D");
605  setMeshProperty("background_intervals_meta", background_intervals_meta);
606  }
607  if (hasMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D"))
608  {
609  const auto node_id_background_meta =
610  getMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D");
611  setMeshProperty("node_id_background_meta", node_id_background_meta);
612  }
613 
614  // This generate() method will be called once the subgenerators that we depend on
615  // have been called. This is where we reassign subdomain ids/names according to what
616  // the user has provided, and also where we set region_id, pin_type_id, and radial_id
617  // extra element integers
618 
619  // Add region id, pin type id, and radial id to the mesh as element integers
620  std::string region_id_name = "region_id";
621  std::string pin_type_id_name = "pin_type_id";
622  std::string assembly_type_id_name = "assembly_type_id";
623  std::string plane_id_name = "plane_id";
624  std::string radial_id_name = "radial_id";
625  const std::string default_block_name =
627  std::to_string(_pin_type);
628 
629  auto region_id_int = getElemIntegerFromMesh(*(*_build_mesh), region_id_name);
630  auto radial_id_int = getElemIntegerFromMesh(*(*_build_mesh), radial_id_name);
631  auto pin_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), pin_type_id_name);
632  unsigned int plane_id_int = 0;
633  unsigned int assembly_type_id_int = 0;
634  if (_extrude)
635  plane_id_int = getElemIntegerFromMesh(*(*_build_mesh), plane_id_name, true);
636  if (_is_assembly)
637  assembly_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), assembly_type_id_name);
638 
639  // Get next free block ID in mesh in case subdomain ids need to be remapped
640  auto next_block_id = MooseMeshUtils::getNextFreeSubdomainID(*(*(_build_mesh)));
641  std::map<std::string, SubdomainID> rgmb_name_id_map;
642 
643  // Loop through all elements and set regions ids, pin type id, and radial idx.
644  // These element integers are also used to infer the block name for the region,
645  // and block IDs/names will be reassigned on the pin mesh if necessary
646  for (auto & elem : (*_build_mesh)->active_element_ptr_range())
647  {
648  const auto base_block_id = elem->subdomain_id();
649  const auto base_block_name = (*_build_mesh)->subdomain_name(base_block_id);
650 
651  // Check if block name has correct prefix
652  std::string prefix = RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R";
653  if (!(base_block_name.find(prefix, 0) == 0))
654  continue;
655  // Radial index is integer value of substring after prefix
656  std::string radial_str = base_block_name.substr(prefix.length());
657 
658  // Filter out RGMB::TRI_BLOCK_NAME_SUFFIX if needed
659  const std::string suffix = RGMB::TRI_BLOCK_NAME_SUFFIX;
660  const std::size_t found = radial_str.find(suffix);
661  if (found != std::string::npos)
662  radial_str.replace(found, suffix.length(), "");
663  const unsigned int radial_idx = std::stoi(radial_str);
664 
665  // Region id is inferred from z_id and radial_idx
666  dof_id_type z_id = _extrude ? elem->get_extra_integer(plane_id_int) : 0;
667  const subdomain_id_type elem_region_id = _region_ids[std::size_t(z_id)][radial_idx];
668 
669  // Set element integers
670  elem->set_extra_integer(region_id_int, elem_region_id);
671  elem->set_extra_integer(pin_type_id_int, _pin_type);
672  elem->set_extra_integer(radial_id_int, radial_idx);
673  if (_is_assembly)
674  elem->set_extra_integer(assembly_type_id_int, _pin_type);
675 
676  // Set element block name and block id
677  auto elem_block_name = default_block_name;
678  if (_has_block_names)
679  elem_block_name += "_" + _block_names[std::size_t(z_id)][radial_idx];
680  else if (getReactorParam<bool>(RGMB::region_id_as_block_name))
681  elem_block_name += "_REG" + std::to_string(elem_region_id);
682  if (elem->type() == TRI3 || elem->type() == PRISM6)
683  elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
685  *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
686  }
687 
688  // Mark mesh as not prepared, as block IDs were re-assigned in this method
689  (*_build_mesh)->set_isnt_prepared();
690 
691  return std::move(*_build_mesh);
692 }
std::unique_ptr< MeshBase > & getMeshByName(const MeshGeneratorName &mesh_generator_name)
const SubdomainName ASSEMBLY_BLOCK_NAME_PREFIX
const subdomain_id_type _pin_type
The id number for this pin type.
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
T & setMeshProperty(const std::string &data_name, Args &&... args)
static const std::string assembly_type
PinMeshGenerator(const InputParameters &parameters)
static const std::string region_id_as_block_name
unsigned int _mesh_dimensions
The number of dimensions the mesh is ultimately going to have (2 or 3, declared in the ReactorMeshPar...
static const std::string is_single_pin
void generateFlexibleAssemblyBoundaries()
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...
T & set(const std::string &name, bool quiet_mode=false)
const subdomain_id_type PIN_BLOCK_ID_START
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
Mesh generator for defining a reactor pin with background and duct regions, with the option to be 2-D...
static const std::string background_block_name
static const std::string assembly_pitch
bool _homogenized
Whether the resulting pin mesh should be homogenized.
std::vector< unsigned int > _intervals
The number of mesh intervals in a radial division starting from the center.
static const std::string pin_type
registerMooseObject("ReactorApp", PinMeshGenerator)
const SubdomainName TRI_BLOCK_NAME_SUFFIX
bool _quad_center
Whether the centermost elements in the pin should be quad elements as opposed to tri elements...
virtual const std::string & name() const
Factory & getFactory()
TRI3
bool _has_block_names
Whether block names have been provided by user.
static const std::string pin_region_id_map
const BoundaryName PIN_BOUNDARY_NAME_PREFIX
bool isParamValid(const std::string &name) const
static const std::string extruded
const T & getReactorParam(const std::string &param_name)
Returns reference of parameter in ReactorMeshParams object.
static const std::string duct_halfpitches
int8_t boundary_id_type
static const std::string mesh_dimensions
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.
static InputParameters validParams()
static const std::string pitch
static constexpr boundary_id_type PIN_BOUNDARY_ID_START
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...
const unsigned int _num_sectors
The number of azimuthal divisions.
const SubdomainName PIN_BLOCK_NAME_PREFIX
static const std::string top_boundary_id
void paramError(const std::string &param, Args... args) const
const bool _extrude
Whether this mesh should be extruded to 3-D, making it the final structure in the reactor mesh...
std::unique_ptr< MeshBase > generate() override
static const std::string is_homogenized
std::vector< Real > _ring_radii
The outer radii of concentric rings in the pin.
static const std::string is_control_drum
bool isParamSetByUser(const std::string &name) const
static const std::string pin_region_ids
static const std::string flexible_assembly_stitching
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real _pitch
The face-to-face size of this pin.
static const std::string ring_radii
MooseApp & _app
const subdomain_id_type PIN_BLOCK_ID_TRI_FLEXIBLE
static const std::string pin_block_names
const subdomain_id_type PIN_BLOCK_ID_TRI
static const std::string axial_mesh_intervals
IntRange< T > make_range(T beg, T end)
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 InputParameters & parameters() const
T & declareMeshProperty(const std::string &data_name, Args &&... args)
std::string _mesh_geometry
The type of geometry that is being described (Square or Hex, declared in the ReactorMeshParams object...
static const std::string bypass_meshgen
bool _is_assembly
Whether the resulting pin mesh should also be used as an assembly mesh.
PRISM6
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
T & copyMeshProperty(const std::string &target_data_name, const std::string &source_data_name, const std::string &source_mesh)
static const std::string num_sectors_flexible_stitching
bool hasMeshProperty(const std::string &data_name, const std::string &prefix) const
static const std::string duct_region_ids
void ErrorVector unsigned int
auto index_range(const T &sizable)
static const std::string bottom_boundary_id
std::unique_ptr< MeshBase > * _build_mesh
The final mesh that is generated by the subgenerators; This mesh is generated by the subgenerators wi...
static const std::string pin_block_name_map
const std::vector< Real > _duct_halfpitch
The inner apothem of any surrounding ducts in the pin.
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...
static const std::string ring_region_ids
uint8_t dof_id_type