$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 // Local includes 00020 #include "libmesh/libmesh_config.h" 00021 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES 00022 00023 #include "libmesh/fe.h" 00024 #include "libmesh/elem.h" 00025 #include "libmesh/number_lookups.h" 00026 #include "libmesh/utility.h" 00027 00028 00029 namespace libMesh 00030 { 00031 00032 00033 template <> 00034 Real FE<2,BERNSTEIN>::shape(const ElemType, 00035 const Order, 00036 const unsigned int, 00037 const Point&) 00038 { 00039 libmesh_error_msg("Bernstein polynomials require the element type \nbecause edge orientation is needed."); 00040 return 0.; 00041 } 00042 00043 00044 00045 template <> 00046 Real FE<2,BERNSTEIN>::shape(const Elem* elem, 00047 const Order order, 00048 const unsigned int i, 00049 const Point& p) 00050 { 00051 libmesh_assert(elem); 00052 00053 const ElemType type = elem->type(); 00054 00055 const Order totalorder = static_cast<Order>(order + elem->p_level()); 00056 00057 // Declare that we are using our own special power function 00058 // from the Utility namespace. This saves typing later. 00059 using Utility::pow; 00060 00061 switch (type) 00062 { 00063 // Hierarchic shape functions on the quadrilateral. 00064 case QUAD4: 00065 case QUAD9: 00066 { 00067 // Compute quad shape functions as a tensor-product 00068 const Real xi = p(0); 00069 const Real eta = p(1); 00070 00071 libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); 00072 00073 // Example i, i0, i1 values for totalorder = 5: 00074 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 00075 // static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 3, 2, 4, 4, 4, 3, 2, 5, 5, 5, 5, 4, 3, 2}; 00076 // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 3, 3, 2, 3, 4, 4, 4, 2, 3, 4, 5, 5, 5, 5}; 00077 00078 unsigned int i0, i1; 00079 00080 // Vertex DoFs 00081 if (i == 0) 00082 { i0 = 0; i1 = 0; } 00083 else if (i == 1) 00084 { i0 = 1; i1 = 0; } 00085 else if (i == 2) 00086 { i0 = 1; i1 = 1; } 00087 else if (i == 3) 00088 { i0 = 0; i1 = 1; } 00089 00090 00091 // Edge DoFs 00092 else if (i < totalorder + 3u) 00093 { i0 = i - 2; i1 = 0; } 00094 else if (i < 2u*totalorder + 2) 00095 { i0 = 1; i1 = i - totalorder - 1; } 00096 else if (i < 3u*totalorder + 1) 00097 { i0 = i - 2u*totalorder; i1 = 1; } 00098 else if (i < 4u*totalorder) 00099 { i0 = 0; i1 = i - 3u*totalorder + 1; } 00100 // Interior DoFs. Use Roy's number look up 00101 else 00102 { 00103 unsigned int basisnum = i - 4*totalorder; 00104 i0 = square_number_column[basisnum] + 2; 00105 i1 = square_number_row[basisnum] + 2; 00106 } 00107 00108 00109 // Flip odd degree of freedom values if necessary 00110 // to keep continuity on sides. 00111 if ((i>= 4 && i<= 4+ totalorder-2u) && elem->point(0) > elem->point(1)) i0=totalorder+2-i0;// 00112 else if((i>= 4+ totalorder-1u && i<= 4+2*totalorder-3u) && elem->point(1) > elem->point(2)) i1=totalorder+2-i1; 00113 else if((i>= 4+2*totalorder-2u && i<= 4+3*totalorder-4u) && elem->point(3) > elem->point(2)) i0=totalorder+2-i0; 00114 else if((i>= 4+3*totalorder-3u && i<= 4+4*totalorder-5u) && elem->point(0) > elem->point(3)) i1=totalorder+2-i1; 00115 00116 00117 return (FE<1,BERNSTEIN>::shape(EDGE3, totalorder, i0, xi)* 00118 FE<1,BERNSTEIN>::shape(EDGE3, totalorder, i1, eta)); 00119 } 00120 // handle serendipity QUAD8 element separately 00121 case QUAD8: 00122 { 00123 libmesh_assert_less (totalorder, 3); 00124 00125 const Real xi = p(0); 00126 const Real eta = p(1); 00127 00128 libmesh_assert_less (i, 8); 00129 00130 // 0 1 2 3 4 5 6 7 8 00131 static const unsigned int i0[] = {0, 1, 1, 0, 2, 1, 2, 0, 2}; 00132 static const unsigned int i1[] = {0, 0, 1, 1, 0, 2, 1, 2, 2}; 00133 static const Real scal[] = {-0.25, -0.25, -0.25, -0.25, 0.5, 0.5, 0.5, 0.5}; 00134 00135 //B_t,i0(i)|xi * B_s,i1(i)|eta + scal(i) * B_t,2|xi * B_t,2|eta 00136 return (FE<1,BERNSTEIN>::shape(EDGE3, totalorder, i0[i], xi)* 00137 FE<1,BERNSTEIN>::shape(EDGE3, totalorder, i1[i], eta) 00138 +scal[i]* 00139 FE<1,BERNSTEIN>::shape(EDGE3, totalorder, i0[8], xi)* 00140 FE<1,BERNSTEIN>::shape(EDGE3, totalorder, i1[8], eta)); 00141 00142 } 00143 00144 case TRI3: 00145 libmesh_assert_less (totalorder, 2); 00146 case TRI6: 00147 switch (totalorder) 00148 { 00149 case FIRST: 00150 { 00151 const Real x=p(0); 00152 const Real y=p(1); 00153 const Real r=1.-x-y; 00154 00155 libmesh_assert_less (i, 3); 00156 00157 switch(i) 00158 { 00159 case 0: return r; //f0,0,1 00160 case 1: return x; //f0,1,1 00161 case 2: return y; //f1,0,1 00162 00163 default: 00164 libmesh_error_msg("Invalid shape function index i = " << i); 00165 } 00166 } 00167 case SECOND: 00168 { 00169 const Real x=p(0); 00170 const Real y=p(1); 00171 const Real r=1.-x-y; 00172 00173 libmesh_assert_less (i, 6); 00174 00175 switch(i) 00176 { 00177 case 0: return r*r; 00178 case 1: return x*x; 00179 case 2: return y*y; 00180 00181 case 3: return 2.*x*r; 00182 case 4: return 2.*x*y; 00183 case 5: return 2.*r*y; 00184 00185 default: 00186 libmesh_error_msg("Invalid shape function index i = " << i); 00187 } 00188 } 00189 case THIRD: 00190 { 00191 const Real x=p(0); 00192 const Real y=p(1); 00193 const Real r=1.-x-y; 00194 libmesh_assert_less (i, 10); 00195 00196 unsigned int shape=i; 00197 00198 00199 if((i==3||i==4) && elem->point(0) > elem->point(1)) shape=7-i; 00200 if((i==5||i==6) && elem->point(1) > elem->point(2)) shape=11-i; 00201 if((i==7||i==8) && elem->point(0) > elem->point(2)) shape=15-i; 00202 00203 switch(shape) 00204 { 00205 case 0: return r*r*r; 00206 case 1: return x*x*x; 00207 case 2: return y*y*y; 00208 00209 case 3: return 3.*x*r*r; 00210 case 4: return 3.*x*x*r; 00211 00212 case 5: return 3.*y*x*x; 00213 case 6: return 3.*y*y*x; 00214 00215 case 7: return 3.*y*r*r; 00216 case 8: return 3.*y*y*r; 00217 00218 case 9: return 6.*x*y*r; 00219 00220 default: 00221 libmesh_error_msg("Invalid shape function index shape = " << shape); 00222 } 00223 } 00224 case FOURTH: 00225 { 00226 const Real x=p(0); 00227 const Real y=p(1); 00228 const Real r=1-x-y; 00229 unsigned int shape=i; 00230 00231 libmesh_assert_less (i, 15); 00232 00233 if((i==3||i== 5) && elem->point(0) > elem->point(1))shape=8-i; 00234 if((i==6||i== 8) && elem->point(1) > elem->point(2))shape=14-i; 00235 if((i==9||i==11) && elem->point(0) > elem->point(2))shape=20-i; 00236 00237 00238 switch(shape) 00239 { 00240 // point functions 00241 case 0: return r*r*r*r; 00242 case 1: return x*x*x*x; 00243 case 2: return y*y*y*y; 00244 00245 // edge functions 00246 case 3: return 4.*x*r*r*r; 00247 case 4: return 6.*x*x*r*r; 00248 case 5: return 4.*x*x*x*r; 00249 00250 case 6: return 4.*y*x*x*x; 00251 case 7: return 6.*y*y*x*x; 00252 case 8: return 4.*y*y*y*x; 00253 00254 case 9: return 4.*y*r*r*r; 00255 case 10: return 6.*y*y*r*r; 00256 case 11: return 4.*y*y*y*r; 00257 00258 // inner functions 00259 case 12: return 12.*x*y*r*r; 00260 case 13: return 12.*x*x*y*r; 00261 case 14: return 12.*x*y*y*r; 00262 00263 default: 00264 libmesh_error_msg("Invalid shape function index shape = " << shape); 00265 } 00266 } 00267 case FIFTH: 00268 { 00269 const Real x=p(0); 00270 const Real y=p(1); 00271 const Real r=1-x-y; 00272 unsigned int shape=i; 00273 00274 libmesh_assert_less (i, 21); 00275 00276 if((i>= 3&&i<= 6) && elem->point(0) > elem->point(1))shape=9-i; 00277 if((i>= 7&&i<=10) && elem->point(1) > elem->point(2))shape=17-i; 00278 if((i>=11&&i<=14) && elem->point(0) > elem->point(2))shape=25-i; 00279 00280 switch(shape) 00281 { 00282 //point functions 00283 case 0: return pow<5>(r); 00284 case 1: return pow<5>(x); 00285 case 2: return pow<5>(y); 00286 00287 //edge functions 00288 case 3: return 5.*x *pow<4>(r); 00289 case 4: return 10.*pow<2>(x)*pow<3>(r); 00290 case 5: return 10.*pow<3>(x)*pow<2>(r); 00291 case 6: return 5.*pow<4>(x)*r; 00292 00293 case 7: return 5.*y *pow<4>(x); 00294 case 8: return 10.*pow<2>(y)*pow<3>(x); 00295 case 9: return 10.*pow<3>(y)*pow<2>(x); 00296 case 10: return 5.*pow<4>(y)*x; 00297 00298 case 11: return 5.*y *pow<4>(r); 00299 case 12: return 10.*pow<2>(y)*pow<3>(r); 00300 case 13: return 10.*pow<3>(y)*pow<2>(r); 00301 case 14: return 5.*pow<4>(y)*r; 00302 00303 //inner functions 00304 case 15: return 20.*x*y*pow<3>(r); 00305 case 16: return 30.*x*pow<2>(y)*pow<2>(r); 00306 case 17: return 30.*pow<2>(x)*y*pow<2>(r); 00307 case 18: return 20.*x*pow<3>(y)*r; 00308 case 19: return 20.*pow<3>(x)*y*r; 00309 case 20: return 30.*pow<2>(x)*pow<2>(y)*r; 00310 00311 default: 00312 libmesh_error_msg("Invalid shape function index shape = " << shape); 00313 } 00314 } 00315 case SIXTH: 00316 { 00317 const Real x=p(0); 00318 const Real y=p(1); 00319 const Real r=1-x-y; 00320 unsigned int shape=i; 00321 00322 libmesh_assert_less (i, 28); 00323 00324 if((i>= 3&&i<= 7) && elem->point(0) > elem->point(1))shape=10-i; 00325 if((i>= 8&&i<=12) && elem->point(1) > elem->point(2))shape=20-i; 00326 if((i>=13&&i<=17) && elem->point(0) > elem->point(2))shape=30-i; 00327 00328 switch(shape) 00329 { 00330 //point functions 00331 case 0: return pow<6>(r); 00332 case 1: return pow<6>(x); 00333 case 2: return pow<6>(y); 00334 00335 //edge functions 00336 case 3: return 6.*x *pow<5>(r); 00337 case 4: return 15.*pow<2>(x)*pow<4>(r); 00338 case 5: return 20.*pow<3>(x)*pow<3>(r); 00339 case 6: return 15.*pow<4>(x)*pow<2>(r); 00340 case 7: return 6.*pow<5>(x)*r; 00341 00342 case 8: return 6.*y *pow<5>(x); 00343 case 9: return 15.*pow<2>(y)*pow<4>(x); 00344 case 10: return 20.*pow<3>(y)*pow<3>(x); 00345 case 11: return 15.*pow<4>(y)*pow<2>(x); 00346 case 12: return 6.*pow<5>(y)*x; 00347 00348 case 13: return 6.*y *pow<5>(r); 00349 case 14: return 15.*pow<2>(y)*pow<4>(r); 00350 case 15: return 20.*pow<3>(y)*pow<3>(r); 00351 case 16: return 15.*pow<4>(y)*pow<2>(r); 00352 case 17: return 6.*pow<5>(y)*r; 00353 00354 //inner functions 00355 case 18: return 30.*x*y*pow<4>(r); 00356 case 19: return 60.*x*pow<2>(y)*pow<3>(r); 00357 case 20: return 60.* pow<2>(x)*y*pow<3>(r); 00358 case 21: return 60.*x*pow<3>(y)*pow<2>(r); 00359 case 22: return 60.*pow<3>(x)*y*pow<2>(r); 00360 case 23: return 90.*pow<2>(x)*pow<2>(y)*pow<2>(r); 00361 case 24: return 30.*x*pow<4>(y)*r; 00362 case 25: return 60.*pow<2>(x)*pow<3>(y)*r; 00363 case 26: return 60.*pow<3>(x)*pow<2>(y)*r; 00364 case 27: return 30.*pow<4>(x)*y*r; 00365 00366 default: 00367 libmesh_error_msg("Invalid shape function index shape = " << shape); 00368 } // switch shape 00369 } // case TRI6 00370 default: 00371 libmesh_error_msg("Invalid totalorder = " << totalorder); 00372 } // switch order 00373 00374 default: 00375 libmesh_error_msg("ERROR: Unsupported element type = " << type); 00376 } // switch type 00377 00378 libmesh_error_msg("We'll never get here!"); 00379 return 0.; 00380 } 00381 00382 00383 00384 template <> 00385 Real FE<2,BERNSTEIN>::shape_deriv(const ElemType, 00386 const Order, 00387 const unsigned int, 00388 const unsigned int, 00389 const Point&) 00390 { 00391 libmesh_error_msg("Bernstein polynomials require the element type \nbecause edge orientation is needed."); 00392 return 0.; 00393 } 00394 00395 00396 00397 template <> 00398 Real FE<2,BERNSTEIN>::shape_deriv(const Elem* elem, 00399 const Order order, 00400 const unsigned int i, 00401 const unsigned int j, 00402 const Point& p) 00403 { 00404 libmesh_assert(elem); 00405 00406 const ElemType type = elem->type(); 00407 00408 const Order totalorder = static_cast<Order>(order + elem->p_level()); 00409 00410 switch (type) 00411 { 00412 // Hierarchic shape functions on the quadrilateral. 00413 case QUAD4: 00414 case QUAD9: 00415 { 00416 // Compute quad shape functions as a tensor-product 00417 const Real xi = p(0); 00418 const Real eta = p(1); 00419 00420 libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); 00421 00422 unsigned int i0, i1; 00423 00424 // Vertex DoFs 00425 if (i == 0) 00426 { i0 = 0; i1 = 0; } 00427 else if (i == 1) 00428 { i0 = 1; i1 = 0; } 00429 else if (i == 2) 00430 { i0 = 1; i1 = 1; } 00431 else if (i == 3) 00432 { i0 = 0; i1 = 1; } 00433 00434 00435 // Edge DoFs 00436 else if (i < totalorder + 3u) 00437 { i0 = i - 2; i1 = 0; } 00438 else if (i < 2u*totalorder + 2) 00439 { i0 = 1; i1 = i - totalorder - 1; } 00440 else if (i < 3u*totalorder + 1) 00441 { i0 = i - 2u*totalorder; i1 = 1; } 00442 else if (i < 4u*totalorder) 00443 { i0 = 0; i1 = i - 3u*totalorder + 1; } 00444 // Interior DoFs 00445 else 00446 { 00447 unsigned int basisnum = i - 4*totalorder; 00448 i0 = square_number_column[basisnum] + 2; 00449 i1 = square_number_row[basisnum] + 2; 00450 } 00451 00452 00453 // Flip odd degree of freedom values if necessary 00454 // to keep continuity on sides 00455 if ((i>= 4 && i<= 4+ totalorder-2u) && elem->point(0) > elem->point(1)) i0=totalorder+2-i0;// 00456 else if((i>= 4+ totalorder-1u && i<= 4+2*totalorder-3u) && elem->point(1) > elem->point(2)) i1=totalorder+2-i1; 00457 else if((i>= 4+2*totalorder-2u && i<= 4+3*totalorder-4u) && elem->point(3) > elem->point(2)) i0=totalorder+2-i0; 00458 else if((i>= 4+3*totalorder-3u && i<= 4+4*totalorder-5u) && elem->point(0) > elem->point(3)) i1=totalorder+2-i1; 00459 00460 switch (j) 00461 { 00462 // d()/dxi 00463 case 0: 00464 return (FE<1,BERNSTEIN>::shape_deriv(EDGE3, totalorder, i0, 0, xi)* 00465 FE<1,BERNSTEIN>::shape (EDGE3, totalorder, i1, eta)); 00466 00467 // d()/deta 00468 case 1: 00469 return (FE<1,BERNSTEIN>::shape (EDGE3, totalorder, i0, xi)* 00470 FE<1,BERNSTEIN>::shape_deriv(EDGE3, totalorder, i1, 0, eta)); 00471 00472 default: 00473 libmesh_error_msg("Invalid shape function derivative j = " << j); 00474 } 00475 } 00476 00477 // Bernstein shape functions on the 8-noded quadrilateral 00478 // is handled separately. 00479 case QUAD8: 00480 { 00481 libmesh_assert_less (totalorder, 3); 00482 00483 const Real xi = p(0); 00484 const Real eta = p(1); 00485 00486 libmesh_assert_less (i, 8); 00487 00488 // 0 1 2 3 4 5 6 7 8 00489 static const unsigned int i0[] = {0, 1, 1, 0, 2, 1, 2, 0, 2}; 00490 static const unsigned int i1[] = {0, 0, 1, 1, 0, 2, 1, 2, 2}; 00491 static const Real scal[] = {-0.25, -0.25, -0.25, -0.25, 0.5, 0.5, 0.5, 0.5}; 00492 switch (j) 00493 { 00494 // d()/dxi 00495 case 0: 00496 return (FE<1,BERNSTEIN>::shape_deriv(EDGE3, totalorder, i0[i], 0, xi)* 00497 FE<1,BERNSTEIN>::shape (EDGE3, totalorder, i1[i], eta) 00498 +scal[i]* 00499 FE<1,BERNSTEIN>::shape_deriv(EDGE3, totalorder, i0[8], 0, xi)* 00500 FE<1,BERNSTEIN>::shape (EDGE3, totalorder, i1[8], eta)); 00501 00502 // d()/deta 00503 case 1: 00504 return (FE<1,BERNSTEIN>::shape (EDGE3, totalorder, i0[i], xi)* 00505 FE<1,BERNSTEIN>::shape_deriv(EDGE3, totalorder, i1[i], 0, eta) 00506 +scal[i]* 00507 FE<1,BERNSTEIN>::shape (EDGE3, totalorder, i0[8], xi)* 00508 FE<1,BERNSTEIN>::shape_deriv(EDGE3, totalorder, i1[8], 0, eta)); 00509 00510 default: 00511 libmesh_error_msg("Invalid shape function derivative j = " << j); 00512 } 00513 } 00514 00515 case TRI3: 00516 libmesh_assert_less (totalorder, 2); 00517 case TRI6: 00518 { 00519 // I have been lazy here and am using finite differences 00520 // to compute the derivatives! 00521 const Real eps = 1.e-6; 00522 00523 switch (j) 00524 { 00525 // d()/dxi 00526 case 0: 00527 { 00528 const Point pp(p(0)+eps, p(1)); 00529 const Point pm(p(0)-eps, p(1)); 00530 00531 return (FE<2,BERNSTEIN>::shape(elem, totalorder, i, pp) - 00532 FE<2,BERNSTEIN>::shape(elem, totalorder, i, pm))/2./eps; 00533 } 00534 00535 // d()/deta 00536 case 1: 00537 { 00538 const Point pp(p(0), p(1)+eps); 00539 const Point pm(p(0), p(1)-eps); 00540 00541 return (FE<2,BERNSTEIN>::shape(elem, totalorder, i, pp) - 00542 FE<2,BERNSTEIN>::shape(elem, totalorder, i, pm))/2./eps; 00543 } 00544 00545 00546 default: 00547 libmesh_error_msg("Invalid shape function derivative j = " << j); 00548 } 00549 } 00550 00551 default: 00552 libmesh_error_msg("ERROR: Unsupported element type = " << type); 00553 } 00554 00555 libmesh_error_msg("We'll never get here!"); 00556 return 0.; 00557 } 00558 00559 00560 00561 template <> 00562 Real FE<2,BERNSTEIN>::shape_second_deriv(const ElemType, 00563 const Order, 00564 const unsigned int, 00565 const unsigned int, 00566 const Point&) 00567 { 00568 static bool warning_given = false; 00569 00570 if (!warning_given) 00571 libMesh::err << "Second derivatives for Bernstein elements " 00572 << "are not yet implemented!" 00573 << std::endl; 00574 00575 warning_given = true; 00576 return 0.; 00577 } 00578 00579 00580 00581 template <> 00582 Real FE<2,BERNSTEIN>::shape_second_deriv(const Elem*, 00583 const Order, 00584 const unsigned int, 00585 const unsigned int, 00586 const Point&) 00587 { 00588 static bool warning_given = false; 00589 00590 if (!warning_given) 00591 libMesh::err << "Second derivatives for Bernstein elements " 00592 << "are not yet implemented!" 00593 << std::endl; 00594 00595 warning_given = true; 00596 return 0.; 00597 } 00598 00599 } // namespace libMesh 00600 00601 00602 #endif// LIBMESH_ENABLE_HIGHER_ORDER_SHAPES