$extrastylesheet
fe_l2_lagrange.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/dof_map.h"
00022 #include "libmesh/fe.h"
00023 #include "libmesh/fe_interface.h"
00024 #include "libmesh/elem.h"
00025 #include "libmesh/threads.h"
00026 #include "libmesh/string_to_enum.h"
00027 
00028 namespace libMesh
00029 {
00030 
00031 // ------------------------------------------------------------
00032 // Lagrange-specific implementations
00033 
00034 
00035 // Anonymous namespace for local helper functions
00036 namespace {
00037 void l2_lagrange_nodal_soln(const Elem* elem,
00038                             const Order order,
00039                             const std::vector<Number>& elem_soln,
00040                             std::vector<Number>&       nodal_soln)
00041 {
00042   const unsigned int n_nodes = elem->n_nodes();
00043   const ElemType type        = elem->type();
00044 
00045   const Order totalorder = static_cast<Order>(order+elem->p_level());
00046 
00047   nodal_soln.resize(n_nodes);
00048 
00049 
00050 
00051   switch (totalorder)
00052     {
00053       // linear Lagrange shape functions
00054     case FIRST:
00055       {
00056         switch (type)
00057           {
00058           case EDGE3:
00059             {
00060               libmesh_assert_equal_to (elem_soln.size(), 2);
00061               libmesh_assert_equal_to (nodal_soln.size(), 3);
00062 
00063               nodal_soln[0] = elem_soln[0];
00064               nodal_soln[1] = elem_soln[1];
00065               nodal_soln[2] = .5*(elem_soln[0] + elem_soln[1]);
00066 
00067               return;
00068             }
00069 
00070           case EDGE4:
00071             {
00072               libmesh_assert_equal_to (elem_soln.size(), 2);
00073               libmesh_assert_equal_to (nodal_soln.size(), 4);
00074 
00075               nodal_soln[0] = elem_soln[0];
00076               nodal_soln[1] = elem_soln[1];
00077               nodal_soln[2] = (2.*elem_soln[0] + elem_soln[1])/3.;
00078               nodal_soln[3] = (elem_soln[0] + 2.*elem_soln[1])/3.;
00079 
00080               return;
00081             }
00082 
00083 
00084           case TRI6:
00085             {
00086               libmesh_assert_equal_to (elem_soln.size(), 3);
00087               libmesh_assert_equal_to (nodal_soln.size(), 6);
00088 
00089               nodal_soln[0] = elem_soln[0];
00090               nodal_soln[1] = elem_soln[1];
00091               nodal_soln[2] = elem_soln[2];
00092               nodal_soln[3] = .5*(elem_soln[0] + elem_soln[1]);
00093               nodal_soln[4] = .5*(elem_soln[1] + elem_soln[2]);
00094               nodal_soln[5] = .5*(elem_soln[2] + elem_soln[0]);
00095 
00096               return;
00097             }
00098 
00099 
00100           case QUAD8:
00101           case QUAD9:
00102             {
00103               libmesh_assert_equal_to (elem_soln.size(), 4);
00104 
00105               if (type == QUAD8)
00106                 libmesh_assert_equal_to (nodal_soln.size(), 8);
00107               else
00108                 libmesh_assert_equal_to (nodal_soln.size(), 9);
00109 
00110 
00111               nodal_soln[0] = elem_soln[0];
00112               nodal_soln[1] = elem_soln[1];
00113               nodal_soln[2] = elem_soln[2];
00114               nodal_soln[3] = elem_soln[3];
00115               nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]);
00116               nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]);
00117               nodal_soln[6] = .5*(elem_soln[2] + elem_soln[3]);
00118               nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]);
00119 
00120               if (type == QUAD9)
00121                 nodal_soln[8] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]);
00122 
00123               return;
00124             }
00125 
00126 
00127           case TET10:
00128             {
00129               libmesh_assert_equal_to (elem_soln.size(), 4);
00130               libmesh_assert_equal_to (nodal_soln.size(), 10);
00131 
00132               nodal_soln[0] = elem_soln[0];
00133               nodal_soln[1] = elem_soln[1];
00134               nodal_soln[2] = elem_soln[2];
00135               nodal_soln[3] = elem_soln[3];
00136               nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]);
00137               nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]);
00138               nodal_soln[6] = .5*(elem_soln[2] + elem_soln[0]);
00139               nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]);
00140               nodal_soln[8] = .5*(elem_soln[3] + elem_soln[1]);
00141               nodal_soln[9] = .5*(elem_soln[3] + elem_soln[2]);
00142 
00143               return;
00144             }
00145 
00146 
00147           case HEX20:
00148           case HEX27:
00149             {
00150               libmesh_assert_equal_to (elem_soln.size(), 8);
00151 
00152               if (type == HEX20)
00153                 libmesh_assert_equal_to (nodal_soln.size(), 20);
00154               else
00155                 libmesh_assert_equal_to (nodal_soln.size(), 27);
00156 
00157               nodal_soln[0]  = elem_soln[0];
00158               nodal_soln[1]  = elem_soln[1];
00159               nodal_soln[2]  = elem_soln[2];
00160               nodal_soln[3]  = elem_soln[3];
00161               nodal_soln[4]  = elem_soln[4];
00162               nodal_soln[5]  = elem_soln[5];
00163               nodal_soln[6]  = elem_soln[6];
00164               nodal_soln[7]  = elem_soln[7];
00165               nodal_soln[8]  = .5*(elem_soln[0] + elem_soln[1]);
00166               nodal_soln[9]  = .5*(elem_soln[1] + elem_soln[2]);
00167               nodal_soln[10] = .5*(elem_soln[2] + elem_soln[3]);
00168               nodal_soln[11] = .5*(elem_soln[3] + elem_soln[0]);
00169               nodal_soln[12] = .5*(elem_soln[0] + elem_soln[4]);
00170               nodal_soln[13] = .5*(elem_soln[1] + elem_soln[5]);
00171               nodal_soln[14] = .5*(elem_soln[2] + elem_soln[6]);
00172               nodal_soln[15] = .5*(elem_soln[3] + elem_soln[7]);
00173               nodal_soln[16] = .5*(elem_soln[4] + elem_soln[5]);
00174               nodal_soln[17] = .5*(elem_soln[5] + elem_soln[6]);
00175               nodal_soln[18] = .5*(elem_soln[6] + elem_soln[7]);
00176               nodal_soln[19] = .5*(elem_soln[4] + elem_soln[7]);
00177 
00178               if (type == HEX27)
00179                 {
00180                   nodal_soln[20] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]);
00181                   nodal_soln[21] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[5]);
00182                   nodal_soln[22] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[6]);
00183                   nodal_soln[23] = .25*(elem_soln[2] + elem_soln[3] + elem_soln[6] + elem_soln[7]);
00184                   nodal_soln[24] = .25*(elem_soln[3] + elem_soln[0] + elem_soln[7] + elem_soln[4]);
00185                   nodal_soln[25] = .25*(elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]);
00186 
00187                   nodal_soln[26] = .125*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3] +
00188                                          elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]);
00189                 }
00190 
00191               return;
00192             }
00193 
00194 
00195           case PRISM15:
00196           case PRISM18:
00197             {
00198               libmesh_assert_equal_to (elem_soln.size(), 6);
00199 
00200               if (type == PRISM15)
00201                 libmesh_assert_equal_to (nodal_soln.size(), 15);
00202               else
00203                 libmesh_assert_equal_to (nodal_soln.size(), 18);
00204 
00205               nodal_soln[0]  = elem_soln[0];
00206               nodal_soln[1]  = elem_soln[1];
00207               nodal_soln[2]  = elem_soln[2];
00208               nodal_soln[3]  = elem_soln[3];
00209               nodal_soln[4]  = elem_soln[4];
00210               nodal_soln[5]  = elem_soln[5];
00211               nodal_soln[6]  = .5*(elem_soln[0] + elem_soln[1]);
00212               nodal_soln[7]  = .5*(elem_soln[1] + elem_soln[2]);
00213               nodal_soln[8]  = .5*(elem_soln[0] + elem_soln[2]);
00214               nodal_soln[9]  = .5*(elem_soln[0] + elem_soln[3]);
00215               nodal_soln[10] = .5*(elem_soln[1] + elem_soln[4]);
00216               nodal_soln[11] = .5*(elem_soln[2] + elem_soln[5]);
00217               nodal_soln[12] = .5*(elem_soln[3] + elem_soln[4]);
00218               nodal_soln[13] = .5*(elem_soln[4] + elem_soln[5]);
00219               nodal_soln[14] = .5*(elem_soln[3] + elem_soln[5]);
00220 
00221               if (type == PRISM18)
00222                 {
00223                   nodal_soln[15] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[3]);
00224                   nodal_soln[16] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[4]);
00225                   nodal_soln[17] = .25*(elem_soln[2] + elem_soln[0] + elem_soln[3] + elem_soln[5]);
00226                 }
00227 
00228               return;
00229             }
00230 
00231 
00232 
00233           default:
00234             {
00235               // By default the element solution _is_ nodal,
00236               // so just copy it.
00237               nodal_soln = elem_soln;
00238 
00239               return;
00240             }
00241           }
00242       }
00243 
00244     case SECOND:
00245       {
00246         switch (type)
00247           {
00248           case EDGE4:
00249             {
00250               libmesh_assert_equal_to (elem_soln.size(), 3);
00251               libmesh_assert_equal_to (nodal_soln.size(), 4);
00252 
00253               // Project quadratic solution onto cubic element nodes
00254               nodal_soln[0] = elem_soln[0];
00255               nodal_soln[1] = elem_soln[1];
00256               nodal_soln[2] = (2.*elem_soln[0] - elem_soln[1] +
00257                                8.*elem_soln[2])/9.;
00258               nodal_soln[3] = (-elem_soln[0] + 2.*elem_soln[1] +
00259                                8.*elem_soln[2])/9.;
00260               return;
00261             }
00262 
00263           default:
00264             {
00265               // By default the element solution _is_ nodal,
00266               // so just copy it.
00267               nodal_soln = elem_soln;
00268 
00269               return;
00270             }
00271           }
00272       }
00273 
00274 
00275 
00276 
00277     default:
00278       {
00279         // By default the element solution _is_ nodal,
00280         // so just copy it.
00281         nodal_soln = elem_soln;
00282 
00283         return;
00284       }
00285     }
00286 }
00287 
00288 
00289 // TODO: We should make this work, for example, for SECOND on a TRI3
00290 // (this is valid with L2_LAGRANGE, but not with LAGRANGE)
00291 unsigned int l2_lagrange_n_dofs(const ElemType t, const Order o)
00292 {
00293   switch (o)
00294     {
00295 
00296       // linear Lagrange shape functions
00297     case FIRST:
00298       {
00299         switch (t)
00300           {
00301           case NODEELEM:
00302             return 1;
00303 
00304           case EDGE2:
00305           case EDGE3:
00306           case EDGE4:
00307             return 2;
00308 
00309           case TRI3:
00310           case TRI6:
00311             return 3;
00312 
00313           case QUAD4:
00314           case QUAD8:
00315           case QUAD9:
00316             return 4;
00317 
00318           case TET4:
00319           case TET10:
00320             return 4;
00321 
00322           case HEX8:
00323           case HEX20:
00324           case HEX27:
00325             return 8;
00326 
00327           case PRISM6:
00328           case PRISM15:
00329           case PRISM18:
00330             return 6;
00331 
00332           case PYRAMID5:
00333           case PYRAMID13:
00334           case PYRAMID14:
00335             return 5;
00336 
00337           case INVALID_ELEM:
00338             return 0;
00339 
00340           default:
00341             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
00342           }
00343       }
00344 
00345 
00346       // quadratic Lagrange shape functions
00347     case SECOND:
00348       {
00349         switch (t)
00350           {
00351           case NODEELEM:
00352             return 1;
00353 
00354           case EDGE3:
00355             return 3;
00356 
00357           case TRI6:
00358             return 6;
00359 
00360           case QUAD8:
00361             return 8;
00362 
00363           case QUAD9:
00364             return 9;
00365 
00366           case TET10:
00367             return 10;
00368 
00369           case HEX20:
00370             return 20;
00371 
00372           case HEX27:
00373             return 27;
00374 
00375           case PRISM15:
00376             return 15;
00377 
00378           case PRISM18:
00379             return 18;
00380 
00381           case INVALID_ELEM:
00382             return 0;
00383 
00384           default:
00385             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
00386           }
00387       }
00388 
00389     case THIRD:
00390       {
00391         switch (t)
00392           {
00393           case NODEELEM:
00394             return 1;
00395 
00396           case EDGE4:
00397             return 4;
00398 
00399           case INVALID_ELEM:
00400             return 0;
00401 
00402           default:
00403             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
00404           }
00405       }
00406 
00407     default:
00408       libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for L2_LAGRANGE FE family!");
00409     }
00410 
00411   libmesh_error_msg("We'll never get here!");
00412   return 0;
00413 }
00414 
00415 } // anonymous namespace
00416 
00417 
00418   // Do full-specialization for every dimension, instead
00419   // of explicit instantiation at the end of this file.
00420   // This could be macro-ified so that it fits on one line...
00421 template <>
00422 void FE<0,L2_LAGRANGE>::nodal_soln(const Elem* elem,
00423                                    const Order order,
00424                                    const std::vector<Number>& elem_soln,
00425                                    std::vector<Number>& nodal_soln)
00426 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); }
00427 
00428 template <>
00429 void FE<1,L2_LAGRANGE>::nodal_soln(const Elem* elem,
00430                                    const Order order,
00431                                    const std::vector<Number>& elem_soln,
00432                                    std::vector<Number>& nodal_soln)
00433 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); }
00434 
00435 template <>
00436 void FE<2,L2_LAGRANGE>::nodal_soln(const Elem* elem,
00437                                    const Order order,
00438                                    const std::vector<Number>& elem_soln,
00439                                    std::vector<Number>& nodal_soln)
00440 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); }
00441 
00442 template <>
00443 void FE<3,L2_LAGRANGE>::nodal_soln(const Elem* elem,
00444                                    const Order order,
00445                                    const std::vector<Number>& elem_soln,
00446                                    std::vector<Number>& nodal_soln)
00447 { l2_lagrange_nodal_soln(elem, order, elem_soln, nodal_soln); }
00448 
00449 
00450 // Do full-specialization for every dimension, instead
00451 // of explicit instantiation at the end of this function.
00452 // This could be macro-ified.
00453 template <> unsigned int FE<0,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00454 template <> unsigned int FE<1,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00455 template <> unsigned int FE<2,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00456 template <> unsigned int FE<3,L2_LAGRANGE>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00457 
00458 
00459 // L2 Lagrange elements have all dofs on elements (hence none on nodes)
00460 template <> unsigned int FE<0,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
00461 template <> unsigned int FE<1,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
00462 template <> unsigned int FE<2,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
00463 template <> unsigned int FE<3,L2_LAGRANGE>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
00464 
00465 
00466 // L2 Lagrange elements have all dofs on elements
00467 template <> unsigned int FE<0,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00468 template <> unsigned int FE<1,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00469 template <> unsigned int FE<2,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00470 template <> unsigned int FE<3,L2_LAGRANGE>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_n_dofs(t, o); }
00471 
00472 // L2 Lagrange FEMs are DISCONTINUOUS
00473 template <> FEContinuity FE<0,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; }
00474 template <> FEContinuity FE<1,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; }
00475 template <> FEContinuity FE<2,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; }
00476 template <> FEContinuity FE<3,L2_LAGRANGE>::get_continuity() const { return DISCONTINUOUS; }
00477 
00478 // Lagrange FEMs are not hierarchic
00479 template <> bool FE<0,L2_LAGRANGE>::is_hierarchic() const { return false; }
00480 template <> bool FE<1,L2_LAGRANGE>::is_hierarchic() const { return false; }
00481 template <> bool FE<2,L2_LAGRANGE>::is_hierarchic() const { return false; }
00482 template <> bool FE<3,L2_LAGRANGE>::is_hierarchic() const { return false; }
00483 
00484 // Lagrange FEM shapes do not need reinit (is this always true?)
00485 template <> bool FE<0,L2_LAGRANGE>::shapes_need_reinit() const { return false; }
00486 template <> bool FE<1,L2_LAGRANGE>::shapes_need_reinit() const { return false; }
00487 template <> bool FE<2,L2_LAGRANGE>::shapes_need_reinit() const { return false; }
00488 template <> bool FE<3,L2_LAGRANGE>::shapes_need_reinit() const { return false; }
00489 
00490 // We don't need any constraints for this DISCONTINUOUS basis, hence these
00491 // are NOOPs
00492 #ifdef LIBMESH_ENABLE_AMR
00493 template <>
00494 void FE<2,L2_LAGRANGE>::compute_constraints (DofConstraints &,
00495                                              DofMap &,
00496                                              const unsigned int ,
00497                                              const Elem* )
00498 { }
00499 
00500 template <>
00501 void FE<3,L2_LAGRANGE>::compute_constraints (DofConstraints &,
00502                                              DofMap &,
00503                                              const unsigned int ,
00504                                              const Elem* )
00505 { }
00506 #endif // LIBMESH_ENABLE_AMR
00507 
00508 } // namespace libMesh