MeshTools::Generation Namespace Reference


Namespaces

namespace  Private

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)
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)
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)
void build_sphere (UnstructuredMesh &mesh, const Real rad=1, const unsigned int nr=2, const ElemType type=INVALID_ELEM)
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=NULL)

Detailed Description

Tools for Mesh generation.

Author:
Benjamin S. Kirk
Date:
2004
Version:
Revision
3391


Function Documentation

void 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.

Definition at line 55 of file mesh_generation.C.

References MeshBase::add_elem(), MeshBase::add_point(), UnstructuredMesh::all_second_order(), MeshBase::boundary_info, Elem::build_side(), MeshBase::clear(), MeshBase::delete_elem(), libMeshEnums::EDGE2, libMeshEnums::EDGE3, libMeshEnums::EDGE4, MeshBase::elements_begin(), MeshBase::elements_end(), Elem::get_node(), libMeshEnums::HEX20, libMeshEnums::HEX27, libMeshEnums::HEX8, MeshTools::Generation::Private::idx(), libMeshEnums::INVALID_ELEM, BoundaryInfo::invalid_id, MeshBase::mesh_dimension(), MeshBase::n_elem(), MeshBase::n_nodes(), Elem::n_sides(), MeshBase::node(), MeshBase::node_ptr(), libMesh::pi, MeshBase::prepare_for_use(), libMeshEnums::PRISM15, libMeshEnums::PRISM18, libMeshEnums::PRISM6, libMeshEnums::PYRAMID5, libMeshEnums::QUAD4, libMeshEnums::QUAD8, libMeshEnums::QUAD9, MeshBase::reserve_elem(), MeshBase::reserve_nodes(), MeshBase::set_mesh_dimension(), Elem::set_node(), side, libMeshEnums::TET10, libMeshEnums::TET4, libMeshEnums::TRI3, and libMeshEnums::TRI6.

Referenced by build_line(), and build_square().

00064 {
00065   START_LOG("build_cube()", "MeshTools::Generation");
00066 
00067   // Declare that we are using the indexing utility routine
00068   // in the "Private" part of our current namespace.  If this doesn't
00069   // work in GCC 2.95.3 we can either remove it or stop supporting
00070   // 2.95.3 altogether.
00071   // Changing this to import the whole namespace... just importing idx
00072   // causes an internal compiler error for Intel Compiler 11.0 on Linux
00073   // in debug mode.
00074   using namespace MeshTools::Generation::Private;
00075   
00076   // Clear the mesh and start from scratch
00077   mesh.clear();
00078 
00079   if (nz != 0)
00080     mesh.set_mesh_dimension(3);
00081   else if (ny != 0)
00082     mesh.set_mesh_dimension(2);
00083   else
00084     mesh.set_mesh_dimension(1);
00085   
00086   switch (mesh.mesh_dimension())
00087     {
00088 
00089       
00090       //---------------------------------------------------------------------
00091       // Build a 1D line
00092     case 1:      
00093       {
00094         libmesh_assert (nx != 0);
00095         libmesh_assert (ny == 0);
00096         libmesh_assert (nz == 0);
00097         libmesh_assert (xmin < xmax);
00098 
00099         // Reserve elements
00100         switch (type)
00101           {
00102           case INVALID_ELEM:
00103           case EDGE2:
00104           case EDGE3:
00105           case EDGE4:
00106             {
00107               mesh.reserve_elem (nx);
00108               break;
00109             }
00110 
00111           default:
00112             {
00113               std::cerr << "ERROR: Unrecognized 1D element type." << std::endl;
00114               libmesh_error();
00115             }
00116           }
00117 
00118         // Reserve nodes
00119         switch (type)
00120           {
00121           case INVALID_ELEM:
00122           case EDGE2:
00123             {
00124               mesh.reserve_nodes(nx+1);
00125               break;
00126             }
00127 
00128           case EDGE3:
00129             {
00130               mesh.reserve_nodes(2*nx+1);
00131               break;
00132             }
00133 
00134           case EDGE4:
00135             {
00136               mesh.reserve_nodes(3*nx+1);
00137               break;
00138             }
00139 
00140           default:
00141             {
00142               std::cerr << "ERROR: Unrecognized 1D element type." << std::endl;
00143               libmesh_error();
00144             }
00145           }
00146 
00147 
00148         // Build the nodes, depends on whether we're using linears, 
00149         // quadratics or cubics and whether using uniform grid or Gauss-Lobatto
00150         unsigned int node_id = 0;
00151         switch(type)
00152         {
00153           case INVALID_ELEM:
00154           case EDGE2:
00155             {
00156               for (unsigned int i=0; i<=nx; i++)
00157               {
00158                 if (gauss_lobatto_grid)
00159                   mesh.add_point (Point(0.5*(std::cos(libMesh::pi*static_cast<Real>(nx-i)/static_cast<Real>(nx))+1.0),
00160                         0, 
00161                         0), node_id++);
00162                 else
00163                   mesh.add_point (Point(static_cast<Real>(i)/static_cast<Real>(nx), 
00164                         0, 
00165                         0), node_id++);
00166               }
00167               break;
00168             }
00169 
00170           case EDGE3:
00171             {
00172               for (unsigned int i=0; i<=2*nx; i++)
00173               {
00174                 if (gauss_lobatto_grid)
00175                 {
00176                   // The x location of the point.
00177                   Real x=0.;
00178 
00179                   // Shortcut variable
00180                   const Real pi = libMesh::pi;
00181 
00182                   // Shortcut quantities (do not depend on i)
00183                   const Real c = std::cos( pi*i / static_cast<Real>(2*nx) );
00184 
00185                   // If i is even, compute a normal Gauss-Lobatto point
00186                   if (i%2 == 0)
00187                     x = 0.5*(1.0 - c);
00188 
00189                   // Otherwise, it is the average of the previous and next points
00190                   else
00191                   {
00192                     Real cmin = std::cos( pi*(i-1) / static_cast<Real>(2*nx) );
00193                     Real cmax = std::cos( pi*(i+1) / static_cast<Real>(2*nx) );
00194                     
00195                     Real xmin = 0.5*(1.0 - cmin);
00196                     Real xmax = 0.5*(1.0 - cmax);
00197                     x = 0.5*(xmin + xmax);
00198                   }
00199 
00200                   mesh.add_point (Point(x,0.,0.), node_id++);
00201                 }
00202                 else
00203                   mesh.add_point (Point(static_cast<Real>(i)/static_cast<Real>(2*nx),
00204                         0,
00205                         0), node_id++);
00206               }
00207               break;
00208             }
00209 
00210           case EDGE4:
00211             {
00212               for (unsigned int i=0; i<=3*nx; i++)
00213               {
00214                 if (gauss_lobatto_grid)
00215                 {
00216                   // The x location of the point
00217                   Real x=0.;
00218                   
00219                   const Real pi = libMesh::pi;
00220 
00221                   // Shortcut quantities
00222                   const Real c = std::cos( pi*i / static_cast<Real>(3*nx) );
00223 
00224                   // If i is multiple of 3, compute a normal Gauss-Lobatto point
00225                   if (i%3 == 0)
00226                     x = 0.5*(1.0 - c);
00227 
00228                   // Otherwise, distribute points evenly within the element
00229                   else
00230                   {
00231                     if(i%3 == 1)
00232                     {
00233                       Real cmin = std::cos( pi*(i-1) / static_cast<Real>(3*nx) );
00234                       Real cmax = std::cos( pi*(i+2) / static_cast<Real>(3*nx) );
00235 
00236                       Real xmin = 0.5*(1.0 - cmin);
00237                       Real xmax = 0.5*(1.0 - cmax);
00238 
00239                       x = (2.*xmin + xmax)/3.;
00240                     }
00241                     else
00242                     if(i%3 == 2)
00243                     {
00244                       Real cmin = std::cos( pi*(i-2) / static_cast<Real>(3*nx) );
00245                       Real cmax = std::cos( pi*(i+1) / static_cast<Real>(3*nx) );
00246 
00247                       Real xmin = 0.5*(1.0 - cmin);
00248                       Real xmax = 0.5*(1.0 - cmax);
00249 
00250                       x = (xmin + 2.*xmax)/3.;
00251                     }
00252 
00253                   }
00254 
00255                   mesh.add_point (Point(x,0.,0.), node_id++);
00256                 }
00257                 else
00258                 mesh.add_point (Point(static_cast<Real>(i)/static_cast<Real>(3*nx),
00259                         0,
00260                         0), node_id++);
00261               }
00262 
00263 
00264             
00265               break;
00266             }
00267             
00268           default:
00269             {
00270               std::cerr << "ERROR: Unrecognized 1D element type." << std::endl;
00271               libmesh_error();
00272             }
00273               
00274         }
00275 
00276         // Build the elements of the mesh
00277         switch(type)
00278           {
00279             case INVALID_ELEM:
00280             case EDGE2:
00281               {
00282                 for (unsigned int i=0; i<nx; i++)
00283                 {
00284                   Elem* elem = mesh.add_elem (new Edge2);
00285                   elem->set_node(0) = mesh.node_ptr(i);
00286                   elem->set_node(1) = mesh.node_ptr(i+1);
00287 
00288                   if (i == 0)
00289                     mesh.boundary_info->add_side(elem, 0, 0);
00290 
00291                   if (i == (nx-1))
00292                     mesh.boundary_info->add_side(elem, 1, 1);
00293                 }
00294               break;
00295               }
00296 
00297             case EDGE3:
00298               {
00299                 for (unsigned int i=0; i<nx; i++)
00300                 {
00301                   Elem* elem = mesh.add_elem (new Edge3);
00302                   elem->set_node(0) = mesh.node_ptr(2*i);
00303                   elem->set_node(2) = mesh.node_ptr(2*i+1);
00304                   elem->set_node(1) = mesh.node_ptr(2*i+2);
00305 
00306                   if (i == 0)
00307                     mesh.boundary_info->add_side(elem, 0, 0);
00308 
00309                   if (i == (nx-1))
00310                     mesh.boundary_info->add_side(elem, 1, 1);
00311                 }
00312               break;
00313               }
00314 
00315             case EDGE4:
00316               {
00317                 for (unsigned int i=0; i<nx; i++)
00318                 {
00319                   Elem* elem = mesh.add_elem (new Edge4);
00320                   elem->set_node(0) = mesh.node_ptr(3*i);
00321                   elem->set_node(2) = mesh.node_ptr(3*i+1);
00322                   elem->set_node(3) = mesh.node_ptr(3*i+2);
00323                   elem->set_node(1) = mesh.node_ptr(3*i+3);
00324 
00325                   if (i == 0)
00326                     mesh.boundary_info->add_side(elem, 0, 0);
00327 
00328                   if (i == (nx-1))
00329                     mesh.boundary_info->add_side(elem, 1, 1);
00330                 }
00331               break;
00332               }
00333 
00334             default:
00335               {
00336                 std::cerr << "ERROR: Unrecognized 1D element type." << std::endl;
00337                 libmesh_error();                
00338               }
00339           }
00340 
00341         // Scale the nodal positions
00342         for (unsigned int p=0; p<mesh.n_nodes(); p++)
00343           mesh.node(p)(0) = (mesh.node(p)(0))*(xmax-xmin) + xmin;
00344         
00345         break;
00346       }
00347 
00348 
00349 
00350 
00351 
00352 
00353 
00354       
00355       
00356       
00357       //---------------------------------------------------------------------
00358       // Build a 2D quadrilateral
00359     case 2:
00360       {
00361         libmesh_assert (nx != 0);
00362         libmesh_assert (ny != 0);
00363         libmesh_assert (nz == 0);
00364         libmesh_assert (xmin < xmax);
00365         libmesh_assert (ymin < ymax);
00366 
00367         // Reserve elements.  The TRI3 and TRI6 meshes
00368         // have twice as many elements...
00369         switch (type)
00370           {
00371           case INVALID_ELEM:
00372           case QUAD4:
00373           case QUAD8:
00374           case QUAD9:
00375             {
00376               mesh.reserve_elem (nx*ny);
00377               break;
00378             }
00379 
00380           case TRI3:
00381           case TRI6:
00382             {
00383               mesh.reserve_elem (2*nx*ny);
00384               break;
00385             }
00386 
00387           default:
00388             {
00389               std::cerr << "ERROR: Unrecognized 2D element type." << std::endl;
00390               libmesh_error();
00391             }
00392           }
00393 
00394 
00395         
00396         // Reserve nodes.  The quadratic element types
00397         // need to reserve more nodes than the linear types.
00398         switch (type)
00399           {
00400           case INVALID_ELEM:
00401           case QUAD4:
00402           case TRI3:
00403             {
00404               mesh.reserve_nodes( (nx+1)*(ny+1) );
00405               break;
00406             }
00407             
00408           case QUAD8:
00409           case QUAD9:
00410           case TRI6:
00411             {
00412               mesh.reserve_nodes( (2*nx+1)*(2*ny+1) );
00413               break;
00414             }
00415 
00416             
00417           default:
00418             {
00419               std::cerr << "ERROR: Unrecognized 2D element type." << std::endl;
00420               libmesh_error();
00421             }
00422           }
00423 
00424 
00425 
00426         // Build the nodes. Depends on whether you are using a linear
00427         // or quadratic element, and whether you are using a uniform
00428         // grid or the Gauss-Lobatto grid points.
00429         unsigned int node_id = 0;
00430         switch (type)
00431           {
00432           case INVALID_ELEM:
00433           case QUAD4:
00434           case TRI3:
00435             {
00436               for (unsigned int j=0; j<=ny; j++)
00437                 for (unsigned int i=0; i<=nx; i++)
00438                   {
00439                     if (gauss_lobatto_grid)
00440                       {
00441                         // Shortcut variable
00442                         const Real pi = libMesh::pi;
00443 
00444                         mesh.add_point (Point(0.5*(1.0 - std::cos(pi*static_cast<Real>(i)/static_cast<Real>(nx))),
00445                                               0.5*(1.0 - std::cos(pi*static_cast<Real>(j)/static_cast<Real>(ny))),
00446                                               0.), node_id++);
00447                       }
00448                   
00449                     else
00450                       mesh.add_point (Point(static_cast<Real>(i)/static_cast<Real>(nx),
00451                                             static_cast<Real>(j)/static_cast<Real>(ny),
00452                                             0.), node_id++);
00453                   }
00454 
00455               break;
00456             }
00457             
00458           case QUAD8:
00459           case QUAD9:
00460           case TRI6:
00461             {
00462               for (unsigned int j=0; j<=(2*ny); j++)
00463                 for (unsigned int i=0; i<=(2*nx); i++)
00464                   {
00465                     if (gauss_lobatto_grid)
00466                       {
00467                         // The x,y locations of the point.
00468                         Real x=0., y=0.;
00469 
00470                         // Shortcut variable
00471                         const Real pi = libMesh::pi;
00472                         
00473                         // Shortcut quantities (do not depend on i,j)
00474                         const Real a = std::cos( pi / static_cast<Real>(2*nx) );
00475                         const Real b = std::cos( pi / static_cast<Real>(2*ny) );
00476 
00477                         // Shortcut quantities (depend on i,j)
00478                         const Real c = std::cos( pi*i / static_cast<Real>(2*nx) );
00479                         const Real d = std::cos( pi*j / static_cast<Real>(2*ny) );
00480                         
00481                         // If i is even, compute a normal Gauss-Lobatto point
00482                         if (i%2 == 0)
00483                           x = 0.5*(1.0 - c);
00484 
00485                         // Otherwise, it is the average of the previous and next points
00486                         else
00487                           x = 0.5*(1.0 - a*c);
00488                       
00489                         // If j is even, compute a normal Gauss-Lobatto point
00490                         if (j%2 == 0)
00491                           y = 0.5*(1.0 - d);
00492                       
00493                         // Otherwise, it is the average of the previous and next points
00494                         else
00495                           y = 0.5*(1.0 - b*d);
00496                       
00497 
00498                         mesh.add_point (Point(x,y,0.), node_id++);
00499                       } 
00500 
00501                   
00502                     else
00503                       mesh.add_point (Point(static_cast<Real>(i)/static_cast<Real>(2*nx),
00504                                             static_cast<Real>(j)/static_cast<Real>(2*ny),
00505                                             0), node_id++);
00506                 }
00507 
00508               break;
00509             }
00510 
00511             
00512           default:
00513             {
00514               std::cerr << "ERROR: Unrecognized 2D element type." << std::endl;
00515               libmesh_error();
00516             }
00517           }
00518 
00519 
00520 
00521 
00522 
00523 
00524         // Build the elements.  Each one is a bit different.
00525         switch (type)
00526           {
00527 
00528           case INVALID_ELEM:
00529           case QUAD4:
00530             {
00531               for (unsigned int j=0; j<ny; j++)
00532                 for (unsigned int i=0; i<nx; i++)
00533                   {
00534                     Elem* elem = mesh.add_elem(new Quad4);
00535 
00536                     elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j)    );
00537                     elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+1,j)  );
00538                     elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+1,j+1));
00539                     elem->set_node(3) = mesh.node_ptr(idx(type,nx,i,j+1)  );
00540 
00541                     if (j == 0)
00542                       mesh.boundary_info->add_side(elem, 0, 0);
00543                   
00544                     if (j == (ny-1))
00545                       mesh.boundary_info->add_side(elem, 2, 2);
00546                   
00547                     if (i == 0)
00548                       mesh.boundary_info->add_side(elem, 3, 3);
00549                   
00550                     if (i == (nx-1))
00551                       mesh.boundary_info->add_side(elem, 1, 1);
00552                   }
00553               break;
00554             }
00555 
00556 
00557           case TRI3:
00558             {
00559               for (unsigned int j=0; j<ny; j++)
00560                 for (unsigned int i=0; i<nx; i++)
00561                   {
00562                     Elem* elem = NULL;
00563 
00564                     // Add first Tri3
00565                     elem = mesh.add_elem(new Tri3);
00566 
00567                     elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j)    );
00568                     elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+1,j)  );
00569                     elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+1,j+1));
00570 
00571                     if (j == 0)
00572                       mesh.boundary_info->add_side(elem, 0, 0);
00573 
00574                     if (i == (nx-1))
00575                       mesh.boundary_info->add_side(elem, 1, 1);
00576 
00577                     // Add second Tri3
00578                     elem = mesh.add_elem(new Tri3);
00579 
00580                     elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j)    );
00581                     elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+1,j+1));
00582                     elem->set_node(2) = mesh.node_ptr(idx(type,nx,i,j+1)  );
00583 
00584                     if (j == (ny-1))
00585                       mesh.boundary_info->add_side(elem, 1, 2);
00586 
00587                     if (i == 0)
00588                       mesh.boundary_info->add_side(elem, 2, 3);
00589                   }
00590               break;
00591             }
00592 
00593 
00594 
00595           case QUAD8:
00596           case QUAD9:
00597             {
00598               for (unsigned int j=0; j<(2*ny); j += 2)
00599                 for (unsigned int i=0; i<(2*nx); i += 2)
00600                   {
00601                     Elem* elem = (type == QUAD8) ?
00602                       mesh.add_elem(new Quad8) :
00603                       mesh.add_elem(new Quad9);
00604                   
00605 
00606                     elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j)    );
00607                     elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+2,j)  );
00608                     elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+2,j+2));
00609                     elem->set_node(3) = mesh.node_ptr(idx(type,nx,i,j+2)  );
00610                     elem->set_node(4) = mesh.node_ptr(idx(type,nx,i+1,j)  );
00611                     elem->set_node(5) = mesh.node_ptr(idx(type,nx,i+2,j+1));
00612                     elem->set_node(6) = mesh.node_ptr(idx(type,nx,i+1,j+2));
00613                     elem->set_node(7) = mesh.node_ptr(idx(type,nx,i,j+1)  );
00614                     if (type == QUAD9)
00615                       elem->set_node(8) = mesh.node_ptr(idx(type,nx,i+1,j+1));
00616                   
00617 
00618                     if (j == 0)
00619                       mesh.boundary_info->add_side(elem, 0, 0);
00620                   
00621                     if (j == 2*(ny-1))
00622                       mesh.boundary_info->add_side(elem, 2, 2);
00623                   
00624                     if (i == 0)
00625                       mesh.boundary_info->add_side(elem, 3, 3);
00626                   
00627                     if (i == 2*(nx-1))
00628                       mesh.boundary_info->add_side(elem, 1, 1);
00629                   }
00630               break;
00631             }
00632 
00633 
00634           case TRI6:
00635             {
00636               for (unsigned int j=0; j<(2*ny); j += 2)
00637                 for (unsigned int i=0; i<(2*nx); i += 2)
00638                   {
00639                     Elem* elem = NULL;
00640 
00641                     // Add first Tri6
00642                     elem = mesh.add_elem(new Tri6);
00643 
00644                     elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j)    );
00645                     elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+2,j)  );
00646                     elem->set_node(2) = mesh.node_ptr(idx(type,nx,i+2,j+2));
00647                     elem->set_node(3) = mesh.node_ptr(idx(type,nx,i+1,j)  );
00648                     elem->set_node(4) = mesh.node_ptr(idx(type,nx,i+2,j+1));
00649                     elem->set_node(5) = mesh.node_ptr(idx(type,nx,i+1,j+1));
00650 
00651                     if (j == 0)
00652                       mesh.boundary_info->add_side(elem, 0, 0);
00653 
00654                     if (i == 2*(nx-1))
00655                       mesh.boundary_info->add_side(elem, 1, 1);
00656 
00657                     // Add second Tri6
00658                     elem = mesh.add_elem(new Tri6);
00659 
00660                     elem->set_node(0) = mesh.node_ptr(idx(type,nx,i,j)    );
00661                     elem->set_node(1) = mesh.node_ptr(idx(type,nx,i+2,j+2));
00662                     elem->set_node(2) = mesh.node_ptr(idx(type,nx,i,j+2)  );
00663                     elem->set_node(3) = mesh.node_ptr(idx(type,nx,i+1,j+1));
00664                     elem->set_node(4) = mesh.node_ptr(idx(type,nx,i+1,j+2));
00665                     elem->set_node(5) = mesh.node_ptr(idx(type,nx,i,j+1)  );
00666 
00667                     if (j == 2*(ny-1))
00668                       mesh.boundary_info->add_side(elem, 1, 2);
00669 
00670                     if (i == 0)
00671                       mesh.boundary_info->add_side(elem, 2, 3);
00672 
00673                   }
00674               break;
00675             };
00676 
00677             
00678           default:
00679             {
00680               std::cerr << "ERROR: Unrecognized 2D element type." << std::endl;
00681               libmesh_error();
00682             }
00683           }
00684 
00685 
00686 
00687         
00688         // Scale the nodal positions
00689         for (unsigned int p=0; p<mesh.n_nodes(); p++)
00690           {
00691             mesh.node(p)(0) = (mesh.node(p)(0))*(xmax-xmin) + xmin;
00692             mesh.node(p)(1) = (mesh.node(p)(1))*(ymax-ymin) + ymin;
00693           }
00694 
00695         
00696         break;
00697       }
00698 
00699 
00700 
00701 
00702 
00703 
00704 
00705 
00706       
00707 
00708 
00709       //---------------------------------------------------------------------
00710       // Build a 3D mesh using hexahedral or prismatic elements.
00711     case 3:
00712       {
00713         libmesh_assert (nx != 0);
00714         libmesh_assert (ny != 0);
00715         libmesh_assert (nz != 0);
00716         libmesh_assert (xmin < xmax);
00717         libmesh_assert (ymin < ymax);
00718         libmesh_assert (zmin < zmax);
00719 
00720 
00721         // Reserve elements.  Meshes with prismatic elements require
00722         // twice as many elements.
00723         switch (type)
00724           {
00725           case INVALID_ELEM:
00726           case HEX8:
00727           case HEX20:
00728           case HEX27:
00729           case TET4:  // TET4's are created from an initial HEX27 discretization
00730           case TET10: // TET10's are created from an initial HEX27 discretization
00731           case PYRAMID5: // PYRAMID5's are created from an initial HEX27 discretization
00732             {
00733               mesh.reserve_elem(nx*ny*nz);
00734               break;
00735             }
00736 
00737           case PRISM6:
00738           case PRISM15:
00739           case PRISM18:
00740             {
00741               mesh.reserve_elem(2*nx*ny*nz);
00742               break;
00743             }
00744 
00745           default:
00746             {
00747               std::cerr << "ERROR: Unrecognized 3D element type." << std::endl;
00748               libmesh_error();
00749             }
00750           }
00751 
00752 
00753 
00754 
00755         
00756         // Reserve nodes.  Quadratic elements need twice as many nodes as linear elements.
00757         switch (type)
00758           {
00759           case INVALID_ELEM:
00760           case HEX8:
00761           case PRISM6:
00762             {
00763               mesh.reserve_nodes( (nx+1)*(ny+1)*(nz+1) );
00764               break;
00765             }
00766 
00767           case HEX20:
00768           case HEX27:
00769           case TET4: // TET4's are created from an initial HEX27 discretization
00770           case TET10: // TET10's are created from an initial HEX27 discretization
00771           case PYRAMID5: // PYRAMID5's are created from an initial HEX27 discretization
00772           case PRISM15:
00773           case PRISM18:
00774             {
00775               // FYI: The resulting TET4 mesh will have exactly
00776               // 5*(nx*ny*nz) + 2*(nx*ny + nx*nz + ny*nz) + (nx+ny+nz) + 1
00777               // nodes once the additional mid-edge nodes for the HEX27 discretization
00778               // have been deleted.
00779               mesh.reserve_nodes( (2*nx+1)*(2*ny+1)*(2*nz+1) );
00780               break;
00781             }
00782 
00783           default:
00784             {
00785               std::cerr << "ERROR: Unrecognized 3D element type." << std::endl;
00786               libmesh_error();
00787             }
00788           }
00789 
00790 
00791 
00792 
00793         // Build the nodes.
00794         unsigned int node_id = 0;
00795         switch (type)
00796           {
00797           case INVALID_ELEM:
00798           case HEX8:
00799           case PRISM6:
00800             {
00801               for (unsigned int k=0; k<=nz; k++)
00802                 for (unsigned int j=0; j<=ny; j++)
00803                   for (unsigned int i=0; i<=nx; i++)
00804                     {
00805                       if (gauss_lobatto_grid)
00806                         {
00807                           // Shortcut variable
00808                           const Real pi = libMesh::pi;
00809 
00810                           mesh.add_point (Point(0.5*(1.0 - std::cos(pi*static_cast<Real>(i)/static_cast<Real>(nx))),
00811                                                 0.5*(1.0 - std::cos(pi*static_cast<Real>(j)/static_cast<Real>(ny))),
00812                                                 0.5*(1.0 - std::cos(pi*static_cast<Real>(k)/static_cast<Real>(nz)))), node_id++);
00813                         }
00814                       
00815                       else
00816                         mesh.add_point(Point(static_cast<Real>(i)/static_cast<Real>(nx),
00817                                              static_cast<Real>(j)/static_cast<Real>(ny),
00818                                              static_cast<Real>(k)/static_cast<Real>(nz)), node_id++);
00819                     }
00820               break;
00821             }
00822             
00823           case HEX20:
00824           case HEX27:
00825           case TET4: // TET4's are created from an initial HEX27 discretization
00826           case TET10: // TET10's are created from an initial HEX27 discretization
00827           case PYRAMID5: // PYRAMID5's are created from an initial HEX27 discretization
00828           case PRISM15:
00829           case PRISM18:
00830             {
00831               for (unsigned int k=0; k<=(2*nz); k++)
00832                 for (unsigned int j=0; j<=(2*ny); j++)
00833                   for (unsigned int i=0; i<=(2*nx); i++)
00834                     {
00835                       if (gauss_lobatto_grid)
00836                         {
00837                           // Shortcut variable
00838                           const Real pi = libMesh::pi;
00839                           
00840                           // The x,y locations of the point.
00841                           Real x=0., y=0., z=0.;
00842 
00843                           // Shortcut quantities (do not depend on i,j)
00844                           const Real a = std::cos( pi / static_cast<Real>(2*nx) );
00845                           const Real b = std::cos( pi / static_cast<Real>(2*ny) );
00846 
00847                           // Shortcut quantities (depend on i,j)
00848                           const Real c = std::cos( pi*i / static_cast<Real>(2*nx) );
00849                           const Real d = std::cos( pi*j / static_cast<Real>(2*ny) );
00850                           
00851                           // Additional shortcut quantities (for 3D)
00852                           const Real e = std::cos( pi / static_cast<Real>(2*nz) );
00853                           const Real f = std::cos( pi*k / static_cast<Real>(2*nz) );
00854                           
00855                           // If i is even, compute a normal Gauss-Lobatto point
00856                           if (i%2 == 0)
00857                             x = 0.5*(1.0 - c);
00858 
00859                           // Otherwise, it is the average of the previous and next points
00860                           else
00861                             x = 0.5*(1.0 - a*c);
00862                       
00863                           // If j is even, compute a normal Gauss-Lobatto point
00864                           if (j%2 == 0)
00865                             y = 0.5*(1.0 - d);
00866                       
00867                           // Otherwise, it is the average of the previous and next points
00868                           else
00869                             y = 0.5*(1.0 - b*d);
00870 
00871                           // If k is even, compute a normal Gauss-Lobatto point
00872                           if (k%2 == 0)
00873                             z = 0.5*(1.0 - f);
00874                       
00875                           // Otherwise, it is the average of the previous and next points
00876                           else
00877                             z = 0.5*(1.0 - e*f);
00878                       
00879                           
00880                           mesh.add_point (Point(x,y,z), node_id++);
00881                         }
00882 
00883                       else
00884                         mesh.add_point(Point(static_cast<Real>(i)/static_cast<Real>(2*nx),
00885                                              static_cast<Real>(j)/static_cast<Real>(2*ny),
00886                                              static_cast<Real>(k)/static_cast<Real>(2*nz)), node_id++);
00887                     }
00888               break;
00889             }
00890 
00891 
00892           default:
00893             {
00894               std::cerr << "ERROR: Unrecognized 3D element type." << std::endl;
00895               libmesh_error();
00896             }
00897           }
00898 
00899             
00900 
00901         
00902         // Build the elements.
00903         switch (type)
00904           {
00905           case INVALID_ELEM:
00906           case HEX8:
00907             {
00908               for (unsigned int k=0; k<nz; k++)
00909                 for (unsigned int j=0; j<ny; j++)
00910                   for (unsigned int i=0; i<nx; i++)
00911                     {
00912                       Elem* elem = mesh.add_elem(new Hex8);
00913                         
00914                       elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i,j,k)      );
00915                       elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k)    );
00916                       elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  );
00917                       elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k)    );
00918                       elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i,j,k+1)    );
00919                       elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1)  );
00920                       elem->set_node(6) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
00921                       elem->set_node(7) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1)  );
00922                         
00923                       if (k == 0)
00924                         mesh.boundary_info->add_side(elem, 0, 0);
00925                         
00926                       if (k == (nz-1))
00927                         mesh.boundary_info->add_side(elem, 5, 5);
00928                         
00929                       if (j == 0)
00930                         mesh.boundary_info->add_side(elem, 1, 1);
00931 
00932                       if (j == (ny-1))
00933                         mesh.boundary_info->add_side(elem, 3, 3);
00934                         
00935                       if (i == 0)
00936                         mesh.boundary_info->add_side(elem, 4, 4);
00937                         
00938                       if (i == (nx-1))
00939                         mesh.boundary_info->add_side(elem, 2, 2);
00940                     }
00941               break;
00942             }
00943 
00944 
00945 
00946 
00947           case PRISM6:
00948             {
00949               for (unsigned int k=0; k<nz; k++)
00950                 for (unsigned int j=0; j<ny; j++)
00951                   for (unsigned int i=0; i<nx; i++)
00952                     {
00953                       // First Prism
00954                       Elem* elem = NULL;
00955                       elem = mesh.add_elem(new Prism6);
00956 
00957                       elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i,j,k)      );
00958                       elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k)    );
00959                       elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k)    );
00960                       elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i,j,k+1)    );
00961                       elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1)  );
00962                       elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1)  );
00963 
00964                       // Add sides for first prism to boundary info object
00965                       if (i==0)
00966                         mesh.boundary_info->add_side(elem, 3, 4);
00967 
00968                       if (j==0)
00969                         mesh.boundary_info->add_side(elem, 1, 1);
00970 
00971                       if (k==0)
00972                         mesh.boundary_info->add_side(elem, 0, 0);
00973 
00974                       if (k == (nz-1))
00975                         mesh.boundary_info->add_side(elem, 4, 5);
00976 
00977                       // Second Prism
00978                       elem = mesh.add_elem(new Prism6);
00979 
00980                       elem->set_node(0) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k)    );
00981                       elem->set_node(1) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  );
00982                       elem->set_node(2) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k)    );
00983                       elem->set_node(3) = mesh.node_ptr(idx(type,nx,ny,i+1,j,k+1)  );
00984                       elem->set_node(4) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
00985                       elem->set_node(5) = mesh.node_ptr(idx(type,nx,ny,i,j+1,k+1)  );
00986 
00987                       // Add sides for second prism to boundary info object
00988                       if (i == (nx-1))
00989                         mesh.boundary_info->add_side(elem, 1, 2);
00990 
00991                       if (j == (ny-1))
00992                         mesh.boundary_info->add_side(elem, 2, 3);
00993 
00994                       if (k==0)
00995                         mesh.boundary_info->add_side(elem, 0, 0);
00996 
00997                       if (k == (nz-1))
00998                         mesh.boundary_info->add_side(elem, 4, 5);
00999                     }
01000               break;
01001             }
01002 
01003 
01004 
01005 
01006             
01007             
01008           case HEX20:
01009           case HEX27:
01010           case TET4: // TET4's are created from an initial HEX27 discretization
01011           case TET10: // TET10's are created from an initial HEX27 discretization
01012           case PYRAMID5: // PYRAMID5's are created from an initial HEX27 discretization
01013             {
01014               for (unsigned int k=0; k<(2*nz); k += 2)
01015                 for (unsigned int j=0; j<(2*ny); j += 2)
01016                   for (unsigned int i=0; i<(2*nx); i += 2)
01017                     {
01018                       Elem* elem = (type == HEX20) ?
01019                         mesh.add_elem(new Hex20) :
01020                         mesh.add_elem(new Hex27);
01021                     
01022                       elem->set_node(0)  = mesh.node_ptr(idx(type,nx,ny,i,  j,  k)  );
01023                       elem->set_node(1)  = mesh.node_ptr(idx(type,nx,ny,i+2,j,  k)  );
01024                       elem->set_node(2)  = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k)  );
01025                       elem->set_node(3)  = mesh.node_ptr(idx(type,nx,ny,i,  j+2,k)  );
01026                       elem->set_node(4)  = mesh.node_ptr(idx(type,nx,ny,i,  j,  k+2));
01027                       elem->set_node(5)  = mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+2));
01028                       elem->set_node(6)  = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+2));
01029                       elem->set_node(7)  = mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+2));
01030                       elem->set_node(8)  = mesh.node_ptr(idx(type,nx,ny,i+1,j,  k)  );
01031                       elem->set_node(9)  = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k)  );
01032                       elem->set_node(10) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k)  );
01033                       elem->set_node(11) = mesh.node_ptr(idx(type,nx,ny,i,  j+1,k)  );
01034                       elem->set_node(12) = mesh.node_ptr(idx(type,nx,ny,i,  j,  k+1));
01035                       elem->set_node(13) = mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+1));
01036                       elem->set_node(14) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+1));
01037                       elem->set_node(15) = mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+1));
01038                       elem->set_node(16) = mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+2));
01039                       elem->set_node(17) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+2));
01040                       elem->set_node(18) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+2));
01041                       elem->set_node(19) = mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+2));
01042                       if ((type == HEX27) || (type == TET4) || (type == TET10) || (type == PYRAMID5))
01043                         {
01044                           elem->set_node(20) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  );
01045                           elem->set_node(21) = mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+1));
01046                           elem->set_node(22) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+1));
01047                           elem->set_node(23) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+1));
01048                           elem->set_node(24) = mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+1));
01049                           elem->set_node(25) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2));
01050                           elem->set_node(26) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
01051                         }
01052                         
01053                         
01054                       if (k == 0)
01055                         mesh.boundary_info->add_side(elem, 0, 0);
01056                         
01057                       if (k == 2*(nz-1))
01058                         mesh.boundary_info->add_side(elem, 5, 5);
01059                         
01060                       if (j == 0)
01061                         mesh.boundary_info->add_side(elem, 1, 1);
01062 
01063                       if (j == 2*(ny-1))
01064                         mesh.boundary_info->add_side(elem, 3, 3);
01065                         
01066                       if (i == 0)
01067                         mesh.boundary_info->add_side(elem, 4, 4);
01068                         
01069                       if (i == 2*(nx-1))
01070                         mesh.boundary_info->add_side(elem, 2, 2);
01071                     }
01072               break;
01073             }
01074 
01075 
01076 
01077             
01078           case PRISM15:
01079           case PRISM18:
01080             {
01081               for (unsigned int k=0; k<(2*nz); k += 2)
01082                 for (unsigned int j=0; j<(2*ny); j += 2)
01083                   for (unsigned int i=0; i<(2*nx); i += 2)
01084                     {
01085                       // First Prism
01086                       Elem* elem = NULL;
01087                       elem = ((type == PRISM15) ?
01088                               mesh.add_elem(new Prism15) :
01089                               mesh.add_elem(new Prism18));
01090 
01091                       elem->set_node(0)  = mesh.node_ptr(idx(type,nx,ny,i,  j,  k)  );
01092                       elem->set_node(1)  = mesh.node_ptr(idx(type,nx,ny,i+2,j,  k)  );
01093                       elem->set_node(2)  = mesh.node_ptr(idx(type,nx,ny,i,  j+2,k)  );
01094                       elem->set_node(3)  = mesh.node_ptr(idx(type,nx,ny,i,  j,  k+2));
01095                       elem->set_node(4)  = mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+2));
01096                       elem->set_node(5)  = mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+2));
01097                       elem->set_node(6)  = mesh.node_ptr(idx(type,nx,ny,i+1,j,  k)  );
01098                       elem->set_node(7)  = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  );
01099                       elem->set_node(8)  = mesh.node_ptr(idx(type,nx,ny,i,  j+1,k)  );
01100                       elem->set_node(9)  = mesh.node_ptr(idx(type,nx,ny,i,  j,  k+1));
01101                       elem->set_node(10) = mesh.node_ptr(idx(type,nx,ny,i+2,j,  k+1));
01102                       elem->set_node(11) = mesh.node_ptr(idx(type,nx,ny,i,  j+2,k+1));
01103                       elem->set_node(12) = mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+2));
01104                       elem->set_node(13) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2));
01105                       elem->set_node(14) = mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+2));
01106                       if (type == PRISM18)
01107                         {
01108                           elem->set_node(15) = mesh.node_ptr(idx(type,nx,ny,i+1,j,  k+1));
01109                           elem->set_node(16) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
01110                           elem->set_node(17) = mesh.node_ptr(idx(type,nx,ny,i,  j+1,k+1));
01111                         }
01112 
01113                       // Add sides for first prism to boundary info object
01114                       if (i==0)
01115                         mesh.boundary_info->add_side(elem, 3, 4);
01116 
01117                       if (j==0)
01118                         mesh.boundary_info->add_side(elem, 1, 1);
01119 
01120                       if (k==0)
01121                         mesh.boundary_info->add_side(elem, 0, 0);
01122 
01123                       if (k == 2*(nz-1))
01124                         mesh.boundary_info->add_side(elem, 4, 5);
01125 
01126                       
01127                       // Second Prism
01128                       elem = ((type == PRISM15) ?
01129                               mesh.add_elem(new Prism15) :
01130                               mesh.add_elem(new Prism18));
01131                         
01132                       elem->set_node(0)  = mesh.node_ptr(idx(type,nx,ny,i+2,j,k)     );
01133                       elem->set_node(1)  = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k)   );
01134                       elem->set_node(2)  = mesh.node_ptr(idx(type,nx,ny,i,j+2,k)     );
01135                       elem->set_node(3)  = mesh.node_ptr(idx(type,nx,ny,i+2,j,k+2)   );
01136                       elem->set_node(4)  = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+2) );
01137                       elem->set_node(5)  = mesh.node_ptr(idx(type,nx,ny,i,j+2,k+2)   );
01138                       elem->set_node(6)  = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k)  );
01139                       elem->set_node(7)  = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k)  );
01140                       elem->set_node(8)  = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k)  );
01141                       elem->set_node(9)  = mesh.node_ptr(idx(type,nx,ny,i+2,j,k+1)  );
01142                       elem->set_node(10) = mesh.node_ptr(idx(type,nx,ny,i+2,j+2,k+1));
01143                       elem->set_node(11) = mesh.node_ptr(idx(type,nx,ny,i,j+2,k+1)  );
01144                       elem->set_node(12) = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+2));
01145                       elem->set_node(13) = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+2));
01146                       elem->set_node(14) = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+2));
01147                       if (type == PRISM18)
01148                         {
01149                           elem->set_node(15)  = mesh.node_ptr(idx(type,nx,ny,i+2,j+1,k+1));
01150                           elem->set_node(16)  = mesh.node_ptr(idx(type,nx,ny,i+1,j+2,k+1));
01151                           elem->set_node(17)  = mesh.node_ptr(idx(type,nx,ny,i+1,j+1,k+1));
01152                         }
01153                       
01154                       // Add sides for second prism to boundary info object
01155                       if (i == 2*(nx-1))
01156                         mesh.boundary_info->add_side(elem, 1, 2);
01157 
01158                       if (j == 2*(ny-1))
01159                         mesh.boundary_info->add_side(elem, 2, 3);
01160 
01161                       if (k==0)
01162                         mesh.boundary_info->add_side(elem, 0, 0);
01163 
01164                       if (k == 2*(nz-1))
01165                         mesh.boundary_info->add_side(elem, 4, 5);
01166 
01167                     }
01168               break;
01169             }
01170 
01171 
01172 
01173 
01174             
01175           default:
01176             {
01177               std::cerr << "ERROR: Unrecognized 3D element type." << std::endl;
01178               libmesh_error();
01179             }
01180           }
01181 
01182             
01183 
01184 
01185         //.......................................
01186         // Scale the nodal positions
01187         for (unsigned int p=0; p<mesh.n_nodes(); p++)
01188           {
01189             mesh.node(p)(0) = (mesh.node(p)(0))*(xmax-xmin) + xmin;
01190             mesh.node(p)(1) = (mesh.node(p)(1))*(ymax-ymin) + ymin;
01191             mesh.node(p)(2) = (mesh.node(p)(2))*(zmax-zmin) + zmin;
01192           }
01193 
01194 
01195 
01196 
01197         // Additional work for tets and pyramids: we take the existing
01198         // HEX27 discretization and split each element into 24
01199         // sub-tets or 6 sub-pyramids.
01200         //
01201         // 24 isn't the minimum-possible number of tets, but it
01202         // obviates any concerns about the edge orientations between
01203         // the various elements.
01204         if ((type == TET4) ||
01205             (type == TET10) ||
01206             (type == PYRAMID5)) 
01207           {
01208             // Temporary storage for new elements. (24 tets per hex, 6 pyramids)
01209             std::vector<Elem*> new_elements;
01210             
01211             if ((type == TET4) || (type == TET10))
01212               new_elements.reserve(24*mesh.n_elem());
01213             else
01214               new_elements.reserve(6*mesh.n_elem());
01215               
01216             // Create tetrahedra or pyramids
01217             {
01218               MeshBase::element_iterator       el     = mesh.elements_begin();
01219               const MeshBase::element_iterator end_el = mesh.elements_end();
01220 
01221               for ( ; el != end_el;  ++el)
01222                 {
01223                   // Get a pointer to the HEX27 element.
01224                   Elem* base_hex = *el;
01225 
01226                   // Get a pointer to the node located at the HEX27 centroid
01227                   Node* apex_node = base_hex->get_node(26);
01228          
01229                   for (unsigned int s=0; s<base_hex->n_sides(); ++s)
01230                     {
01231                       // Get the boundary ID for this side
01232                       short int b_id = mesh.boundary_info->boundary_id(*el, s);
01233                       
01234                       // Need to build the full-ordered side!
01235                       AutoPtr<Elem> side = base_hex->build_side(s);
01236 
01237                       if ((type == TET4) || (type == TET10))
01238                         {
01239                           // Build 4 sub-tets per side
01240                           for (unsigned int sub_tet=0; sub_tet<4; ++sub_tet)
01241                             {
01242                               new_elements.push_back( new Tet4 );
01243                               Elem* sub_elem = new_elements.back();
01244                               sub_elem->set_node(0) = side->get_node(sub_tet);
01245                               sub_elem->set_node(1) = side->get_node(8);                           // centroid of the face
01246                               sub_elem->set_node(2) = side->get_node(sub_tet==3 ? 0 : sub_tet+1 ); // wrap-around
01247                               sub_elem->set_node(3) = apex_node;                                   // apex node always used!
01248 
01249                               // If the original hex was a boundary hex, add the new sub_tet's side
01250                               // 0 with the same b_id.  Note: the tets are all aligned so that their
01251                               // side 0 is on the boundary.
01252                               if (b_id != BoundaryInfo::invalid_id)
01253                                 mesh.boundary_info->add_side(sub_elem, 0, b_id);
01254                             }
01255                         } // end if ((type == TET4) || (type == TET10))
01256 
01257                       else // type==PYRAMID5
01258                         {
01259                           // Build 1 sub-pyramid per side.
01260                           new_elements.push_back(new Pyramid5);
01261                           Elem* sub_elem = new_elements.back();
01262                               
01263                           // Set the base.  Note that since the apex is *inside* the base_hex,
01264                           // and the pyramid uses a counter-clockwise base numbering, we need to
01265                           // reverse the [1] and [3] node indices.
01266                           sub_elem->set_node(0) = side->get_node(0);
01267                           sub_elem->set_node(1) = side->get_node(3);
01268                           sub_elem->set_node(2) = side->get_node(2);
01269                           sub_elem->set_node(3) = side->get_node(1);
01270                               
01271                           // Set the apex
01272                           sub_elem->set_node(4) = apex_node;
01273                               
01274                           // If the original hex was a boundary hex, add the new sub_pyr's side
01275                           // 4 (the square base) with the same b_id.  
01276                           if (b_id != BoundaryInfo::invalid_id)
01277                             mesh.boundary_info->add_side(sub_elem, 4, b_id);
01278                         } // end else type==PYRAMID5
01279                     }
01280                 }
01281             }
01282             
01283 
01284             // Delete the original HEX27 elements from the mesh, and the boundary info structure.
01285             {
01286               MeshBase::element_iterator       el     = mesh.elements_begin();
01287               const MeshBase::element_iterator end_el = mesh.elements_end();
01288        
01289               for ( ; el != end_el;  ++el)
01290                 {
01291                   mesh.boundary_info->remove(*el); // Safe even if *el has no boundary info.
01292                   mesh.delete_elem(*el);
01293                 }
01294             }
01295 
01296             // Add the new elements
01297             for (unsigned int i=0; i<new_elements.size(); ++i)
01298               mesh.add_elem(new_elements[i]);
01299             
01300           } // end if (type == TET4,TET10,PYRAMID5
01301 
01302 
01303         // Use all_second_order to convert the TET4's to TET10's
01304         if (type == TET10)
01305           {
01306             mesh.all_second_order();
01307           }
01308 
01309         
01310         break;
01311       } // end case dim==3
01312 
01313     default:
01314       {
01315         libmesh_error();
01316       }
01317     }  
01318 
01319   STOP_LOG("build_cube()", "MeshTools::Generation");
01320 
01321 
01322   
01323   // Done building the mesh.  Now prepare it for use.
01324   mesh.prepare_for_use ();  
01325 }

void 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 = NULL 
)

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 34 of file mesh_triangle_support.C.

References MeshBase::add_point(), TriangleInterface::attach_hole_list(), bc_id, MeshBase::boundary_info, Elem::build_side(), MeshBase::clear(), TriangleInterface::desired_area(), TriangleInterface::elem_type(), MeshBase::elements_begin(), MeshBase::elements_end(), DofObject::id(), MeshBase::n_nodes(), Elem::n_sides(), Elem::neighbor(), TriangleInterface::PSLG, MeshBase::set_mesh_dimension(), side, TriangleInterface::triangulate(), and TriangleInterface::triangulation_type().

00041 {
00042   // Check for reasonable size
00043   libmesh_assert (nx >= 1); // need at least 1 element in x-direction
00044   libmesh_assert (ny >= 1); // need at least 1 element in y-direction
00045   libmesh_assert (xmin < xmax);
00046   libmesh_assert (ymin < ymax);
00047 
00048   // Clear out any data which may have been in the Mesh
00049   mesh.clear();
00050 
00051   // Make sure the new Mesh will be 2D
00052   mesh.set_mesh_dimension(2);
00053   
00054   // The x and y spacing between boundary points
00055   const Real delta_x = (xmax-xmin) / static_cast<Real>(nx);
00056   const Real delta_y = (ymax-ymin) / static_cast<Real>(ny);  
00057 
00058   // Bottom
00059   for (unsigned int p=0; p<=nx; ++p)
00060     mesh.add_point(Point(xmin + p*delta_x, ymin));
00061   
00062   // Right side
00063   for (unsigned int p=1; p<ny; ++p)
00064     mesh.add_point(Point(xmax, ymin + p*delta_y)); 
00065 
00066   // Top
00067   for (unsigned int p=0; p<=nx; ++p)
00068     mesh.add_point(Point(xmax - p*delta_x, ymax));
00069 
00070   // Left side
00071   for (unsigned int p=1; p<ny; ++p)
00072     mesh.add_point(Point(xmin,  ymax - p*delta_y)); 
00073                    
00074   // Be sure we added as many points as we thought we did
00075   libmesh_assert (mesh.n_nodes() == 2*(nx+ny));
00076 
00077   // Construct the Triangle Interface object
00078   TriangleInterface t(mesh);
00079 
00080   // Set custom variables for the triangulation
00081   t.desired_area()       = 0.5 * (xmax-xmin)*(ymax-ymin) / static_cast<Real>(nx*ny);
00082   t.triangulation_type() = TriangleInterface::PSLG;
00083   t.elem_type()          = type;
00084 
00085   if (holes != NULL)
00086     t.attach_hole_list(holes);
00087 
00088   // Triangulate!
00089   t.triangulate();
00090 
00091   // The mesh is now generated, but we still need to mark the boundaries
00092   // to be consistent with the other build_square routines.  Note that only
00093   // the external boundaries of the square are given boundary ids, the holes
00094   // are not numbered.
00095   MeshBase::element_iterator       el     = mesh.elements_begin();
00096   const MeshBase::element_iterator end_el = mesh.elements_end();
00097   for ( ; el != end_el; ++el)
00098     {
00099       const Elem* elem = *el;
00100       
00101       for (unsigned int s=0; s<elem->n_sides(); s++)
00102         if (elem->neighbor(s) == NULL)
00103           {
00104             AutoPtr<Elem> side (elem->build_side(s));
00105 
00106             // Check the location of the side's midpoint.  Since
00107             // the square has straight sides, the midpoint is not
00108             // on the corner and thus it is uniquely on one of the
00109             // sides.
00110             Point side_midpoint= 0.5*( (*side->get_node(0)) + (*side->get_node(1)) );
00111 
00112             // The boundary ids are set following the same convention as Quad4 sides
00113             // bottom = 0
00114             // right  = 1
00115             // top = 2
00116             // left = 3
00117             // hole = 4
00118             short int bc_id=4;
00119 
00120             // bottom
00121             if      (std::fabs(side_midpoint(1) - ymin) < TOLERANCE)
00122               bc_id=0;
00123 
00124             // right
00125             else if (std::fabs(side_midpoint(0) - xmax) < TOLERANCE)
00126               bc_id=1;
00127 
00128             // top
00129             else if (std::fabs(side_midpoint(1) - ymax) < TOLERANCE)
00130               bc_id=2;
00131 
00132             // left
00133             else if (std::fabs(side_midpoint(0) - xmin) < TOLERANCE)
00134               bc_id=3;
00135 
00136             // If the point is not on any of the external boundaries, it
00137             // is on one of the holes....
00138             
00139             // Finally, add this element's information to the boundary info object.
00140             mesh.boundary_info->add_side(elem->id(), s, bc_id);
00141           }
00142     }
00143   
00144 }

void 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

Definition at line 1329 of file mesh_generation.C.

References build_cube().

01334 {
01335     // This method only makes sense in 1D!
01336     // But we now just turn a non-1D mesh into a 1D mesh
01337     //libmesh_assert(mesh.mesh_dimension() == 1);
01338 
01339     build_cube(mesh,
01340                nx, 0, 0,
01341                xmin, xmax,
01342                0., 0.,
01343                0., 0.,
01344                type,
01345                gauss_lobatto_grid);
01346 }

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

Meshes a spherical or mapped-spherical domain.

Definition at line 1381 of file mesh_generation.C.

01385 {
01386         std::cout << "Building a circle/sphere only works with AMR." << std::endl;
01387         libmesh_error();
01388 }

void 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.

Definition at line 1350 of file mesh_generation.C.

References build_cube().

01357 {
01358   // This method only makes sense in 2D!
01359   // But we now just turn a non-2D mesh into a 2D mesh
01360   //libmesh_assert (mesh.mesh_dimension() == 2);
01361 
01362   // Call the build_cube() member to actually do the work for us.
01363   build_cube (mesh,
01364               nx, ny, 0,
01365               xmin, xmax,
01366               ymin, ymax,
01367               0., 0.,
01368               type,
01369               gauss_lobatto_grid);
01370 }


Site Created By: libMesh Developers
Last modified: November 25 2009 03:45:16.

Hosted By:
SourceForge.net Logo