libMesh::MeshTools::Modification Namespace Reference

Functions

void distort (MeshBase &mesh, const Real factor, const bool perturb_boundary=false)
void translate (MeshBase &mesh, const Real xt=0., const Real yt=0., const Real zt=0.)
void rotate (MeshBase &mesh, const Real phi, const Real theta=0., const Real psi=0.)
void scale (MeshBase &mesh, const Real xs, const Real ys=0., const Real zs=0.)
void all_tri (MeshBase &mesh)
void smooth (MeshBase &, unsigned int, Real)
void flatten (MeshBase &mesh)
void change_boundary_id (MeshBase &mesh, const boundary_id_type old_id, const boundary_id_type new_id)
void change_subdomain_id (MeshBase &mesh, const subdomain_id_type old_id, const subdomain_id_type new_id)

Detailed Description

Tools for Mesh modification.

Author:
Benjamin S. Kirk
Date:
2004

Function Documentation

void libMesh::MeshTools::Modification::all_tri ( MeshBase &  mesh  ) 

Converts the 2D quadrilateral elements of a Mesh into triangular elements. Note: Only works for 2D elements! 3D elements are ignored. Note: Probably won't do the right thing for meshes which have been refined previously.

Definition at line 686 of file mesh_modification.C.

References libMesh::MeshBase::add_elem(), libMesh::MeshBase::add_point(), libMesh::MeshBase::boundary_info, libMesh::MeshBase::delete_elem(), libMesh::MeshBase::elements_begin(), libMesh::MeshBase::elements_end(), end, libMesh::Utility::enum_to_string< ElemType >(), libMesh::err, libMesh::Elem::get_node(), libMesh::DofObject::id(), libMesh::BoundaryInfo::invalid_id, libMesh::MeshBase::n_elem(), libMesh::Elem::n_sides(), libMesh::Elem::neighbor(), libMesh::Elem::node(), libMesh::MeshBase::node(), libMesh::Elem::parent(), libMesh::Elem::point(), libMesh::MeshBase::prepare_for_use(), libMesh::DofObject::processor_id(), libMeshEnums::QUAD4, libMeshEnums::QUAD8, libMeshEnums::QUAD9, libMesh::remote_elem, libMesh::DofObject::set_id(), libMesh::Elem::set_neighbor(), libMesh::Elem::set_node(), libMesh::Elem::subdomain_id(), libMeshEnums::TRI3, libMeshEnums::TRI6, and libMesh::Elem::type().

00687 {
00688   // The number of elements in the original mesh before any additions
00689   // or deletions.
00690   const dof_id_type n_orig_elem = mesh.n_elem();
00691 
00692   // We store pointers to the newly created elements in a vector
00693   // until they are ready to be added to the mesh.  This is because
00694   // adding new elements on the fly can cause reallocation and invalidation
00695   // of existing iterators.
00696   std::vector<Elem*> new_elements;
00697   new_elements.reserve (2*n_orig_elem);
00698 
00699   // If the original mesh has boundary data, we carry that over
00700   // to the new mesh with triangular elements.
00701   const bool mesh_has_boundary_data = (mesh.boundary_info->n_boundary_ids() > 0);
00702 
00703   // Temporary vectors to store the new boundary element pointers, side numbers, and boundary ids
00704   std::vector<Elem*> new_bndry_elements;
00705   std::vector<unsigned short int> new_bndry_sides;
00706   std::vector<boundary_id_type> new_bndry_ids;
00707 
00708   // Iterate over the elements, splitting QUADS into
00709   // pairs of conforming triangles.
00710   // FIXME: This algorithm does not work on refined grids!
00711   {
00712     MeshBase::element_iterator       el  = mesh.elements_begin();
00713     const MeshBase::element_iterator end = mesh.elements_end();
00714 
00715     for (; el!=end; ++el)
00716       {
00717         Elem* elem = *el;
00718 
00719         const ElemType etype = elem->type();
00720 
00721         // all_tri currently only works on coarse meshes
00722         libmesh_assert (!elem->parent());
00723 
00724         // We split the quads using the shorter of the two diagonals
00725         // to maintain the best angle properties.
00726         bool edge_swap = false;
00727 
00728         // True if we actually split the current element.
00729         bool split_elem = false;
00730 
00731         // The two new triangular elements we will split the quad into.
00732         Elem* tri0 = NULL;
00733         Elem* tri1 = NULL;
00734 
00735 
00736         switch (etype)
00737           {
00738           case QUAD4:
00739             {
00740               split_elem = true;
00741 
00742               tri0 = new Tri3;
00743               tri1 = new Tri3;
00744 
00745               // Check for possible edge swap
00746               if ((elem->point(0) - elem->point(2)).size() <
00747                   (elem->point(1) - elem->point(3)).size())
00748                 {
00749                   tri0->set_node(0) = elem->get_node(0);
00750                   tri0->set_node(1) = elem->get_node(1);
00751                   tri0->set_node(2) = elem->get_node(2);
00752 
00753                   tri1->set_node(0) = elem->get_node(0);
00754                   tri1->set_node(1) = elem->get_node(2);
00755                   tri1->set_node(2) = elem->get_node(3);
00756                 }
00757 
00758               else
00759                 {
00760                   edge_swap=true;
00761 
00762                   tri0->set_node(0) = elem->get_node(0);
00763                   tri0->set_node(1) = elem->get_node(1);
00764                   tri0->set_node(2) = elem->get_node(3);
00765 
00766                   tri1->set_node(0) = elem->get_node(1);
00767                   tri1->set_node(1) = elem->get_node(2);
00768                   tri1->set_node(2) = elem->get_node(3);
00769                 }
00770 
00771 
00772               break;
00773             }
00774 
00775           case QUAD8:
00776             {
00777               split_elem =  true;
00778 
00779               tri0 = new Tri6;
00780               tri1 = new Tri6;
00781 
00782               Node* new_node = mesh.add_point( (mesh.node(elem->node(0)) +
00783                                                 mesh.node(elem->node(1)) +
00784                                                 mesh.node(elem->node(2)) +
00785                                                 mesh.node(elem->node(3)) / 4)
00786                                                );
00787 
00788               // Check for possible edge swap
00789               if ((elem->point(0) - elem->point(2)).size() <
00790                   (elem->point(1) - elem->point(3)).size())
00791                 {
00792                   tri0->set_node(0) = elem->get_node(0);
00793                   tri0->set_node(1) = elem->get_node(1);
00794                   tri0->set_node(2) = elem->get_node(2);
00795                   tri0->set_node(3) = elem->get_node(4);
00796                   tri0->set_node(4) = elem->get_node(5);
00797                   tri0->set_node(5) = new_node;
00798 
00799                   tri1->set_node(0) = elem->get_node(0);
00800                   tri1->set_node(1) = elem->get_node(2);
00801                   tri1->set_node(2) = elem->get_node(3);
00802                   tri1->set_node(3) = new_node;
00803                   tri1->set_node(4) = elem->get_node(6);
00804                   tri1->set_node(5) = elem->get_node(7);
00805 
00806                 }
00807 
00808               else
00809                 {
00810                   edge_swap=true;
00811 
00812                   tri0->set_node(0) = elem->get_node(3);
00813                   tri0->set_node(1) = elem->get_node(0);
00814                   tri0->set_node(2) = elem->get_node(1);
00815                   tri0->set_node(3) = elem->get_node(7);
00816                   tri0->set_node(4) = elem->get_node(4);
00817                   tri0->set_node(5) = new_node;
00818 
00819                   tri1->set_node(0) = elem->get_node(1);
00820                   tri1->set_node(1) = elem->get_node(2);
00821                   tri1->set_node(2) = elem->get_node(3);
00822                   tri1->set_node(3) = elem->get_node(5);
00823                   tri1->set_node(4) = elem->get_node(6);
00824                   tri1->set_node(5) = new_node;
00825                 }
00826 
00827               break;
00828             }
00829 
00830           case QUAD9:
00831             {
00832               split_elem =  true;
00833 
00834               tri0 = new Tri6;
00835               tri1 = new Tri6;
00836 
00837               // Check for possible edge swap
00838               if ((elem->point(0) - elem->point(2)).size() <
00839                   (elem->point(1) - elem->point(3)).size())
00840                 {
00841                   tri0->set_node(0) = elem->get_node(0);
00842                   tri0->set_node(1) = elem->get_node(1);
00843                   tri0->set_node(2) = elem->get_node(2);
00844                   tri0->set_node(3) = elem->get_node(4);
00845                   tri0->set_node(4) = elem->get_node(5);
00846                   tri0->set_node(5) = elem->get_node(8);
00847 
00848                   tri1->set_node(0) = elem->get_node(0);
00849                   tri1->set_node(1) = elem->get_node(2);
00850                   tri1->set_node(2) = elem->get_node(3);
00851                   tri1->set_node(3) = elem->get_node(8);
00852                   tri1->set_node(4) = elem->get_node(6);
00853                   tri1->set_node(5) = elem->get_node(7);
00854                 }
00855 
00856               else
00857                 {
00858                   edge_swap=true;
00859 
00860                   tri0->set_node(0) = elem->get_node(0);
00861                   tri0->set_node(1) = elem->get_node(1);
00862                   tri0->set_node(2) = elem->get_node(3);
00863                   tri0->set_node(3) = elem->get_node(4);
00864                   tri0->set_node(4) = elem->get_node(8);
00865                   tri0->set_node(5) = elem->get_node(7);
00866 
00867                   tri1->set_node(0) = elem->get_node(1);
00868                   tri1->set_node(1) = elem->get_node(2);
00869                   tri1->set_node(2) = elem->get_node(3);
00870                   tri1->set_node(3) = elem->get_node(5);
00871                   tri1->set_node(4) = elem->get_node(6);
00872                   tri1->set_node(5) = elem->get_node(8);
00873                 }
00874 
00875               break;
00876             }
00877           // No need to split elements that are already triangles
00878           case TRI3:
00879           case TRI6:
00880             continue;
00881           // Try to ignore non-2D elements for now
00882           default:
00883             {
00884               libMesh::err << "Warning, encountered non-2D element "
00885                             << Utility::enum_to_string<ElemType>(etype)
00886                             << " in MeshTools::Modification::all_tri(), hope that's OK..."
00887                             << std::endl;
00888             }
00889           } // end switch (etype)
00890 
00891 
00892 
00893         if (split_elem)
00894           {
00895             // Be sure the correct ID's are also set for tri0 and
00896             // tri1.
00897             tri0->processor_id() = elem->processor_id();
00898             tri0->subdomain_id() = elem->subdomain_id();
00899             tri1->processor_id() = elem->processor_id();
00900             tri1->subdomain_id() = elem->subdomain_id();
00901 
00902             if (mesh_has_boundary_data)
00903               {
00904                 for (unsigned int sn=0; sn<elem->n_sides(); ++sn)
00905                   {
00906                     const std::vector<boundary_id_type>& bc_ids = mesh.boundary_info->boundary_ids(*el, sn);
00907                     for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it)
00908                       {
00909                         const boundary_id_type b_id = *id_it;
00910 
00911                         if (b_id != BoundaryInfo::invalid_id)
00912                           {
00913                             // Add the boundary ID to the list of new boundary ids
00914                             new_bndry_ids.push_back(b_id);
00915 
00916                             // Convert the boundary side information of the old element to
00917                             // boundary side information for the new element.
00918                             if (!edge_swap)
00919                               {
00920                                 switch (sn)
00921                                   {
00922                                   case 0:
00923                                     {
00924                                       // New boundary side is Tri 0, side 0
00925                                       new_bndry_elements.push_back(tri0);
00926                                       new_bndry_sides.push_back(0);
00927                                       break;
00928                                     }
00929                                   case 1:
00930                                     {
00931                                       // New boundary side is Tri 0, side 1
00932                                       new_bndry_elements.push_back(tri0);
00933                                       new_bndry_sides.push_back(1);
00934                                       break;
00935                                     }
00936                                   case 2:
00937                                     {
00938                                       // New boundary side is Tri 1, side 1
00939                                       new_bndry_elements.push_back(tri1);
00940                                       new_bndry_sides.push_back(1);
00941                                       break;
00942                                     }
00943                                   case 3:
00944                                     {
00945                                       // New boundary side is Tri 1, side 2
00946                                       new_bndry_elements.push_back(tri1);
00947                                       new_bndry_sides.push_back(2);
00948                                       break;
00949                                     }
00950 
00951                                   default:
00952                                     {
00953                                       libMesh::err << "Quad4/8/9 cannot have more than 4 sides." << std::endl;
00954                                       libmesh_error();
00955                                     }
00956                                   }
00957                               }
00958 
00959                             else // edge_swap==true
00960                               {
00961                                 switch (sn)
00962                                   {
00963                                   case 0:
00964                                     {
00965                                       // New boundary side is Tri 0, side 0
00966                                       new_bndry_elements.push_back(tri0);
00967                                       new_bndry_sides.push_back(0);
00968                                       break;
00969                                     }
00970                                   case 1:
00971                                     {
00972                                       // New boundary side is Tri 1, side 0
00973                                       new_bndry_elements.push_back(tri1);
00974                                       new_bndry_sides.push_back(0);
00975                                       break;
00976                                     }
00977                                   case 2:
00978                                     {
00979                                       // New boundary side is Tri 1, side 1
00980                                       new_bndry_elements.push_back(tri1);
00981                                       new_bndry_sides.push_back(1);
00982                                       break;
00983                                     }
00984                                   case 3:
00985                                     {
00986                                       // New boundary side is Tri 0, side 2
00987                                       new_bndry_elements.push_back(tri0);
00988                                       new_bndry_sides.push_back(2);
00989                                       break;
00990                                     }
00991 
00992                                   default:
00993                                     {
00994                                       libMesh::err << "Quad4/8/9 cannot have more than 4 sides." << std::endl;
00995                                       libmesh_error();
00996                                     }
00997                                   }
00998                               } // end edge_swap==true
00999                           } // end if (b_id != BoundaryInfo::invalid_id)
01000                       } // end for loop over boundary IDs
01001                   } // end for loop over sides
01002 
01003                 // Remove the original element from the BoundaryInfo structure.
01004                 mesh.boundary_info->remove(elem);
01005 
01006               } // end if (mesh_has_boundary_data)
01007 
01008 
01009             // On a distributed mesh, we need to preserve remote_elem
01010             // links, since prepare_for_use can't reconstruct them for
01011             // us.
01012             for (unsigned int sn=0; sn<elem->n_sides(); ++sn)
01013               {
01014                 if (elem->neighbor(sn) == remote_elem)
01015                   {
01016                     // Create a remote_elem link on one of the new
01017                     // elements corresponding to the link from the old
01018                     // element.
01019                     if (!edge_swap)
01020                       {
01021                         switch (sn)
01022                               {
01023                               case 0:
01024                                 {
01025                                   // New remote side is Tri 0, side 0
01026                                   tri0->set_neighbor(0, const_cast<RemoteElem*>(remote_elem));
01027                                   break;
01028                                 }
01029                               case 1:
01030                                 {
01031                                   // New remote side is Tri 0, side 1
01032                                   tri0->set_neighbor(1, const_cast<RemoteElem*>(remote_elem));
01033                                   break;
01034                                 }
01035                               case 2:
01036                                 {
01037                                   // New remote side is Tri 1, side 1
01038                                   tri1->set_neighbor(1, const_cast<RemoteElem*>(remote_elem));
01039                                   break;
01040                                 }
01041                               case 3:
01042                                 {
01043                                   // New remote side is Tri 1, side 2
01044                                   tri1->set_neighbor(2, const_cast<RemoteElem*>(remote_elem));
01045                                   break;
01046                                 }
01047 
01048                               default:
01049                                 {
01050                                   libMesh::err << "Quad4/8/9 cannot have more than 4 sides." << std::endl;
01051                                   libmesh_error();
01052                                 }
01053                               }
01054                           }
01055 
01056                         else // edge_swap==true
01057                           {
01058                             switch (sn)
01059                               {
01060                               case 0:
01061                                 {
01062                                   // New remote side is Tri 0, side 0
01063                                   tri0->set_neighbor(0, const_cast<RemoteElem*>(remote_elem));
01064                                   break;
01065                                 }
01066                               case 1:
01067                                 {
01068                                   // New remote side is Tri 1, side 0
01069                                   tri1->set_neighbor(0, const_cast<RemoteElem*>(remote_elem));
01070                                   break;
01071                                 }
01072                               case 2:
01073                                 {
01074                                   // New remote side is Tri 1, side 1
01075                                   tri1->set_neighbor(1, const_cast<RemoteElem*>(remote_elem));
01076                                   break;
01077                                 }
01078                               case 3:
01079                                 {
01080                                   // New remote side is Tri 0, side 2
01081                                   tri0->set_neighbor(2, const_cast<RemoteElem*>(remote_elem));
01082                                   break;
01083                                 }
01084 
01085                               default:
01086                                 {
01087                                   libMesh::err << "Quad4/8/9 cannot have more than 4 sides." << std::endl;
01088                                   libmesh_error();
01089                                 }
01090                               }
01091                           } // end edge_swap==true
01092                       } // end if (elem->neighbor(sn) == remote_elem)
01093               } // end for loop over sides
01094 
01095             // Determine new IDs for the split elements which will be
01096             // the same on all processors, therefore keeping the Mesh
01097             // in sync.  Note: we offset the new IDs by n_orig_elem to
01098             // avoid overwriting any of the original IDs, this assumes
01099             // they were contiguously-numbered to begin with...
01100             tri0->set_id( n_orig_elem + 2*elem->id() + 0 );
01101             tri1->set_id( n_orig_elem + 2*elem->id() + 1 );
01102 
01103             // Add the newly-created triangles to the temporary vector of new elements.
01104             new_elements.push_back(tri0);
01105             new_elements.push_back(tri1);
01106 
01107             // Delete the original element
01108             mesh.delete_elem(elem);
01109           } // end if (split_elem)
01110       } // End for loop over elements
01111   } // end scope
01112 
01113 
01114   // Now, iterate over the new elements vector, and add them each to
01115   // the Mesh.
01116   {
01117     std::vector<Elem*>::iterator el        = new_elements.begin();
01118     const std::vector<Elem*>::iterator end = new_elements.end();
01119     for (; el != end; ++el)
01120       mesh.add_elem(*el);
01121   }
01122 
01123   if (mesh_has_boundary_data)
01124     {
01125       // By this time, we should have removed all of the original boundary sides
01126       // - except on a hybrid mesh, where we can't "start from a blank slate"! - RHS
01127       // libmesh_assert_equal_to (mesh.boundary_info->n_boundary_conds(), 0);
01128 
01129       // Clear the boundary info, to be sure and start from a blank slate.
01130       // mesh.boundary_info->clear();
01131 
01132       // If the old mesh had boundary data, the new mesh better have some.
01133       libmesh_assert_greater (new_bndry_elements.size(), 0);
01134 
01135       // We should also be sure that the lengths of the new boundary data vectors
01136       // are all the same.
01137       libmesh_assert_equal_to (new_bndry_elements.size(), new_bndry_sides.size());
01138       libmesh_assert_equal_to (new_bndry_sides.size(), new_bndry_ids.size());
01139 
01140       // Add the new boundary info to the mesh
01141       for (unsigned int s=0; s<new_bndry_elements.size(); ++s)
01142         mesh.boundary_info->add_side(new_bndry_elements[s],
01143                                      new_bndry_sides[s],
01144                                      new_bndry_ids[s]);
01145     }
01146 
01147 
01148   // Prepare the newly created mesh for use.
01149   mesh.prepare_for_use(/*skip_renumber =*/ false);
01150 
01151   // Let the new_elements and new_bndry_elements vectors go out of scope.
01152 }

void libMesh::MeshTools::Modification::change_boundary_id ( MeshBase &  mesh,
const boundary_id_type  old_id,
const boundary_id_type  new_id 
)

Finds any boundary ids that are currently old_id, changes them to new_id

Definition at line 1463 of file mesh_modification.C.

References libMesh::MeshBase::boundary_info, libMesh::MeshBase::level_elements_begin(), libMesh::MeshBase::level_elements_end(), and libMesh::Elem::n_sides().

01466 {
01467   // Only level-0 elements store BCs.  Loop over them.
01468   MeshBase::element_iterator           el = mesh.level_elements_begin(0);
01469   const MeshBase::element_iterator end_el = mesh.level_elements_end(0);
01470   for (; el != end_el; ++el)
01471     {
01472       Elem *elem = *el;
01473       unsigned int n_sides = elem->n_sides();
01474       for (unsigned int s=0; s != n_sides; ++s)
01475         {
01476           const std::vector<boundary_id_type>& old_ids = mesh.boundary_info->boundary_ids(elem, s);
01477           if (std::find(old_ids.begin(), old_ids.end(), old_id) != old_ids.end())
01478             {
01479               std::vector<boundary_id_type> new_ids(old_ids);
01480               std::replace(new_ids.begin(), new_ids.end(), old_id, new_id);
01481               mesh.boundary_info->remove_side(elem, s);
01482               mesh.boundary_info->add_side(elem, s, new_ids);
01483             }
01484         }
01485     }
01486 }

void libMesh::MeshTools::Modification::change_subdomain_id ( MeshBase &  mesh,
const subdomain_id_type  old_id,
const subdomain_id_type  new_id 
)

Finds any subdomain ids that are currently old_id, changes them to new_id

Definition at line 1490 of file mesh_modification.C.

References libMesh::MeshBase::elements_begin(), libMesh::MeshBase::elements_end(), and libMesh::Elem::subdomain_id().

01493 {
01494   MeshBase::element_iterator           el = mesh.elements_begin();
01495   const MeshBase::element_iterator end_el = mesh.elements_end();
01496 
01497   for (; el != end_el; ++el)
01498     {
01499       Elem *elem = *el;
01500 
01501       if (elem->subdomain_id() == old_id)
01502         elem->subdomain_id() = new_id;
01503     }
01504 }

void libMesh::MeshTools::Modification::distort ( MeshBase &  mesh,
const Real  factor,
const bool  perturb_boundary = false 
)

Randomly perturb the nodal locations. This function will move each node factor fraction of its minimum neighboring node separation distance. Nodes on the boundary are not moved by default, however they may be by setting the flag perturb_boundary true.

Definition at line 47 of file mesh_modification.C.

References libMesh::MeshBase::active_elements_begin(), libMesh::MeshBase::active_elements_end(), end, libMesh::MeshTools::find_boundary_nodes(), std::max(), libMesh::MeshBase::mesh_dimension(), std::min(), libMesh::MeshBase::n_elem(), libMesh::MeshBase::n_nodes(), libMesh::MeshBase::node_ptr(), and libMesh::TypeVector< T >::unit().

00050 {
00051   libmesh_assert (mesh.n_nodes());
00052   libmesh_assert (mesh.n_elem());
00053   libmesh_assert ((factor >= 0.) && (factor <= 1.));
00054 
00055   START_LOG("distort()", "MeshTools::Modification");
00056 
00057 
00058 
00059   // First find nodes on the boundary and flag them
00060   // so that we don't move them
00061   // on_boundary holds false (not on boundary) and true (on boundary)
00062   std::vector<bool> on_boundary (mesh.n_nodes(), false);
00063 
00064   if (!perturb_boundary) MeshTools::find_boundary_nodes (mesh, on_boundary);
00065 
00066   // Now calculate the minimum distance to
00067   // neighboring nodes for each node.
00068   // hmin holds these distances.
00069   std::vector<float> hmin (mesh.n_nodes(),
00070                            std::numeric_limits<float>::max());
00071 
00072   MeshBase::element_iterator       el  = mesh.active_elements_begin();
00073   const MeshBase::element_iterator end = mesh.active_elements_end();
00074 
00075   for (; el!=end; ++el)
00076     for (unsigned int n=0; n<(*el)->n_nodes(); n++)
00077       hmin[(*el)->node(n)] = std::min(hmin[(*el)->node(n)],
00078                                       static_cast<float>((*el)->hmin()));
00079 
00080 
00081   // Now actually move the nodes
00082   {
00083     const unsigned int seed = 123456;
00084 
00085     // seed the random number generator.
00086     // We'll loop from 1 to n_nodes on every processor, even those
00087     // that don't have a particular node, so that the pseudorandom
00088     // numbers will be the same everywhere.
00089     std::srand(seed);
00090 
00091     // If the node is on the boundary or
00092     // the node is not used by any element (hmin[n]<1.e20)
00093     // then we should not move it.
00094     // [Note: Testing for (in)equality might be wrong
00095     // (different types, namely float and double)]
00096     for (unsigned int n=0; n<mesh.n_nodes(); n++)
00097       if (!on_boundary[n] && (hmin[n] < 1.e20) )
00098         {
00099           // the direction, random but unit normalized
00100 
00101           Point dir( static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX),
00102                      (mesh.mesh_dimension() > 1) ?
00103                      static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX)
00104                      : 0.,
00105                      ((mesh.mesh_dimension() == 3) ?
00106                       static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX)
00107                       : 0.)
00108                      );
00109 
00110           dir(0) = (dir(0)-.5)*2.;
00111           if (mesh.mesh_dimension() > 1)
00112             dir(1) = (dir(1)-.5)*2.;
00113           if (mesh.mesh_dimension() == 3)
00114             dir(2) = (dir(2)-.5)*2.;
00115 
00116           dir = dir.unit();
00117 
00118           Node *node = mesh.node_ptr(n);
00119           if (!node)
00120             continue;
00121 
00122           (*node)(0) += dir(0)*factor*hmin[n];
00123           if (mesh.mesh_dimension() > 1)
00124             (*node)(1) += dir(1)*factor*hmin[n];
00125           if (mesh.mesh_dimension() == 3)
00126             (*node)(2) += dir(2)*factor*hmin[n];
00127         }
00128   }
00129 
00130 
00131   // All done
00132   STOP_LOG("distort()", "MeshTools::Modification");
00133 }

void libMesh::MeshTools::Modification::flatten ( MeshBase &  mesh  ) 

Removes all the refinement tree structure of Mesh, leaving only the highest-level (most-refined) elements. This is useful when you want to write out a uniformly-refined grid to be treated later as an initial mesh. Note that many functions in LibMesh assume a conforming (with no hanging nodes) grid exists at some level, so you probably only want to do this on meshes which have been uniformly refined.

Definition at line 1337 of file mesh_modification.C.

References libMesh::MeshBase::active_elements_begin(), libMesh::MeshBase::active_elements_end(), libMesh::MeshBase::add_elem(), bc_id, libMesh::MeshBase::boundary_info, libMesh::Elem::build(), libMesh::MeshBase::delete_elem(), libMesh::MeshBase::elements_begin(), libMesh::MeshBase::elements_end(), end, libMesh::Elem::get_node(), libMesh::DofObject::id(), libMesh::BoundaryInfo::invalid_id, libMesh::MeshBase::n_active_elem(), libMesh::Elem::n_nodes(), libMesh::Elem::n_sides(), libMesh::Elem::neighbor(), libMesh::MeshBase::prepare_for_use(), libMesh::DofObject::processor_id(), libMesh::remote_elem, libMesh::DofObject::set_id(), libMesh::Elem::set_neighbor(), libMesh::Elem::set_node(), libMesh::Elem::subdomain_id(), and libMesh::Elem::type().

01338 {
01339   // Algorithm:
01340   // .) For each active element in the mesh: construct a
01341   //    copy which is the same in every way *except* it is
01342   //    a level 0 element.  Store the pointers to these in
01343   //    a separate vector. Save any boundary information as well.
01344   //    Delete the active element from the mesh.
01345   // .) Loop over all (remaining) elements in the mesh, delete them.
01346   // .) Add the level-0 copies back to the mesh
01347 
01348   // Temporary storage for new element pointers
01349   std::vector<Elem*> new_elements;
01350 
01351   // BoundaryInfo Storage for element ids, sides, and BC ids
01352   std::vector<Elem*>              saved_boundary_elements;
01353   std::vector<boundary_id_type>   saved_bc_ids;
01354   std::vector<unsigned short int> saved_bc_sides;
01355 
01356   // Reserve a reasonable amt. of space for each
01357   new_elements.reserve(mesh.n_active_elem());
01358   saved_boundary_elements.reserve(mesh.boundary_info->n_boundary_conds());
01359   saved_bc_ids.reserve(mesh.boundary_info->n_boundary_conds());
01360   saved_bc_sides.reserve(mesh.boundary_info->n_boundary_conds());
01361   {
01362     MeshBase::element_iterator       it  = mesh.active_elements_begin();
01363     const MeshBase::element_iterator end = mesh.active_elements_end();
01364 
01365     for (; it != end; ++it)
01366       {
01367         Elem* elem = *it;
01368 
01369         // Make a new element of the same type
01370         Elem* copy = Elem::build(elem->type()).release();
01371 
01372         // Set node pointers (they still point to nodes in the original mesh)
01373         for(unsigned int n=0; n<elem->n_nodes(); n++)
01374           copy->set_node(n) = elem->get_node(n);
01375 
01376         // Copy over ids
01377         copy->processor_id() = elem->processor_id();
01378         copy->subdomain_id() = elem->subdomain_id();
01379 
01380         // Retain the original element's ID as well, otherwise ParallelMesh will
01381         // try to create one for you...
01382         copy->set_id( elem->id() );
01383 
01384         // This element could have boundary info or ParallelMesh
01385         // remote_elem links as well.  We need to save the (elem,
01386         // side, bc_id) triples and those links
01387         for (unsigned int s=0; s<elem->n_sides(); s++)
01388           {
01389             if (elem->neighbor(s) == remote_elem)
01390               copy->set_neighbor(s, const_cast<RemoteElem*>(remote_elem));
01391 
01392             const std::vector<boundary_id_type>& bc_ids = mesh.boundary_info->boundary_ids(elem,s);
01393             for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it)
01394               {
01395                 const boundary_id_type bc_id = *id_it;
01396 
01397                 if (bc_id != BoundaryInfo::invalid_id)
01398                   {
01399                     saved_boundary_elements.push_back(copy);
01400                     saved_bc_ids.push_back(bc_id);
01401                     saved_bc_sides.push_back(s);
01402                   }
01403               }
01404           }
01405 
01406 
01407         // We're done with this element
01408         mesh.delete_elem(elem);
01409 
01410         // But save the copy
01411         new_elements.push_back(copy);
01412       }
01413 
01414     // Make sure we saved the same number of boundary conditions
01415     // in each vector.
01416     libmesh_assert_equal_to (saved_boundary_elements.size(), saved_bc_ids.size());
01417     libmesh_assert_equal_to (saved_bc_ids.size(), saved_bc_sides.size());
01418   }
01419 
01420 
01421   // Loop again, delete any remaining elements
01422   {
01423     MeshBase::element_iterator       it  = mesh.elements_begin();
01424     const MeshBase::element_iterator end = mesh.elements_end();
01425 
01426     for (; it != end; ++it)
01427       mesh.delete_elem( *it );
01428   }
01429 
01430 
01431   // Add the copied (now level-0) elements back to the mesh
01432   {
01433     for (std::vector<Elem*>::iterator it = new_elements.begin();
01434          it != new_elements.end();
01435          ++it)
01436       {
01437         dof_id_type orig_id = (*it)->id();
01438 
01439         Elem* added_elem = mesh.add_elem(*it);
01440 
01441         dof_id_type added_id = added_elem->id();
01442 
01443         // If the Elem, as it was re-added to the mesh, now has a
01444         // different ID (this is unlikely, so it's just an assert)
01445         // the boundary information will no longer be correct.
01446         libmesh_assert_equal_to (orig_id, added_id);
01447       }
01448   }
01449 
01450   // Finally, also add back the saved boundary information
01451   for (unsigned int e=0; e<saved_boundary_elements.size(); ++e)
01452     mesh.boundary_info->add_side(saved_boundary_elements[e],
01453                                  saved_bc_sides[e],
01454                                  saved_bc_ids[e]);
01455 
01456   // Trim unused and renumber nodes and elements
01457   mesh.prepare_for_use(/*skip_renumber =*/ false);
01458 }

void libMesh::MeshTools::Modification::rotate ( MeshBase &  mesh,
const Real  phi,
const Real  theta = 0.,
const Real  psi = 0. 
)

Rotates the mesh in the xy plane. The rotation is counter-clock-wise (mathematical definition). The angle is in degrees (360 make a full circle) Rotates the mesh in 3D space. Here the standard Euler angles are adopted (http://mathworld.wolfram.com/EulerAngles.html) The angles are in degrees (360 make a full circle)

Definition at line 174 of file mesh_modification.C.

References libMesh::MeshBase::mesh_dimension(), libMesh::MeshBase::nodes_begin(), libMesh::MeshBase::nodes_end(), libMesh::pi, and libMesh::Real.

00178 {
00179   libmesh_assert_not_equal_to (mesh.mesh_dimension(), 1);
00180 
00181   const Real  p = -phi/180.*libMesh::pi;
00182   const Real  t = -theta/180.*libMesh::pi;
00183   const Real  s = -psi/180.*libMesh::pi;
00184   const Real sp = std::sin(p), cp = std::cos(p);
00185   const Real st = std::sin(t), ct = std::cos(t);
00186   const Real ss = std::sin(s), cs = std::cos(s);
00187 
00188   // We follow the convention described at http://mathworld.wolfram.com/EulerAngles.html
00189   // (equations 6-14 give the entries of the composite transformation matrix).
00190   // The rotations are performed sequentially about the z, x, and z axes, in that order.
00191   // A positive angle yields a counter-clockwise rotation about the axis in question.
00192   const MeshBase::node_iterator nd_end = mesh.nodes_end();
00193 
00194   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00195        nd != nd_end; ++nd)
00196     {
00197       const Point pt = **nd;
00198       const Real  x  = pt(0);
00199       const Real  y  = pt(1);
00200       const Real  z  = pt(2);
00201       **nd = Point(( cp*cs-sp*ct*ss)*x + ( sp*cs+cp*ct*ss)*y + (st*ss)*z,
00202                    (-cp*ss-sp*ct*cs)*x + (-sp*ss+cp*ct*cs)*y + (st*cs)*z,
00203                    ( sp*st)*x          + (-cp*st)*y          + (ct)*z   );
00204     }
00205 }

void libMesh::MeshTools::Modification::scale ( MeshBase &  mesh,
const Real  xs,
const Real  ys = 0.,
const Real  zs = 0. 
)

Scales the mesh. The grid points are scaled in the x direction by xs, in the y direction by ys, etc... If only xs is specified then the scaling is assumed uniform in all directions.

Definition at line 208 of file mesh_modification.C.

References libMesh::MeshBase::nodes_begin(), libMesh::MeshBase::nodes_end(), libMesh::Real, and libMesh::MeshBase::spatial_dimension().

00212 {
00213   const Real x_scale = xs;
00214   Real y_scale       = ys;
00215   Real z_scale       = zs;
00216 
00217   if (ys == 0.)
00218     {
00219       libmesh_assert_equal_to (zs, 0.);
00220 
00221       y_scale = z_scale = x_scale;
00222     }
00223 
00224   // Scale the x coordinate in all dimensions
00225   const MeshBase::node_iterator nd_end = mesh.nodes_end();
00226 
00227   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00228        nd != nd_end; ++nd)
00229     (**nd)(0) *= x_scale;
00230 
00231 
00232   // Only scale the y coordinate in 2 and 3D
00233   if (mesh.spatial_dimension() < 2)
00234     return;
00235 
00236   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00237        nd != nd_end; ++nd)
00238     (**nd)(1) *= y_scale;
00239 
00240   // Only scale the z coordinate in 3D
00241   if (mesh.spatial_dimension() < 3)
00242     return;
00243 
00244   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00245        nd != nd_end; ++nd)
00246     (**nd)(2) *= z_scale;
00247 }

void libMesh::MeshTools::Modification::smooth ( MeshBase &  mesh,
unsigned int  n_iterations,
Real  power 
)

Smooth the mesh with a simple Laplace smoothing algorithm. The mesh is smoothed n_iterations times. If the parameter power is 0, each node is moved to the average postition of the neighboring connected nodes. If power > 0, the node positions are weighted by their distance. The positions of higher order nodes, and nodes living in refined elements, are calculated from the vertex positions of their parent nodes. Only works in 2D.

Author:
Martin Lüthi (luthi@gi.alaska.edu)
Date:
2005

This implementation assumes every element "side" has only 2 nodes.

Definition at line 1155 of file mesh_modification.C.

References libMesh::TypeVector< T >::add(), libMesh::TypeVector< T >::add_scaled(), libMesh::Elem::build_side(), libMesh::Elem::child(), libMesh::Elem::embedding_matrix(), end, libMesh::MeshTools::find_boundary_nodes(), libMesh::Elem::get_node(), libMesh::DofObject::id(), libMesh::MeshBase::level_elements_begin(), libMesh::MeshBase::level_elements_end(), libMesh::MeshBase::mesh_dimension(), libMesh::Elem::n_children(), libMesh::MeshTools::n_levels(), libMesh::Elem::n_neighbors(), libMesh::Elem::n_nodes(), libMesh::MeshBase::n_nodes(), libMesh::Elem::n_second_order_adjacent_vertices(), libMesh::Elem::n_vertices(), libMesh::Elem::neighbor(), libMesh::MeshBase::node(), libMesh::Elem::parent(), libMesh::Elem::point(), std::pow(), libMesh::Real, libMesh::Elem::second_order_adjacent_vertex(), side, libMesh::TypeVector< T >::size(), and libMesh::MeshTools::weight().

01158 {
01162   libmesh_assert_equal_to (mesh.mesh_dimension(), 2);
01163 
01164   /*
01165    * find the boundary nodes
01166    */
01167   std::vector<bool>  on_boundary;
01168   MeshTools::find_boundary_nodes(mesh, on_boundary);
01169 
01170   for (unsigned int iter=0; iter<n_iterations; iter++)
01171 
01172     {
01173       /*
01174        * loop over the mesh refinement level
01175        */
01176       unsigned int n_levels = MeshTools::n_levels(mesh);
01177       for (unsigned int refinement_level=0; refinement_level != n_levels;
01178            refinement_level++)
01179         {
01180           // initialize the storage (have to do it on every level to get empty vectors
01181           std::vector<Point> new_positions;
01182           std::vector<Real>   weight;
01183           new_positions.resize(mesh.n_nodes());
01184           weight.resize(mesh.n_nodes());
01185 
01186           {
01187             /*
01188              * Loop over the elements to calculate new node positions
01189              */
01190             MeshBase::element_iterator       el  = mesh.level_elements_begin(refinement_level);
01191             const MeshBase::element_iterator end = mesh.level_elements_end(refinement_level);
01192 
01193             for (; el != end; ++el)
01194               {
01195                 /*
01196                  * Constant handle for the element
01197                  */
01198                 const Elem* elem = *el;
01199 
01200                 /*
01201                  * We relax all nodes on level 0 first
01202                  * If the element is refined (level > 0), we interpolate the
01203                  * parents nodes with help of the embedding matrix
01204                  */
01205                 if (refinement_level == 0)
01206                   {
01207                     for (unsigned int s=0; s<elem->n_neighbors(); s++)
01208                       {
01209                         /*
01210                          * Only operate on sides which are on the
01211                          * boundary or for which the current element's
01212                          * id is greater than its neighbor's.
01213                          * Sides get only built once.
01214                          */
01215                         if ((elem->neighbor(s) != NULL) &&
01216                             (elem->id() > elem->neighbor(s)->id()) )
01217                           {
01218                             AutoPtr<Elem> side(elem->build_side(s));
01219 
01220                             Node* node0 = side->get_node(0);
01221                             Node* node1 = side->get_node(1);
01222 
01223                             Real node_weight = 1.;
01224                             // calculate the weight of the nodes
01225                             if (power > 0)
01226                               {
01227                                 Point diff = (*node0)-(*node1);
01228                                 node_weight = std::pow( diff.size(), power );
01229                               }
01230 
01231                             const dof_id_type id0 = node0->id(), id1 = node1->id();
01232                             new_positions[id0].add_scaled( *node1, node_weight );
01233                             new_positions[id1].add_scaled( *node0, node_weight );
01234                             weight[id0] += node_weight;
01235                             weight[id1] += node_weight;
01236                           }
01237                       } // element neighbor loop
01238                   }
01239 #ifdef LIBMESH_ENABLE_AMR
01240                 else   // refinement_level > 0
01241                   {
01242                     /*
01243                      * Find the positions of the hanging nodes of refined elements.
01244                      * We do this by calculating their position based on the parent
01245                      * (one level less refined) element, and the embedding matrix
01246                      */
01247 
01248                     const Elem* parent = elem->parent();
01249 
01250                     /*
01251                      * find out which child I am
01252                      */
01253                     for (unsigned int c=0; c < parent->n_children(); c++)
01254                       {
01255                         if (parent->child(c) == elem)
01256                           {
01257                             /*
01258                              *loop over the childs (that is, the current elements) nodes
01259                              */
01260                             for (unsigned int nc=0; nc < elem->n_nodes(); nc++)
01261                               {
01262                                 /*
01263                                  * the new position of the node
01264                                  */
01265                                 Point point;
01266                                 for (unsigned int n=0; n<parent->n_nodes(); n++)
01267                                   {
01268                                     /*
01269                                      * The value from the embedding matrix
01270                                      */
01271                                     const float em_val = parent->embedding_matrix(c,nc,n);
01272 
01273                                     if (em_val != 0.)
01274                                       point.add_scaled (parent->point(n), em_val);
01275                                   }
01276 
01277                                 const dof_id_type id = elem->get_node(nc)->id();
01278                                 new_positions[id] = point;
01279                                 weight[id] = 1.;
01280                               }
01281 
01282                           } // if parent->child == elem
01283                       } // for parent->n_children
01284                   } // if element refinement_level
01285 #endif // #ifdef LIBMESH_ENABLE_AMR
01286 
01287               } // element loop
01288 
01289             /*
01290              * finally reposition the vertex nodes
01291              */
01292             for (unsigned int nid=0; nid<mesh.n_nodes(); ++nid)
01293               if (!on_boundary[nid] && weight[nid] > 0.)
01294                 mesh.node(nid) = new_positions[nid]/weight[nid];
01295           }
01296 
01297           {
01298             /*
01299              * Now handle the additional second_order nodes by calculating
01300              * their position based on the vertex postitions
01301              * we do a second loop over the level elements
01302              */
01303             MeshBase::element_iterator       el  = mesh.level_elements_begin(refinement_level);
01304             const MeshBase::element_iterator end = mesh.level_elements_end(refinement_level);
01305 
01306             for (; el != end; ++el)
01307               {
01308                 /*
01309                  * Constant handle for the element
01310                  */
01311                 const Elem* elem = *el;
01312                 const unsigned int son_begin = elem->n_vertices();
01313                 const unsigned int son_end   = elem->n_nodes();
01314                 for (unsigned int n=son_begin; n<son_end; n++)
01315                   {
01316                     const unsigned int n_adjacent_vertices =
01317                       elem->n_second_order_adjacent_vertices(n);
01318 
01319                     Point point;
01320                     for (unsigned int v=0; v<n_adjacent_vertices; v++)
01321                       point.add(elem->point( elem->second_order_adjacent_vertex(n,v) ));
01322 
01323                     const dof_id_type id = elem->get_node(n)->id();
01324                     mesh.node(id) = point/n_adjacent_vertices;
01325                   }
01326               }
01327           }
01328 
01329         } // refinement_level loop
01330 
01331     } // end iteration
01332 }

void libMesh::MeshTools::Modification::translate ( MeshBase &  mesh,
const Real  xt = 0.,
const Real  yt = 0.,
const Real  zt = 0. 
)

Translates the mesh. The grid points are translated in the x direction by xt, in the y direction by yt, etc...

Definition at line 137 of file mesh_modification.C.

References libMesh::MeshBase::nodes_begin(), and libMesh::MeshBase::nodes_end().

00141 {
00142   const Point p(xt, yt, zt);
00143 
00144   const MeshBase::node_iterator nd_end = mesh.nodes_end();
00145 
00146   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00147        nd != nd_end; ++nd)
00148     **nd += p;
00149 }


Site Created By: libMesh Developers
Last modified: February 05 2013 19:55:44 UTC

Hosted By:
SourceForge.net Logo