$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 // C++ includes 00019 00020 // Local includes 00021 #include "libmesh/side.h" 00022 #include "libmesh/edge_edge2.h" 00023 #include "libmesh/face_quad4.h" 00024 00025 namespace libMesh 00026 { 00027 00028 00029 00030 00031 // ------------------------------------------------------------ 00032 // Quad class static member initialization 00033 const unsigned int Quad4::side_nodes_map[4][2] = 00034 { 00035 {0, 1}, // Side 0 00036 {1, 2}, // Side 1 00037 {2, 3}, // Side 2 00038 {3, 0} // Side 3 00039 }; 00040 00041 00042 #ifdef LIBMESH_ENABLE_AMR 00043 00044 const float Quad4::_embedding_matrix[4][4][4] = 00045 { 00046 // embedding matrix for child 0 00047 { 00048 // 0 1 2 3 00049 {1.0, 0.0, 0.0, 0.0}, // 0 00050 {0.5, 0.5, 0.0, 0.0}, // 1 00051 {.25, .25, .25, .25}, // 2 00052 {0.5, 0.0, 0.0, 0.5} // 3 00053 }, 00054 00055 // embedding matrix for child 1 00056 { 00057 // 0 1 2 3 00058 {0.5, 0.5, 0.0, 0.0}, // 0 00059 {0.0, 1.0, 0.0, 0.0}, // 1 00060 {0.0, 0.5, 0.5, 0.0}, // 2 00061 {.25, .25, .25, .25} // 3 00062 }, 00063 00064 // embedding matrix for child 2 00065 { 00066 // 0 1 2 3 00067 {0.5, 0.0, 0.0, 0.5}, // 0 00068 {.25, .25, .25, .25}, // 1 00069 {0.0, 0.0, 0.5, 0.5}, // 2 00070 {0.0, 0.0, 0.0, 1.0} // 3 00071 }, 00072 00073 // embedding matrix for child 3 00074 { 00075 // 0 1 2 3 00076 {.25, .25, .25, .25}, // 0 00077 {0.0, 0.5, 0.5, 0.0}, // 1 00078 {0.0, 0.0, 1.0, 0.0}, // 2 00079 {0.0, 0.0, 0.5, 0.5} // 3 00080 } 00081 }; 00082 00083 #endif 00084 00085 00086 00087 00088 00089 // ------------------------------------------------------------ 00090 // Quad4 class member functions 00091 00092 bool Quad4::is_vertex(const unsigned int) const 00093 { 00094 return true; 00095 } 00096 00097 bool Quad4::is_edge(const unsigned int) const 00098 { 00099 return false; 00100 } 00101 00102 bool Quad4::is_face(const unsigned int) const 00103 { 00104 return false; 00105 } 00106 00107 bool Quad4::is_node_on_side(const unsigned int n, 00108 const unsigned int s) const 00109 { 00110 libmesh_assert_less (s, n_sides()); 00111 for (unsigned int i = 0; i != 2; ++i) 00112 if (side_nodes_map[s][i] == n) 00113 return true; 00114 return false; 00115 } 00116 00117 00118 00119 bool Quad4::has_affine_map() const 00120 { 00121 Point v = this->point(3) - this->point(0); 00122 return (v.relative_fuzzy_equals(this->point(2) - this->point(1))); 00123 } 00124 00125 00126 00127 UniquePtr<Elem> Quad4::build_side (const unsigned int i, 00128 bool proxy) const 00129 { 00130 libmesh_assert_less (i, this->n_sides()); 00131 00132 if (proxy) 00133 return UniquePtr<Elem>(new Side<Edge2,Quad4>(this,i)); 00134 00135 else 00136 { 00137 Elem * edge = new Edge2; 00138 edge->subdomain_id() = this->subdomain_id(); 00139 00140 switch (i) 00141 { 00142 case 0: 00143 { 00144 edge->set_node(0) = this->get_node(0); 00145 edge->set_node(1) = this->get_node(1); 00146 break; 00147 } 00148 case 1: 00149 { 00150 edge->set_node(0) = this->get_node(1); 00151 edge->set_node(1) = this->get_node(2); 00152 break; 00153 } 00154 case 2: 00155 { 00156 edge->set_node(0) = this->get_node(2); 00157 edge->set_node(1) = this->get_node(3); 00158 break; 00159 } 00160 case 3: 00161 { 00162 edge->set_node(0) = this->get_node(3); 00163 edge->set_node(1) = this->get_node(0); 00164 break; 00165 } 00166 default: 00167 libmesh_error_msg("Invalid side i = " << i); 00168 } 00169 00170 return UniquePtr<Elem>(edge); 00171 } 00172 00173 libmesh_error_msg("We'll never get here!"); 00174 return UniquePtr<Elem>(); 00175 } 00176 00177 00178 00179 00180 00181 void Quad4::connectivity(const unsigned int libmesh_dbg_var(sf), 00182 const IOPackage iop, 00183 std::vector<dof_id_type>& conn) const 00184 { 00185 libmesh_assert_less (sf, this->n_sub_elem()); 00186 libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE); 00187 00188 // Create storage. 00189 conn.resize(4); 00190 00191 switch (iop) 00192 { 00193 case TECPLOT: 00194 { 00195 conn[0] = this->node(0)+1; 00196 conn[1] = this->node(1)+1; 00197 conn[2] = this->node(2)+1; 00198 conn[3] = this->node(3)+1; 00199 return; 00200 } 00201 00202 case VTK: 00203 { 00204 conn[0] = this->node(0); 00205 conn[1] = this->node(1); 00206 conn[2] = this->node(2); 00207 conn[3] = this->node(3); 00208 return; 00209 } 00210 00211 default: 00212 libmesh_error_msg("Unsupported IO package " << iop); 00213 } 00214 } 00215 00216 00217 00218 Real Quad4::volume () const 00219 { 00220 // The A,B,C,D naming scheme here corresponds exactly to the 00221 // libmesh counter-clockwise numbering scheme. 00222 00223 // 3 2 D C 00224 // QUAD4: o-----------o o-----------o 00225 // | | | | 00226 // | | | | 00227 // | | | | 00228 // | | | | 00229 // | | | | 00230 // o-----------o o-----------o 00231 // 0 1 A B 00232 00233 // Vector pointing from A to C 00234 Point AC ( this->point(2) - this->point(0) ); 00235 00236 // Vector pointing from A to B 00237 Point AB ( this->point(1) - this->point(0) ); 00238 00239 // Vector pointing from A to D 00240 Point AD ( this->point(3) - this->point(0) ); 00241 00242 // The diagonal vector minus the side vectors 00243 Point AC_AB_AD (AC - AB - AD); 00244 00245 // Check for quick return for planar QUAD4. This will 00246 // be the most common case, occuring for all purely 2D meshes. 00247 if (AC_AB_AD == Point(0.,0.,0.)) 00248 return AB.cross(AD).size(); 00249 00250 else 00251 { 00252 // Use 2x2 quadrature to approximate the surface area. (The 00253 // true integral is too difficult to compute analytically.) The 00254 // accuracy here is exactly the same as would be obtained via a 00255 // call to Elem::volume(), however it is a bit more optimized to 00256 // do it this way. The technique used is to integrate the magnitude 00257 // of the normal vector over the whole area. See for example, 00258 // 00259 // Y. Zhang, C. Bajaj, G. Xu. Surface Smoothing and Quality 00260 // Improvement of Quadrilateral/Hexahedral Meshes with Geometric 00261 // Flow. The special issue of the Journal Communications in 00262 // Numerical Methods in Engineering (CNME), submitted as an 00263 // invited paper, 2006. 00264 // http://www.ices.utexas.edu/~jessica/paper/quadhexgf/quadhex_geomflow_CNM.pdf 00265 00266 // 4-point rule 00267 const Real q[2] = {0.5 - std::sqrt(3.) / 6., 00268 0.5 + std::sqrt(3.) / 6.}; 00269 00270 Real vol=0.; 00271 for (unsigned int i=0; i<2; ++i) 00272 for (unsigned int j=0; j<2; ++j) 00273 vol += (AB + q[i]*AC_AB_AD).cross(AD + q[j]*AC_AB_AD).size(); 00274 00275 return 0.25*vol; 00276 } 00277 } 00278 00279 } // namespace libMesh