$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 00019 00020 // Local includes 00021 #include "libmesh/elem.h" 00022 #include "libmesh/fe.h" 00023 #include "libmesh/fe_interface.h" 00024 #include "libmesh/string_to_enum.h" 00025 00026 namespace libMesh 00027 { 00028 00029 // ------------------------------------------------------------ 00030 // Hermite-specific implementations 00031 00032 // Anonymous namespace for local helper functions 00033 namespace { 00034 00035 void hermite_nodal_soln(const Elem* elem, 00036 const Order order, 00037 const std::vector<Number>& elem_soln, 00038 std::vector<Number>& nodal_soln, 00039 unsigned Dim) 00040 { 00041 const unsigned int n_nodes = elem->n_nodes(); 00042 00043 const ElemType elem_type = elem->type(); 00044 00045 nodal_soln.resize(n_nodes); 00046 00047 const Order totalorder = static_cast<Order>(order + elem->p_level()); 00048 00049 // FEType object to be passed to various FEInterface functions below. 00050 FEType fe_type(totalorder, HERMITE); 00051 00052 const unsigned int n_sf = 00053 // FE<Dim,T>::n_shape_functions(elem_type, totalorder); 00054 FEInterface::n_shape_functions(Dim, fe_type, elem_type); 00055 00056 std::vector<Point> refspace_nodes; 00057 FEBase::get_refspace_nodes(elem_type,refspace_nodes); 00058 libmesh_assert_equal_to (refspace_nodes.size(), n_nodes); 00059 00060 for (unsigned int n=0; n<n_nodes; n++) 00061 { 00062 libmesh_assert_equal_to (elem_soln.size(), n_sf); 00063 00064 // Zero before summation 00065 nodal_soln[n] = 0; 00066 00067 // u_i = Sum (alpha_i phi_i) 00068 for (unsigned int i=0; i<n_sf; i++) 00069 nodal_soln[n] += elem_soln[i] * 00070 // FE<Dim,T>::shape(elem, order, i, mapped_point); 00071 FEInterface::shape(Dim, fe_type, elem, i, refspace_nodes[n]); 00072 } 00073 } // hermite_nodal_soln() 00074 00075 00076 00077 unsigned int hermite_n_dofs(const ElemType t, const Order o) 00078 { 00079 #ifdef DEBUG 00080 if (o < 3) 00081 libmesh_error_msg("Error: Hermite elements require order>=3, but you asked for order=" << o); 00082 #endif 00083 00084 // Piecewise (bi/tri)cubic C1 Hermite splines 00085 switch (t) 00086 { 00087 case NODEELEM: 00088 return 1; 00089 case EDGE2: 00090 libmesh_assert_less (o, 4); 00091 case EDGE3: 00092 return (o+1); 00093 00094 case QUAD4: 00095 case QUAD8: 00096 libmesh_assert_less (o, 4); 00097 case QUAD9: 00098 return ((o+1)*(o+1)); 00099 00100 case HEX8: 00101 case HEX20: 00102 libmesh_assert_less (o, 4); 00103 case HEX27: 00104 return ((o+1)*(o+1)*(o+1)); 00105 00106 case INVALID_ELEM: 00107 return 0; 00108 00109 default: 00110 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00111 } 00112 00113 libmesh_error_msg("We'll never get here!"); 00114 return 0; 00115 } // hermite_n_dofs() 00116 00117 00118 00119 00120 unsigned int hermite_n_dofs_at_node(const ElemType t, 00121 const Order o, 00122 const unsigned int n) 00123 { 00124 libmesh_assert_greater (o, 2); 00125 // Piecewise (bi/tri)cubic C1 Hermite splines 00126 switch (t) 00127 { 00128 case NODEELEM: 00129 return 1; 00130 case EDGE2: 00131 case EDGE3: 00132 { 00133 switch (n) 00134 { 00135 case 0: 00136 case 1: 00137 return 2; 00138 case 2: 00139 // Interior DoFs are carried on Elems 00140 // return (o-3); 00141 return 0; 00142 00143 default: 00144 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for EDGE2/3!"); 00145 } 00146 } 00147 00148 case QUAD4: 00149 libmesh_assert_less (o, 4); 00150 case QUAD8: 00151 case QUAD9: 00152 { 00153 switch (n) 00154 { 00155 // Vertices 00156 case 0: 00157 case 1: 00158 case 2: 00159 case 3: 00160 return 4; 00161 // Edges 00162 case 4: 00163 case 5: 00164 case 6: 00165 case 7: 00166 return (2*(o-3)); 00167 case 8: 00168 // Interior DoFs are carried on Elems 00169 // return ((o-3)*(o-3)); 00170 return 0; 00171 00172 default: 00173 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for QUAD4/8/9!"); 00174 } 00175 } 00176 00177 case HEX8: 00178 case HEX20: 00179 libmesh_assert_less (o, 4); 00180 case HEX27: 00181 { 00182 switch (n) 00183 { 00184 // Vertices 00185 case 0: 00186 case 1: 00187 case 2: 00188 case 3: 00189 case 4: 00190 case 5: 00191 case 6: 00192 case 7: 00193 return 8; 00194 // Edges 00195 case 8: 00196 case 9: 00197 case 10: 00198 case 11: 00199 case 12: 00200 case 13: 00201 case 14: 00202 case 15: 00203 case 16: 00204 case 17: 00205 case 18: 00206 case 19: 00207 return (4*(o-3)); 00208 // Faces 00209 case 20: 00210 case 21: 00211 case 22: 00212 case 23: 00213 case 24: 00214 case 25: 00215 return (2*(o-3)*(o-3)); 00216 case 26: 00217 // Interior DoFs are carried on Elems 00218 // return ((o-3)*(o-3)*(o-3)); 00219 return 0; 00220 00221 default: 00222 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for HEX8/20/27!"); 00223 } 00224 } 00225 00226 case INVALID_ELEM: 00227 return 0; 00228 00229 default: 00230 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00231 } 00232 00233 libmesh_error_msg("We'll never get here!"); 00234 return 0; 00235 } // hermite_n_dofs_at_node() 00236 00237 00238 00239 unsigned int hermite_n_dofs_per_elem(const ElemType t, 00240 const Order o) 00241 { 00242 libmesh_assert_greater (o, 2); 00243 00244 switch (t) 00245 { 00246 case NODEELEM: 00247 return 0; 00248 case EDGE2: 00249 case EDGE3: 00250 return (o-3); 00251 case QUAD4: 00252 libmesh_assert_less (o, 4); 00253 case QUAD8: 00254 case QUAD9: 00255 return ((o-3)*(o-3)); 00256 case HEX8: 00257 libmesh_assert_less (o, 4); 00258 case HEX20: 00259 case HEX27: 00260 return ((o-3)*(o-3)*(o-3)); 00261 00262 case INVALID_ELEM: 00263 return 0; 00264 00265 default: 00266 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00267 } 00268 00269 libmesh_error_msg("We'll never get here!"); 00270 return 0; 00271 } // hermite_n_dofs_per_elem() 00272 00273 00274 } // anonymous namespace 00275 00276 00277 00278 00279 // Do full-specialization of nodal_soln() function for every 00280 // dimension, instead of explicit instantiation at the end of this 00281 // file. 00282 // This could be macro-ified so that it fits on one line... 00283 template <> 00284 void FE<0,HERMITE>::nodal_soln(const Elem* elem, 00285 const Order order, 00286 const std::vector<Number>& elem_soln, 00287 std::vector<Number>& nodal_soln) 00288 { hermite_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/0); } 00289 00290 template <> 00291 void FE<1,HERMITE>::nodal_soln(const Elem* elem, 00292 const Order order, 00293 const std::vector<Number>& elem_soln, 00294 std::vector<Number>& nodal_soln) 00295 { hermite_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/1); } 00296 00297 template <> 00298 void FE<2,HERMITE>::nodal_soln(const Elem* elem, 00299 const Order order, 00300 const std::vector<Number>& elem_soln, 00301 std::vector<Number>& nodal_soln) 00302 { hermite_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/2); } 00303 00304 template <> 00305 void FE<3,HERMITE>::nodal_soln(const Elem* elem, 00306 const Order order, 00307 const std::vector<Number>& elem_soln, 00308 std::vector<Number>& nodal_soln) 00309 { hermite_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/3); } 00310 00311 00312 00313 00314 // Do full-specialization for every dimension, instead 00315 // of explicit instantiation at the end of this function. 00316 // This could be macro-ified. 00317 template <> unsigned int FE<0,HERMITE>::n_dofs(const ElemType t, const Order o) { return hermite_n_dofs(t, o); } 00318 template <> unsigned int FE<1,HERMITE>::n_dofs(const ElemType t, const Order o) { return hermite_n_dofs(t, o); } 00319 template <> unsigned int FE<2,HERMITE>::n_dofs(const ElemType t, const Order o) { return hermite_n_dofs(t, o); } 00320 template <> unsigned int FE<3,HERMITE>::n_dofs(const ElemType t, const Order o) { return hermite_n_dofs(t, o); } 00321 00322 // Do full-specialization for every dimension, instead 00323 // of explicit instantiation at the end of this function. 00324 template <> unsigned int FE<0,HERMITE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hermite_n_dofs_at_node(t, o, n); } 00325 template <> unsigned int FE<1,HERMITE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hermite_n_dofs_at_node(t, o, n); } 00326 template <> unsigned int FE<2,HERMITE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hermite_n_dofs_at_node(t, o, n); } 00327 template <> unsigned int FE<3,HERMITE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return hermite_n_dofs_at_node(t, o, n); } 00328 00329 // Full specialization of n_dofs_per_elem() function for every dimension. 00330 template <> unsigned int FE<0,HERMITE>::n_dofs_per_elem(const ElemType t, const Order o) { return hermite_n_dofs_per_elem(t, o); } 00331 template <> unsigned int FE<1,HERMITE>::n_dofs_per_elem(const ElemType t, const Order o) { return hermite_n_dofs_per_elem(t, o); } 00332 template <> unsigned int FE<2,HERMITE>::n_dofs_per_elem(const ElemType t, const Order o) { return hermite_n_dofs_per_elem(t, o); } 00333 template <> unsigned int FE<3,HERMITE>::n_dofs_per_elem(const ElemType t, const Order o) { return hermite_n_dofs_per_elem(t, o); } 00334 00335 // Hermite FEMs are C^1 continuous 00336 template <> FEContinuity FE<0,HERMITE>::get_continuity() const { return C_ONE; } 00337 template <> FEContinuity FE<1,HERMITE>::get_continuity() const { return C_ONE; } 00338 template <> FEContinuity FE<2,HERMITE>::get_continuity() const { return C_ONE; } 00339 template <> FEContinuity FE<3,HERMITE>::get_continuity() const { return C_ONE; } 00340 00341 // Hermite FEMs are hierarchic 00342 template <> bool FE<0,HERMITE>::is_hierarchic() const { return true; } 00343 template <> bool FE<1,HERMITE>::is_hierarchic() const { return true; } 00344 template <> bool FE<2,HERMITE>::is_hierarchic() const { return true; } 00345 template <> bool FE<3,HERMITE>::is_hierarchic() const { return true; } 00346 00347 00348 #ifdef LIBMESH_ENABLE_AMR 00349 // compute_constraints() specializations are only needed for 2 and 3D 00350 template <> 00351 void FE<2,HERMITE>::compute_constraints (DofConstraints &constraints, 00352 DofMap &dof_map, 00353 const unsigned int variable_number, 00354 const Elem* elem) 00355 { compute_proj_constraints(constraints, dof_map, variable_number, elem); } 00356 00357 template <> 00358 void FE<3,HERMITE>::compute_constraints (DofConstraints &constraints, 00359 DofMap &dof_map, 00360 const unsigned int variable_number, 00361 const Elem* elem) 00362 { compute_proj_constraints(constraints, dof_map, variable_number, elem); } 00363 #endif // #ifdef LIBMESH_ENABLE_AMR 00364 00365 // Hermite FEM shapes need reinit 00366 template <> bool FE<0,HERMITE>::shapes_need_reinit() const { return true; } 00367 template <> bool FE<1,HERMITE>::shapes_need_reinit() const { return true; } 00368 template <> bool FE<2,HERMITE>::shapes_need_reinit() const { return true; } 00369 template <> bool FE<3,HERMITE>::shapes_need_reinit() const { return true; } 00370 00371 } // namespace libMesh