$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/dof_map.h" 00022 #include "libmesh/fe.h" 00023 #include "libmesh/fe_interface.h" 00024 #include "libmesh/elem.h" 00025 #include "libmesh/threads.h" 00026 #include "libmesh/string_to_enum.h" 00027 00028 namespace libMesh 00029 { 00030 00031 // ------------------------------------------------------------ 00032 // Lagrange-specific implementations 00033 00034 00035 // Anonymous namespace for local helper functions 00036 namespace { 00037 void l2_lagrange_nodal_soln(const Elem* elem, 00038 const Order order, 00039 const std::vector<Number>& elem_soln, 00040 std::vector<Number>& nodal_soln) 00041 { 00042 const unsigned int n_nodes = elem->n_nodes(); 00043 const ElemType type = elem->type(); 00044 00045 const Order totalorder = static_cast<Order>(order+elem->p_level()); 00046 00047 nodal_soln.resize(n_nodes); 00048 00049 00050 00051 switch (totalorder) 00052 { 00053 // linear Lagrange shape functions 00054 case FIRST: 00055 { 00056 switch (type) 00057 { 00058 case EDGE3: 00059 { 00060 libmesh_assert_equal_to (elem_soln.size(), 2); 00061 libmesh_assert_equal_to (nodal_soln.size(), 3); 00062 00063 nodal_soln[0] = elem_soln[0]; 00064 nodal_soln[1] = elem_soln[1]; 00065 nodal_soln[2] = .5*(elem_soln[0] + elem_soln[1]); 00066 00067 return; 00068 } 00069 00070 case EDGE4: 00071 { 00072 libmesh_assert_equal_to (elem_soln.size(), 2); 00073 libmesh_assert_equal_to (nodal_soln.size(), 4); 00074 00075 nodal_soln[0] = elem_soln[0]; 00076 nodal_soln[1] = elem_soln[1]; 00077 nodal_soln[2] = (2.*elem_soln[0] + elem_soln[1])/3.; 00078 nodal_soln[3] = (elem_soln[0] + 2.*elem_soln[1])/3.; 00079 00080 return; 00081 } 00082 00083 00084 case TRI6: 00085 { 00086 libmesh_assert_equal_to (elem_soln.size(), 3); 00087 libmesh_assert_equal_to (nodal_soln.size(), 6); 00088 00089 nodal_soln[0] = elem_soln[0]; 00090 nodal_soln[1] = elem_soln[1]; 00091 nodal_soln[2] = elem_soln[2]; 00092 nodal_soln[3] = .5*(elem_soln[0] + elem_soln[1]); 00093 nodal_soln[4] = .5*(elem_soln[1] + elem_soln[2]); 00094 nodal_soln[5] = .5*(elem_soln[2] + elem_soln[0]); 00095 00096 return; 00097 } 00098 00099 00100 case QUAD8: 00101 case QUAD9: 00102 { 00103 libmesh_assert_equal_to (elem_soln.size(), 4); 00104 00105 if (type == QUAD8) 00106 libmesh_assert_equal_to (nodal_soln.size(), 8); 00107 else 00108 libmesh_assert_equal_to (nodal_soln.size(), 9); 00109 00110 00111 nodal_soln[0] = elem_soln[0]; 00112 nodal_soln[1] = elem_soln[1]; 00113 nodal_soln[2] = elem_soln[2]; 00114 nodal_soln[3] = elem_soln[3]; 00115 nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]); 00116 nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]); 00117 nodal_soln[6] = .5*(elem_soln[2] + elem_soln[3]); 00118 nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]); 00119 00120 if (type == QUAD9) 00121 nodal_soln[8] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]); 00122 00123 return; 00124 } 00125 00126 00127 case TET10: 00128 { 00129 libmesh_assert_equal_to (elem_soln.size(), 4); 00130 libmesh_assert_equal_to (nodal_soln.size(), 10); 00131 00132 nodal_soln[0] = elem_soln[0]; 00133 nodal_soln[1] = elem_soln[1]; 00134 nodal_soln[2] = elem_soln[2]; 00135 nodal_soln[3] = elem_soln[3]; 00136 nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]); 00137 nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]); 00138 nodal_soln[6] = .5*(elem_soln[2] + elem_soln[0]); 00139 nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]); 00140 nodal_soln[8] = .5*(elem_soln[3] + elem_soln[1]); 00141 nodal_soln[9] = .5*(elem_soln[3] + elem_soln[2]); 00142 00143 return; 00144 } 00145 00146 00147 case HEX20: 00148 case HEX27: 00149 { 00150 libmesh_assert_equal_to (elem_soln.size(), 8); 00151 00152 if (type == HEX20) 00153 libmesh_assert_equal_to (nodal_soln.size(), 20); 00154 else 00155 libmesh_assert_equal_to (nodal_soln.size(), 27); 00156 00157 nodal_soln[0] = elem_soln[0]; 00158 nodal_soln[1] = elem_soln[1]; 00159 nodal_soln[2] = elem_soln[2]; 00160 nodal_soln[3] = elem_soln[3]; 00161 nodal_soln[4] = elem_soln[4]; 00162 nodal_soln[5] = elem_soln[5]; 00163 nodal_soln[6] = elem_soln[6]; 00164 nodal_soln[7] = elem_soln[7]; 00165 nodal_soln[8] = .5*(elem_soln[0] + elem_soln[1]); 00166 nodal_soln[9] = .5*(elem_soln[1] + elem_soln[2]); 00167 nodal_soln[10] = .5*(elem_soln[2] + elem_soln[3]); 00168 nodal_soln[11] = .5*(elem_soln[3] + elem_soln[0]); 00169 nodal_soln[12] = .5*(elem_soln[0] + elem_soln[4]); 00170 nodal_soln[13] = .5*(elem_soln[1] + elem_soln[5]); 00171 nodal_soln[14] = .5*(elem_soln[2] + elem_soln[6]); 00172 nodal_soln[15] = .5*(elem_soln[3] + elem_soln[7]); 00173 nodal_soln[16] = .5*(elem_soln[4] + elem_soln[5]); 00174 nodal_soln[17] = .5*(elem_soln[5] + elem_soln[6]); 00175 nodal_soln[18] = .5*(elem_soln[6] + elem_soln[7]); 00176 nodal_soln[19] = .5*(elem_soln[4] + elem_soln[7]); 00177 00178 if (type == HEX27) 00179 { 00180 nodal_soln[20] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]); 00181 nodal_soln[21] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[5]); 00182 nodal_soln[22] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[6]); 00183 nodal_soln[23] = .25*(elem_soln[2] + elem_soln[3] + elem_soln[6] + elem_soln[7]); 00184 nodal_soln[24] = .25*(elem_soln[3] + elem_soln[0] + elem_soln[7] + elem_soln[4]); 00185 nodal_soln[25] = .25*(elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]); 00186 00187 nodal_soln[26] = .125*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3] + 00188 elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]); 00189 } 00190 00191 return; 00192 } 00193 00194 00195 case PRISM15: 00196 case PRISM18: 00197 { 00198 libmesh_assert_equal_to (elem_soln.size(), 6); 00199 00200 if (type == PRISM15) 00201 libmesh_assert_equal_to (nodal_soln.size(), 15); 00202 else 00203 libmesh_assert_equal_to (nodal_soln.size(), 18); 00204 00205 nodal_soln[0] = elem_soln[0]; 00206 nodal_soln[1] = elem_soln[1]; 00207 nodal_soln[2] = elem_soln[2]; 00208 nodal_soln[3] = elem_soln[3]; 00209 nodal_soln[4] = elem_soln[4]; 00210 nodal_soln[5] = elem_soln[5]; 00211 nodal_soln[6] = .5*(elem_soln[0] + elem_soln[1]); 00212 nodal_soln[7] = .5*(elem_soln[1] + elem_soln[2]); 00213 nodal_soln[8] = .5*(elem_soln[0] + elem_soln[2]); 00214 nodal_soln[9] = .5*(elem_soln[0] + elem_soln[3]); 00215 nodal_soln[10] = .5*(elem_soln[1] + elem_soln[4]); 00216 nodal_soln[11] = .5*(elem_soln[2] + elem_soln[5]); 00217 nodal_soln[12] = .5*(elem_soln[3] + elem_soln[4]); 00218 nodal_soln[13] = .5*(elem_soln[4] + elem_soln[5]); 00219 nodal_soln[14] = .5*(elem_soln[3] + elem_soln[5]); 00220 00221 if (type == PRISM18) 00222 { 00223 nodal_soln[15] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[3]); 00224 nodal_soln[16] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[4]); 00225 nodal_soln[17] = .25*(elem_soln[2] + elem_soln[0] + elem_soln[3] + elem_soln[5]); 00226 } 00227 00228 return; 00229 } 00230 00231 00232 00233 default: 00234 { 00235 // By default the element solution _is_ nodal, 00236 // so just copy it. 00237 nodal_soln = elem_soln; 00238 00239 return; 00240 } 00241 } 00242 } 00243 00244 case SECOND: 00245 { 00246 switch (type) 00247 { 00248 case EDGE4: 00249 { 00250 libmesh_assert_equal_to (elem_soln.size(), 3); 00251 libmesh_assert_equal_to (nodal_soln.size(), 4); 00252 00253 // Project quadratic solution onto cubic element nodes 00254 nodal_soln[0] = elem_soln[0]; 00255 nodal_soln[1] = elem_soln[1]; 00256 nodal_soln[2] = (2.*elem_soln[0] - elem_soln[1] + 00257 8.*elem_soln[2])/9.; 00258 nodal_soln[3] = (-elem_soln[0] + 2.*elem_soln[1] + 00259 8.*elem_soln[2])/9.; 00260 return; 00261 } 00262 00263 default: 00264 { 00265 // By default the element solution _is_ nodal, 00266 // so just copy it. 00267 nodal_soln = elem_soln; 00268 00269 return; 00270 } 00271 } 00272 } 00273 00274 00275 00276 00277 default: 00278 { 00279 // By default the element solution _is_ nodal, 00280 // so just copy it. 00281 nodal_soln = elem_soln; 00282 00283 return; 00284 } 00285 } 00286 } 00287 00288 00289 // TODO: We should make this work, for example, for SECOND on a TRI3 00290 // (this is valid with L2_LAGRANGE, but not with LAGRANGE) 00291 unsigned int l2_lagrange_n_dofs(const ElemType t, const Order o) 00292 { 00293 switch (o) 00294 { 00295 00296 // linear Lagrange shape functions 00297 case FIRST: 00298 { 00299 switch (t) 00300 { 00301 case NODEELEM: 00302 return 1; 00303 00304 case EDGE2: 00305 case EDGE3: 00306 case EDGE4: 00307 return 2; 00308 00309 case TRI3: 00310 case TRI6: 00311 return 3; 00312 00313 case QUAD4: 00314 case QUAD8: 00315 case QUAD9: 00316 return 4; 00317 00318 case TET4: 00319 case TET10: 00320 return 4; 00321 00322 case HEX8: 00323 case HEX20: 00324 case HEX27: 00325 return 8; 00326 00327 case PRISM6: 00328 case PRISM15: 00329 case PRISM18: 00330 return 6; 00331 00332 case PYRAMID5: 00333 case PYRAMID13: 00334 case PYRAMID14: 00335 return 5; 00336 00337 case INVALID_ELEM: 00338 return 0; 00339 00340 default: 00341 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00342 } 00343 } 00344 00345 00346 // quadratic Lagrange shape functions 00347 case SECOND: 00348 { 00349 switch (t) 00350 { 00351 case NODEELEM: 00352 return 1; 00353 00354 case EDGE3: 00355 return 3; 00356 00357 case TRI6: 00358 return 6; 00359 00360 case QUAD8: 00361 return 8; 00362 00363 case QUAD9: 00364 return 9; 00365 00366 case TET10: 00367 return 10; 00368 00369 case HEX20: 00370 return 20; 00371 00372 case HEX27: 00373 return 27; 00374 00375 case PRISM15: 00376 return 15; 00377 00378 case PRISM18: 00379 return 18; 00380 00381 case INVALID_ELEM: 00382 return 0; 00383 00384 default: 00385 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00386 } 00387 } 00388 00389 case THIRD: 00390 { 00391 switch (t) 00392 { 00393 case NODEELEM: 00394 return 1; 00395 00396 case EDGE4: 00397 return 4; 00398 00399 case INVALID_ELEM: 00400 return 0; 00401 00402 default: 00403 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00404 } 00405 } 00406 00407 default: 00408 libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for L2_LAGRANGE FE family!"); 00409 } 00410 00411 libmesh_error_msg("We'll never get here!"); 00412 return 0; 00413 } 00414 00415 } // anonymous namespace 00416 00417 00418 // Do full-specialization for every dimension, instead 00419 // of explicit instantiation at the end of this file. 00420 // This could be macro-ified so that it fits on one line... 00421 template <> 00422 void FE<0,L2_LAGRANGE>::nodal_soln(const Elem* elem, 00423 const Order order, 00424 const std::vector<Number>& elem_soln, 00425 std::vector<Number>& nodal_soln) 00426 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00427 00428 template <> 00429 void FE<1,L2_LAGRANGE>::nodal_soln(const Elem* elem, 00430 const Order order, 00431 const std::vector<Number>& elem_soln, 00432 std::vector<Number>& nodal_soln) 00433 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00434 00435 template <> 00436 void FE<2,L2_LAGRANGE>::nodal_soln(const Elem* elem, 00437 const Order order, 00438 const std::vector<Number>& elem_soln, 00439 std::vector<Number>& nodal_soln) 00440 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00441 00442 template <> 00443 void FE<3,L2_LAGRANGE>::nodal_soln(const Elem* elem, 00444 const Order order, 00445 const std::vector<Number>& elem_soln, 00446 std::vector<Number>& nodal_soln) 00447 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); } 00448 00449 00450 // Do full-specialization for every dimension, instead 00451 // of explicit instantiation at the end of this function. 00452 // This could be macro-ified. 00453 template <> unsigned int FE<0,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00454 template <> unsigned int FE<1,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00455 template <> unsigned int FE<2,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00456 template <> unsigned int FE<3,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00457 00458 00459 // L2 Lagrange elements have all dofs on elements (hence none on nodes) 00460 template <> unsigned int FE<0,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; } 00461 template <> unsigned int FE<1,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; } 00462 template <> unsigned int FE<2,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; } 00463 template <> unsigned int FE<3,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; } 00464 00465 00466 // L2 Lagrange elements have all dofs on elements 00467 template <> unsigned int FE<0,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00468 template <> unsigned int FE<1,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00469 template <> unsigned int FE<2,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00470 template <> unsigned int FE<3,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); } 00471 00472 // L2 Lagrange FEMs are DISCONTINUOUS 00473 template <> FEContinuity FE<0,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; } 00474 template <> FEContinuity FE<1,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; } 00475 template <> FEContinuity FE<2,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; } 00476 template <> FEContinuity FE<3,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; } 00477 00478 // Lagrange FEMs are not hierarchic 00479 template <> bool FE<0,L2_LAGRANGE>::is_hierarchic() const { return false; } 00480 template <> bool FE<1,L2_LAGRANGE>::is_hierarchic() const { return false; } 00481 template <> bool FE<2,L2_LAGRANGE>::is_hierarchic() const { return false; } 00482 template <> bool FE<3,L2_LAGRANGE>::is_hierarchic() const { return false; } 00483 00484 // Lagrange FEM shapes do not need reinit (is this always true?) 00485 template <> bool FE<0,L2_LAGRANGE>::shapes_need_reinit() const { return false; } 00486 template <> bool FE<1,L2_LAGRANGE>::shapes_need_reinit() const { return false; } 00487 template <> bool FE<2,L2_LAGRANGE>::shapes_need_reinit() const { return false; } 00488 template <> bool FE<3,L2_LAGRANGE>::shapes_need_reinit() const { return false; } 00489 00490 // We don't need any constraints for this DISCONTINUOUS basis, hence these 00491 // are NOOPs 00492 #ifdef LIBMESH_ENABLE_AMR 00493 template <> 00494 void FE<2,L2_LAGRANGE>::compute_constraints (DofConstraints &, 00495 DofMap &, 00496 const unsigned int , 00497 const Elem* ) 00498 { } 00499 00500 template <> 00501 void FE<3,L2_LAGRANGE>::compute_constraints (DofConstraints &, 00502 DofMap &, 00503 const unsigned int , 00504 const Elem* ) 00505 { } 00506 #endif // LIBMESH_ENABLE_AMR 00507 00508 } // namespace libMesh