$extrastylesheet
fe.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/elem.h"
00022 #include "libmesh/fe.h"
00023 #include "libmesh/fe_interface.h"
00024 #include "libmesh/fe_macro.h"
00025 #include "libmesh/libmesh_logging.h"
00026 #include "libmesh/quadrature.h"
00027 #include "libmesh/tensor_value.h"
00028 
00029 namespace libMesh
00030 {
00031 
00032 
00033 // ------------------------------------------------------------
00034 // FE class members
00035 template <unsigned int Dim, FEFamily T>
00036 unsigned int FE<Dim,T>::n_shape_functions () const
00037 {
00038   return FE<Dim,T>::n_dofs (this->elem_type,
00039                             static_cast<Order>(this->fe_type.order + this->_p_level));
00040 }
00041 
00042 
00043 template <unsigned int Dim, FEFamily T>
00044 void FE<Dim,T>::attach_quadrature_rule (QBase* q)
00045 {
00046   libmesh_assert(q);
00047   this->qrule = q;
00048   // make sure we don't cache results from a previous quadrature rule
00049   this->elem_type = INVALID_ELEM;
00050   return;
00051 }
00052 
00053 
00054 template <unsigned int Dim, FEFamily T>
00055 unsigned int FE<Dim,T>::n_quadrature_points () const
00056 {
00057   libmesh_assert(this->qrule);
00058   return this->qrule->n_points();
00059 }
00060 
00061 
00062 template <unsigned int Dim, FEFamily T>
00063 void FE<Dim,T>::dofs_on_side(const Elem* const elem,
00064                              const Order o,
00065                              unsigned int s,
00066                              std::vector<unsigned int>& di)
00067 {
00068   libmesh_assert(elem);
00069   libmesh_assert_less (s, elem->n_sides());
00070 
00071   di.clear();
00072   unsigned int nodenum = 0;
00073   const unsigned int n_nodes = elem->n_nodes();
00074   for (unsigned int n = 0; n != n_nodes; ++n)
00075     {
00076       const unsigned int n_dofs = n_dofs_at_node(elem->type(),
00077                                                  static_cast<Order>(o + elem->p_level()), n);
00078       if (elem->is_node_on_side(n, s))
00079         for (unsigned int i = 0; i != n_dofs; ++i)
00080           di.push_back(nodenum++);
00081       else
00082         nodenum += n_dofs;
00083     }
00084 }
00085 
00086 
00087 
00088 template <unsigned int Dim, FEFamily T>
00089 void FE<Dim,T>::dofs_on_edge(const Elem* const elem,
00090                              const Order o,
00091                              unsigned int e,
00092                              std::vector<unsigned int>& di)
00093 {
00094   libmesh_assert(elem);
00095   libmesh_assert_less (e, elem->n_edges());
00096 
00097   di.clear();
00098   unsigned int nodenum = 0;
00099   const unsigned int n_nodes = elem->n_nodes();
00100   for (unsigned int n = 0; n != n_nodes; ++n)
00101     {
00102       const unsigned int n_dofs = n_dofs_at_node(elem->type(),
00103                                                  static_cast<Order>(o + elem->p_level()), n);
00104       if (elem->is_node_on_edge(n, e))
00105         for (unsigned int i = 0; i != n_dofs; ++i)
00106           di.push_back(nodenum++);
00107       else
00108         nodenum += n_dofs;
00109     }
00110 }
00111 
00112 
00113 
00114 template <unsigned int Dim, FEFamily T>
00115 void FE<Dim,T>::reinit(const Elem* elem,
00116                        const std::vector<Point>* const pts,
00117                        const std::vector<Real>* const weights)
00118 {
00119   // We can be called with no element.  If we're evaluating SCALAR
00120   // dofs we'll still have work to do.
00121   // libmesh_assert(elem);
00122 
00123   // Try to avoid calling init_shape_functions
00124   // even when shapes_need_reinit
00125   bool cached_nodes_still_fit = false;
00126 
00127   // Most of the hard work happens when we have an actual element
00128   if (elem)
00129     {
00130       // Initialize the shape functions at the user-specified
00131       // points
00132       if (pts != NULL)
00133         {
00134           // Set the type and p level for this element
00135           this->elem_type = elem->type();
00136           this->_p_level = elem->p_level();
00137 
00138           // Initialize the shape functions
00139           this->_fe_map->template init_reference_to_physical_map<Dim>
00140             (*pts, elem);
00141           this->init_shape_functions (*pts, elem);
00142 
00143           // The shape functions do not correspond to the qrule
00144           this->shapes_on_quadrature = false;
00145         }
00146 
00147       // If there are no user specified points, we use the
00148       // quadrature rule
00149 
00150       // update the type in accordance to the current cell
00151       // and reinit if the cell type has changed or (as in
00152       // the case of the hierarchics) the shape functions need
00153       // reinit, since they depend on the particular element shape
00154       else
00155         {
00156           libmesh_assert(this->qrule);
00157           this->qrule->init(elem->type(), elem->p_level());
00158 
00159           if(this->qrule->shapes_need_reinit())
00160             this->shapes_on_quadrature = false;
00161 
00162           if (this->elem_type != elem->type() ||
00163               this->_p_level != elem->p_level() ||
00164               !this->shapes_on_quadrature)
00165             {
00166               // Set the type and p level for this element
00167               this->elem_type = elem->type();
00168               this->_p_level = elem->p_level();
00169               // Initialize the shape functions
00170               this->_fe_map->template init_reference_to_physical_map<Dim>
00171                 (this->qrule->get_points(), elem);
00172               this->init_shape_functions (this->qrule->get_points(), elem);
00173 
00174               if (this->shapes_need_reinit())
00175                 {
00176                   cached_nodes.resize(elem->n_nodes());
00177                   for (unsigned int n = 0; n != elem->n_nodes(); ++n)
00178                     {
00179                       cached_nodes[n] = elem->point(n);
00180                     }
00181                 }
00182             }
00183           else
00184             {
00185               // libmesh_assert_greater (elem->n_nodes(), 1);
00186 
00187               cached_nodes_still_fit = true;
00188               if (cached_nodes.size() != elem->n_nodes())
00189                 cached_nodes_still_fit = false;
00190               else
00191                 for (unsigned int n = 1; n < elem->n_nodes(); ++n)
00192                   {
00193                     if (!(elem->point(n) - elem->point(0)).relative_fuzzy_equals
00194                         ((cached_nodes[n] - cached_nodes[0]), 1e-13))
00195                       {
00196                         cached_nodes_still_fit = false;
00197                         break;
00198                       }
00199                   }
00200 
00201               if (this->shapes_need_reinit() && !cached_nodes_still_fit)
00202                 {
00203                   this->_fe_map->template init_reference_to_physical_map<Dim>
00204                     (this->qrule->get_points(), elem);
00205                   this->init_shape_functions (this->qrule->get_points(), elem);
00206                   cached_nodes.resize(elem->n_nodes());
00207                   for (unsigned int n = 0; n != elem->n_nodes(); ++n)
00208                     cached_nodes[n] = elem->point(n);
00209                 }
00210             }
00211 
00212           // The shape functions correspond to the qrule
00213           this->shapes_on_quadrature = true;
00214         }
00215     }
00216   else // With no defined elem, so mapping or caching to
00217        // be done, and our "quadrature rule" is one point for nonlocal
00218        // (SCALAR) variables and zero points for local variables.
00219     {
00220       this->elem_type = INVALID_ELEM;
00221       this->_p_level = 0;
00222 
00223       if (!pts)
00224         {
00225           if (T == SCALAR)
00226             {
00227               this->qrule->get_points() =
00228                 std::vector<Point>(1,Point(0));
00229 
00230               this->qrule->get_weights() =
00231                 std::vector<Real>(1,1);
00232             }
00233           else
00234             {
00235               this->qrule->get_points().clear();
00236               this->qrule->get_weights().clear();
00237             }
00238 
00239           this->init_shape_functions (this->qrule->get_points(), elem);
00240         }
00241       else
00242         this->init_shape_functions (*pts, elem);
00243     }
00244 
00245   // Compute the map for this element.
00246   if (pts != NULL)
00247     {
00248       if (weights != NULL)
00249         {
00250           this->_fe_map->compute_map (this->dim,*weights, elem);
00251         }
00252       else
00253         {
00254           std::vector<Real> dummy_weights (pts->size(), 1.);
00255           this->_fe_map->compute_map (this->dim,dummy_weights, elem);
00256         }
00257     }
00258   else
00259     {
00260       this->_fe_map->compute_map (this->dim,this->qrule->get_weights(), elem);
00261     }
00262 
00263   // Compute the shape functions and the derivatives at all of the
00264   // quadrature points.
00265   if (!cached_nodes_still_fit)
00266     {
00267       if (pts != NULL)
00268         this->compute_shape_functions (elem,*pts);
00269       else
00270         this->compute_shape_functions(elem,this->qrule->get_points());
00271     }
00272 }
00273 
00274 
00275 
00276 template <unsigned int Dim, FEFamily T>
00277 void FE<Dim,T>::init_shape_functions(const std::vector<Point>& qp,
00278                                      const Elem* elem)
00279 {
00280   // We can be called with no element.  If we're evaluating SCALAR
00281   // dofs we'll still have work to do.
00282   // libmesh_assert(elem);
00283 
00284   this->calculations_started = true;
00285 
00286   // If the user forgot to request anything, we'll be safe and
00287   // calculate everything:
00288 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00289   if (!this->calculate_phi && !this->calculate_dphi && !this->calculate_d2phi
00290       && !this->calculate_curl_phi && !this->calculate_div_phi)
00291     {
00292       this->calculate_phi = this->calculate_dphi = this->calculate_d2phi = this->calculate_dphiref = true;
00293       if( FEInterface::field_type(T) == TYPE_VECTOR )
00294         {
00295           this->calculate_curl_phi = true;
00296           this->calculate_div_phi  = true;
00297         }
00298     }
00299 #else
00300   if (!this->calculate_phi && !this->calculate_dphi && !this->calculate_curl_phi && !this->calculate_div_phi)
00301     {
00302       this->calculate_phi = this->calculate_dphi = this->calculate_dphiref = true;
00303       if( FEInterface::field_type(T) == TYPE_VECTOR )
00304         {
00305           this->calculate_curl_phi = true;
00306           this->calculate_div_phi  = true;
00307         }
00308     }
00309 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
00310 
00311   // Start logging the shape function initialization
00312   START_LOG("init_shape_functions()", "FE");
00313 
00314 
00315   // The number of quadrature points.
00316   const unsigned int n_qp = cast_int<unsigned int>(qp.size());
00317 
00318   // Number of shape functions in the finite element approximation
00319   // space.
00320   const unsigned int n_approx_shape_functions =
00321     this->n_shape_functions(this->get_type(),
00322                             this->get_order());
00323 
00324   // resize the vectors to hold current data
00325   // Phi are the shape functions used for the FE approximation
00326   // Phi_map are the shape functions used for the FE mapping
00327   if (this->calculate_phi)
00328     this->phi.resize     (n_approx_shape_functions);
00329 
00330   if (this->calculate_dphi)
00331     {
00332       this->dphi.resize    (n_approx_shape_functions);
00333       this->dphidx.resize  (n_approx_shape_functions);
00334       this->dphidy.resize  (n_approx_shape_functions);
00335       this->dphidz.resize  (n_approx_shape_functions);
00336     }
00337 
00338   if(this->calculate_dphiref)
00339     {
00340       if (Dim > 0)
00341         this->dphidxi.resize (n_approx_shape_functions);
00342 
00343       if (Dim > 1)
00344         this->dphideta.resize      (n_approx_shape_functions);
00345 
00346       if (Dim > 2)
00347         this->dphidzeta.resize     (n_approx_shape_functions);
00348     }
00349 
00350   if( this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR) )
00351     this->curl_phi.resize(n_approx_shape_functions);
00352 
00353   if( this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR) )
00354     this->div_phi.resize(n_approx_shape_functions);
00355 
00356 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00357   if (this->calculate_d2phi)
00358     {
00359       this->d2phi.resize     (n_approx_shape_functions);
00360       this->d2phidx2.resize  (n_approx_shape_functions);
00361       this->d2phidxdy.resize (n_approx_shape_functions);
00362       this->d2phidxdz.resize (n_approx_shape_functions);
00363       this->d2phidy2.resize  (n_approx_shape_functions);
00364       this->d2phidydz.resize (n_approx_shape_functions);
00365       this->d2phidz2.resize  (n_approx_shape_functions);
00366 
00367       if (Dim > 0)
00368         this->d2phidxi2.resize (n_approx_shape_functions);
00369 
00370       if (Dim > 1)
00371         {
00372           this->d2phidxideta.resize (n_approx_shape_functions);
00373           this->d2phideta2.resize   (n_approx_shape_functions);
00374         }
00375       if (Dim > 2)
00376         {
00377           this->d2phidxidzeta.resize  (n_approx_shape_functions);
00378           this->d2phidetadzeta.resize (n_approx_shape_functions);
00379           this->d2phidzeta2.resize    (n_approx_shape_functions);
00380         }
00381     }
00382 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00383 
00384   for (unsigned int i=0; i<n_approx_shape_functions; i++)
00385     {
00386       if (this->calculate_phi)
00387         this->phi[i].resize         (n_qp);
00388       if (this->calculate_dphi)
00389         {
00390           this->dphi[i].resize        (n_qp);
00391           this->dphidx[i].resize      (n_qp);
00392           this->dphidy[i].resize      (n_qp);
00393           this->dphidz[i].resize      (n_qp);
00394         }
00395 
00396       if(this->calculate_dphiref)
00397         {
00398           if (Dim > 0)
00399             this->dphidxi[i].resize(n_qp);
00400 
00401           if (Dim > 1)
00402             this->dphideta[i].resize(n_qp);
00403 
00404           if (Dim > 2)
00405             this->dphidzeta[i].resize(n_qp);
00406         }
00407 
00408       if(this->calculate_curl_phi && (FEInterface::field_type(T) == TYPE_VECTOR) )
00409         this->curl_phi[i].resize(n_qp);
00410 
00411       if(this->calculate_div_phi && (FEInterface::field_type(T) == TYPE_VECTOR) )
00412         this->div_phi[i].resize(n_qp);
00413 
00414 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00415       if (this->calculate_d2phi)
00416         {
00417           this->d2phi[i].resize     (n_qp);
00418           this->d2phidx2[i].resize  (n_qp);
00419           this->d2phidxdy[i].resize (n_qp);
00420           this->d2phidxdz[i].resize (n_qp);
00421           this->d2phidy2[i].resize  (n_qp);
00422           this->d2phidydz[i].resize (n_qp);
00423           this->d2phidz2[i].resize  (n_qp);
00424           if (Dim > 0)
00425             this->d2phidxi2[i].resize (n_qp);
00426           if (Dim > 1)
00427             {
00428               this->d2phidxideta[i].resize (n_qp);
00429               this->d2phideta2[i].resize   (n_qp);
00430             }
00431           if (Dim > 2)
00432             {
00433               this->d2phidxidzeta[i].resize  (n_qp);
00434               this->d2phidetadzeta[i].resize (n_qp);
00435               this->d2phidzeta2[i].resize    (n_qp);
00436             }
00437         }
00438 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00439     }
00440 
00441 
00442 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00443   //------------------------------------------------------------
00444   // Initialize the data fields, which should only be used for infinite
00445   // elements, to some sensible values, so that using a FE with the
00446   // variational formulation of an InfFE, correct element matrices are
00447   // returned
00448 
00449   {
00450     this->weight.resize  (n_qp);
00451     this->dweight.resize (n_qp);
00452     this->dphase.resize  (n_qp);
00453 
00454     for (unsigned int p=0; p<n_qp; p++)
00455       {
00456         this->weight[p] = 1.;
00457         this->dweight[p].zero();
00458         this->dphase[p].zero();
00459       }
00460 
00461   }
00462 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00463 
00464   switch (Dim)
00465     {
00466 
00467       //------------------------------------------------------------
00468       // 0D
00469     case 0:
00470       {
00471         break;
00472       }
00473 
00474       //------------------------------------------------------------
00475       // 1D
00476     case 1:
00477       {
00478         // Compute the value of the approximation shape function i at quadrature point p
00479         if (this->calculate_dphiref)
00480           for (unsigned int i=0; i<n_approx_shape_functions; i++)
00481             for (unsigned int p=0; p<n_qp; p++)
00482               this->dphidxi[i][p]  = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 0, qp[p]);
00483 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00484         if (this->calculate_d2phi)
00485           for (unsigned int i=0; i<n_approx_shape_functions; i++)
00486             for (unsigned int p=0; p<n_qp; p++)
00487               this->d2phidxi2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 0, qp[p]);
00488 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00489 
00490         break;
00491       }
00492 
00493 
00494 
00495       //------------------------------------------------------------
00496       // 2D
00497     case 2:
00498       {
00499         // Compute the value of the approximation shape function i at quadrature point p
00500         if (this->calculate_dphiref)
00501           for (unsigned int i=0; i<n_approx_shape_functions; i++)
00502             for (unsigned int p=0; p<n_qp; p++)
00503               {
00504                 this->dphidxi[i][p]  = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 0, qp[p]);
00505                 this->dphideta[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 1, qp[p]);
00506               }
00507 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00508         if (this->calculate_d2phi)
00509           for (unsigned int i=0; i<n_approx_shape_functions; i++)
00510             for (unsigned int p=0; p<n_qp; p++)
00511               {
00512                 this->d2phidxi2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 0, qp[p]);
00513                 this->d2phidxideta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 1, qp[p]);
00514                 this->d2phideta2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 2, qp[p]);
00515               }
00516 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00517 
00518 
00519         break;
00520       }
00521 
00522 
00523 
00524       //------------------------------------------------------------
00525       // 3D
00526     case 3:
00527       {
00528         // Compute the value of the approximation shape function i at quadrature point p
00529         if (this->calculate_dphiref)
00530           for (unsigned int i=0; i<n_approx_shape_functions; i++)
00531             for (unsigned int p=0; p<n_qp; p++)
00532               {
00533                 this->dphidxi[i][p]   = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 0, qp[p]);
00534                 this->dphideta[i][p]  = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 1, qp[p]);
00535                 this->dphidzeta[i][p] = FE<Dim,T>::shape_deriv (elem, this->fe_type.order, i, 2, qp[p]);
00536               }
00537 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00538         if (this->calculate_d2phi)
00539           for (unsigned int i=0; i<n_approx_shape_functions; i++)
00540             for (unsigned int p=0; p<n_qp; p++)
00541               {
00542                 this->d2phidxi2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 0, qp[p]);
00543                 this->d2phidxideta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 1, qp[p]);
00544                 this->d2phideta2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 2, qp[p]);
00545                 this->d2phidxidzeta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 3, qp[p]);
00546                 this->d2phidetadzeta[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 4, qp[p]);
00547                 this->d2phidzeta2[i][p] = FE<Dim,T>::shape_second_deriv (elem, this->fe_type.order, i, 5, qp[p]);
00548               }
00549 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00550 
00551         break;
00552       }
00553 
00554 
00555     default:
00556       libmesh_error_msg("Invalid dimension Dim = " << Dim);
00557     }
00558 
00559   // Stop logging the shape function initialization
00560   STOP_LOG("init_shape_functions()", "FE");
00561 }
00562 
00563 
00564 
00565 
00566 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00567 
00568 template <unsigned int Dim, FEFamily T>
00569 void FE<Dim,T>::init_base_shape_functions(const std::vector<Point>& qp,
00570                                           const Elem* e)
00571 {
00572   // I don't understand infinite elements well enough to risk
00573   // calculating too little.  :-(  RHS
00574   this->calculate_phi = this->calculate_dphi = this->calculate_d2phi = true;
00575 
00576   this->elem_type = e->type();
00577   this->_fe_map->template init_reference_to_physical_map<Dim>(qp, e);
00578   init_shape_functions(qp, e);
00579 }
00580 
00581 #endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
00582 
00583 
00584 
00585 //--------------------------------------------------------------
00586 // Explicit instantiations using macro from fe_macro.h
00587 
00588 INSTANTIATE_FE(0);
00589 
00590 INSTANTIATE_FE(1);
00591 
00592 INSTANTIATE_FE(2);
00593 
00594 INSTANTIATE_FE(3);
00595 
00596 INSTANTIATE_SUBDIVISION_FE;
00597 
00598 } // namespace libMesh