$extrastylesheet
fe_bernstein_shape_2D.C
Go to the documentation of this file.
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