$extrastylesheet
hcurl_fe_transformation.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 #include "libmesh/hcurl_fe_transformation.h"
00019 #include "libmesh/fe_interface.h"
00020 
00021 namespace libMesh
00022 {
00023 
00024 template< typename OutputShape >
00025 void HCurlFETransformation<OutputShape>::map_phi( const unsigned int dim,
00026                                                   const Elem* const elem,
00027                                                   const std::vector<Point>& qp,
00028                                                   const FEGenericBase<OutputShape>& fe,
00029                                                   std::vector<std::vector<OutputShape> >& phi ) const
00030 {
00031   switch (dim)
00032     {
00033     case 0:
00034     case 1:
00035       libmesh_error_msg("These element transformations only make sense in 2D and 3D.");
00036 
00037     case 2:
00038       {
00039         const std::vector<Real>& dxidx_map = fe.get_fe_map().get_dxidx();
00040         const std::vector<Real>& dxidy_map = fe.get_fe_map().get_dxidy();
00041 
00042         const std::vector<Real>& detadx_map = fe.get_fe_map().get_detadx();
00043         const std::vector<Real>& detady_map = fe.get_fe_map().get_detady();
00044 
00045         // FIXME: Need to update for 2D elements in 3D space
00046         /* phi = (dx/dxi)^-T * \hat{phi}
00047            In 2D:
00048            (dx/dxi)^{-1} = [  dxi/dx   dxi/dy
00049            deta/dx  deta/dy ]
00050 
00051            so: dxi/dx^{-T} * \hat{phi} = [ dxi/dx  deta/dx   [ \hat{phi}_xi
00052            dxi/dy  deta/dy ]   \hat{phi}_eta ]
00053 
00054            or in indicial notation:  phi_j = xi_{i,j}*\hat{phi}_i */
00055 
00056         for (unsigned int i=0; i<phi.size(); i++)
00057           for (unsigned int p=0; p<phi[i].size(); p++)
00058             {
00059               // Need to temporarily cache reference shape functions
00060               // TODO: PB: Might be worth trying to build phi_ref separately to see
00061               //           if we can get vectorization
00062               OutputShape phi_ref;
00063               FEInterface::shape<OutputShape>(2, fe.get_fe_type(), elem, i, qp[p], phi_ref);
00064 
00065               phi[i][p](0) = dxidx_map[p]*phi_ref.slice(0) + detadx_map[p]*phi_ref.slice(1);
00066 
00067               phi[i][p](1) = dxidy_map[p]*phi_ref.slice(0) + detady_map[p]*phi_ref.slice(1);
00068             }
00069 
00070         break;
00071       }
00072 
00073     case 3:
00074       {
00075         const std::vector<Real>& dxidx_map = fe.get_fe_map().get_dxidx();
00076         const std::vector<Real>& dxidy_map = fe.get_fe_map().get_dxidy();
00077         const std::vector<Real>& dxidz_map = fe.get_fe_map().get_dxidz();
00078 
00079         const std::vector<Real>& detadx_map = fe.get_fe_map().get_detadx();
00080         const std::vector<Real>& detady_map = fe.get_fe_map().get_detady();
00081         const std::vector<Real>& detadz_map = fe.get_fe_map().get_detadz();
00082 
00083         const std::vector<Real>& dzetadx_map = fe.get_fe_map().get_dzetadx();
00084         const std::vector<Real>& dzetady_map = fe.get_fe_map().get_dzetady();
00085         const std::vector<Real>& dzetadz_map = fe.get_fe_map().get_dzetadz();
00086 
00087         /* phi = (dx/dxi)^-T * \hat{phi}
00088            In 3D:
00089            dx/dxi^-1 = [  dxi/dx    dxi/dy    dxi/dz
00090            deta/dx   deta/dy   deta/dz
00091            dzeta/dx  dzeta/dy  dzeta/dz]
00092 
00093            so: dxi/dx^-T * \hat{phi} = [ dxi/dx  deta/dx  dzeta/dx   [ \hat{phi}_xi
00094            dxi/dy  deta/dy  dzeta/dy     \hat{phi}_eta
00095            dxi/dz  deta/dz  dzeta/dz ]   \hat{phi}_zeta ]
00096 
00097            or in indicial notation:  phi_j = xi_{i,j}*\hat{phi}_i */
00098 
00099         for (unsigned int i=0; i<phi.size(); i++)
00100           for (unsigned int p=0; p<phi[i].size(); p++)
00101             {
00102               // Need to temporarily cache reference shape functions
00103               // TODO: PB: Might be worth trying to build phi_ref separately to see
00104               //           if we can get vectorization
00105               OutputShape phi_ref;
00106               FEInterface::shape<OutputShape>(3, fe.get_fe_type(), elem, i, qp[p], phi_ref);
00107 
00108               phi[i][p].slice(0) = dxidx_map[p]*phi_ref.slice(0) + detadx_map[p]*phi_ref.slice(1)
00109                 + dzetadx_map[p]*phi_ref.slice(2);
00110 
00111               phi[i][p].slice(1) = dxidy_map[p]*phi_ref.slice(0) + detady_map[p]*phi_ref.slice(1)
00112                 + dzetady_map[p]*phi_ref.slice(2);
00113 
00114               phi[i][p].slice(2) = dxidz_map[p]*phi_ref.slice(0) + detadz_map[p]*phi_ref.slice(1)
00115                 + dzetadz_map[p]*phi_ref.slice(2);
00116             }
00117         break;
00118       }
00119 
00120     default:
00121       libmesh_error_msg("Invalid dim = " << dim);
00122     } // switch(dim)
00123 }
00124 
00125 template< typename OutputShape >
00126 void HCurlFETransformation<OutputShape>::map_curl( const unsigned int dim,
00127                                                    const Elem* const,
00128                                                    const std::vector<Point>&,
00129                                                    const FEGenericBase<OutputShape>& fe,
00130                                                    std::vector<std::vector<OutputShape> >& curl_phi ) const
00131 {
00132   switch (dim)
00133     {
00134     case 0:
00135     case 1:
00136       libmesh_error_msg("These element transformations only make sense in 2D and 3D.");
00137 
00138     case 2:
00139       {
00140         const std::vector<std::vector<OutputShape> >& dphi_dxi = fe.get_dphidxi();
00141         const std::vector<std::vector<OutputShape> >& dphi_deta = fe.get_dphideta();
00142 
00143         const std::vector<Real>& J = fe.get_fe_map().get_jacobian();
00144 
00145         // FIXME: I don't think this is valid for 2D elements in 3D space
00146         /* In 2D: curl(phi) = J^{-1} * curl(\hat{phi}) */
00147         for (unsigned int i=0; i<curl_phi.size(); i++)
00148           for (unsigned int p=0; p<curl_phi[i].size(); p++)
00149             {
00150               curl_phi[i][p].slice(0) = curl_phi[i][p].slice(1) = 0.0;
00151 
00152               curl_phi[i][p].slice(2) = ( dphi_dxi[i][p].slice(1) - dphi_deta[i][p].slice(0) )/J[p];
00153             }
00154 
00155         break;
00156       }
00157 
00158     case 3:
00159       {
00160         const std::vector<std::vector<OutputShape> >& dphi_dxi = fe.get_dphidxi();
00161         const std::vector<std::vector<OutputShape> >& dphi_deta = fe.get_dphideta();
00162         const std::vector<std::vector<OutputShape> >& dphi_dzeta = fe.get_dphidzeta();
00163 
00164         const std::vector<RealGradient>& dxyz_dxi   = fe.get_fe_map().get_dxyzdxi();
00165         const std::vector<RealGradient>& dxyz_deta  = fe.get_fe_map().get_dxyzdeta();
00166         const std::vector<RealGradient>& dxyz_dzeta = fe.get_fe_map().get_dxyzdzeta();
00167 
00168         const std::vector<Real>& J = fe.get_fe_map().get_jacobian();
00169 
00170         for (unsigned int i=0; i<curl_phi.size(); i++)
00171           for (unsigned int p=0; p<curl_phi[i].size(); p++)
00172             {
00173               Real dx_dxi   = dxyz_dxi[p](0);
00174               Real dx_deta  = dxyz_deta[p](0);
00175               Real dx_dzeta = dxyz_dzeta[p](0);
00176 
00177               Real dy_dxi   = dxyz_dxi[p](1);
00178               Real dy_deta  = dxyz_deta[p](1);
00179               Real dy_dzeta = dxyz_dzeta[p](1);
00180 
00181               Real dz_dxi   = dxyz_dxi[p](2);
00182               Real dz_deta  = dxyz_deta[p](2);
00183               Real dz_dzeta = dxyz_dzeta[p](2);
00184 
00185               const Real inv_jac = 1.0/J[p];
00186 
00187               /* In 3D: curl(phi) = J^{-1} dx/dxi * curl(\hat{phi})
00188 
00189                  dx/dxi = [  dx/dxi  dx/deta  dx/dzeta
00190                  dy/dxi  dy/deta  dy/dzeta
00191                  dz/dxi  dz/deta  dz/dzeta ]
00192 
00193                  curl(u) = [ du_z/deta  - du_y/dzeta
00194                  du_x/dzeta - du_z/dxi
00195                  du_y/dxi   - du_x/deta ]
00196               */
00197               curl_phi[i][p].slice(0) = inv_jac*( dx_dxi*( dphi_deta[i][p].slice(2)  -
00198                                                            dphi_dzeta[i][p].slice(1)   ) +
00199                                                   dx_deta*( dphi_dzeta[i][p].slice(0) -
00200                                                             dphi_dxi[i][p].slice(2)     ) +
00201                                                   dx_dzeta*( dphi_dxi[i][p].slice(1) -
00202                                                              dphi_deta[i][p].slice(0)    ) );
00203 
00204               curl_phi[i][p].slice(1) = inv_jac*( dy_dxi*( dphi_deta[i][p].slice(2) -
00205                                                            dphi_dzeta[i][p].slice(1)  ) +
00206                                                   dy_deta*( dphi_dzeta[i][p].slice(0)-
00207                                                             dphi_dxi[i][p].slice(2)    ) +
00208                                                   dy_dzeta*( dphi_dxi[i][p].slice(1) -
00209                                                              dphi_deta[i][p].slice(0)   ) );
00210 
00211               curl_phi[i][p].slice(2) = inv_jac*( dz_dxi*( dphi_deta[i][p].slice(2) -
00212                                                            dphi_dzeta[i][p].slice(1)   ) +
00213                                                   dz_deta*( dphi_dzeta[i][p].slice(0) -
00214                                                             dphi_dxi[i][p].slice(2)     ) +
00215                                                   dz_dzeta*( dphi_dxi[i][p].slice(1) -
00216                                                              dphi_deta[i][p].slice(0)    ) );
00217             }
00218 
00219         break;
00220       }
00221 
00222     default:
00223       libmesh_error_msg("Invalid dim = " << dim);
00224     } // switch(dim)
00225 }
00226 
00227 template class HCurlFETransformation<RealGradient>;
00228 
00229 template<>
00230 void HCurlFETransformation<Real>::map_phi( const unsigned int,
00231                                            const Elem* const,
00232                                            const std::vector<Point>&,
00233                                            const FEGenericBase<Real>&,
00234                                            std::vector<std::vector<Real> >& ) const
00235 {
00236   libmesh_error_msg("HCurl transformations only make sense for vector-valued elements.");
00237 }
00238 
00239 template<>
00240 void HCurlFETransformation<Real>::map_curl( const unsigned int,
00241                                             const Elem* const,
00242                                             const std::vector<Point>&,
00243                                             const FEGenericBase<Real>&,
00244                                             std::vector<std::vector<Real> >& ) const
00245 {
00246   libmesh_error_msg("HCurl transformations only make sense for vector-valued elements.");
00247 }
00248 
00249 
00250 } // namespace libMesh