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.
- 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.
- 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().
Site Created By: libMesh Developers
Last modified: February 05 2013 19:55:44 UTC
Hosted By: