libMesh
Namespaces | Classes | Functions
libMesh::MeshTools::Generation Namespace Reference

Tools for Mesh generation. More...

Namespaces

 Private
 

Classes

class  QueryElemSubdomainIDBase
 Class for receiving the callback during extrusion generation and providing user-defined subdomains based on the old (existing) element id and the current layer. More...
 

Functions

void build_cube (UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
 Builds a \( nx \times ny \times nz \) (elements) cube. More...
 
void build_point (UnstructuredMesh &mesh, const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
 A specialized build_cube() for 0D meshes. More...
 
void build_line (UnstructuredMesh &mesh, const unsigned int nx, const Real xmin=0., const Real xmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
 A specialized build_cube() for 1D meshes. More...
 
void build_square (UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
 A specialized build_cube() for 2D meshes. More...
 
void build_sphere (UnstructuredMesh &mesh, const Real rad=1, const unsigned int nr=2, const ElemType type=INVALID_ELEM, const unsigned int n_smooth=2, const bool flat=true)
 Meshes a spherical or mapped-spherical domain. More...
 
void build_extrusion (UnstructuredMesh &mesh, const MeshBase &cross_section, const unsigned int nz, RealVectorValue extrusion_vector, QueryElemSubdomainIDBase *elem_subdomain=nullptr)
 Meshes the tensor product of a 1D and a 1D-or-2D domain. More...
 
void build_delaunay_square (UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin, const Real xmax, const Real ymin, const Real ymax, const ElemType type, const std::vector< TriangleInterface::Hole * > *holes=nullptr)
 Meshes a rectangular (2D) region (with or without holes) with a Delaunay triangulation. More...
 

Detailed Description

Tools for Mesh generation.

Author
Benjamin S. Kirk
Date
2004

Function Documentation

◆ build_cube()

void libMesh::MeshTools::Generation::build_cube ( UnstructuredMesh mesh,
const unsigned int  nx = 0,
const unsigned int  ny = 0,
const unsigned int  nz = 0,
const Real  xmin = 0.,
const Real  xmax = 1.,
const Real  ymin = 0.,
const Real  ymax = 1.,
const Real  zmin = 0.,
const Real  zmax = 1.,
const ElemType  type = INVALID_ELEM,
const bool  gauss_lobatto_grid = false 
)

Builds a \( nx \times ny \times nz \) (elements) cube.

Defaults to a unit cube (or line in 1D, square in 2D), but the dimensions can be specified through the optional arguments.

Boundary ids are set to be equal to the side indexing on a master hex

Definition at line 298 of file mesh_generation.C.

307 {
308  START_LOG("build_cube()", "MeshTools::Generation");
309 
310  // Declare that we are using the indexing utility routine
311  // in the "Private" part of our current namespace. If this doesn't
312  // work in GCC 2.95.3 we can either remove it or stop supporting
313  // 2.95.3 altogether.
314  // Changing this to import the whole namespace... just importing idx
315  // causes an internal compiler error for Intel Compiler 11.0 on Linux
316  // in debug mode.
317  using namespace MeshTools::Generation::Private;
318 
319  // Clear the mesh and start from scratch
320  mesh.clear();
321 
322  BoundaryInfo & boundary_info = mesh.get_boundary_info();
323 
324  if (nz != 0)
325  {
326  mesh.set_mesh_dimension(3);
327  mesh.set_spatial_dimension(3);
328  }
329  else if (ny != 0)
330  {
331  mesh.set_mesh_dimension(2);
332  mesh.set_spatial_dimension(2);
333  }
334  else if (nx != 0)
335  {
336  mesh.set_mesh_dimension(1);
337  mesh.set_spatial_dimension(1);
338  }
339  else
340  {
341  // Will we get here?
342  mesh.set_mesh_dimension(0);
343  mesh.set_spatial_dimension(0);
344  }
345 
346  switch (mesh.mesh_dimension())
347  {
348  //---------------------------------------------------------------------
349  // Build a 0D point
350  case 0:
351  {
352  libmesh_assert_equal_to (nx, 0);
353  libmesh_assert_equal_to (ny, 0);
354  libmesh_assert_equal_to (nz, 0);
355 
356  libmesh_assert (type == INVALID_ELEM || type == NODEELEM);
357 
358  // Build one nodal element for the mesh
359  mesh.add_point (Point(0, 0, 0), 0);
360  Elem * elem = mesh.add_elem (new NodeElem);
361  elem->set_node(0) = mesh.node_ptr(0);
362 
363  break;
364  }
365 
366 
367 
368  //---------------------------------------------------------------------
369  // Build a 1D line
370  case 1:
371  {
372  libmesh_assert_not_equal_to (nx, 0);
373  libmesh_assert_equal_to (ny, 0);
374  libmesh_assert_equal_to (nz, 0);
375  libmesh_assert_less (xmin, xmax);
376 
377  // Reserve elements
378  switch (type)
379  {
380  case INVALID_ELEM:
381  case EDGE2:
382  case EDGE3:
383  case EDGE4:
384  {
385  mesh.reserve_elem (nx);
386  break;
387  }
388 
389  default:
390  libmesh_error_msg("ERROR: Unrecognized 1D element type.");
391  }
392 
393  // Reserve nodes
394  switch (type)
395  {
396  case INVALID_ELEM:
397  case EDGE2:
398  {
399  mesh.reserve_nodes(nx+1);
400  break;
401  }
402 
403  case EDGE3:
404  {
405  mesh.reserve_nodes(2*nx+1);
406  break;
407  }
408 
409  case EDGE4:
410  {
411  mesh.reserve_nodes(3*nx+1);
412  break;
413  }
414 
415  default:
416  libmesh_error_msg("ERROR: Unrecognized 1D element type.");
417  }
418 
419 
420  // Build the nodes, depends on whether we're using linears,
421  // quadratics or cubics and whether using uniform grid or Gauss-Lobatto
422  unsigned int node_id = 0;
423  switch(type)
424  {
425  case INVALID_ELEM:
426  case EDGE2:
427  {
428  for (unsigned int i=0; i<=nx; i++)
429  mesh.add_point (Point(static_cast<Real>(i)/nx, 0, 0), node_id++);
430 
431  break;
432  }
433 
434  case EDGE3:
435  {
436  for (unsigned int i=0; i<=2*nx; i++)
437  mesh.add_point (Point(static_cast<Real>(i)/(2*nx), 0, 0), node_id++);
438  break;
439  }
440 
441  case EDGE4:
442  {
443  for (unsigned int i=0; i<=3*nx; i++)
444  mesh.add_point (Point(static_cast<Real>(i)/(3*nx), 0, 0), node_id++);
445 
446  break;
447  }
448 
449  default:
450  libmesh_error_msg("ERROR: Unrecognized 1D element type.");
451 
452  }
453 
454  // Build the elements of the mesh
455  switch(type)
456  {
457  case INVALID_ELEM:
458  case EDGE2:
459  {
460  for (unsigned int i=0; i<nx; i++)
461  {
462  Elem * elem = new Edge2;
463  elem->set_id(i);
464  elem = mesh.add_elem (elem);
465  elem->set_node(0) = mesh.node_ptr(i);
466  elem->set_node(1) = mesh.node_ptr(i+1);
467 
468  if (i == 0)
469  boundary_info.add_side(elem, 0, 0);
470 
471  if (i == (nx-1))
472  boundary_info.add_side(elem, 1, 1);
473  }
474  break;
475  }
476 
477  case EDGE3:
478  {
479  for (unsigned int i=0; i<nx; i++)
480  {
481  Elem * elem = new Edge3;
482  elem->set_id(i);
483  elem = mesh.add_elem (elem);
484  elem->set_node(0) = mesh.node_ptr(2*i);
485  elem->set_node(2) = mesh.node_ptr(2*i+1);
486  elem->set_node(1) = mesh.node_ptr(2*i+2);
487 
488  if (i == 0)
489  boundary_info.add_side(elem, 0, 0);
490 
491  if (i == (nx-1))
492  boundary_info.add_side(elem, 1, 1);
493  }
494  break;
495  }
496 
497  case EDGE4:
498  {
499  for (unsigned int i=0; i<nx; i++)
500  {
501  Elem * elem = new Edge4;
502  elem->set_id(i);
503  elem = mesh.add_elem (elem);
504  elem->set_node(0) = mesh.node_ptr(3*i);
505  elem->set_node(2) = mesh.node_ptr(3*i+1);
506  elem->set_node(3) = mesh.node_ptr(3*i+2);
507  elem->set_node(1) = mesh.node_ptr(3*i+3);
508 
509  if (i == 0)
510  boundary_info.add_side(elem, 0, 0);
511 
512  if (i == (nx-1))
513  boundary_info.add_side(elem, 1, 1);
514  }
515  break;
516  }
517 
518  default:
519  libmesh_error_msg("ERROR: Unrecognized 1D element type.");
520  }
521 
522  // Move the nodes to their final locations.
523  if (gauss_lobatto_grid)
524  {
525  GaussLobattoRedistributionFunction func(nx, xmin, xmax);
527  }
528  else // !gauss_lobatto_grid
529  {
530  for (Node * node : mesh.node_ptr_range())
531  (*node)(0) = (*node)(0)*(xmax-xmin) + xmin;
532  }
533 
534  // Add sideset names to boundary info
535  boundary_info.sideset_name(0) = "left";
536  boundary_info.sideset_name(1) = "right";
537 
538  // Add nodeset names to boundary info
539  boundary_info.nodeset_name(0) = "left";
540  boundary_info.nodeset_name(1) = "right";
541 
542  break;
543  }
544 
545 
546 
547 
548 
549 
550 
551 
552 
553 
554  //---------------------------------------------------------------------
555  // Build a 2D quadrilateral
556  case 2:
557  {
558  libmesh_assert_not_equal_to (nx, 0);
559  libmesh_assert_not_equal_to (ny, 0);
560  libmesh_assert_equal_to (nz, 0);
561  libmesh_assert_less (xmin, xmax);
562  libmesh_assert_less (ymin, ymax);
563 
564  // Reserve elements. The TRI3 and TRI6 meshes
565  // have twice as many elements...
566  switch (type)
567  {
568  case INVALID_ELEM:
569  case QUAD4:
570  case QUAD8:
571  case QUAD9:
572  {
573  mesh.reserve_elem (nx*ny);
574  break;
575  }
576 
577  case TRI3:
578  case TRI6:
579  {
580  mesh.reserve_elem (2*nx*ny);
581  break;
582  }
583 
584  default:
585  libmesh_error_msg("ERROR: Unrecognized 2D element type.");
586  }
587 
588 
589 
590  // Reserve nodes. The quadratic element types
591  // need to reserve more nodes than the linear types.
592  switch (type)
593  {
594  case INVALID_ELEM:
595  case QUAD4:
596  case TRI3:
597  {
598  mesh.reserve_nodes( (nx+1)*(ny+1) );
599  break;
600  }
601 
602  case QUAD8:
603  case QUAD9:
604  case TRI6:
605  {
606  mesh.reserve_nodes( (2*nx+1)*(2*ny+1) );
607  break;
608  }
609 
610 
611  default:
612  libmesh_error_msg("ERROR: Unrecognized 2D element type.");
613  }
614 
615 
616 
617  // Build the nodes. Depends on whether you are using a linear
618  // or quadratic element, and whether you are using a uniform
619  // grid or the Gauss-Lobatto grid points.
620  unsigned int node_id = 0;
621  switch (type)
622  {
623  case INVALID_ELEM:
624  case QUAD4:
625  case TRI3:
626  {
627  for (unsigned int j=0; j<=ny; j++)
628  for (unsigned int i=0; i<=nx; i++)
629  mesh.add_point (Point(static_cast<Real>(i)/static_cast<Real>(nx),
630  static_cast<Real>(j)/static_cast<Real>(ny),
631  0.), node_id++);
632 
633  break;
634  }
635 
636  case QUAD8:
637  case QUAD9:
638  case TRI6:
639  {
640  for (unsigned int j=0; j<=(2*ny); j++)
641  for (unsigned int i=0; i<=(2*nx); i++)
642  mesh.add_point (Point(static_cast<Real>(i)/static_cast<Real>(2*nx),
643  static_cast<Real>(j)/static_cast<Real>(2*ny),
644  0), node_id++);
645 
646  break;
647  }
648 
649 
650  default:
651  libmesh_error_msg("ERROR: Unrecognized 2D element type.");
652  }
653 
654 
655 
656 
657 
658 
659  // Build the elements. Each one is a bit different.
660  unsigned int elem_id = 0;
661  switch (type)
662  {
663 
664  case INVALID_ELEM:
665  case QUAD4:
666  {
667  for (unsigned int j=0; j<ny; j++)
668  for (unsigned int i=0; i<nx; i++)
669  {
670  Elem * elem = new Quad4;
671  elem->set_id(elem_id++);
672  elem = mesh.add_elem (elem);
673 
674  elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j) );
675  elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+1,j) );
676  elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+1,j+1));
677  elem->set_node(3) = mesh.node_ptr(idx(type,nx,i,j+1) );
678 
679  if (j == 0)
680  boundary_info.add_side(elem, 0, 0);
681 
682  if (j == (ny-1))
683  boundary_info.add_side(elem, 2, 2);
684 
685  if (i == 0)
686  boundary_info.add_side(elem, 3, 3);
687 
688  if (i == (nx-1))
689  boundary_info.add_side(elem, 1, 1);
690  }
691  break;
692  }
693 
694 
695  case TRI3:
696  {
697  for (unsigned int j=0; j<ny; j++)
698  for (unsigned int i=0; i<nx; i++)
699  {
700  // Add first Tri3
701  Elem * elem = new Tri3;
702  elem->set_id(elem_id++);
703  elem = mesh.add_elem (elem);
704 
705  elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j) );
706  elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+1,j) );
707  elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+1,j+1));
708 
709  if (j == 0)
710  boundary_info.add_side(elem, 0, 0);
711 
712  if (i == (nx-1))
713  boundary_info.add_side(elem, 1, 1);
714 
715  // Add second Tri3
716  elem = new Tri3;
717  elem->set_id(elem_id++);
718  elem = mesh.add_elem (elem);
719 
720  elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j) );
721  elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+1,j+1));
722  elem->set_node(2) = mesh.node_ptr(idx(type,nx,i,j+1) );
723 
724  if (j == (ny-1))
725  boundary_info.add_side(elem, 1, 2);
726 
727  if (i == 0)
728  boundary_info.add_side(elem, 2, 3);
729  }
730  break;
731  }
732 
733 
734 
735  case QUAD8:
736  case QUAD9:
737  {
738  for (unsigned int j=0; j<(2*ny); j += 2)
739  for (unsigned int i=0; i<(2*nx); i += 2)
740  {
741  Elem * elem = (type == QUAD8) ?
742  static_cast<Elem *>(new Quad8) :
743  static_cast<Elem *>(new Quad9);
744  elem->set_id(elem_id++);
745  elem = mesh.add_elem (elem);
746 
747  elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j) );
748  elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+2,j) );
749  elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+2,j+2));
750  elem->set_node(3) = mesh.node_ptr(idx(type,nx,i,j+2) );
751  elem->set_node(4) = mesh.node_ptr(idx(type,nx,i+1,j) );
752  elem->set_node(5) = mesh.node_ptr(idx(type,nx,i+2,j+1));
753  elem->set_node(6) = mesh.node_ptr(idx(type,nx,i+1,j+2));
754  elem->set_node(7) = mesh.node_ptr(idx(type,nx,i,j+1) );
755  if (type == QUAD9)
756  elem->set_node(8) = mesh.node_ptr(idx(type,nx,i+1,j+1));
757 
758 
759  if (j == 0)
760  boundary_info.add_side(elem, 0, 0);
761 
762  if (j == 2*(ny-1))
763  boundary_info.add_side(elem, 2, 2);
764 
765  if (i == 0)
766  boundary_info.add_side(elem, 3, 3);
767 
768  if (i == 2*(nx-1))
769  boundary_info.add_side(elem, 1, 1);
770  }
771  break;
772  }
773 
774 
775  case TRI6:
776  {
777  for (unsigned int j=0; j<(2*ny); j += 2)
778  for (unsigned int i=0; i<(2*nx); i += 2)
779  {
780  // Add first Tri6
781  Elem * elem = new Tri6;
782  elem->set_id(elem_id++);
783  elem = mesh.add_elem (elem);
784 
785  elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j) );
786  elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+2,j) );
787  elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+2,j+2));
788  elem->set_node(3) = mesh.node_ptr(idx(type,nx,i+1,j) );
789  elem->set_node(4) = mesh.node_ptr(idx(type,nx,i+2,j+1));
790  elem->set_node(5) = mesh.node_ptr(idx(type,nx,i+1,j+1));
791 
792  if (j == 0)
793  boundary_info.add_side(elem, 0, 0);
794 
795  if (i == 2*(nx-1))
796  boundary_info.add_side(elem, 1, 1);
797 
798  // Add second Tri6
799  elem = new Tri6;
800  elem->set_id(elem_id++);
801  elem = mesh.add_elem (elem);
802 
803  elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j) );
804  elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+2,j+2));
805  elem->set_node(2) = mesh.node_ptr(idx(type,nx,i,j+2) );
806  elem->set_node(3) = mesh.node_ptr(idx(type,nx,i+1,j+1));
807  elem->set_node(4) = mesh.node_ptr(idx(type,nx,i+1,j+2));
808  elem->set_node(5) = mesh.node_ptr(idx(type,nx,i,j+1) );
809 
810  if (j == 2*(ny-1))
811  boundary_info.add_side(elem, 1, 2);
812 
813  if (i == 0)
814  boundary_info.add_side(elem, 2, 3);
815 
816  }
817  break;
818  };
819 
820 
821  default:
822  libmesh_error_msg("ERROR: Unrecognized 2D element type.");
823  }
824 
825 
826 
827 
828  // Scale the nodal positions
829  if (gauss_lobatto_grid)
830  {
831  GaussLobattoRedistributionFunction func(nx, xmin, xmax,
832  ny, ymin, ymax);
834  }
835  else // !gauss_lobatto_grid
836  {
837  for (Node * node : mesh.node_ptr_range())
838  {
839  (*node)(0) = ((*node)(0))*(xmax-xmin) + xmin;
840  (*node)(1) = ((*node)(1))*(ymax-ymin) + ymin;
841  }
842  }
843 
844  // Add sideset names to boundary info
845  boundary_info.sideset_name(0) = "bottom";
846  boundary_info.sideset_name(1) = "right";
847  boundary_info.sideset_name(2) = "top";
848  boundary_info.sideset_name(3) = "left";
849 
850  // Add nodeset names to boundary info
851  boundary_info.nodeset_name(0) = "bottom";
852  boundary_info.nodeset_name(1) = "right";
853  boundary_info.nodeset_name(2) = "top";
854  boundary_info.nodeset_name(3) = "left";
855 
856  break;
857  }
858 
859 
860 
861 
862 
863 
864 
865 
866 
867 
868 
869  //---------------------------------------------------------------------
870  // Build a 3D mesh using hexes, tets, prisms, or pyramids.
871  case 3:
872  {
873  libmesh_assert_not_equal_to (nx, 0);
874  libmesh_assert_not_equal_to (ny, 0);
875  libmesh_assert_not_equal_to (nz, 0);
876  libmesh_assert_less (xmin, xmax);
877  libmesh_assert_less (ymin, ymax);
878  libmesh_assert_less (zmin, zmax);
879 
880 
881  // Reserve elements. Meshes with prismatic elements require
882  // twice as many elements.
883  switch (type)
884  {
885  case INVALID_ELEM:
886  case HEX8:
887  case HEX20:
888  case HEX27:
889  case TET4: // TET4's are created from an initial HEX27 discretization
890  case TET10: // TET10's are created from an initial HEX27 discretization
891  case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
892  case PYRAMID13:
893  case PYRAMID14:
894  {
895  mesh.reserve_elem(nx*ny*nz);
896  break;
897  }
898 
899  case PRISM6:
900  case PRISM15:
901  case PRISM18:
902  {
903  mesh.reserve_elem(2*nx*ny*nz);
904  break;
905  }
906 
907  default:
908  libmesh_error_msg("ERROR: Unrecognized 3D element type.");
909  }
910 
911 
912 
913 
914 
915  // Reserve nodes. Quadratic elements need twice as many nodes as linear elements.
916  switch (type)
917  {
918  case INVALID_ELEM:
919  case HEX8:
920  case PRISM6:
921  {
922  mesh.reserve_nodes( (nx+1)*(ny+1)*(nz+1) );
923  break;
924  }
925 
926  case HEX20:
927  case HEX27:
928  case TET4: // TET4's are created from an initial HEX27 discretization
929  case TET10: // TET10's are created from an initial HEX27 discretization
930  case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
931  case PYRAMID13:
932  case PYRAMID14:
933  case PRISM15:
934  case PRISM18:
935  {
936  // FYI: The resulting TET4 mesh will have exactly
937  // 5*(nx*ny*nz) + 2*(nx*ny + nx*nz + ny*nz) + (nx+ny+nz) + 1
938  // nodes once the additional mid-edge nodes for the HEX27 discretization
939  // have been deleted.
940  mesh.reserve_nodes( (2*nx+1)*(2*ny+1)*(2*nz+1) );
941  break;
942  }
943 
944  default:
945  libmesh_error_msg("ERROR: Unrecognized 3D element type.");
946  }
947 
948 
949 
950 
951  // Build the nodes.
952  unsigned int node_id = 0;
953  switch (type)
954  {
955  case INVALID_ELEM:
956  case HEX8:
957  case PRISM6:
958  {
959  for (unsigned int k=0; k<=nz; k++)
960  for (unsigned int j=0; j<=ny; j++)
961  for (unsigned int i=0; i<=nx; i++)
962  mesh.add_point(Point(static_cast<Real>(i)/static_cast<Real>(nx),
963  static_cast<Real>(j)/static_cast<Real>(ny),
964  static_cast<Real>(k)/static_cast<Real>(nz)), node_id++);
965 
966  break;
967  }
968 
969  case HEX20:
970  case HEX27:
971  case TET4: // TET4's are created from an initial HEX27 discretization
972  case TET10: // TET10's are created from an initial HEX27 discretization
973  case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
974  case PYRAMID13:
975  case PYRAMID14:
976  case PRISM15:
977  case PRISM18:
978  {
979  for (unsigned int k=0; k<=(2*nz); k++)
980  for (unsigned int j=0; j<=(2*ny); j++)
981  for (unsigned int i=0; i<=(2*nx); i++)
982  mesh.add_point(Point(static_cast<Real>(i)/static_cast<Real>(2*nx),
983  static_cast<Real>(j)/static_cast<Real>(2*ny),
984  static_cast<Real>(k)/static_cast<Real>(2*nz)), node_id++);
985 
986  break;
987  }
988 
989 
990  default:
991  libmesh_error_msg("ERROR: Unrecognized 3D element type.");
992  }
993 
994 
995 
996 
997  // Build the elements.
998  unsigned int elem_id = 0;
999  switch (type)
1000  {
1001  case INVALID_ELEM:
1002  case HEX8:
1003  {
1004  for (unsigned int k=0; k<nz; k++)
1005  for (unsigned int j=0; j<ny; j++)
1006  for (unsigned int i=0; i<nx; i++)
1007  {
1008  Elem * elem = new Hex8;
1009  elem->set_id(elem_id++);
1010  elem = mesh.add_elem (elem);
1011 
1012  elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i,j,k) );
1013  elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k) );
1014  elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k) );
1015  elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k) );
1016  elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i,j,k+1) );
1017  elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1) );
1018  elem->set_node(6) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
1019  elem->set_node(7) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1) );
1020 
1021  if (k == 0)
1022  boundary_info.add_side(elem, 0, 0);
1023 
1024  if (k == (nz-1))
1025  boundary_info.add_side(elem, 5, 5);
1026 
1027  if (j == 0)
1028  boundary_info.add_side(elem, 1, 1);
1029 
1030  if (j == (ny-1))
1031  boundary_info.add_side(elem, 3, 3);
1032 
1033  if (i == 0)
1034  boundary_info.add_side(elem, 4, 4);
1035 
1036  if (i == (nx-1))
1037  boundary_info.add_side(elem, 2, 2);
1038  }
1039  break;
1040  }
1041 
1042 
1043 
1044 
1045  case PRISM6:
1046  {
1047  for (unsigned int k=0; k<nz; k++)
1048  for (unsigned int j=0; j<ny; j++)
1049  for (unsigned int i=0; i<nx; i++)
1050  {
1051  // First Prism
1052  Elem * elem = new Prism6;
1053  elem->set_id(elem_id++);
1054  elem = mesh.add_elem (elem);
1055 
1056  elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i,j,k) );
1057  elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k) );
1058  elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k) );
1059  elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i,j,k+1) );
1060  elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1) );
1061  elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1) );
1062 
1063  // Add sides for first prism to boundary info object
1064  if (i==0)
1065  boundary_info.add_side(elem, 3, 4);
1066 
1067  if (j==0)
1068  boundary_info.add_side(elem, 1, 1);
1069 
1070  if (k==0)
1071  boundary_info.add_side(elem, 0, 0);
1072 
1073  if (k == (nz-1))
1074  boundary_info.add_side(elem, 4, 5);
1075 
1076  // Second Prism
1077  elem = new Prism6;
1078  elem->set_id(elem_id++);
1079  elem = mesh.add_elem (elem);
1080 
1081  elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k) );
1082  elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k) );
1083  elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k) );
1084  elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1) );
1085  elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
1086  elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1) );
1087 
1088  // Add sides for second prism to boundary info object
1089  if (i == (nx-1))
1090  boundary_info.add_side(elem, 1, 2);
1091 
1092  if (j == (ny-1))
1093  boundary_info.add_side(elem, 2, 3);
1094 
1095  if (k==0)
1096  boundary_info.add_side(elem, 0, 0);
1097 
1098  if (k == (nz-1))
1099  boundary_info.add_side(elem, 4, 5);
1100  }
1101  break;
1102  }
1103 
1104 
1105 
1106 
1107 
1108 
1109  case HEX20:
1110  case HEX27:
1111  case TET4: // TET4's are created from an initial HEX27 discretization
1112  case TET10: // TET10's are created from an initial HEX27 discretization
1113  case PYRAMID5: // PYRAMIDs are created from an initial HEX27 discretization
1114  case PYRAMID13:
1115  case PYRAMID14:
1116  {
1117  for (unsigned int k=0; k<(2*nz); k += 2)
1118  for (unsigned int j=0; j<(2*ny); j += 2)
1119  for (unsigned int i=0; i<(2*nx); i += 2)
1120  {
1121  Elem * elem = (type == HEX20) ?
1122  static_cast<Elem *>(new Hex20) :
1123  static_cast<Elem *>(new Hex27);
1124  elem->set_id(elem_id++);
1125  elem = mesh.add_elem (elem);
1126 
1127  elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i, j, k) );
1128  elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+2,j, k) );
1129  elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k) );
1130  elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i, j+2,k) );
1131  elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i, j, k+2));
1132  elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i+2,j, k+2));
1133  elem->set_node(6) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+2));
1134  elem->set_node(7) = mesh.node_ptr(idx(type,nx,ny,i, j+2,k+2));
1135  elem->set_node(8) = mesh.node_ptr(idx(type,nx,ny,i+1,j, k) );
1136  elem->set_node(9) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k) );
1137  elem->set_node(10) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k) );
1138  elem->set_node(11) = mesh.node_ptr(idx(type,nx,ny,i, j+1,k) );
1139  elem->set_node(12) = mesh.node_ptr(idx(type,nx,ny,i, j, k+1));
1140  elem->set_node(13) = mesh.node_ptr(idx(type,nx,ny,i+2,j, k+1));
1141  elem->set_node(14) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+1));
1142  elem->set_node(15) = mesh.node_ptr(idx(type,nx,ny,i, j+2,k+1));
1143  elem->set_node(16) = mesh.node_ptr(idx(type,nx,ny,i+1,j, k+2));
1144  elem->set_node(17) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+2));
1145  elem->set_node(18) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+2));
1146  elem->set_node(19) = mesh.node_ptr(idx(type,nx,ny,i, j+1,k+2));
1147  if ((type == HEX27) || (type == TET4) || (type == TET10) ||
1148  (type == PYRAMID5) || (type == PYRAMID13) || (type == PYRAMID14))
1149  {
1150  elem->set_node(20) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k) );
1151  elem->set_node(21) = mesh.node_ptr(idx(type,nx,ny,i+1,j, k+1));
1152  elem->set_node(22) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+1));
1153  elem->set_node(23) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+1));
1154  elem->set_node(24) = mesh.node_ptr(idx(type,nx,ny,i, j+1,k+1));
1155  elem->set_node(25) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2));
1156  elem->set_node(26) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
1157  }
1158 
1159 
1160  if (k == 0)
1161  boundary_info.add_side(elem, 0, 0);
1162 
1163  if (k == 2*(nz-1))
1164  boundary_info.add_side(elem, 5, 5);
1165 
1166  if (j == 0)
1167  boundary_info.add_side(elem, 1, 1);
1168 
1169  if (j == 2*(ny-1))
1170  boundary_info.add_side(elem, 3, 3);
1171 
1172  if (i == 0)
1173  boundary_info.add_side(elem, 4, 4);
1174 
1175  if (i == 2*(nx-1))
1176  boundary_info.add_side(elem, 2, 2);
1177  }
1178  break;
1179  }
1180 
1181 
1182 
1183 
1184  case PRISM15:
1185  case PRISM18:
1186  {
1187  for (unsigned int k=0; k<(2*nz); k += 2)
1188  for (unsigned int j=0; j<(2*ny); j += 2)
1189  for (unsigned int i=0; i<(2*nx); i += 2)
1190  {
1191  // First Prism
1192  Elem * elem = (type == PRISM15) ?
1193  static_cast<Elem *>(new Prism15) :
1194  static_cast<Elem *>(new Prism18);
1195  elem->set_id(elem_id++);
1196  elem = mesh.add_elem (elem);
1197 
1198  elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i, j, k) );
1199  elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+2,j, k) );
1200  elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i, j+2,k) );
1201  elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i, j, k+2));
1202  elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i+2,j, k+2));
1203  elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i, j+2,k+2));
1204  elem->set_node(6) = mesh.node_ptr(idx(type,nx,ny,i+1,j, k) );
1205  elem->set_node(7) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k) );
1206  elem->set_node(8) = mesh.node_ptr(idx(type,nx,ny,i, j+1,k) );
1207  elem->set_node(9) = mesh.node_ptr(idx(type,nx,ny,i, j, k+1));
1208  elem->set_node(10) = mesh.node_ptr(idx(type,nx,ny,i+2,j, k+1));
1209  elem->set_node(11) = mesh.node_ptr(idx(type,nx,ny,i, j+2,k+1));
1210  elem->set_node(12) = mesh.node_ptr(idx(type,nx,ny,i+1,j, k+2));
1211  elem->set_node(13) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2));
1212  elem->set_node(14) = mesh.node_ptr(idx(type,nx,ny,i, j+1,k+2));
1213  if (type == PRISM18)
1214  {
1215  elem->set_node(15) = mesh.node_ptr(idx(type,nx,ny,i+1,j, k+1));
1216  elem->set_node(16) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
1217  elem->set_node(17) = mesh.node_ptr(idx(type,nx,ny,i, j+1,k+1));
1218  }
1219 
1220  // Add sides for first prism to boundary info object
1221  if (i==0)
1222  boundary_info.add_side(elem, 3, 4);
1223 
1224  if (j==0)
1225  boundary_info.add_side(elem, 1, 1);
1226 
1227  if (k==0)
1228  boundary_info.add_side(elem, 0, 0);
1229 
1230  if (k == 2*(nz-1))
1231  boundary_info.add_side(elem, 4, 5);
1232 
1233 
1234  // Second Prism
1235  elem = (type == PRISM15) ?
1236  static_cast<Elem *>(new Prism15) :
1237  static_cast<Elem *>(new Prism18);
1238  elem->set_id(elem_id++);
1239  elem = mesh.add_elem (elem);
1240 
1241  elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i+2,j,k) );
1242  elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k) );
1243  elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i,j+2,k) );
1244  elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i+2,j,k+2) );
1245  elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+2) );
1246  elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i,j+2,k+2) );
1247  elem->set_node(6) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k) );
1248  elem->set_node(7) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k) );
1249  elem->set_node(8) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k) );
1250  elem->set_node(9) = mesh.node_ptr(idx(type,nx,ny,i+2,j,k+1) );
1251  elem->set_node(10) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+1));
1252  elem->set_node(11) = mesh.node_ptr(idx(type,nx,ny,i,j+2,k+1) );
1253  elem->set_node(12) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+2));
1254  elem->set_node(13) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+2));
1255  elem->set_node(14) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2));
1256  if (type == PRISM18)
1257  {
1258  elem->set_node(15) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+1));
1259  elem->set_node(16) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+1));
1260  elem->set_node(17) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
1261  }
1262 
1263  // Add sides for second prism to boundary info object
1264  if (i == 2*(nx-1))
1265  boundary_info.add_side(elem, 1, 2);
1266 
1267  if (j == 2*(ny-1))
1268  boundary_info.add_side(elem, 2, 3);
1269 
1270  if (k==0)
1271  boundary_info.add_side(elem, 0, 0);
1272 
1273  if (k == 2*(nz-1))
1274  boundary_info.add_side(elem, 4, 5);
1275 
1276  }
1277  break;
1278  }
1279 
1280 
1281 
1282 
1283 
1284  default:
1285  libmesh_error_msg("ERROR: Unrecognized 3D element type.");
1286  }
1287 
1288 
1289 
1290 
1291  //.......................................
1292  // Scale the nodal positions
1293  if (gauss_lobatto_grid)
1294  {
1295  GaussLobattoRedistributionFunction func(nx, xmin, xmax,
1296  ny, ymin, ymax,
1297  nz, zmin, zmax);
1299  }
1300  else // !gauss_lobatto_grid
1301  {
1302  for (unsigned int p=0; p<mesh.n_nodes(); p++)
1303  {
1304  mesh.node_ref(p)(0) = (mesh.node_ref(p)(0))*(xmax-xmin) + xmin;
1305  mesh.node_ref(p)(1) = (mesh.node_ref(p)(1))*(ymax-ymin) + ymin;
1306  mesh.node_ref(p)(2) = (mesh.node_ref(p)(2))*(zmax-zmin) + zmin;
1307  }
1308  }
1309 
1310 
1311 
1312  // Additional work for tets and pyramids: we take the existing
1313  // HEX27 discretization and split each element into 24
1314  // sub-tets or 6 sub-pyramids.
1315  //
1316  // 24 isn't the minimum-possible number of tets, but it
1317  // obviates any concerns about the edge orientations between
1318  // the various elements.
1319  if ((type == TET4) ||
1320  (type == TET10) ||
1321  (type == PYRAMID5) ||
1322  (type == PYRAMID13) ||
1323  (type == PYRAMID14))
1324  {
1325  // Temporary storage for new elements. (24 tets per hex, 6 pyramids)
1326  std::vector<Elem *> new_elements;
1327 
1328  if ((type == TET4) || (type == TET10))
1329  new_elements.reserve(24*mesh.n_elem());
1330  else
1331  new_elements.reserve(6*mesh.n_elem());
1332 
1333  // Create tetrahedra or pyramids
1334  for (auto & base_hex : mesh.element_ptr_range())
1335  {
1336  // Get a pointer to the node located at the HEX27 centroid
1337  Node * apex_node = base_hex->node_ptr(26);
1338 
1339  // Container to catch ids handed back from BoundaryInfo
1340  std::vector<boundary_id_type> ids;
1341 
1342  for (auto s : base_hex->side_index_range())
1343  {
1344  // Get the boundary ID(s) for this side
1345  boundary_info.boundary_ids(base_hex, s, ids);
1346 
1347  // We're creating this Mesh, so there should be 0 or 1 boundary IDs.
1348  libmesh_assert(ids.size() <= 1);
1349 
1350  // A convenient name for the side's ID.
1351  boundary_id_type b_id = ids.empty() ? BoundaryInfo::invalid_id : ids[0];
1352 
1353  // Need to build the full-ordered side!
1354  std::unique_ptr<Elem> side = base_hex->build_side_ptr(s);
1355 
1356  if ((type == TET4) || (type == TET10))
1357  {
1358  // Build 4 sub-tets per side
1359  for (unsigned int sub_tet=0; sub_tet<4; ++sub_tet)
1360  {
1361  new_elements.push_back( new Tet4 );
1362  Elem * sub_elem = new_elements.back();
1363  sub_elem->set_node(0) = side->node_ptr(sub_tet);
1364  sub_elem->set_node(1) = side->node_ptr(8); // centroid of the face
1365  sub_elem->set_node(2) = side->node_ptr(sub_tet==3 ? 0 : sub_tet+1 ); // wrap-around
1366  sub_elem->set_node(3) = apex_node; // apex node always used!
1367 
1368  // If the original hex was a boundary hex, add the new sub_tet's side
1369  // 0 with the same b_id. Note: the tets are all aligned so that their
1370  // side 0 is on the boundary.
1371  if (b_id != BoundaryInfo::invalid_id)
1372  boundary_info.add_side(sub_elem, 0, b_id);
1373  }
1374  } // end if ((type == TET4) || (type == TET10))
1375 
1376  else // type==PYRAMID5 || type==PYRAMID13 || type==PYRAMID14
1377  {
1378  // Build 1 sub-pyramid per side.
1379  new_elements.push_back(new Pyramid5);
1380  Elem * sub_elem = new_elements.back();
1381 
1382  // Set the base. Note that since the apex is *inside* the base_hex,
1383  // and the pyramid uses a counter-clockwise base numbering, we need to
1384  // reverse the [1] and [3] node indices.
1385  sub_elem->set_node(0) = side->node_ptr(0);
1386  sub_elem->set_node(1) = side->node_ptr(3);
1387  sub_elem->set_node(2) = side->node_ptr(2);
1388  sub_elem->set_node(3) = side->node_ptr(1);
1389 
1390  // Set the apex
1391  sub_elem->set_node(4) = apex_node;
1392 
1393  // If the original hex was a boundary hex, add the new sub_pyr's side
1394  // 4 (the square base) with the same b_id.
1395  if (b_id != BoundaryInfo::invalid_id)
1396  boundary_info.add_side(sub_elem, 4, b_id);
1397  } // end else type==PYRAMID5 || type==PYRAMID13 || type==PYRAMID14
1398  }
1399  }
1400 
1401 
1402  // Delete the original HEX27 elements from the mesh, and the boundary info structure.
1403  for (auto & elem : mesh.element_ptr_range())
1404  {
1405  boundary_info.remove(elem); // Safe even if elem has no boundary info.
1406  mesh.delete_elem(elem);
1407  }
1408 
1409  // Add the new elements
1410  for (dof_id_type i=0,
1411  n_new = cast_int<dof_id_type>(new_elements.size());
1412  i != n_new; ++i)
1413  {
1414  new_elements[i]->set_id(i);
1415  mesh.add_elem(new_elements[i]);
1416  }
1417 
1418  } // end if (type == TET4,TET10,PYRAMID5,PYRAMID13,PYRAMID14
1419 
1420 
1421  // Use all_second_order to convert the TET4's to TET10's or PYRAMID5's to PYRAMID14's
1422  if ((type == TET10) || (type == PYRAMID14))
1423  mesh.all_second_order();
1424 
1425  else if (type == PYRAMID13)
1426  mesh.all_second_order(/*full_ordered=*/false);
1427 
1428 
1429  // Add sideset names to boundary info (Z axis out of the screen)
1430  boundary_info.sideset_name(0) = "back";
1431  boundary_info.sideset_name(1) = "bottom";
1432  boundary_info.sideset_name(2) = "right";
1433  boundary_info.sideset_name(3) = "top";
1434  boundary_info.sideset_name(4) = "left";
1435  boundary_info.sideset_name(5) = "front";
1436 
1437  // Add nodeset names to boundary info
1438  boundary_info.nodeset_name(0) = "back";
1439  boundary_info.nodeset_name(1) = "bottom";
1440  boundary_info.nodeset_name(2) = "right";
1441  boundary_info.nodeset_name(3) = "top";
1442  boundary_info.nodeset_name(4) = "left";
1443  boundary_info.nodeset_name(5) = "front";
1444 
1445  break;
1446  } // end case dim==3
1447 
1448  default:
1449  libmesh_error_msg("Unknown dimension " << mesh.mesh_dimension());
1450  }
1451 
1452  STOP_LOG("build_cube()", "MeshTools::Generation");
1453 
1454 
1455 
1456  // Done building the mesh. Now prepare it for use.
1457  mesh.prepare_for_use (/*skip_renumber =*/ false);
1458 }

References libMesh::BoundaryInfo::add_side(), libMesh::BoundaryInfo::boundary_ids(), libMesh::EDGE2, libMesh::EDGE3, libMesh::EDGE4, libMesh::HEX20, libMesh::HEX27, libMesh::HEX8, libMesh::MeshTools::Generation::Private::idx(), libMesh::INVALID_ELEM, libMesh::BoundaryInfo::invalid_id, libMesh::libmesh_assert(), mesh, libMesh::NODEELEM, libMesh::BoundaryInfo::nodeset_name(), libMesh::PRISM15, libMesh::PRISM18, libMesh::PRISM6, libMesh::PYRAMID13, libMesh::PYRAMID14, libMesh::PYRAMID5, libMesh::QUAD4, libMesh::QUAD8, libMesh::QUAD9, libMesh::MeshTools::Modification::redistribute(), libMesh::BoundaryInfo::remove(), libMesh::DofObject::set_id(), libMesh::Elem::set_node(), libMesh::BoundaryInfo::sideset_name(), libMesh::TET10, libMesh::TET4, libMesh::TRI3, and libMesh::TRI6.

Referenced by add_cube_convex_hull_to_mesh(), Biharmonic::Biharmonic(), build_line(), ExtraIntegersTest::build_mesh(), build_point(), build_square(), main(), ElemTest< elem_type >::setUp(), ParsedFEMFunctionTest::setUp(), RationalMapTest< elem_type >::setUp(), setup(), FETest< order, family, elem_type >::setUp(), DistortTest::test_helper_3D(), AllTriTest::test_helper_3D(), MeshFunctionTest::test_p_level(), SystemsTest::testAssemblyWithDgFemContext(), SystemsTest::testBlockRestrictedVarNDofs(), SystemsTest::testBoundaryProjectCube(), DefaultCouplingTest::testCoupling(), PointNeighborCouplingTest::testCoupling(), SystemsTest::testDofCouplingWithVarGroups(), DofMapTest::testDofOwner(), BoundaryInfoTest::testEdgeBoundaryConditions(), MeshInputTest::testExodusWriteElementDataFromDiscontinuousNodalData(), PointLocatorTest::testLocator(), MeshStitchTest::testMeshStitch(), PartitionerTest< PartitionerSubclass, MeshClass >::testPartition(), SystemsTest::testProjectCube(), SystemsTest::testProjectCubeWithMeshFunction(), SystemsTest::testProjectMatrix3D(), InfFERadialTest::testSingleOrder(), and WriteEdgesetData::testWrite().

◆ build_delaunay_square()

void libMesh::MeshTools::Generation::build_delaunay_square ( UnstructuredMesh mesh,
const unsigned int  nx,
const unsigned int  ny,
const Real  xmin,
const Real  xmax,
const Real  ymin,
const Real  ymax,
const ElemType  type,
const std::vector< TriangleInterface::Hole * > *  holes = nullptr 
)

Meshes a rectangular (2D) region (with or without holes) with a Delaunay triangulation.

This function internally calls the triangle library written by J.R. Shewchuk.

Definition at line 2321 of file mesh_generation.C.

2328 {
2329  // Check for reasonable size
2330  libmesh_assert_greater_equal (nx, 1); // need at least 1 element in x-direction
2331  libmesh_assert_greater_equal (ny, 1); // need at least 1 element in y-direction
2332  libmesh_assert_less (xmin, xmax);
2333  libmesh_assert_less (ymin, ymax);
2334 
2335  // Clear out any data which may have been in the Mesh
2336  mesh.clear();
2337 
2338  BoundaryInfo & boundary_info = mesh.get_boundary_info();
2339 
2340  // Make sure the new Mesh will be 2D
2341  mesh.set_mesh_dimension(2);
2342 
2343  // The x and y spacing between boundary points
2344  const Real delta_x = (xmax-xmin) / static_cast<Real>(nx);
2345  const Real delta_y = (ymax-ymin) / static_cast<Real>(ny);
2346 
2347  // Bottom
2348  for (unsigned int p=0; p<=nx; ++p)
2349  mesh.add_point(Point(xmin + p*delta_x, ymin));
2350 
2351  // Right side
2352  for (unsigned int p=1; p<ny; ++p)
2353  mesh.add_point(Point(xmax, ymin + p*delta_y));
2354 
2355  // Top
2356  for (unsigned int p=0; p<=nx; ++p)
2357  mesh.add_point(Point(xmax - p*delta_x, ymax));
2358 
2359  // Left side
2360  for (unsigned int p=1; p<ny; ++p)
2361  mesh.add_point(Point(xmin, ymax - p*delta_y));
2362 
2363  // Be sure we added as many points as we thought we did
2364  libmesh_assert_equal_to (mesh.n_nodes(), 2*(nx+ny));
2365 
2366  // Construct the Triangle Interface object
2367  TriangleInterface t(mesh);
2368 
2369  // Set custom variables for the triangulation
2370  t.desired_area() = 0.5 * (xmax-xmin)*(ymax-ymin) / static_cast<Real>(nx*ny);
2371  t.triangulation_type() = TriangleInterface::PSLG;
2372  t.elem_type() = type;
2373 
2374  if (holes != nullptr)
2375  t.attach_hole_list(holes);
2376 
2377  // Triangulate!
2378  t.triangulate();
2379 
2380  // The mesh is now generated, but we still need to mark the boundaries
2381  // to be consistent with the other build_square routines. Note that all
2382  // hole boundary elements get the same ID, 4.
2383  for (auto & elem : mesh.element_ptr_range())
2384  for (auto s : elem->side_index_range())
2385  if (elem->neighbor_ptr(s) == nullptr)
2386  {
2387  std::unique_ptr<const Elem> side (elem->build_side_ptr(s));
2388 
2389  // Check the location of the side's midpoint. Since
2390  // the square has straight sides, the midpoint is not
2391  // on the corner and thus it is uniquely on one of the
2392  // sides.
2393  Point side_midpoint= 0.5f*( side->point(0) + side->point(1) );
2394 
2395  // The boundary ids are set following the same convention as Quad4 sides
2396  // bottom = 0
2397  // right = 1
2398  // top = 2
2399  // left = 3
2400  // hole = 4
2401  boundary_id_type bc_id=4;
2402 
2403  // bottom
2404  if (std::fabs(side_midpoint(1) - ymin) < TOLERANCE)
2405  bc_id=0;
2406 
2407  // right
2408  else if (std::fabs(side_midpoint(0) - xmax) < TOLERANCE)
2409  bc_id=1;
2410 
2411  // top
2412  else if (std::fabs(side_midpoint(1) - ymax) < TOLERANCE)
2413  bc_id=2;
2414 
2415  // left
2416  else if (std::fabs(side_midpoint(0) - xmin) < TOLERANCE)
2417  bc_id=3;
2418 
2419  // If the point is not on any of the external boundaries, it
2420  // is on one of the holes....
2421 
2422  // Finally, add this element's information to the boundary info object.
2423  boundary_info.add_side(elem->id(), s, bc_id);
2424  }
2425 
2426 } // end build_delaunay_square

References libMesh::MeshBase::add_point(), libMesh::BoundaryInfo::add_side(), libMesh::TriangleInterface::attach_hole_list(), libMesh::MeshBase::clear(), libMesh::TriangleInterface::desired_area(), libMesh::TriangleInterface::elem_type(), libMesh::MeshBase::element_ptr_range(), libMesh::MeshBase::get_boundary_info(), mesh, libMesh::MeshBase::n_nodes(), libMesh::TriangleInterface::PSLG, libMesh::Real, libMesh::MeshBase::set_mesh_dimension(), libMesh::TOLERANCE, libMesh::TriangleInterface::triangulate(), and libMesh::TriangleInterface::triangulation_type().

◆ build_extrusion()

void libMesh::MeshTools::Generation::build_extrusion ( UnstructuredMesh mesh,
const MeshBase cross_section,
const unsigned int  nz,
RealVectorValue  extrusion_vector,
QueryElemSubdomainIDBase elem_subdomain = nullptr 
)

Meshes the tensor product of a 1D and a 1D-or-2D domain.

Definition at line 1994 of file mesh_generation.C.

1999 {
2000  if (!cross_section.n_elem())
2001  return;
2002 
2003  START_LOG("build_extrusion()", "MeshTools::Generation");
2004 
2005  dof_id_type orig_elem = cross_section.n_elem();
2006  dof_id_type orig_nodes = cross_section.n_nodes();
2007 
2008 #ifdef LIBMESH_ENABLE_UNIQUE_ID
2009  unique_id_type orig_unique_ids = cross_section.parallel_max_unique_id();
2010 #endif
2011 
2012  unsigned int order = 1;
2013 
2014  BoundaryInfo & boundary_info = mesh.get_boundary_info();
2015  const BoundaryInfo & cross_section_boundary_info = cross_section.get_boundary_info();
2016 
2017  // If cross_section is distributed, so is its extrusion
2018  if (!cross_section.is_serial())
2019  mesh.delete_remote_elements();
2020 
2021  // We know a priori how many elements we'll need
2022  mesh.reserve_elem(nz*orig_elem);
2023 
2024  // For straightforward meshes we need one or two additional layers per
2025  // element.
2026  if (cross_section.elements_begin() != cross_section.elements_end() &&
2027  (*cross_section.elements_begin())->default_order() == SECOND)
2028  order = 2;
2029  mesh.comm().max(order);
2030 
2031  mesh.reserve_nodes((order*nz+1)*orig_nodes);
2032 
2033  // Container to catch the boundary IDs handed back by the BoundaryInfo object
2034  std::vector<boundary_id_type> ids_to_copy;
2035 
2036  for (const auto & node : cross_section.node_ptr_range())
2037  {
2038  for (unsigned int k=0; k != order*nz+1; ++k)
2039  {
2040  Node * new_node =
2041  mesh.add_point(*node +
2042  (extrusion_vector * k / nz / order),
2043  node->id() + (k * orig_nodes),
2044  node->processor_id());
2045 
2046 #ifdef LIBMESH_ENABLE_UNIQUE_ID
2047  // Let's give the base of the extruded mesh the same
2048  // unique_ids as the source mesh, in case anyone finds that
2049  // a useful map to preserve.
2050  const unique_id_type uid = (k == 0) ?
2051  node->unique_id() :
2052  orig_unique_ids + (k-1)*(orig_nodes + orig_elem) + node->id();
2053 
2054  new_node->set_unique_id() = uid;
2055 #endif
2056 
2057  cross_section_boundary_info.boundary_ids(node, ids_to_copy);
2058  boundary_info.add_node(new_node, ids_to_copy);
2059  }
2060  }
2061 
2062  const std::set<boundary_id_type> & side_ids =
2063  cross_section_boundary_info.get_side_boundary_ids();
2064 
2065  boundary_id_type next_side_id = side_ids.empty() ?
2066  0 : cast_int<boundary_id_type>(*side_ids.rbegin() + 1);
2067 
2068  // side_ids may not include ids from remote elements, in which case
2069  // some processors may have underestimated the next_side_id; let's
2070  // fix that.
2071  cross_section.comm().max(next_side_id);
2072 
2073  for (const auto & elem : cross_section.element_ptr_range())
2074  {
2075  const ElemType etype = elem->type();
2076 
2077  // build_extrusion currently only works on coarse meshes
2078  libmesh_assert (!elem->parent());
2079 
2080  for (unsigned int k=0; k != nz; ++k)
2081  {
2082  Elem * new_elem;
2083  switch (etype)
2084  {
2085  case EDGE2:
2086  {
2087  new_elem = new Quad4;
2088  new_elem->set_node(0) = mesh.node_ptr(elem->node_ptr(0)->id() + (k * orig_nodes));
2089  new_elem->set_node(1) = mesh.node_ptr(elem->node_ptr(1)->id() + (k * orig_nodes));
2090  new_elem->set_node(2) = mesh.node_ptr(elem->node_ptr(1)->id() + ((k+1) * orig_nodes));
2091  new_elem->set_node(3) = mesh.node_ptr(elem->node_ptr(0)->id() + ((k+1) * orig_nodes));
2092 
2093  if (elem->neighbor_ptr(0) == remote_elem)
2094  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
2095  if (elem->neighbor_ptr(1) == remote_elem)
2096  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
2097 
2098  break;
2099  }
2100  case EDGE3:
2101  {
2102  new_elem = new Quad9;
2103  new_elem->set_node(0) = mesh.node_ptr(elem->node_ptr(0)->id() + (2*k * orig_nodes));
2104  new_elem->set_node(1) = mesh.node_ptr(elem->node_ptr(1)->id() + (2*k * orig_nodes));
2105  new_elem->set_node(2) = mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+2) * orig_nodes));
2106  new_elem->set_node(3) = mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+2) * orig_nodes));
2107  new_elem->set_node(4) = mesh.node_ptr(elem->node_ptr(2)->id() + (2*k * orig_nodes));
2108  new_elem->set_node(5) = mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+1) * orig_nodes));
2109  new_elem->set_node(6) = mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+2) * orig_nodes));
2110  new_elem->set_node(7) = mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+1) * orig_nodes));
2111  new_elem->set_node(8) = mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+1) * orig_nodes));
2112 
2113  if (elem->neighbor_ptr(0) == remote_elem)
2114  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
2115  if (elem->neighbor_ptr(1) == remote_elem)
2116  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
2117 
2118  break;
2119  }
2120  case TRI3:
2121  {
2122  new_elem = new Prism6;
2123  new_elem->set_node(0) = mesh.node_ptr(elem->node_ptr(0)->id() + (k * orig_nodes));
2124  new_elem->set_node(1) = mesh.node_ptr(elem->node_ptr(1)->id() + (k * orig_nodes));
2125  new_elem->set_node(2) = mesh.node_ptr(elem->node_ptr(2)->id() + (k * orig_nodes));
2126  new_elem->set_node(3) = mesh.node_ptr(elem->node_ptr(0)->id() + ((k+1) * orig_nodes));
2127  new_elem->set_node(4) = mesh.node_ptr(elem->node_ptr(1)->id() + ((k+1) * orig_nodes));
2128  new_elem->set_node(5) = mesh.node_ptr(elem->node_ptr(2)->id() + ((k+1) * orig_nodes));
2129 
2130  if (elem->neighbor_ptr(0) == remote_elem)
2131  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
2132  if (elem->neighbor_ptr(1) == remote_elem)
2133  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
2134  if (elem->neighbor_ptr(2) == remote_elem)
2135  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
2136 
2137  break;
2138  }
2139  case TRI6:
2140  {
2141  new_elem = new Prism18;
2142  new_elem->set_node(0) = mesh.node_ptr(elem->node_ptr(0)->id() + (2*k * orig_nodes));
2143  new_elem->set_node(1) = mesh.node_ptr(elem->node_ptr(1)->id() + (2*k * orig_nodes));
2144  new_elem->set_node(2) = mesh.node_ptr(elem->node_ptr(2)->id() + (2*k * orig_nodes));
2145  new_elem->set_node(3) = mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+2) * orig_nodes));
2146  new_elem->set_node(4) = mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+2) * orig_nodes));
2147  new_elem->set_node(5) = mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+2) * orig_nodes));
2148  new_elem->set_node(6) = mesh.node_ptr(elem->node_ptr(3)->id() + (2*k * orig_nodes));
2149  new_elem->set_node(7) = mesh.node_ptr(elem->node_ptr(4)->id() + (2*k * orig_nodes));
2150  new_elem->set_node(8) = mesh.node_ptr(elem->node_ptr(5)->id() + (2*k * orig_nodes));
2151  new_elem->set_node(9) = mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+1) * orig_nodes));
2152  new_elem->set_node(10) = mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+1) * orig_nodes));
2153  new_elem->set_node(11) = mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+1) * orig_nodes));
2154  new_elem->set_node(12) = mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+2) * orig_nodes));
2155  new_elem->set_node(13) = mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+2) * orig_nodes));
2156  new_elem->set_node(14) = mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+2) * orig_nodes));
2157  new_elem->set_node(15) = mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+1) * orig_nodes));
2158  new_elem->set_node(16) = mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+1) * orig_nodes));
2159  new_elem->set_node(17) = mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+1) * orig_nodes));
2160 
2161  if (elem->neighbor_ptr(0) == remote_elem)
2162  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
2163  if (elem->neighbor_ptr(1) == remote_elem)
2164  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
2165  if (elem->neighbor_ptr(2) == remote_elem)
2166  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
2167 
2168  break;
2169  }
2170  case QUAD4:
2171  {
2172  new_elem = new Hex8;
2173  new_elem->set_node(0) = mesh.node_ptr(elem->node_ptr(0)->id() + (k * orig_nodes));
2174  new_elem->set_node(1) = mesh.node_ptr(elem->node_ptr(1)->id() + (k * orig_nodes));
2175  new_elem->set_node(2) = mesh.node_ptr(elem->node_ptr(2)->id() + (k * orig_nodes));
2176  new_elem->set_node(3) = mesh.node_ptr(elem->node_ptr(3)->id() + (k * orig_nodes));
2177  new_elem->set_node(4) = mesh.node_ptr(elem->node_ptr(0)->id() + ((k+1) * orig_nodes));
2178  new_elem->set_node(5) = mesh.node_ptr(elem->node_ptr(1)->id() + ((k+1) * orig_nodes));
2179  new_elem->set_node(6) = mesh.node_ptr(elem->node_ptr(2)->id() + ((k+1) * orig_nodes));
2180  new_elem->set_node(7) = mesh.node_ptr(elem->node_ptr(3)->id() + ((k+1) * orig_nodes));
2181 
2182  if (elem->neighbor_ptr(0) == remote_elem)
2183  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
2184  if (elem->neighbor_ptr(1) == remote_elem)
2185  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
2186  if (elem->neighbor_ptr(2) == remote_elem)
2187  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
2188  if (elem->neighbor_ptr(3) == remote_elem)
2189  new_elem->set_neighbor(4, const_cast<RemoteElem *>(remote_elem));
2190 
2191  break;
2192  }
2193  case QUAD9:
2194  {
2195  new_elem = new Hex27;
2196  new_elem->set_node(0) = mesh.node_ptr(elem->node_ptr(0)->id() + (2*k * orig_nodes));
2197  new_elem->set_node(1) = mesh.node_ptr(elem->node_ptr(1)->id() + (2*k * orig_nodes));
2198  new_elem->set_node(2) = mesh.node_ptr(elem->node_ptr(2)->id() + (2*k * orig_nodes));
2199  new_elem->set_node(3) = mesh.node_ptr(elem->node_ptr(3)->id() + (2*k * orig_nodes));
2200  new_elem->set_node(4) = mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+2) * orig_nodes));
2201  new_elem->set_node(5) = mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+2) * orig_nodes));
2202  new_elem->set_node(6) = mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+2) * orig_nodes));
2203  new_elem->set_node(7) = mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+2) * orig_nodes));
2204  new_elem->set_node(8) = mesh.node_ptr(elem->node_ptr(4)->id() + (2*k * orig_nodes));
2205  new_elem->set_node(9) = mesh.node_ptr(elem->node_ptr(5)->id() + (2*k * orig_nodes));
2206  new_elem->set_node(10) = mesh.node_ptr(elem->node_ptr(6)->id() + (2*k * orig_nodes));
2207  new_elem->set_node(11) = mesh.node_ptr(elem->node_ptr(7)->id() + (2*k * orig_nodes));
2208  new_elem->set_node(12) = mesh.node_ptr(elem->node_ptr(0)->id() + ((2*k+1) * orig_nodes));
2209  new_elem->set_node(13) = mesh.node_ptr(elem->node_ptr(1)->id() + ((2*k+1) * orig_nodes));
2210  new_elem->set_node(14) = mesh.node_ptr(elem->node_ptr(2)->id() + ((2*k+1) * orig_nodes));
2211  new_elem->set_node(15) = mesh.node_ptr(elem->node_ptr(3)->id() + ((2*k+1) * orig_nodes));
2212  new_elem->set_node(16) = mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+2) * orig_nodes));
2213  new_elem->set_node(17) = mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+2) * orig_nodes));
2214  new_elem->set_node(18) = mesh.node_ptr(elem->node_ptr(6)->id() + ((2*k+2) * orig_nodes));
2215  new_elem->set_node(19) = mesh.node_ptr(elem->node_ptr(7)->id() + ((2*k+2) * orig_nodes));
2216  new_elem->set_node(20) = mesh.node_ptr(elem->node_ptr(8)->id() + (2*k * orig_nodes));
2217  new_elem->set_node(21) = mesh.node_ptr(elem->node_ptr(4)->id() + ((2*k+1) * orig_nodes));
2218  new_elem->set_node(22) = mesh.node_ptr(elem->node_ptr(5)->id() + ((2*k+1) * orig_nodes));
2219  new_elem->set_node(23) = mesh.node_ptr(elem->node_ptr(6)->id() + ((2*k+1) * orig_nodes));
2220  new_elem->set_node(24) = mesh.node_ptr(elem->node_ptr(7)->id() + ((2*k+1) * orig_nodes));
2221  new_elem->set_node(25) = mesh.node_ptr(elem->node_ptr(8)->id() + ((2*k+2) * orig_nodes));
2222  new_elem->set_node(26) = mesh.node_ptr(elem->node_ptr(8)->id() + ((2*k+1) * orig_nodes));
2223 
2224  if (elem->neighbor_ptr(0) == remote_elem)
2225  new_elem->set_neighbor(1, const_cast<RemoteElem *>(remote_elem));
2226  if (elem->neighbor_ptr(1) == remote_elem)
2227  new_elem->set_neighbor(2, const_cast<RemoteElem *>(remote_elem));
2228  if (elem->neighbor_ptr(2) == remote_elem)
2229  new_elem->set_neighbor(3, const_cast<RemoteElem *>(remote_elem));
2230  if (elem->neighbor_ptr(3) == remote_elem)
2231  new_elem->set_neighbor(4, const_cast<RemoteElem *>(remote_elem));
2232 
2233  break;
2234  }
2235  default:
2236  {
2237  libmesh_not_implemented();
2238  break;
2239  }
2240  }
2241 
2242  new_elem->set_id(elem->id() + (k * orig_elem));
2243  new_elem->processor_id() = elem->processor_id();
2244 
2245 #ifdef LIBMESH_ENABLE_UNIQUE_ID
2246  // Let's give the base of the extruded mesh the same
2247  // unique_ids as the source mesh, in case anyone finds that
2248  // a useful map to preserve.
2249  const unique_id_type uid = (k == 0) ?
2250  elem->unique_id() :
2251  orig_unique_ids + (k-1)*(orig_nodes + orig_elem) + orig_nodes + elem->id();
2252 
2253  new_elem->set_unique_id() = uid;
2254 #endif
2255 
2256  if (!elem_subdomain)
2257  // maintain the subdomain_id
2258  new_elem->subdomain_id() = elem->subdomain_id();
2259  else
2260  // Allow the user to choose new subdomain_ids
2261  new_elem->subdomain_id() = elem_subdomain->get_subdomain_for_layer(elem, k);
2262 
2263  new_elem = mesh.add_elem(new_elem);
2264 
2265  // Copy any old boundary ids on all sides
2266  for (auto s : elem->side_index_range())
2267  {
2268  cross_section_boundary_info.boundary_ids(elem, s, ids_to_copy);
2269 
2270  if (new_elem->dim() == 3)
2271  {
2272  // For 2D->3D extrusion, we give the boundary IDs
2273  // for side s on the old element to side s+1 on the
2274  // new element. This is just a happy coincidence as
2275  // far as I can tell...
2276  boundary_info.add_side(new_elem,
2277  cast_int<unsigned short>(s+1),
2278  ids_to_copy);
2279  }
2280  else
2281  {
2282  // For 1D->2D extrusion, the boundary IDs map as:
2283  // Old elem -> New elem
2284  // 0 -> 3
2285  // 1 -> 1
2286  libmesh_assert_less(s, 2);
2287  const unsigned short sidemap[2] = {3, 1};
2288  boundary_info.add_side(new_elem, sidemap[s], ids_to_copy);
2289  }
2290  }
2291 
2292  // Give new boundary ids to bottom and top
2293  if (k == 0)
2294  boundary_info.add_side(new_elem, 0, next_side_id);
2295  if (k == nz-1)
2296  {
2297  // For 2D->3D extrusion, the "top" ID is 1+the original
2298  // element's number of sides. For 1D->2D extrusion, the
2299  // "top" ID is side 2.
2300  const unsigned short top_id = new_elem->dim() == 3 ?
2301  cast_int<unsigned short>(elem->n_sides()+1) : 2;
2302  boundary_info.add_side
2303  (new_elem, top_id,
2304  cast_int<boundary_id_type>(next_side_id+1));
2305  }
2306  }
2307  }
2308 
2309  STOP_LOG("build_extrusion()", "MeshTools::Generation");
2310 
2311  // Done building the mesh. Now prepare it for use.
2312  mesh.prepare_for_use(/*skip_renumber =*/ false);
2313 }

References libMesh::MeshBase::add_elem(), libMesh::BoundaryInfo::add_node(), libMesh::MeshBase::add_point(), libMesh::BoundaryInfo::add_side(), libMesh::BoundaryInfo::boundary_ids(), libMesh::ParallelObject::comm(), libMesh::MeshBase::delete_remote_elements(), libMesh::Elem::dim(), libMesh::EDGE2, libMesh::EDGE3, libMesh::MeshBase::element_ptr_range(), libMesh::MeshBase::elements_begin(), libMesh::MeshBase::elements_end(), libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::get_side_boundary_ids(), libMesh::MeshTools::Generation::QueryElemSubdomainIDBase::get_subdomain_for_layer(), libMesh::MeshBase::is_serial(), libMesh::libmesh_assert(), mesh, libMesh::MeshBase::n_elem(), libMesh::MeshBase::n_nodes(), libMesh::MeshBase::node_ptr(), libMesh::MeshBase::node_ptr_range(), libMesh::MeshBase::parallel_max_unique_id(), libMesh::MeshBase::prepare_for_use(), libMesh::DofObject::processor_id(), libMesh::QUAD4, libMesh::QUAD9, libMesh::remote_elem, libMesh::MeshBase::reserve_elem(), libMesh::MeshBase::reserve_nodes(), libMesh::SECOND, libMesh::DofObject::set_id(), libMesh::Elem::set_neighbor(), libMesh::Elem::set_node(), libMesh::DofObject::set_unique_id(), libMesh::Elem::subdomain_id(), libMesh::TRI3, libMesh::TRI6, and libMesh::DofObject::unique_id().

Referenced by MeshExtruderTest::testExtruder().

◆ build_line()

void libMesh::MeshTools::Generation::build_line ( UnstructuredMesh mesh,
const unsigned int  nx,
const Real  xmin = 0.,
const Real  xmax = 1.,
const ElemType  type = INVALID_ELEM,
const bool  gauss_lobatto_grid = false 
)

A specialized build_cube() for 1D meshes.

Boundary ids are set to be equal to the side indexing on a master edge

Definition at line 1480 of file mesh_generation.C.

1485 {
1486  // This method only makes sense in 1D!
1487  // But we now just turn a non-1D mesh into a 1D mesh
1488  //libmesh_assert_equal_to (mesh.mesh_dimension(), 1);
1489 
1490  build_cube(mesh,
1491  nx, 0, 0,
1492  xmin, xmax,
1493  0., 0.,
1494  0., 0.,
1495  type,
1496  gauss_lobatto_grid);
1497 }

References build_cube(), and mesh.

Referenced by Biharmonic::Biharmonic(), NodalNeighborsTest::do_test(), main(), MeshSpatialDimensionTest::test1D(), EquationSystemsTest::testPostInitAddElem(), SystemsTest::testProjectLine(), SystemsTest::testProjectMatrix1D(), and EquationSystemsTest::testReinitWithNodeElem().

◆ build_point()

void libMesh::MeshTools::Generation::build_point ( UnstructuredMesh mesh,
const ElemType  type = INVALID_ELEM,
const bool  gauss_lobatto_grid = false 
)

A specialized build_cube() for 0D meshes.

The resulting mesh is a single NodeElem suitable for ODE tests

Definition at line 1462 of file mesh_generation.C.

1465 {
1466  // This method only makes sense in 0D!
1467  // But we now just turn a non-0D mesh into a 0D mesh
1468  //libmesh_assert_equal_to (mesh.mesh_dimension(), 1);
1469 
1470  build_cube(mesh,
1471  0, 0, 0,
1472  0., 0.,
1473  0., 0.,
1474  0., 0.,
1475  type,
1476  gauss_lobatto_grid);
1477 }

References build_cube(), and mesh.

Referenced by TimeSolverTestImplementation< NewmarkSolver >::run_test_with_exact_soln(), EquationSystemsTest::testInit(), EquationSystemsTest::testPostInitAddRealSystem(), and EquationSystemsTest::testPostInitAddSystem().

◆ build_sphere()

void libMesh::MeshTools::Generation::build_sphere ( UnstructuredMesh mesh,
const Real  rad = 1,
const unsigned int  nr = 2,
const ElemType  type = INVALID_ELEM,
const unsigned int  n_smooth = 2,
const bool  flat = true 
)

Meshes a spherical or mapped-spherical domain.

Definition at line 1532 of file mesh_generation.C.

1538 {
1539  libmesh_error_msg("Building a circle/sphere only works with AMR.");
1540 }

Referenced by main().

◆ build_square()

void libMesh::MeshTools::Generation::build_square ( UnstructuredMesh mesh,
const unsigned int  nx,
const unsigned int  ny,
const Real  xmin = 0.,
const Real  xmax = 1.,
const Real  ymin = 0.,
const Real  ymax = 1.,
const ElemType  type = INVALID_ELEM,
const bool  gauss_lobatto_grid = false 
)

A specialized build_cube() for 2D meshes.

Boundary ids are set to be equal to the side indexing on a master quad

Definition at line 1501 of file mesh_generation.C.

1508 {
1509  // This method only makes sense in 2D!
1510  // But we now just turn a non-2D mesh into a 2D mesh
1511  //libmesh_assert_equal_to (mesh.mesh_dimension(), 2);
1512 
1513  // Call the build_cube() member to actually do the work for us.
1514  build_cube (mesh,
1515  nx, ny, 0,
1516  xmin, xmax,
1517  ymin, ymax,
1518  0., 0.,
1519  type,
1520  gauss_lobatto_grid);
1521 }

References build_cube(), and mesh.

Referenced by AllSecondOrderTest::allSecondOrder(), Biharmonic::Biharmonic(), BoundaryMeshTest::build_mesh(), main(), MeshSpatialDimensionTest::test2D(), DistortTest::test_helper_2D(), AllTriTest::test_helper_2D(), DofMapTest::testConstraintLoopDetection(), MeshInputTest::testExodusCopyElementSolution(), MeshExtruderTest::testExtruder(), MappedSubdomainPartitionerTest::testMappedSubdomainPartitioner(), BoundaryInfoTest::testMesh(), MeshInputTest::testMeshMoveConstructor(), SystemsTest::testProjectMatrix2D(), SystemsTest::testProjectSquare(), EquationSystemsTest::testRefineThenReinitPreserveFlags(), EquationSystemsTest::testRepartitionThenReinit(), CheckpointIOTest::testSplitter(), WriteSidesetData::testWrite(), and WriteVecAndScalar::testWrite().

libMesh::HEX20
Definition: enum_elem_type.h:48
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::PRISM6
Definition: enum_elem_type.h:50
libMesh::unique_id_type
uint8_t unique_id_type
Definition: id_types.h:86
libMesh::HEX8
Definition: enum_elem_type.h:47
libMesh::EDGE4
Definition: enum_elem_type.h:37
libMesh::TET10
Definition: enum_elem_type.h:46
libMesh::MeshTools::Generation::build_cube
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
Definition: mesh_generation.C:298
libMesh::TOLERANCE
static const Real TOLERANCE
Definition: libmesh_common.h:128
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::SECOND
Definition: enum_order.h:43
libMesh::boundary_id_type
int8_t boundary_id_type
Definition: id_types.h:51
libMesh::TET4
Definition: enum_elem_type.h:45
libMesh::PRISM15
Definition: enum_elem_type.h:51
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::MeshTools::Generation::Private::idx
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int ny, const unsigned int i, const unsigned int j, const unsigned int k)
Definition: mesh_generation.C:104
libMesh::HEX27
Definition: enum_elem_type.h:49
libMesh::QUAD4
Definition: enum_elem_type.h:41
libMesh::TRI3
Definition: enum_elem_type.h:39
libMesh::MeshTools::Modification::redistribute
void redistribute(MeshBase &mesh, const FunctionBase< Real > &mapfunc)
Deterministically perturb the nodal locations.
Definition: mesh_modification.C:146
libMesh::TRI6
Definition: enum_elem_type.h:40
libMesh::INVALID_ELEM
Definition: enum_elem_type.h:75
libMesh::PYRAMID5
Definition: enum_elem_type.h:53
libMesh::EDGE3
Definition: enum_elem_type.h:36
libMesh::NODEELEM
Definition: enum_elem_type.h:66
libMesh::QUAD9
Definition: enum_elem_type.h:43
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::PRISM18
Definition: enum_elem_type.h:52
libMesh::remote_elem
const RemoteElem * remote_elem
Definition: remote_elem.C:57
libMesh::PYRAMID13
Definition: enum_elem_type.h:54
libMesh::PYRAMID14
Definition: enum_elem_type.h:55
libMesh::EDGE2
Definition: enum_elem_type.h:35
libMesh::QUAD8
Definition: enum_elem_type.h:42
libMesh::ElemType
ElemType
Defines an enum for geometric element types.
Definition: enum_elem_type.h:33