www.mooseframework.org
FancyExtruderGenerator.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "FancyExtruderGenerator.h"
11 
12 #include "libmesh/boundary_info.h"
13 #include "libmesh/function_base.h"
14 #include "libmesh/cell_prism6.h"
15 #include "libmesh/cell_prism18.h"
16 #include "libmesh/cell_hex8.h"
17 #include "libmesh/cell_hex27.h"
18 #include "libmesh/cell_tet4.h"
19 #include "libmesh/cell_tet10.h"
20 #include "libmesh/face_tri3.h"
21 #include "libmesh/face_tri6.h"
22 #include "libmesh/face_quad4.h"
23 #include "libmesh/face_quad9.h"
24 #include "libmesh/libmesh_logging.h"
25 #include "libmesh/mesh_communication.h"
26 #include "libmesh/mesh_modification.h"
27 #include "libmesh/mesh_tools.h"
28 #include "libmesh/parallel.h"
29 #include "libmesh/remote_elem.h"
30 #include "libmesh/string_to_enum.h"
31 #include "libmesh/unstructured_mesh.h"
32 #include "libmesh/point.h"
33 
34 #include <numeric>
35 
37 
39 
42 {
44 
45  params.addRequiredParam<MeshGeneratorName>("input", "The mesh to extrude");
46 
47  params.addClassDescription("Extrudes a 2D mesh into 3D, can have variable a variable height for "
48  "each elevation, variable number of layers within each elevation and "
49  "remap subdomain_ids within each elevation");
50 
51  params.addRequiredParam<std::vector<Real>>("heights", "The height of each elevation");
52 
53  params.addRequiredParam<std::vector<unsigned int>>(
54  "num_layers", "The number of layers for each elevation - must be num_elevations in length!");
55 
56  params.addParam<std::vector<std::vector<subdomain_id_type>>>(
57  "subdomain_swaps",
58  "For each row, every two entries are interpreted as a pair of "
59  "'from' and 'to' to remap the subdomains for that elevation");
60 
61  params.addRequiredParam<Point>(
62  "direction",
63  "A vector that points in the direction to extrude (note, this will be "
64  "normalized internally - so don't worry about it here)");
65 
66  params.addParam<boundary_id_type>(
67  "top_boundary",
68  "The boundary ID to set on the top boundary. If ommitted one will be generated.");
69 
70  params.addParam<boundary_id_type>(
71  "bottom_boundary",
72  "The boundary ID to set on the bottom boundary. If omitted one will be generated.");
73 
74  return params;
75 }
76 
78  : MeshGenerator(parameters),
79  _input(getMesh("input")),
80  _heights(getParam<std::vector<Real>>("heights")),
81  _num_layers(getParam<std::vector<unsigned int>>("num_layers")),
82  _subdomain_swaps(getParam<std::vector<std::vector<subdomain_id_type>>>("subdomain_swaps")),
83  _direction(getParam<Point>("direction")),
84  _has_top_boundary(isParamValid("top_boundary")),
85  _top_boundary(isParamValid("top_boundary") ? getParam<boundary_id_type>("top_boundary") : 0),
86  _has_bottom_boundary(isParamValid("bottom_boundary")),
87  _bottom_boundary(isParamValid("bottom_boundary") ? getParam<boundary_id_type>("bottom_boundary")
88  : 0)
89 {
90  if (!_direction.norm())
91  paramError("direction", "Must have some length!");
92 
93  // Normalize it
94  _direction /= _direction.norm();
95 
96  const auto num_elevations = _heights.size();
97 
98  if (_num_layers.size() != num_elevations)
99  paramError("heights", "The length of 'heights' and 'num_layers' must be the same in ", name());
100 
101  if (_subdomain_swaps.size() && (_subdomain_swaps.size() != num_elevations))
102  paramError("subdomain_swaps",
103  "If specified, 'subdomain_swaps' must be the same length as 'heights' in ",
104  name());
105 
107 
108  // Reprocess the subdomain swaps to make pairs out of them so they are easier to use
109  for (unsigned int i = 0; i < _subdomain_swaps.size(); i++)
110  {
111  const auto & elevation_swaps = _subdomain_swaps[i];
112  auto & elevation_swap_pairs = _subdomain_swap_pairs[i];
113 
114  if (elevation_swaps.size() % 2)
115  paramError("subdomain_swaps",
116  "Row ",
117  i + 1,
118  " of subdomain_swaps in ",
119  name(),
120  " does not contain an even number of entries! Num entries: ",
121  elevation_swaps.size());
122 
123  for (unsigned int j = 0; j < elevation_swaps.size(); j += 2)
124  elevation_swap_pairs[elevation_swaps[j]] = elevation_swaps[j + 1];
125  }
126 }
127 
128 std::unique_ptr<MeshBase>
130 {
131  // Note: bulk of this code originally from libmesh mesh_modification.C
132  // Original copyright: Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
133  // Original license is LGPL so it can be used here.
134 
135  auto mesh = _mesh->buildMeshBaseObject();
136 
137  std::unique_ptr<MeshBase> input = std::move(_input);
138 
139  // If we're using a distributed mesh... then make sure we don't have any remote elements hanging
140  // around
141  if (!input->is_serial())
142  mesh->delete_remote_elements();
143 
144  unsigned int total_num_layers = std::accumulate(_num_layers.begin(), _num_layers.end(), 0);
145 
146  auto total_num_elevations = _heights.size();
147 
148  dof_id_type orig_elem = input->n_elem();
149  dof_id_type orig_nodes = input->n_nodes();
150 
151 #ifdef LIBMESH_ENABLE_UNIQUE_ID
152  unique_id_type orig_unique_ids = input->parallel_max_unique_id();
153 #endif
154 
155  unsigned int order = 1;
156 
157  BoundaryInfo & boundary_info = mesh->get_boundary_info();
158  const BoundaryInfo & input_boundary_info = input->get_boundary_info();
159 
160  // We know a priori how many elements we'll need
161  mesh->reserve_elem(total_num_layers * orig_elem);
162 
163  // For straightforward meshes we need one or two additional layers per
164  // element.
165  if (input->elements_begin() != input->elements_end() &&
166  (*input->elements_begin())->default_order() == SECOND)
167  order = 2;
168  mesh->comm().max(order);
169 
170  mesh->reserve_nodes((order * total_num_layers + 1) * orig_nodes);
171 
172  // Container to catch the boundary IDs handed back by the BoundaryInfo object
173  std::vector<boundary_id_type> ids_to_copy;
174 
175  Point old_distance;
176  Point current_distance;
177 
178  for (const auto & node : input->node_ptr_range())
179  {
180  unsigned int current_node_layer = 0;
181 
182  old_distance.zero();
183 
184  for (unsigned int e = 0; e < total_num_elevations; e++)
185  {
186  auto num_layers = _num_layers[e];
187 
188  auto height = _heights[e];
189 
190  for (unsigned int k = 0; k < order * num_layers + (e == 0 ? 1 : 0); ++k)
191  {
192  // For the first layer we don't need to move
193  if (e == 0 && k == 0)
194  current_distance.zero();
195  else
196  current_distance = old_distance + _direction * (height / (Real)num_layers / (Real)order);
197 
198  Node * new_node = mesh->add_point(*node + current_distance,
199  node->id() + (current_node_layer * orig_nodes),
200  node->processor_id());
201 
202 #ifdef LIBMESH_ENABLE_UNIQUE_ID
203  // Let's give the base of the extruded mesh the same
204  // unique_ids as the source mesh, in case anyone finds that
205  // a useful map to preserve.
206  const unique_id_type uid = (current_node_layer == 0)
207  ? node->unique_id()
208  : orig_unique_ids +
209  (current_node_layer - 1) * (orig_nodes + orig_elem) +
210  node->id();
211 
212  new_node->set_unique_id() = uid;
213 #endif
214 
215  input_boundary_info.boundary_ids(node, ids_to_copy);
216  boundary_info.add_node(new_node, ids_to_copy);
217 
218  old_distance = current_distance;
219  current_node_layer++;
220  }
221  }
222  }
223 
224  const std::set<boundary_id_type> & side_ids = input_boundary_info.get_side_boundary_ids();
225 
226  boundary_id_type next_side_id =
227  side_ids.empty() ? 0 : cast_int<boundary_id_type>(*side_ids.rbegin() + 1);
228 
229  // side_ids may not include ids from remote elements, in which case
230  // some processors may have underestimated the next_side_id; let's
231  // fix that.
232  input->comm().max(next_side_id);
233 
234  for (const auto & elem : input->element_ptr_range())
235  {
236  const ElemType etype = elem->type();
237 
238  // build_extrusion currently only works on coarse meshes
239  libmesh_assert(!elem->parent());
240 
241  unsigned int current_layer = 0;
242 
243  for (unsigned int e = 0; e != total_num_elevations; e++)
244  {
245  auto num_layers = _num_layers[e];
246 
247  for (unsigned int k = 0; k != num_layers; ++k)
248  {
249  Elem * new_elem;
250  switch (etype)
251  {
252  case EDGE2:
253  {
254  new_elem = new Quad4;
255  new_elem->set_node(0) =
256  mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * orig_nodes));
257  new_elem->set_node(1) =
258  mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * orig_nodes));
259  new_elem->set_node(2) =
260  mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer + 1) * orig_nodes));
261  new_elem->set_node(3) =
262  mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer + 1) * orig_nodes));
263 
264  if (elem->neighbor_ptr(0) == remote_elem)
265  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
266  if (elem->neighbor_ptr(1) == remote_elem)
267  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
268 
269  break;
270  }
271  case EDGE3:
272  {
273  new_elem = new Quad9;
274  new_elem->set_node(0) =
275  mesh->node_ptr(elem->node_ptr(0)->id() + (2 * current_layer * orig_nodes));
276  new_elem->set_node(1) =
277  mesh->node_ptr(elem->node_ptr(1)->id() + (2 * current_layer * orig_nodes));
278  new_elem->set_node(2) =
279  mesh->node_ptr(elem->node_ptr(1)->id() + ((2 * current_layer + 2) * orig_nodes));
280  new_elem->set_node(3) =
281  mesh->node_ptr(elem->node_ptr(0)->id() + ((2 * current_layer + 2) * orig_nodes));
282  new_elem->set_node(4) =
283  mesh->node_ptr(elem->node_ptr(2)->id() + (2 * current_layer * orig_nodes));
284  new_elem->set_node(5) =
285  mesh->node_ptr(elem->node_ptr(1)->id() + ((2 * current_layer + 1) * orig_nodes));
286  new_elem->set_node(6) =
287  mesh->node_ptr(elem->node_ptr(2)->id() + ((2 * current_layer + 2) * orig_nodes));
288  new_elem->set_node(7) =
289  mesh->node_ptr(elem->node_ptr(0)->id() + ((2 * current_layer + 1) * orig_nodes));
290  new_elem->set_node(8) =
291  mesh->node_ptr(elem->node_ptr(2)->id() + ((2 * current_layer + 1) * orig_nodes));
292 
293  if (elem->neighbor_ptr(0) == remote_elem)
294  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
295  if (elem->neighbor_ptr(1) == remote_elem)
296  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
297 
298  break;
299  }
300  case TRI3:
301  {
302  new_elem = new Prism6;
303  new_elem->set_node(0) =
304  mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * orig_nodes));
305  new_elem->set_node(1) =
306  mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * orig_nodes));
307  new_elem->set_node(2) =
308  mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * orig_nodes));
309  new_elem->set_node(3) =
310  mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer + 1) * orig_nodes));
311  new_elem->set_node(4) =
312  mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer + 1) * orig_nodes));
313  new_elem->set_node(5) =
314  mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer + 1) * orig_nodes));
315 
316  if (elem->neighbor_ptr(0) == remote_elem)
317  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
318  if (elem->neighbor_ptr(1) == remote_elem)
319  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
320  if (elem->neighbor_ptr(2) == remote_elem)
321  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
322 
323  break;
324  }
325  case TRI6:
326  {
327  new_elem = new Prism18;
328  new_elem->set_node(0) =
329  mesh->node_ptr(elem->node_ptr(0)->id() + (2 * current_layer * orig_nodes));
330  new_elem->set_node(1) =
331  mesh->node_ptr(elem->node_ptr(1)->id() + (2 * current_layer * orig_nodes));
332  new_elem->set_node(2) =
333  mesh->node_ptr(elem->node_ptr(2)->id() + (2 * current_layer * orig_nodes));
334  new_elem->set_node(3) =
335  mesh->node_ptr(elem->node_ptr(0)->id() + ((2 * current_layer + 2) * orig_nodes));
336  new_elem->set_node(4) =
337  mesh->node_ptr(elem->node_ptr(1)->id() + ((2 * current_layer + 2) * orig_nodes));
338  new_elem->set_node(5) =
339  mesh->node_ptr(elem->node_ptr(2)->id() + ((2 * current_layer + 2) * orig_nodes));
340  new_elem->set_node(6) =
341  mesh->node_ptr(elem->node_ptr(3)->id() + (2 * current_layer * orig_nodes));
342  new_elem->set_node(7) =
343  mesh->node_ptr(elem->node_ptr(4)->id() + (2 * current_layer * orig_nodes));
344  new_elem->set_node(8) =
345  mesh->node_ptr(elem->node_ptr(5)->id() + (2 * current_layer * orig_nodes));
346  new_elem->set_node(9) =
347  mesh->node_ptr(elem->node_ptr(0)->id() + ((2 * current_layer + 1) * orig_nodes));
348  new_elem->set_node(10) =
349  mesh->node_ptr(elem->node_ptr(1)->id() + ((2 * current_layer + 1) * orig_nodes));
350  new_elem->set_node(11) =
351  mesh->node_ptr(elem->node_ptr(2)->id() + ((2 * current_layer + 1) * orig_nodes));
352  new_elem->set_node(12) =
353  mesh->node_ptr(elem->node_ptr(3)->id() + ((2 * current_layer + 2) * orig_nodes));
354  new_elem->set_node(13) =
355  mesh->node_ptr(elem->node_ptr(4)->id() + ((2 * current_layer + 2) * orig_nodes));
356  new_elem->set_node(14) =
357  mesh->node_ptr(elem->node_ptr(5)->id() + ((2 * current_layer + 2) * orig_nodes));
358  new_elem->set_node(15) =
359  mesh->node_ptr(elem->node_ptr(3)->id() + ((2 * current_layer + 1) * orig_nodes));
360  new_elem->set_node(16) =
361  mesh->node_ptr(elem->node_ptr(4)->id() + ((2 * current_layer + 1) * orig_nodes));
362  new_elem->set_node(17) =
363  mesh->node_ptr(elem->node_ptr(5)->id() + ((2 * current_layer + 1) * orig_nodes));
364 
365  if (elem->neighbor_ptr(0) == remote_elem)
366  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
367  if (elem->neighbor_ptr(1) == remote_elem)
368  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
369  if (elem->neighbor_ptr(2) == remote_elem)
370  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
371 
372  break;
373  }
374  case QUAD4:
375  {
376  new_elem = new Hex8;
377  new_elem->set_node(0) =
378  mesh->node_ptr(elem->node_ptr(0)->id() + (current_layer * orig_nodes));
379  new_elem->set_node(1) =
380  mesh->node_ptr(elem->node_ptr(1)->id() + (current_layer * orig_nodes));
381  new_elem->set_node(2) =
382  mesh->node_ptr(elem->node_ptr(2)->id() + (current_layer * orig_nodes));
383  new_elem->set_node(3) =
384  mesh->node_ptr(elem->node_ptr(3)->id() + (current_layer * orig_nodes));
385  new_elem->set_node(4) =
386  mesh->node_ptr(elem->node_ptr(0)->id() + ((current_layer + 1) * orig_nodes));
387  new_elem->set_node(5) =
388  mesh->node_ptr(elem->node_ptr(1)->id() + ((current_layer + 1) * orig_nodes));
389  new_elem->set_node(6) =
390  mesh->node_ptr(elem->node_ptr(2)->id() + ((current_layer + 1) * orig_nodes));
391  new_elem->set_node(7) =
392  mesh->node_ptr(elem->node_ptr(3)->id() + ((current_layer + 1) * orig_nodes));
393 
394  if (elem->neighbor_ptr(0) == remote_elem)
395  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
396  if (elem->neighbor_ptr(1) == remote_elem)
397  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
398  if (elem->neighbor_ptr(2) == remote_elem)
399  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
400  if (elem->neighbor_ptr(3) == remote_elem)
401  new_elem->set_neighbor(4, const_cast<RemoteElem *>(remote_elem));
402 
403  break;
404  }
405  case QUAD9:
406  {
407  new_elem = new Hex27;
408  new_elem->set_node(0) =
409  mesh->node_ptr(elem->node_ptr(0)->id() + (2 * current_layer * orig_nodes));
410  new_elem->set_node(1) =
411  mesh->node_ptr(elem->node_ptr(1)->id() + (2 * current_layer * orig_nodes));
412  new_elem->set_node(2) =
413  mesh->node_ptr(elem->node_ptr(2)->id() + (2 * current_layer * orig_nodes));
414  new_elem->set_node(3) =
415  mesh->node_ptr(elem->node_ptr(3)->id() + (2 * current_layer * orig_nodes));
416  new_elem->set_node(4) =
417  mesh->node_ptr(elem->node_ptr(0)->id() + ((2 * current_layer + 2) * orig_nodes));
418  new_elem->set_node(5) =
419  mesh->node_ptr(elem->node_ptr(1)->id() + ((2 * current_layer + 2) * orig_nodes));
420  new_elem->set_node(6) =
421  mesh->node_ptr(elem->node_ptr(2)->id() + ((2 * current_layer + 2) * orig_nodes));
422  new_elem->set_node(7) =
423  mesh->node_ptr(elem->node_ptr(3)->id() + ((2 * current_layer + 2) * orig_nodes));
424  new_elem->set_node(8) =
425  mesh->node_ptr(elem->node_ptr(4)->id() + (2 * current_layer * orig_nodes));
426  new_elem->set_node(9) =
427  mesh->node_ptr(elem->node_ptr(5)->id() + (2 * current_layer * orig_nodes));
428  new_elem->set_node(10) =
429  mesh->node_ptr(elem->node_ptr(6)->id() + (2 * current_layer * orig_nodes));
430  new_elem->set_node(11) =
431  mesh->node_ptr(elem->node_ptr(7)->id() + (2 * current_layer * orig_nodes));
432  new_elem->set_node(12) =
433  mesh->node_ptr(elem->node_ptr(0)->id() + ((2 * current_layer + 1) * orig_nodes));
434  new_elem->set_node(13) =
435  mesh->node_ptr(elem->node_ptr(1)->id() + ((2 * current_layer + 1) * orig_nodes));
436  new_elem->set_node(14) =
437  mesh->node_ptr(elem->node_ptr(2)->id() + ((2 * current_layer + 1) * orig_nodes));
438  new_elem->set_node(15) =
439  mesh->node_ptr(elem->node_ptr(3)->id() + ((2 * current_layer + 1) * orig_nodes));
440  new_elem->set_node(16) =
441  mesh->node_ptr(elem->node_ptr(4)->id() + ((2 * current_layer + 2) * orig_nodes));
442  new_elem->set_node(17) =
443  mesh->node_ptr(elem->node_ptr(5)->id() + ((2 * current_layer + 2) * orig_nodes));
444  new_elem->set_node(18) =
445  mesh->node_ptr(elem->node_ptr(6)->id() + ((2 * current_layer + 2) * orig_nodes));
446  new_elem->set_node(19) =
447  mesh->node_ptr(elem->node_ptr(7)->id() + ((2 * current_layer + 2) * orig_nodes));
448  new_elem->set_node(20) =
449  mesh->node_ptr(elem->node_ptr(8)->id() + (2 * current_layer * orig_nodes));
450  new_elem->set_node(21) =
451  mesh->node_ptr(elem->node_ptr(4)->id() + ((2 * current_layer + 1) * orig_nodes));
452  new_elem->set_node(22) =
453  mesh->node_ptr(elem->node_ptr(5)->id() + ((2 * current_layer + 1) * orig_nodes));
454  new_elem->set_node(23) =
455  mesh->node_ptr(elem->node_ptr(6)->id() + ((2 * current_layer + 1) * orig_nodes));
456  new_elem->set_node(24) =
457  mesh->node_ptr(elem->node_ptr(7)->id() + ((2 * current_layer + 1) * orig_nodes));
458  new_elem->set_node(25) =
459  mesh->node_ptr(elem->node_ptr(8)->id() + ((2 * current_layer + 2) * orig_nodes));
460  new_elem->set_node(26) =
461  mesh->node_ptr(elem->node_ptr(8)->id() + ((2 * current_layer + 1) * orig_nodes));
462 
463  if (elem->neighbor_ptr(0) == remote_elem)
464  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
465  if (elem->neighbor_ptr(1) == remote_elem)
466  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
467  if (elem->neighbor_ptr(2) == remote_elem)
468  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
469  if (elem->neighbor_ptr(3) == remote_elem)
470  new_elem->set_neighbor(4, const_cast<RemoteElem *>(remote_elem));
471 
472  break;
473  }
474  default:
475  {
476  libmesh_not_implemented();
477  break;
478  }
479  }
480 
481  new_elem->set_id(elem->id() + (current_layer * orig_elem));
482  new_elem->processor_id() = elem->processor_id();
483 
484 #ifdef LIBMESH_ENABLE_UNIQUE_ID
485  // Let's give the base of the extruded mesh the same
486  // unique_ids as the source mesh, in case anyone finds that
487  // a useful map to preserve.
488  const unique_id_type uid = (current_layer == 0)
489  ? elem->unique_id()
490  : orig_unique_ids +
491  (current_layer - 1) * (orig_nodes + orig_elem) +
492  orig_nodes + elem->id();
493 
494  new_elem->set_unique_id() = uid;
495 #endif
496 
497  // maintain the subdomain_id
498  new_elem->subdomain_id() = elem->subdomain_id();
499 
500  if (_subdomain_swap_pairs.size())
501  {
502  auto & elevation_swap_pairs = _subdomain_swap_pairs[e];
503 
504  auto new_id_it = elevation_swap_pairs.find(elem->subdomain_id());
505 
506  if (new_id_it != elevation_swap_pairs.end())
507  new_elem->subdomain_id() = new_id_it->second;
508  }
509 
510  new_elem = mesh->add_elem(new_elem);
511 
512  // Copy any old boundary ids on all sides
513  for (auto s : elem->side_index_range())
514  {
515  input_boundary_info.boundary_ids(elem, s, ids_to_copy);
516 
517  if (new_elem->dim() == 3)
518  {
519  // For 2D->3D extrusion, we give the boundary IDs
520  // for side s on the old element to side s+1 on the
521  // new element. This is just a happy coincidence as
522  // far as I can tell...
523  boundary_info.add_side(new_elem, cast_int<unsigned short>(s + 1), ids_to_copy);
524  }
525  else
526  {
527  // For 1D->2D extrusion, the boundary IDs map as:
528  // Old elem -> New elem
529  // 0 -> 3
530  // 1 -> 1
531  libmesh_assert_less(s, 2);
532  const unsigned short sidemap[2] = {3, 1};
533  boundary_info.add_side(new_elem, sidemap[s], ids_to_copy);
534  }
535  }
536 
537  // Give new boundary ids to bottom and top
538  if (current_layer == 0)
539  {
541  boundary_info.add_side(new_elem, 0, _bottom_boundary);
542  else
543  boundary_info.add_side(new_elem, 0, next_side_id);
544  }
545 
546  if (current_layer == total_num_layers - 1)
547  {
548  // For 2D->3D extrusion, the "top" ID is 1+the original
549  // element's number of sides. For 1D->2D extrusion, the
550  // "top" ID is side 2.
551  const unsigned short top_id =
552  new_elem->dim() == 3 ? cast_int<unsigned short>(elem->n_sides() + 1) : 2;
553 
554  if (_has_top_boundary)
555  boundary_info.add_side(new_elem, top_id, _top_boundary);
556  else
557  boundary_info.add_side(new_elem, top_id, cast_int<boundary_id_type>(next_side_id + 1));
558  }
559 
560  current_layer++;
561  }
562  }
563  }
564 
565  return mesh;
566 }
registerMooseObject
registerMooseObject("MooseApp", FancyExtruderGenerator)
MeshGenerator
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
InputParameters::addParam
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object.
Definition: InputParameters.h:1198
FancyExtruderGenerator::_subdomain_swap_pairs
std::vector< std::unordered_map< subdomain_id_type, subdomain_id_type > > _subdomain_swap_pairs
Easier to work with version of _sudomain_swaps.
Definition: FancyExtruderGenerator.h:48
FancyExtruderGenerator::_num_layers
const std::vector< unsigned int > & _num_layers
Number of layers in each elevation.
Definition: FancyExtruderGenerator.h:42
FancyExtruderGenerator::_heights
const std::vector< Real > & _heights
Height of each elevation.
Definition: FancyExtruderGenerator.h:39
MooseObject::paramError
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseObject.h:215
MeshGenerator::_mesh
std::shared_ptr< MooseMesh > & _mesh
References to the mesh and displaced mesh (currently in the ActionWarehouse)
Definition: MeshGenerator.h:87
InputParameters
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
Definition: InputParameters.h:53
FancyExtruderGenerator::validParams
static InputParameters validParams()
Definition: FancyExtruderGenerator.C:41
FancyExtruderGenerator.h
FancyExtruderGenerator::_bottom_boundary
boundary_id_type _bottom_boundary
Definition: FancyExtruderGenerator.h:57
FancyExtruderGenerator::_has_top_boundary
bool _has_top_boundary
Definition: FancyExtruderGenerator.h:53
FancyExtruderGenerator::generate
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
Definition: FancyExtruderGenerator.C:129
FancyExtruderGenerator::_has_bottom_boundary
bool _has_bottom_boundary
Definition: FancyExtruderGenerator.h:56
InputParameters::addClassDescription
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
Definition: InputParameters.C:70
defineLegacyParams
defineLegacyParams(FancyExtruderGenerator)
std
Definition: TheWarehouse.h:80
FancyExtruderGenerator::FancyExtruderGenerator
FancyExtruderGenerator(const InputParameters &parameters)
Definition: FancyExtruderGenerator.C:77
MeshGenerator::validParams
static InputParameters validParams()
Constructor.
Definition: MeshGenerator.C:17
FancyExtruderGenerator::_input
std::unique_ptr< MeshBase > & _input
Mesh that comes from another generator.
Definition: FancyExtruderGenerator.h:36
FancyExtruderGenerator::_subdomain_swaps
const std::vector< std::vector< subdomain_id_type > > & _subdomain_swaps
Subdomains to swap out for each elevation.
Definition: FancyExtruderGenerator.h:45
InputParameters::addRequiredParam
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
Definition: InputParameters.h:1176
FancyExtruderGenerator
Generates a mesh by reading it from an file.
Definition: FancyExtruderGenerator.h:25
FancyExtruderGenerator::_direction
Point _direction
The direction of the extrusion.
Definition: FancyExtruderGenerator.h:51
MooseObject::name
virtual const std::string & name() const
Get the name of the object.
Definition: MooseObject.h:70
FancyExtruderGenerator::_top_boundary
boundary_id_type _top_boundary
Definition: FancyExtruderGenerator.h:54