$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/libmesh_config.h" 00022 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00023 00024 #include "libmesh/fe.h" 00025 #include "libmesh/elem.h" 00026 #include "libmesh/fe_interface.h" 00027 #include "libmesh/string_to_enum.h" 00028 00029 namespace libMesh 00030 { 00031 00032 // ------------------------------------------------------------ 00033 // Bernstein-specific implementations, Steffen Petersen 2005 00034 00035 // Anonymous namespace for local helper functions 00036 namespace { 00037 00038 void bernstein_nodal_soln(const Elem* elem, 00039 const Order order, 00040 const std::vector<Number>& elem_soln, 00041 std::vector<Number>& nodal_soln, 00042 unsigned Dim) 00043 { 00044 const unsigned int n_nodes = elem->n_nodes(); 00045 00046 const ElemType elem_type = elem->type(); 00047 00048 nodal_soln.resize(n_nodes); 00049 00050 const Order totalorder = static_cast<Order>(order + elem->p_level()); 00051 00052 // FEType object to be passed to various FEInterface functions below. 00053 FEType fe_type(totalorder, BERNSTEIN); 00054 00055 switch (totalorder) 00056 { 00057 // Constant shape functions 00058 case CONSTANT: 00059 { 00060 libmesh_assert_equal_to (elem_soln.size(), 1); 00061 00062 const Number val = elem_soln[0]; 00063 00064 for (unsigned int n=0; n<n_nodes; n++) 00065 nodal_soln[n] = val; 00066 00067 return; 00068 } 00069 00070 00071 // For other bases do interpolation at the nodes 00072 // explicitly. 00073 case FIRST: 00074 case SECOND: 00075 case THIRD: 00076 case FOURTH: 00077 case FIFTH: 00078 case SIXTH: 00079 { 00080 00081 const unsigned int n_sf = 00082 // FE<Dim,T>::n_shape_functions(elem_type, totalorder); 00083 FEInterface::n_shape_functions(Dim, fe_type, elem_type); 00084 00085 std::vector<Point> refspace_nodes; 00086 FEBase::get_refspace_nodes(elem_type,refspace_nodes); 00087 libmesh_assert_equal_to (refspace_nodes.size(), n_nodes); 00088 00089 for (unsigned int n=0; n<n_nodes; n++) 00090 { 00091 libmesh_assert_equal_to (elem_soln.size(), n_sf); 00092 00093 // Zero before summation 00094 nodal_soln[n] = 0; 00095 00096 // u_i = Sum (alpha_i phi_i) 00097 for (unsigned int i=0; i<n_sf; i++) 00098 nodal_soln[n] += elem_soln[i] * 00099 // FE<Dim,T>::shape(elem, order, i, mapped_point); 00100 FEInterface::shape(Dim, fe_type, elem, i, refspace_nodes[n]); 00101 } 00102 00103 return; 00104 } 00105 00106 default: 00107 libmesh_error_msg("ERROR: Invalid total order " << totalorder); 00108 } 00109 } // bernstein_nodal_soln() 00110 00111 00112 00113 unsigned int bernstein_n_dofs(const ElemType t, const Order o) 00114 { 00115 switch (t) 00116 { 00117 case NODEELEM: 00118 return 1; 00119 case EDGE2: 00120 case EDGE3: 00121 return (o+1); 00122 case QUAD4: 00123 libmesh_assert_less (o, 2); 00124 case QUAD8: 00125 { 00126 if (o == 1) 00127 return 4; 00128 else if (o == 2) 00129 return 8; 00130 else 00131 libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for BERNSTEIN FE family!"); 00132 } 00133 case QUAD9: 00134 return ((o+1)*(o+1)); 00135 case HEX8: 00136 libmesh_assert_less (o, 2); 00137 case HEX20: 00138 { 00139 if (o == 1) 00140 return 8; 00141 else if (o == 2) 00142 return 20; 00143 else 00144 libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for BERNSTEIN FE family!"); 00145 } 00146 case HEX27: 00147 return ((o+1)*(o+1)*(o+1)); 00148 case TRI3: 00149 libmesh_assert_less (o, 2); 00150 case TRI6: 00151 return ((o+1)*(o+2)/2); 00152 case TET4: 00153 libmesh_assert_less (o, 2); 00154 case TET10: 00155 { 00156 libmesh_assert_less (o, 3); 00157 return ((o+1)*(o+2)*(o+3)/6); 00158 } 00159 case INVALID_ELEM: 00160 return 0; 00161 default: 00162 libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!"); 00163 } 00164 00165 libmesh_error_msg("We'll never get here!"); 00166 return 0; 00167 } // bernstein_n_dofs() 00168 00169 00170 00171 00172 unsigned int bernstein_n_dofs_at_node(const ElemType t, 00173 const Order o, 00174 const unsigned int n) 00175 { 00176 switch (t) 00177 { 00178 case NODEELEM: 00179 return 1; 00180 00181 case EDGE2: 00182 case EDGE3: 00183 switch (n) 00184 { 00185 case 0: 00186 case 1: 00187 return 1; 00188 case 2: 00189 libmesh_assert (o>1); 00190 return (o-1); 00191 default: 00192 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for EDGE2/3!"); 00193 } 00194 case TRI6: 00195 switch (n) 00196 { 00197 case 0: 00198 case 1: 00199 case 2: 00200 return 1; 00201 00202 case 3: 00203 case 4: 00204 case 5: 00205 return (o-1); 00206 // Internal DoFs are associated with the elem, not its nodes 00207 default: 00208 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!"); 00209 } 00210 case QUAD8: 00211 libmesh_assert_less (n, 8); 00212 libmesh_assert_less (o, 3); 00213 case QUAD9: 00214 { 00215 switch (n) 00216 { 00217 case 0: 00218 case 1: 00219 case 2: 00220 case 3: 00221 return 1; 00222 00223 case 4: 00224 case 5: 00225 case 6: 00226 case 7: 00227 return (o-1); 00228 00229 // Internal DoFs are associated with the elem, not its nodes 00230 case 8: 00231 return 0; 00232 00233 default: 00234 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for QUAD9!"); 00235 } 00236 } 00237 case HEX8: 00238 libmesh_assert_less (n, 8); 00239 libmesh_assert_less (o, 2); 00240 case HEX20: 00241 libmesh_assert_less (n, 20); 00242 libmesh_assert_less (o, 3); 00243 case HEX27: 00244 switch (n) 00245 { 00246 case 0: 00247 case 1: 00248 case 2: 00249 case 3: 00250 case 4: 00251 case 5: 00252 case 6: 00253 case 7: 00254 return 1; 00255 00256 case 8: 00257 case 9: 00258 case 10: 00259 case 11: 00260 case 12: 00261 case 13: 00262 case 14: 00263 case 15: 00264 case 16: 00265 case 17: 00266 case 18: 00267 case 19: 00268 return (o-1); 00269 00270 case 20: 00271 case 21: 00272 case 22: 00273 case 23: 00274 case 24: 00275 case 25: 00276 return ((o-1)*(o-1)); 00277 00278 // Internal DoFs are associated with the elem, not its nodes 00279 case 26: 00280 return 0; 00281 00282 default: 00283 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for HEX27!"); 00284 } 00285 case TET4: 00286 libmesh_assert_less (n, 4); 00287 libmesh_assert_less (o, 2); 00288 case TET10: 00289 libmesh_assert_less (o, 3); 00290 libmesh_assert_less (n, 10); 00291 switch (n) 00292 { 00293 case 0: 00294 case 1: 00295 case 2: 00296 case 3: 00297 return 1; 00298 00299 case 4: 00300 case 5: 00301 case 6: 00302 case 7: 00303 case 8: 00304 case 9: 00305 return (o-1); 00306 00307 default: 00308 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TET10!"); 00309 } 00310 case INVALID_ELEM: 00311 return 0; 00312 default: 00313 libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!"); 00314 } 00315 00316 libmesh_error_msg("We'll never get here!"); 00317 return 0; 00318 } // bernstein_n_dofs_at_node() 00319 00320 00321 00322 00323 unsigned int bernstein_n_dofs_per_elem(const ElemType t, const Order o) 00324 { 00325 switch (t) 00326 { 00327 case NODEELEM: 00328 case EDGE2: 00329 case EDGE3: 00330 return 0; 00331 case TRI3: 00332 case QUAD4: 00333 return 0; 00334 case TRI6: 00335 return ((o-1)*(o-2)/2); 00336 case QUAD8: 00337 if (o <= 2) 00338 return 0; 00339 case QUAD9: 00340 return ((o-1)*(o-1)); 00341 case HEX8: 00342 libmesh_assert_less (o, 2); 00343 case HEX20: 00344 libmesh_assert_less (o, 3); 00345 return 0; 00346 case HEX27: 00347 return ((o-1)*(o-1)*(o-1)); 00348 case TET4: 00349 libmesh_assert_less (o, 2); 00350 case TET10: 00351 libmesh_assert_less (o, 3); 00352 return 0; 00353 case INVALID_ELEM: 00354 return 0; 00355 default: 00356 libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!"); 00357 } 00358 00359 libmesh_error_msg("We'll never get here!"); 00360 return 0; 00361 } // bernstein_n_dofs_per_elem 00362 00363 } // anonymous namespace 00364 00365 00366 00367 00368 // Do full-specialization of nodal_soln() function for every 00369 // dimension, instead of explicit instantiation at the end of this 00370 // file. 00371 // This could be macro-ified so that it fits on one line... 00372 template <> 00373 void FE<0,BERNSTEIN>::nodal_soln(const Elem* elem, 00374 const Order order, 00375 const std::vector<Number>& elem_soln, 00376 std::vector<Number>& nodal_soln) 00377 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/0); } 00378 00379 template <> 00380 void FE<1,BERNSTEIN>::nodal_soln(const Elem* elem, 00381 const Order order, 00382 const std::vector<Number>& elem_soln, 00383 std::vector<Number>& nodal_soln) 00384 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/1); } 00385 00386 template <> 00387 void FE<2,BERNSTEIN>::nodal_soln(const Elem* elem, 00388 const Order order, 00389 const std::vector<Number>& elem_soln, 00390 std::vector<Number>& nodal_soln) 00391 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/2); } 00392 00393 template <> 00394 void FE<3,BERNSTEIN>::nodal_soln(const Elem* elem, 00395 const Order order, 00396 const std::vector<Number>& elem_soln, 00397 std::vector<Number>& nodal_soln) 00398 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/3); } 00399 00400 00401 // Full specialization of n_dofs() function for every dimension 00402 template <> unsigned int FE<0,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); } 00403 template <> unsigned int FE<1,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); } 00404 template <> unsigned int FE<2,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); } 00405 template <> unsigned int FE<3,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); } 00406 00407 // Full specialization of n_dofs_at_node() function for every dimension. 00408 template <> unsigned int FE<0,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); } 00409 template <> unsigned int FE<1,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); } 00410 template <> unsigned int FE<2,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); } 00411 template <> unsigned int FE<3,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); } 00412 00413 // Full specialization of n_dofs_per_elem() function for every dimension. 00414 template <> unsigned int FE<0,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); } 00415 template <> unsigned int FE<1,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); } 00416 template <> unsigned int FE<2,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); } 00417 template <> unsigned int FE<3,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); } 00418 00419 // Bernstein FEMs are C^0 continuous 00420 template <> FEContinuity FE<0,BERNSTEIN>::get_continuity() const { return C_ZERO; } 00421 template <> FEContinuity FE<1,BERNSTEIN>::get_continuity() const { return C_ZERO; } 00422 template <> FEContinuity FE<2,BERNSTEIN>::get_continuity() const { return C_ZERO; } 00423 template <> FEContinuity FE<3,BERNSTEIN>::get_continuity() const { return C_ZERO; } 00424 00425 // Bernstein FEMs are not hierarchic 00426 template <> bool FE<0,BERNSTEIN>::is_hierarchic() const { return false; } 00427 template <> bool FE<1,BERNSTEIN>::is_hierarchic() const { return false; } 00428 template <> bool FE<2,BERNSTEIN>::is_hierarchic() const { return false; } 00429 template <> bool FE<3,BERNSTEIN>::is_hierarchic() const { return false; } 00430 00431 #ifdef LIBMESH_ENABLE_AMR 00432 // compute_constraints() specializations are only needed for 2 and 3D 00433 template <> 00434 void FE<2,BERNSTEIN>::compute_constraints (DofConstraints &constraints, 00435 DofMap &dof_map, 00436 const unsigned int variable_number, 00437 const Elem* elem) 00438 { compute_proj_constraints(constraints, dof_map, variable_number, elem); } 00439 00440 template <> 00441 void FE<3,BERNSTEIN>::compute_constraints (DofConstraints &constraints, 00442 DofMap &dof_map, 00443 const unsigned int variable_number, 00444 const Elem* elem) 00445 { compute_proj_constraints(constraints, dof_map, variable_number, elem); } 00446 #endif // #ifdef LIBMESH_ENABLE_AMR 00447 00448 // Bernstein shapes need reinit only for approximation orders >= 3, 00449 // but we might reach that with p refinement 00450 template <> bool FE<0,BERNSTEIN>::shapes_need_reinit() const { return true; } 00451 template <> bool FE<1,BERNSTEIN>::shapes_need_reinit() const { return true; } 00452 template <> bool FE<2,BERNSTEIN>::shapes_need_reinit() const { return true; } 00453 template <> bool FE<3,BERNSTEIN>::shapes_need_reinit() const { return true; } 00454 00455 } // namespace libMesh 00456 00457 #endif //LIBMESH_ENABLE_HIGHER_ORDER_SHAPES