$extrastylesheet
fe_l2_hierarchic_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 // C++ includes
00020 
00021 // Local includes
00022 #include "libmesh/fe.h"
00023 #include "libmesh/elem.h"
00024 #include "libmesh/number_lookups.h"
00025 #include "libmesh/utility.h"
00026 
00027 
00028 namespace libMesh
00029 {
00030 
00031 template <>
00032 Real FE<2,L2_HIERARCHIC>::shape(const ElemType,
00033                                 const Order,
00034                                 const unsigned int,
00035                                 const Point&)
00036 {
00037   libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge orientation is needed.");
00038   return 0.;
00039 }
00040 
00041 
00042 
00043 template <>
00044 Real FE<2,L2_HIERARCHIC>::shape(const Elem* elem,
00045                                 const Order order,
00046                                 const unsigned int i,
00047                                 const Point& p)
00048 {
00049   libmesh_assert(elem);
00050 
00051   const Order totalorder = static_cast<Order>(order+elem->p_level());
00052   libmesh_assert_greater (totalorder, 0);
00053 
00054   switch (elem->type())
00055     {
00056     case TRI3:
00057     case TRI6:
00058       {
00059         const Real zeta1 = p(0);
00060         const Real zeta2 = p(1);
00061         const Real zeta0 = 1. - zeta1 - zeta2;
00062 
00063         libmesh_assert_less (i, (totalorder+1u)*(totalorder+2u)/2);
00064         libmesh_assert (elem->type() == TRI6 || totalorder < 2);
00065 
00066         // Vertex DoFs
00067         if (i == 0)
00068           return zeta0;
00069         else if (i == 1)
00070           return zeta1;
00071         else if (i == 2)
00072           return zeta2;
00073         // Edge DoFs
00074         else if (i < totalorder + 2u)
00075           {
00076             // Avoid returning NaN on vertices!
00077             if (zeta0 + zeta1 == 0.)
00078               return 0.;
00079 
00080             const unsigned int basisorder = i - 1;
00081             // Get factors to account for edge-flipping
00082             Real f0 = 1;
00083             if (basisorder%2 && (elem->point(0) > elem->point(1)))
00084               f0 = -1.;
00085 
00086             Real edgeval = (zeta1 - zeta0) / (zeta1 + zeta0);
00087             Real crossfunc = zeta0 + zeta1;
00088             for (unsigned int n=1; n != basisorder; ++n)
00089               crossfunc *= (zeta0 + zeta1);
00090 
00091             return f0 * crossfunc *
00092               FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder,
00093                                          basisorder, edgeval);
00094           }
00095         else if (i < 2u*totalorder + 1)
00096           {
00097             // Avoid returning NaN on vertices!
00098             if (zeta1 + zeta2 == 0.)
00099               return 0.;
00100 
00101             const unsigned int basisorder = i - totalorder;
00102             // Get factors to account for edge-flipping
00103             Real f1 = 1;
00104             if (basisorder%2 && (elem->point(1) > elem->point(2)))
00105               f1 = -1.;
00106 
00107             Real edgeval = (zeta2 - zeta1) / (zeta2 + zeta1);
00108             Real crossfunc = zeta2 + zeta1;
00109             for (unsigned int n=1; n != basisorder; ++n)
00110               crossfunc *= (zeta2 + zeta1);
00111 
00112             return f1 * crossfunc *
00113               FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder,
00114                                          basisorder, edgeval);
00115           }
00116         else if (i < 3u*totalorder)
00117           {
00118             // Avoid returning NaN on vertices!
00119             if (zeta0 + zeta2 == 0.)
00120               return 0.;
00121 
00122             const unsigned int basisorder = i - (2u*totalorder) + 1;
00123             // Get factors to account for edge-flipping
00124             Real f2 = 1;
00125             if (basisorder%2 && (elem->point(2) > elem->point(0)))
00126               f2 = -1.;
00127 
00128             Real edgeval = (zeta0 - zeta2) / (zeta0 + zeta2);
00129             Real crossfunc = zeta0 + zeta2;
00130             for (unsigned int n=1; n != basisorder; ++n)
00131               crossfunc *= (zeta0 + zeta2);
00132 
00133             return f2 * crossfunc *
00134               FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder,
00135                                          basisorder, edgeval);
00136           }
00137         // Interior DoFs
00138         else
00139           {
00140             const unsigned int basisnum = i - (3u*totalorder);
00141             unsigned int exp0 = triangular_number_column[basisnum] + 1;
00142             unsigned int exp1 = triangular_number_row[basisnum] + 1 -
00143               triangular_number_column[basisnum];
00144 
00145             Real returnval = 1;
00146             for (unsigned int n = 0; n != exp0; ++n)
00147               returnval *= zeta0;
00148             for (unsigned int n = 0; n != exp1; ++n)
00149               returnval *= zeta1;
00150             returnval *= zeta2;
00151             return returnval;
00152           }
00153       }
00154 
00155       // Hierarchic shape functions on the quadrilateral.
00156     case QUAD4:
00157       libmesh_assert_less (totalorder, 2);
00158     case QUAD8:
00159     case QUAD9:
00160       {
00161         // Compute quad shape functions as a tensor-product
00162         const Real xi  = p(0);
00163         const Real eta = p(1);
00164 
00165         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u));
00166 
00167         // Example i, i0, i1 values for totalorder = 5:
00168         //                                    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
00169         //  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};
00170         //  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};
00171 
00172         unsigned int i0, i1;
00173 
00174         // Vertex DoFs
00175         if (i == 0)
00176           { i0 = 0; i1 = 0; }
00177         else if (i == 1)
00178           { i0 = 1; i1 = 0; }
00179         else if (i == 2)
00180           { i0 = 1; i1 = 1; }
00181         else if (i == 3)
00182           { i0 = 0; i1 = 1; }
00183         // Edge DoFs
00184         else if (i < totalorder + 3u)
00185           { i0 = i - 2; i1 = 0; }
00186         else if (i < 2u*totalorder + 2)
00187           { i0 = 1; i1 = i - totalorder - 1; }
00188         else if (i < 3u*totalorder + 1)
00189           { i0 = i - 2u*totalorder; i1 = 1; }
00190         else if (i < 4u*totalorder)
00191           { i0 = 0; i1 = i - 3u*totalorder + 1; }
00192         // Interior DoFs
00193         else
00194           {
00195             unsigned int basisnum = i - 4*totalorder;
00196             i0 = square_number_column[basisnum] + 2;
00197             i1 = square_number_row[basisnum] + 2;
00198           }
00199 
00200         // Flip odd degree of freedom values if necessary
00201         // to keep continuity on sides
00202         Real f = 1.;
00203 
00204         if ((i0%2) && (i0 > 2) && (i1 == 0))
00205           f = (elem->point(0) > elem->point(1))?-1.:1.;
00206         else if ((i0%2) && (i0>2) && (i1 == 1))
00207           f = (elem->point(3) > elem->point(2))?-1.:1.;
00208         else if ((i0 == 0) && (i1%2) && (i1>2))
00209           f = (elem->point(0) > elem->point(3))?-1.:1.;
00210         else if ((i0 == 1) && (i1%2) && (i1>2))
00211           f = (elem->point(1) > elem->point(2))?-1.:1.;
00212 
00213         return f*(FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)*
00214                   FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, i1, eta));
00215       }
00216 
00217     default:
00218       libmesh_error_msg("ERROR: Unsupported element type = " << elem->type());
00219     }
00220 
00221   return 0.;
00222 }
00223 
00224 
00225 
00226 template <>
00227 Real FE<2,L2_HIERARCHIC>::shape_deriv(const ElemType,
00228                                       const Order,
00229                                       const unsigned int,
00230                                       const unsigned int,
00231                                       const Point&)
00232 {
00233   libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge orientation is needed.");
00234   return 0.;
00235 }
00236 
00237 
00238 
00239 template <>
00240 Real FE<2,L2_HIERARCHIC>::shape_deriv(const Elem* elem,
00241                                       const Order order,
00242                                       const unsigned int i,
00243                                       const unsigned int j,
00244                                       const Point& p)
00245 {
00246   libmesh_assert(elem);
00247 
00248   const ElemType type = elem->type();
00249 
00250   const Order totalorder = static_cast<Order>(order+elem->p_level());
00251 
00252   libmesh_assert_greater (totalorder, 0);
00253 
00254   switch (type)
00255     {
00256       // 1st & 2nd-order Hierarchics.
00257     case TRI3:
00258     case TRI6:
00259       {
00260         const Real eps = 1.e-6;
00261 
00262         libmesh_assert_less (j, 2);
00263 
00264         switch (j)
00265           {
00266             //  d()/dxi
00267           case 0:
00268             {
00269               const Point pp(p(0)+eps, p(1));
00270               const Point pm(p(0)-eps, p(1));
00271 
00272               return (FE<2,L2_HIERARCHIC>::shape(elem, order, i, pp) -
00273                       FE<2,L2_HIERARCHIC>::shape(elem, order, i, pm))/2./eps;
00274             }
00275 
00276             // d()/deta
00277           case 1:
00278             {
00279               const Point pp(p(0), p(1)+eps);
00280               const Point pm(p(0), p(1)-eps);
00281 
00282               return (FE<2,L2_HIERARCHIC>::shape(elem, order, i, pp) -
00283                       FE<2,L2_HIERARCHIC>::shape(elem, order, i, pm))/2./eps;
00284             }
00285 
00286 
00287           default:
00288             libmesh_error_msg("Invalid derivative index j = " << j);
00289           }
00290       }
00291 
00292     case QUAD4:
00293       libmesh_assert_less (totalorder, 2);
00294     case QUAD8:
00295     case QUAD9:
00296       {
00297         // Compute quad shape functions as a tensor-product
00298         const Real xi  = p(0);
00299         const Real eta = p(1);
00300 
00301         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u));
00302 
00303         // Example i, i0, i1 values for totalorder = 5:
00304         //                                    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
00305         //  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, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5};
00306         //  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, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
00307 
00308         unsigned int i0, i1;
00309 
00310         // Vertex DoFs
00311         if (i == 0)
00312           { i0 = 0; i1 = 0; }
00313         else if (i == 1)
00314           { i0 = 1; i1 = 0; }
00315         else if (i == 2)
00316           { i0 = 1; i1 = 1; }
00317         else if (i == 3)
00318           { i0 = 0; i1 = 1; }
00319         // Edge DoFs
00320         else if (i < totalorder + 3u)
00321           { i0 = i - 2; i1 = 0; }
00322         else if (i < 2u*totalorder + 2)
00323           { i0 = 1; i1 = i - totalorder - 1; }
00324         else if (i < 3u*totalorder + 1u)
00325           { i0 = i - 2u*totalorder; i1 = 1; }
00326         else if (i < 4u*totalorder)
00327           { i0 = 0; i1 = i - 3u*totalorder + 1; }
00328         // Interior DoFs
00329         else
00330           {
00331             unsigned int basisnum = i - 4*totalorder;
00332             i0 = square_number_column[basisnum] + 2;
00333             i1 = square_number_row[basisnum] + 2;
00334           }
00335 
00336         // Flip odd degree of freedom values if necessary
00337         // to keep continuity on sides
00338         Real f = 1.;
00339 
00340         if ((i0%2) && (i0 > 2) && (i1 == 0))
00341           f = (elem->point(0) > elem->point(1))?-1.:1.;
00342         else if ((i0%2) && (i0>2) && (i1 == 1))
00343           f = (elem->point(3) > elem->point(2))?-1.:1.;
00344         else if ((i0 == 0) && (i1%2) && (i1>2))
00345           f = (elem->point(0) > elem->point(3))?-1.:1.;
00346         else if ((i0 == 1) && (i1%2) && (i1>2))
00347           f = (elem->point(1) > elem->point(2))?-1.:1.;
00348 
00349         switch (j)
00350           {
00351             // d()/dxi
00352           case 0:
00353             return f*(FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i0, 0, xi)*
00354                       FE<1,L2_HIERARCHIC>::shape      (EDGE3, totalorder, i1,    eta));
00355 
00356             // d()/deta
00357           case 1:
00358             return f*(FE<1,L2_HIERARCHIC>::shape      (EDGE3, totalorder, i0,    xi)*
00359                       FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i1, 0, eta));
00360 
00361           default:
00362             libmesh_error_msg("Invalid derivative index j = " << j);
00363           }
00364       }
00365 
00366     default:
00367       libmesh_error_msg("ERROR: Unsupported element type = " << type);
00368     }
00369 
00370   return 0.;
00371 }
00372 
00373 
00374 
00375 template <>
00376 Real FE<2,L2_HIERARCHIC>::shape_second_deriv(const ElemType,
00377                                              const Order,
00378                                              const unsigned int,
00379                                              const unsigned int,
00380                                              const Point&)
00381 {
00382   libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge orientation is needed.");
00383   return 0.;
00384 }
00385 
00386 
00387 
00388 template <>
00389 Real FE<2,L2_HIERARCHIC>::shape_second_deriv(const Elem* elem,
00390                                              const Order order,
00391                                              const unsigned int i,
00392                                              const unsigned int j,
00393                                              const Point& p)
00394 {
00395   libmesh_assert(elem);
00396 
00397   // I have been lazy here and am using finite differences
00398   // to compute the derivatives!
00399   const Real eps = 1.e-6;
00400   Point pp, pm;
00401   unsigned int prevj = libMesh::invalid_uint;
00402 
00403   switch (j)
00404     {
00405       //  d^2()/dxi^2
00406     case 0:
00407       {
00408         pp = Point(p(0)+eps, p(1));
00409         pm = Point(p(0)-eps, p(1));
00410         prevj = 0;
00411         break;
00412       }
00413 
00414       // d^2()/dxideta
00415     case 1:
00416       {
00417         pp = Point(p(0), p(1)+eps);
00418         pm = Point(p(0), p(1)-eps);
00419         prevj = 0;
00420         break;
00421       }
00422 
00423       // d^2()/deta^2
00424     case 2:
00425       {
00426         pp = Point(p(0), p(1)+eps);
00427         pm = Point(p(0), p(1)-eps);
00428         prevj = 1;
00429         break;
00430       }
00431     default:
00432       libmesh_error_msg("Invalid derivative index j = " << j);
00433     }
00434   return (FE<2,L2_HIERARCHIC>::shape_deriv(elem, order, i, prevj, pp) -
00435           FE<2,L2_HIERARCHIC>::shape_deriv(elem, order, i, prevj, pm)
00436           )/2./eps;
00437 }
00438 
00439 } // namespace libMesh