Line data Source code
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 :
12 : #include "ReactorGeometryMeshBuilderBase.h"
13 : #include <cmath>
14 : #include "MooseApp.h"
15 : #include "MooseMeshUtils.h"
16 : #include "Factory.h"
17 : #include "libmesh/elem.h"
18 :
19 : registerMooseObject("ReactorApp", PinMeshGenerator);
20 :
21 : InputParameters
22 1946 : PinMeshGenerator::validParams()
23 : {
24 1946 : auto params = ReactorGeometryMeshBuilderBase::validParams();
25 :
26 3892 : params.addRequiredParam<MeshGeneratorName>(
27 : "reactor_params",
28 : "The ReactorMeshParams MeshGenerator that is the basis for this component conformal mesh.");
29 :
30 3892 : params.addRequiredParam<subdomain_id_type>("pin_type",
31 : "The integer ID for this pin type definition");
32 :
33 3892 : params.addRequiredRangeCheckedParam<Real>(
34 : "pitch", "pitch>0.0", "The pitch for the outermost boundary polygon");
35 :
36 3892 : params.addRangeCheckedParam<unsigned int>(
37 : "num_sectors", "num_sectors>0", "Number of azimuthal sectors in each quadrant");
38 :
39 3892 : 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 3892 : 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 5838 : params.addRangeCheckedParam<std::vector<unsigned int>>(
50 : "mesh_intervals",
51 3892 : 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 3892 : 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 3892 : 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 3892 : params.addParam<bool>("extrude",
69 3892 : 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 3892 : params.addParam<bool>(
74 3892 : "homogenized", false, "Determines whether homogenized pin mesh should be generated");
75 3892 : params.addParam<bool>(
76 3892 : "use_as_assembly", false, "Determines whether pin mesh should be used as an assembly mesh");
77 :
78 3892 : params.addParam<bool>(
79 3892 : "quad_center_elements", true, "Whether the center elements are quad or triangular.");
80 3892 : params.addParamNamesToGroup("region_ids pin_type", "ID assigment");
81 3892 : params.addParamNamesToGroup(
82 : "mesh_intervals ring_radii num_sectors pin_type homogenized use_as_assembly",
83 : "Pin specifications");
84 3892 : params.addParamNamesToGroup("mesh_intervals duct_halfpitch num_sectors", "Duct specifications");
85 :
86 1946 : 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 1946 : return params;
94 0 : }
95 :
96 970 : PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters)
97 : : ReactorGeometryMeshBuilderBase(parameters),
98 970 : _pin_type(getParam<subdomain_id_type>("pin_type")),
99 1940 : _pitch(getParam<Real>("pitch")),
100 3694 : _num_sectors(isParamValid("num_sectors") ? getParam<unsigned int>("num_sectors") : 0),
101 3517 : _ring_radii(isParamValid("ring_radii") ? getParam<std::vector<Real>>("ring_radii")
102 : : std::vector<Real>()),
103 3197 : _duct_halfpitch(isParamValid("duct_halfpitch") ? getParam<std::vector<Real>>("duct_halfpitch")
104 : : std::vector<Real>()),
105 1940 : _intervals(getParam<std::vector<unsigned int>>("mesh_intervals")),
106 3880 : _region_ids(isParamValid("region_ids")
107 970 : ? getParam<std::vector<std::vector<subdomain_id_type>>>("region_ids")
108 : : std::vector<std::vector<subdomain_id_type>>()),
109 1940 : _extrude(getParam<bool>("extrude")),
110 1940 : _quad_center(getParam<bool>("quad_center_elements")),
111 1940 : _homogenized(getParam<bool>("homogenized")),
112 2910 : _is_assembly(getParam<bool>("use_as_assembly"))
113 : {
114 : // Initialize ReactorMeshParams object
115 2910 : initializeReactorMeshParams(getParam<MeshGeneratorName>("reactor_params"));
116 :
117 970 : _mesh_dimensions = getReactorParam<unsigned int>(RGMB::mesh_dimensions);
118 970 : _mesh_geometry = getReactorParam<std::string>(RGMB::mesh_geometry);
119 :
120 970 : if (_is_assembly)
121 : {
122 145 : auto assembly_pitch = getReactorParam<Real>(RGMB::assembly_pitch);
123 145 : if (assembly_pitch != _pitch)
124 0 : mooseError("Pitch defined in PinMeshGenerator must match assembly_pitch defined in "
125 : "ReactorMeshParams if use_as_assembly is set to true");
126 : }
127 :
128 970 : if (_extrude && _mesh_dimensions != 3)
129 0 : paramError("extrude",
130 : "In order to extrude this mesh, ReactorMeshParams/dim needs to be set to 3\n");
131 1976 : if (_extrude && (!hasReactorParam<boundary_id_type>(RGMB::top_boundary_id) ||
132 1006 : !hasReactorParam<boundary_id_type>(RGMB::bottom_boundary_id)))
133 0 : mooseError("Both top_boundary_id and bottom_boundary_id must be provided in ReactorMeshParams "
134 : "if using extruded geometry");
135 :
136 970 : if (_homogenized)
137 : {
138 93 : if (_mesh_geometry == "Square")
139 0 : mooseError("Homogenization in PinMeshGenerator is only supported for hexagonal geometries");
140 : const std::vector<std::string> disallowed_parameters = {
141 93 : "num_sectors", "ring_radii", "duct_halfpitch", "mesh_intervals"};
142 465 : for (const auto & parameter : disallowed_parameters)
143 372 : if (parameters.isParamSetByUser(parameter))
144 0 : paramError(parameter,
145 0 : "Parameter " + parameter + " should not be defined for a homogenized pin mesh");
146 93 : }
147 : else
148 : {
149 877 : if (_num_sectors == 0)
150 0 : mooseError(
151 : "Number of sectors must be assigned with parameter num_sectors for non-homogenized pins");
152 877 : if (_intervals.size() != (_ring_radii.size() + _duct_halfpitch.size() + 1))
153 0 : 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 1940 : if (isParamValid("region_ids"))
160 : {
161 : unsigned int n_axial_levels =
162 970 : (_mesh_dimensions == 3)
163 : ? getReactorParam<std::vector<unsigned int>>(RGMB::axial_mesh_intervals).size()
164 1775 : : 1;
165 970 : if (_region_ids.size() != n_axial_levels)
166 0 : mooseError("The size of region IDs must be equal to the number of axial levels as defined in "
167 : "the ReactorMeshParams object");
168 970 : if (_region_ids[0].size() != (_ring_radii.size() + _duct_halfpitch.size() + 1))
169 0 : 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 0 : mooseError("Region IDs must be assigned with parameter region_ids");
175 : }
176 1940 : if (isParamValid("block_names"))
177 : {
178 173 : if (getReactorParam<bool>(RGMB::region_id_as_block_name))
179 2 : paramError("block_names",
180 : "If ReactorMeshParams/region_id_as_block_name is set, block_names should not be "
181 : "specified in PinMeshGenerator");
182 171 : _has_block_names = true;
183 513 : _block_names = getParam<std::vector<std::vector<std::string>>>("block_names");
184 171 : if (_region_ids.size() != _block_names.size())
185 0 : mooseError("The size of block_names must match the size of region_ids");
186 513 : for (const auto i : index_range(_region_ids))
187 342 : if (_region_ids[i].size() != _block_names[i].size())
188 0 : mooseError("The size of block_names must match the size of region_ids");
189 : }
190 : else
191 797 : _has_block_names = false;
192 :
193 968 : 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 968 : if (!getReactorParam<bool>(RGMB::bypass_meshgen))
198 : {
199 854 : 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 84 : bool skip_assembly_generation = _is_assembly && use_flexible_stitching;
205 :
206 84 : auto params = _app.getFactory().getValidParams("SimpleHexagonGenerator");
207 :
208 84 : params.set<Real>("hexagon_size") = _pitch / 2.0;
209 84 : params.set<boundary_id_type>("external_boundary_id") =
210 84 : RGMB::PIN_BOUNDARY_ID_START + _pin_type;
211 : const auto boundary_name =
212 84 : (_is_assembly ? RGMB::ASSEMBLY_BOUNDARY_NAME_PREFIX : RGMB::PIN_BOUNDARY_NAME_PREFIX) +
213 252 : std::to_string(_pin_type);
214 168 : params.set<BoundaryName>("external_boundary_name") = boundary_name;
215 84 : params.set<std::vector<subdomain_id_type>>("block_id") = {
216 216 : _quad_center ? RGMB::PIN_BLOCK_ID_START : RGMB::PIN_BLOCK_ID_TRI};
217 216 : params.set<MooseEnum>("element_type") = _quad_center ? "QUAD" : "TRI";
218 84 : auto block_name = RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R0";
219 84 : if (!_quad_center)
220 : block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
221 252 : params.set<std::vector<SubdomainName>>("block_name") = {block_name};
222 :
223 84 : if (!skip_assembly_generation)
224 : {
225 54 : build_mesh_name = name() + "_2D";
226 108 : addMeshSubgenerator("SimpleHexagonGenerator", build_mesh_name, params);
227 : }
228 84 : }
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 2363 : for (const auto i : index_range(_intervals))
243 : {
244 : const auto block_name =
245 4779 : RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R" + std::to_string(i);
246 1593 : const auto block_id = RGMB::PIN_BLOCK_ID_START + i;
247 :
248 1593 : if (i < _ring_radii.size())
249 : {
250 565 : ring_intervals.push_back(_intervals[i]);
251 565 : ring_blk_ids.push_back(block_id);
252 565 : ring_blk_names.push_back(block_name);
253 : }
254 1028 : else if (i > _ring_radii.size())
255 : {
256 258 : duct_intervals.push_back(_intervals[i]);
257 258 : duct_blk_ids.push_back(block_id);
258 258 : duct_blk_names.push_back(block_name);
259 : }
260 : else
261 : {
262 770 : background_intervals = _intervals[i];
263 770 : background_blk_ids.push_back(block_id);
264 770 : background_blk_names.push_back(block_name);
265 : }
266 : }
267 770 : if (ring_intervals.size() > 0)
268 : {
269 529 : 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 18 : if (_quad_center)
275 : {
276 9 : ring_blk_ids.insert(ring_blk_ids.begin(), ring_blk_ids.front());
277 9 : ring_blk_names.insert(ring_blk_names.begin(), ring_blk_names.front());
278 : }
279 : else
280 : {
281 9 : const auto block_name = ring_blk_names.front() + RGMB::TRI_BLOCK_NAME_SUFFIX;
282 9 : const auto block_id = RGMB::PIN_BLOCK_ID_TRI;
283 9 : ring_blk_ids.insert(ring_blk_ids.begin(), block_id);
284 9 : 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 511 : else if (!_quad_center)
289 : {
290 276 : ring_blk_ids[0] = RGMB::PIN_BLOCK_ID_TRI;
291 276 : ring_blk_names[0] += RGMB::TRI_BLOCK_NAME_SUFFIX;
292 : }
293 : }
294 : else
295 : {
296 241 : 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 168 : if (_quad_center)
302 : {
303 159 : background_blk_ids.insert(background_blk_ids.begin(), background_blk_ids.front());
304 159 : background_blk_names.insert(background_blk_names.begin(), background_blk_names.front());
305 : }
306 : else
307 : {
308 9 : const auto block_name = background_blk_names.front() + RGMB::TRI_BLOCK_NAME_SUFFIX;
309 9 : const auto block_id = RGMB::PIN_BLOCK_ID_TRI;
310 9 : background_blk_ids.insert(background_blk_ids.begin(), block_id);
311 9 : 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 73 : else if (!_quad_center)
317 : {
318 64 : background_blk_ids[0] = RGMB::PIN_BLOCK_ID_TRI;
319 64 : 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 770 : _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 760 : auto params = _app.getFactory().getValidParams("PolygonConcentricCircleMeshGenerator");
336 760 : params.set<bool>("preserve_volumes") = true;
337 760 : params.set<bool>("quad_center_elements") = _quad_center;
338 1520 : params.set<MooseEnum>("polygon_size_style") = "apothem";
339 760 : params.set<Real>("polygon_size") = _pitch / 2.0;
340 760 : params.set<boundary_id_type>("external_boundary_id") =
341 760 : RGMB::PIN_BOUNDARY_ID_START + _pin_type;
342 760 : const auto boundary_name = (_is_assembly ? RGMB::ASSEMBLY_BOUNDARY_NAME_PREFIX
343 : : RGMB::PIN_BOUNDARY_NAME_PREFIX) +
344 2280 : std::to_string(_pin_type);
345 1520 : params.set<BoundaryName>("external_boundary_name") = boundary_name;
346 760 : bool flat_side_up = (_mesh_geometry == "Square");
347 760 : params.set<bool>("flat_side_up") = flat_side_up;
348 760 : params.set<bool>("create_outward_interface_boundaries") = false;
349 :
350 760 : const auto num_sides = (_mesh_geometry == "Square") ? 4 : 6;
351 760 : params.set<unsigned int>("num_sides") = num_sides;
352 760 : params.set<std::vector<unsigned int>>("num_sectors_per_side") =
353 1520 : std::vector<unsigned int>(num_sides, _num_sectors);
354 :
355 760 : if (ring_intervals.size() > 0)
356 : {
357 529 : params.set<std::vector<Real>>("ring_radii") = _ring_radii;
358 529 : params.set<std::vector<subdomain_id_type>>("ring_block_ids") = ring_blk_ids;
359 529 : params.set<std::vector<SubdomainName>>("ring_block_names") = ring_blk_names;
360 1058 : params.set<std::vector<unsigned int>>("ring_intervals") = ring_intervals;
361 : }
362 :
363 760 : params.set<std::vector<subdomain_id_type>>("background_block_ids") = background_blk_ids;
364 760 : params.set<std::vector<SubdomainName>>("background_block_names") = background_blk_names;
365 760 : params.set<unsigned int>("background_intervals") = background_intervals;
366 :
367 760 : if (duct_intervals.size() > 0)
368 : {
369 516 : params.set<MooseEnum>("duct_sizes_style") = "apothem";
370 258 : params.set<std::vector<Real>>("duct_sizes") = _duct_halfpitch;
371 258 : params.set<std::vector<subdomain_id_type>>("duct_block_ids") = duct_blk_ids;
372 258 : params.set<std::vector<SubdomainName>>("duct_block_names") = duct_blk_names;
373 516 : params.set<std::vector<unsigned int>>("duct_intervals") = duct_intervals;
374 : }
375 :
376 1520 : addMeshSubgenerator("PolygonConcentricCircleMeshGenerator", name() + "_2D", params);
377 760 : }
378 :
379 : // Remove extra sidesets created by PolygonConcentricCircleMeshGenerator
380 : {
381 1520 : auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
382 :
383 2280 : params.set<MeshGeneratorName>("input") = name() + "_2D";
384 :
385 760 : auto num_sides = (_mesh_geometry == "Square") ? 4 : 6;
386 : std::vector<BoundaryName> boundaries_to_delete = {};
387 4680 : for (const auto i : make_range(num_sides))
388 11760 : boundaries_to_delete.insert(boundaries_to_delete.end(),
389 11760 : {std::to_string(10001 + i), std::to_string(15001 + i)});
390 1520 : params.set<std::vector<BoundaryName>>("boundary_names") = boundaries_to_delete;
391 :
392 760 : build_mesh_name = name() + "_delbds";
393 1520 : addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params);
394 760 : }
395 : }
396 770 : }
397 :
398 : // For pin acting as assembly, modify outermost mesh interval to enable flexible assembly
399 : // stitching
400 854 : if (_is_assembly && use_flexible_stitching)
401 : {
402 55 : generateFlexibleAssemblyBoundaries();
403 110 : build_mesh_name = name() + "_fpg_delbds";
404 : }
405 :
406 : // Pass mesh meta-data defined in subgenerator constructor to this MeshGenerator
407 1708 : if (hasMeshProperty<Real>("pitch_meta", name() + "_2D"))
408 1628 : copyMeshProperty<Real>("pitch_meta", name() + "_2D");
409 1708 : if (hasMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta", name() + "_2D"))
410 1628 : copyMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta", name() + "_2D");
411 1708 : if (hasMeshProperty<Real>("max_radius_meta", name() + "_2D"))
412 1628 : copyMeshProperty<Real>("max_radius_meta", name() + "_2D");
413 1708 : if (hasMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D"))
414 1628 : copyMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D");
415 1708 : if (hasMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D"))
416 1628 : copyMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D");
417 :
418 854 : if (_is_assembly)
419 272 : declareMeshProperty("pattern_pitch_meta", getReactorParam<Real>(RGMB::assembly_pitch));
420 1436 : else if (hasMeshProperty<Real>("pattern_pitch_meta", name() + "_2D"))
421 1382 : copyMeshProperty<Real>("pattern_pitch_meta", name() + "_2D");
422 854 : declareMeshProperty("is_control_drum_meta", false);
423 :
424 854 : if (_extrude && _mesh_dimensions == 3)
425 36 : build_mesh_name = callExtrusionMeshSubgenerators(build_mesh_name);
426 :
427 : // Store final mesh subgenerator
428 854 : _build_mesh = &getMeshByName(build_mesh_name);
429 : }
430 :
431 968 : generateMetadata();
432 968 : }
433 :
434 : void
435 55 : PinMeshGenerator::generateFlexibleAssemblyBoundaries()
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 55 : if (_homogenized || (_intervals.size() == 1))
443 : {
444 80 : 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 45 : outermost_block_name = RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R" +
450 15 : std::to_string(_intervals.size() - 1);
451 : has_single_mesh_interval = false;
452 :
453 : // Invoke BlockDeletionGenerator to delete outermost mesh interval of assembly
454 30 : auto params = _app.getFactory().getValidParams("BlockDeletionGenerator");
455 :
456 45 : params.set<std::vector<SubdomainName>>("block") = {outermost_block_name};
457 45 : params.set<MeshGeneratorName>("input") = _homogenized ? name() + "_2D" : name() + "_delbds";
458 :
459 30 : addMeshSubgenerator("BlockDeletionGenerator", name() + "_del_outer", params);
460 15 : }
461 :
462 : {
463 : // Invoke FlexiblePatternGenerator to triangulate deleted mesh interval
464 55 : auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator");
465 :
466 55 : if (has_single_mesh_interval)
467 80 : params.set<std::vector<MeshGeneratorName>>("inputs") = {};
468 : else
469 : {
470 75 : params.set<std::vector<MeshGeneratorName>>("inputs") = {name() + "_del_outer"};
471 15 : params.set<std::vector<libMesh::Point>>("extra_positions") = {libMesh::Point(0, 0, 0)};
472 30 : params.set<std::vector<unsigned int>>("extra_positions_mg_indices") = {0};
473 : }
474 55 : params.set<bool>("use_auto_area_func") = true;
475 55 : params.set<bool>("verify_holes") = false;
476 125 : params.set<MooseEnum>("boundary_type") = (_mesh_geometry == "Hex") ? "HEXAGON" : "CARTESIAN";
477 55 : params.set<unsigned int>("boundary_sectors") =
478 55 : getReactorParam<unsigned int>(RGMB::num_sectors_flexible_stitching);
479 55 : params.set<Real>("boundary_size") = getReactorParam<Real>(RGMB::assembly_pitch);
480 55 : params.set<boundary_id_type>("external_boundary_id") = RGMB::PIN_BOUNDARY_ID_START + _pin_type;
481 110 : params.set<BoundaryName>("external_boundary_name") =
482 55 : RGMB::ASSEMBLY_BOUNDARY_NAME_PREFIX + std::to_string(_pin_type);
483 110 : params.set<SubdomainName>("background_subdomain_name") =
484 55 : outermost_block_name + RGMB::TRI_BLOCK_NAME_SUFFIX;
485 55 : params.set<unsigned short>("background_subdomain_id") = RGMB::PIN_BLOCK_ID_TRI_FLEXIBLE;
486 :
487 110 : addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params);
488 55 : }
489 : {
490 : // Delete extra boundary created by FlexiblePatternGenerator
491 110 : auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
492 :
493 220 : params.set<MeshGeneratorName>("input") = name() + "_fpg";
494 : std::vector<BoundaryName> boundaries_to_delete = {};
495 55 : if (!has_single_mesh_interval)
496 30 : boundaries_to_delete.push_back(std::to_string(1));
497 55 : params.set<std::vector<BoundaryName>>("boundary_names") = boundaries_to_delete;
498 :
499 110 : addMeshSubgenerator("BoundaryDeletionGenerator", name() + "_fpg_delbds", params);
500 55 : }
501 55 : }
502 :
503 : void
504 968 : PinMeshGenerator::generateMetadata()
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{
509 1936 : {_pin_type, _region_ids}};
510 :
511 : // Declare mesh properties that need to be moved up to the assembly level
512 968 : if (_is_assembly)
513 : {
514 145 : declareMeshProperty(RGMB::assembly_type, _pin_type);
515 145 : declareMeshProperty(RGMB::background_block_name, std::vector<std::string>());
516 145 : declareMeshProperty(RGMB::duct_block_names, std::vector<std::vector<std::string>>());
517 145 : declareMeshProperty(RGMB::is_single_pin, _is_assembly);
518 145 : declareMeshProperty(RGMB::is_control_drum, false);
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 145 : 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 136 : pin_region_id_map.insert(
525 136 : std::pair<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>(
526 136 : region_id_map.begin()->first, region_id_map.begin()->second));
527 : declareMeshProperty(RGMB::pin_region_id_map, pin_region_id_map);
528 : std::map<subdomain_id_type, std::vector<std::vector<std::string>>> pin_block_name_map;
529 272 : pin_block_name_map.insert(std::pair<subdomain_id_type, std::vector<std::vector<std::string>>>(
530 136 : _pin_type, _block_names));
531 : declareMeshProperty(RGMB::pin_block_name_map, pin_block_name_map);
532 : }
533 : }
534 : // Declare mesh properties that are only relevant to pin meshes
535 : else
536 : {
537 823 : declareMeshProperty(RGMB::pin_type, _pin_type);
538 : declareMeshProperty(RGMB::pin_region_ids, region_id_map);
539 823 : declareMeshProperty(RGMB::pin_block_names, _block_names);
540 : }
541 :
542 : // Set metadata to describe pin attributes
543 968 : declareMeshProperty(RGMB::pitch, _pitch);
544 968 : declareMeshProperty(RGMB::is_homogenized, _homogenized);
545 968 : declareMeshProperty(RGMB::ring_radii, _ring_radii);
546 968 : declareMeshProperty(RGMB::duct_halfpitches, _duct_halfpitch);
547 1918 : declareMeshProperty(RGMB::extruded, _extrude && _mesh_dimensions == 3);
548 :
549 : unsigned int n_axial_levels =
550 968 : (_mesh_dimensions == 3)
551 : ? getReactorParam<std::vector<unsigned int>>(RGMB::axial_mesh_intervals).size()
552 1773 : : 1;
553 : std::vector<std::vector<subdomain_id_type>> ring_region_ids(
554 968 : n_axial_levels, std::vector<subdomain_id_type>(_ring_radii.size()));
555 : std::vector<std::vector<subdomain_id_type>> duct_region_ids(
556 968 : n_axial_levels, std::vector<subdomain_id_type>(_duct_halfpitch.size()));
557 968 : std::vector<subdomain_id_type> background_region_ids(n_axial_levels);
558 :
559 2241 : for (const auto axial_idx : make_range(n_axial_levels))
560 : {
561 2098 : for (const auto ring_idx : index_range(_ring_radii))
562 825 : ring_region_ids[axial_idx][ring_idx] = _region_ids[axial_idx][ring_idx];
563 :
564 1273 : background_region_ids[axial_idx] = _region_ids[axial_idx][_ring_radii.size()];
565 :
566 1273 : for (unsigned int duct_idx = _ring_radii.size() + 1;
567 1690 : duct_idx < _duct_halfpitch.size() + _ring_radii.size() + 1;
568 : ++duct_idx)
569 417 : 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
574 : declareMeshProperty(RGMB::ring_region_ids, ring_region_ids);
575 : declareMeshProperty(RGMB::background_region_id, background_region_ids);
576 : declareMeshProperty(RGMB::duct_region_ids, duct_region_ids);
577 1936 : }
578 :
579 : std::unique_ptr<MeshBase>
580 828 : PinMeshGenerator::generate()
581 : {
582 : // Must be called to free the ReactorMeshParams mesh
583 828 : freeReactorMeshParams();
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 828 : 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 1656 : if (hasMeshProperty<Real>("max_radius_meta", name() + "_2D"))
597 : {
598 788 : const auto max_radius_meta = getMeshProperty<Real>("max_radius_meta", name() + "_2D");
599 1576 : setMeshProperty("max_radius_meta", max_radius_meta);
600 : }
601 1656 : if (hasMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D"))
602 : {
603 : const auto background_intervals_meta =
604 788 : getMeshProperty<unsigned int>("background_intervals_meta", name() + "_2D");
605 1576 : setMeshProperty("background_intervals_meta", background_intervals_meta);
606 : }
607 1656 : if (hasMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D"))
608 : {
609 : const auto node_id_background_meta =
610 788 : getMeshProperty<dof_id_type>("node_id_background_meta", name() + "_2D");
611 1576 : 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 828 : std::string region_id_name = "region_id";
621 828 : std::string pin_type_id_name = "pin_type_id";
622 828 : std::string assembly_type_id_name = "assembly_type_id";
623 828 : std::string plane_id_name = "plane_id";
624 828 : std::string radial_id_name = "radial_id";
625 : const std::string default_block_name =
626 828 : (_is_assembly ? RGMB::ASSEMBLY_BLOCK_NAME_PREFIX : RGMB::PIN_BLOCK_NAME_PREFIX) +
627 1656 : std::to_string(_pin_type);
628 :
629 828 : auto region_id_int = getElemIntegerFromMesh(*(*_build_mesh), region_id_name);
630 828 : auto radial_id_int = getElemIntegerFromMesh(*(*_build_mesh), radial_id_name);
631 828 : 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 828 : if (_extrude)
635 36 : plane_id_int = getElemIntegerFromMesh(*(*_build_mesh), plane_id_name, true);
636 828 : if (_is_assembly)
637 272 : 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 828 : 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 64208 : for (auto & elem : (*_build_mesh)->active_element_ptr_range())
647 : {
648 31276 : const auto base_block_id = elem->subdomain_id();
649 31276 : const auto base_block_name = (*_build_mesh)->subdomain_name(base_block_id);
650 :
651 : // Check if block name has correct prefix
652 62552 : std::string prefix = RGMB::PIN_BLOCK_NAME_PREFIX + std::to_string(_pin_type) + "_R";
653 31276 : if (!(base_block_name.find(prefix, 0) == 0))
654 : continue;
655 : // Radial index is integer value of substring after prefix
656 31276 : std::string radial_str = base_block_name.substr(prefix.length());
657 :
658 : // Filter out RGMB::TRI_BLOCK_NAME_SUFFIX if needed
659 31276 : const std::string suffix = RGMB::TRI_BLOCK_NAME_SUFFIX;
660 : const std::size_t found = radial_str.find(suffix);
661 31276 : if (found != std::string::npos)
662 14984 : radial_str.replace(found, suffix.length(), "");
663 31276 : const unsigned int radial_idx = std::stoi(radial_str);
664 :
665 : // Region id is inferred from z_id and radial_idx
666 31276 : dof_id_type z_id = _extrude ? elem->get_extra_integer(plane_id_int) : 0;
667 31276 : const subdomain_id_type elem_region_id = _region_ids[std::size_t(z_id)][radial_idx];
668 :
669 : // Set element integers
670 31276 : elem->set_extra_integer(region_id_int, elem_region_id);
671 31276 : elem->set_extra_integer(pin_type_id_int, _pin_type);
672 31276 : elem->set_extra_integer(radial_id_int, radial_idx);
673 31276 : if (_is_assembly)
674 12462 : elem->set_extra_integer(assembly_type_id_int, _pin_type);
675 :
676 : // Set element block name and block id
677 31276 : auto elem_block_name = default_block_name;
678 31276 : if (_has_block_names)
679 7020 : elem_block_name += "_" + _block_names[std::size_t(z_id)][radial_idx];
680 27766 : else if (getReactorParam<bool>(RGMB::region_id_as_block_name))
681 29720 : elem_block_name += "_REG" + std::to_string(elem_region_id);
682 31276 : if (elem->type() == TRI3 || elem->type() == PRISM6)
683 : elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
684 62552 : updateElementBlockNameId(
685 31276 : *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
686 828 : }
687 :
688 : // Mark mesh as not prepared, as block IDs were re-assigned in this method
689 828 : (*_build_mesh)->set_isnt_prepared();
690 :
691 : return std::move(*_build_mesh);
692 : }
|