https://mooseframework.inl.gov
CoreMeshGenerator.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 "CoreMeshGenerator.h"
11 
12 #include "MooseApp.h"
13 #include "MooseMeshUtils.h"
14 #include "Factory.h"
15 #include "libmesh/elem.h"
16 #include "CSGZCylinder.h"
17 
19 
22 {
24 
25  params.addRequiredParam<std::vector<MeshGeneratorName>>(
26  "inputs",
27  "The AssemblyMeshGenerator and ControlDrumMeshGenerator objects that form the components of "
28  "the assembly.");
29 
30  params.addParam<std::string>(
31  "dummy_assembly_name",
32  "dummy",
33  "The place holder name in \"inputs\" that indicates an empty position.");
34 
35  params.addRequiredParam<std::vector<std::vector<unsigned int>>>(
36  "pattern",
37  "A double-indexed array starting with the upper-left corner where the index"
38  "represents the layout of input assemblies in the core lattice.");
39  params.addParam<bool>(
40  "mesh_periphery", false, "Determines if the core periphery should be meshed.");
41  MooseEnum periphery_mesher("triangle quad_ring", "triangle");
42  params.addParam<MooseEnum>("periphery_generator",
43  periphery_mesher,
44  "The meshgenerator to use when meshing the core boundary.");
45 
46  // Periphery meshing interface
47  params.addRangeCheckedParam<Real>(
48  "outer_circle_radius", 0, "outer_circle_radius>=0", "Radius of outer circle boundary.");
49  params.addRangeCheckedParam<unsigned int>(
50  "outer_circle_num_segments",
51  0,
52  "outer_circle_num_segments>=0",
53  "Number of radial segments to subdivide outer circle boundary.");
54  params.addRangeCheckedParam<unsigned int>(
55  "periphery_num_layers",
56  1,
57  "periphery_num_layers>0",
58  "Number of layers to subdivide the periphery boundary.");
59  params.addParam<std::string>(
60  "periphery_block_name", RGMB::CORE_BLOCK_NAME_PREFIX, "Block name for periphery zone.");
61  params.addParam<subdomain_id_type>(
62  "periphery_region_id",
63  -1,
64  "ID for periphery zone for assignment of region_id extra element id.");
65  params.addRangeCheckedParam<Real>(
66  "desired_area",
67  0,
68  "desired_area>=0",
69  "Desired (maximum) triangle area, or 0 to skip uniform refinement");
70  params.addParam<std::string>(
71  "desired_area_func",
72  std::string(),
73  "Desired (local) triangle area as a function of x,y; omit to skip non-uniform refinement");
74  params.addParam<bool>("assign_control_drum_id",
75  true,
76  "Whether control drum id is assigned to the mesh as an extra integer.");
77  params.addParamNamesToGroup("periphery_block_name periphery_region_id outer_circle_radius "
78  "mesh_periphery periphery_generator",
79  "Periphery Meshing");
80  params.addParamNamesToGroup("outer_circle_num_segments desired_area desired_area_func",
81  "Periphery Meshing: PTMG specific");
82  params.addParamNamesToGroup("periphery_num_layers", "Periphery Meshing: PRMG specific");
83  // end meshing interface
84 
85  params.addParam<bool>("extrude",
86  false,
87  "Determines if this is the final step in the geometry construction"
88  " and extrudes the 2D geometry to 3D. If this is true then this mesh "
89  "cannot be used in further mesh building in the Reactor workflow");
90 
91  params.addClassDescription(
92  "This CoreMeshGenerator object is designed to generate a core-like "
93  "structure, with IDs, from a reactor geometry. "
94  "The core-like structure consists of a pattern of assembly-like "
95  "structures generated with AssemblyMeshGenerator and/or ControlDrumMeshGenerator "
96  "and is permitted to have \"empty\" locations. The size and spacing "
97  "of the assembly-like structures is defined, and "
98  "enforced by declaration in the ReactorMeshParams.");
99  // depletion id generation params are added
100  addDepletionIDParams(params);
101 
102  // Declare that this generator has a generateCSG method
104 
105  return params;
106 }
107 
109  : ReactorGeometryMeshBuilderBase(parameters),
110  _inputs(getParam<std::vector<MeshGeneratorName>>("inputs")),
111  _empty_key(getParam<std::string>("dummy_assembly_name")),
112  _pattern(getParam<std::vector<std::vector<unsigned int>>>("pattern")),
113  _extrude(getParam<bool>("extrude")),
114  _mesh_periphery(getParam<bool>("mesh_periphery")),
115  _periphery_meshgenerator(getParam<MooseEnum>("periphery_generator")),
116  _periphery_region_id(getParam<subdomain_id_type>("periphery_region_id")),
117  _outer_circle_radius(getParam<Real>("outer_circle_radius")),
118  _outer_circle_num_segments(getParam<unsigned int>("outer_circle_num_segments")),
119  _periphery_block_name(getParam<std::string>("periphery_block_name")),
120  _periphery_num_layers(getParam<unsigned int>("periphery_num_layers")),
121  _desired_area(getParam<Real>("desired_area")),
122  _desired_area_func(getParam<std::string>("desired_area_func"))
123 {
124  // This sets it so that any mesh that is input with the name _empty_key is considered a "null"
125  // mesh, that is, whenever we try to get it with the standard getMesh() API we get a nullptr
126  // mesh instead. In the specific case of the CoreMeshGenerator, we use said "null" mesh to
127  // represent an empty position
129 
130  // periphery meshing input checking
131  if (_mesh_periphery)
132  {
133  // missing required input
134  if (!parameters.isParamSetByUser("outer_circle_radius"))
135  {
136  paramError("outer_circle_radius",
137  "Outer circle radius must be specified when using periphery meshing.");
138  }
139  if (!parameters.isParamSetByUser("periphery_region_id"))
140  {
141  paramError("periphery_region_id",
142  "Periphery region id must be specified when using periphery meshing.");
143  }
144  // using PTMG-specific options with PRMG
145  if (_periphery_meshgenerator == "quad_ring")
146  {
147  if (parameters.isParamSetByUser("outer_circle_num_segments"))
148  {
149  paramError("outer_circle_num_segments",
150  "outer_circle_num_segments cannot be used with PRMG periphery mesher.");
151  }
152  if (parameters.isParamSetByUser("extra_circle_radii"))
153  {
154  paramError("extra_circle_radii",
155  "extra_circle_radii cannot be used with PRMG periphery mesher.");
156  }
157  if (parameters.isParamSetByUser("extra_circle_num_segments"))
158  {
159  paramError("extra_circle_num_segments",
160  "extra_circle_num_segments cannot be used with PRMG periphery mesher.");
161  }
162  }
163  // using PRMG-specific options with PTMG
164  else if (_periphery_meshgenerator == "triangle")
165  {
166  if (parameters.isParamSetByUser("periphery_num_layers"))
167  {
168  paramError("periphery_num_layers",
169  "periphery_num_layers cannot be used with PTMG periphery mesher.");
170  }
171  }
172  else
173  paramError("periphery_generator",
174  "Provided periphery meshgenerator has not been implemented.");
175  }
176 
177  MeshGeneratorName first_nondummy_assembly = "";
178  MeshGeneratorName reactor_params = "";
179  bool assembly_homogenization = false;
180  bool pin_as_assembly = false;
181  std::map<subdomain_id_type, std::string> global_pin_map_type_to_name;
182  std::map<subdomain_id_type, std::string> assembly_map_type_to_name;
183  // Check that MG name for reactor params and assembly homogenization schemes are
184  // consistent across all assemblies, and there is no overlap in pin_type / assembly_type ids
185  for (const auto i : index_range(_inputs))
186  {
187  // Skip if assembly name is equal to dummy assembly name
188  if (_inputs[i] == _empty_key)
189  continue;
190 
191  // Save properties of first non-dummy assembly to compare to other assemblies
192  if (first_nondummy_assembly == "")
193  {
194  first_nondummy_assembly = MeshGeneratorName(_inputs[i]);
195  reactor_params =
196  MeshGeneratorName(getMeshProperty<std::string>(RGMB::reactor_params_name, _inputs[i]));
197  assembly_homogenization = getMeshProperty<bool>(RGMB::is_homogenized, _inputs[i]);
198  pin_as_assembly = getMeshProperty<bool>(RGMB::is_single_pin, _inputs[i]);
199  }
200  if (getMeshProperty<std::string>(RGMB::reactor_params_name, _inputs[i]) != reactor_params)
201  mooseError("The name of all reactor_params objects should be identical across all pins in "
202  "the input assemblies.\n");
203  if ((getMeshProperty<bool>(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization) &&
204  !getMeshProperty<bool>(RGMB::flexible_assembly_stitching, reactor_params))
205  mooseError("In order to stitch heterogeneous assemblies with homogeneous assemblies in "
206  "CoreMeshGenerator, ReactorMeshParams/flexible_assembly_stitching should be set "
207  "to true\n");
208 
209  // Check assembly_types across constituent assemblies are uniquely defined
210  const auto assembly_type = getMeshProperty<subdomain_id_type>(RGMB::assembly_type, _inputs[i]);
211  if (assembly_map_type_to_name.find(assembly_type) != assembly_map_type_to_name.end() &&
212  assembly_map_type_to_name[assembly_type] != _inputs[i])
213  mooseError(
214  "Constituent assemblies have shared assembly_type ids but different names. Each uniquely "
215  "defined assembly in AssemblyMeshGenerator must have its own assembly_type id.");
216  assembly_map_type_to_name[assembly_type] = _inputs[i];
217 
218  // If assembly is composed of pins, check pin_types across all constituent assemblies are
219  // uniquely defined
220  if (hasMeshProperty<std::vector<std::string>>(RGMB::pin_names, _inputs[i]))
221  {
222  const auto pin_names = getMeshProperty<std::vector<std::string>>(RGMB::pin_names, _inputs[i]);
223  for (const auto & input_pin_name : pin_names)
224  {
225  const auto pin_type = getMeshProperty<subdomain_id_type>(RGMB::pin_type, input_pin_name);
226  if (global_pin_map_type_to_name.find(pin_type) != global_pin_map_type_to_name.end() &&
227  global_pin_map_type_to_name[pin_type] != input_pin_name)
228  mooseError(
229  "Constituent pins within assemblies have shared pin_type ids but different names. "
230  "Each uniquely defined pin in AssemblyMeshGenerator must have its own pin_type id.");
231  global_pin_map_type_to_name[pin_type] = input_pin_name;
232  }
233  }
234  }
235 
236  // Check that there is at least one non-dummy assemby defined in lattice
237  if (first_nondummy_assembly == "")
238  paramError("inputs", "At least one non-dummy assembly must be defined in input assembly names");
239 
240  // Initialize ReactorMeshParams object stored in pin input
241  initializeReactorMeshParams(reactor_params);
242 
243  _geom_type = getReactorParam<std::string>(RGMB::mesh_geometry);
244  _mesh_dimensions = getReactorParam<unsigned int>(RGMB::mesh_dimensions);
245 
246  if (_extrude && _mesh_dimensions != 3)
247  paramError("extrude",
248  "In order to extrude this mesh, ReactorMeshParams/dim needs to be set to 3\n");
249  if (_extrude && (!hasReactorParam<boundary_id_type>(RGMB::top_boundary_id) ||
250  !hasReactorParam<boundary_id_type>(RGMB::bottom_boundary_id)))
251  mooseError("Both top_boundary_id and bottom_boundary_id must be provided in ReactorMeshParams "
252  "if using extruded geometry");
253  if (!hasReactorParam<boundary_id_type>(RGMB::radial_boundary_id))
254  mooseError("radial_boundary_id must be provided in ReactorMeshParams for CoreMeshGenerators");
255 
256  if (parameters.isParamSetByUser("periphery_block_name") &&
257  getReactorParam<bool>(RGMB::region_id_as_block_name))
258  paramError("periphery_block_name",
259  "If ReactorMeshParams/region_id_as_block_name is set, periphery_block_name should "
260  "not be specified in CoreMeshGenerator");
261 
262  std::size_t empty_pattern_loc = 0;
263  bool make_empty = false;
264  for (auto assembly : _inputs)
265  {
266  if (assembly != _empty_key)
267  {
268  ++empty_pattern_loc;
269  if (getMeshProperty<bool>(RGMB::extruded, assembly))
270  mooseError("Assemblies that have already been extruded cannot be used in CoreMeshGenerator "
271  "definition.\n");
272  }
273  else
274  {
275  // Found dummy assembly in input assembly names
276  make_empty = true;
277  for (const auto i : index_range(_pattern))
278  {
279  for (const auto j : index_range(_pattern[i]))
280  {
281  // Found dummy assembly in input lattice definition
282  if (_pattern[i][j] == empty_pattern_loc)
283  _empty_pos = true;
284  }
285  }
286  }
287  }
288 
289  // No subgenerators will be called if option to bypass mesh generators is enabled
290  if (!getReactorParam<bool>(RGMB::bypass_meshgen))
291  {
292  // Check whether flexible stitching should be used for constituent assemblies and throw a
293  // warning if flexible stitching option is not enabled
294  if (!getReactorParam<bool>(RGMB::flexible_assembly_stitching) &&
296  mooseWarning("Constituent assemblies do not share the same number of nodes at the outer "
297  "boundary. In order to ensure that output mesh does not having hanging nodes, a "
298  "flexible stitching approach should be used by setting "
299  "ReactorMeshParams/flexible_assembly_stitching = true.");
300 
301  // Declare that all of the meshes in the "inputs" parameter are to be used by
302  // a sub mesh generator.
303  declareMeshesForSub("inputs");
304 
305  // Stitch assemblies into a hexagonal / Cartesian core lattice
306  {
307  // create a dummy assembly that is a renamed version of one of the inputs
308  if (make_empty)
309  {
310  {
311  if (assembly_homogenization)
312  {
313  auto params = _app.getFactory().getValidParams("SimpleHexagonGenerator");
314 
315  params.set<Real>("hexagon_size") = getReactorParam<Real>(RGMB::assembly_pitch) / 2.0;
316  params.set<std::vector<subdomain_id_type>>("block_id") = {
318 
319  addMeshSubgenerator("SimpleHexagonGenerator", std::string(_empty_key), params);
320  }
321  else
322  {
323  const auto adaptive_mg_name =
324  _geom_type == "Hex" ? "HexagonConcentricCircleAdaptiveBoundaryMeshGenerator"
325  : "CartesianConcentricCircleAdaptiveBoundaryMeshGenerator";
326  auto params = _app.getFactory().getValidParams(adaptive_mg_name);
327 
328  const auto assembly_pitch = getReactorParam<Real>(RGMB::assembly_pitch);
329  if (_geom_type == "Hex")
330  {
331  params.set<Real>("hexagon_size") = assembly_pitch / 2.0;
332  params.set<std::vector<unsigned int>>("num_sectors_per_side") =
333  std::vector<unsigned int>(6, 2);
334  }
335  else
336  {
337  params.set<Real>("square_size") = assembly_pitch;
338  params.set<std::vector<unsigned int>>("num_sectors_per_side") =
339  std::vector<unsigned int>(4, 2);
340  }
341  params.set<std::vector<unsigned int>>("sides_to_adapt") = std::vector<unsigned int>{0};
342  params.set<std::vector<MeshGeneratorName>>("meshes_to_adapt_to") =
343  std::vector<MeshGeneratorName>{first_nondummy_assembly};
344  params.set<std::vector<subdomain_id_type>>("background_block_ids") =
345  std::vector<subdomain_id_type>{RGMB::DUMMY_ASSEMBLY_BLOCK_ID};
346 
347  addMeshSubgenerator(adaptive_mg_name, std::string(_empty_key), params);
348  }
349  }
350  }
351  {
352  const auto patterned_mg_name =
353  _geom_type == "Hex" ? "PatternedHexMeshGenerator" : "PatternedCartesianMeshGenerator";
354  auto params = _app.getFactory().getValidParams(patterned_mg_name);
355 
356  params.set<std::vector<std::string>>("id_name") = {"assembly_id"};
357  params.set<std::vector<MooseEnum>>("assign_type") = {
358  MooseEnum("cell", "cell")}; // give elems IDs relative to position in assembly
359  params.set<std::vector<MeshGeneratorName>>("inputs") = _inputs;
360  params.set<std::vector<std::vector<unsigned int>>>("pattern") = _pattern;
361  params.set<MooseEnum>("pattern_boundary") = "none";
362  params.set<bool>("generate_core_metadata") = !pin_as_assembly;
363  params.set<bool>("create_outward_interface_boundaries") = false;
364  params.set<bool>("assign_control_drum_id") = getParam<bool>("assign_control_drum_id");
365  if (make_empty)
366  {
367  params.set<std::vector<MeshGeneratorName>>("exclude_id") =
368  std::vector<MeshGeneratorName>{_empty_key};
369  }
370 
371  const auto radial_boundary = getReactorParam<boundary_id_type>(RGMB::radial_boundary_id);
372  params.set<boundary_id_type>("external_boundary_id") = radial_boundary;
373  params.set<BoundaryName>("external_boundary_name") = RGMB::CORE_BOUNDARY_NAME;
374  params.set<double>("rotate_angle") = 0.0;
375  params.set<bool>("allow_unused_inputs") = true;
376 
377  addMeshSubgenerator(patterned_mg_name, name() + "_pattern", params);
378  }
379  }
380  if (_empty_pos)
381  {
382  auto params = _app.getFactory().getValidParams("BlockDeletionGenerator");
383 
384  params.set<std::vector<SubdomainName>>("block") = {
385  std::to_string(RGMB::DUMMY_ASSEMBLY_BLOCK_ID)};
386  params.set<MeshGeneratorName>("input") = name() + "_pattern";
387  params.set<BoundaryName>("new_boundary") = RGMB::CORE_BOUNDARY_NAME;
388 
389  addMeshSubgenerator("BlockDeletionGenerator", name() + "_deleted", params);
390  }
391 
392  std::string build_mesh_name;
393 
394  // Remove outer assembly sidesets created during assembly generation
395  {
396  // Get outer boundaries of all constituent assemblies based on assembly_type,
397  // skipping all dummy assemblies
398  std::vector<BoundaryName> boundaries_to_delete = {};
399  for (const auto & pattern_x : _pattern)
400  {
401  for (const auto & pattern_idx : pattern_x)
402  {
403  const auto assembly_name = _inputs[pattern_idx];
404  if (assembly_name == _empty_key)
405  continue;
406  const auto assembly_id =
407  getMeshProperty<subdomain_id_type>(RGMB::assembly_type, assembly_name);
408  const BoundaryName boundary_name =
409  RGMB::ASSEMBLY_BOUNDARY_NAME_PREFIX + std::to_string(assembly_id);
410  if (!std::count(boundaries_to_delete.begin(), boundaries_to_delete.end(), boundary_name))
411  boundaries_to_delete.push_back(boundary_name);
412  }
413  }
414  auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
415 
416  params.set<MeshGeneratorName>("input") =
417  _empty_pos ? name() + "_deleted" : name() + "_pattern";
418  params.set<std::vector<BoundaryName>>("boundary_names") = boundaries_to_delete;
419 
420  build_mesh_name = name() + "_delbds";
421  addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params);
422  }
423 
424  for (auto assembly : _inputs)
425  {
426  if (assembly != _empty_key)
427  {
429  getMeshProperty<subdomain_id_type>(RGMB::assembly_type, assembly);
430  if (!getMeshProperty<bool>(RGMB::is_control_drum, assembly))
431  {
432  // For assembly structures, store region ID and block names of assembly regions and
433  // constituent pins
434  const auto & pin_region_id_map = getMeshProperty<
435  std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>>(
436  RGMB::pin_region_id_map, assembly);
437  for (auto pin = pin_region_id_map.begin(); pin != pin_region_id_map.end(); ++pin)
438  _pin_region_id_map.insert(
439  std::pair<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>(
440  pin->first, pin->second));
441 
442  const auto & pin_block_name_map =
443  getMeshProperty<std::map<subdomain_id_type, std::vector<std::vector<std::string>>>>(
444  RGMB::pin_block_name_map, assembly);
445  for (auto pin = pin_block_name_map.begin(); pin != pin_block_name_map.end(); ++pin)
446  _pin_block_name_map.insert(
447  std::pair<subdomain_id_type, std::vector<std::vector<std::string>>>(pin->first,
448  pin->second));
449 
450  // Define background and duct region ID map from constituent assemblies
452  {
453  // Store region ids and block names associated with duct and background regions for each
454  // assembly, in case block names need to be recovered from region ids after
455  // multiple assemblies have been stitched together into a core
456  std::vector<subdomain_id_type> background_region_ids =
457  getMeshProperty<std::vector<subdomain_id_type>>(RGMB::background_region_id,
458  assembly);
459  std::vector<std::vector<subdomain_id_type>> duct_region_ids =
460  getMeshProperty<std::vector<std::vector<subdomain_id_type>>>(RGMB::duct_region_ids,
461  assembly);
463  std::pair<subdomain_id_type, std::vector<subdomain_id_type>>(
464  assembly_type, background_region_ids));
465  _duct_region_id_map.insert(
466  std::pair<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>(
468 
469  std::vector<std::string> background_block_names =
470  getMeshProperty<std::vector<std::string>>(RGMB::background_block_name, assembly);
471  std::vector<std::vector<std::string>> duct_block_names =
472  getMeshProperty<std::vector<std::vector<std::string>>>(RGMB::duct_block_names,
473  assembly);
475  std::pair<subdomain_id_type, std::vector<std::string>>(assembly_type,
476  background_block_names));
477  _duct_block_name_map.insert(
478  std::pair<subdomain_id_type, std::vector<std::vector<std::string>>>(
480  }
481  }
482  else
483  {
484  // For control drum structures, store region ID and block name information of drum regions
485  const auto & drum_region_ids =
486  getMeshProperty<std::vector<std::vector<subdomain_id_type>>>(RGMB::drum_region_ids,
487  assembly);
488  _drum_region_id_map.insert(
489  std::pair<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>(
491  std::vector<std::vector<std::string>> drum_block_names =
492  getMeshProperty<std::vector<std::vector<std::string>>>(RGMB::drum_block_names,
493  assembly);
494  _drum_block_name_map.insert(
495  std::pair<subdomain_id_type, std::vector<std::vector<std::string>>>(
497  }
498  }
499  }
500 
501  // periphery meshing
502  if (_mesh_periphery)
503  {
504  std::string periphery_mg_name = (_periphery_meshgenerator == "triangle")
505  ? "PeripheralTriangleMeshGenerator"
506  : "PeripheralRingMeshGenerator";
507 
508  // set up common options
509  auto params = _app.getFactory().getValidParams(periphery_mg_name);
510  params.set<MeshGeneratorName>("input") = name() + "_delbds";
511  params.set<Real>("peripheral_ring_radius") = _outer_circle_radius;
512  params.set<BoundaryName>("external_boundary_name") = "outside_periphery";
513  params.set<SubdomainName>("peripheral_ring_block_name") = RGMB::PERIPHERAL_RING_BLOCK_NAME;
514 
515  // unique MG options
516  if (_periphery_meshgenerator == "triangle")
517  {
518  params.set<unsigned int>("peripheral_ring_num_segments") = _outer_circle_num_segments;
519  params.set<Real>("desired_area") = _desired_area;
520  params.set<std::string>("desired_area_func") = _desired_area_func;
521  }
522  else if (_periphery_meshgenerator == "quad_ring")
523  {
524  params.set<subdomain_id_type>("peripheral_ring_block_id") = RGMB::PERIPHERAL_RING_BLOCK_ID;
525  params.set<BoundaryName>("input_mesh_external_boundary") = RGMB::CORE_BOUNDARY_NAME;
526  params.set<unsigned int>("peripheral_layer_num") = _periphery_num_layers;
527  }
528 
529  // finish periphery input
530  build_mesh_name = name() + "_periphery";
531  addMeshSubgenerator(periphery_mg_name, build_mesh_name, params);
532  }
533 
534  if (_extrude && _mesh_dimensions == 3)
535  build_mesh_name = callExtrusionMeshSubgenerators(build_mesh_name);
536 
537  // Store final mesh subgenerator
538  _build_mesh = &getMeshByName(build_mesh_name);
539  }
540  // If mesh generation should be bypassed, call getMeshes to resolve MeshGeneratorSystem
541  // dependencies
542  else
543  auto input_meshes = getMeshes("inputs");
544 
545  // If we are in CSG only mode, store the CSGBase objects associated with input MG's
547  _input_csg_bases = getCSGBases("inputs");
548 
550 }
551 
552 void
554 {
555  // Define metadata related to downstream function calls
556  if (_mesh_periphery)
557  {
560  }
561 
562  // Determine constituent pin type ids and define lattice
563  std::vector<std::vector<int>> assembly_name_lattice;
564  std::vector<std::string> input_assembly_names;
565  std::vector<std::string> input_pin_names;
566 
567  // Iterate through input assembly names and define constituent assemblies and pins
568  for (const auto i : index_range(_inputs))
569  {
570  const auto input_assembly_name = _inputs[i];
571  if (input_assembly_name != _empty_key)
572  {
573  input_assembly_names.push_back(input_assembly_name);
574  if (!getMeshProperty<bool>(RGMB::is_control_drum, input_assembly_name) &&
575  !getMeshProperty<bool>(RGMB::is_single_pin, input_assembly_name))
576  {
577  const auto pin_names =
578  getMeshProperty<std::vector<std::string>>(RGMB::pin_names, input_assembly_name);
579  for (const auto & pin_name : pin_names)
580  if (std::find(input_pin_names.begin(), input_pin_names.end(), pin_name) ==
581  input_pin_names.end())
582  input_pin_names.push_back(pin_name);
583  }
584  }
585  }
586 
587  // Iterate through pattern and remap dummy assemblies with index -1
588  for (const auto i : index_range(_pattern))
589  {
590  std::vector<int> assembly_name_idx(_pattern[i].size());
591  for (const auto j : index_range(_pattern[i]))
592  {
593  const auto input_assembly_name = _inputs[_pattern[i][j]];
594  // Use an assembly type of -1 to represent a dummy assembly
595  if (input_assembly_name == _empty_key)
596  assembly_name_idx[j] = -1;
597  // Set index of assembly name based on `input_assembly_names` variable
598  else
599  {
600  const auto it = std::find(
601  input_assembly_names.begin(), input_assembly_names.end(), input_assembly_name);
602  assembly_name_idx[j] = it - input_assembly_names.begin();
603  }
604  }
605  assembly_name_lattice.push_back(assembly_name_idx);
606  }
607 
608  declareMeshProperty(RGMB::pin_names, input_pin_names);
609  declareMeshProperty(RGMB::assembly_names, input_assembly_names);
610  declareMeshProperty(RGMB::assembly_lattice, assembly_name_lattice);
612 }
613 
614 bool
616 {
617  MeshGeneratorName first_nondummy_assembly = "";
618  bool assembly_homogenization = false;
619  unsigned int n_constituent_pins = 0;
620  unsigned int n_pin_sectors = 0;
621 
622  // Loop through all non-dummy input assemblies. Flexible assembly stitching is needed if one of
623  // the following criteria are met:
624  // 1. The number of constituent pins within the assembly does not match with another assembly
625  // 2. The value of is_single_pin and is_homogenized metadata do not agree with another assembly
626  // 3. The number of sectors of the constituent pins of an assembly do not match with the
627  // constituent pins of another assembly
628  for (const auto i : index_range(_inputs))
629  {
630  // Skip if assembly name is equal to dummy assembly name
631  if (_inputs[i] == _empty_key)
632  continue;
633 
634  // Compute total number of constituent pins in assembly, as well as the number of sectors per
635  // side for each pin Note: number of sectors per side is defined uniformly across constituent
636  // pins of an assembly, so only first one needs to be checked
637  unsigned int total_pins = 0;
638  unsigned int pin_sectors_per_side = 0;
639  if (!getMeshProperty<bool>(RGMB::is_single_pin, _inputs[i]))
640  {
641  const auto first_pin_name =
642  getMeshProperty<std::vector<std::string>>(RGMB::pin_names, _inputs[i])[0];
643  pin_sectors_per_side = getMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta",
644  first_pin_name + "_2D")[0];
645  const auto pin_lattice =
646  getMeshProperty<std::vector<std::vector<int>>>(RGMB::pin_lattice, _inputs[i]);
647  for (const auto i : index_range(pin_lattice))
648  total_pins += pin_lattice[i].size();
649  }
650  else
651  {
652  if (getMeshProperty<bool>(RGMB::is_homogenized, _inputs[i]))
653  {
654  // Homogenized assembly
655  total_pins = 0;
656  pin_sectors_per_side = 0;
657  }
658  else
659  {
660  // Assembly with single constituent pin
661  total_pins = 1;
662  pin_sectors_per_side = getMeshProperty<std::vector<unsigned int>>(
663  "num_sectors_per_side_meta", _inputs[i] + "_2D")[0];
664  }
665  }
666 
667  if (first_nondummy_assembly == "")
668  {
669  first_nondummy_assembly = MeshGeneratorName(_inputs[i]);
670  assembly_homogenization = getMeshProperty<bool>(RGMB::is_homogenized, _inputs[i]);
671  n_constituent_pins = total_pins;
672  n_pin_sectors = pin_sectors_per_side;
673  }
674  else
675  {
676  if (getMeshProperty<bool>(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization)
677  {
678  mooseWarning("Detected mix of homogenized and heterogeneous assemblies between " +
679  first_nondummy_assembly + " and " + _inputs[i]);
680  return true;
681  }
682  if (total_pins != n_constituent_pins)
683  {
684  mooseWarning(
685  "Detected assemblies with different number of total constituent pins between " +
686  first_nondummy_assembly + " and " + _inputs[i]);
687  return true;
688  }
689  if (pin_sectors_per_side != n_pin_sectors)
690  {
691  mooseWarning("Constituent pins in " + first_nondummy_assembly + " and " + _inputs[i] +
692  " differ in terms of number of sectors per side");
693  return true;
694  }
695  }
696  }
697  return false;
698 }
699 
700 std::unique_ptr<MeshBase>
702 {
703  // Must be called to free the ReactorMeshParams mesh
705 
706  // If bypass_mesh is true, return a null mesh. In this mode, an output mesh is not
707  // generated and only metadata is defined on the generator, so logic related to
708  // generation of output mesh will not be called
709  if (getReactorParam<bool>(RGMB::bypass_meshgen))
710  {
711  auto null_mesh = nullptr;
712  return null_mesh;
713  }
714  // This generate() method will be called once the subgenerators that we depend on are
715  // called. This is where we reassign subdomain ids/names in case they were merged
716  // when stitching assemblies into the core. This is also where we set region_id extra
717  // element integers, which has not been set yet for extruded geometries
718 
719  // Define all extra element names and integers
720  std::string pin_type_id_name = "pin_type_id";
721  std::string assembly_type_id_name = "assembly_type_id";
722  std::string plane_id_name = "plane_id";
723  std::string region_id_name = "region_id";
724  std::string radial_id_name = "radial_id";
725  const std::string default_block_name = RGMB::CORE_BLOCK_NAME_PREFIX;
726 
727  auto pin_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), pin_type_id_name, true);
728  auto assembly_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), assembly_type_id_name, true);
729  auto radial_id_int = getElemIntegerFromMesh(*(*_build_mesh), radial_id_name, true);
730  auto region_id_int = getElemIntegerFromMesh(*(*_build_mesh), region_id_name, true);
731  unsigned int plane_id_int = 0;
732  if (_extrude)
733  plane_id_int = getElemIntegerFromMesh(*(*_build_mesh), plane_id_name, true);
734 
735  // Get next free block ID in mesh in case subdomain ids need to be remapped
736  auto next_block_id = MooseMeshUtils::getNextFreeSubdomainID(*(*(_build_mesh)));
737  std::map<std::string, SubdomainID> rgmb_name_id_map;
738 
739  // Loop through all mesh elements and set region ids and reassign block IDs/names
740  // if they were merged during assembly stitching
741  for (auto & elem : (*_build_mesh)->active_element_ptr_range())
742  {
743  dof_id_type z_id = _extrude ? elem->get_extra_integer(plane_id_int) : 0;
744  dof_id_type pin_type_id = elem->get_extra_integer(pin_type_id_int);
745 
746  if (_pin_region_id_map.find(pin_type_id) != _pin_region_id_map.end())
747  {
748  // Pin type element, get region ID from pin_type, z_id, and radial_idx
749  const dof_id_type radial_idx = elem->get_extra_integer(radial_id_int);
750  const auto elem_rid = _pin_region_id_map[pin_type_id][z_id][radial_idx];
751  elem->set_extra_integer(region_id_int, elem_rid);
752 
753  // Set element block name and block id
754  bool has_block_names = !_pin_block_name_map[pin_type_id].empty();
755  auto elem_block_name = default_block_name;
756  if (has_block_names)
757  elem_block_name += "_" + _pin_block_name_map[pin_type_id][z_id][radial_idx];
758  else if (getReactorParam<bool>(RGMB::region_id_as_block_name))
759  elem_block_name += "_REG" + std::to_string(elem_rid);
760  if (elem->type() == TRI3 || elem->type() == PRISM6)
761  elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
763  *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
764  }
765  else if ((*_build_mesh)->subdomain_name(elem->subdomain_id()) ==
767  // periphery type element
768  {
769  // set region ID of core periphery element
770  elem->set_extra_integer(region_id_int, _periphery_region_id);
771  // set block name and block name of core periphery element
772  auto elem_block_name = _periphery_block_name;
773  if (getReactorParam<bool>(RGMB::region_id_as_block_name))
774  elem_block_name += "_REG" + std::to_string(_periphery_region_id);
775  if (elem->type() == TRI3 || elem->type() == PRISM6)
776  elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
778  *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
779  }
780  else
781  {
782  dof_id_type assembly_type_id = elem->get_extra_integer(assembly_type_id_int);
783  // Infer peripheral index of assembly background, assembly duct, or control drum regions from
784  // pin_type_id
785  unsigned int peripheral_idx = RGMB::MAX_PIN_TYPE_ID - pin_type_id;
786 
787  // check if element is part of drum region
788  if (_drum_region_id_map.find(assembly_type_id) != _drum_region_id_map.end())
789  {
790  // Element is in a control drum region. Infer region id from assembly_type_id, z_id, and
791  // peripheral_index
792  const auto elem_rid = _drum_region_id_map[assembly_type_id][z_id][peripheral_idx];
793  elem->set_extra_integer(region_id_int, elem_rid);
794 
795  // Set element block name and block id
796  auto elem_block_name = default_block_name;
797  if (getReactorParam<bool>(RGMB::region_id_as_block_name))
798  elem_block_name += "_REG" + std::to_string(elem_rid);
799  else
800  {
801  bool has_drum_block_name = !_drum_block_name_map[assembly_type_id].empty();
802  if (has_drum_block_name)
803  elem_block_name += "_" + _drum_block_name_map[assembly_type_id][z_id][peripheral_idx];
804  }
805  if (elem->type() == TRI3 || elem->type() == PRISM6)
806  elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
808  *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
809  }
810  else
811  {
812  // Element is in an assembly duct or background region since it doesn't
813  // have an assembly type id in the drum region map. Infer region id from
814  // assembly_type_id, z_id, and peripheral_index
815  bool is_background_region = peripheral_idx == 0;
816  const auto elem_rid =
817  (is_background_region
818  ? _background_region_id_map[assembly_type_id][z_id]
819  : _duct_region_id_map[assembly_type_id][z_id][peripheral_idx - 1]);
820  elem->set_extra_integer(region_id_int, elem_rid);
821 
822  // Set element block name and block id
823  auto elem_block_name = default_block_name;
824  if (getReactorParam<bool>(RGMB::region_id_as_block_name))
825  elem_block_name += "_REG" + std::to_string(elem_rid);
826  else
827  {
828  if (is_background_region)
829  {
830  bool has_background_block_name = !_background_block_name_map[assembly_type_id].empty();
831  if (has_background_block_name)
832  elem_block_name += "_" + _background_block_name_map[assembly_type_id][z_id];
833  }
834  else
835  {
836  bool has_duct_block_names = !_duct_block_name_map[assembly_type_id].empty();
837  if (has_duct_block_names)
838  elem_block_name +=
839  "_" + _duct_block_name_map[assembly_type_id][z_id][peripheral_idx - 1];
840  }
841  }
842  if (elem->type() == TRI3 || elem->type() == PRISM6)
843  elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
845  *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
846  }
847  }
848  }
849 
850  // Sideset 10000 does not get stitched properly when BlockDeletionGenerator
851  // is used for deleting dummy assemblies. This block copies missing sides
852  // into sideset 10000 from sideset RGMB::CORE_BOUNDARY_NAME
853  BoundaryInfo & boundary_info = (*_build_mesh)->get_boundary_info();
854  boundary_id_type source_id =
856  boundary_id_type target_id = 10000;
857  const auto sideset_map = boundary_info.get_sideset_map();
858 
859  for (const auto & [elem, id_pair] : sideset_map)
860  {
861  const auto side_id = id_pair.first;
862  const auto sideset_id = id_pair.second;
863 
864  // Filter all sides that belong to RGMB::CORE_BOUNDARY_NAME sideset
865  if (sideset_id == source_id)
866  {
867  auto mm_it = sideset_map.equal_range(elem);
868  bool found = false;
869  // Check if side is defined in sideset 10000
870  for (auto it = mm_it.first; it != mm_it.second; it++)
871  {
872  if (it->second.first == side_id && it->second.second == target_id)
873  found = true;
874  }
875  // Add side if not found in sideset 10000
876  if (!found)
877  boundary_info.add_side(elem, side_id, target_id);
878  }
879  }
880 
881  if (getParam<bool>("generate_depletion_id"))
882  {
883  const MooseEnum option = getParam<MooseEnum>("depletion_id_type");
885  }
886 
887  // Mark mesh as not prepared, as block ID's were re-assigned in this method
888  (*_build_mesh)->unset_is_prepared();
889 
890  return std::move(*_build_mesh);
891 }
892 
893 std::unique_ptr<CSG::CSGBase>
895 {
896  // Must be called to free the ReactorMeshParams CSGBase object
898 
899  auto csg_obj = std::make_unique<CSG::CSGBase>();
900 
901  const auto dummy_univ_name = _empty_key + "_univ";
902  if (_empty_pos || !_mesh_periphery)
903  {
904  // Create universe with a single void cell with an empty region. This universe is used for
905  // defining dummy assemblies in the core lattice and the lattce outer universe for lattices
906  // that do not have a mesh periphery
907  const auto dummy_cell_name = _empty_key + "_cell";
908  const auto & dummy_univ = csg_obj->createUniverse(dummy_univ_name);
909  CSG::CSGRegion empty_region;
910  csg_obj->createCell(dummy_cell_name, empty_region, &dummy_univ);
911  }
912 
913  // Combine all bases from AssemblyMG inputs into this base. We expect each AssemblyMG
914  // input to contain a root universe with a single cell that constrains the assembly based
915  // on the FEM boundary. Root universes from inputs are renamed to a new universe name.
916  // These universes and their cells will be discarded, so that only the infinite assembly
917  // universes are retained.
918  std::unordered_map<unsigned int, std::string> univ_id_names;
919  std::vector<std::string> univs_to_discard;
920  for (const auto i : index_range(_inputs))
921  {
922  if (_inputs[i] == _empty_key)
923  univ_id_names[i] = dummy_univ_name;
924  else
925  {
926  const auto input_univ_name_discard = _inputs[i] + "_root_univ";
927  const auto input_univ_name = _inputs[i] + "_univ";
928  csg_obj->joinOtherBase(std::move(*_input_csg_bases[i]), true, input_univ_name_discard);
929  univs_to_discard.push_back(input_univ_name_discard);
930  univ_id_names[i] = input_univ_name;
931  }
932  }
933 
934  // Discard root universes of the input assemblies and their cells
935  for (const auto & univ_name : univs_to_discard)
936  {
937  const auto & universe_to_delete = csg_obj->getUniverseByName(univ_name);
938  const auto cells_to_delete = universe_to_delete.getAllCells();
939  csg_obj->deleteUniverse(universe_to_delete);
940  for (const auto & cell : cells_to_delete)
941  csg_obj->deleteCell(cell.get());
942  }
943 
944  // Build the universe pattern for the assembly lattice from the input pattern
945  std::vector<std::vector<std::reference_wrapper<const CSG::CSGUniverse>>> universe_pattern;
946  for (const auto & row : _pattern)
947  {
948  std::vector<std::reference_wrapper<const CSG::CSGUniverse>> universe_row;
949  for (const auto & univ_id : row)
950  {
951  const auto & lattice_univ = csg_obj->getUniverseByName(univ_id_names[univ_id]);
952  universe_row.push_back(lattice_univ);
953  }
954  universe_pattern.push_back(universe_row);
955  }
956 
957  const auto assembly_pitch = getReactorParam<Real>(RGMB::assembly_pitch);
958  auto & core_lattice = createRGMBLattice(assembly_pitch, universe_pattern, *csg_obj);
959 
960  // Define universe that fills region outside of lattice. For an explicity
961  // defined outer ring, this is a material outer corresponding to the region ID
962  // of the ring region. Otherwise, the outer is defined as a universe containing a void cell
963  if (_mesh_periphery)
964  {
965  std::string region_name = "rgmb_region_" + std::to_string(_periphery_region_id);
966  csg_obj->setLatticeOuter(core_lattice, region_name);
967  }
968  else
969  {
970  const auto & outer_univ = csg_obj->getUniverseByName(dummy_univ_name);
971  csg_obj->setLatticeOuter(core_lattice, outer_univ);
972  }
973 
974  // Define lattice cell, with the lattice surrounded by a bounding circle whose radius is
975  // determined by the mesh periphery radius. If no mesh periphery is defined, the radius will be (N
976  // + 1) times the assembly pitch of the lattice for hex lattices, where N is the number of rings
977  // for a hexagonal lattice. For Cartesian lattices, the radius will be (N / 2 * sqrt(2)) times the
978  // assembly pitch, where N is the number of assembly widths that span a square lattice. This
979  // ensures that the ring radius completely surrounds the underlying lattice.
980  std::string lat_cell_name = name() + "_lattice_cell";
981  const auto ring_radius = _mesh_periphery ? _outer_circle_radius
982  : (_geom_type == "Hex")
983  ? (universe_pattern.size() + 2) / 2. * assembly_pitch
984  : universe_pattern.size() / 2. * sqrt(2.) * assembly_pitch;
985  const auto ring_surf_name = name() + "_radial_ring";
986  std::unique_ptr<CSG::CSGSurface> ring_surf_ptr =
987  std::make_unique<CSG::CSGZCylinder>(ring_surf_name, 0, 0, ring_radius);
988  const auto & ring_surf = csg_obj->addSurface(std::move(ring_surf_ptr));
989  auto lat_cell_region = -ring_surf;
990 
991  if (_mesh_dimensions == 3)
992  {
993  const auto surfaces_by_axial_region = getAxialPlaneSurfaces(*csg_obj);
994  const auto & lowest_axial_surf = surfaces_by_axial_region.front().get();
995  const auto & highest_axial_surf = surfaces_by_axial_region.back().get();
996  lat_cell_region = lat_cell_region & +lowest_axial_surf & -highest_axial_surf;
997  }
998  csg_obj->createCell(lat_cell_name, core_lattice, lat_cell_region);
999 
1000  return csg_obj;
1001 }
const T & getMeshProperty(const std::string &data_name, const std::string &prefix)
std::unique_ptr< MeshBase > & getMeshByName(const MeshGeneratorName &mesh_generator_name)
static void addDepletionIDParams(InputParameters &parameters)
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
void paramError(const std::string &param, Args... args) const
std::vector< std::unique_ptr< CSG::CSGBase > *> getCSGBases(const std::string &param_name)
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
std::vector< std::unique_ptr< CSG::CSGBase > * > _input_csg_bases
List of pointers to all CSG bases created by input mesh generators.
std::unique_ptr< CSG::CSGBase > generateCSG() override
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
const InputParameters & parameters() const
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
T & set(const std::string &name, bool quiet_mode=false)
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
std::vector< std::reference_wrapper< const CSG::CSGSurface > > getAxialPlaneSurfaces(CSG::CSGBase &csg_obj)
Get CSGSurfaces corresponding to axial planes of the extruded RGMB mesh.
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
const SubdomainName TRI_BLOCK_NAME_SUFFIX
bool _empty_pos
Whether empty positions are to be used in the pattern.
Factory & getFactory()
std::string _desired_area_func
Desired (local) triangle area as a function of (x,y)
TRI3
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.
const std::string & name() const
int8_t boundary_id_type
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. ...
void freeReactorParamsMesh()
Releases the mesh obtained in _reactor_params_mesh.
const SubdomainName CORE_BLOCK_NAME_PREFIX
bool constituentAssembliesNeedFlexibleStiching()
bool getCSGOnly() const
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 &param_name)
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...
static void setHasGenerateCSG(InputParameters &params)
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
void freeReactorParamsCSG()
Releases the CSG base object obtained in _reactor_params_csg.
static const std::string is_control_drum
bool isParamSetByUser(const std::string &name) const
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
MooseApp & _app
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
std::unique_ptr< MeshBase > generate() override
const CSG::CSGLattice & createRGMBLattice(const Real pitch, const std::vector< std::vector< std::reference_wrapper< const CSG::CSGUniverse >>> pattern, CSG::CSGBase &csg_obj)
Create CSG lattice for assembly and core lattices.
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...
void mooseWarning(Args &&... args) const
void mooseError(Args &&... args) const
A base class that contains common members for Reactor Geometry Mesh Builder mesh generators.
const BoundaryName ASSEMBLY_BOUNDARY_NAME_PREFIX
const Real _desired_area
Desired (maximum) triangle area.
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...
MeshGeneratorSystem & getMeshGeneratorSystem()
PRISM6
void declareMeshesForSub(const std::string &param_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.
bool hasMeshProperty(const std::string &data_name, const std::string &prefix) const
CoreMeshGenerator(const InputParameters &parameters)
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...
uint8_t dof_id_type