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 "AssemblyMeshGenerator.h"
11 :
12 : #include "ReactorGeometryMeshBuilderBase.h"
13 : #include "MooseApp.h"
14 : #include "Factory.h"
15 : #include "libmesh/elem.h"
16 : #include "MooseMeshUtils.h"
17 :
18 : registerMooseObject("ReactorApp", AssemblyMeshGenerator);
19 :
20 : InputParameters
21 1018 : AssemblyMeshGenerator::validParams()
22 : {
23 1018 : auto params = ReactorGeometryMeshBuilderBase::validParams();
24 :
25 2036 : params.addRequiredParam<std::vector<MeshGeneratorName>>(
26 : "inputs", "The PinMeshGenerators that form the components of the assembly.");
27 :
28 2036 : params.addRequiredParam<subdomain_id_type>("assembly_type",
29 : "The integer ID for this assembly type definition");
30 :
31 2036 : params.addRequiredParam<std::vector<std::vector<unsigned int>>>(
32 : "pattern",
33 : "A double-indexed array starting with the upper-left corner where the index"
34 : "represents the layout of input pins in the assembly lattice.");
35 :
36 2036 : params.addRangeCheckedParam<std::vector<Real>>(
37 : "duct_halfpitch",
38 : "duct_halfpitch>0.0",
39 : "Distance(s) from center to duct(s) inner boundaries.");
40 :
41 2036 : params.addRangeCheckedParam<unsigned int>("background_intervals",
42 : "background_intervals>0",
43 : "Radial intervals in the assembly peripheral region.");
44 :
45 2036 : params.addRangeCheckedParam<std::vector<unsigned int>>(
46 : "duct_intervals", "duct_intervals>0", "Number of meshing intervals in each enclosing duct.");
47 :
48 2036 : params.addParam<std::vector<subdomain_id_type>>(
49 : "background_region_id",
50 : "The region id for the background area between the pins and the ducts to set region_id "
51 : "extra-element integer");
52 :
53 2036 : params.addParam<std::vector<std::vector<subdomain_id_type>>>(
54 : "duct_region_ids",
55 : "The region id for the ducts from innermost to outermost, to set region_id "
56 : "extra-element integer.");
57 :
58 2036 : params.addParam<std::vector<std::string>>("background_block_name",
59 : "The block names for the assembly background regions");
60 :
61 2036 : params.addParam<std::vector<std::vector<std::string>>>(
62 : "duct_block_names",
63 : "The block names for the assembly duct regions from innermost to outermost");
64 :
65 2036 : params.addParam<bool>("extrude",
66 2036 : false,
67 : "Determines if this is the final step in the geometry construction"
68 : " and extrudes the 2D geometry to 3D. If this is true then this mesh "
69 : "cannot be used in further mesh building in the Reactor workflow");
70 2036 : params.addParamNamesToGroup("background_region_id duct_region_ids assembly_type", "ID assigment");
71 2036 : params.addParamNamesToGroup("background_intervals background_region_id",
72 : "Background specifications");
73 2036 : params.addParamNamesToGroup("duct_intervals duct_region_ids duct_halfpitch",
74 : "Duct specifications");
75 :
76 1018 : params.addClassDescription("This AssemblyMeshGenerator object is designed to generate "
77 : "assembly-like structures, with IDs, from a reactor geometry. "
78 : "The assembly-like structures must consist of a full pattern of equal "
79 : "sized pins from PinMeshGenerator. "
80 : "A hexagonal assembly will be placed inside of a bounding hexagon "
81 : "consisting of a background region and, optionally,"
82 : " duct regions.");
83 : // depletion id generation params are added
84 1018 : addDepletionIDParams(params);
85 :
86 1018 : return params;
87 0 : }
88 :
89 509 : AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters)
90 : : ReactorGeometryMeshBuilderBase(parameters),
91 509 : _inputs(getParam<std::vector<MeshGeneratorName>>("inputs")),
92 1018 : _assembly_type(getParam<subdomain_id_type>("assembly_type")),
93 1018 : _pattern(getParam<std::vector<std::vector<unsigned int>>>("pattern")),
94 1755 : _duct_sizes(isParamValid("duct_halfpitch") ? getParam<std::vector<Real>>("duct_halfpitch")
95 : : std::vector<Real>()),
96 509 : _background_intervals(
97 1720 : isParamValid("background_intervals") ? getParam<unsigned int>("background_intervals") : 0),
98 1474 : _duct_intervals(isParamValid("duct_intervals")
99 509 : ? getParam<std::vector<unsigned int>>("duct_intervals")
100 : : std::vector<unsigned int>()),
101 1720 : _background_region_id(isParamValid("background_region_id")
102 509 : ? getParam<std::vector<subdomain_id_type>>("background_region_id")
103 : : std::vector<subdomain_id_type>()),
104 1474 : _duct_region_ids(isParamValid("duct_region_ids")
105 509 : ? getParam<std::vector<std::vector<subdomain_id_type>>>("duct_region_ids")
106 : : std::vector<std::vector<subdomain_id_type>>()),
107 1527 : _extrude(getParam<bool>("extrude"))
108 : {
109 : MeshGeneratorName reactor_params =
110 509 : MeshGeneratorName(getMeshProperty<std::string>(RGMB::reactor_params_name, _inputs[0]));
111 : // Check that MG name for reactor params is consistent across all assemblies
112 809 : for (unsigned int i = 1; i < _inputs.size(); i++)
113 300 : if (getMeshProperty<std::string>(RGMB::reactor_params_name, _inputs[i]) != reactor_params)
114 0 : mooseError("The name of all reactor_params objects should be identical across all input pins "
115 : "in the assembly.\n");
116 :
117 : // Initialize ReactorMeshParams object stored in pin input
118 1018 : initializeReactorMeshParams(reactor_params);
119 :
120 509 : _geom_type = getReactorParam<std::string>(RGMB::mesh_geometry);
121 509 : _mesh_dimensions = getReactorParam<unsigned int>(RGMB::mesh_dimensions);
122 :
123 509 : if (_extrude && _mesh_dimensions != 3)
124 0 : paramError("extrude",
125 : "In order to extrude this mesh, ReactorMeshParams/dim needs to be set to 3\n");
126 1152 : if (_extrude && (!hasReactorParam<boundary_id_type>(RGMB::top_boundary_id) ||
127 643 : !hasReactorParam<boundary_id_type>(RGMB::bottom_boundary_id)))
128 0 : mooseError("Both top_boundary_id and bottom_boundary_id must be provided in ReactorMeshParams "
129 : "if using extruded geometry");
130 :
131 : Real base_pitch = 0.0;
132 :
133 : // Check constitutent pins do not have shared pin_type ids
134 : std::map<subdomain_id_type, std::string> pin_map_type_to_name;
135 1316 : for (const auto i : index_range(_inputs))
136 : {
137 : auto pin = _inputs[i];
138 809 : if (i == 0)
139 509 : base_pitch = getMeshProperty<Real>(RGMB::pitch, pin);
140 : else
141 : {
142 300 : auto pitch = getMeshProperty<Real>(RGMB::pitch, pin);
143 300 : if (!MooseUtils::absoluteFuzzyEqual(pitch, base_pitch))
144 0 : mooseError("All pins within an assembly must have the same pitch");
145 : }
146 809 : if (getMeshProperty<bool>(RGMB::extruded, pin))
147 0 : mooseError("Pins that have already been extruded cannot be used in AssemblyMeshGenerator "
148 : "definition.\n");
149 809 : const auto pin_type = getMeshProperty<subdomain_id_type>(RGMB::pin_type, pin);
150 811 : if (pin_map_type_to_name.find(pin_type) != pin_map_type_to_name.end() &&
151 2 : pin_map_type_to_name[pin_type] != pin)
152 2 : mooseError("Constituent pins have shared pin_type ids but different names. Each uniquely "
153 : "defined pin in PinMeshGenerator must have its own pin_type id.");
154 807 : pin_map_type_to_name[pin_type] = pin;
155 : }
156 507 : auto assembly_pitch = getReactorParam<Real>(RGMB::assembly_pitch);
157 :
158 : unsigned int n_axial_levels =
159 507 : (_mesh_dimensions == 3)
160 : ? getReactorParam<std::vector<unsigned int>>(RGMB::axial_mesh_intervals).size()
161 964 : : 1;
162 507 : if (_geom_type == "Square")
163 : {
164 : const auto ny = _pattern.size();
165 : const auto nx = _pattern[0].size();
166 194 : if (_background_region_id.size() == 0)
167 : {
168 156 : if ((!MooseUtils::absoluteFuzzyEqual(base_pitch * ny, assembly_pitch)) ||
169 156 : (!MooseUtils::absoluteFuzzyEqual(base_pitch * nx, assembly_pitch)))
170 0 : mooseError(
171 : "Assembly pitch must be equal to lattice dimension times pin pitch for Cartesian "
172 : "assemblies with no background region");
173 156 : if (_background_intervals > 0)
174 0 : mooseError("\"background_region_id\" must be defined if \"background_intervals\" is "
175 : "greater than 0");
176 : }
177 : else
178 : {
179 38 : if ((base_pitch * ny > assembly_pitch) || (base_pitch * nx > assembly_pitch))
180 0 : mooseError(
181 : "Assembly pitch must be larger than lattice dimension times pin pitch for Cartesian "
182 : "assemblies with background region");
183 38 : if (_background_intervals == 0)
184 0 : mooseError("\"background_intervals\" must be greater than 0 if \"background_region_id\" is "
185 : "defined");
186 38 : if (_background_region_id.size() != n_axial_levels)
187 0 : mooseError(
188 : "The size of background_region_id must be equal to the number of axial levels as "
189 : "defined in the ReactorMeshParams object");
190 : }
191 : }
192 : else
193 : {
194 313 : if ((_background_region_id.size() == 0) || _background_intervals == 0)
195 0 : mooseError("Hexagonal assemblies must have a background region defined");
196 313 : if (assembly_pitch / std::sin(M_PI / 3.0) < _pattern.size() * base_pitch)
197 0 : mooseError("Hexagonal diameter of assembly must be larger than the number of assembly rows "
198 : "times the pin pitch");
199 : // Check size of background region id matches number of axial levels
200 313 : if (_background_region_id.size() != n_axial_levels)
201 0 : mooseError("The size of background_region_id must be equal to the number of axial levels as "
202 : "defined in the ReactorMeshParams object");
203 : }
204 :
205 507 : if (_duct_sizes.size() != _duct_intervals.size())
206 0 : mooseError("If ducts are defined then \"duct_intervals\" and \"duct_region_ids\" must also be "
207 : "defined and of equal size.");
208 :
209 507 : if (_duct_sizes.size() != 0)
210 : {
211 : // Check size of duct region id matches number of axial levels
212 228 : if (_duct_region_ids.size() != n_axial_levels)
213 0 : mooseError("The size of duct_region_id must be equal to the number of axial levels as "
214 : "defined in the ReactorMeshParams object");
215 228 : if (_duct_region_ids[0].size() != _duct_sizes.size())
216 0 : paramError("duct_halfpitch",
217 : "If ducts are defined, then \"duct_intervals\" and \"duct_region_ids\" "
218 : "must also be defined and of equal size.");
219 : }
220 :
221 : // Check whether block names are defined properly
222 1014 : if (isParamValid("background_block_name"))
223 : {
224 128 : if (getReactorParam<bool>(RGMB::region_id_as_block_name))
225 2 : paramError("background_block_name",
226 : "If ReactorMeshParams/region_id_as_block_name is set, background_block_name "
227 : "should not be specified in AssemblyMeshGenerator");
228 126 : _has_background_block_name = true;
229 378 : _background_block_name = getParam<std::vector<std::string>>("background_block_name");
230 126 : if (_background_region_id.size() != _background_block_name.size())
231 0 : mooseError("The size of background_block_name must match the size of background_region_id");
232 : }
233 : else
234 379 : _has_background_block_name = false;
235 :
236 1010 : if (isParamValid("duct_block_names"))
237 : {
238 63 : if (getReactorParam<bool>(RGMB::region_id_as_block_name))
239 0 : paramError("duct_block_names",
240 : "If ReactorMeshParams/region_id_as_block_name is set, duct_block_names should not "
241 : "be specified in AssemblyMeshGenerator");
242 63 : _has_duct_block_names = true;
243 189 : _duct_block_names = getParam<std::vector<std::vector<std::string>>>("duct_block_names");
244 63 : if (_duct_region_ids.size() != _duct_block_names.size())
245 0 : mooseError("The size of duct_block_names must match the size of duct_region_ids");
246 189 : for (const auto i : index_range(_duct_region_ids))
247 126 : if (_duct_region_ids[i].size() != _duct_block_names[i].size())
248 0 : mooseError("The size of duct_block_names must match the size of duct_region_ids");
249 : }
250 : else
251 442 : _has_duct_block_names = false;
252 :
253 : // No subgenerators will be called if option to bypass mesh generators is enabled
254 505 : if (!getReactorParam<bool>(RGMB::bypass_meshgen))
255 : {
256 : // Declare dependency of inputs to sub generator calls. If mesh generation
257 429 : declareMeshesForSub("inputs");
258 :
259 429 : _assembly_boundary_id = RGMB::ASSEMBLY_BOUNDARY_ID_START + _assembly_type;
260 429 : _assembly_boundary_name = RGMB::ASSEMBLY_BOUNDARY_NAME_PREFIX + std::to_string(_assembly_type);
261 :
262 : // Call PatternedHexMeshGenerator or PatternedCartesianMeshGenerator to stitch assembly
263 : {
264 : const auto patterned_mg_name =
265 429 : _geom_type == "Hex" ? "PatternedHexMeshGenerator" : "PatternedCartesianMeshGenerator";
266 429 : auto params = _app.getFactory().getValidParams(patterned_mg_name);
267 :
268 429 : if (_geom_type == "Hex")
269 : {
270 275 : params.set<Real>("hexagon_size") = getReactorParam<Real>(RGMB::assembly_pitch) / 2.0;
271 550 : params.set<MooseEnum>("hexagon_size_style") = "apothem";
272 : }
273 : else
274 : {
275 154 : if (_background_region_id.size() == 0)
276 232 : params.set<MooseEnum>("pattern_boundary") = "none";
277 : else
278 : {
279 76 : params.set<MooseEnum>("pattern_boundary") = "expanded";
280 38 : params.set<Real>("square_size") = getReactorParam<Real>(RGMB::assembly_pitch);
281 38 : params.set<bool>("uniform_mesh_on_sides") = true;
282 : }
283 : }
284 :
285 1287 : params.set<std::vector<std::string>>("id_name") = {"pin_id"};
286 858 : params.set<std::vector<MooseEnum>>("assign_type") = {
287 1716 : MooseEnum("cell", "cell")}; // give elems IDs relative to position in assembly
288 429 : params.set<std::vector<MeshGeneratorName>>("inputs") = _inputs;
289 429 : params.set<std::vector<std::vector<unsigned int>>>("pattern") = _pattern;
290 429 : params.set<bool>("create_outward_interface_boundaries") = false;
291 :
292 429 : if (_background_intervals > 0)
293 : {
294 313 : params.set<unsigned int>("background_intervals") = _background_intervals;
295 : // Initial block id used to define peripheral regions of assembly
296 :
297 : const auto background_block_name =
298 313 : RGMB::ASSEMBLY_BLOCK_NAME_PREFIX + std::to_string(_assembly_type) + "_R0";
299 : const auto background_block_id = RGMB::ASSEMBLY_BLOCK_ID_START;
300 313 : params.set<subdomain_id_type>("background_block_id") = background_block_id;
301 626 : params.set<SubdomainName>("background_block_name") = background_block_name;
302 : }
303 :
304 429 : if (_duct_sizes.size() > 0)
305 : {
306 : std::vector<subdomain_id_type> duct_block_ids;
307 : std::vector<SubdomainName> duct_block_names;
308 398 : for (const auto duct_it : index_range(_duct_region_ids[0]))
309 : {
310 199 : const auto duct_block_name = RGMB::ASSEMBLY_BLOCK_NAME_PREFIX +
311 398 : std::to_string(_assembly_type) + "_R" +
312 398 : std::to_string(duct_it + 1);
313 199 : const auto duct_block_id = RGMB::ASSEMBLY_BLOCK_ID_START + duct_it + 1;
314 199 : duct_block_ids.push_back(duct_block_id);
315 199 : duct_block_names.push_back(duct_block_name);
316 : }
317 :
318 199 : params.set<std::vector<Real>>("duct_sizes") = _duct_sizes;
319 199 : params.set<std::vector<subdomain_id_type>>("duct_block_ids") = duct_block_ids;
320 199 : params.set<std::vector<SubdomainName>>("duct_block_names") = duct_block_names;
321 199 : params.set<std::vector<unsigned int>>("duct_intervals") = _duct_intervals;
322 199 : }
323 :
324 429 : params.set<boundary_id_type>("external_boundary_id") = _assembly_boundary_id;
325 429 : params.set<BoundaryName>("external_boundary_name") = _assembly_boundary_name;
326 :
327 858 : addMeshSubgenerator(patterned_mg_name, name() + "_pattern", params);
328 :
329 : // Pass mesh meta-data defined in subgenerator constructor to this MeshGenerator
330 858 : copyMeshProperty<bool>("is_control_drum_meta", name() + "_pattern");
331 858 : copyMeshProperty<std::vector<Point>>("control_drum_positions", name() + "_pattern");
332 858 : copyMeshProperty<std::vector<Real>>("control_drum_angles", name() + "_pattern");
333 858 : copyMeshProperty<std::vector<std::vector<Real>>>("control_drums_azimuthal_meta",
334 858 : name() + "_pattern");
335 858 : copyMeshProperty<std::string>("position_file_name", name() + "_pattern");
336 858 : copyMeshProperty<Real>("pattern_pitch_meta", name() + "_pattern");
337 429 : }
338 :
339 429 : std::string build_mesh_name = name() + "_delbds";
340 :
341 : // Remove outer pin sidesets created by PolygonConcentricCircleMeshGenerator
342 : {
343 : // Get outer boundaries of all constituent pins based on pin_type
344 : std::vector<BoundaryName> boundaries_to_delete = {};
345 1587 : for (const auto & pattern_x : _pattern)
346 : {
347 3844 : for (const auto & pattern_idx : pattern_x)
348 : {
349 2686 : const auto pin_name = _inputs[pattern_idx];
350 2686 : const auto pin_id = getMeshProperty<subdomain_id_type>(RGMB::pin_type, pin_name);
351 : const BoundaryName boundary_name =
352 5372 : RGMB::PIN_BOUNDARY_NAME_PREFIX + std::to_string(pin_id);
353 2686 : if (!std::count(boundaries_to_delete.begin(), boundaries_to_delete.end(), boundary_name))
354 676 : boundaries_to_delete.push_back(boundary_name);
355 : }
356 : }
357 858 : auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
358 :
359 1287 : params.set<MeshGeneratorName>("input") = name() + "_pattern";
360 429 : params.set<std::vector<BoundaryName>>("boundary_names") = boundaries_to_delete;
361 :
362 858 : addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params);
363 429 : }
364 :
365 : // Modify outermost mesh interval to enable flexible assembly stitching
366 429 : const auto use_flexible_stitching = getReactorParam<bool>(RGMB::flexible_assembly_stitching);
367 429 : if (use_flexible_stitching)
368 : {
369 75 : generateFlexibleAssemblyBoundaries();
370 150 : build_mesh_name = name() + "_fpg_delbds";
371 : }
372 :
373 1105 : for (auto pinMG : _inputs)
374 : {
375 : std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>> region_id_map =
376 : getMeshProperty<std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>>(
377 676 : RGMB::pin_region_ids, pinMG);
378 1352 : _pin_region_id_map.insert(
379 0 : std::pair<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>>(
380 676 : region_id_map.begin()->first, region_id_map.begin()->second));
381 676 : subdomain_id_type pin_type_id = getMeshProperty<subdomain_id_type>(RGMB::pin_type, pinMG);
382 : std::vector<std::vector<std::string>> pin_block_names =
383 676 : getMeshProperty<std::vector<std::vector<std::string>>>(RGMB::pin_block_names, pinMG);
384 1352 : _pin_block_name_map.insert(
385 676 : std::pair<subdomain_id_type, std::vector<std::vector<std::string>>>(pin_type_id,
386 : pin_block_names));
387 676 : }
388 :
389 429 : if (_extrude && _mesh_dimensions == 3)
390 126 : build_mesh_name = callExtrusionMeshSubgenerators(build_mesh_name);
391 :
392 : // Store final mesh subgenerator
393 429 : _build_mesh = &getMeshByName(build_mesh_name);
394 : }
395 : // If mesh generation should be bypassed, call getMeshes to resolve MeshGeneratorSystem
396 : // dependencies
397 : else
398 152 : auto input_meshes = getMeshes("inputs");
399 :
400 505 : generateMetadata();
401 1792 : }
402 :
403 : void
404 505 : AssemblyMeshGenerator::generateMetadata()
405 : {
406 : // Declare metadata for use in downstream mesh generators
407 505 : declareMeshProperty(RGMB::assembly_type, _assembly_type);
408 : declareMeshProperty(RGMB::pitch, getReactorParam<Real>(RGMB::assembly_pitch));
409 505 : declareMeshProperty(RGMB::background_region_id, _background_region_id);
410 505 : declareMeshProperty(RGMB::background_block_name, _background_block_name);
411 505 : declareMeshProperty(RGMB::duct_halfpitches, _duct_sizes);
412 505 : declareMeshProperty(RGMB::duct_region_ids, _duct_region_ids);
413 505 : declareMeshProperty(RGMB::duct_block_names, _duct_block_names);
414 505 : declareMeshProperty(RGMB::is_homogenized, false);
415 505 : declareMeshProperty(RGMB::is_single_pin, false);
416 947 : declareMeshProperty(RGMB::extruded, _extrude && _mesh_dimensions == 3);
417 505 : declareMeshProperty(RGMB::is_control_drum, false);
418 : // Following metadata is only relevant if an output mesh is generated by RGMB
419 505 : if (!getReactorParam<bool>(RGMB::bypass_meshgen))
420 : {
421 429 : declareMeshProperty(RGMB::pin_region_id_map, _pin_region_id_map);
422 429 : declareMeshProperty(RGMB::pin_block_name_map, _pin_block_name_map);
423 : }
424 :
425 : // Determine constituent pin names and define lattice as metadata
426 : std::vector<std::vector<int>> pin_name_lattice;
427 : std::vector<std::string> input_pin_names;
428 1851 : for (const auto i : index_range(_pattern))
429 : {
430 1346 : std::vector<int> pin_name_idx(_pattern[i].size());
431 4444 : for (const auto j : index_range(_pattern[i]))
432 : {
433 3098 : const auto input_pin_name = _inputs[_pattern[i][j]];
434 3098 : const auto it = std::find(input_pin_names.begin(), input_pin_names.end(), input_pin_name);
435 3098 : if (it == input_pin_names.end())
436 : {
437 801 : pin_name_idx[j] = input_pin_names.size();
438 801 : input_pin_names.push_back(input_pin_name);
439 : }
440 : else
441 2297 : pin_name_idx[j] = it - input_pin_names.begin();
442 : }
443 1346 : pin_name_lattice.push_back(pin_name_idx);
444 1346 : }
445 : declareMeshProperty(RGMB::pin_names, input_pin_names);
446 : declareMeshProperty(RGMB::pin_lattice, pin_name_lattice);
447 505 : }
448 :
449 : void
450 75 : AssemblyMeshGenerator::generateFlexibleAssemblyBoundaries()
451 : {
452 : // Assemblies that invoke this method have constituent pin lattice, delete outermost background or
453 : // duct region (if present)
454 : SubdomainName block_to_delete = "";
455 75 : if (_background_region_id.size() == 0)
456 0 : mooseError("Attempting to use flexible stitching on assembly " + name() +
457 : " that does not have a background region. This is not yet supported.");
458 75 : const auto radial_index = _duct_region_ids.size() == 0 ? 0 : _duct_region_ids[0].size();
459 225 : block_to_delete = RGMB::ASSEMBLY_BLOCK_NAME_PREFIX + std::to_string(_assembly_type) + "_R" +
460 75 : std::to_string(radial_index);
461 :
462 : {
463 : // Invoke BlockDeletionGenerator to delete outermost mesh interval of assembly
464 150 : auto params = _app.getFactory().getValidParams("BlockDeletionGenerator");
465 :
466 225 : params.set<std::vector<SubdomainName>>("block") = {block_to_delete};
467 225 : params.set<MeshGeneratorName>("input") = name() + "_delbds";
468 :
469 150 : addMeshSubgenerator("BlockDeletionGenerator", name() + "_del_outer", params);
470 75 : }
471 : {
472 : // Invoke FlexiblePatternGenerator to triangulate deleted mesh region
473 150 : auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator");
474 :
475 375 : params.set<std::vector<MeshGeneratorName>>("inputs") = {name() + "_del_outer"};
476 75 : params.set<std::vector<libMesh::Point>>("extra_positions") = {libMesh::Point(0, 0, 0)};
477 75 : params.set<std::vector<unsigned int>>("extra_positions_mg_indices") = {0};
478 75 : params.set<bool>("use_auto_area_func") = true;
479 170 : params.set<MooseEnum>("boundary_type") = (_geom_type == "Hex") ? "HEXAGON" : "CARTESIAN";
480 75 : params.set<unsigned int>("boundary_sectors") =
481 75 : getReactorParam<unsigned int>(RGMB::num_sectors_flexible_stitching);
482 75 : params.set<Real>("boundary_size") = getReactorParam<Real>(RGMB::assembly_pitch);
483 75 : params.set<boundary_id_type>("external_boundary_id") = _assembly_boundary_id;
484 75 : params.set<BoundaryName>("external_boundary_name") = _assembly_boundary_name;
485 150 : params.set<SubdomainName>("background_subdomain_name") =
486 75 : block_to_delete + RGMB::TRI_BLOCK_NAME_SUFFIX;
487 75 : params.set<bool>("verify_holes") = false;
488 75 : params.set<unsigned short>("background_subdomain_id") = RGMB::ASSEMBLY_BLOCK_ID_TRI_FLEXIBLE;
489 :
490 150 : addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params);
491 75 : }
492 : {
493 : // Delete extra boundary created by FlexiblePatternGenerator
494 150 : auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
495 :
496 225 : params.set<MeshGeneratorName>("input") = name() + "_fpg";
497 300 : params.set<std::vector<BoundaryName>>("boundary_names") = {std::to_string(1)};
498 :
499 150 : addMeshSubgenerator("BoundaryDeletionGenerator", name() + "_fpg_delbds", params);
500 75 : }
501 75 : }
502 :
503 : std::unique_ptr<MeshBase>
504 417 : AssemblyMeshGenerator::generate()
505 : {
506 : // Must be called to free the ReactorMeshParams mesh
507 417 : freeReactorMeshParams();
508 :
509 : // If bypass_mesh is true, return a null mesh. In this mode, an output mesh is not
510 : // generated and only metadata is defined on the generator, so logic related to
511 : // generation of output mesh will not be called
512 417 : if (getReactorParam<bool>(RGMB::bypass_meshgen))
513 : {
514 : auto null_mesh = nullptr;
515 : return null_mesh;
516 : }
517 :
518 : // Update metadata at this point since values for these metadata only get set by PCCMG
519 : // at generate() stage
520 834 : if (hasMeshProperty<Real>("pattern_pitch_meta", name() + "_pattern"))
521 : {
522 : const auto pattern_pitch_meta =
523 417 : getMeshProperty<Real>("pattern_pitch_meta", name() + "_pattern");
524 834 : setMeshProperty("pattern_pitch_meta", pattern_pitch_meta);
525 : }
526 :
527 : // This generate() method will be called once the subgenerators that we depend on are
528 : // called. This is where we reassign subdomain ids/name in case they were merged when
529 : // stitching pins into an assembly. This is also where we set region_id and
530 : // assembly_type_id element integers.
531 :
532 : // Define all extra element names and integers
533 417 : std::string plane_id_name = "plane_id";
534 417 : std::string region_id_name = "region_id";
535 417 : std::string pin_type_id_name = "pin_type_id";
536 417 : std::string assembly_type_id_name = "assembly_type_id";
537 417 : std::string radial_id_name = "radial_id";
538 : const std::string default_block_name =
539 417 : RGMB::ASSEMBLY_BLOCK_NAME_PREFIX + std::to_string(_assembly_type);
540 :
541 417 : auto pin_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), pin_type_id_name, true);
542 417 : auto region_id_int = getElemIntegerFromMesh(*(*_build_mesh), region_id_name, true);
543 417 : auto radial_id_int = getElemIntegerFromMesh(*(*_build_mesh), radial_id_name, true);
544 :
545 417 : auto assembly_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), assembly_type_id_name);
546 :
547 : unsigned int plane_id_int = 0;
548 417 : if (_extrude)
549 126 : plane_id_int = getElemIntegerFromMesh(*(*_build_mesh), plane_id_name, true);
550 :
551 : // Get next free block ID in mesh in case subdomain ids need to be remapped
552 417 : auto next_block_id = MooseMeshUtils::getNextFreeSubdomainID(*(*(_build_mesh)));
553 : std::map<std::string, SubdomainID> rgmb_name_id_map;
554 :
555 : // Loop through all mesh elements and set region ids and reassign block IDs/names
556 : // if they were merged during pin stitching
557 311398 : for (auto & elem : (*_build_mesh)->active_element_ptr_range())
558 : {
559 155282 : elem->set_extra_integer(assembly_type_id_int, _assembly_type);
560 155282 : const dof_id_type pin_type_id = elem->get_extra_integer(pin_type_id_int);
561 155282 : const dof_id_type z_id = _extrude ? elem->get_extra_integer(plane_id_int) : 0;
562 :
563 : // Element is part of a pin mesh
564 155282 : if (_pin_region_id_map.find(pin_type_id) != _pin_region_id_map.end())
565 : {
566 : // Get region ID from pin_type, z_id, and radial_idx
567 81050 : const dof_id_type radial_idx = elem->get_extra_integer(radial_id_int);
568 81050 : const auto elem_rid = _pin_region_id_map[pin_type_id][z_id][radial_idx];
569 81050 : elem->set_extra_integer(region_id_int, elem_rid);
570 :
571 : // Set element block name and block id
572 81050 : bool has_block_names = !_pin_block_name_map[pin_type_id].empty();
573 81050 : auto elem_block_name = default_block_name;
574 81050 : if (has_block_names)
575 39960 : elem_block_name += "_" + _pin_block_name_map[pin_type_id][z_id][radial_idx];
576 61070 : else if (getReactorParam<bool>(RGMB::region_id_as_block_name))
577 43300 : elem_block_name += "_REG" + std::to_string(elem_rid);
578 81050 : if (elem->type() == TRI3 || elem->type() == PRISM6)
579 : elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
580 162100 : updateElementBlockNameId(
581 81050 : *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
582 : }
583 : else
584 : {
585 : // Assembly peripheral element (background / duct), set subdomains according
586 : // to user preferences and set pin type id to RGMB::MAX_PIN_TYPE_ID - peripheral index
587 : // Region id is inferred from z_id and peripheral_idx
588 74232 : const auto base_block_id = elem->subdomain_id();
589 74232 : const auto base_block_name = (*_build_mesh)->subdomain_name(base_block_id);
590 :
591 : // Check if block name has correct prefix
592 148464 : std::string prefix = RGMB::ASSEMBLY_BLOCK_NAME_PREFIX + std::to_string(_assembly_type) + "_R";
593 74232 : if (!(base_block_name.find(prefix, 0) == 0))
594 : continue;
595 : // Peripheral index is integer value of substring after prefix
596 148464 : const unsigned int peripheral_idx = std::stoi(base_block_name.substr(prefix.length()));
597 :
598 : bool is_background_region = peripheral_idx == 0;
599 :
600 74232 : subdomain_id_type pin_type = RGMB::MAX_PIN_TYPE_ID - peripheral_idx;
601 74232 : elem->set_extra_integer(pin_type_id_int, pin_type);
602 :
603 74232 : const auto elem_rid = (is_background_region ? _background_region_id[z_id]
604 22510 : : _duct_region_ids[z_id][peripheral_idx - 1]);
605 74232 : elem->set_extra_integer(region_id_int, elem_rid);
606 :
607 : // Set element block name and block id
608 74232 : auto elem_block_name = default_block_name;
609 74232 : if (getReactorParam<bool>(RGMB::region_id_as_block_name))
610 118152 : elem_block_name += "_REG" + std::to_string(elem_rid);
611 15156 : else if (is_background_region && _has_background_block_name)
612 8424 : elem_block_name += "_" + _background_block_name[z_id];
613 5976 : else if (!is_background_region && _has_duct_block_names)
614 3888 : elem_block_name += "_" + _duct_block_names[z_id][peripheral_idx - 1];
615 74232 : if (elem->type() == TRI3 || elem->type() == PRISM6)
616 : elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
617 148464 : updateElementBlockNameId(
618 74232 : *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
619 : }
620 417 : }
621 :
622 834 : if (getParam<bool>("generate_depletion_id"))
623 : {
624 36 : const MooseEnum option = getParam<MooseEnum>("depletion_id_type");
625 18 : addDepletionId(*(*_build_mesh), option, DepletionIDGenerationLevel::Assembly, _extrude);
626 18 : }
627 :
628 : // Mark mesh as not prepared, as block IDs were re-assigned in this method
629 417 : (*_build_mesh)->set_isnt_prepared();
630 :
631 : return std::move(*_build_mesh);
632 : }
|