$extrastylesheet
fe_bernstein.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 
00020 // Local includes
00021 #include "libmesh/libmesh_config.h"
00022 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00023 
00024 #include "libmesh/fe.h"
00025 #include "libmesh/elem.h"
00026 #include "libmesh/fe_interface.h"
00027 #include "libmesh/string_to_enum.h"
00028 
00029 namespace libMesh
00030 {
00031 
00032 // ------------------------------------------------------------
00033 // Bernstein-specific implementations, Steffen Petersen 2005
00034 
00035 // Anonymous namespace for local helper functions
00036 namespace {
00037 
00038 void bernstein_nodal_soln(const Elem* elem,
00039                           const Order order,
00040                           const std::vector<Number>& elem_soln,
00041                           std::vector<Number>&       nodal_soln,
00042                           unsigned Dim)
00043 {
00044   const unsigned int n_nodes = elem->n_nodes();
00045 
00046   const ElemType elem_type = elem->type();
00047 
00048   nodal_soln.resize(n_nodes);
00049 
00050   const Order totalorder = static_cast<Order>(order + elem->p_level());
00051 
00052   // FEType object to be passed to various FEInterface functions below.
00053   FEType fe_type(totalorder, BERNSTEIN);
00054 
00055   switch (totalorder)
00056     {
00057       // Constant shape functions
00058     case CONSTANT:
00059       {
00060         libmesh_assert_equal_to (elem_soln.size(), 1);
00061 
00062         const Number val = elem_soln[0];
00063 
00064         for (unsigned int n=0; n<n_nodes; n++)
00065           nodal_soln[n] = val;
00066 
00067         return;
00068       }
00069 
00070 
00071       // For other bases do interpolation at the nodes
00072       // explicitly.
00073     case FIRST:
00074     case SECOND:
00075     case THIRD:
00076     case FOURTH:
00077     case FIFTH:
00078     case SIXTH:
00079       {
00080 
00081         const unsigned int n_sf =
00082           // FE<Dim,T>::n_shape_functions(elem_type, totalorder);
00083           FEInterface::n_shape_functions(Dim, fe_type, elem_type);
00084 
00085         std::vector<Point> refspace_nodes;
00086         FEBase::get_refspace_nodes(elem_type,refspace_nodes);
00087         libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);
00088 
00089         for (unsigned int n=0; n<n_nodes; n++)
00090           {
00091             libmesh_assert_equal_to (elem_soln.size(), n_sf);
00092 
00093             // Zero before summation
00094             nodal_soln[n] = 0;
00095 
00096             // u_i = Sum (alpha_i phi_i)
00097             for (unsigned int i=0; i<n_sf; i++)
00098               nodal_soln[n] += elem_soln[i] *
00099                 // FE<Dim,T>::shape(elem, order, i, mapped_point);
00100                 FEInterface::shape(Dim, fe_type, elem, i, refspace_nodes[n]);
00101           }
00102 
00103         return;
00104       }
00105 
00106     default:
00107       libmesh_error_msg("ERROR: Invalid total order " << totalorder);
00108     }
00109 } //  bernstein_nodal_soln()
00110 
00111 
00112 
00113 unsigned int bernstein_n_dofs(const ElemType t, const Order o)
00114 {
00115   switch (t)
00116     {
00117     case NODEELEM:
00118       return 1;
00119     case EDGE2:
00120     case EDGE3:
00121       return (o+1);
00122     case QUAD4:
00123       libmesh_assert_less (o, 2);
00124     case QUAD8:
00125       {
00126         if (o == 1)
00127           return 4;
00128         else if (o == 2)
00129           return 8;
00130         else
00131           libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for BERNSTEIN FE family!");
00132       }
00133     case QUAD9:
00134       return ((o+1)*(o+1));
00135     case HEX8:
00136       libmesh_assert_less (o, 2);
00137     case HEX20:
00138       {
00139         if (o == 1)
00140           return 8;
00141         else if (o == 2)
00142           return 20;
00143         else
00144           libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for BERNSTEIN FE family!");
00145       }
00146     case HEX27:
00147       return ((o+1)*(o+1)*(o+1));
00148     case TRI3:
00149       libmesh_assert_less (o, 2);
00150     case TRI6:
00151       return ((o+1)*(o+2)/2);
00152     case TET4:
00153       libmesh_assert_less (o, 2);
00154     case TET10:
00155       {
00156         libmesh_assert_less (o, 3);
00157         return ((o+1)*(o+2)*(o+3)/6);
00158       }
00159     case INVALID_ELEM:
00160       return 0;
00161     default:
00162       libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!");
00163     }
00164 
00165   libmesh_error_msg("We'll never get here!");
00166   return 0;
00167 } // bernstein_n_dofs()
00168 
00169 
00170 
00171 
00172 unsigned int bernstein_n_dofs_at_node(const ElemType t,
00173                                       const Order o,
00174                                       const unsigned int n)
00175 {
00176   switch (t)
00177     {
00178     case NODEELEM:
00179       return 1;
00180 
00181     case EDGE2:
00182     case EDGE3:
00183       switch (n)
00184         {
00185         case 0:
00186         case 1:
00187           return 1;
00188         case 2:
00189           libmesh_assert (o>1);
00190           return (o-1);
00191         default:
00192           libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for EDGE2/3!");
00193         }
00194     case TRI6:
00195       switch (n)
00196         {
00197         case 0:
00198         case 1:
00199         case 2:
00200           return 1;
00201 
00202         case 3:
00203         case 4:
00204         case 5:
00205           return (o-1);
00206           // Internal DoFs are associated with the elem, not its nodes
00207         default:
00208           libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!");
00209         }
00210     case QUAD8:
00211       libmesh_assert_less (n, 8);
00212       libmesh_assert_less (o, 3);
00213     case QUAD9:
00214       {
00215         switch (n)
00216           {
00217           case 0:
00218           case 1:
00219           case 2:
00220           case 3:
00221             return 1;
00222 
00223           case 4:
00224           case 5:
00225           case 6:
00226           case 7:
00227             return (o-1);
00228 
00229             // Internal DoFs are associated with the elem, not its nodes
00230           case 8:
00231             return 0;
00232 
00233           default:
00234             libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for QUAD9!");
00235           }
00236       }
00237     case HEX8:
00238       libmesh_assert_less (n, 8);
00239       libmesh_assert_less (o, 2);
00240     case HEX20:
00241       libmesh_assert_less (n, 20);
00242       libmesh_assert_less (o, 3);
00243     case HEX27:
00244       switch (n)
00245         {
00246         case 0:
00247         case 1:
00248         case 2:
00249         case 3:
00250         case 4:
00251         case 5:
00252         case 6:
00253         case 7:
00254           return 1;
00255 
00256         case 8:
00257         case 9:
00258         case 10:
00259         case 11:
00260         case 12:
00261         case 13:
00262         case 14:
00263         case 15:
00264         case 16:
00265         case 17:
00266         case 18:
00267         case 19:
00268           return (o-1);
00269 
00270         case 20:
00271         case 21:
00272         case 22:
00273         case 23:
00274         case 24:
00275         case 25:
00276           return ((o-1)*(o-1));
00277 
00278           // Internal DoFs are associated with the elem, not its nodes
00279         case 26:
00280           return 0;
00281 
00282         default:
00283           libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for HEX27!");
00284         }
00285     case TET4:
00286       libmesh_assert_less (n, 4);
00287       libmesh_assert_less (o, 2);
00288     case TET10:
00289       libmesh_assert_less (o, 3);
00290       libmesh_assert_less (n, 10);
00291       switch (n)
00292         {
00293         case 0:
00294         case 1:
00295         case 2:
00296         case 3:
00297           return 1;
00298 
00299         case 4:
00300         case 5:
00301         case 6:
00302         case 7:
00303         case 8:
00304         case 9:
00305           return (o-1);
00306 
00307         default:
00308           libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TET10!");
00309         }
00310     case INVALID_ELEM:
00311       return 0;
00312     default:
00313       libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!");
00314     }
00315 
00316   libmesh_error_msg("We'll never get here!");
00317   return 0;
00318 } // bernstein_n_dofs_at_node()
00319 
00320 
00321 
00322 
00323 unsigned int bernstein_n_dofs_per_elem(const ElemType t, const Order o)
00324 {
00325   switch (t)
00326     {
00327     case NODEELEM:
00328     case EDGE2:
00329     case EDGE3:
00330       return 0;
00331     case TRI3:
00332     case QUAD4:
00333       return 0;
00334     case TRI6:
00335       return ((o-1)*(o-2)/2);
00336     case QUAD8:
00337       if (o <= 2)
00338         return 0;
00339     case QUAD9:
00340       return ((o-1)*(o-1));
00341     case HEX8:
00342       libmesh_assert_less (o, 2);
00343     case HEX20:
00344       libmesh_assert_less (o, 3);
00345       return 0;
00346     case HEX27:
00347       return ((o-1)*(o-1)*(o-1));
00348     case TET4:
00349       libmesh_assert_less (o, 2);
00350     case TET10:
00351       libmesh_assert_less (o, 3);
00352       return 0;
00353     case INVALID_ELEM:
00354       return 0;
00355     default:
00356       libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for BERNSTEIN FE family!");
00357     }
00358 
00359   libmesh_error_msg("We'll never get here!");
00360   return 0;
00361 } // bernstein_n_dofs_per_elem
00362 
00363 } // anonymous namespace
00364 
00365 
00366 
00367 
00368   // Do full-specialization of nodal_soln() function for every
00369   // dimension, instead of explicit instantiation at the end of this
00370   // file.
00371   // This could be macro-ified so that it fits on one line...
00372 template <>
00373 void FE<0,BERNSTEIN>::nodal_soln(const Elem* elem,
00374                                  const Order order,
00375                                  const std::vector<Number>& elem_soln,
00376                                  std::vector<Number>& nodal_soln)
00377 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/0); }
00378 
00379 template <>
00380 void FE<1,BERNSTEIN>::nodal_soln(const Elem* elem,
00381                                  const Order order,
00382                                  const std::vector<Number>& elem_soln,
00383                                  std::vector<Number>& nodal_soln)
00384 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/1); }
00385 
00386 template <>
00387 void FE<2,BERNSTEIN>::nodal_soln(const Elem* elem,
00388                                  const Order order,
00389                                  const std::vector<Number>& elem_soln,
00390                                  std::vector<Number>& nodal_soln)
00391 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/2); }
00392 
00393 template <>
00394 void FE<3,BERNSTEIN>::nodal_soln(const Elem* elem,
00395                                  const Order order,
00396                                  const std::vector<Number>& elem_soln,
00397                                  std::vector<Number>& nodal_soln)
00398 { bernstein_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/3); }
00399 
00400 
00401 // Full specialization of n_dofs() function for every dimension
00402 template <> unsigned int FE<0,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
00403 template <> unsigned int FE<1,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
00404 template <> unsigned int FE<2,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
00405 template <> unsigned int FE<3,BERNSTEIN>::n_dofs(const ElemType t, const Order o) { return bernstein_n_dofs(t, o); }
00406 
00407 // Full specialization of n_dofs_at_node() function for every dimension.
00408 template <> unsigned int FE<0,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
00409 template <> unsigned int FE<1,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
00410 template <> unsigned int FE<2,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
00411 template <> unsigned int FE<3,BERNSTEIN>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return bernstein_n_dofs_at_node(t, o, n); }
00412 
00413 // Full specialization of n_dofs_per_elem() function for every dimension.
00414 template <> unsigned int FE<0,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
00415 template <> unsigned int FE<1,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
00416 template <> unsigned int FE<2,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
00417 template <> unsigned int FE<3,BERNSTEIN>::n_dofs_per_elem(const ElemType t, const Order o) { return bernstein_n_dofs_per_elem(t, o); }
00418 
00419 // Bernstein FEMs are C^0 continuous
00420 template <> FEContinuity FE<0,BERNSTEIN>::get_continuity() const { return C_ZERO; }
00421 template <> FEContinuity FE<1,BERNSTEIN>::get_continuity() const { return C_ZERO; }
00422 template <> FEContinuity FE<2,BERNSTEIN>::get_continuity() const { return C_ZERO; }
00423 template <> FEContinuity FE<3,BERNSTEIN>::get_continuity() const { return C_ZERO; }
00424 
00425 // Bernstein FEMs are not hierarchic
00426 template <> bool FE<0,BERNSTEIN>::is_hierarchic() const { return false; }
00427 template <> bool FE<1,BERNSTEIN>::is_hierarchic() const { return false; }
00428 template <> bool FE<2,BERNSTEIN>::is_hierarchic() const { return false; }
00429 template <> bool FE<3,BERNSTEIN>::is_hierarchic() const { return false; }
00430 
00431 #ifdef LIBMESH_ENABLE_AMR
00432 // compute_constraints() specializations are only needed for 2 and 3D
00433 template <>
00434 void FE<2,BERNSTEIN>::compute_constraints (DofConstraints &constraints,
00435                                            DofMap &dof_map,
00436                                            const unsigned int variable_number,
00437                                            const Elem* elem)
00438 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
00439 
00440 template <>
00441 void FE<3,BERNSTEIN>::compute_constraints (DofConstraints &constraints,
00442                                            DofMap &dof_map,
00443                                            const unsigned int variable_number,
00444                                            const Elem* elem)
00445 { compute_proj_constraints(constraints, dof_map, variable_number, elem); }
00446 #endif // #ifdef LIBMESH_ENABLE_AMR
00447 
00448 // Bernstein shapes need reinit only for approximation orders >= 3,
00449 // but we might reach that with p refinement
00450 template <> bool FE<0,BERNSTEIN>::shapes_need_reinit() const { return true; }
00451 template <> bool FE<1,BERNSTEIN>::shapes_need_reinit() const { return true; }
00452 template <> bool FE<2,BERNSTEIN>::shapes_need_reinit() const { return true; }
00453 template <> bool FE<3,BERNSTEIN>::shapes_need_reinit() const { return true; }
00454 
00455 } // namespace libMesh
00456 
00457 #endif //LIBMESH_ENABLE_HIGHER_ORDER_SHAPES