https://mooseframework.inl.gov
Loading...
Searching...
No Matches
RevolveGenerator.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 "RevolveGenerator.h"
12
13#include "libmesh/cell_prism6.h"
14#include "libmesh/cell_prism15.h"
15#include "libmesh/cell_prism18.h"
16#include "libmesh/cell_prism21.h"
17#include "libmesh/cell_pyramid5.h"
18#include "libmesh/cell_pyramid13.h"
19#include "libmesh/cell_pyramid14.h"
20#include "libmesh/cell_pyramid18.h"
21#include "libmesh/cell_tet4.h"
22#include "libmesh/cell_tet10.h"
23#include "libmesh/cell_tet14.h"
24#include "libmesh/cell_hex8.h"
25#include "libmesh/cell_hex20.h"
26#include "libmesh/cell_hex27.h"
27#include "libmesh/face_tri3.h"
28#include "libmesh/face_tri7.h"
29#include "libmesh/face_quad4.h"
30#include "libmesh/face_quad9.h"
31#include "libmesh/point.h"
32#include "libmesh/mesh_tools.h"
33
34// C++ includes
35#include <cmath>
36
38
41{
43 params.addClassDescription("This RevolveGenerator object is designed to revolve a 1D mesh into "
44 "2D, or a 2D mesh into 3D based on an axis.");
45
46 params.addRequiredParam<MeshGeneratorName>("input", "The mesh to revolve");
47
48 params.addRequiredParam<Point>("axis_point", "A point on the axis of revolution");
49
50 params.addRequiredParam<Point>("axis_direction", "The direction of the axis of revolution");
51
52 params.addRangeCheckedParam<std::vector<Real>>(
53 "revolving_angles",
54 "revolving_angles<=360.0 & revolving_angles>0.0",
55 "The angles delineating each azimuthal section of revolution around the axis in degrees");
56
57 params.addParam<std::vector<std::vector<subdomain_id_type>>>(
58 "subdomain_swaps",
59 {},
60 "For each row, every two entries are interpreted as a pair of "
61 "'from' and 'to' to remap the subdomains for that azimuthal section");
62
63 params.addParam<std::vector<std::vector<boundary_id_type>>>(
64 "boundary_swaps",
65 {},
66 "For each row, every two entries are interpreted as a pair of "
67 "'from' and 'to' to remap the boundaries for that elevation");
68
69 params.addParam<std::vector<std::string>>(
70 "elem_integer_names_to_swap",
71 {},
72 "Array of element extra integer names that need to be swapped during revolving.");
73
74 params.addParam<std::vector<std::vector<std::vector<dof_id_type>>>>(
75 "elem_integers_swaps",
76 {},
77 "For each row, every two entries are interpreted as a pair of 'from' and 'to' to remap the "
78 "element extra integer for that elevation. If multiple element extra integers need to be "
79 "swapped, the enties are stacked based on the order provided in "
80 "'elem_integer_names_to_swap' to form the third dimension.");
81
82 params.addParam<boundary_id_type>(
83 "start_boundary",
84 "The boundary ID to set on the starting boundary for a partial revolution.");
85
86 params.addParam<boundary_id_type>(
87 "end_boundary", "The boundary ID to set on the ending boundary for partial revolving.");
88
89 params.addParam<bool>(
90 "clockwise", true, "Revolve clockwise around the axis or not (i.e., counterclockwise)");
91
92 params.addRequiredParam<std::vector<unsigned int>>(
93 "nums_azimuthal_intervals",
94 "List of the numbers of azimuthal interval discretization for each azimuthal section");
95
96 params.addParam<bool>("preserve_volumes",
97 false,
98 "Whether the volume of the revolved mesh is preserving the circular area "
99 "by modifying (expanding) the radius to account for polygonization.");
100
101 params.addParamNamesToGroup("start_boundary end_boundary", "Boundary Assignment");
103 "subdomain_swaps boundary_swaps elem_integer_names_to_swap elem_integers_swaps", "ID Swap");
104
105 return params;
106}
107
109 : PolygonMeshGeneratorBase(parameters),
110 _input(getMesh("input")),
111 _axis_point(getParam<Point>("axis_point")),
112 _axis_direction(getParam<Point>("axis_direction")),
113 _revolving_angles(isParamValid("revolving_angles")
114 ? getParam<std::vector<Real>>("revolving_angles")
115 : std::vector<Real>(1, 360.0)),
116 _subdomain_swaps(getParam<std::vector<std::vector<subdomain_id_type>>>("subdomain_swaps")),
117 _boundary_swaps(getParam<std::vector<std::vector<boundary_id_type>>>("boundary_swaps")),
118 _elem_integer_names_to_swap(getParam<std::vector<std::string>>("elem_integer_names_to_swap")),
119 _elem_integers_swaps(
120 getParam<std::vector<std::vector<std::vector<dof_id_type>>>>("elem_integers_swaps")),
121 _clockwise(getParam<bool>("clockwise")),
122 _nums_azimuthal_intervals(getParam<std::vector<unsigned int>>("nums_azimuthal_intervals")),
123 _preserve_volumes(getParam<bool>("preserve_volumes")),
124 _has_start_boundary(isParamValid("start_boundary")),
125 _start_boundary(isParamValid("start_boundary") ? getParam<boundary_id_type>("start_boundary")
126 : 0),
127 _has_end_boundary(isParamValid("end_boundary")),
128 _end_boundary(isParamValid("end_boundary") ? getParam<boundary_id_type>("end_boundary") : 0),
129 _radius_correction_factor(1.0)
130{
131 if (_revolving_angles.size() != _nums_azimuthal_intervals.size())
132 paramError("nums_azimuthal_intervals",
133 "The number of azimuthal intervals should be the same as the number of revolving "
134 "angles.");
135 if (_subdomain_swaps.size() && (_subdomain_swaps.size() != _nums_azimuthal_intervals.size()))
137 "subdomain_swaps",
138 "If specified, 'subdomain_swaps' must be the same length as 'nums_azimuthal_intervals'.");
139
140 if (_boundary_swaps.size() && (_boundary_swaps.size() != _nums_azimuthal_intervals.size()))
142 "boundary_swaps",
143 "If specified, 'boundary_swaps' must be the same length as 'nums_azimuthal_intervals'.");
144
145 for (const auto & unit_elem_integers_swaps : _elem_integers_swaps)
146 if (unit_elem_integers_swaps.size() != _nums_azimuthal_intervals.size())
147 paramError("elem_integers_swaps",
148 "If specified, each element of 'elem_integers_swaps' must have the same length as "
149 "the length of 'nums_azimuthal_intervals'.");
150
151 if (_elem_integers_swaps.size() &&
153 paramError("elem_integers_swaps",
154 "If specified, 'elem_integers_swaps' must have the same length as the length of "
155 "'elem_integer_names_to_swap'.");
156
158 MooseUtils::absoluteFuzzyEqual(
159 std::accumulate(_revolving_angles.begin(), _revolving_angles.end(), 0), 360.0)
160 ? true
161 : false;
162 if (MooseUtils::absoluteFuzzyGreaterThan(
163 std::accumulate(_revolving_angles.begin(), _revolving_angles.end(), 0), 360.0))
164 paramError("revolving_angles",
165 "The sum of revolving angles should be less than or equal to 360.");
166
169 paramError("full_circle_revolving",
170 "starting or ending boundaries can only be assigned for partial revolving.");
171
172 try
173 {
175 name(), "subdomain_swaps", _subdomain_swaps, _subdomain_swap_pairs);
176 }
177 catch (const MooseException & e)
178 {
179 paramError("subdomain_swaps", e.what());
180 }
181
182 try
183 {
185 name(), "boundary_swaps", _boundary_swaps, _boundary_swap_pairs);
186 }
187 catch (const MooseException & e)
188 {
189 paramError("boundary_swaps", e.what());
190 }
191
192 try
193 {
199 }
200 catch (const MooseException & e)
201 {
202 paramError("elem_integers_swaps", e.what());
203 }
204}
205
206std::unique_ptr<MeshBase>
208{
209 // Note: Inspired by AdvancedExtruderGenerator::generate()
210
211 auto mesh = buildMeshBaseObject();
212
213 // Only works for 1D and 2D input meshes
214 if (_input->mesh_dimension() > 2)
215 paramError("input", "This mesh generator only works for 1D and 2D input meshes.");
216
217 mesh->set_mesh_dimension(_input->mesh_dimension() + 1);
218
219 // Check if the element integer names are existent in the input mesh.
220 for (const auto i : index_range(_elem_integer_names_to_swap))
221 if (_input->has_elem_integer(_elem_integer_names_to_swap[i]))
223 _input->get_elem_integer_index(_elem_integer_names_to_swap[i]));
224 else
225 paramError("elem_integer_names_to_swap",
226 "Element ",
227 i + 1,
228 " of 'elem_integer_names_to_swap' is not a valid extra element integer of the "
229 "input mesh.");
230
231 // prepare for transferring extra element integers from original mesh to the revolved mesh.
232 const unsigned int num_extra_elem_integers = _input->n_elem_integers();
233 std::vector<std::string> id_names;
234
235 for (const auto i : make_range(num_extra_elem_integers))
236 {
237 id_names.push_back(_input->get_elem_integer_name(i));
238 if (!mesh->has_elem_integer(id_names[i]))
239 mesh->add_elem_integer(id_names[i]);
240 }
241
242 // retrieve subdomain/sideset/nodeset name maps
243 const auto & input_subdomain_map = _input->get_subdomain_name_map();
244 const auto & input_sideset_map = _input->get_boundary_info().get_sideset_name_map();
245 const auto & input_nodeset_map = _input->get_boundary_info().get_nodeset_name_map();
246
247 std::unique_ptr<MeshBase> input = std::move(_input);
248
249 // If we're using a distributed mesh... then make sure we don't have any remote elements hanging
250 // around
251 if (!input->is_serial())
252 mesh->delete_remote_elements();
253
254 // Subdomain IDs for on-axis elements must be new
255 if (!input->preparation().has_cached_elem_data)
256 input->cache_elem_data();
257
258 // check that subdomain swap sources exist in the mesh
259 std::set<subdomain_id_type> blocks;
260 input->subdomain_ids(blocks, true);
261 for (const auto & swap_map : _subdomain_swap_pairs)
262 for (const auto & [bid, tbid] : swap_map)
263 {
264 libmesh_ignore(tbid);
265 if (blocks.count(bid) == 0)
266 paramError("subdomain_swaps",
267 "Source subdomain " + std::to_string(bid) + " was not found in the mesh");
268 }
269
270 std::set<subdomain_id_type> subdomain_ids_set;
271 input->subdomain_ids(subdomain_ids_set);
272 const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
273 const subdomain_id_type tri_to_pyramid_subdomain_id_shift =
274 std::max((int)max_subdomain_id, 1) + 1;
275 const subdomain_id_type tri_to_tet_subdomain_id_shift =
276 std::max((int)max_subdomain_id, 1) * 2 + 1;
277 const subdomain_id_type quad_to_prism_subdomain_id_shift = std::max((int)max_subdomain_id, 1) + 1;
278 const subdomain_id_type quad_to_pyramid_subdomain_id_shift =
279 std::max((int)max_subdomain_id, 1) * 2 + 1;
280 const subdomain_id_type quad_to_hi_pyramid_subdomain_id_shift =
281 std::max((int)max_subdomain_id, 1) * 3 + 1;
282 const subdomain_id_type edge_to_tri_subdomain_id_shift = std::max((int)max_subdomain_id, 1) + 1;
283
284 // Get the centroid of the input mesh
285 const auto input_centroid = MooseMeshUtils::meshCentroidCalculator(*input);
286 const Point axis_centroid_cross = (input_centroid - _axis_point).cross(_axis_direction);
287
288 if (MooseUtils::absoluteFuzzyEqual(axis_centroid_cross.norm(), 0.0))
289 mooseError("The input mesh is either across the axis or overlapped with the axis!");
290
291 Real inner_product_1d(0.0);
292 bool inner_product_1d_initialized(false);
293 // record ids of nodes on the axis
294 std::vector<dof_id_type> node_ids_on_axis;
295 for (const auto & node : input->node_ptr_range())
296 {
297 const Point axis_node_cross = (*node - _axis_point).cross(_axis_direction);
298 // if the cross product is zero, then the node is on the axis
299 if (!MooseUtils::absoluteFuzzyEqual(axis_node_cross.norm(), 0.0))
300 {
301 if (MooseUtils::absoluteFuzzyLessThan(axis_node_cross * axis_centroid_cross, 0.0))
302 mooseError("The input mesh is across the axis.");
303 else if (MooseUtils::absoluteFuzzyLessThan(axis_node_cross * axis_centroid_cross,
304 axis_centroid_cross.norm() *
305 axis_node_cross.norm()))
306 mooseError("The input mesh is not in the same plane with the rotation axis.");
307 }
308 else
309 node_ids_on_axis.push_back(node->id());
310
311 // Only for 1D input mesh, we need to check if the axis is perpendicular to the input mesh
312 if (input->mesh_dimension() == 1)
313 {
314 const Real temp_inner_product = (*node - _axis_point) * _axis_direction.unit();
315 if (inner_product_1d_initialized)
316 {
317 if (!MooseUtils::absoluteFuzzyEqual(temp_inner_product, inner_product_1d))
318 mooseError("The 1D input mesh is not perpendicular to the rotation axis.");
319 }
320 else
321 {
322 inner_product_1d_initialized = true;
323 inner_product_1d = temp_inner_product;
324 }
325 }
326 }
327
328 // If there are any on-axis nodes, we need to check if there are any QUAD8 elements with one
329 // vertex on the axis. If so, we need to replace it with a QUAD9 element.
330 if (!node_ids_on_axis.empty())
331 {
332 // Sort the vector for using set_intersection
333 std::sort(node_ids_on_axis.begin(), node_ids_on_axis.end());
334 // For QUAD8 elements with one vertex on the axis, we need to replace it with a QUAD9 element
335 std::set<subdomain_id_type> converted_quad8_subdomain_ids;
336 for (const auto & elem : input->element_ptr_range())
337 {
338 if (elem->type() == QUAD8)
339 {
340 std::vector<dof_id_type> elem_vertex_node_ids;
341 for (unsigned int i = 0; i < 4; i++)
342 {
343 elem_vertex_node_ids.push_back(elem->node_id(i));
344 }
345 std::sort(elem_vertex_node_ids.begin(), elem_vertex_node_ids.end());
346 std::vector<dof_id_type> common_node_ids;
347 std::set_intersection(node_ids_on_axis.begin(),
348 node_ids_on_axis.end(),
349 elem_vertex_node_ids.begin(),
350 elem_vertex_node_ids.end(),
351 std::back_inserter(common_node_ids));
352 // Temporarily shift the subdomain ID to mark the element
353 if (common_node_ids.size() == 1)
354 {
355 // we borrow quad_to_hi_pyramid_subdomain_id_shift here
356 elem->subdomain_id() += quad_to_hi_pyramid_subdomain_id_shift;
357 converted_quad8_subdomain_ids.emplace(elem->subdomain_id());
358 }
359 }
360 }
361 // Convert the recorded subdomains
362 input->all_second_order_range(
363 input->active_subdomain_set_elements_ptr_range(converted_quad8_subdomain_ids));
364 // Restore the subdomain ID; we do not worry about repeated subdomain IDs because those QUAD9
365 // will become PYRAMID and PRISM elements with new shifts
366 for (auto elem : input->active_subdomain_set_elements_ptr_range(converted_quad8_subdomain_ids))
367 elem->subdomain_id() -= quad_to_hi_pyramid_subdomain_id_shift;
368 }
369
370 // We should only record this info after QUAD8->QUAD9 conversion
371 dof_id_type orig_elem = input->n_elem();
372 dof_id_type orig_nodes = input->n_nodes();
373
374#ifdef LIBMESH_ENABLE_UNIQUE_ID
375 // Add the number of original elements as revolving may create two elements per layer for one
376 // original element
377 unique_id_type orig_unique_ids = input->parallel_max_unique_id() + orig_elem;
378#endif
379
380 // get rotation vectors
381 const auto rotation_vectors = rotationVectors(_axis_point, _axis_direction, input_centroid);
382
383 unsigned int order = 1;
384
385 BoundaryInfo & boundary_info = mesh->get_boundary_info();
386 const BoundaryInfo & input_boundary_info = input->get_boundary_info();
387
388 const unsigned int total_num_azimuthal_intervals =
389 std::accumulate(_nums_azimuthal_intervals.begin(), _nums_azimuthal_intervals.end(), 0);
390 // We know a priori how many elements we'll need
391 // In the worst case, all quad elements will become two elements per layer
392 mesh->reserve_elem(total_num_azimuthal_intervals * orig_elem * 2);
393 const dof_id_type elem_id_shift = total_num_azimuthal_intervals * orig_elem;
394
395 // Look for higher order elements which introduce an extra layer
396 std::set<ElemType> higher_orders = {EDGE3, TRI6, TRI7, QUAD8, QUAD9};
397 std::vector<ElemType> types;
398 MeshTools::elem_types(*input, types);
399 for (const auto elem_type : types)
400 if (higher_orders.count(elem_type))
401 order = 2;
402 mesh->comm().max(order);
403
404 // Collect azimuthal angles and use them to calculate the correction factor if applicable
405 std::vector<Real> azi_array;
406 for (const auto & i : index_range(_revolving_angles))
407 {
408 const Real section_start_angle =
409 azi_array.empty() ? 0.0 : (azi_array.back() + _unit_angles.back());
411 for (unsigned int j = 0; j < _nums_azimuthal_intervals[i] * order; j++)
412 azi_array.push_back(section_start_angle + _unit_angles.back() * (Real)j);
413 }
415 {
417 azi_array, _full_circle_revolving, order);
418
419 // In the meanwhile, modify the input mesh for radius correction if applicable
420 for (const auto & node : input->node_ptr_range())
421 nodeModification(*node);
422 }
423
424 mesh->reserve_nodes(
425 (order * total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
426 orig_nodes);
427
428 // Container to catch the boundary IDs handed back by the BoundaryInfo object
429 std::vector<boundary_id_type> ids_to_copy;
430
431 Point old_distance;
432 Point current_distance;
433 if (!_clockwise)
434 std::transform(_unit_angles.begin(),
435 _unit_angles.end(),
436 _unit_angles.begin(),
437 [](auto & c) { return c * (-1.0) * M_PI / 180.0; });
438 else
439 std::transform(_unit_angles.begin(),
440 _unit_angles.end(),
441 _unit_angles.begin(),
442 [](auto & c) { return c * M_PI / 180.0; });
443 std::vector<dof_id_type> nodes_on_axis;
444
445 for (const auto & node : input->node_ptr_range())
446 {
447 // Calculate the radius and corresponding center point on the rotation axis
448 // If the radius is 0, then the node is on the axis
449 const auto radius_and_center = getRotationCenterAndRadius(*node, _axis_point, _axis_direction);
450 const bool isOnAxis = MooseUtils::absoluteFuzzyEqual(radius_and_center.first, 0.0);
451 if (isOnAxis)
452 {
453 nodes_on_axis.push_back(node->id());
454 }
455
456 unsigned int current_node_layer = 0;
457
458 old_distance.zero();
459
460 const unsigned int num_rotations = _revolving_angles.size();
461 for (unsigned int e = 0; e < num_rotations; e++)
462 {
463 auto num_layers = _nums_azimuthal_intervals[e];
464
465 auto angle = _unit_angles[e];
466
467 const auto base_angle =
468 std::accumulate(_revolving_angles.begin(), _revolving_angles.begin() + e, 0.0) / 180.0 *
469 M_PI;
470
471 for (unsigned int k = 0;
472 k < order * num_layers + (e == 0 ? 1 : 0) -
473 (e == num_rotations - 1 ? (unsigned int)_full_circle_revolving : 0);
474 ++k)
475 {
476 bool is_node_created(false);
477 if (!isOnAxis)
478 {
479 // For the first layer we don't need to move
480 if (e == 0 && k == 0)
481 current_distance.zero();
482 else
483 {
484 auto layer_index = (k - (e == 0 ? 1 : 0)) + 1;
485
486 // Calculate the rotation angle in XY Plane
487 const Point vector_xy =
488 Point(-2.0 * radius_and_center.first *
489 std::sin((base_angle + angle * (Real)layer_index) / 2.0) *
490 std::sin((base_angle + angle * (Real)layer_index) / 2.0),
491 2.0 * radius_and_center.first *
492 std::sin((base_angle + angle * (Real)layer_index) / 2.0) *
493 std::cos((base_angle + angle * (Real)layer_index) / 2.0),
494 0.0);
495 current_distance = Point(rotation_vectors[0] * vector_xy,
496 rotation_vectors[1] * vector_xy,
497 rotation_vectors[2] * vector_xy);
498 }
499
500 is_node_created = true;
501 }
502 else if (e == 0 && k == 0)
503 {
504 // On-axis nodes are only added once
505 current_distance.zero();
506 is_node_created = true;
507 }
508
509 if (is_node_created)
510 {
511 Node * new_node = mesh->add_point(*node + current_distance,
512 node->id() + (current_node_layer * orig_nodes),
513 node->processor_id());
514#ifdef LIBMESH_ENABLE_UNIQUE_ID
515 // Let's give the base nodes of the revolved mesh the same
516 // unique_ids as the source mesh, in case anyone finds that
517 // a useful map to preserve.
518 const unique_id_type uid =
519 (current_node_layer == 0)
520 ? node->unique_id()
521 : (orig_unique_ids + (current_node_layer - 1) * (orig_nodes + orig_elem * 2) +
522 node->id());
523 new_node->set_unique_id(uid);
524#endif
525
526 input_boundary_info.boundary_ids(node, ids_to_copy);
527 if (_boundary_swap_pairs.empty())
528 boundary_info.add_node(new_node, ids_to_copy);
529 else
530 for (const auto & id_to_copy : ids_to_copy)
531 boundary_info.add_node(new_node,
532 _boundary_swap_pairs[e].count(id_to_copy)
533 ? _boundary_swap_pairs[e][id_to_copy]
534 : id_to_copy);
535 }
536
537 current_node_layer++;
538 }
539 }
540 }
541
542 for (const auto & elem : input->element_ptr_range())
543 {
544 const ElemType etype = elem->type();
545
546 // revolving currently only works on coarse meshes
547 mooseAssert(!elem->parent(), "RevolveGenerator only works on coarse meshes.");
548
549 unsigned int current_layer = 0;
550
551 const unsigned int num_rotations = _revolving_angles.size();
552
553 for (unsigned int e = 0; e < num_rotations; e++)
554 {
555 auto num_layers = _nums_azimuthal_intervals[e];
556
557 for (unsigned int k = 0; k < num_layers; ++k)
558 {
559 std::unique_ptr<Elem> new_elem;
560 std::unique_ptr<Elem> new_elem_1;
561 bool is_flipped(false);
562 // In some cases, two elements per layer are generated by revolving one element. So we
563 // reserve an additional flag for the potential second element.
564 bool is_flipped_additional(false);
565 dof_id_type axis_node_case(-1);
566 std::vector<std::pair<dof_id_type, dof_id_type>> side_pairs;
567 switch (etype)
568 {
569 case EDGE2:
570 {
571 // Possible scenarios:
572 // 1. None of the nodes are on the axis
573 // Then a quad4 element is created
574 // 2. One of the nodes is on the axis
575 // Then a tri3 element is created
576 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
577 if (nodes_cates.first.empty())
578 {
580 elem,
581 mesh,
582 new_elem,
583 current_layer,
584 orig_nodes,
585 total_num_azimuthal_intervals,
586 side_pairs,
587 is_flipped);
588 }
589 else
590 {
591 createTRIfromEDGE(nodes_cates,
592 TRI3,
593 elem,
594 mesh,
595 new_elem,
596 current_layer,
597 orig_nodes,
598 total_num_azimuthal_intervals,
599 side_pairs,
600 axis_node_case,
601 is_flipped);
602 }
603 break;
604 }
605 case EDGE3:
606 {
607 // Possible scenarios:
608 // 1. None of the nodes are on the axis
609 // Then a QUAD9 element is created
610 // 2. One of the nodes is on the axis
611 // Then a TRI7 element is created
612 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
613 if (nodes_cates.first.empty())
614 {
616 elem,
617 mesh,
618 new_elem,
619 current_layer,
620 orig_nodes,
621 total_num_azimuthal_intervals,
622 side_pairs,
623 is_flipped);
624 }
625 else
626 {
627 createTRIfromEDGE(nodes_cates,
628 TRI7,
629 elem,
630 mesh,
631 new_elem,
632 current_layer,
633 orig_nodes,
634 total_num_azimuthal_intervals,
635 side_pairs,
636 axis_node_case,
637 is_flipped);
638 }
639 break;
640 }
641 case TRI3:
642 {
643 // Possible scenarios:
644 // 1. None of the nodes are on the axis
645 // Then a prism6 element is created
646 // 2. One of the nodes is on the axis
647 // Then a pyramid5 element is created
648 // 3. Two of the nodes are on the axis
649 // Then a tet4 element is created
650 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
651 if (nodes_cates.first.empty())
652 {
653 createPRISMfromTRI(PRISM6,
654 elem,
655 mesh,
656 new_elem,
657 current_layer,
658 orig_nodes,
659 total_num_azimuthal_intervals,
660 side_pairs,
661 is_flipped);
662 }
663 else if (nodes_cates.first.size() == 1)
664 {
665 createPYRAMIDfromTRI(nodes_cates,
666 PYRAMID5,
667 elem,
668 mesh,
669 new_elem,
670 current_layer,
671 orig_nodes,
672 total_num_azimuthal_intervals,
673 side_pairs,
674 axis_node_case,
675 is_flipped);
676 }
677 else if (nodes_cates.first.size() == 2)
678 {
679 createTETfromTRI(nodes_cates,
680 TET4,
681 elem,
682 mesh,
683 new_elem,
684 current_layer,
685 orig_nodes,
686 total_num_azimuthal_intervals,
687 side_pairs,
688 axis_node_case,
689 is_flipped);
690 }
691 else
692 mooseError("A degenerate TRI3 elements overlapped with the rotation axis cannot be "
693 "revolved.");
694
695 break;
696 }
697 case TRI6:
698 {
699 // Possible scenarios:
700 // 1. None of the nodes are on the axis
701 // Then a prism18 element is created
702 // 2. One of the nodes is on the axis
703 // Then a pyramid13 element is created
704 // 3. Three of the nodes are on the axis
705 // Then a tet10 element is created
706 // NOTE: We do not support two nodes on the axis for tri6 elements
707 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
708 if (nodes_cates.first.empty())
709 {
710 createPRISMfromTRI(PRISM18,
711 elem,
712 mesh,
713 new_elem,
714 current_layer,
715 orig_nodes,
716 total_num_azimuthal_intervals,
717 side_pairs,
718 is_flipped);
719 }
720 else if (nodes_cates.first.size() == 1)
721 {
722 createPYRAMIDfromTRI(nodes_cates,
723 PYRAMID13,
724 elem,
725 mesh,
726 new_elem,
727 current_layer,
728 orig_nodes,
729 total_num_azimuthal_intervals,
730 side_pairs,
731 axis_node_case,
732 is_flipped);
733 }
734 else if (nodes_cates.first.size() == 3)
735 {
736 createTETfromTRI(nodes_cates,
737 TET10,
738 elem,
739 mesh,
740 new_elem,
741 current_layer,
742 orig_nodes,
743 total_num_azimuthal_intervals,
744 side_pairs,
745 axis_node_case,
746 is_flipped);
747 }
748 else
750 "You either have a degenerate TRI6 element, or the mid-point of the "
751 "on-axis edge is not colinear with the two vertices, which is not supported.");
752 break;
753 }
754 case TRI7:
755 {
756 // Possible scenarios:
757 // 1. None of the nodes are on the axis
758 // Then a prism21 element is created
759 // 2. One of the nodes is on the axis
760 // Then a pyramid18 element is created
761 // 3. Three of the nodes are on the axis
762 // Then a tet14 element is created
763 // NOTE: We do not support two nodes on the axis for tri7 elements
764 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
765 if (nodes_cates.first.empty())
766 {
767 createPRISMfromTRI(PRISM21,
768 elem,
769 mesh,
770 new_elem,
771 current_layer,
772 orig_nodes,
773 total_num_azimuthal_intervals,
774 side_pairs,
775 is_flipped);
776 }
777 else if (nodes_cates.first.size() == 1)
778 {
779 createPYRAMIDfromTRI(nodes_cates,
780 PYRAMID18,
781 elem,
782 mesh,
783 new_elem,
784 current_layer,
785 orig_nodes,
786 total_num_azimuthal_intervals,
787 side_pairs,
788 axis_node_case,
789 is_flipped);
790 }
791 else if (nodes_cates.first.size() == 3)
792 {
793 createTETfromTRI(nodes_cates,
794 TET14,
795 elem,
796 mesh,
797 new_elem,
798 current_layer,
799 orig_nodes,
800 total_num_azimuthal_intervals,
801 side_pairs,
802 axis_node_case,
803 is_flipped);
804 }
805 else
806 mooseError("You either have a degenerate TRI6 element, or the mid-point of the "
807 "on-axis edge of the TRI6 element is not colinear with the two vertices, "
808 "which is not supported.");
809 break;
810 }
811 case QUAD4:
812 {
813 // Possible scenarios:
814 // 1. None of the nodes are on the axis
815 // Then a hex8 element is created
816 // 2. One of the nodes is on the axis
817 // Then a pyramid5 element and a prism6 element are created
818 // 3. Two of the nodes are on the axis
819 // Then a prism6 is created
820 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
821 if (nodes_cates.first.empty())
822 {
824 elem,
825 mesh,
826 new_elem,
827 current_layer,
828 orig_nodes,
829 total_num_azimuthal_intervals,
830 side_pairs,
831 is_flipped);
832 }
833 else if (nodes_cates.first.size() == 1)
834 {
835 createPYRAMIDPRISMfromQUAD(nodes_cates,
836 PYRAMID5,
837 PRISM6,
838 elem,
839 mesh,
840 new_elem,
841 new_elem_1,
842 current_layer,
843 orig_nodes,
844 total_num_azimuthal_intervals,
845 side_pairs,
846 axis_node_case,
847 is_flipped,
848 is_flipped_additional);
849 }
850 else if (nodes_cates.first.size() == 2)
851 {
852 createPRISMfromQUAD(nodes_cates,
853 PRISM6,
854 elem,
855 mesh,
856 new_elem,
857 current_layer,
858 orig_nodes,
859 total_num_azimuthal_intervals,
860 side_pairs,
861 axis_node_case,
862 is_flipped);
863 }
864
865 else
866 mooseError("Degenerate QUAD4 element with 3 or more aligned nodes cannot be "
867 "azimuthally revolved");
868
869 break;
870 }
871 case QUAD8:
872 {
873 // Possible scenarios:
874 // 1. None of the nodes are on the axis
875 // Then a hex20 element is created
876 // 2. One of the nodes is on the axis
877 // In that case, it is already converted to a QUAD9 element before,
878 // SO we do not need to worry about this case
879 // 3. Three of the nodes are on the axis
880 // Then a prism15 is created
881 // NOTE: We do not support two nodes on the axis for quad8 elements
882 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
883 if (nodes_cates.first.empty())
884 {
885 createHEXfromQUAD(HEX20,
886 elem,
887 mesh,
888 new_elem,
889 current_layer,
890 orig_nodes,
891 total_num_azimuthal_intervals,
892 side_pairs,
893 is_flipped);
894 }
895 else if (nodes_cates.first.size() == 3)
896 {
897 createPRISMfromQUAD(nodes_cates,
898 PRISM15,
899 elem,
900 mesh,
901 new_elem,
902 current_layer,
903 orig_nodes,
904 total_num_azimuthal_intervals,
905 side_pairs,
906 axis_node_case,
907 is_flipped);
908 }
909 else
910 mooseError("You either have a degenerate QUAD8 element, or the mid-point of the "
911 "on-axis edge of the QUAD8 element is not colinear with the two vertices, "
912 "which is not supported.");
913
914 break;
915 }
916 case QUAD9:
917 {
918 // Possible scenarios:
919 // 1. None of the nodes are on the axis
920 // Then a hex27 element is created
921 // 2. One of the nodes is on the axis
922 // Then a pyramid14 element and a prism18 element are created
923 // 3. Two of the nodes are on the axis
924 // Then a prism18 is created
925 // (we do not create prism20/21 here just to make prism18 the only possible prism
926 // elements for simplicity)
927 const auto nodes_cates = onAxisNodesIdentifier(*elem, nodes_on_axis);
928 if (nodes_cates.first.empty())
929 {
930 createHEXfromQUAD(HEX27,
931 elem,
932 mesh,
933 new_elem,
934 current_layer,
935 orig_nodes,
936 total_num_azimuthal_intervals,
937 side_pairs,
938 is_flipped);
939 }
940 else if (nodes_cates.first.size() == 1)
941 {
942 createPYRAMIDPRISMfromQUAD(nodes_cates,
943 PYRAMID14,
944 PRISM18,
945 elem,
946 mesh,
947 new_elem,
948 new_elem_1,
949 current_layer,
950 orig_nodes,
951 total_num_azimuthal_intervals,
952 side_pairs,
953 axis_node_case,
954 is_flipped,
955 is_flipped_additional);
956 }
957 else if (nodes_cates.first.size() == 3)
958 {
959 createPRISMfromQUAD(nodes_cates,
960 PRISM18,
961 elem,
962 mesh,
963 new_elem,
964 current_layer,
965 orig_nodes,
966 total_num_azimuthal_intervals,
967 side_pairs,
968 axis_node_case,
969 is_flipped);
970 }
971 else
972 mooseError("You either have a degenerate QUAD9 element, or the mid-point of the "
973 "on-axis edge of the QUAD9 element is not colinear with the two vertices, "
974 "which is not supported.");
975 break;
976 }
977 default:
978 mooseError("The input mesh contains unsupported element type(s).");
979 }
980 new_elem->set_id(elem->id() + (current_layer * orig_elem));
981 new_elem->processor_id() = elem->processor_id();
982 if (new_elem_1)
983 {
984 new_elem_1->set_id(elem->id() + (current_layer * orig_elem) + elem_id_shift);
985 new_elem_1->processor_id() = elem->processor_id();
986 }
987
988#ifdef LIBMESH_ENABLE_UNIQUE_ID
989 // Let's give the base elements of the revolved mesh the same
990 // unique_ids as the source mesh, in case anyone finds that
991 // a useful map to preserve.
992 const unique_id_type uid =
993 (current_layer == 0)
994 ? elem->unique_id()
995 : (orig_unique_ids + (current_layer - 1) * (orig_nodes + orig_elem * 2) +
996 orig_nodes + elem->id());
997
998 new_elem->set_unique_id(uid);
999
1000 // Special case for extra elements
1001 if (new_elem_1)
1002 {
1003 const unique_id_type uid_1 =
1004 (current_layer == 0)
1005 ? (elem->id() + orig_unique_ids - orig_elem)
1006 : (orig_unique_ids + (current_layer - 1) * (orig_nodes + orig_elem * 2) +
1007 orig_nodes + orig_elem + elem->id());
1008
1009 new_elem_1->set_unique_id(uid_1);
1010 }
1011#endif
1012
1013 // maintain the subdomain_id
1014 switch (etype)
1015 {
1016 case EDGE2:
1017 switch (new_elem->type())
1018 {
1019 case QUAD4:
1020 new_elem->subdomain_id() = elem->subdomain_id();
1021 break;
1022 case TRI3:
1023 new_elem->subdomain_id() = edge_to_tri_subdomain_id_shift + elem->subdomain_id();
1024 break;
1025 default:
1026 mooseAssert(false,
1027 "impossible element type generated by revolving an EDGE2 element");
1028 }
1029 break;
1030 case EDGE3:
1031 switch (new_elem->type())
1032 {
1033 case QUAD9:
1034 new_elem->subdomain_id() = elem->subdomain_id();
1035 break;
1036 case TRI7:
1037 new_elem->subdomain_id() = edge_to_tri_subdomain_id_shift + elem->subdomain_id();
1038 break;
1039 default:
1040 mooseAssert(false,
1041 "impossible element type generated by revolving an EDGE3 element");
1042 }
1043 break;
1044 case TRI3:
1045 switch (new_elem->type())
1046 {
1047 case PRISM6:
1048 new_elem->subdomain_id() = elem->subdomain_id();
1049 break;
1050 case PYRAMID5:
1051 new_elem->subdomain_id() = tri_to_pyramid_subdomain_id_shift + elem->subdomain_id();
1052 break;
1053 case TET4:
1054 new_elem->subdomain_id() = tri_to_tet_subdomain_id_shift + elem->subdomain_id();
1055 break;
1056 default:
1057 mooseAssert(false, "impossible element type generated by revolving a TRI3 element");
1058 }
1059 break;
1060 case TRI6:
1061 switch (new_elem->type())
1062 {
1063 case PRISM18:
1064 new_elem->subdomain_id() = elem->subdomain_id();
1065 break;
1066 case PYRAMID13:
1067 new_elem->subdomain_id() = tri_to_pyramid_subdomain_id_shift + elem->subdomain_id();
1068 break;
1069 case TET10:
1070 new_elem->subdomain_id() = tri_to_tet_subdomain_id_shift + elem->subdomain_id();
1071 break;
1072 default:
1073 mooseAssert(false, "impossible element type generated by revolving a TRI6 element");
1074 }
1075 break;
1076 case TRI7:
1077 switch (new_elem->type())
1078 {
1079 case PRISM21:
1080 new_elem->subdomain_id() = elem->subdomain_id();
1081 break;
1082 case PYRAMID18:
1083 new_elem->subdomain_id() = tri_to_pyramid_subdomain_id_shift + elem->subdomain_id();
1084 break;
1085 case TET14:
1086 new_elem->subdomain_id() = tri_to_tet_subdomain_id_shift + elem->subdomain_id();
1087 break;
1088 default:
1089 mooseAssert(false, "impossible element type generated by revolving a TRI7 element");
1090 }
1091 break;
1092 case QUAD4:
1093 switch (new_elem->type())
1094 {
1095 case HEX8:
1096 new_elem->subdomain_id() = elem->subdomain_id();
1097 break;
1098 case PRISM6:
1099 new_elem->subdomain_id() = quad_to_prism_subdomain_id_shift + elem->subdomain_id();
1100 break;
1101 case PYRAMID5:
1102 new_elem->subdomain_id() =
1103 quad_to_pyramid_subdomain_id_shift + elem->subdomain_id();
1104 new_elem_1->subdomain_id() =
1105 quad_to_prism_subdomain_id_shift + elem->subdomain_id();
1106 break;
1107 default:
1108 mooseAssert(false,
1109 "impossible element type generated by revolving a QUAD4 element");
1110 }
1111 break;
1112 case QUAD8:
1113 switch (new_elem->type())
1114 {
1115 case HEX20:
1116 new_elem->subdomain_id() = elem->subdomain_id();
1117 break;
1118 case PRISM15:
1119 new_elem->subdomain_id() = quad_to_prism_subdomain_id_shift + elem->subdomain_id();
1120 break;
1121 default:
1122 mooseAssert(false,
1123 "impossible element type generated by revolving a QUAD8 element");
1124 }
1125 break;
1126 case QUAD9:
1127 switch (new_elem->type())
1128 {
1129 case HEX27:
1130 new_elem->subdomain_id() = elem->subdomain_id();
1131 break;
1132 case PRISM18:
1133 new_elem->subdomain_id() =
1134 quad_to_hi_pyramid_subdomain_id_shift + elem->subdomain_id();
1135 break;
1136 case PYRAMID14:
1137 new_elem->subdomain_id() =
1138 quad_to_pyramid_subdomain_id_shift + elem->subdomain_id();
1139 new_elem_1->subdomain_id() =
1140 quad_to_hi_pyramid_subdomain_id_shift + elem->subdomain_id();
1141 break;
1142 default:
1143 mooseAssert(false,
1144 "impossible element type generated by revolving a QUAD9 element");
1145 }
1146 break;
1147 default:
1148 mooseAssert(false,
1149 "The input mesh contains unsupported element type(s), which should have "
1150 "been checked in prior steps in this code.");
1151 }
1152
1153 if (_subdomain_swap_pairs.size())
1154 {
1155 auto & revolving_swap_pairs = _subdomain_swap_pairs[e];
1156
1157 auto new_id_it = revolving_swap_pairs.find(elem->subdomain_id());
1158
1159 if (new_id_it != revolving_swap_pairs.end())
1160 {
1161 new_elem->subdomain_id() =
1162 new_elem->subdomain_id() - elem->subdomain_id() + new_id_it->second;
1163 if (new_elem_1)
1164 new_elem_1->subdomain_id() =
1165 new_elem_1->subdomain_id() - elem->subdomain_id() + new_id_it->second;
1166 }
1167 }
1168
1169 Elem * added_elem = mesh->add_elem(std::move(new_elem));
1170 Elem * added_elem_1 = NULL;
1171
1172 if (new_elem_1)
1173 added_elem_1 = mesh->add_elem(std::move(new_elem_1));
1174
1175 // maintain extra integers
1176 for (unsigned int i = 0; i < num_extra_elem_integers; i++)
1177 {
1178 added_elem->set_extra_integer(i, elem->get_extra_integer(i));
1179 if (added_elem_1)
1180 added_elem_1->set_extra_integer(i, elem->get_extra_integer(i));
1181 }
1182
1183 if (_elem_integers_swap_pairs.size())
1184 {
1185 for (unsigned int i = 0; i < _elem_integer_indices_to_swap.size(); i++)
1186 {
1187 auto & elevation_extra_swap_pairs =
1189
1190 auto new_extra_id_it = elevation_extra_swap_pairs.find(
1191 elem->get_extra_integer(_elem_integer_indices_to_swap[i]));
1192
1193 if (new_extra_id_it != elevation_extra_swap_pairs.end())
1194 {
1195 added_elem->set_extra_integer(_elem_integer_indices_to_swap[i],
1196 new_extra_id_it->second);
1197 if (added_elem_1)
1198 added_elem_1->set_extra_integer(_elem_integer_indices_to_swap[i],
1199 new_extra_id_it->second);
1200 }
1201 }
1202 }
1203
1204 // Copy any old boundary ids on all sides
1205 for (auto s : elem->side_index_range())
1206 {
1207 input_boundary_info.boundary_ids(elem, s, ids_to_copy);
1208 std::vector<boundary_id_type> ids_to_copy_swapped;
1209 if (_boundary_swap_pairs.empty())
1210 ids_to_copy_swapped = ids_to_copy;
1211 else
1212 for (const auto & id_to_copy : ids_to_copy)
1213 ids_to_copy_swapped.push_back(_boundary_swap_pairs[e].count(id_to_copy)
1214 ? _boundary_swap_pairs[e][id_to_copy]
1215 : id_to_copy);
1216
1217 switch (etype)
1218 {
1219 case EDGE2:
1220 switch (added_elem->type())
1221 {
1222 case QUAD4:
1223 boundary_info.add_side(
1224 added_elem, cast_int<unsigned short>(s == 0 ? 3 : 1), ids_to_copy_swapped);
1225 break;
1226 case TRI3:
1227 if (s != axis_node_case)
1228 boundary_info.add_side(
1229 added_elem, cast_int<unsigned short>(s), ids_to_copy_swapped);
1230 break;
1231 default:
1232 mooseAssert(false,
1233 "impossible element type generated by revolving an EDGE2 element");
1234 }
1235 break;
1236 case EDGE3:
1237 switch (added_elem->type())
1238 {
1239 case QUAD9:
1240 boundary_info.add_side(
1241 added_elem, cast_int<unsigned short>(s == 0 ? 3 : 1), ids_to_copy_swapped);
1242 break;
1243 case TRI7:
1244 if (s != axis_node_case)
1245 boundary_info.add_side(
1246 added_elem, cast_int<unsigned short>(s), ids_to_copy_swapped);
1247 break;
1248 default:
1249 mooseAssert(false,
1250 "impossible element type generated by revolving an EDGE3 element");
1251 }
1252 break;
1253 case TRI3:
1254 switch (added_elem->type())
1255 {
1256 case PRISM6:
1257 boundary_info.add_side(
1258 added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
1259 break;
1260 case PYRAMID5:
1261 if ((s + 3 - axis_node_case) % 3 == 0)
1262 boundary_info.add_side(
1263 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1264 else if ((s + 3 - axis_node_case) % 3 == 1)
1265 boundary_info.add_side(
1266 added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
1267 else
1268 boundary_info.add_side(
1269 added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
1270 break;
1271 case TET4:
1272 if ((s + 3 - axis_node_case) % 3 == 0)
1273 boundary_info.add_side(
1274 added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
1275 else if ((s + 3 - axis_node_case) % 3 == 2)
1276 boundary_info.add_side(
1277 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1278 break;
1279 default:
1280 mooseAssert(false,
1281 "impossible element type generated by revolving a TRI3 element");
1282 }
1283 break;
1284 case TRI6:
1285 switch (added_elem->type())
1286 {
1287 case PRISM18:
1288 boundary_info.add_side(
1289 added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
1290 break;
1291 case PYRAMID13:
1292 if ((s + 3 - axis_node_case) % 3 == 0)
1293 boundary_info.add_side(
1294 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1295 else if ((s + 3 - axis_node_case) % 3 == 1)
1296 boundary_info.add_side(
1297 added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
1298 else
1299 boundary_info.add_side(
1300 added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
1301 break;
1302 case TET10:
1303 if ((s + 3 - axis_node_case) % 3 == 0)
1304 boundary_info.add_side(
1305 added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
1306 else if ((s + 3 - axis_node_case) % 3 == 2)
1307 boundary_info.add_side(
1308 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1309 break;
1310 default:
1311 mooseAssert(false,
1312 "impossible element type generated by revolving a TRI6 element");
1313 }
1314 break;
1315 case TRI7:
1316 switch (added_elem->type())
1317 {
1318 case PRISM21:
1319 boundary_info.add_side(
1320 added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
1321 break;
1322 case PYRAMID18:
1323 if ((s + 3 - axis_node_case) % 3 == 0)
1324 boundary_info.add_side(
1325 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1326 else if ((s + 3 - axis_node_case) % 3 == 1)
1327 boundary_info.add_side(
1328 added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
1329 else
1330 boundary_info.add_side(
1331 added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
1332 break;
1333 case TET14:
1334 if ((s + 3 - axis_node_case) % 3 == 0)
1335 boundary_info.add_side(
1336 added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
1337 else if ((s + 3 - axis_node_case) % 3 == 2)
1338 boundary_info.add_side(
1339 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1340 break;
1341 default:
1342 mooseAssert(false,
1343 "impossible element type generated by revolving a TRI7 element");
1344 }
1345 break;
1346 case QUAD4:
1347 switch (added_elem->type())
1348 {
1349 case HEX8:
1350 boundary_info.add_side(
1351 added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
1352 break;
1353 case PRISM6:
1354 if ((s + 4 - axis_node_case) % 4 == 1)
1355 boundary_info.add_side(
1356 added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
1357 else if ((s + 4 - axis_node_case) % 4 == 2)
1358 boundary_info.add_side(
1359 added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
1360 else if ((s + 4 - axis_node_case) % 4 == 3)
1361 boundary_info.add_side(
1362 added_elem, cast_int<unsigned short>(0), ids_to_copy_swapped);
1363 break;
1364 case PYRAMID5:
1365 if ((s + 4 - axis_node_case) % 4 == 3)
1366 boundary_info.add_side(
1367 added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
1368 else if ((s + 4 - axis_node_case) % 4 == 0)
1369 boundary_info.add_side(
1370 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1371 else if ((s + 4 - axis_node_case) % 4 == 1)
1372 boundary_info.add_side(
1373 added_elem_1, cast_int<unsigned short>(3), ids_to_copy_swapped);
1374 else
1375 boundary_info.add_side(
1376 added_elem_1, cast_int<unsigned short>(2), ids_to_copy_swapped);
1377 break;
1378 default:
1379 mooseAssert(false,
1380 "impossible element type generated by revolving a QUAD4 element");
1381 }
1382 break;
1383 case QUAD8:
1384 switch (added_elem->type())
1385 {
1386 case HEX20:
1387 boundary_info.add_side(
1388 added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
1389 break;
1390 case PRISM15:
1391 if ((s + 4 - axis_node_case) % 4 == 1)
1392 boundary_info.add_side(
1393 added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
1394 else if ((s + 4 - axis_node_case) % 4 == 2)
1395 boundary_info.add_side(
1396 added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
1397 else if ((s + 4 - axis_node_case) % 4 == 3)
1398 boundary_info.add_side(
1399 added_elem, cast_int<unsigned short>(0), ids_to_copy_swapped);
1400 break;
1401 default:
1402 mooseAssert(false,
1403 "impossible element type generated by revolving a QUAD8 element");
1404 }
1405 break;
1406 case QUAD9:
1407 switch (added_elem->type())
1408 {
1409 case HEX27:
1410 boundary_info.add_side(
1411 added_elem, cast_int<unsigned short>(s + 1), ids_to_copy_swapped);
1412 break;
1413 case PRISM18:
1414 if ((s + 4 - axis_node_case) % 4 == 1)
1415 boundary_info.add_side(
1416 added_elem, cast_int<unsigned short>(4), ids_to_copy_swapped);
1417 else if ((s + 4 - axis_node_case) % 4 == 2)
1418 boundary_info.add_side(
1419 added_elem, cast_int<unsigned short>(2), ids_to_copy_swapped);
1420 else if ((s + 4 - axis_node_case) % 4 == 3)
1421 boundary_info.add_side(
1422 added_elem, cast_int<unsigned short>(0), ids_to_copy_swapped);
1423 break;
1424 case PYRAMID14:
1425 if ((s + 4 - axis_node_case) % 4 == 3)
1426 boundary_info.add_side(
1427 added_elem, cast_int<unsigned short>(1), ids_to_copy_swapped);
1428 else if ((s + 4 - axis_node_case) % 4 == 0)
1429 boundary_info.add_side(
1430 added_elem, cast_int<unsigned short>(3), ids_to_copy_swapped);
1431 else if ((s + 4 - axis_node_case) % 4 == 1)
1432 boundary_info.add_side(
1433 added_elem_1, cast_int<unsigned short>(3), ids_to_copy_swapped);
1434 else
1435 boundary_info.add_side(
1436 added_elem_1, cast_int<unsigned short>(2), ids_to_copy_swapped);
1437 break;
1438 default:
1439 mooseAssert(false,
1440 "impossible element type generated by revolving a QUAD9 element");
1441 }
1442 break;
1443 default:
1444 mooseAssert(false,
1445 "The input mesh contains unsupported element type(s), which should have "
1446 "been checked in prior steps in this code.");
1447 }
1448 }
1449
1450 if (current_layer == 0 && _has_start_boundary)
1451 {
1452 boundary_info.add_side(
1453 added_elem, is_flipped ? side_pairs[0].second : side_pairs[0].first, _start_boundary);
1454 if (side_pairs.size() > 1)
1455 boundary_info.add_side(added_elem_1,
1456 is_flipped_additional ? side_pairs[1].second
1457 : side_pairs[1].first,
1459 }
1460
1461 if (current_layer == num_layers - 1 && _has_end_boundary)
1462 {
1463 boundary_info.add_side(
1464 added_elem, is_flipped ? side_pairs[0].first : side_pairs[0].second, _end_boundary);
1465 if (side_pairs.size() > 1)
1466 boundary_info.add_side(added_elem_1,
1467 is_flipped_additional ? side_pairs[1].first
1468 : side_pairs[1].second,
1470 }
1471 current_layer++;
1472 }
1473 }
1474 }
1475
1476#ifdef LIBMESH_ENABLE_UNIQUE_ID
1477 // Update the value of next_unique_id based on newly created nodes and elements
1478 // Note: the calculation here is quite conservative to ensure uniqueness
1479 unsigned int total_new_node_layers = total_num_azimuthal_intervals * order;
1480 unsigned int new_unique_ids = orig_unique_ids + (total_new_node_layers - 1) * orig_elem * 2 +
1481 total_new_node_layers * orig_nodes;
1482 mesh->set_next_unique_id(new_unique_ids);
1483#endif
1484
1485 // Copy all the subdomain/sideset/nodeset name maps to the revolved mesh
1486 if (!input_subdomain_map.empty())
1487 mesh->set_subdomain_name_map().insert(input_subdomain_map.begin(), input_subdomain_map.end());
1488 if (!input_sideset_map.empty())
1489 mesh->get_boundary_info().set_sideset_name_map().insert(input_sideset_map.begin(),
1490 input_sideset_map.end());
1491 if (!input_nodeset_map.empty())
1492 mesh->get_boundary_info().set_nodeset_name_map().insert(input_nodeset_map.begin(),
1493 input_nodeset_map.end());
1494
1495 mesh->remove_orphaned_nodes();
1496 mesh->renumber_nodes_and_elements();
1497 mesh->unset_is_prepared();
1498
1499 return mesh;
1500}
1501
1502std::pair<Real, Point>
1504 const Point & p_axis,
1505 const Point & dir_axis) const
1506{
1507 // First use point product to get the distance between the axis point and the projection of the
1508 // external point on the axis
1509 const Real dist = (p_ext - p_axis) * dir_axis.unit();
1510 const Point center_pt = p_axis + dist * dir_axis.unit();
1511 // Then get the radius
1512 const Real radius = (p_ext - center_pt).norm();
1513 return std::make_pair(radius, center_pt);
1514}
1515
1516std::vector<Point>
1518 const Point & dir_axis,
1519 const Point & p_input) const
1520{
1521 // To make the rotation mathematically simple, we perform rotation in a coordination system
1522 // (x',y',z') defined by rotation axis and the mesh to be rotated.
1523 // z' is the rotation axis, which is trivial dir_axis.unit()
1524 const Point z_prime = dir_axis.unit();
1525 // the x' and z' should form the plane that accommodates input mesh
1526 const Point x_prime = ((p_input - p_axis) - ((p_input - p_axis) * z_prime) * z_prime).unit();
1527 const Point y_prime = z_prime.cross(x_prime);
1528 // Then we transform things back to the original coordination system (x,y,z), which is trivial
1529 // (1,0,0), (0,1,0), (0,0,1)
1530 return {{x_prime(0), y_prime(0), z_prime(0)},
1531 {x_prime(1), y_prime(1), z_prime(1)},
1532 {x_prime(2), y_prime(2), z_prime(2)}};
1533}
1534
1535std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>>
1537 const std::vector<dof_id_type> & nodes_on_axis) const
1538{
1539 std::vector<dof_id_type> nodes_on_axis_in_elem;
1540 std::vector<dof_id_type> nodes_not_on_axis_in_elem;
1541 for (unsigned int i = 0; i < elem.n_nodes(); i++)
1542 {
1543 const auto node_id = elem.node_id(i);
1544 if (std::find(nodes_on_axis.begin(), nodes_on_axis.end(), node_id) != nodes_on_axis.end())
1545 {
1546 nodes_on_axis_in_elem.push_back(i);
1547 }
1548 else
1549 {
1550 nodes_not_on_axis_in_elem.push_back(i);
1551 }
1552 }
1553 return std::make_pair(nodes_on_axis_in_elem, nodes_not_on_axis_in_elem);
1554}
1555
1556void
1558{
1559 const Point axis_component =
1560 ((node - _axis_point) * _axis_direction.unit()) * _axis_direction.unit();
1561 const Point rad_component = ((node - _axis_point) - axis_component) * _radius_correction_factor;
1562 node = _axis_point + axis_component + rad_component;
1563}
1564
1565void
1566RevolveGenerator::createQUADfromEDGE(const ElemType quad_elem_type,
1567 const Elem * elem,
1568 const std::unique_ptr<MeshBase> & mesh,
1569 std::unique_ptr<Elem> & new_elem,
1570 const int current_layer,
1571 const unsigned int orig_nodes,
1572 const unsigned int total_num_azimuthal_intervals,
1573 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
1574 bool & is_flipped) const
1575{
1576 if (quad_elem_type != QUAD4 && quad_elem_type != QUAD9)
1577 mooseError("Unsupported element type", quad_elem_type);
1578
1579 side_pairs.push_back(std::make_pair(0, 2));
1580 const unsigned int order = quad_elem_type == QUAD4 ? 1 : 2;
1581
1582 new_elem = std::make_unique<Quad4>();
1583 if (quad_elem_type == QUAD9)
1584 {
1585 new_elem = std::make_unique<Quad9>();
1586 new_elem->set_node(4,
1587 mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * 2 * orig_nodes)));
1588 new_elem->set_node(
1589 5, mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1590 new_elem->set_node(
1591 6,
1592 mesh->node_ptr(elem->node_ptr(2)->id() +
1593 ((current_layer + 1) %
1594 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1595 2 * orig_nodes)));
1596 new_elem->set_node(
1597 7, mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1598 new_elem->set_node(
1599 8, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1600 }
1601
1602 new_elem->set_node(
1603 0, mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * order * orig_nodes)));
1604 new_elem->set_node(
1605 1, mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * order * orig_nodes)));
1606 new_elem->set_node(
1607 3,
1608 mesh->node_ptr(elem->node_ptr(0)->id() +
1609 ((current_layer + 1) %
1610 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1611 order * orig_nodes)));
1612 new_elem->set_node(
1613 2,
1614 mesh->node_ptr(elem->node_ptr(1)->id() +
1615 ((current_layer + 1) %
1616 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1617 order * orig_nodes)));
1618
1619 if (new_elem->volume() < 0.0)
1620 {
1621 MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
1622 MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
1623 if (quad_elem_type == QUAD9)
1624 MooseMeshUtils::swapNodesInElem(*new_elem, 4, 6);
1625 is_flipped = true;
1626 }
1627}
1628
1629void
1631 const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
1632 const ElemType tri_elem_type,
1633 const Elem * elem,
1634 const std::unique_ptr<MeshBase> & mesh,
1635 std::unique_ptr<Elem> & new_elem,
1636 const int current_layer,
1637 const unsigned int orig_nodes,
1638 const unsigned int total_num_azimuthal_intervals,
1639 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
1640 dof_id_type & axis_node_case,
1641 bool & is_flipped) const
1642{
1643 if (tri_elem_type != TRI3 && tri_elem_type != TRI7)
1644 mooseError("Unsupported element type", tri_elem_type);
1645
1646 side_pairs.push_back(std::make_pair(0, 2));
1647 const unsigned int order = tri_elem_type == TRI3 ? 1 : 2;
1648 axis_node_case = nodes_cates.first.front();
1649
1650 new_elem = std::make_unique<Tri3>();
1651 if (tri_elem_type == TRI7)
1652 {
1653 new_elem = std::make_unique<Tri7>();
1654 new_elem->set_node(3,
1655 mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * 2 * orig_nodes)));
1656 new_elem->set_node(4,
1657 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 2)->id() +
1658 ((current_layer * 2 + 1) * orig_nodes)));
1659 new_elem->set_node(
1660 5,
1661 mesh->node_ptr(elem->node_ptr(2)->id() +
1662 ((current_layer + 1) %
1663 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1664 2 * orig_nodes)));
1665 new_elem->set_node(
1666 6, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1667 }
1668
1669 new_elem->set_node(0, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
1670 new_elem->set_node(1,
1671 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 2)->id() +
1672 (current_layer * order * orig_nodes)));
1673 new_elem->set_node(
1674 2,
1675 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 2)->id() +
1676 ((current_layer + 1) %
1677 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1678 order * orig_nodes)));
1679
1680 if (new_elem->volume() < 0.0)
1681 {
1682 MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
1683 if (tri_elem_type == TRI7)
1684 MooseMeshUtils::swapNodesInElem(*new_elem, 3, 5);
1685 is_flipped = true;
1686 }
1687}
1688
1689void
1690RevolveGenerator::createPRISMfromTRI(const ElemType prism_elem_type,
1691 const Elem * elem,
1692 const std::unique_ptr<MeshBase> & mesh,
1693 std::unique_ptr<Elem> & new_elem,
1694 const int current_layer,
1695 const unsigned int orig_nodes,
1696 const unsigned int total_num_azimuthal_intervals,
1697 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
1698 bool & is_flipped) const
1699{
1700 if (prism_elem_type != PRISM6 && prism_elem_type != PRISM18 && prism_elem_type != PRISM21)
1701 mooseError("unsupported situation");
1702
1703 side_pairs.push_back(std::make_pair(0, 4));
1704 const unsigned int order = prism_elem_type == PRISM6 ? 1 : 2;
1705
1706 new_elem = std::make_unique<Prism6>();
1707
1708 if (order == 2)
1709 {
1710 new_elem = std::make_unique<Prism18>();
1711 if (prism_elem_type == PRISM21)
1712 {
1713 new_elem = std::make_unique<Prism21>();
1714 new_elem->set_node(
1715 18, mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
1716 new_elem->set_node(
1717 19,
1718 mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer + 1) %
1719 (total_num_azimuthal_intervals + 1 -
1720 (unsigned int)_full_circle_revolving) *
1721 2 * orig_nodes)));
1722 new_elem->set_node(
1723 20, mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1724 }
1725 new_elem->set_node(6,
1726 mesh->node_ptr(elem->node_ptr(3)->id() + (current_layer * 2 * orig_nodes)));
1727 new_elem->set_node(7,
1728 mesh->node_ptr(elem->node_ptr(4)->id() + (current_layer * 2 * orig_nodes)));
1729 new_elem->set_node(8,
1730 mesh->node_ptr(elem->node_ptr(5)->id() + (current_layer * 2 * orig_nodes)));
1731 new_elem->set_node(
1732 9, mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1733 new_elem->set_node(
1734 10, mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1735 new_elem->set_node(
1736 11, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1737 new_elem->set_node(
1738 12,
1739 mesh->node_ptr(elem->node_ptr(3)->id() +
1740 ((current_layer + 1) %
1741 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1742 2 * orig_nodes)));
1743 new_elem->set_node(
1744 13,
1745 mesh->node_ptr(elem->node_ptr(4)->id() +
1746 ((current_layer + 1) %
1747 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1748 2 * orig_nodes)));
1749 new_elem->set_node(
1750 14,
1751 mesh->node_ptr(elem->node_ptr(5)->id() +
1752 ((current_layer + 1) %
1753 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1754 2 * orig_nodes)));
1755 new_elem->set_node(
1756 15, mesh->node_ptr(elem->node_ptr(3)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1757 new_elem->set_node(
1758 16, mesh->node_ptr(elem->node_ptr(4)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1759 new_elem->set_node(
1760 17, mesh->node_ptr(elem->node_ptr(5)->id() + ((current_layer * 2 + 1) * orig_nodes)));
1761 }
1762 new_elem->set_node(
1763 0, mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * order * orig_nodes)));
1764 new_elem->set_node(
1765 1, mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * order * orig_nodes)));
1766 new_elem->set_node(
1767 2, mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * order * orig_nodes)));
1768 new_elem->set_node(
1769 3,
1770 mesh->node_ptr(elem->node_ptr(0)->id() +
1771 ((current_layer + 1) %
1772 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1773 order * orig_nodes)));
1774 new_elem->set_node(
1775 4,
1776 mesh->node_ptr(elem->node_ptr(1)->id() +
1777 ((current_layer + 1) %
1778 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1779 order * orig_nodes)));
1780 new_elem->set_node(
1781 5,
1782 mesh->node_ptr(elem->node_ptr(2)->id() +
1783 ((current_layer + 1) %
1784 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1785 order * orig_nodes)));
1786
1787 if (new_elem->volume() < 0.0)
1788 {
1789 MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
1790 MooseMeshUtils::swapNodesInElem(*new_elem, 1, 4);
1791 MooseMeshUtils::swapNodesInElem(*new_elem, 2, 5);
1792 if (prism_elem_type != PRISM6)
1793 {
1794 MooseMeshUtils::swapNodesInElem(*new_elem, 6, 12);
1795 MooseMeshUtils::swapNodesInElem(*new_elem, 7, 13);
1796 MooseMeshUtils::swapNodesInElem(*new_elem, 8, 14);
1797 if (prism_elem_type == PRISM21)
1798 {
1799 MooseMeshUtils::swapNodesInElem(*new_elem, 18, 19);
1800 }
1801 }
1802 is_flipped = true;
1803 }
1804}
1805
1806void
1808 const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
1809 const ElemType pyramid_elem_type,
1810 const Elem * elem,
1811 const std::unique_ptr<MeshBase> & mesh,
1812 std::unique_ptr<Elem> & new_elem,
1813 const int current_layer,
1814 const unsigned int orig_nodes,
1815 const unsigned int total_num_azimuthal_intervals,
1816 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
1817 dof_id_type & axis_node_case,
1818 bool & is_flipped) const
1819{
1820 if (pyramid_elem_type != PYRAMID5 && pyramid_elem_type != PYRAMID13 &&
1821 pyramid_elem_type != PYRAMID18)
1822 mooseError("unsupported situation");
1823
1824 side_pairs.push_back(std::make_pair(0, 2));
1825 const unsigned int order = pyramid_elem_type == PYRAMID5 ? 1 : 2;
1826 axis_node_case = nodes_cates.first.front();
1827
1828 new_elem = std::make_unique<Pyramid5>();
1829
1830 if (order == 2)
1831 {
1832 new_elem = std::make_unique<Pyramid13>();
1833 if (pyramid_elem_type == PYRAMID18)
1834 {
1835 new_elem = std::make_unique<Pyramid18>();
1836 new_elem->set_node(13,
1837 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3 + 3)->id() +
1838 ((current_layer * 2 + 1) * orig_nodes)));
1839 new_elem->set_node(15,
1840 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3 + 3)->id() +
1841 ((current_layer * 2 + 1) * orig_nodes)));
1842 new_elem->set_node(17,
1843 mesh->node_ptr(elem->node_ptr(axis_node_case + 3)->id() +
1844 ((current_layer * 2 + 1) * orig_nodes)));
1845 new_elem->set_node(
1846 14, mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
1847 new_elem->set_node(
1848 16,
1849 mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer + 1) %
1850 (total_num_azimuthal_intervals + 1 -
1851 (unsigned int)_full_circle_revolving) *
1852 2 * orig_nodes)));
1853 }
1854 new_elem->set_node(6,
1855 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3)->id() +
1856 ((current_layer * 2 + 1) * orig_nodes)));
1857 new_elem->set_node(8,
1858 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3)->id() +
1859 ((current_layer * 2 + 1) * orig_nodes)));
1860 new_elem->set_node(5,
1861 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3 + 3)->id() +
1862 (current_layer * 2 * orig_nodes)));
1863 new_elem->set_node(
1864 7,
1865 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3 + 3)->id() +
1866 ((current_layer + 1) %
1867 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1868 2 * orig_nodes)));
1869 new_elem->set_node(9,
1870 mesh->node_ptr(elem->node_ptr(axis_node_case + 3)->id() +
1871 (current_layer * 2 * orig_nodes)));
1872 new_elem->set_node(10,
1873 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3 + 3)->id() +
1874 (current_layer * 2 * orig_nodes)));
1875 new_elem->set_node(
1876 12,
1877 mesh->node_ptr(elem->node_ptr(axis_node_case + 3)->id() +
1878 ((current_layer + 1) %
1879 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1880 2 * orig_nodes)));
1881 new_elem->set_node(
1882 11,
1883 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3 + 3)->id() +
1884 ((current_layer + 1) %
1885 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1886 2 * orig_nodes)));
1887 }
1888 new_elem->set_node(4, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
1889 new_elem->set_node(0,
1890 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3)->id() +
1891 (current_layer * order * orig_nodes)));
1892 new_elem->set_node(1,
1893 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3)->id() +
1894 (current_layer * order * orig_nodes)));
1895 new_elem->set_node(
1896 2,
1897 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 3)->id() +
1898 ((current_layer + 1) %
1899 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1900 order * orig_nodes)));
1901 new_elem->set_node(
1902 3,
1903 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 3)->id() +
1904 ((current_layer + 1) %
1905 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
1906 order * orig_nodes)));
1907
1908 if (new_elem->volume() < 0.0)
1909 {
1910 MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
1911 MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
1912 if (order == 2)
1913 {
1914 MooseMeshUtils::swapNodesInElem(*new_elem, 5, 7);
1915 MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
1916 MooseMeshUtils::swapNodesInElem(*new_elem, 9, 12);
1917 if (pyramid_elem_type == PYRAMID18)
1918 {
1919 MooseMeshUtils::swapNodesInElem(*new_elem, 14, 16);
1920 }
1921 }
1922 is_flipped = true;
1923 }
1924}
1925
1926void
1928 const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
1929 const ElemType tet_elem_type,
1930 const Elem * elem,
1931 const std::unique_ptr<MeshBase> & mesh,
1932 std::unique_ptr<Elem> & new_elem,
1933 const int current_layer,
1934 const unsigned int orig_nodes,
1935 const unsigned int total_num_azimuthal_intervals,
1936 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
1937 dof_id_type & axis_node_case,
1938 bool & is_flipped) const
1939{
1940 if (tet_elem_type != TET4 && tet_elem_type != TET10 && tet_elem_type != TET14)
1941 mooseError("unsupported situation");
1942
1943 side_pairs.push_back(std::make_pair(0, 1));
1944 const unsigned int order = tet_elem_type == TET4 ? 1 : 2;
1945 if (order == 2)
1946 {
1947 // Sanity check to filter unsupported cases
1948 if (nodes_cates.first[0] > 2 || nodes_cates.first[1] > 2 || nodes_cates.first[2] < 3)
1949 mooseError("unsupported situation 2");
1950 }
1951 axis_node_case = nodes_cates.second.front();
1952
1953 new_elem = std::make_unique<Tet4>();
1954 if (order == 2)
1955 {
1956 const bool node_order = nodes_cates.first[1] - nodes_cates.first[0] == 1;
1957 new_elem = std::make_unique<Tet10>();
1958 if (tet_elem_type == TET14)
1959 {
1960 new_elem = std::make_unique<Tet14>();
1961 new_elem->set_node(
1962 12,
1963 mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[1] + 3)
1964 : (nodes_cates.second.front() + 3))
1965 ->id() +
1966 ((current_layer * 2 + 1) * orig_nodes)));
1967 new_elem->set_node(13,
1968 mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.second.front() + 3)
1969 : (nodes_cates.first[0] + 3))
1970 ->id() +
1971 ((current_layer * 2 + 1) * orig_nodes)));
1972 new_elem->set_node(
1973 10, mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
1974 new_elem->set_node(
1975 11,
1976 mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer + 1) %
1977 (total_num_azimuthal_intervals + 1 -
1978 (unsigned int)_full_circle_revolving) *
1979 2 * orig_nodes)));
1980 }
1981 new_elem->set_node(4,
1982 mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[0] + 3)
1983 : (nodes_cates.first[1] + 3))
1984 ->id()));
1985 new_elem->set_node(5,
1986 mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[1] + 3)
1987 : (nodes_cates.second.front() + 3))
1988 ->id() +
1989 (current_layer * 2 * orig_nodes)));
1990 new_elem->set_node(6,
1991 mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.second.front() + 3)
1992 : (nodes_cates.first[0] + 3))
1993 ->id() +
1994 (current_layer * 2 * orig_nodes)));
1995 new_elem->set_node(
1996 8,
1997 mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.first[1] + 3)
1998 : (nodes_cates.second.front() + 3))
1999 ->id() +
2000 ((current_layer + 1) %
2001 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2002 2 * orig_nodes)));
2003 new_elem->set_node(
2004 7,
2005 mesh->node_ptr(elem->node_ptr(node_order ? (nodes_cates.second.front() + 3)
2006 : (nodes_cates.first[0] + 3))
2007 ->id() +
2008 ((current_layer + 1) %
2009 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2010 2 * orig_nodes)));
2011 new_elem->set_node(9,
2012 mesh->node_ptr(elem->node_ptr(nodes_cates.second.front())->id() +
2013 ((current_layer * 2 + 1) * orig_nodes)));
2014 }
2015 new_elem->set_node(0, mesh->node_ptr(elem->node_ptr(nodes_cates.first[0])->id()));
2016 new_elem->set_node(1, mesh->node_ptr(elem->node_ptr(nodes_cates.first[1])->id()));
2017 new_elem->set_node(2,
2018 mesh->node_ptr(elem->node_ptr(nodes_cates.second.front())->id() +
2019 (current_layer * order * orig_nodes)));
2020 new_elem->set_node(
2021 3,
2022 mesh->node_ptr(elem->node_ptr(nodes_cates.second.front())->id() +
2023 ((current_layer + 1) %
2024 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2025 order * orig_nodes)));
2026
2027 if (new_elem->volume() < 0.0)
2028 {
2029 MooseMeshUtils::swapNodesInElem(*new_elem, 2, 3);
2030 if (order == 2)
2031 {
2032 MooseMeshUtils::swapNodesInElem(*new_elem, 5, 8);
2033 MooseMeshUtils::swapNodesInElem(*new_elem, 6, 7);
2034 if (tet_elem_type == TET14)
2035 {
2036 MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
2037 }
2038 }
2039 is_flipped = true;
2040 }
2041}
2042
2043void
2044RevolveGenerator::createHEXfromQUAD(const ElemType hex_elem_type,
2045 const Elem * elem,
2046 const std::unique_ptr<MeshBase> & mesh,
2047 std::unique_ptr<Elem> & new_elem,
2048 const int current_layer,
2049 const unsigned int orig_nodes,
2050 const unsigned int total_num_azimuthal_intervals,
2051 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
2052 bool & is_flipped) const
2053{
2054 if (hex_elem_type != HEX8 && hex_elem_type != HEX20 && hex_elem_type != HEX27)
2055 mooseError("unsupported situation");
2056
2057 side_pairs.push_back(std::make_pair(0, 5));
2058 const unsigned int order = hex_elem_type == HEX8 ? 1 : 2;
2059
2060 new_elem = std::make_unique<Hex8>();
2061 if (order == 2)
2062 {
2063 new_elem = std::make_unique<Hex20>();
2064 if (hex_elem_type == HEX27)
2065 {
2066 new_elem = std::make_unique<Hex27>();
2067 new_elem->set_node(
2068 20, mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
2069 new_elem->set_node(
2070 25,
2071 mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer + 1) %
2072 (total_num_azimuthal_intervals + 1 -
2073 (unsigned int)_full_circle_revolving) *
2074 2 * orig_nodes)));
2075 new_elem->set_node(
2076 26, mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2077 new_elem->set_node(
2078 21, mesh->node_ptr(elem->node_ptr(4)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2079 new_elem->set_node(
2080 22, mesh->node_ptr(elem->node_ptr(5)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2081 new_elem->set_node(
2082 23, mesh->node_ptr(elem->node_ptr(6)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2083 new_elem->set_node(
2084 24, mesh->node_ptr(elem->node_ptr(7)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2085 }
2086 new_elem->set_node(8,
2087 mesh->node_ptr(elem->node_ptr(4)->id() + (current_layer * 2 * orig_nodes)));
2088 new_elem->set_node(9,
2089 mesh->node_ptr(elem->node_ptr(5)->id() + (current_layer * 2 * orig_nodes)));
2090 new_elem->set_node(10,
2091 mesh->node_ptr(elem->node_ptr(6)->id() + (current_layer * 2 * orig_nodes)));
2092 new_elem->set_node(11,
2093 mesh->node_ptr(elem->node_ptr(7)->id() + (current_layer * 2 * orig_nodes)));
2094 new_elem->set_node(
2095 16,
2096 mesh->node_ptr(elem->node_ptr(4)->id() +
2097 ((current_layer + 1) %
2098 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2099 2 * orig_nodes)));
2100 new_elem->set_node(
2101 17,
2102 mesh->node_ptr(elem->node_ptr(5)->id() +
2103 ((current_layer + 1) %
2104 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2105 2 * orig_nodes)));
2106 new_elem->set_node(
2107 18,
2108 mesh->node_ptr(elem->node_ptr(6)->id() +
2109 ((current_layer + 1) %
2110 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2111 2 * orig_nodes)));
2112 new_elem->set_node(
2113 19,
2114 mesh->node_ptr(elem->node_ptr(7)->id() +
2115 ((current_layer + 1) %
2116 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2117 2 * orig_nodes)));
2118 new_elem->set_node(
2119 12, mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2120 new_elem->set_node(
2121 13, mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2122 new_elem->set_node(
2123 14, mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2124 new_elem->set_node(
2125 15, mesh->node_ptr(elem->node_ptr(3)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2126 }
2127 new_elem->set_node(
2128 0, mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * order * orig_nodes)));
2129 new_elem->set_node(
2130 1, mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * order * orig_nodes)));
2131 new_elem->set_node(
2132 2, mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * order * orig_nodes)));
2133 new_elem->set_node(
2134 3, mesh->node_ptr(elem->node_ptr(3)->id() + (current_layer * order * orig_nodes)));
2135 new_elem->set_node(
2136 4,
2137 mesh->node_ptr(elem->node_ptr(0)->id() +
2138 ((current_layer + 1) %
2139 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2140 order * orig_nodes)));
2141 new_elem->set_node(
2142 5,
2143 mesh->node_ptr(elem->node_ptr(1)->id() +
2144 ((current_layer + 1) %
2145 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2146 order * orig_nodes)));
2147 new_elem->set_node(
2148 6,
2149 mesh->node_ptr(elem->node_ptr(2)->id() +
2150 ((current_layer + 1) %
2151 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2152 order * orig_nodes)));
2153 new_elem->set_node(
2154 7,
2155 mesh->node_ptr(elem->node_ptr(3)->id() +
2156 ((current_layer + 1) %
2157 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2158 order * orig_nodes)));
2159
2160 if (new_elem->volume() < 0.0)
2161 {
2162 MooseMeshUtils::swapNodesInElem(*new_elem, 0, 4);
2163 MooseMeshUtils::swapNodesInElem(*new_elem, 1, 5);
2164 MooseMeshUtils::swapNodesInElem(*new_elem, 2, 6);
2165 MooseMeshUtils::swapNodesInElem(*new_elem, 3, 7);
2166 if (order == 2)
2167 {
2168 MooseMeshUtils::swapNodesInElem(*new_elem, 8, 16);
2169 MooseMeshUtils::swapNodesInElem(*new_elem, 9, 17);
2170 MooseMeshUtils::swapNodesInElem(*new_elem, 10, 18);
2171 MooseMeshUtils::swapNodesInElem(*new_elem, 11, 19);
2172 if (hex_elem_type == HEX27)
2173 {
2174 MooseMeshUtils::swapNodesInElem(*new_elem, 20, 25);
2175 }
2176 }
2177 is_flipped = true;
2178 }
2179}
2180
2181void
2183 const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
2184 const ElemType prism_elem_type,
2185 const Elem * elem,
2186 const std::unique_ptr<MeshBase> & mesh,
2187 std::unique_ptr<Elem> & new_elem,
2188 const int current_layer,
2189 const unsigned int orig_nodes,
2190 const unsigned int total_num_azimuthal_intervals,
2191 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
2192 dof_id_type & axis_node_case,
2193 bool & is_flipped) const
2194{
2195 if (prism_elem_type != PRISM6 && prism_elem_type != PRISM15 && prism_elem_type != PRISM18)
2196 mooseError("unsupported situation");
2197
2198 side_pairs.push_back(std::make_pair(1, 3));
2199 const unsigned int order = prism_elem_type == PRISM6 ? 1 : 2;
2200 if (order == 2)
2201 {
2202 // Sanity check to filter unsupported cases
2203 if (nodes_cates.first[0] > 3 || nodes_cates.first[1] > 3 || nodes_cates.first[2] < 4)
2204 mooseError("unsupported situation 2");
2205 }
2206 // Can only be 0-1, 1-2, 2-3, 3-0, we only consider vetices here.
2207 // nodes_cates are natually sorted
2208 const dof_id_type min_on_axis = nodes_cates.first[0];
2209 const dof_id_type max_on_axis = nodes_cates.first[1];
2210 axis_node_case = max_on_axis - min_on_axis == 1 ? min_on_axis : max_on_axis;
2211
2212 new_elem = std::make_unique<Prism6>();
2213 if (order == 2)
2214 {
2215 new_elem = std::make_unique<Prism15>();
2216 if (prism_elem_type == PRISM18)
2217 {
2218 new_elem = std::make_unique<Prism18>();
2219 new_elem->set_node(
2220 15, mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
2221 new_elem->set_node(16,
2222 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
2223 ((current_layer * 2 + 1) * orig_nodes)));
2224 new_elem->set_node(
2225 17,
2226 mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer + 1) %
2227 (total_num_azimuthal_intervals + 1 -
2228 (unsigned int)_full_circle_revolving) *
2229 2 * orig_nodes)));
2230 }
2231 new_elem->set_node(9, mesh->node_ptr(elem->node_ptr(axis_node_case + 4)->id()));
2232 new_elem->set_node(10,
2233 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
2234 (current_layer * 2 * orig_nodes)));
2235 new_elem->set_node(12,
2236 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
2237 (current_layer * 2 * orig_nodes)));
2238 new_elem->set_node(6,
2239 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
2240 (current_layer * 2 * orig_nodes)));
2241 new_elem->set_node(
2242 14,
2243 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
2244 ((current_layer + 1) %
2245 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2246 2 * orig_nodes)));
2247 new_elem->set_node(
2248 8,
2249 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
2250 ((current_layer + 1) %
2251 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2252 2 * orig_nodes)));
2253 new_elem->set_node(
2254 11,
2255 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
2256 ((current_layer + 1) %
2257 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2258 2 * orig_nodes)));
2259 new_elem->set_node(7,
2260 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2261 ((current_layer * 2 + 1) * orig_nodes)));
2262 new_elem->set_node(13,
2263 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
2264 ((current_layer * 2 + 1) * orig_nodes)));
2265 }
2266 new_elem->set_node(0, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
2267 new_elem->set_node(3, mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id()));
2268 new_elem->set_node(4,
2269 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
2270 (current_layer * order * orig_nodes)));
2271 new_elem->set_node(1,
2272 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2273 (current_layer * order * orig_nodes)));
2274 new_elem->set_node(
2275 5,
2276 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
2277 ((current_layer + 1) %
2278 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2279 order * orig_nodes)));
2280 new_elem->set_node(
2281 2,
2282 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2283 ((current_layer + 1) %
2284 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2285 order * orig_nodes)));
2286
2287 if (new_elem->volume() < 0.0)
2288 {
2289 MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
2290 MooseMeshUtils::swapNodesInElem(*new_elem, 4, 5);
2291 if (order == 2)
2292 {
2293 MooseMeshUtils::swapNodesInElem(*new_elem, 12, 14);
2294 MooseMeshUtils::swapNodesInElem(*new_elem, 6, 8);
2295 MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
2296 if (prism_elem_type == PRISM18)
2297 {
2298 MooseMeshUtils::swapNodesInElem(*new_elem, 15, 17);
2299 }
2300 }
2301 is_flipped = true;
2302 }
2303}
2304
2305void
2307 const std::pair<std::vector<dof_id_type>, std::vector<dof_id_type>> & nodes_cates,
2308 const ElemType pyramid_elem_type,
2309 const ElemType prism_elem_type,
2310 const Elem * elem,
2311 const std::unique_ptr<MeshBase> & mesh,
2312 std::unique_ptr<Elem> & new_elem,
2313 std::unique_ptr<Elem> & new_elem_1,
2314 const int current_layer,
2315 const unsigned int orig_nodes,
2316 const unsigned int total_num_azimuthal_intervals,
2317 std::vector<std::pair<dof_id_type, dof_id_type>> & side_pairs,
2318 dof_id_type & axis_node_case,
2319 bool & is_flipped,
2320 bool & is_flipped_additional) const
2321{
2322 if (!(pyramid_elem_type == PYRAMID5 && prism_elem_type == PRISM6) &&
2323 !(pyramid_elem_type == PYRAMID14 && prism_elem_type == PRISM18))
2324 mooseError("unsupported situation");
2325 const unsigned int order = pyramid_elem_type == PYRAMID5 ? 1 : 2;
2326
2327 side_pairs.push_back(std::make_pair(0, 2));
2328 axis_node_case = nodes_cates.first.front();
2329 new_elem = std::make_unique<Pyramid5>();
2330 if (pyramid_elem_type == PYRAMID14)
2331 {
2332 new_elem = std::make_unique<Pyramid14>();
2333 new_elem->set_node(9,
2334 mesh->node_ptr(elem->node_ptr(axis_node_case + 4)->id() +
2335 (current_layer * 2 * orig_nodes)));
2336 new_elem->set_node(10,
2337 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
2338 (current_layer * 2 * orig_nodes)));
2339 new_elem->set_node(5,
2340 mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
2341 new_elem->set_node(8,
2342 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
2343 ((current_layer * 2 + 1) * orig_nodes)));
2344 new_elem->set_node(6,
2345 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2346 ((current_layer * 2 + 1) * orig_nodes)));
2347 new_elem->set_node(
2348 13, mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2349 new_elem->set_node(
2350 7,
2351 mesh->node_ptr(elem->node_ptr(8)->id() +
2352 ((current_layer + 1) %
2353 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2354 2 * orig_nodes)));
2355 new_elem->set_node(
2356 11,
2357 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4 + 4)->id() +
2358 ((current_layer + 1) %
2359 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2360 2 * orig_nodes)));
2361 new_elem->set_node(
2362 12,
2363 mesh->node_ptr(elem->node_ptr(axis_node_case + 4)->id() +
2364 ((current_layer + 1) %
2365 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2366 2 * orig_nodes)));
2367 }
2368 new_elem->set_node(4, mesh->node_ptr(elem->node_ptr(axis_node_case)->id()));
2369 new_elem->set_node(0,
2370 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
2371 (current_layer * order * orig_nodes)));
2372 new_elem->set_node(1,
2373 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2374 (current_layer * order * orig_nodes)));
2375 new_elem->set_node(
2376 2,
2377 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2378 ((current_layer + 1) %
2379 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2380 order * orig_nodes)));
2381 new_elem->set_node(
2382 3,
2383 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
2384 ((current_layer + 1) %
2385 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2386 order * orig_nodes)));
2387
2388 if (new_elem->volume() < 0.0)
2389 {
2390 MooseMeshUtils::swapNodesInElem(*new_elem, 1, 2);
2391 MooseMeshUtils::swapNodesInElem(*new_elem, 0, 3);
2392 if (pyramid_elem_type == PYRAMID14)
2393 {
2394 MooseMeshUtils::swapNodesInElem(*new_elem, 5, 7);
2395 MooseMeshUtils::swapNodesInElem(*new_elem, 10, 11);
2396 MooseMeshUtils::swapNodesInElem(*new_elem, 9, 12);
2397 }
2398 is_flipped = true;
2399 }
2400
2401 side_pairs.push_back(std::make_pair(0, 4));
2402 new_elem_1 = std::make_unique<Prism6>();
2403 if (prism_elem_type == PRISM18)
2404 {
2405 new_elem_1 = std::make_unique<Prism18>();
2406 new_elem_1->set_node(
2407 6, mesh->node_ptr(elem->node_ptr(8)->id() + (current_layer * 2 * orig_nodes)));
2408 new_elem_1->set_node(8,
2409 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
2410 (current_layer * 2 * orig_nodes)));
2411 new_elem_1->set_node(7,
2412 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
2413 (current_layer * 2 * orig_nodes)));
2414 new_elem_1->set_node(9,
2415 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
2416 ((current_layer * 2 + 1) * orig_nodes)));
2417 new_elem_1->set_node(10,
2418 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2419 ((current_layer * 2 + 1) * orig_nodes)));
2420 new_elem_1->set_node(11,
2421 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
2422 ((current_layer * 2 + 1) * orig_nodes)));
2423 new_elem_1->set_node(
2424 15, mesh->node_ptr(elem->node_ptr(8)->id() + ((current_layer * 2 + 1) * orig_nodes)));
2425 new_elem_1->set_node(17,
2426 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
2427 ((current_layer * 2 + 1) * orig_nodes)));
2428 new_elem_1->set_node(16,
2429 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
2430 ((current_layer * 2 + 1) * orig_nodes)));
2431 new_elem_1->set_node(
2432 12,
2433 mesh->node_ptr(elem->node_ptr(8)->id() +
2434 ((current_layer + 1) %
2435 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2436 2 * orig_nodes)));
2437 new_elem_1->set_node(
2438 13,
2439 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4 + 4)->id() +
2440 ((current_layer + 1) %
2441 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2442 2 * orig_nodes)));
2443 new_elem_1->set_node(
2444 14,
2445 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4 + 4)->id() +
2446 ((current_layer + 1) %
2447 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2448 2 * orig_nodes)));
2449 }
2450 new_elem_1->set_node(0,
2451 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
2452 (current_layer * order * orig_nodes)));
2453 new_elem_1->set_node(1,
2454 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2455 (current_layer * order * orig_nodes)));
2456 new_elem_1->set_node(2,
2457 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
2458 (current_layer * order * orig_nodes)));
2459 new_elem_1->set_node(
2460 3,
2461 mesh->node_ptr(elem->node_ptr((axis_node_case + 1) % 4)->id() +
2462 ((current_layer + 1) %
2463 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2464 order * orig_nodes)));
2465 new_elem_1->set_node(
2466 4,
2467 mesh->node_ptr(elem->node_ptr((axis_node_case + 3) % 4)->id() +
2468 ((current_layer + 1) %
2469 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2470 order * orig_nodes)));
2471 new_elem_1->set_node(
2472 5,
2473 mesh->node_ptr(elem->node_ptr((axis_node_case + 2) % 4)->id() +
2474 ((current_layer + 1) %
2475 (total_num_azimuthal_intervals + 1 - (unsigned int)_full_circle_revolving) *
2476 order * orig_nodes)));
2477
2478 if (new_elem_1->volume() < 0.0)
2479 {
2480 MooseMeshUtils::swapNodesInElem(*new_elem_1, 0, 3);
2481 MooseMeshUtils::swapNodesInElem(*new_elem_1, 1, 4);
2482 MooseMeshUtils::swapNodesInElem(*new_elem_1, 2, 5);
2483 if (prism_elem_type == PRISM18)
2484 {
2485 MooseMeshUtils::swapNodesInElem(*new_elem_1, 6, 12);
2486 MooseMeshUtils::swapNodesInElem(*new_elem_1, 7, 13);
2487 MooseMeshUtils::swapNodesInElem(*new_elem_1, 8, 14);
2488 }
2489 is_flipped_additional = true;
2490 }
2491}
char ** blocks
registerMooseObject("ReactorApp", RevolveGenerator)
void ErrorVector unsigned int
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
const std::string & name() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
virtual const char * what() const
A base class that contains common members for Reactor module mesh generators.
static InputParameters validParams()
This RevolveGenerator object is designed to revolve a 1D mesh into 2D, or a 2D mesh into 3D based on ...
const std::vector< std::vector< boundary_id_type > > & _boundary_swaps
Boundaries to swap out for each elevation.
void nodeModification(Node &node)
Modify the position of a node to account for radius correction.
std::vector< unsigned int > _elem_integer_indices_to_swap
std::vector< std::unordered_map< subdomain_id_type, subdomain_id_type > > _subdomain_swap_pairs
Easier to work with version of _sudomain_swaps.
boundary_id_type _start_boundary
Boundary ID of the starting boundary.
bool _has_start_boundary
Whether a starting boundary is specified.
RevolveGenerator(const InputParameters &parameters)
std::vector< std::unordered_map< boundary_id_type, boundary_id_type > > _boundary_swap_pairs
Easier to work with version of _boundary_swaps.
void createPRISMfromTRI(const ElemType prism_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, bool &is_flipped) const
Create a new PRISM element from an existing TRI element by revolving it.
std::unique_ptr< MeshBase > generate() override
void createTRIfromEDGE(const std::pair< std::vector< dof_id_type >, std::vector< dof_id_type > > &nodes_cates, const ElemType tri_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, dof_id_type &axis_node_case, bool &is_flipped) const
Create a new TRI element from an existing EDGE element by revolving it.
std::vector< Point > rotationVectors(const Point &p_axis, const Point &dir_axis, const Point &p_input) const
Calculate the transform matrix between the rotation coordinate system and the original coordinate sys...
const bool & _clockwise
Revolving direction.
std::pair< Real, Point > getRotationCenterAndRadius(const Point &p_ext, const Point &p_axis, const Point &dir_axis) const
Get the rotation center and radius of the circular rotation based on the rotation axis and the extern...
static InputParameters validParams()
std::pair< std::vector< dof_id_type >, std::vector< dof_id_type > > onAxisNodesIdentifier(const Elem &elem, const std::vector< dof_id_type > &nodes_on_axis) const
Categorize the nodes of an element into two groups: nodes on the axis and nodes off the axis.
std::unique_ptr< MeshBase > & _input
Lower dimensional mesh from another generator.
const std::vector< unsigned int > & _nums_azimuthal_intervals
Numbers of azimuthal mesh intervals in each azimuthal section.
const std::vector< std::vector< std::vector< dof_id_type > > > & _elem_integers_swaps
Extra element integers to swap out for each elevation and each element integer name.
bool _full_circle_revolving
Whether to revolve for a full circle or not.
void createPYRAMIDfromTRI(const std::pair< std::vector< dof_id_type >, std::vector< dof_id_type > > &nodes_cates, const ElemType pyramid_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, dof_id_type &axis_node_case, bool &is_flipped) const
Create a new PYRAMID element from an existing TRI element by revolving it.
bool _has_end_boundary
Whether an ending boundary is specified.
void createQUADfromEDGE(const ElemType quad_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, bool &is_flipped) const
Create a new QUAD element from an existing EDGE element by revolving it.
const bool _preserve_volumes
Volume preserving function is optional.
boundary_id_type _end_boundary
Boundary ID of the ending boundary.
const Point & _axis_direction
A direction vector of the axis of revolution.
const std::vector< std::vector< subdomain_id_type > > & _subdomain_swaps
Subdomains to swap out for each azimuthal section.
std::vector< std::unordered_map< dof_id_type, dof_id_type > > _elem_integers_swap_pairs
Easier to work with version of _elem_integers_swaps.
void createHEXfromQUAD(const ElemType hex_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, bool &is_flipped) const
Create a new HEX element from an existing QUAD element by revolving it.
void createPRISMfromQUAD(const std::pair< std::vector< dof_id_type >, std::vector< dof_id_type > > &nodes_cates, const ElemType prism_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, dof_id_type &axis_node_case, bool &is_flipped) const
Create a new PRISM element from an existing QUAD element by revolving it.
const std::vector< std::string > & _elem_integer_names_to_swap
Names and indices of extra element integers to swap.
Real _radius_correction_factor
Radius correction factor.
std::vector< Real > _unit_angles
Unit angles of all azimuthal sections of revolution.
const std::vector< Real > _revolving_angles
Angles of revolution delineating each azimuthal section.
const Point & _axis_point
A point of the axis of revolution.
void createTETfromTRI(const std::pair< std::vector< dof_id_type >, std::vector< dof_id_type > > &nodes_cates, const ElemType tet_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, dof_id_type &axis_node_case, bool &is_flipped) const
Create a new TET element from an existing TRI element by revolving it.
void createPYRAMIDPRISMfromQUAD(const std::pair< std::vector< dof_id_type >, std::vector< dof_id_type > > &nodes_cates, const ElemType pyramid_elem_type, const ElemType prism_elem_type, const Elem *elem, const std::unique_ptr< MeshBase > &mesh, std::unique_ptr< Elem > &new_elem, std::unique_ptr< Elem > &new_elem_1, const int current_layer, const unsigned int orig_nodes, const unsigned int total_num_azimuthal_intervals, std::vector< std::pair< dof_id_type, dof_id_type > > &side_pairs, dof_id_type &axis_node_case, bool &is_flipped, bool &is_flipped_additional) const
Create a new PYRAMID element and a new PRISM element from an existing QUAD element by revolving it.
MeshBase & mesh
void extraElemIntegerSwapParametersProcessor(const std::string &class_name, const unsigned int num_sections, const unsigned int num_integers, const std::vector< std::vector< std::vector< dof_id_type > > > &elem_integers_swaps, std::vector< std::unordered_map< dof_id_type, dof_id_type > > &elem_integers_swap_pairs)
void swapNodesInElem(Elem &elem, const unsigned int nd1, const unsigned int nd2)
void idSwapParametersProcessor(const std::string &class_name, const std::string &id_name, const std::vector< std::vector< T > > &id_swaps, std::vector< std::unordered_map< T, T > > &id_swap_pairs, const unsigned int row_index_shift=0)
Point meshCentroidCalculator(const MeshBase &mesh)
Real radiusCorrectionFactor(const std::vector< Real > &azimuthal_list, const bool full_circle=true, const unsigned int order=1, const bool is_first_value_vertex=true)
Makes radial correction to preserve ring area.