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"
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");
51 params.
addRequiredParam<std::vector<Real>>(
"heights",
"The height of each elevation");
54 "num_layers",
"The number of layers for each elevation - must be num_elevations in length!");
56 params.
addParam<std::vector<std::vector<subdomain_id_type>>>(
58 "For each row, every two entries are interpreted as a pair of "
59 "'from' and 'to' to remap the subdomains for that elevation");
63 "A vector that points in the direction to extrude (note, this will be "
64 "normalized internally - so don't worry about it here)");
68 "The boundary ID to set on the top boundary. If ommitted one will be generated.");
72 "The boundary ID to set on the bottom boundary. If omitted one will be generated.");
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")
91 paramError(
"direction",
"Must have some length!");
96 const auto num_elevations =
_heights.size();
99 paramError(
"heights",
"The length of 'heights' and 'num_layers' must be the same in ",
name());
103 "If specified, 'subdomain_swaps' must be the same length as 'heights' in ",
114 if (elevation_swaps.size() % 2)
118 " of subdomain_swaps in ",
120 " does not contain an even number of entries! Num entries: ",
121 elevation_swaps.size());
123 for (
unsigned int j = 0; j < elevation_swaps.size(); j += 2)
124 elevation_swap_pairs[elevation_swaps[j]] = elevation_swaps[j + 1];
128 std::unique_ptr<MeshBase>
135 auto mesh =
_mesh->buildMeshBaseObject();
137 std::unique_ptr<MeshBase> input = std::move(
_input);
141 if (!input->is_serial())
142 mesh->delete_remote_elements();
146 auto total_num_elevations =
_heights.size();
148 dof_id_type orig_elem = input->n_elem();
149 dof_id_type orig_nodes = input->n_nodes();
151 #ifdef LIBMESH_ENABLE_UNIQUE_ID
152 unique_id_type orig_unique_ids = input->parallel_max_unique_id();
155 unsigned int order = 1;
157 BoundaryInfo & boundary_info = mesh->get_boundary_info();
158 const BoundaryInfo & input_boundary_info = input->get_boundary_info();
161 mesh->reserve_elem(total_num_layers * orig_elem);
165 if (input->elements_begin() != input->elements_end() &&
166 (*input->elements_begin())->default_order() == SECOND)
168 mesh->comm().max(order);
170 mesh->reserve_nodes((order * total_num_layers + 1) * orig_nodes);
173 std::vector<boundary_id_type> ids_to_copy;
176 Point current_distance;
178 for (
const auto & node : input->node_ptr_range())
180 unsigned int current_node_layer = 0;
184 for (
unsigned int e = 0; e < total_num_elevations; e++)
190 for (
unsigned int k = 0; k < order * num_layers + (e == 0 ? 1 : 0); ++k)
193 if (e == 0 && k == 0)
194 current_distance.zero();
196 current_distance = old_distance +
_direction * (height / (Real)num_layers / (Real)order);
198 Node * new_node = mesh->add_point(*node + current_distance,
199 node->id() + (current_node_layer * orig_nodes),
200 node->processor_id());
202 #ifdef LIBMESH_ENABLE_UNIQUE_ID
206 const unique_id_type uid = (current_node_layer == 0)
209 (current_node_layer - 1) * (orig_nodes + orig_elem) +
212 new_node->set_unique_id() = uid;
215 input_boundary_info.boundary_ids(node, ids_to_copy);
216 boundary_info.add_node(new_node, ids_to_copy);
218 old_distance = current_distance;
219 current_node_layer++;
224 const std::set<boundary_id_type> & side_ids = input_boundary_info.get_side_boundary_ids();
226 boundary_id_type next_side_id =
227 side_ids.empty() ? 0 : cast_int<boundary_id_type>(*side_ids.rbegin() + 1);
232 input->comm().max(next_side_id);
234 for (
const auto & elem : input->element_ptr_range())
236 const ElemType etype = elem->type();
239 libmesh_assert(!elem->parent());
241 unsigned int current_layer = 0;
243 for (
unsigned int e = 0; e != total_num_elevations; e++)
247 for (
unsigned int k = 0; k != num_layers; ++k)
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
476 libmesh_not_implemented();
481 new_elem->set_id(elem->id() + (current_layer * orig_elem));
482 new_elem->processor_id() = elem->processor_id();
484 #ifdef LIBMESH_ENABLE_UNIQUE_ID
488 const unique_id_type uid = (current_layer == 0)
491 (current_layer - 1) * (orig_nodes + orig_elem) +
492 orig_nodes + elem->id();
494 new_elem->set_unique_id() = uid;
498 new_elem->subdomain_id() = elem->subdomain_id();
504 auto new_id_it = elevation_swap_pairs.find(elem->subdomain_id());
506 if (new_id_it != elevation_swap_pairs.end())
507 new_elem->subdomain_id() = new_id_it->second;
510 new_elem = mesh->add_elem(new_elem);
513 for (
auto s : elem->side_index_range())
515 input_boundary_info.boundary_ids(elem, s, ids_to_copy);
517 if (new_elem->dim() == 3)
523 boundary_info.add_side(new_elem, cast_int<unsigned short>(s + 1), ids_to_copy);
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);
538 if (current_layer == 0)
543 boundary_info.add_side(new_elem, 0, next_side_id);
546 if (current_layer == total_num_layers - 1)
551 const unsigned short top_id =
552 new_elem->dim() == 3 ? cast_int<unsigned short>(elem->n_sides() + 1) : 2;
557 boundary_info.add_side(new_elem, top_id, cast_int<boundary_id_type>(next_side_id + 1));