$extrastylesheet
fe_boundary.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 // C++ includes
00021 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
00022 #include <cmath> // for std::sqrt
00023 
00024 
00025 // Local includes
00026 #include "libmesh/libmesh_common.h"
00027 #include "libmesh/fe.h"
00028 #include "libmesh/quadrature.h"
00029 #include "libmesh/elem.h"
00030 #include "libmesh/libmesh_logging.h"
00031 #include "libmesh/tensor_value.h"  // May be necessary if destructors
00032 // get instantiated here
00033 
00034 namespace libMesh
00035 {
00036 
00037 //-------------------------------------------------------
00038 // Full specializations for useless methods in 0D, 1D
00039 #define REINIT_ERROR(_dim, _type, _func)                                \
00040   template <>                                                           \
00041   void FE<_dim,_type>::_func(const Elem*,                               \
00042                              const unsigned int,                        \
00043                              const Real,                                \
00044                              const std::vector<Point>* const,           \
00045                              const std::vector<Real>* const)            \
00046   {                                                                     \
00047     libmesh_error_msg("ERROR: This method makes no sense for low-D elements!"); \
00048   }
00049 
00050 #define SIDEMAP_ERROR(_dim, _type, _func)                               \
00051   template <>                                                           \
00052   void FE<_dim,_type>::_func(const Elem*,                               \
00053                              const Elem*,                               \
00054                              const unsigned int,                        \
00055                              const std::vector<Point>&,                 \
00056                              std::vector<Point>&)                       \
00057   {                                                                     \
00058     libmesh_error_msg("ERROR: This method makes no sense for low-D elements!"); \
00059   }
00060 
00061 #define FACE_EDGE_SHAPE_ERROR(_dim, _func)                              \
00062   template <>                                                           \
00063   void FEMap::_func<_dim>(const std::vector<Point>&,                    \
00064                           const Elem* )                                 \
00065   {                                                                     \
00066     libmesh_error_msg("ERROR: This method makes no sense for low-D elements!"); \
00067   }
00068 
00069 
00070 REINIT_ERROR(0, CLOUGH, reinit)
00071 REINIT_ERROR(0, CLOUGH, edge_reinit)
00072 SIDEMAP_ERROR(0, CLOUGH, side_map)
00073 REINIT_ERROR(0, HERMITE, reinit)
00074 REINIT_ERROR(0, HERMITE, edge_reinit)
00075 SIDEMAP_ERROR(0, HERMITE, side_map)
00076 REINIT_ERROR(0, HIERARCHIC, reinit)
00077 REINIT_ERROR(0, HIERARCHIC, edge_reinit)
00078 SIDEMAP_ERROR(0, HIERARCHIC, side_map)
00079 REINIT_ERROR(0, L2_HIERARCHIC, reinit)
00080 REINIT_ERROR(0, L2_HIERARCHIC, edge_reinit)
00081 SIDEMAP_ERROR(0, L2_HIERARCHIC, side_map)
00082 REINIT_ERROR(0, LAGRANGE, reinit)
00083 REINIT_ERROR(0, LAGRANGE, edge_reinit)
00084 SIDEMAP_ERROR(0, LAGRANGE, side_map)
00085 REINIT_ERROR(0, LAGRANGE_VEC, reinit)
00086 REINIT_ERROR(0, LAGRANGE_VEC, edge_reinit)
00087 SIDEMAP_ERROR(0, LAGRANGE_VEC, side_map)
00088 REINIT_ERROR(0, L2_LAGRANGE, reinit)
00089 REINIT_ERROR(0, L2_LAGRANGE, edge_reinit)
00090 SIDEMAP_ERROR(0, L2_LAGRANGE, side_map)
00091 REINIT_ERROR(0, MONOMIAL, reinit)
00092 REINIT_ERROR(0, MONOMIAL, edge_reinit)
00093 SIDEMAP_ERROR(0, MONOMIAL, side_map)
00094 REINIT_ERROR(0, SCALAR, reinit)
00095 REINIT_ERROR(0, SCALAR, edge_reinit)
00096 SIDEMAP_ERROR(0, SCALAR, side_map)
00097 REINIT_ERROR(0, XYZ, reinit)
00098 REINIT_ERROR(0, XYZ, edge_reinit)
00099 SIDEMAP_ERROR(0, XYZ, side_map)
00100 REINIT_ERROR(0, NEDELEC_ONE, reinit)
00101 REINIT_ERROR(0, NEDELEC_ONE, edge_reinit)
00102 SIDEMAP_ERROR(0, NEDELEC_ONE, side_map)
00103 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00104 REINIT_ERROR(0, BERNSTEIN, reinit)
00105 REINIT_ERROR(0, BERNSTEIN, edge_reinit)
00106 SIDEMAP_ERROR(0, BERNSTEIN, side_map)
00107 REINIT_ERROR(0, SZABAB, reinit)
00108 REINIT_ERROR(0, SZABAB, edge_reinit)
00109 SIDEMAP_ERROR(0, SZABAB, side_map)
00110 #endif
00111 
00112 REINIT_ERROR(1, CLOUGH, edge_reinit)
00113 REINIT_ERROR(1, HERMITE, edge_reinit)
00114 REINIT_ERROR(1, HIERARCHIC, edge_reinit)
00115 REINIT_ERROR(1, L2_HIERARCHIC, edge_reinit)
00116 REINIT_ERROR(1, LAGRANGE, edge_reinit)
00117 REINIT_ERROR(1, LAGRANGE_VEC, edge_reinit)
00118 REINIT_ERROR(1, L2_LAGRANGE, edge_reinit)
00119 REINIT_ERROR(1, XYZ, edge_reinit)
00120 REINIT_ERROR(1, MONOMIAL, edge_reinit)
00121 REINIT_ERROR(1, SCALAR, edge_reinit)
00122 REINIT_ERROR(1, NEDELEC_ONE, reinit)
00123 REINIT_ERROR(1, NEDELEC_ONE, edge_reinit)
00124 SIDEMAP_ERROR(1, NEDELEC_ONE, side_map)
00125 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00126 REINIT_ERROR(1, BERNSTEIN, edge_reinit)
00127 REINIT_ERROR(1, SZABAB, edge_reinit)
00128 #endif
00129 
00130 
00131 //-------------------------------------------------------
00132 // Methods for 2D, 3D
00133 template <unsigned int Dim, FEFamily T>
00134 void FE<Dim,T>::reinit(const Elem* elem,
00135                        const unsigned int s,
00136                        const Real /* tolerance */,
00137                        const std::vector<Point>* const pts,
00138                        const std::vector<Real>* const weights)
00139 {
00140   libmesh_assert(elem);
00141   libmesh_assert (this->qrule != NULL || pts != NULL);
00142   // We now do this for 1D elements!
00143   // libmesh_assert_not_equal_to (Dim, 1);
00144 
00145   // Build the side of interest
00146   const UniquePtr<Elem> side(elem->build_side(s));
00147 
00148   // Find the max p_level to select
00149   // the right quadrature rule for side integration
00150   unsigned int side_p_level = elem->p_level();
00151   if (elem->neighbor(s) != NULL)
00152     side_p_level = std::max(side_p_level, elem->neighbor(s)->p_level());
00153 
00154   // Initialize the shape functions at the user-specified
00155   // points
00156   if (pts != NULL)
00157     {
00158       // The shape functions do not correspond to the qrule
00159       this->shapes_on_quadrature = false;
00160 
00161       // Initialize the face shape functions
00162       this->_fe_map->template init_face_shape_functions<Dim>(*pts, side.get());
00163 
00164       // Compute the Jacobian*Weight on the face for integration
00165       if (weights != NULL)
00166         {
00167           this->_fe_map->compute_face_map (Dim, *weights, side.get());
00168         }
00169       else
00170         {
00171           std::vector<Real> dummy_weights (pts->size(), 1.);
00172           this->_fe_map->compute_face_map (Dim, dummy_weights, side.get());
00173         }
00174     }
00175   // If there are no user specified points, we use the
00176   // quadrature rule
00177   else
00178     {
00179       // initialize quadrature rule
00180       this->qrule->init(side->type(), side_p_level);
00181 
00182       if(this->qrule->shapes_need_reinit())
00183         this->shapes_on_quadrature = false;
00184 
00185       // FIXME - could this break if the same FE object was used
00186       // for both volume and face integrals? - RHS
00187       // We might not need to reinitialize the shape functions
00188       if ((this->get_type() != elem->type())    ||
00189           (side->type() != last_side)           ||
00190           (this->get_p_level() != side_p_level) ||
00191           this->shapes_need_reinit()            ||
00192           !this->shapes_on_quadrature)
00193         {
00194           // Set the element type and p_level
00195           this->elem_type = elem->type();
00196 
00197           // Set the last_side
00198           last_side = side->type();
00199 
00200           // Set the last p level
00201           this->_p_level = side_p_level;
00202 
00203           // Initialize the face shape functions
00204           this->_fe_map->template init_face_shape_functions<Dim>(this->qrule->get_points(),  side.get());
00205         }
00206 
00207       // Compute the Jacobian*Weight on the face for integration
00208       this->_fe_map->compute_face_map (Dim, this->qrule->get_weights(), side.get());
00209 
00210       // The shape functions correspond to the qrule
00211       this->shapes_on_quadrature = true;
00212     }
00213 
00214   // make a copy of the Jacobian for integration
00215   const std::vector<Real> JxW_int(this->_fe_map->get_JxW());
00216 
00217   // make a copy of shape on quadrature info
00218   bool shapes_on_quadrature_side = this->shapes_on_quadrature;
00219 
00220   // Find where the integration points are located on the
00221   // full element.
00222   const std::vector<Point>* ref_qp;
00223   if (pts != NULL)
00224     ref_qp = pts;
00225   else
00226     ref_qp = &this->qrule->get_points();
00227 
00228   std::vector<Point> qp;
00229   this->side_map(elem, side.get(), s, *ref_qp, qp);
00230 
00231   // compute the shape function and derivative values
00232   // at the points qp
00233   this->reinit  (elem, &qp);
00234 
00235   this->shapes_on_quadrature = shapes_on_quadrature_side;
00236 
00237   // copy back old data
00238   this->_fe_map->get_JxW() = JxW_int;
00239 }
00240 
00241 
00242 
00243 template <unsigned int Dim, FEFamily T>
00244 void FE<Dim,T>::edge_reinit(const Elem* elem,
00245                             const unsigned int e,
00246                             const Real tolerance,
00247                             const std::vector<Point>* const pts,
00248                             const std::vector<Real>* const weights)
00249 {
00250   libmesh_assert(elem);
00251   libmesh_assert (this->qrule != NULL || pts != NULL);
00252   // We don't do this for 1D elements!
00253   libmesh_assert_not_equal_to (Dim, 1);
00254 
00255   // Build the side of interest
00256   const UniquePtr<Elem> edge(elem->build_edge(e));
00257 
00258   // Initialize the shape functions at the user-specified
00259   // points
00260   if (pts != NULL)
00261     {
00262       // The shape functions do not correspond to the qrule
00263       this->shapes_on_quadrature = false;
00264 
00265       // Initialize the edge shape functions
00266       this->_fe_map->template init_edge_shape_functions<Dim> (*pts, edge.get());
00267 
00268       // Compute the Jacobian*Weight on the face for integration
00269       if (weights != NULL)
00270         {
00271           this->_fe_map->compute_edge_map (Dim, *weights, edge.get());
00272         }
00273       else
00274         {
00275           std::vector<Real> dummy_weights (pts->size(), 1.);
00276           this->_fe_map->compute_edge_map (Dim, dummy_weights, edge.get());
00277         }
00278     }
00279   // If there are no user specified points, we use the
00280   // quadrature rule
00281   else
00282     {
00283       // initialize quadrature rule
00284       this->qrule->init(edge->type(), elem->p_level());
00285 
00286       if(this->qrule->shapes_need_reinit())
00287         this->shapes_on_quadrature = false;
00288 
00289       // We might not need to reinitialize the shape functions
00290       if ((this->get_type() != elem->type())                   ||
00291           (edge->type() != static_cast<int>(last_edge))        || // Comparison between enum and unsigned, cast the unsigned to int
00292           this->shapes_need_reinit()                           ||
00293           !this->shapes_on_quadrature)
00294         {
00295           // Set the element type
00296           this->elem_type = elem->type();
00297 
00298           // Set the last_edge
00299           last_edge = edge->type();
00300 
00301           // Initialize the edge shape functions
00302           this->_fe_map->template init_edge_shape_functions<Dim> (this->qrule->get_points(), edge.get());
00303         }
00304 
00305       // Compute the Jacobian*Weight on the face for integration
00306       this->_fe_map->compute_edge_map (Dim, this->qrule->get_weights(), edge.get());
00307 
00308       // The shape functions correspond to the qrule
00309       this->shapes_on_quadrature = true;
00310     }
00311 
00312   // make a copy of the Jacobian for integration
00313   const std::vector<Real> JxW_int(this->_fe_map->get_JxW());
00314 
00315   // Find where the integration points are located on the
00316   // full element.
00317   std::vector<Point> qp;
00318   this->inverse_map (elem, this->_fe_map->get_xyz(), qp, tolerance);
00319 
00320   // compute the shape function and derivative values
00321   // at the points qp
00322   this->reinit  (elem, &qp);
00323 
00324   // copy back old data
00325   this->_fe_map->get_JxW() = JxW_int;
00326 }
00327 
00328 template <unsigned int Dim, FEFamily T>
00329 void FE<Dim,T>::side_map (const Elem* elem,
00330                           const Elem* side,
00331                           const unsigned int s,
00332                           const std::vector<Point>& reference_side_points,
00333                           std::vector<Point>&       reference_points)
00334 {
00335   unsigned int side_p_level = elem->p_level();
00336   if (elem->neighbor(s) != NULL)
00337     side_p_level = std::max(side_p_level, elem->neighbor(s)->p_level());
00338 
00339   if (side->type() != last_side ||
00340       side_p_level != this->_p_level ||
00341       !this->shapes_on_quadrature)
00342     {
00343       // Set the element type
00344       this->elem_type = elem->type();
00345       this->_p_level = side_p_level;
00346 
00347       // Set the last_side
00348       last_side = side->type();
00349 
00350       // Initialize the face shape functions
00351       this->_fe_map->template init_face_shape_functions<Dim>(reference_side_points, side);
00352     }
00353 
00354   const unsigned int n_points =
00355     cast_int<unsigned int>(reference_side_points.size());
00356   reference_points.resize(n_points);
00357   for (unsigned int i = 0; i < n_points; i++)
00358     reference_points[i].zero();
00359 
00360   std::vector<unsigned int> elem_nodes_map;
00361   elem_nodes_map.resize(side->n_nodes());
00362   for (unsigned int j = 0; j < side->n_nodes(); j++)
00363     for (unsigned int i = 0; i < elem->n_nodes(); i++)
00364       if (side->node(j) == elem->node(i))
00365         elem_nodes_map[j] = i;
00366   std::vector<Point> refspace_nodes;
00367   this->get_refspace_nodes(elem->type(), refspace_nodes);
00368 
00369   const std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi();
00370 
00371   for (unsigned int i=0; i<psi_map.size(); i++) // sum over the nodes
00372     {
00373       const Point& side_node = refspace_nodes[elem_nodes_map[i]];
00374       for (unsigned int p=0; p<n_points; p++)
00375         reference_points[p].add_scaled (side_node, psi_map[i][p]);
00376     }
00377 }
00378 
00379 template<unsigned int Dim>
00380 void FEMap::init_face_shape_functions(const std::vector<Point>& qp,
00381                                       const Elem* side)
00382 {
00383   libmesh_assert(side);
00384 
00388   START_LOG("init_face_shape_functions()", "FEMap");
00389 
00390   // The element type and order to use in
00391   // the map
00392   const Order    mapping_order     (side->default_order());
00393   const ElemType mapping_elem_type (side->type());
00394 
00395   // The number of quadrature points.
00396   const unsigned int n_qp = cast_int<unsigned int>(qp.size());
00397 
00398   const unsigned int n_mapping_shape_functions =
00399     FE<Dim,LAGRANGE>::n_shape_functions (mapping_elem_type,
00400                                          mapping_order);
00401 
00402   // resize the vectors to hold current data
00403   // Psi are the shape functions used for the FE mapping
00404   this->psi_map.resize        (n_mapping_shape_functions);
00405 
00406   if (Dim > 1)
00407     {
00408       this->dpsidxi_map.resize    (n_mapping_shape_functions);
00409       this->d2psidxi2_map.resize  (n_mapping_shape_functions);
00410     }
00411 
00412   if (Dim == 3)
00413     {
00414       this->dpsideta_map.resize     (n_mapping_shape_functions);
00415       this->d2psidxideta_map.resize (n_mapping_shape_functions);
00416       this->d2psideta2_map.resize   (n_mapping_shape_functions);
00417     }
00418 
00419   for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00420     {
00421       // Allocate space to store the values of the shape functions
00422       // and their first and second derivatives at the quadrature points.
00423       this->psi_map[i].resize        (n_qp);
00424       if (Dim > 1)
00425         {
00426           this->dpsidxi_map[i].resize    (n_qp);
00427           this->d2psidxi2_map[i].resize  (n_qp);
00428         }
00429       if (Dim == 3)
00430         {
00431           this->dpsideta_map[i].resize     (n_qp);
00432           this->d2psidxideta_map[i].resize (n_qp);
00433           this->d2psideta2_map[i].resize   (n_qp);
00434         }
00435 
00436       // Compute the value of shape function i, and its first and
00437       // second derivatives at quadrature point p
00438       // (Lagrange shape functions are used for the mapping)
00439       for (unsigned int p=0; p<n_qp; p++)
00440         {
00441           this->psi_map[i][p]        = FE<Dim-1,LAGRANGE>::shape             (mapping_elem_type, mapping_order, i,    qp[p]);
00442           if (Dim > 1)
00443             {
00444               this->dpsidxi_map[i][p]    = FE<Dim-1,LAGRANGE>::shape_deriv       (mapping_elem_type, mapping_order, i, 0, qp[p]);
00445               this->d2psidxi2_map[i][p]  = FE<Dim-1,LAGRANGE>::shape_second_deriv(mapping_elem_type, mapping_order, i, 0, qp[p]);
00446             }
00447           // libMesh::out << "this->d2psidxi2_map["<<i<<"][p]=" << d2psidxi2_map[i][p] << std::endl;
00448 
00449           // If we are in 3D, then our sides are 2D faces.
00450           // For the second derivatives, we must also compute the cross
00451           // derivative d^2() / dxi deta
00452           if (Dim == 3)
00453             {
00454               this->dpsideta_map[i][p]     = FE<Dim-1,LAGRANGE>::shape_deriv       (mapping_elem_type, mapping_order, i, 1, qp[p]);
00455               this->d2psidxideta_map[i][p] = FE<Dim-1,LAGRANGE>::shape_second_deriv(mapping_elem_type, mapping_order, i, 1, qp[p]);
00456               this->d2psideta2_map[i][p]   = FE<Dim-1,LAGRANGE>::shape_second_deriv(mapping_elem_type, mapping_order, i, 2, qp[p]);
00457             }
00458         }
00459     }
00460 
00461 
00465   STOP_LOG("init_face_shape_functions()", "FEMap");
00466 }
00467 
00468 template<unsigned int Dim>
00469 void FEMap::init_edge_shape_functions(const std::vector<Point>& qp,
00470                                       const Elem* edge)
00471 {
00472   libmesh_assert(edge);
00473 
00477   START_LOG("init_edge_shape_functions()", "FEMap");
00478 
00479   // The element type and order to use in
00480   // the map
00481   const Order    mapping_order     (edge->default_order());
00482   const ElemType mapping_elem_type (edge->type());
00483 
00484   // The number of quadrature points.
00485   const unsigned int n_qp = cast_int<unsigned int>(qp.size());
00486 
00487   const unsigned int n_mapping_shape_functions =
00488     FE<Dim,LAGRANGE>::n_shape_functions (mapping_elem_type,
00489                                          mapping_order);
00490 
00491   // resize the vectors to hold current data
00492   // Psi are the shape functions used for the FE mapping
00493   this->psi_map.resize        (n_mapping_shape_functions);
00494   this->dpsidxi_map.resize    (n_mapping_shape_functions);
00495   this->d2psidxi2_map.resize  (n_mapping_shape_functions);
00496 
00497   for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00498     {
00499       // Allocate space to store the values of the shape functions
00500       // and their first and second derivatives at the quadrature points.
00501       this->psi_map[i].resize        (n_qp);
00502       this->dpsidxi_map[i].resize    (n_qp);
00503       this->d2psidxi2_map[i].resize  (n_qp);
00504 
00505       // Compute the value of shape function i, and its first and
00506       // second derivatives at quadrature point p
00507       // (Lagrange shape functions are used for the mapping)
00508       for (unsigned int p=0; p<n_qp; p++)
00509         {
00510           this->psi_map[i][p]        = FE<1,LAGRANGE>::shape             (mapping_elem_type, mapping_order, i,    qp[p]);
00511           this->dpsidxi_map[i][p]    = FE<1,LAGRANGE>::shape_deriv       (mapping_elem_type, mapping_order, i, 0, qp[p]);
00512           this->d2psidxi2_map[i][p]  = FE<1,LAGRANGE>::shape_second_deriv(mapping_elem_type, mapping_order, i, 0, qp[p]);
00513         }
00514     }
00515 
00519   STOP_LOG("init_edge_shape_functions()", "FEMap");
00520 }
00521 
00522 
00523 
00524 void FEMap::compute_face_map(int dim, const std::vector<Real>& qw,
00525                              const Elem* side)
00526 {
00527   libmesh_assert(side);
00528 
00529   START_LOG("compute_face_map()", "FEMap");
00530 
00531   // The number of quadrature points.
00532   const unsigned int n_qp = cast_int<unsigned int>(qw.size());
00533 
00534   switch (dim)
00535     {
00536     case 1:
00537       {
00538         // A 1D finite element, currently assumed to be in 1D space
00539         // This means the boundary is a "0D finite element", a
00540         // NODEELEM.
00541 
00542         // Resize the vectors to hold data at the quadrature points
00543         {
00544           this->xyz.resize(n_qp);
00545           normals.resize(n_qp);
00546 
00547           this->JxW.resize(n_qp);
00548         }
00549 
00550         // If we have no quadrature points, there's nothing else to do
00551         if (!n_qp)
00552           break;
00553 
00554         // We need to look back at the full edge to figure out the normal
00555         // vector
00556         const Elem *elem = side->parent();
00557         libmesh_assert (elem);
00558         if (side->node(0) == elem->node(0))
00559           normals[0] = Point(-1.);
00560         else
00561           {
00562             libmesh_assert_equal_to (side->node(0), elem->node(1));
00563             normals[0] = Point(1.);
00564           }
00565 
00566         // Calculate x at the point
00567         libmesh_assert_equal_to (this->psi_map.size(), 1);
00568         // In the unlikely event we have multiple quadrature
00569         // points, they'll be in the same place
00570         for (unsigned int p=0; p<n_qp; p++)
00571           {
00572             this->xyz[p].zero();
00573             this->xyz[p].add_scaled          (side->point(0), this->psi_map[0][p]);
00574             normals[p] = normals[0];
00575             this->JxW[p] = 1.0*qw[p];
00576           }
00577 
00578         // done computing the map
00579         break;
00580       }
00581 
00582     case 2:
00583       {
00584         // A 2D finite element living in either 2D or 3D space.
00585         // This means the boundary is a 1D finite element, i.e.
00586         // and EDGE2 or EDGE3.
00587         // Resize the vectors to hold data at the quadrature points
00588         {
00589           this->xyz.resize(n_qp);
00590           this->dxyzdxi_map.resize(n_qp);
00591           this->d2xyzdxi2_map.resize(n_qp);
00592           this->tangents.resize(n_qp);
00593           this->normals.resize(n_qp);
00594           this->curvatures.resize(n_qp);
00595 
00596           this->JxW.resize(n_qp);
00597         }
00598 
00599         // Clear the entities that will be summed
00600         // Compute the tangent & normal at the quadrature point
00601         for (unsigned int p=0; p<n_qp; p++)
00602           {
00603             this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D
00604             this->xyz[p].zero();
00605             this->dxyzdxi_map[p].zero();
00606             this->d2xyzdxi2_map[p].zero();
00607           }
00608 
00609         // compute x, dxdxi at the quadrature points
00610         for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes
00611           {
00612             const Point& side_point = side->point(i);
00613 
00614             for (unsigned int p=0; p<n_qp; p++) // for each quadrature point...
00615               {
00616                 this->xyz[p].add_scaled          (side_point, this->psi_map[i][p]);
00617                 this->dxyzdxi_map[p].add_scaled  (side_point, this->dpsidxi_map[i][p]);
00618                 this->d2xyzdxi2_map[p].add_scaled(side_point, this->d2psidxi2_map[i][p]);
00619               }
00620           }
00621 
00622         // Compute the tangent & normal at the quadrature point
00623         for (unsigned int p=0; p<n_qp; p++)
00624           {
00625             // The first tangent comes from just the edge's Jacobian
00626             this->tangents[p][0] = this->dxyzdxi_map[p].unit();
00627 
00628 #if LIBMESH_DIM == 2
00629             // For a 2D element living in 2D, the normal is given directly
00630             // from the entries in the edge Jacobian.
00631             this->normals[p] = (Point(this->dxyzdxi_map[p](1), -this->dxyzdxi_map[p](0), 0.)).unit();
00632 
00633 #elif LIBMESH_DIM == 3
00634             // For a 2D element living in 3D, there is a second tangent.
00635             // For the second tangent, we need to refer to the full
00636             // element's (not just the edge's) Jacobian.
00637             const Elem *elem = side->parent();
00638             libmesh_assert(elem);
00639 
00640             // Inverse map xyz[p] to a reference point on the parent...
00641             Point reference_point = FE<2,LAGRANGE>::inverse_map(elem, this->xyz[p]);
00642 
00643             // Get dxyz/dxi and dxyz/deta from the parent map.
00644             Point dx_dxi  = FE<2,LAGRANGE>::map_xi (elem, reference_point);
00645             Point dx_deta = FE<2,LAGRANGE>::map_eta(elem, reference_point);
00646 
00647             // The second tangent vector is formed by crossing these vectors.
00648             tangents[p][1] = dx_dxi.cross(dx_deta).unit();
00649 
00650             // Finally, the normal in this case is given by crossing these
00651             // two tangents.
00652             normals[p] = tangents[p][0].cross(tangents[p][1]).unit();
00653 #endif
00654 
00655 
00656             // The curvature is computed via the familiar Frenet formula:
00657             // curvature = [d^2(x) / d (xi)^2] dot [normal]
00658             // For a reference, see:
00659             // F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill, p. 310
00660             //
00661             // Note: The sign convention here is different from the
00662             // 3D case.  Concave-upward curves (smiles) have a positive
00663             // curvature.  Concave-downward curves (frowns) have a
00664             // negative curvature.  Be sure to take that into account!
00665             const Real numerator   = this->d2xyzdxi2_map[p] * this->normals[p];
00666             const Real denominator = this->dxyzdxi_map[p].size_sq();
00667             libmesh_assert_not_equal_to (denominator, 0);
00668             curvatures[p] = numerator / denominator;
00669           }
00670 
00671         // compute the jacobian at the quadrature points
00672         for (unsigned int p=0; p<n_qp; p++)
00673           {
00674             const Real the_jac = this->dxyzdxi_map[p].size();
00675 
00676             libmesh_assert_greater (the_jac, 0.);
00677 
00678             this->JxW[p] = the_jac*qw[p];
00679           }
00680 
00681         // done computing the map
00682         break;
00683       }
00684 
00685 
00686 
00687     case 3:
00688       {
00689         // A 3D finite element living in 3D space.
00690         // Resize the vectors to hold data at the quadrature points
00691         {
00692           this->xyz.resize(n_qp);
00693           this->dxyzdxi_map.resize(n_qp);
00694           this->dxyzdeta_map.resize(n_qp);
00695           this->d2xyzdxi2_map.resize(n_qp);
00696           this->d2xyzdxideta_map.resize(n_qp);
00697           this->d2xyzdeta2_map.resize(n_qp);
00698           this->tangents.resize(n_qp);
00699           this->normals.resize(n_qp);
00700           this->curvatures.resize(n_qp);
00701 
00702           this->JxW.resize(n_qp);
00703         }
00704 
00705         // Clear the entities that will be summed
00706         for (unsigned int p=0; p<n_qp; p++)
00707           {
00708             this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D
00709             this->xyz[p].zero();
00710             this->dxyzdxi_map[p].zero();
00711             this->dxyzdeta_map[p].zero();
00712             this->d2xyzdxi2_map[p].zero();
00713             this->d2xyzdxideta_map[p].zero();
00714             this->d2xyzdeta2_map[p].zero();
00715           }
00716 
00717         // compute x, dxdxi at the quadrature points
00718         for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes
00719           {
00720             const Point& side_point = side->point(i);
00721 
00722             for (unsigned int p=0; p<n_qp; p++) // for each quadrature point...
00723               {
00724                 this->xyz[p].add_scaled         (side_point, this->psi_map[i][p]);
00725                 this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]);
00726                 this->dxyzdeta_map[p].add_scaled(side_point, this->dpsideta_map[i][p]);
00727                 this->d2xyzdxi2_map[p].add_scaled   (side_point, this->d2psidxi2_map[i][p]);
00728                 this->d2xyzdxideta_map[p].add_scaled(side_point, this->d2psidxideta_map[i][p]);
00729                 this->d2xyzdeta2_map[p].add_scaled  (side_point, this->d2psideta2_map[i][p]);
00730               }
00731           }
00732 
00733         // Compute the tangents, normal, and curvature at the quadrature point
00734         for (unsigned int p=0; p<n_qp; p++)
00735           {
00736             const Point n  = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]);
00737             this->normals[p]     = n.unit();
00738             this->tangents[p][0] = this->dxyzdxi_map[p].unit();
00739             this->tangents[p][1] = n.cross(this->dxyzdxi_map[p]).unit();
00740 
00741             // Compute curvature using the typical nomenclature
00742             // of the first and second fundamental forms.
00743             // For reference, see:
00744             // 1) http://mathworld.wolfram.com/MeanCurvature.html
00745             //    (note -- they are using inward normal)
00746             // 2) F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill
00747             const Real L  = -this->d2xyzdxi2_map[p]    * this->normals[p];
00748             const Real M  = -this->d2xyzdxideta_map[p] * this->normals[p];
00749             const Real N  = -this->d2xyzdeta2_map[p]   * this->normals[p];
00750             const Real E  =  this->dxyzdxi_map[p].size_sq();
00751             const Real F  =  this->dxyzdxi_map[p]      * this->dxyzdeta_map[p];
00752             const Real G  =  this->dxyzdeta_map[p].size_sq();
00753 
00754             const Real numerator   = E*N -2.*F*M + G*L;
00755             const Real denominator = E*G - F*F;
00756             libmesh_assert_not_equal_to (denominator, 0.);
00757             curvatures[p] = 0.5*numerator/denominator;
00758           }
00759 
00760         // compute the jacobian at the quadrature points, see
00761         // http://sp81.msi.umn.edu:999/fluent/fidap/help/theory/thtoc.htm
00762         for (unsigned int p=0; p<n_qp; p++)
00763           {
00764             const Real g11 = (dxdxi_map(p)*dxdxi_map(p) +
00765                               dydxi_map(p)*dydxi_map(p) +
00766                               dzdxi_map(p)*dzdxi_map(p));
00767 
00768             const Real g12 = (dxdxi_map(p)*dxdeta_map(p) +
00769                               dydxi_map(p)*dydeta_map(p) +
00770                               dzdxi_map(p)*dzdeta_map(p));
00771 
00772             const Real g21 = g12;
00773 
00774             const Real g22 = (dxdeta_map(p)*dxdeta_map(p) +
00775                               dydeta_map(p)*dydeta_map(p) +
00776                               dzdeta_map(p)*dzdeta_map(p));
00777 
00778 
00779             const Real the_jac = std::sqrt(g11*g22 - g12*g21);
00780 
00781             libmesh_assert_greater (the_jac, 0.);
00782 
00783             this->JxW[p] = the_jac*qw[p];
00784           }
00785 
00786         // done computing the map
00787         break;
00788       }
00789 
00790 
00791     default:
00792       libmesh_error_msg("Invalid dimension dim = " << dim);
00793     }
00794   STOP_LOG("compute_face_map()", "FEMap");
00795 }
00796 
00797 
00798 
00799 
00800 void FEMap::compute_edge_map(int dim,
00801                              const std::vector<Real>& qw,
00802                              const Elem* edge)
00803 {
00804   libmesh_assert(edge);
00805 
00806   if (dim == 2)
00807     {
00808       // A 2D finite element living in either 2D or 3D space.
00809       // The edges here are the sides of the element, so the
00810       // (misnamed) compute_face_map function does what we want
00811       this->compute_face_map(dim, qw, edge);
00812       return;
00813     }
00814 
00815   libmesh_assert_equal_to (dim, 3);  // 1D is unnecessary and currently unsupported
00816 
00817   START_LOG("compute_edge_map()", "FEMap");
00818 
00819   // The number of quadrature points.
00820   const unsigned int n_qp = cast_int<unsigned int>(qw.size());
00821 
00822   // Resize the vectors to hold data at the quadrature points
00823   this->xyz.resize(n_qp);
00824   this->dxyzdxi_map.resize(n_qp);
00825   this->dxyzdeta_map.resize(n_qp);
00826   this->d2xyzdxi2_map.resize(n_qp);
00827   this->d2xyzdxideta_map.resize(n_qp);
00828   this->d2xyzdeta2_map.resize(n_qp);
00829   this->tangents.resize(n_qp);
00830   this->normals.resize(n_qp);
00831   this->curvatures.resize(n_qp);
00832 
00833   this->JxW.resize(n_qp);
00834 
00835   // Clear the entities that will be summed
00836   for (unsigned int p=0; p<n_qp; p++)
00837     {
00838       this->tangents[p].resize(1);
00839       this->xyz[p].zero();
00840       this->dxyzdxi_map[p].zero();
00841       this->dxyzdeta_map[p].zero();
00842       this->d2xyzdxi2_map[p].zero();
00843       this->d2xyzdxideta_map[p].zero();
00844       this->d2xyzdeta2_map[p].zero();
00845     }
00846 
00847   // compute x, dxdxi at the quadrature points
00848   for (unsigned int i=0; i<this->psi_map.size(); i++) // sum over the nodes
00849     {
00850       const Point& edge_point = edge->point(i);
00851 
00852       for (unsigned int p=0; p<n_qp; p++) // for each quadrature point...
00853         {
00854           this->xyz[p].add_scaled             (edge_point, this->psi_map[i][p]);
00855           this->dxyzdxi_map[p].add_scaled     (edge_point, this->dpsidxi_map[i][p]);
00856           this->d2xyzdxi2_map[p].add_scaled   (edge_point, this->d2psidxi2_map[i][p]);
00857         }
00858     }
00859 
00860   // Compute the tangents at the quadrature point
00861   // FIXME: normals (plural!) and curvatures are uncalculated
00862   for (unsigned int p=0; p<n_qp; p++)
00863     {
00864       const Point n  = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]);
00865       this->tangents[p][0] = this->dxyzdxi_map[p].unit();
00866 
00867       // compute the jacobian at the quadrature points
00868       const Real the_jac = std::sqrt(this->dxdxi_map(p)*this->dxdxi_map(p) +
00869                                      this->dydxi_map(p)*this->dydxi_map(p) +
00870                                      this->dzdxi_map(p)*this->dzdxi_map(p));
00871 
00872       libmesh_assert_greater (the_jac, 0.);
00873 
00874       this->JxW[p] = the_jac*qw[p];
00875     }
00876 
00877   STOP_LOG("compute_edge_map()", "FEMap");
00878 }
00879 
00880 
00881 // Explicit FEMap Instantiations
00882 FACE_EDGE_SHAPE_ERROR(0,init_face_shape_functions)
00883 template void FEMap::init_face_shape_functions<1>(const std::vector<Point>&,const Elem*);
00884 template void FEMap::init_face_shape_functions<2>(const std::vector<Point>&,const Elem*);
00885 template void FEMap::init_face_shape_functions<3>(const std::vector<Point>&,const Elem*);
00886 
00887 FACE_EDGE_SHAPE_ERROR(0,init_edge_shape_functions)
00888 template void FEMap::init_edge_shape_functions<1>(const std::vector<Point>&, const Elem*);
00889 template void FEMap::init_edge_shape_functions<2>(const std::vector<Point>&, const Elem*);
00890 template void FEMap::init_edge_shape_functions<3>(const std::vector<Point>&, const Elem*);
00891 
00892 //--------------------------------------------------------------
00893 // Explicit FE instantiations
00894 template void FE<1,LAGRANGE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00895 template void FE<1,LAGRANGE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00896 template void FE<1,LAGRANGE_VEC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00897 template void FE<1,LAGRANGE_VEC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00898 template void FE<1,L2_LAGRANGE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00899 template void FE<1,L2_LAGRANGE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00900 template void FE<1,HIERARCHIC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00901 template void FE<1,HIERARCHIC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00902 template void FE<1,L2_HIERARCHIC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00903 template void FE<1,L2_HIERARCHIC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00904 template void FE<1,CLOUGH>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00905 template void FE<1,CLOUGH>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00906 template void FE<1,HERMITE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00907 template void FE<1,HERMITE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00908 template void FE<1,MONOMIAL>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00909 template void FE<1,MONOMIAL>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00910 template void FE<1,SCALAR>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00911 template void FE<1,SCALAR>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00912 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00913 template void FE<1,BERNSTEIN>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00914 template void FE<1,BERNSTEIN>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00915 template void FE<1,SZABAB>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00916 template void FE<1,SZABAB>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00917 #endif
00918 template void FE<1,XYZ>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00919 template void FE<1,XYZ>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00920 
00921 template void FE<2,LAGRANGE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00922 template void FE<2,LAGRANGE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00923 template void FE<2,LAGRANGE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00924 template void FE<2,LAGRANGE_VEC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00925 template void FE<2,LAGRANGE_VEC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00926 template void FE<2,LAGRANGE_VEC>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00927 template void FE<2,L2_LAGRANGE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00928 template void FE<2,L2_LAGRANGE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00929 template void FE<2,L2_LAGRANGE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00930 template void FE<2,HIERARCHIC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00931 template void FE<2,HIERARCHIC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00932 template void FE<2,HIERARCHIC>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00933 template void FE<2,L2_HIERARCHIC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00934 template void FE<2,L2_HIERARCHIC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00935 template void FE<2,L2_HIERARCHIC>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00936 template void FE<2,CLOUGH>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00937 template void FE<2,CLOUGH>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00938 template void FE<2,CLOUGH>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00939 template void FE<2,HERMITE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00940 template void FE<2,HERMITE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00941 template void FE<2,HERMITE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00942 template void FE<2,MONOMIAL>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00943 template void FE<2,MONOMIAL>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00944 template void FE<2,MONOMIAL>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00945 template void FE<2,SCALAR>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00946 template void FE<2,SCALAR>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00947 template void FE<2,SCALAR>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00948 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00949 template void FE<2,BERNSTEIN>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00950 template void FE<2,BERNSTEIN>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00951 template void FE<2,BERNSTEIN>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00952 template void FE<2,SZABAB>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00953 template void FE<2,SZABAB>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00954 template void FE<2,SZABAB>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00955 #endif
00956 template void FE<2,SUBDIVISION>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00957 template void FE<2,XYZ>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00958 template void FE<2,XYZ>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00959 template void FE<2,XYZ>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00960 template void FE<2,NEDELEC_ONE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00961 template void FE<2,NEDELEC_ONE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00962 template void FE<2,NEDELEC_ONE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00963 
00964 // Intel 9.1 complained it needed this in devel mode.
00965 //template void FE<2,XYZ>::init_face_shape_functions(const std::vector<Point>&, const Elem*);
00966 
00967 template void FE<3,LAGRANGE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00968 template void FE<3,LAGRANGE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00969 template void FE<3,LAGRANGE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00970 template void FE<3,LAGRANGE_VEC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00971 template void FE<3,LAGRANGE_VEC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00972 template void FE<3,LAGRANGE_VEC>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00973 template void FE<3,L2_LAGRANGE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00974 template void FE<3,L2_LAGRANGE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00975 template void FE<3,L2_LAGRANGE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00976 template void FE<3,HIERARCHIC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00977 template void FE<3,HIERARCHIC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00978 template void FE<3,HIERARCHIC>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00979 template void FE<3,L2_HIERARCHIC>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00980 template void FE<3,L2_HIERARCHIC>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00981 template void FE<3,L2_HIERARCHIC>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00982 template void FE<3,CLOUGH>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00983 template void FE<3,CLOUGH>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00984 template void FE<3,CLOUGH>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00985 template void FE<3,HERMITE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00986 template void FE<3,HERMITE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00987 template void FE<3,HERMITE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00988 template void FE<3,MONOMIAL>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00989 template void FE<3,MONOMIAL>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00990 template void FE<3,MONOMIAL>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00991 template void FE<3,SCALAR>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00992 template void FE<3,SCALAR>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00993 template void FE<3,SCALAR>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00994 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00995 template void FE<3,BERNSTEIN>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00996 template void FE<3,BERNSTEIN>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
00997 template void FE<3,BERNSTEIN>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00998 template void FE<3,SZABAB>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
00999 template void FE<3,SZABAB>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
01000 template void FE<3,SZABAB>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
01001 #endif
01002 template void FE<3,XYZ>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
01003 template void FE<3,XYZ>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
01004 template void FE<3,XYZ>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
01005 template void FE<3,NEDELEC_ONE>::reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
01006 template void FE<3,NEDELEC_ONE>::side_map(Elem const*, Elem const*, const unsigned int, const std::vector<Point>&, std::vector<Point>&);
01007 template void FE<3,NEDELEC_ONE>::edge_reinit(Elem const*, unsigned int, Real, const std::vector<Point>* const, const std::vector<Real>* const);
01008 
01009 // Intel 9.1 complained it needed this in devel mode.
01010 //template void FE<3,XYZ>::init_face_shape_functions(const std::vector<Point>&, const Elem*);
01011 
01012 } // namespace libMesh