288{
289
291
292
293 const auto ref_vol = target_elem->reference_elem()->volume();
294
295
296 const Real sqrt_2 = std::sqrt(
Real(2));
297 const Real sqrt_3 = std::sqrt(
Real(3));
298 std::vector<std::unique_ptr<Node>> owned_nodes;
299
301
302
303 if (type_str.compare(0, 3, "TRI") == 0)
304 {
305
306
307
308
309
310 const auto side_length = std::sqrt(4. / sqrt_3 * ref_vol);
311
312
313 const auto & s = side_length;
314
318
319 switch (type)
320 {
323
324 break;
325 }
326
329
330
332 owned_nodes.emplace_back(
Node::build(
Point(0.75 * s, 0.25 * sqrt_3 * s), 4));
333 owned_nodes.emplace_back(
Node::build(
Point(0.25 * s, 0.25 * sqrt_3 * s), 5));
334
336 {
337
338 const auto & on = owned_nodes;
339 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[1] + *on[2]) / 3.), 6));
340 }
341
342 break;
343 }
344
345 default:
346 libmesh_error_msg("Unsupported triangular element: " << type_str);
347 break;
348 }
349 }
350
351
352 else if (type_str.compare(0, 5, "PRISM") == 0)
353 {
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 const auto side_length = std::cbrt(16. * ref_vol / 3.);
371
372 const auto target_height = 0.25 * side_length * sqrt_3;
373
374 const auto & s = side_length;
375 const auto & h = target_height;
376
379 owned_nodes.emplace_back(
Node::build(
Point(0.5 * s, 0.5 * sqrt_3 * s, 0.), 2));
382 owned_nodes.emplace_back(
Node::build(
Point(0.5 * s, 0.5 * sqrt_3 * s, h), 5));
383
385 {
386
387 const auto & on = owned_nodes;
397
399 {
400
401 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[1] + *on[3] + *on[4]) / 4.), 15));
402 owned_nodes.emplace_back(
Node::build(
Point((*on[1] + *on[2] + *on[4] + *on[5]) / 4.), 16));
403 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[2] + *on[3] + *on[5]) / 4.), 17));
404
406 {
407
408 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[1] + *on[2]) / 3.), 18));
409 owned_nodes.emplace_back(
Node::build(
Point((*on[3] + *on[4] + *on[5]) / 3.), 19));
410
412
413 owned_nodes.emplace_back(
Node::build(
Point((*on[9] + *on[10] + *on[11]) / 3.), 20));
414
415 }
416 }
417 }
418
420 libmesh_error_msg("Unsupported prism element: " << type_str);
421
422 }
423
424
425 else if (type_str.compare(0, 7, "PYRAMID") == 0)
426 {
427
428
429
430
431
432
433
434
435
436
437
438
439 const auto side_length = std::cbrt(3. * sqrt_2 * ref_vol);
440
441 const auto target_height = side_length / sqrt_2;
442
443 const auto & s = side_length;
444 const auto & h = target_height;
445
446
452
454 {
455 const auto & on = owned_nodes;
456
457
458
459 owned_nodes.emplace_back(
Node::build((*on[0] + *on[1]) / 2., 5));
460 owned_nodes.emplace_back(
Node::build((*on[1] + *on[2]) / 2., 6));
461 owned_nodes.emplace_back(
Node::build((*on[2] + *on[3]) / 2., 7));
462 owned_nodes.emplace_back(
Node::build((*on[3] + *on[0]) / 2., 8));
463
464
469
471 {
472
473 owned_nodes.emplace_back(
475
477 {
478
479 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[1] + *on[4]) / 3.), 14));
480 owned_nodes.emplace_back(
Node::build(
Point((*on[1] + *on[2] + *on[4]) / 3.), 15));
481 owned_nodes.emplace_back(
Node::build(
Point((*on[2] + *on[3] + *on[4]) / 3.), 16));
482 owned_nodes.emplace_back(
Node::build(
Point((*on[3] + *on[0] + *on[4]) / 3.), 17));
483 }
484 }
485 }
486
488 libmesh_error_msg("Unsupported pyramid element: " << type_str);
489
490 }
491
492
493 else if (type_str.compare(0, 3, "TET") == 0)
494 {
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 const auto side_length = std::cbrt(6. * sqrt_2 * ref_vol);
511
512 const auto target_height = sqrt_2 / sqrt_3 * side_length;
513
514 const auto & s = side_length;
515 const auto & h = target_height;
516
517
518
521 owned_nodes.emplace_back(
Node::build(
Point(0.5 * s, 0.5 * sqrt_3 * s, 0.), 2));
522 owned_nodes.emplace_back(
Node::build(
Point(0.5 * s, sqrt_3 / 6. * s, h), 3));
523
525 {
526 const auto & on = owned_nodes;
527
528
529
533
537
539 {
540
541 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[1] + *on[2]) / 3.), 10));
542 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[1] + *on[3]) / 3.), 11));
543 owned_nodes.emplace_back(
Node::build(
Point((*on[1] + *on[2] + *on[3]) / 3.), 12));
544 owned_nodes.emplace_back(
Node::build(
Point((*on[0] + *on[2] + *on[3]) / 3.), 13));
545 }
546 }
547
548 else if (type !=
TET4)
549 libmesh_error_msg("Unsupported tet element: " << type_str);
550
551 }
552
553
554 else
555 for (const auto & node : target_elem->reference_elem()->node_ref_range())
556 owned_nodes.emplace_back(
Node::build(node, node.id()));
557
558
559 for (const auto & node_ptr : owned_nodes)
560 target_elem->set_node(node_ptr->id(), node_ptr.
get());
561
563
564 return std::make_pair(std::move(target_elem), std::move(owned_nodes));
565}
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
A Node is like a Point, but with more information.
static std::unique_ptr< Node > build(const Node &n)
A Point defines a location in LIBMESH_DIM dimensional Real space.
const Elem & get(const ElemType type_in)
bool relative_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
Function to check whether two variables are equal within a relative tolerance.
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real