$extrastylesheet
fe_hierarchic_shape_3D.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 
00026 namespace libMesh
00027 {
00028 
00029 // anonymous namespace for local helper functions
00030 namespace
00031 {
00032 
00033 Point get_min_point(const Elem *elem,
00034                     unsigned int a,
00035                     unsigned int b,
00036                     unsigned int c,
00037                     unsigned int d)
00038 {
00039   return std::min(std::min(elem->point(a),elem->point(b)),
00040                   std::min(elem->point(c),elem->point(d)));
00041 }
00042 
00043 void cube_indices(const Elem *elem,
00044                   const unsigned int totalorder,
00045                   const unsigned int i,
00046                   Real &xi, Real &eta, Real &zeta,
00047                   unsigned int &i0,
00048                   unsigned int &i1,
00049                   unsigned int &i2)
00050 {
00051   // The only way to make any sense of this
00052   // is to look at the mgflo/mg2/mgf documentation
00053   // and make the cut-out cube!
00054   // Example i0 and i1 values for totalorder = 3:
00055   // FIXME - these examples are incorrect now that we've got truly
00056   // hierarchic basis functions
00057   //     Nodes                         0  1  2  3  4  5  6  7  8  8  9  9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 20 20 21 21 21 21 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 26 26 26 26
00058   //     DOFS                          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 18 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 60 62 63
00059   // static const unsigned int i0[] = {0, 1, 1, 0, 0, 1, 1, 0, 2, 3, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 3, 1, 1, 2, 3, 0, 0, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3};
00060   // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 3, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 3, 1, 1, 2, 3, 2, 2, 3, 3, 0, 0, 0, 0, 2, 3, 2, 3, 1, 1, 1, 1, 2, 3, 2, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3};
00061   // static const unsigned int i2[] = {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3};
00062 
00063   // the number of DoFs per edge appears everywhere:
00064   const unsigned int e = totalorder - 1u;
00065 
00066   libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
00067 
00068   Real xi_saved = xi, eta_saved = eta, zeta_saved = zeta;
00069 
00070   // Vertices:
00071   if (i == 0)
00072     {
00073       i0 = 0;
00074       i1 = 0;
00075       i2 = 0;
00076     }
00077   else if (i == 1)
00078     {
00079       i0 = 1;
00080       i1 = 0;
00081       i2 = 0;
00082     }
00083   else if (i == 2)
00084     {
00085       i0 = 1;
00086       i1 = 1;
00087       i2 = 0;
00088     }
00089   else if (i == 3)
00090     {
00091       i0 = 0;
00092       i1 = 1;
00093       i2 = 0;
00094     }
00095   else if (i == 4)
00096     {
00097       i0 = 0;
00098       i1 = 0;
00099       i2 = 1;
00100     }
00101   else if (i == 5)
00102     {
00103       i0 = 1;
00104       i1 = 0;
00105       i2 = 1;
00106     }
00107   else if (i == 6)
00108     {
00109       i0 = 1;
00110       i1 = 1;
00111       i2 = 1;
00112     }
00113   else if (i == 7)
00114     {
00115       i0 = 0;
00116       i1 = 1;
00117       i2 = 1;
00118     }
00119   // Edge 0
00120   else if (i < 8 + e)
00121     {
00122       i0 = i - 6;
00123       i1 = 0;
00124       i2 = 0;
00125       if (elem->point(0) > elem->point(1))
00126         xi = -xi_saved;
00127     }
00128   // Edge 1
00129   else if (i < 8 + 2*e)
00130     {
00131       i0 = 1;
00132       i1 = i - e - 6;
00133       i2 = 0;
00134       if (elem->point(1) > elem->point(2))
00135         eta = -eta_saved;
00136     }
00137   // Edge 2
00138   else if (i < 8 + 3*e)
00139     {
00140       i0 = i - 2*e - 6;
00141       i1 = 1;
00142       i2 = 0;
00143       if (elem->point(3) > elem->point(2))
00144         xi = -xi_saved;
00145     }
00146   // Edge 3
00147   else if (i < 8 + 4*e)
00148     {
00149       i0 = 0;
00150       i1 = i - 3*e - 6;
00151       i2 = 0;
00152       if (elem->point(0) > elem->point(3))
00153         eta = -eta_saved;
00154     }
00155   // Edge 4
00156   else if (i < 8 + 5*e)
00157     {
00158       i0 = 0;
00159       i1 = 0;
00160       i2 = i - 4*e - 6;
00161       if (elem->point(0) > elem->point(4))
00162         zeta = -zeta_saved;
00163     }
00164   // Edge 5
00165   else if (i < 8 + 6*e)
00166     {
00167       i0 = 1;
00168       i1 = 0;
00169       i2 = i - 5*e - 6;
00170       if (elem->point(1) > elem->point(5))
00171         zeta = -zeta_saved;
00172     }
00173   // Edge 6
00174   else if (i < 8 + 7*e)
00175     {
00176       i0 = 1;
00177       i1 = 1;
00178       i2 = i - 6*e - 6;
00179       if (elem->point(2) > elem->point(6))
00180         zeta = -zeta_saved;
00181     }
00182   // Edge 7
00183   else if (i < 8 + 8*e)
00184     {
00185       i0 = 0;
00186       i1 = 1;
00187       i2 = i - 7*e - 6;
00188       if (elem->point(3) > elem->point(7))
00189         zeta = -zeta_saved;
00190     }
00191   // Edge 8
00192   else if (i < 8 + 9*e)
00193     {
00194       i0 = i - 8*e - 6;
00195       i1 = 0;
00196       i2 = 1;
00197       if (elem->point(4) > elem->point(5))
00198         xi = -xi_saved;
00199     }
00200   // Edge 9
00201   else if (i < 8 + 10*e)
00202     {
00203       i0 = 1;
00204       i1 = i - 9*e - 6;
00205       i2 = 1;
00206       if (elem->point(5) > elem->point(6))
00207         eta = -eta_saved;
00208     }
00209   // Edge 10
00210   else if (i < 8 + 11*e)
00211     {
00212       i0 = i - 10*e - 6;
00213       i1 = 1;
00214       i2 = 1;
00215       if (elem->point(7) > elem->point(6))
00216         xi = -xi_saved;
00217     }
00218   // Edge 11
00219   else if (i < 8 + 12*e)
00220     {
00221       i0 = 0;
00222       i1 = i - 11*e - 6;
00223       i2 = 1;
00224       if (elem->point(4) > elem->point(7))
00225         eta = -eta_saved;
00226     }
00227   // Face 0
00228   else if (i < 8 + 12*e + e*e)
00229     {
00230       unsigned int basisnum = i - 8 - 12*e;
00231       i0 = square_number_row[basisnum] + 2;
00232       i1 = square_number_column[basisnum] + 2;
00233       i2 = 0;
00234       const Point min_point = get_min_point(elem, 1, 2, 0, 3);
00235 
00236       if (elem->point(0) == min_point)
00237         if (elem->point(1) == std::min(elem->point(1), elem->point(3)))
00238           {
00239             // Case 1
00240             xi  = xi_saved;
00241             eta = eta_saved;
00242           }
00243         else
00244           {
00245             // Case 2
00246             xi  = eta_saved;
00247             eta = xi_saved;
00248           }
00249 
00250       else if (elem->point(3) == min_point)
00251         if (elem->point(0) == std::min(elem->point(0), elem->point(2)))
00252           {
00253             // Case 3
00254             xi  = -eta_saved;
00255             eta = xi_saved;
00256           }
00257         else
00258           {
00259             // Case 4
00260             xi  = xi_saved;
00261             eta = -eta_saved;
00262           }
00263 
00264       else if (elem->point(2) == min_point)
00265         if (elem->point(3) == std::min(elem->point(3), elem->point(1)))
00266           {
00267             // Case 5
00268             xi  = -xi_saved;
00269             eta = -eta_saved;
00270           }
00271         else
00272           {
00273             // Case 6
00274             xi  = -eta_saved;
00275             eta = -xi_saved;
00276           }
00277 
00278       else if (elem->point(1) == min_point)
00279         {
00280           if (elem->point(2) == std::min(elem->point(2), elem->point(0)))
00281             {
00282               // Case 7
00283               xi  = eta_saved;
00284               eta = -xi_saved;
00285             }
00286           else
00287             {
00288               // Case 8
00289               xi  = -xi_saved;
00290               eta = eta_saved;
00291             }
00292         }
00293     }
00294   // Face 1
00295   else if (i < 8 + 12*e + 2*e*e)
00296     {
00297       unsigned int basisnum = i - 8 - 12*e - e*e;
00298       i0 = square_number_row[basisnum] + 2;
00299       i1 = 0;
00300       i2 = square_number_column[basisnum] + 2;
00301       const Point min_point = get_min_point(elem, 0, 1, 5, 4);
00302 
00303       if (elem->point(0) == min_point)
00304         if (elem->point(1) == std::min(elem->point(1), elem->point(4)))
00305           {
00306             // Case 1
00307             xi   = xi_saved;
00308             zeta = zeta_saved;
00309           }
00310         else
00311           {
00312             // Case 2
00313             xi   = zeta_saved;
00314             zeta = xi_saved;
00315           }
00316 
00317       else if (elem->point(1) == min_point)
00318         if (elem->point(5) == std::min(elem->point(5), elem->point(0)))
00319           {
00320             // Case 3
00321             xi   = zeta_saved;
00322             zeta = -xi_saved;
00323           }
00324         else
00325           {
00326             // Case 4
00327             xi   = -xi_saved;
00328             zeta = zeta_saved;
00329           }
00330 
00331       else if (elem->point(5) == min_point)
00332         if (elem->point(4) == std::min(elem->point(4), elem->point(1)))
00333           {
00334             // Case 5
00335             xi   = -xi_saved;
00336             zeta = -zeta_saved;
00337           }
00338         else
00339           {
00340             // Case 6
00341             xi   = -zeta_saved;
00342             zeta = -xi_saved;
00343           }
00344 
00345       else if (elem->point(4) == min_point)
00346         {
00347           if (elem->point(0) == std::min(elem->point(0), elem->point(5)))
00348             {
00349               // Case 7
00350               xi   = -xi_saved;
00351               zeta = zeta_saved;
00352             }
00353           else
00354             {
00355               // Case 8
00356               xi   = xi_saved;
00357               zeta = -zeta_saved;
00358             }
00359         }
00360     }
00361   // Face 2
00362   else if (i < 8 + 12*e + 3*e*e)
00363     {
00364       unsigned int basisnum = i - 8 - 12*e - 2*e*e;
00365       i0 = 1;
00366       i1 = square_number_row[basisnum] + 2;
00367       i2 = square_number_column[basisnum] + 2;
00368       const Point min_point = get_min_point(elem, 1, 2, 6, 5);
00369 
00370       if (elem->point(1) == min_point)
00371         if (elem->point(2) == std::min(elem->point(2), elem->point(5)))
00372           {
00373             // Case 1
00374             eta  = eta_saved;
00375             zeta = zeta_saved;
00376           }
00377         else
00378           {
00379             // Case 2
00380             eta  = zeta_saved;
00381             zeta = eta_saved;
00382           }
00383 
00384       else if (elem->point(2) == min_point)
00385         if (elem->point(6) == std::min(elem->point(6), elem->point(1)))
00386           {
00387             // Case 3
00388             eta  = zeta_saved;
00389             zeta = -eta_saved;
00390           }
00391         else
00392           {
00393             // Case 4
00394             eta  = -eta_saved;
00395             zeta = zeta_saved;
00396           }
00397 
00398       else if (elem->point(6) == min_point)
00399         if (elem->point(5) == std::min(elem->point(5), elem->point(2)))
00400           {
00401             // Case 5
00402             eta  = -eta_saved;
00403             zeta = -zeta_saved;
00404           }
00405         else
00406           {
00407             // Case 6
00408             eta  = -zeta_saved;
00409             zeta = -eta_saved;
00410           }
00411 
00412       else if (elem->point(5) == min_point)
00413         {
00414           if (elem->point(1) == std::min(elem->point(1), elem->point(6)))
00415             {
00416               // Case 7
00417               eta  = -zeta_saved;
00418               zeta = eta_saved;
00419             }
00420           else
00421             {
00422               // Case 8
00423               eta   = eta_saved;
00424               zeta = -zeta_saved;
00425             }
00426         }
00427     }
00428   // Face 3
00429   else if (i < 8 + 12*e + 4*e*e)
00430     {
00431       unsigned int basisnum = i - 8 - 12*e - 3*e*e;
00432       i0 = square_number_row[basisnum] + 2;
00433       i1 = 1;
00434       i2 = square_number_column[basisnum] + 2;
00435       const Point min_point = get_min_point(elem, 2, 3, 7, 6);
00436 
00437       if (elem->point(3) == min_point)
00438         if (elem->point(2) == std::min(elem->point(2), elem->point(7)))
00439           {
00440             // Case 1
00441             xi   = xi_saved;
00442             zeta = zeta_saved;
00443           }
00444         else
00445           {
00446             // Case 2
00447             xi   = zeta_saved;
00448             zeta = xi_saved;
00449           }
00450 
00451       else if (elem->point(7) == min_point)
00452         if (elem->point(3) == std::min(elem->point(3), elem->point(6)))
00453           {
00454             // Case 3
00455             xi   = -zeta_saved;
00456             zeta = xi_saved;
00457           }
00458         else
00459           {
00460             // Case 4
00461             xi   = xi_saved;
00462             zeta = -zeta_saved;
00463           }
00464 
00465       else if (elem->point(6) == min_point)
00466         if (elem->point(7) == std::min(elem->point(7), elem->point(2)))
00467           {
00468             // Case 5
00469             xi   = -xi_saved;
00470             zeta = -zeta_saved;
00471           }
00472         else
00473           {
00474             // Case 6
00475             xi   = -zeta_saved;
00476             zeta = -xi_saved;
00477           }
00478 
00479       else if (elem->point(2) == min_point)
00480         {
00481           if (elem->point(6) == std::min(elem->point(3), elem->point(6)))
00482             {
00483               // Case 7
00484               xi   = zeta_saved;
00485               zeta = -xi_saved;
00486             }
00487           else
00488             {
00489               // Case 8
00490               xi   = -xi_saved;
00491               zeta = zeta_saved;
00492             }
00493         }
00494     }
00495   // Face 4
00496   else if (i < 8 + 12*e + 5*e*e)
00497     {
00498       unsigned int basisnum = i - 8 - 12*e - 4*e*e;
00499       i0 = 0;
00500       i1 = square_number_row[basisnum] + 2;
00501       i2 = square_number_column[basisnum] + 2;
00502       const Point min_point = get_min_point(elem, 3, 0, 4, 7);
00503 
00504       if (elem->point(0) == min_point)
00505         if (elem->point(3) == std::min(elem->point(3), elem->point(4)))
00506           {
00507             // Case 1
00508             eta  = eta_saved;
00509             zeta = zeta_saved;
00510           }
00511         else
00512           {
00513             // Case 2
00514             eta  = zeta_saved;
00515             zeta = eta_saved;
00516           }
00517 
00518       else if (elem->point(4) == min_point)
00519         if (elem->point(0) == std::min(elem->point(0), elem->point(7)))
00520           {
00521             // Case 3
00522             eta  = -zeta_saved;
00523             zeta = eta_saved;
00524           }
00525         else
00526           {
00527             // Case 4
00528             eta  = eta_saved;
00529             zeta = -zeta_saved;
00530           }
00531 
00532       else if (elem->point(7) == min_point)
00533         if (elem->point(4) == std::min(elem->point(4), elem->point(3)))
00534           {
00535             // Case 5
00536             eta  = -eta_saved;
00537             zeta = -zeta_saved;
00538           }
00539         else
00540           {
00541             // Case 6
00542             eta  = -zeta_saved;
00543             zeta = -eta_saved;
00544           }
00545 
00546       else if (elem->point(3) == min_point)
00547         {
00548           if (elem->point(7) == std::min(elem->point(7), elem->point(0)))
00549             {
00550               // Case 7
00551               eta   = zeta_saved;
00552               zeta = -eta_saved;
00553             }
00554           else
00555             {
00556               // Case 8
00557               eta  = -eta_saved;
00558               zeta = zeta_saved;
00559             }
00560         }
00561     }
00562   // Face 5
00563   else if (i < 8 + 12*e + 6*e*e)
00564     {
00565       unsigned int basisnum = i - 8 - 12*e - 5*e*e;
00566       i0 = square_number_row[basisnum] + 2;
00567       i1 = square_number_column[basisnum] + 2;
00568       i2 = 1;
00569       const Point min_point = get_min_point(elem, 4, 5, 6, 7);
00570 
00571       if (elem->point(4) == min_point)
00572         if (elem->point(5) == std::min(elem->point(5), elem->point(7)))
00573           {
00574             // Case 1
00575             xi  = xi_saved;
00576             eta = eta_saved;
00577           }
00578         else
00579           {
00580             // Case 2
00581             xi  = eta_saved;
00582             eta = xi_saved;
00583           }
00584 
00585       else if (elem->point(5) == min_point)
00586         if (elem->point(6) == std::min(elem->point(6), elem->point(4)))
00587           {
00588             // Case 3
00589             xi  = eta_saved;
00590             eta = -xi_saved;
00591           }
00592         else
00593           {
00594             // Case 4
00595             xi  = -xi_saved;
00596             eta = eta_saved;
00597           }
00598 
00599       else if (elem->point(6) == min_point)
00600         if (elem->point(7) == std::min(elem->point(7), elem->point(5)))
00601           {
00602             // Case 5
00603             xi  = -xi_saved;
00604             eta = -eta_saved;
00605           }
00606         else
00607           {
00608             // Case 6
00609             xi  = -eta_saved;
00610             eta = -xi_saved;
00611           }
00612 
00613       else if (elem->point(7) == min_point)
00614         {
00615           if (elem->point(4) == std::min(elem->point(4), elem->point(6)))
00616             {
00617               // Case 7
00618               xi  = -eta_saved;
00619               eta = xi_saved;
00620             }
00621           else
00622             {
00623               // Case 8
00624               xi  = xi_saved;
00625               eta = eta_saved;
00626             }
00627         }
00628     }
00629 
00630   // Internal DoFs
00631   else
00632     {
00633       unsigned int basisnum = i - 8 - 12*e - 6*e*e;
00634       i0 = cube_number_column[basisnum] + 2;
00635       i1 = cube_number_row[basisnum] + 2;
00636       i2 = cube_number_page[basisnum] + 2;
00637     }
00638 }
00639 } // end anonymous namespace
00640 
00641 
00642 
00643 
00644 template <>
00645 Real FE<3,HIERARCHIC>::shape(const ElemType,
00646                              const Order,
00647                              const unsigned int,
00648                              const Point&)
00649 {
00650   libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge and face orientation is needed.");
00651   return 0.;
00652 }
00653 
00654 
00655 
00656 template <>
00657 Real FE<3,HIERARCHIC>::shape(const Elem* elem,
00658                              const Order order,
00659                              const unsigned int i,
00660                              const Point& p)
00661 {
00662 #if LIBMESH_DIM == 3
00663 
00664   libmesh_assert(elem);
00665   const ElemType type = elem->type();
00666 
00667   const Order totalorder = static_cast<Order>(order+elem->p_level());
00668 
00669   switch (type)
00670     {
00671     case HEX8:
00672     case HEX20:
00673       libmesh_assert_less (totalorder, 2);
00674     case HEX27:
00675       {
00676         libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)*(totalorder+1u));
00677 
00678         // Compute hex shape functions as a tensor-product
00679         Real xi   = p(0);
00680         Real eta  = p(1);
00681         Real zeta = p(2);
00682 
00683         unsigned int i0, i1, i2;
00684 
00685         cube_indices(elem, totalorder, i, xi, eta, zeta, i0, i1, i2);
00686 
00687         return (FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)*
00688                 FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i1, eta)*
00689                 FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i2, zeta));
00690       }
00691 
00692     default:
00693       libmesh_error_msg("Invalid element type = " << type);
00694     }
00695 
00696 #endif
00697 
00698   libmesh_error_msg("We'll never get here!");
00699   return 0.;
00700 }
00701 
00702 
00703 
00704 
00705 template <>
00706 Real FE<3,HIERARCHIC>::shape_deriv(const ElemType,
00707                                    const Order,
00708                                    const unsigned int,
00709                                    const unsigned int,
00710                                    const Point& )
00711 {
00712   libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge and face orientation is needed.");
00713   return 0.;
00714 }
00715 
00716 
00717 
00718 template <>
00719 Real FE<3,HIERARCHIC>::shape_deriv(const Elem* elem,
00720                                    const Order order,
00721                                    const unsigned int i,
00722                                    const unsigned int j,
00723                                    const Point& p)
00724 {
00725 #if LIBMESH_DIM == 3
00726   libmesh_assert(elem);
00727 
00728   libmesh_assert_less (j, 3);
00729 
00730   // cheat by using finite difference approximations:
00731   const Real eps = 1.e-6;
00732   Point pp, pm;
00733 
00734   switch (j)
00735     {
00736       // d()/dxi
00737     case 0:
00738       {
00739         pp = Point(p(0)+eps, p(1), p(2));
00740         pm = Point(p(0)-eps, p(1), p(2));
00741         break;
00742       }
00743 
00744       // d()/deta
00745     case 1:
00746       {
00747         pp = Point(p(0), p(1)+eps, p(2));
00748         pm = Point(p(0), p(1)-eps, p(2));
00749         break;
00750       }
00751 
00752       // d()/dzeta
00753     case 2:
00754       {
00755         pp = Point(p(0), p(1), p(2)+eps);
00756         pm = Point(p(0), p(1), p(2)-eps);
00757         break;
00758       }
00759 
00760     default:
00761       libmesh_error_msg("Invalid derivative index j = " << j);
00762     }
00763 
00764   return (FE<3,HIERARCHIC>::shape(elem, order, i, pp) -
00765           FE<3,HIERARCHIC>::shape(elem, order, i, pm))/2./eps;
00766 #endif
00767 
00768   libmesh_error_msg("We'll never get here!");
00769   return 0.;
00770 }
00771 
00772 
00773 
00774 template <>
00775 Real FE<3,HIERARCHIC>::shape_second_deriv(const ElemType,
00776                                           const Order,
00777                                           const unsigned int,
00778                                           const unsigned int,
00779                                           const Point& )
00780 {
00781   libmesh_error_msg("Hierarchic polynomials require the element type \nbecause edge and face orientation is needed.");
00782   return 0.;
00783 }
00784 
00785 
00786 
00787 template <>
00788 Real FE<3,HIERARCHIC>::shape_second_deriv(const Elem* elem,
00789                                           const Order order,
00790                                           const unsigned int i,
00791                                           const unsigned int j,
00792                                           const Point& p)
00793 {
00794   libmesh_assert(elem);
00795 
00796   const Real eps = 1.e-6;
00797   Point pp, pm;
00798   unsigned int prevj = libMesh::invalid_uint;
00799 
00800   switch (j)
00801     {
00802       //  d^2()/dxi^2
00803     case 0:
00804       {
00805         pp = Point(p(0)+eps, p(1), p(2));
00806         pm = Point(p(0)-eps, p(1), p(2));
00807         prevj = 0;
00808         break;
00809       }
00810 
00811       //  d^2()/dxideta
00812     case 1:
00813       {
00814         pp = Point(p(0), p(1)+eps, p(2));
00815         pm = Point(p(0), p(1)-eps, p(2));
00816         prevj = 0;
00817         break;
00818       }
00819 
00820       //  d^2()/deta^2
00821     case 2:
00822       {
00823         pp = Point(p(0), p(1)+eps, p(2));
00824         pm = Point(p(0), p(1)-eps, p(2));
00825         prevj = 1;
00826         break;
00827       }
00828 
00829       //  d^2()/dxidzeta
00830     case 3:
00831       {
00832         pp = Point(p(0), p(1), p(2)+eps);
00833         pm = Point(p(0), p(1), p(2)-eps);
00834         prevj = 0;
00835         break;
00836       }
00837 
00838       //  d^2()/detadzeta
00839     case 4:
00840       {
00841         pp = Point(p(0), p(1), p(2)+eps);
00842         pm = Point(p(0), p(1), p(2)-eps);
00843         prevj = 1;
00844         break;
00845       }
00846 
00847       //  d^2()/dzeta^2
00848     case 5:
00849       {
00850         pp = Point(p(0), p(1), p(2)+eps);
00851         pm = Point(p(0), p(1), p(2)-eps);
00852         prevj = 2;
00853         break;
00854       }
00855     default:
00856       libmesh_error_msg("Invalid derivative index j = " << j);
00857     }
00858 
00859   return (FE<3,HIERARCHIC>::shape_deriv(elem, order, i, prevj, pp) -
00860           FE<3,HIERARCHIC>::shape_deriv(elem, order, i, prevj, pm))
00861     / 2. / eps;
00862 }
00863 
00864 } // namespace libMesh