$extrastylesheet
fe_map.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, std::abs
00023 
00024 
00025 // Local includes
00026 #include "libmesh/fe.h"
00027 #include "libmesh/elem.h"
00028 #include "libmesh/libmesh_logging.h"
00029 #include "libmesh/fe_macro.h"
00030 #include "libmesh/fe_map.h"
00031 #include "libmesh/fe_xyz_map.h"
00032 #include "libmesh/mesh_subdivision_support.h"
00033 
00034 namespace libMesh
00035 {
00036 
00037 // Constructor (empty)
00038 FEMap::FEMap() {}
00039 
00040 
00041 
00042 UniquePtr<FEMap> FEMap::build( FEType fe_type )
00043 {
00044   switch( fe_type.family )
00045     {
00046     case XYZ:
00047       return UniquePtr<FEMap>(new FEXYZMap);
00048 
00049     default:
00050       return UniquePtr<FEMap>(new FEMap);
00051     }
00052 
00053   libmesh_error_msg("We'll never get here!");
00054   return UniquePtr<FEMap>();
00055 }
00056 
00057 
00058 
00059 template<unsigned int Dim>
00060 void FEMap::init_reference_to_physical_map( const std::vector<Point>& qp,
00061                                             const Elem* elem)
00062 {
00063   // Start logging the reference->physical map initialization
00064   START_LOG("init_reference_to_physical_map()", "FEMap");
00065 
00066   // The number of quadrature points.
00067   const std::size_t n_qp = qp.size();
00068 
00069   // The element type and order to use in
00070   // the map
00071   const Order    mapping_order     (elem->default_order());
00072   const ElemType mapping_elem_type (elem->type());
00073 
00074   // Number of shape functions used to construt the map
00075   // (Lagrange shape functions are used for mapping)
00076   const unsigned int n_mapping_shape_functions =
00077     FE<Dim,LAGRANGE>::n_shape_functions (mapping_elem_type,
00078                                          mapping_order);
00079 
00080   this->phi_map.resize         (n_mapping_shape_functions);
00081   if (Dim > 0)
00082     {
00083       this->dphidxi_map.resize     (n_mapping_shape_functions);
00084 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00085       this->d2phidxi2_map.resize   (n_mapping_shape_functions);
00086 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00087     }
00088 
00089   if (Dim > 1)
00090     {
00091       this->dphideta_map.resize  (n_mapping_shape_functions);
00092 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00093       this->d2phidxideta_map.resize   (n_mapping_shape_functions);
00094       this->d2phideta2_map.resize     (n_mapping_shape_functions);
00095 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00096     }
00097 
00098   if (Dim > 2)
00099     {
00100       this->dphidzeta_map.resize (n_mapping_shape_functions);
00101 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00102       this->d2phidxidzeta_map.resize  (n_mapping_shape_functions);
00103       this->d2phidetadzeta_map.resize (n_mapping_shape_functions);
00104       this->d2phidzeta2_map.resize    (n_mapping_shape_functions);
00105 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00106     }
00107 
00108 
00109   for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00110     {
00111       this->phi_map[i].resize         (n_qp);
00112       if (Dim > 0)
00113         {
00114           this->dphidxi_map[i].resize     (n_qp);
00115 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00116           this->d2phidxi2_map[i].resize     (n_qp);
00117           if (Dim > 1)
00118             {
00119               this->d2phidxideta_map[i].resize (n_qp);
00120               this->d2phideta2_map[i].resize (n_qp);
00121             }
00122           if (Dim > 2)
00123             {
00124               this->d2phidxidzeta_map[i].resize  (n_qp);
00125               this->d2phidetadzeta_map[i].resize (n_qp);
00126               this->d2phidzeta2_map[i].resize    (n_qp);
00127             }
00128 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00129 
00130           if (Dim > 1)
00131             this->dphideta_map[i].resize  (n_qp);
00132 
00133           if (Dim > 2)
00134             this->dphidzeta_map[i].resize (n_qp);
00135         }
00136     }
00137 
00138   // Optimize for the *linear* geometric elements case:
00139   bool is_linear = elem->is_linear();
00140 
00141   switch (Dim)
00142     {
00143 
00144       //------------------------------------------------------------
00145       // 0D
00146     case 0:
00147       {
00148         for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00149           for (std::size_t p=0; p<n_qp; p++)
00150             this->phi_map[i][p]      = FE<Dim,LAGRANGE>::shape (mapping_elem_type, mapping_order, i,    qp[p]);
00151 
00152         break;
00153       }
00154 
00155       //------------------------------------------------------------
00156       // 1D
00157     case 1:
00158       {
00159         // Compute the value of the mapping shape function i at quadrature point p
00160         // (Lagrange shape functions are used for mapping)
00161         if (is_linear)
00162           {
00163             for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00164               {
00165                 this->phi_map[i][0]      = FE<Dim,LAGRANGE>::shape       (mapping_elem_type, mapping_order, i,    qp[0]);
00166                 this->dphidxi_map[i][0]  = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 0, qp[0]);
00167 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00168                 this->d2phidxi2_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 0, qp[0]);
00169 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00170                 for (std::size_t p=1; p<n_qp; p++)
00171                   {
00172                     this->phi_map[i][p]      = FE<Dim,LAGRANGE>::shape (mapping_elem_type, mapping_order, i,    qp[p]);
00173                     this->dphidxi_map[i][p]  = this->dphidxi_map[i][0];
00174 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00175                     this->d2phidxi2_map[i][p] = this->d2phidxi2_map[i][0];
00176 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00177                   }
00178               }
00179           }
00180         else
00181           for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00182             for (std::size_t p=0; p<n_qp; p++)
00183               {
00184                 this->phi_map[i][p]      = FE<Dim,LAGRANGE>::shape       (mapping_elem_type, mapping_order, i,    qp[p]);
00185                 this->dphidxi_map[i][p]  = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 0, qp[p]);
00186 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00187                 this->d2phidxi2_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 0, qp[p]);
00188 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00189               }
00190 
00191         break;
00192       }
00193       //------------------------------------------------------------
00194       // 2D
00195     case 2:
00196       {
00197         // Compute the value of the mapping shape function i at quadrature point p
00198         // (Lagrange shape functions are used for mapping)
00199         if (is_linear)
00200           {
00201             for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00202               {
00203                 this->phi_map[i][0]      = FE<Dim,LAGRANGE>::shape       (mapping_elem_type, mapping_order, i,    qp[0]);
00204                 this->dphidxi_map[i][0]  = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 0, qp[0]);
00205                 this->dphideta_map[i][0] = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 1, qp[0]);
00206 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00207                 this->d2phidxi2_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 0, qp[0]);
00208                 this->d2phidxideta_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 1, qp[0]);
00209                 this->d2phideta2_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 2, qp[0]);
00210 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00211                 for (std::size_t p=1; p<n_qp; p++)
00212                   {
00213                     this->phi_map[i][p]      = FE<Dim,LAGRANGE>::shape (mapping_elem_type, mapping_order, i,    qp[p]);
00214                     this->dphidxi_map[i][p]  = this->dphidxi_map[i][0];
00215                     this->dphideta_map[i][p] = this->dphideta_map[i][0];
00216 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00217                     this->d2phidxi2_map[i][p] = this->d2phidxi2_map[i][0];
00218                     this->d2phidxideta_map[i][p] = this->d2phidxideta_map[i][0];
00219                     this->d2phideta2_map[i][p] = this->d2phideta2_map[i][0];
00220 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00221                   }
00222               }
00223           }
00224         else
00225           for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00226             for (std::size_t p=0; p<n_qp; p++)
00227               {
00228                 this->phi_map[i][p]      = FE<Dim,LAGRANGE>::shape       (mapping_elem_type, mapping_order, i,    qp[p]);
00229                 this->dphidxi_map[i][p]  = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 0, qp[p]);
00230                 this->dphideta_map[i][p] = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 1, qp[p]);
00231 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00232                 this->d2phidxi2_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 0, qp[p]);
00233                 this->d2phidxideta_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 1, qp[p]);
00234                 this->d2phideta2_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 2, qp[p]);
00235 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00236               }
00237 
00238         break;
00239       }
00240 
00241       //------------------------------------------------------------
00242       // 3D
00243     case 3:
00244       {
00245         // Compute the value of the mapping shape function i at quadrature point p
00246         // (Lagrange shape functions are used for mapping)
00247         if (is_linear)
00248           {
00249             for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00250               {
00251                 this->phi_map[i][0]      = FE<Dim,LAGRANGE>::shape       (mapping_elem_type, mapping_order, i,    qp[0]);
00252                 this->dphidxi_map[i][0]  = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 0, qp[0]);
00253                 this->dphideta_map[i][0] = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 1, qp[0]);
00254                 this->dphidzeta_map[i][0] = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 2, qp[0]);
00255 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00256                 this->d2phidxi2_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 0, qp[0]);
00257                 this->d2phidxideta_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 1, qp[0]);
00258                 this->d2phideta2_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 2, qp[0]);
00259                 this->d2phidxidzeta_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 3, qp[0]);
00260                 this->d2phidetadzeta_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 4, qp[0]);
00261                 this->d2phidzeta2_map[i][0] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 5, qp[0]);
00262 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00263                 for (std::size_t p=1; p<n_qp; p++)
00264                   {
00265                     this->phi_map[i][p]      = FE<Dim,LAGRANGE>::shape (mapping_elem_type, mapping_order, i,    qp[p]);
00266                     this->dphidxi_map[i][p]  = this->dphidxi_map[i][0];
00267                     this->dphideta_map[i][p] = this->dphideta_map[i][0];
00268                     this->dphidzeta_map[i][p] = this->dphidzeta_map[i][0];
00269 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00270                     this->d2phidxi2_map[i][p] = this->d2phidxi2_map[i][0];
00271                     this->d2phidxideta_map[i][p] = this->d2phidxideta_map[i][0];
00272                     this->d2phideta2_map[i][p] = this->d2phideta2_map[i][0];
00273                     this->d2phidxidzeta_map[i][p] = this->d2phidxidzeta_map[i][0];
00274                     this->d2phidetadzeta_map[i][p] = this->d2phidetadzeta_map[i][0];
00275                     this->d2phidzeta2_map[i][p] = this->d2phidzeta2_map[i][0];
00276 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00277                   }
00278               }
00279           }
00280         else
00281           for (unsigned int i=0; i<n_mapping_shape_functions; i++)
00282             for (std::size_t p=0; p<n_qp; p++)
00283               {
00284                 this->phi_map[i][p]       = FE<Dim,LAGRANGE>::shape       (mapping_elem_type, mapping_order, i,    qp[p]);
00285                 this->dphidxi_map[i][p]   = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 0, qp[p]);
00286                 this->dphideta_map[i][p]  = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 1, qp[p]);
00287                 this->dphidzeta_map[i][p] = FE<Dim,LAGRANGE>::shape_deriv (mapping_elem_type, mapping_order, i, 2, qp[p]);
00288 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00289                 this->d2phidxi2_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 0, qp[p]);
00290                 this->d2phidxideta_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 1, qp[p]);
00291                 this->d2phideta2_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 2, qp[p]);
00292                 this->d2phidxidzeta_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 3, qp[p]);
00293                 this->d2phidetadzeta_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 4, qp[p]);
00294                 this->d2phidzeta2_map[i][p] = FE<Dim,LAGRANGE>::shape_second_deriv (mapping_elem_type, mapping_order, i, 5, qp[p]);
00295 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00296               }
00297 
00298         break;
00299       }
00300 
00301     default:
00302       libmesh_error_msg("Invalid Dim = " << Dim);
00303     }
00304 
00305   // Stop logging the reference->physical map initialization
00306   STOP_LOG("init_reference_to_physical_map()", "FEMap");
00307   return;
00308 }
00309 
00310 
00311 
00312 void FEMap::compute_single_point_map(const unsigned int dim,
00313                                      const std::vector<Real>& qw,
00314                                      const Elem* elem,
00315                                      unsigned int p,
00316                                      const std::vector<Node*>& elem_nodes)
00317 {
00318   libmesh_assert(elem);
00319   libmesh_assert_equal_to(phi_map.size(), elem_nodes.size());
00320 
00321   switch (dim)
00322     {
00323       //--------------------------------------------------------------------
00324       // 0D
00325     case 0:
00326       {
00327         libmesh_assert(elem_nodes[0]);
00328         xyz[p] = *elem_nodes[0];
00329         jac[p] = 1.0;
00330         JxW[p] = qw[p];
00331         break;
00332       }
00333 
00334       //--------------------------------------------------------------------
00335       // 1D
00336     case 1:
00337       {
00338         // Clear the entities that will be summed
00339         xyz[p].zero();
00340         dxyzdxi_map[p].zero();
00341 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00342         d2xyzdxi2_map[p].zero();
00343 #endif
00344 
00345         // compute x, dx, d2x at the quadrature point
00346         for (unsigned int i=0; i<phi_map.size(); i++) // sum over the nodes
00347           {
00348             // Reference to the point, helps eliminate
00349             // exessive temporaries in the inner loop
00350             libmesh_assert(elem_nodes[i]);
00351             const Point& elem_point = *elem_nodes[i];
00352 
00353             xyz[p].add_scaled          (elem_point, phi_map[i][p]    );
00354             dxyzdxi_map[p].add_scaled  (elem_point, dphidxi_map[i][p]);
00355 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00356             d2xyzdxi2_map[p].add_scaled(elem_point, d2phidxi2_map[i][p]);
00357 #endif
00358           }
00359 
00360         // Compute the jacobian
00361         //
00362         // 1D elements can live in 2D or 3D space.
00363         // The transformation matrix from local->global
00364         // coordinates is
00365         //
00366         // T = | dx/dxi |
00367         //     | dy/dxi |
00368         //     | dz/dxi |
00369         //
00370         // The generalized determinant of T (from the
00371         // so-called "normal" eqns.) is
00372         // jac = "det(T)" = sqrt(det(T'T))
00373         //
00374         // where T'= transpose of T, so
00375         //
00376         // jac = sqrt( (dx/dxi)^2 + (dy/dxi)^2 + (dz/dxi)^2 )
00377         jac[p] = dxyzdxi_map[p].size();
00378 
00379         if (jac[p] <= 0.)
00380           libmesh_error_msg("ERROR: negative Jacobian: " << jac[p] << " in element " << elem->id());
00381 
00382         // The inverse Jacobian entries also come from the
00383         // generalized inverse of T (see also the 2D element
00384         // living in 3D code).
00385         const Real jacm2 = 1./jac[p]/jac[p];
00386         dxidx_map[p] = jacm2*dxdxi_map(p);
00387 #if LIBMESH_DIM > 1
00388         dxidy_map[p] = jacm2*dydxi_map(p);
00389 #endif
00390 #if LIBMESH_DIM > 2
00391         dxidz_map[p] = jacm2*dzdxi_map(p);
00392 #endif
00393 
00394         JxW[p] = jac[p]*qw[p];
00395 
00396         // done computing the map
00397         break;
00398       }
00399 
00400 
00401       //--------------------------------------------------------------------
00402       // 2D
00403     case 2:
00404       {
00405         //------------------------------------------------------------------
00406         // Compute the (x,y) values at the quadrature points,
00407         // the Jacobian at the quadrature points
00408 
00409         xyz[p].zero();
00410 
00411         dxyzdxi_map[p].zero();
00412         dxyzdeta_map[p].zero();
00413 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00414         d2xyzdxi2_map[p].zero();
00415         d2xyzdxideta_map[p].zero();
00416         d2xyzdeta2_map[p].zero();
00417 #endif
00418 
00419 
00420         // compute (x,y) at the quadrature points, derivatives once
00421         for (unsigned int i=0; i<phi_map.size(); i++) // sum over the nodes
00422           {
00423             // Reference to the point, helps eliminate
00424             // exessive temporaries in the inner loop
00425             libmesh_assert(elem_nodes[i]);
00426             const Point& elem_point = *elem_nodes[i];
00427 
00428             xyz[p].add_scaled          (elem_point, phi_map[i][p]     );
00429 
00430             dxyzdxi_map[p].add_scaled      (elem_point, dphidxi_map[i][p] );
00431             dxyzdeta_map[p].add_scaled     (elem_point, dphideta_map[i][p]);
00432 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00433             d2xyzdxi2_map[p].add_scaled    (elem_point, d2phidxi2_map[i][p]);
00434             d2xyzdxideta_map[p].add_scaled (elem_point, d2phidxideta_map[i][p]);
00435             d2xyzdeta2_map[p].add_scaled   (elem_point, d2phideta2_map[i][p]);
00436 #endif
00437           }
00438 
00439         // compute the jacobian once
00440         const Real dx_dxi = dxdxi_map(p),
00441           dx_deta = dxdeta_map(p),
00442           dy_dxi = dydxi_map(p),
00443           dy_deta = dydeta_map(p);
00444 
00445 #if LIBMESH_DIM == 2
00446         // Compute the Jacobian.  This assumes the 2D face
00447         // lives in 2D space
00448         //
00449         // Symbolically, the matrix determinant is
00450         //
00451         //         | dx/dxi  dx/deta |
00452         // jac =   | dy/dxi  dy/deta |
00453         //
00454         // jac = dx/dxi*dy/deta - dx/deta*dy/dxi
00455         jac[p] = (dx_dxi*dy_deta - dx_deta*dy_dxi);
00456 
00457         if (jac[p] <= 0.)
00458           libmesh_error_msg("ERROR: negative Jacobian: " << jac[p] << " in element " << elem->id());
00459 
00460         JxW[p] = jac[p]*qw[p];
00461 
00462         // Compute the shape function derivatives wrt x,y at the
00463         // quadrature points
00464         const Real inv_jac = 1./jac[p];
00465 
00466         dxidx_map[p]  =  dy_deta*inv_jac; //dxi/dx  =  (1/J)*dy/deta
00467         dxidy_map[p]  = -dx_deta*inv_jac; //dxi/dy  = -(1/J)*dx/deta
00468         detadx_map[p] = -dy_dxi* inv_jac; //deta/dx = -(1/J)*dy/dxi
00469         detady_map[p] =  dx_dxi* inv_jac; //deta/dy =  (1/J)*dx/dxi
00470 
00471         dxidz_map[p] = detadz_map[p] = 0.;
00472 #else
00473 
00474         const Real dz_dxi = dzdxi_map(p),
00475           dz_deta = dzdeta_map(p);
00476 
00477         // Compute the Jacobian.  This assumes a 2D face in
00478         // 3D space.
00479         //
00480         // The transformation matrix T from local to global
00481         // coordinates is
00482         //
00483         //         | dx/dxi  dx/deta |
00484         //     T = | dy/dxi  dy/deta |
00485         //         | dz/dxi  dz/deta |
00486         // note det(T' T) = det(T')det(T) = det(T)det(T)
00487         // so det(T) = std::sqrt(det(T' T))
00488         //
00489         //----------------------------------------------
00490         // Notes:
00491         //
00492         //       dX = R dXi -> R'dX = R'R dXi
00493         // (R^-1)dX =   dXi    [(R'R)^-1 R']dX = dXi
00494         //
00495         // so R^-1 = (R'R)^-1 R'
00496         //
00497         // and R^-1 R = (R'R)^-1 R'R = I.
00498         //
00499         const Real g11 = (dx_dxi*dx_dxi +
00500                           dy_dxi*dy_dxi +
00501                           dz_dxi*dz_dxi);
00502 
00503         const Real g12 = (dx_dxi*dx_deta +
00504                           dy_dxi*dy_deta +
00505                           dz_dxi*dz_deta);
00506 
00507         const Real g21 = g12;
00508 
00509         const Real g22 = (dx_deta*dx_deta +
00510                           dy_deta*dy_deta +
00511                           dz_deta*dz_deta);
00512 
00513         const Real det = (g11*g22 - g12*g21);
00514 
00515         if (det <= 0.)
00516           libmesh_error_msg("ERROR: negative Jacobian! " << " in element " << elem->id());
00517 
00518         const Real inv_det = 1./det;
00519         jac[p] = std::sqrt(det);
00520 
00521         JxW[p] = jac[p]*qw[p];
00522 
00523         const Real g11inv =  g22*inv_det;
00524         const Real g12inv = -g12*inv_det;
00525         const Real g21inv = -g21*inv_det;
00526         const Real g22inv =  g11*inv_det;
00527 
00528         dxidx_map[p]  = g11inv*dx_dxi + g12inv*dx_deta;
00529         dxidy_map[p]  = g11inv*dy_dxi + g12inv*dy_deta;
00530         dxidz_map[p]  = g11inv*dz_dxi + g12inv*dz_deta;
00531 
00532         detadx_map[p] = g21inv*dx_dxi + g22inv*dx_deta;
00533         detady_map[p] = g21inv*dy_dxi + g22inv*dy_deta;
00534         detadz_map[p] = g21inv*dz_dxi + g22inv*dz_deta;
00535 
00536 #endif
00537         // done computing the map
00538         break;
00539       }
00540 
00541 
00542 
00543       //--------------------------------------------------------------------
00544       // 3D
00545     case 3:
00546       {
00547         //------------------------------------------------------------------
00548         // Compute the (x,y,z) values at the quadrature points,
00549         // the Jacobian at the quadrature point
00550 
00551         // Clear the entities that will be summed
00552         xyz[p].zero           ();
00553         dxyzdxi_map[p].zero   ();
00554         dxyzdeta_map[p].zero  ();
00555         dxyzdzeta_map[p].zero ();
00556 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00557         d2xyzdxi2_map[p].zero();
00558         d2xyzdxideta_map[p].zero();
00559         d2xyzdxidzeta_map[p].zero();
00560         d2xyzdeta2_map[p].zero();
00561         d2xyzdetadzeta_map[p].zero();
00562         d2xyzdzeta2_map[p].zero();
00563 #endif
00564 
00565 
00566         // compute (x,y,z) at the quadrature points,
00567         // dxdxi,   dydxi,   dzdxi,
00568         // dxdeta,  dydeta,  dzdeta,
00569         // dxdzeta, dydzeta, dzdzeta  all once
00570         for (unsigned int i=0; i<phi_map.size(); i++) // sum over the nodes
00571           {
00572             // Reference to the point, helps eliminate
00573             // exessive temporaries in the inner loop
00574             libmesh_assert(elem_nodes[i]);
00575             const Point& elem_point = *elem_nodes[i];
00576 
00577             xyz[p].add_scaled           (elem_point, phi_map[i][p]      );
00578             dxyzdxi_map[p].add_scaled   (elem_point, dphidxi_map[i][p]  );
00579             dxyzdeta_map[p].add_scaled  (elem_point, dphideta_map[i][p] );
00580             dxyzdzeta_map[p].add_scaled (elem_point, dphidzeta_map[i][p]);
00581 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00582             d2xyzdxi2_map[p].add_scaled      (elem_point,
00583                                               d2phidxi2_map[i][p]);
00584             d2xyzdxideta_map[p].add_scaled   (elem_point,
00585                                               d2phidxideta_map[i][p]);
00586             d2xyzdxidzeta_map[p].add_scaled  (elem_point,
00587                                               d2phidxidzeta_map[i][p]);
00588             d2xyzdeta2_map[p].add_scaled     (elem_point,
00589                                               d2phideta2_map[i][p]);
00590             d2xyzdetadzeta_map[p].add_scaled (elem_point,
00591                                               d2phidetadzeta_map[i][p]);
00592             d2xyzdzeta2_map[p].add_scaled    (elem_point,
00593                                               d2phidzeta2_map[i][p]);
00594 #endif
00595           }
00596 
00597         // compute the jacobian
00598         const Real
00599           dx_dxi   = dxdxi_map(p),   dy_dxi   = dydxi_map(p),   dz_dxi   = dzdxi_map(p),
00600           dx_deta  = dxdeta_map(p),  dy_deta  = dydeta_map(p),  dz_deta  = dzdeta_map(p),
00601           dx_dzeta = dxdzeta_map(p), dy_dzeta = dydzeta_map(p), dz_dzeta = dzdzeta_map(p);
00602 
00603         // Symbolically, the matrix determinant is
00604         //
00605         //         | dx/dxi   dy/dxi   dz/dxi   |
00606         // jac =   | dx/deta  dy/deta  dz/deta  |
00607         //         | dx/dzeta dy/dzeta dz/dzeta |
00608         //
00609         // jac = dx/dxi*(dy/deta*dz/dzeta - dz/deta*dy/dzeta) +
00610         //       dy/dxi*(dz/deta*dx/dzeta - dx/deta*dz/dzeta) +
00611         //       dz/dxi*(dx/deta*dy/dzeta - dy/deta*dx/dzeta)
00612 
00613         jac[p] = (dx_dxi*(dy_deta*dz_dzeta - dz_deta*dy_dzeta)  +
00614                   dy_dxi*(dz_deta*dx_dzeta - dx_deta*dz_dzeta)  +
00615                   dz_dxi*(dx_deta*dy_dzeta - dy_deta*dx_dzeta));
00616 
00617         if (jac[p] <= 0.)
00618           libmesh_error_msg("ERROR: negative Jacobian: " << jac[p] << " in element " << elem->id());
00619 
00620         JxW[p] = jac[p]*qw[p];
00621 
00622         // Compute the shape function derivatives wrt x,y at the
00623         // quadrature points
00624         const Real inv_jac  = 1./jac[p];
00625 
00626         dxidx_map[p]   = (dy_deta*dz_dzeta - dz_deta*dy_dzeta)*inv_jac;
00627         dxidy_map[p]   = (dz_deta*dx_dzeta - dx_deta*dz_dzeta)*inv_jac;
00628         dxidz_map[p]   = (dx_deta*dy_dzeta - dy_deta*dx_dzeta)*inv_jac;
00629 
00630         detadx_map[p]  = (dz_dxi*dy_dzeta  - dy_dxi*dz_dzeta )*inv_jac;
00631         detady_map[p]  = (dx_dxi*dz_dzeta  - dz_dxi*dx_dzeta )*inv_jac;
00632         detadz_map[p]  = (dy_dxi*dx_dzeta  - dx_dxi*dy_dzeta )*inv_jac;
00633 
00634         dzetadx_map[p] = (dy_dxi*dz_deta   - dz_dxi*dy_deta  )*inv_jac;
00635         dzetady_map[p] = (dz_dxi*dx_deta   - dx_dxi*dz_deta  )*inv_jac;
00636         dzetadz_map[p] = (dx_dxi*dy_deta   - dy_dxi*dx_deta  )*inv_jac;
00637 
00638         // done computing the map
00639         break;
00640       }
00641 
00642     default:
00643       libmesh_error_msg("Invalid dim = " << dim);
00644     }
00645 }
00646 
00647 
00648 
00649 void FEMap::resize_quadrature_map_vectors(const unsigned int dim, unsigned int n_qp)
00650 {
00651   // Resize the vectors to hold data at the quadrature points
00652   xyz.resize(n_qp);
00653   dxyzdxi_map.resize(n_qp);
00654   dxidx_map.resize(n_qp);
00655   dxidy_map.resize(n_qp); // 1D element may live in 2D ...
00656   dxidz_map.resize(n_qp); // ... or 3D
00657 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00658   d2xyzdxi2_map.resize(n_qp);
00659 #endif
00660   if (dim > 1)
00661     {
00662       dxyzdeta_map.resize(n_qp);
00663       detadx_map.resize(n_qp);
00664       detady_map.resize(n_qp);
00665       detadz_map.resize(n_qp);
00666 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00667       d2xyzdxideta_map.resize(n_qp);
00668       d2xyzdeta2_map.resize(n_qp);
00669 #endif
00670       if (dim > 2)
00671         {
00672           dxyzdzeta_map.resize (n_qp);
00673           dzetadx_map.resize   (n_qp);
00674           dzetady_map.resize   (n_qp);
00675           dzetadz_map.resize   (n_qp);
00676 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00677           d2xyzdxidzeta_map.resize(n_qp);
00678           d2xyzdetadzeta_map.resize(n_qp);
00679           d2xyzdzeta2_map.resize(n_qp);
00680 #endif
00681         }
00682     }
00683 
00684   jac.resize(n_qp);
00685   JxW.resize(n_qp);
00686 }
00687 
00688 
00689 
00690 void FEMap::compute_affine_map( const unsigned int dim,
00691                                 const std::vector<Real>& qw,
00692                                 const Elem* elem )
00693 {
00694   // Start logging the map computation.
00695   START_LOG("compute_affine_map()", "FEMap");
00696 
00697   libmesh_assert(elem);
00698 
00699   const unsigned int n_qp = cast_int<unsigned int>(qw.size());
00700 
00701   // Resize the vectors to hold data at the quadrature points
00702   this->resize_quadrature_map_vectors(dim, n_qp);
00703 
00704   // Determine the nodes contributing to element elem
00705   std::vector<Node*> elem_nodes(elem->n_nodes(), NULL);
00706   for (unsigned int i=0; i<elem->n_nodes(); i++)
00707     elem_nodes[i] = elem->get_node(i);
00708 
00709   // Compute map at quadrature point 0
00710   this->compute_single_point_map(dim, qw, elem, 0, elem_nodes);
00711 
00712   // Compute xyz at all other quadrature points
00713   for (unsigned int p=1; p<n_qp; p++)
00714     {
00715       xyz[p].zero();
00716       for (unsigned int i=0; i<phi_map.size(); i++) // sum over the nodes
00717         xyz[p].add_scaled        (*elem_nodes[i], phi_map[i][p]    );
00718     }
00719 
00720   // Copy other map data from quadrature point 0
00721   for (unsigned int p=1; p<n_qp; p++) // for each extra quadrature point
00722     {
00723       dxyzdxi_map[p] = dxyzdxi_map[0];
00724       dxidx_map[p] = dxidx_map[0];
00725       dxidy_map[p] = dxidy_map[0];
00726       dxidz_map[p] = dxidz_map[0];
00727 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00728       // The map should be affine, so second derivatives are zero
00729       d2xyzdxi2_map[p] = 0.;
00730 #endif
00731       if (dim > 1)
00732         {
00733           dxyzdeta_map[p] = dxyzdeta_map[0];
00734           detadx_map[p] = detadx_map[0];
00735           detady_map[p] = detady_map[0];
00736           detadz_map[p] = detadz_map[0];
00737 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00738           d2xyzdxideta_map[p] = 0.;
00739           d2xyzdeta2_map[p] = 0.;
00740 #endif
00741           if (dim > 2)
00742             {
00743               dxyzdzeta_map[p] = dxyzdzeta_map[0];
00744               dzetadx_map[p] = dzetadx_map[0];
00745               dzetady_map[p] = dzetady_map[0];
00746               dzetadz_map[p] = dzetadz_map[0];
00747 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00748               d2xyzdxidzeta_map[p] = 0.;
00749               d2xyzdetadzeta_map[p] = 0.;
00750               d2xyzdzeta2_map[p] = 0.;
00751 #endif
00752             }
00753         }
00754       jac[p] = jac[0];
00755       JxW[p] = JxW[0] / qw[0] * qw[p];
00756     }
00757 
00758   STOP_LOG("compute_affine_map()", "FEMap");
00759 }
00760 
00761 
00762 
00763 void FEMap::compute_null_map( const unsigned int dim,
00764                               const std::vector<Real>& qw)
00765 {
00766   // Start logging the map computation.
00767   START_LOG("compute_null_map()", "FEMap");
00768 
00769   const unsigned int n_qp = cast_int<unsigned int>(qw.size());
00770 
00771   // Resize the vectors to hold data at the quadrature points
00772   this->resize_quadrature_map_vectors(dim, n_qp);
00773 
00774   // Compute "fake" xyz
00775   for (unsigned int p=1; p<n_qp; p++)
00776     {
00777       xyz[p].zero();
00778 
00779       dxyzdxi_map[p] = 0;
00780       dxidx_map[p] = 0;
00781       dxidy_map[p] = 0;
00782       dxidz_map[p] = 0;
00783 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00784       d2xyzdxi2_map[p] = 0;
00785 #endif
00786       if (dim > 1)
00787         {
00788           dxyzdeta_map[p] = 0;
00789           detadx_map[p] = 0;
00790           detady_map[p] = 0;
00791           detadz_map[p] = 0;
00792 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00793           d2xyzdxideta_map[p] = 0.;
00794           d2xyzdeta2_map[p] = 0.;
00795 #endif
00796           if (dim > 2)
00797             {
00798               dxyzdzeta_map[p] = 0;
00799               dzetadx_map[p] = 0;
00800               dzetady_map[p] = 0;
00801               dzetadz_map[p] = 0;
00802 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00803               d2xyzdxidzeta_map[p] = 0;
00804               d2xyzdetadzeta_map[p] = 0;
00805               d2xyzdzeta2_map[p] = 0;
00806 #endif
00807             }
00808         }
00809       jac[p] = 1;
00810       JxW[p] = qw[p];
00811     }
00812 
00813   STOP_LOG("compute_null_map()", "FEMap");
00814 }
00815 
00816 
00817 
00818 void FEMap::compute_map(const unsigned int dim,
00819                         const std::vector<Real>& qw,
00820                         const Elem* elem)
00821 {
00822   if (!elem)
00823     {
00824       compute_null_map(dim, qw);
00825       return;
00826     }
00827 
00828   if (elem->has_affine_map())
00829     {
00830       compute_affine_map(dim, qw, elem);
00831       return;
00832     }
00833 
00834   // Start logging the map computation.
00835   START_LOG("compute_map()", "FEMap");
00836 
00837   libmesh_assert(elem);
00838 
00839   const unsigned int n_qp = cast_int<unsigned int>(qw.size());
00840 
00841   // Resize the vectors to hold data at the quadrature points
00842   this->resize_quadrature_map_vectors(dim, n_qp);
00843 
00844   // Determine the nodes contributing to element elem
00845   std::vector<Node*> elem_nodes;
00846   if (elem->type() == TRI3SUBDIVISION)
00847     {
00848       // Subdivision surface FE require the 1-ring around elem
00849       libmesh_assert_equal_to (dim, 2);
00850       const Tri3Subdivision* sd_elem = static_cast<const Tri3Subdivision*>(elem);
00851       MeshTools::Subdivision::find_one_ring(sd_elem, elem_nodes);
00852     }
00853   else
00854     {
00855       // All other FE use only the nodes of elem itself
00856       elem_nodes.resize(elem->n_nodes(), NULL);
00857       for (unsigned int i=0; i<elem->n_nodes(); i++)
00858         elem_nodes[i] = elem->get_node(i);
00859     }
00860 
00861   // Compute map at all quadrature points
00862   for (unsigned int p=0; p!=n_qp; p++)
00863     this->compute_single_point_map(dim, qw, elem, p, elem_nodes);
00864 
00865   // Stop logging the map computation.
00866   STOP_LOG("compute_map()", "FEMap");
00867 }
00868 
00869 
00870 
00871 void FEMap::print_JxW(std::ostream& os) const
00872 {
00873   for (unsigned int i=0; i<JxW.size(); ++i)
00874     os << " [" << i << "]: " <<  JxW[i] << std::endl;
00875 }
00876 
00877 
00878 
00879 void FEMap::print_xyz(std::ostream& os) const
00880 {
00881   for (unsigned int i=0; i<xyz.size(); ++i)
00882     os << " [" << i << "]: " << xyz[i];
00883 }
00884 
00885 
00886 
00887 // TODO: PB: We should consider moving this to the FEMap class
00888 template <unsigned int Dim, FEFamily T>
00889 Point FE<Dim,T>::inverse_map (const Elem* elem,
00890                               const Point& physical_point,
00891                               const Real tolerance,
00892                               const bool secure)
00893 {
00894   libmesh_assert(elem);
00895   libmesh_assert_greater_equal (tolerance, 0.);
00896 
00897 
00898   // Start logging the map inversion.
00899   START_LOG("inverse_map()", "FE");
00900 
00901   // How much did the point on the reference
00902   // element change by in this Newton step?
00903   Real inverse_map_error = 0.;
00904 
00905   //  The point on the reference element.  This is
00906   //  the "initial guess" for Newton's method.  The
00907   //  centroid seems like a good idea, but computing
00908   //  it is a little more intensive than, say taking
00909   //  the zero point.
00910   //
00911   //  Convergence should be insensitive of this choice
00912   //  for "good" elements.
00913   Point p; // the zero point.  No computation required
00914 
00915   //  The number of iterations in the map inversion process.
00916   unsigned int cnt = 0;
00917 
00918   //  The number of iterations after which we give up and declare
00919   //  divergence
00920   const unsigned int max_cnt = 10;
00921 
00922   //  The distance (in master element space) beyond which we give up
00923   //  and declare divergence.  This is no longer used...
00924   // Real max_step_length = 4.;
00925 
00926 
00927 
00928   //  Newton iteration loop.
00929   do
00930     {
00931       //  Where our current iterate \p p maps to.
00932       const Point physical_guess = FE<Dim,T>::map (elem, p);
00933 
00934       //  How far our current iterate is from the actual point.
00935       const Point delta = physical_point - physical_guess;
00936 
00937       //  Increment in current iterate \p p, will be computed.
00938       Point dp;
00939 
00940 
00941       //  The form of the map and how we invert it depends
00942       //  on the dimension that we are in.
00943       switch (Dim)
00944         {
00945           // ------------------------------------------------------------------
00946           //  0D map inversion is trivial
00947         case 0:
00948           {
00949             break;
00950           }
00951 
00952           // ------------------------------------------------------------------
00953           //  1D map inversion
00954           //
00955           //  Here we find the point on a 1D reference element that maps to
00956           //  the point \p physical_point in the domain.  This is a bit tricky
00957           //  since we do not want to assume that the point \p physical_point
00958           //  is also in a 1D domain.  In particular, this method might get
00959           //  called on the edge of a 3D element, in which case
00960           //  \p physical_point actually lives in 3D.
00961         case 1:
00962           {
00963             const Point dxi = FE<Dim,T>::map_xi (elem, p);
00964 
00965             //  Newton's method in this case looks like
00966             //
00967             //  {X} - {X_n} = [J]*dp
00968             //
00969             //  Where {X}, {X_n} are 3x1 vectors, [J] is a 3x1 matrix
00970             //  d(x,y,z)/dxi, and we seek dp, a scalar.  Since the above
00971             //  system is either overdetermined or rank-deficient, we will
00972             //  solve the normal equations for this system
00973             //
00974             //  [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
00975             //
00976             //  which involves the trivial inversion of the scalar
00977             //  G = [J]^T [J]
00978             const Real G = dxi*dxi;
00979 
00980             if (secure)
00981               libmesh_assert_greater (G, 0.);
00982 
00983             const Real Ginv = 1./G;
00984 
00985             const Real  dxidelta = dxi*delta;
00986 
00987             dp(0) = Ginv*dxidelta;
00988 
00989             // No master elements have radius > 4, but sometimes we
00990             // can take a step that big while still converging
00991             // if (secure)
00992             // libmesh_assert_less (dp.size(), max_step_length);
00993 
00994             break;
00995           }
00996 
00997 
00998 
00999           // ------------------------------------------------------------------
01000           //  2D map inversion
01001           //
01002           //  Here we find the point on a 2D reference element that maps to
01003           //  the point \p physical_point in the domain.  This is a bit tricky
01004           //  since we do not want to assume that the point \p physical_point
01005           //  is also in a 2D domain.  In particular, this method might get
01006           //  called on the face of a 3D element, in which case
01007           //  \p physical_point actually lives in 3D.
01008         case 2:
01009           {
01010             const Point dxi  = FE<Dim,T>::map_xi  (elem, p);
01011             const Point deta = FE<Dim,T>::map_eta (elem, p);
01012 
01013             //  Newton's method in this case looks like
01014             //
01015             //  {X} - {X_n} = [J]*{dp}
01016             //
01017             //  Where {X}, {X_n} are 3x1 vectors, [J] is a 3x2 matrix
01018             //  d(x,y,z)/d(xi,eta), and we seek {dp}, a 2x1 vector.  Since
01019             //  the above system is either overdermined or rank-deficient,
01020             //  we will solve the normal equations for this system
01021             //
01022             //  [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
01023             //
01024             //  which involves the inversion of the 2x2 matrix
01025             //  [G] = [J]^T [J]
01026             const Real
01027               G11 = dxi*dxi,  G12 = dxi*deta,
01028               G21 = dxi*deta, G22 = deta*deta;
01029 
01030 
01031             const Real det = (G11*G22 - G12*G21);
01032 
01033             if (secure)
01034               libmesh_assert_not_equal_to (det, 0.);
01035 
01036             const Real inv_det = 1./det;
01037 
01038             const Real
01039               Ginv11 =  G22*inv_det,
01040               Ginv12 = -G12*inv_det,
01041 
01042               Ginv21 = -G21*inv_det,
01043               Ginv22 =  G11*inv_det;
01044 
01045 
01046             const Real  dxidelta  = dxi*delta;
01047             const Real  detadelta = deta*delta;
01048 
01049             dp(0) = (Ginv11*dxidelta + Ginv12*detadelta);
01050             dp(1) = (Ginv21*dxidelta + Ginv22*detadelta);
01051 
01052             // No master elements have radius > 4, but sometimes we
01053             // can take a step that big while still converging
01054             // if (secure)
01055             // libmesh_assert_less (dp.size(), max_step_length);
01056 
01057             break;
01058           }
01059 
01060 
01061 
01062           // ------------------------------------------------------------------
01063           //  3D map inversion
01064           //
01065           //  Here we find the point in a 3D reference element that maps to
01066           //  the point \p physical_point in a 3D domain. Nothing special
01067           //  has to happen here, since (unless the map is singular because
01068           //  you have a BAD element) the map will be invertable and we can
01069           //  apply Newton's method directly.
01070         case 3:
01071           {
01072             const Point dxi   = FE<Dim,T>::map_xi   (elem, p);
01073             const Point deta  = FE<Dim,T>::map_eta  (elem, p);
01074             const Point dzeta = FE<Dim,T>::map_zeta (elem, p);
01075 
01076             //  Newton's method in this case looks like
01077             //
01078             //  {X} = {X_n} + [J]*{dp}
01079             //
01080             //  Where {X}, {X_n} are 3x1 vectors, [J] is a 3x3 matrix
01081             //  d(x,y,z)/d(xi,eta,zeta), and we seek {dp}, a 3x1 vector.
01082             //  Since the above system is nonsingular for invertable maps
01083             //  we will solve
01084             //
01085             //  {dp} = [J]^-1 ({X} - {X_n})
01086             //
01087             //  which involves the inversion of the 3x3 matrix [J]
01088             dp = RealTensorValue(dxi(0), deta(0), dzeta(0),
01089                                  dxi(1), deta(1), dzeta(1),
01090                                  dxi(2), deta(2), dzeta(2)).inverse() * delta;
01091 
01092             // No master elements have radius > 4, but sometimes we
01093             // can take a step that big while still converging
01094             // if (secure)
01095             // libmesh_assert_less (dp.size(), max_step_length);
01096 
01097             break;
01098           }
01099 
01100 
01101           //  Some other dimension?
01102         default:
01103           libmesh_error_msg("Invalid Dim = " << Dim);
01104         } // end switch(Dim), dp now computed
01105 
01106 
01107 
01108       //  ||P_n+1 - P_n||
01109       inverse_map_error = dp.size();
01110 
01111       //  P_n+1 = P_n + dp
01112       p.add (dp);
01113 
01114       //  Increment the iteration count.
01115       cnt++;
01116 
01117       //  Watch for divergence of Newton's
01118       //  method.  Here's how it goes:
01119       //  (1) For good elements, we expect convergence in 10
01120       //      iterations, with no too-large steps.
01121       //      - If called with (secure == true) and we have not yet converged
01122       //        print out a warning message.
01123       //      - If called with (secure == true) and we have not converged in
01124       //        20 iterations abort
01125       //  (2) This method may be called in cases when the target point is not
01126       //      inside the element and we have no business expecting convergence.
01127       //      For these cases if we have not converged in 10 iterations forget
01128       //      about it.
01129       if (cnt > max_cnt)
01130         {
01131           //  Warn about divergence when secure is true - this
01132           //  shouldn't happen
01133           if (secure)
01134             {
01135               // Print every time in devel/dbg modes
01136 #ifndef NDEBUG
01137               libmesh_here();
01138               libMesh::err << "WARNING: Newton scheme has not converged in "
01139                            << cnt << " iterations:" << std::endl
01140                            << "   physical_point="
01141                            << physical_point
01142                            << "   physical_guess="
01143                            << physical_guess
01144                            << "   dp="
01145                            << dp
01146                            << "   p="
01147                            << p
01148                            << "   error=" << inverse_map_error
01149                            << "   in element " << elem->id()
01150                            << std::endl;
01151 
01152               elem->print_info(libMesh::err);
01153 #else
01154               // In optimized mode, just print once that an inverse_map() call
01155               // had trouble converging its Newton iteration.
01156               libmesh_do_once(libMesh::err << "WARNING: At least one element took more than "
01157                               << max_cnt
01158                               << " iterations to converge in inverse_map()...\n"
01159                               << "Rerun in devel/dbg mode for more details."
01160                               << std::endl;);
01161 
01162 #endif // NDEBUG
01163 
01164               if (cnt > 2*max_cnt)
01165                 {
01166                   libMesh::err << "ERROR: Newton scheme FAILED to converge in "
01167                                << cnt
01168                                << " iterations!"
01169                                << " in element "
01170                                << elem->id()
01171                                << std::endl;
01172 
01173                   elem->print_info(libMesh::err);
01174 
01175                   libmesh_error_msg("Exiting...");
01176                 }
01177             }
01178           //  Return a far off point when secure is false - this
01179           //  should only happen when we're trying to map a point
01180           //  that's outside the element
01181           else
01182             {
01183               for (unsigned int i=0; i != Dim; ++i)
01184                 p(i) = 1e6;
01185 
01186               STOP_LOG("inverse_map()", "FE");
01187               return p;
01188             }
01189         }
01190     }
01191   while (inverse_map_error > tolerance);
01192 
01193 
01194 
01195   //  If we are in debug mode do two sanity checks.
01196 #ifdef DEBUG
01197 
01198   if (secure)
01199     {
01200       // Make sure the point \p p on the reference element actually
01201       // does map to the point \p physical_point within a tolerance.
01202 
01203       const Point check = FE<Dim,T>::map (elem, p);
01204       const Point diff  = physical_point - check;
01205 
01206       if (diff.size() > tolerance)
01207         {
01208           libmesh_here();
01209           libMesh::err << "WARNING:  diff is "
01210                        << diff.size()
01211                        << std::endl
01212                        << " point="
01213                        << physical_point;
01214           libMesh::err << " local=" << check;
01215           libMesh::err << " lref= " << p;
01216 
01217           elem->print_info(libMesh::err);
01218         }
01219 
01220       // Make sure the point \p p on the reference element actually
01221       // is
01222 
01223       if (!FEAbstract::on_reference_element(p, elem->type(), 2*tolerance))
01224         {
01225           libmesh_here();
01226           libMesh::err << "WARNING:  inverse_map of physical point "
01227                        << physical_point
01228                        << "is not on element." << '\n';
01229           elem->print_info(libMesh::err);
01230         }
01231     }
01232 
01233 #endif
01234 
01235 
01236 
01237   //  Stop logging the map inversion.
01238   STOP_LOG("inverse_map()", "FE");
01239 
01240   return p;
01241 }
01242 
01243 
01244 
01245 // TODO: PB: We should consider moving this to the FEMap class
01246 template <unsigned int Dim, FEFamily T>
01247 void FE<Dim,T>::inverse_map (const Elem* elem,
01248                              const std::vector<Point>& physical_points,
01249                              std::vector<Point>&       reference_points,
01250                              const Real tolerance,
01251                              const bool secure)
01252 {
01253   // The number of points to find the
01254   // inverse map of
01255   const std::size_t n_points = physical_points.size();
01256 
01257   // Resize the vector to hold the points
01258   // on the reference element
01259   reference_points.resize(n_points);
01260 
01261   // Find the coordinates on the reference
01262   // element of each point in physical space
01263   for (std::size_t p=0; p<n_points; p++)
01264     reference_points[p] =
01265       FE<Dim,T>::inverse_map (elem, physical_points[p], tolerance, secure);
01266 }
01267 
01268 
01269 
01270 // TODO: PB: We should consider moving this to the FEMap class
01271 template <unsigned int Dim, FEFamily T>
01272 Point FE<Dim,T>::map (const Elem* elem,
01273                       const Point& reference_point)
01274 {
01275   libmesh_assert(elem);
01276 
01277   Point p;
01278 
01279   const ElemType type     = elem->type();
01280   const Order order       = elem->default_order();
01281   const unsigned int n_sf = FE<Dim,LAGRANGE>::n_shape_functions(type, order);
01282 
01283   // Lagrange basis functions are used for mapping
01284   for (unsigned int i=0; i<n_sf; i++)
01285     p.add_scaled (elem->point(i),
01286                   FE<Dim,LAGRANGE>::shape(type,
01287                                           order,
01288                                           i,
01289                                           reference_point)
01290                   );
01291 
01292   return p;
01293 }
01294 
01295 
01296 
01297 // TODO: PB: We should consider moving this to the FEMap class
01298 template <unsigned int Dim, FEFamily T>
01299 Point FE<Dim,T>::map_xi (const Elem* elem,
01300                          const Point& reference_point)
01301 {
01302   libmesh_assert(elem);
01303 
01304   Point p;
01305 
01306   const ElemType type     = elem->type();
01307   const Order order       = elem->default_order();
01308   const unsigned int n_sf = FE<Dim,LAGRANGE>::n_shape_functions(type, order);
01309 
01310   // Lagrange basis functions are used for mapping
01311   for (unsigned int i=0; i<n_sf; i++)
01312     p.add_scaled (elem->point(i),
01313                   FE<Dim,LAGRANGE>::shape_deriv(type,
01314                                                 order,
01315                                                 i,
01316                                                 0,
01317                                                 reference_point)
01318                   );
01319 
01320   return p;
01321 }
01322 
01323 
01324 
01325 // TODO: PB: We should consider moving this to the FEMap class
01326 template <unsigned int Dim, FEFamily T>
01327 Point FE<Dim,T>::map_eta (const Elem* elem,
01328                           const Point& reference_point)
01329 {
01330   libmesh_assert(elem);
01331 
01332   Point p;
01333 
01334   const ElemType type     = elem->type();
01335   const Order order       = elem->default_order();
01336   const unsigned int n_sf = FE<Dim,LAGRANGE>::n_shape_functions(type, order);
01337 
01338   // Lagrange basis functions are used for mapping
01339   for (unsigned int i=0; i<n_sf; i++)
01340     p.add_scaled (elem->point(i),
01341                   FE<Dim,LAGRANGE>::shape_deriv(type,
01342                                                 order,
01343                                                 i,
01344                                                 1,
01345                                                 reference_point)
01346                   );
01347 
01348   return p;
01349 }
01350 
01351 
01352 
01353 // TODO: PB: We should consider moving this to the FEMap class
01354 template <unsigned int Dim, FEFamily T>
01355 Point FE<Dim,T>::map_zeta (const Elem* elem,
01356                            const Point& reference_point)
01357 {
01358   libmesh_assert(elem);
01359 
01360   Point p;
01361 
01362   const ElemType type     = elem->type();
01363   const Order order       = elem->default_order();
01364   const unsigned int n_sf = FE<Dim,LAGRANGE>::n_shape_functions(type, order);
01365 
01366   // Lagrange basis functions are used for mapping
01367   for (unsigned int i=0; i<n_sf; i++)
01368     p.add_scaled (elem->point(i),
01369                   FE<Dim,LAGRANGE>::shape_deriv(type,
01370                                                 order,
01371                                                 i,
01372                                                 2,
01373                                                 reference_point)
01374                   );
01375 
01376   return p;
01377 }
01378 
01379 
01380 
01381 // Explicit instantiation of FEMap member functions
01382 template void FEMap::init_reference_to_physical_map<0>( const std::vector<Point>&, const Elem*);
01383 template void FEMap::init_reference_to_physical_map<1>( const std::vector<Point>&, const Elem*);
01384 template void FEMap::init_reference_to_physical_map<2>( const std::vector<Point>&, const Elem*);
01385 template void FEMap::init_reference_to_physical_map<3>( const std::vector<Point>&, const Elem*);
01386 
01387 //--------------------------------------------------------------
01388 // Explicit instantiations using the macro from fe_macro.h
01389 INSTANTIATE_ALL_MAPS(0);
01390 INSTANTIATE_ALL_MAPS(1);
01391 INSTANTIATE_ALL_MAPS(2);
01392 INSTANTIATE_ALL_MAPS(3);
01393 
01394 // subdivision elements are implemented only for 2D meshes & reimplement
01395 // the inverse_maps method separately
01396 INSTANTIATE_SUBDIVISION_MAPS;
01397 
01398 } // namespace libMesh