$extrastylesheet
fe_abstract.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 
00020 // Local includes
00021 #include "libmesh/fe.h"
00022 #include "libmesh/libmesh_logging.h"
00023 
00024 // For projection code:
00025 #include "libmesh/boundary_info.h"
00026 #include "libmesh/mesh_base.h"
00027 #include "libmesh/dense_matrix.h"
00028 #include "libmesh/dense_vector.h"
00029 #include "libmesh/dof_map.h"
00030 #include "libmesh/elem.h"
00031 #include "libmesh/fe_interface.h"
00032 #include "libmesh/numeric_vector.h"
00033 #include "libmesh/periodic_boundaries.h"
00034 #include "libmesh/periodic_boundary.h"
00035 #include "libmesh/quadrature.h"
00036 #include "libmesh/quadrature_gauss.h"
00037 #include "libmesh/remote_elem.h"
00038 #include "libmesh/tensor_value.h"
00039 #include "libmesh/threads.h"
00040 
00041 namespace libMesh
00042 {
00043 
00044 UniquePtr<FEAbstract> FEAbstract::build(const unsigned int dim,
00045                                         const FEType& fet)
00046 {
00047   switch (dim)
00048     {
00049       // 0D
00050     case 0:
00051       {
00052         switch (fet.family)
00053           {
00054           case CLOUGH:
00055             return UniquePtr<FEAbstract>(new FE<0,CLOUGH>(fet));
00056 
00057           case HERMITE:
00058             return UniquePtr<FEAbstract>(new FE<0,HERMITE>(fet));
00059 
00060           case LAGRANGE:
00061             return UniquePtr<FEAbstract>(new FE<0,LAGRANGE>(fet));
00062 
00063           case LAGRANGE_VEC:
00064             return UniquePtr<FEAbstract>(new FE<0,LAGRANGE_VEC>(fet));
00065 
00066           case L2_LAGRANGE:
00067             return UniquePtr<FEAbstract>(new FE<0,L2_LAGRANGE>(fet));
00068 
00069           case HIERARCHIC:
00070             return UniquePtr<FEAbstract>(new FE<0,HIERARCHIC>(fet));
00071 
00072           case L2_HIERARCHIC:
00073             return UniquePtr<FEAbstract>(new FE<0,L2_HIERARCHIC>(fet));
00074 
00075           case MONOMIAL:
00076             return UniquePtr<FEAbstract>(new FE<0,MONOMIAL>(fet));
00077 
00078 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00079           case SZABAB:
00080             return UniquePtr<FEAbstract>(new FE<0,SZABAB>(fet));
00081 
00082           case BERNSTEIN:
00083             return UniquePtr<FEAbstract>(new FE<0,BERNSTEIN>(fet));
00084 #endif
00085 
00086           case XYZ:
00087             return UniquePtr<FEAbstract>(new FEXYZ<0>(fet));
00088 
00089           case SCALAR:
00090             return UniquePtr<FEAbstract>(new FEScalar<0>(fet));
00091 
00092           default:
00093             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00094           }
00095       }
00096       // 1D
00097     case 1:
00098       {
00099         switch (fet.family)
00100           {
00101           case CLOUGH:
00102             return UniquePtr<FEAbstract>(new FE<1,CLOUGH>(fet));
00103 
00104           case HERMITE:
00105             return UniquePtr<FEAbstract>(new FE<1,HERMITE>(fet));
00106 
00107           case LAGRANGE:
00108             return UniquePtr<FEAbstract>(new FE<1,LAGRANGE>(fet));
00109 
00110           case LAGRANGE_VEC:
00111             return UniquePtr<FEAbstract>(new FE<1,LAGRANGE_VEC>(fet));
00112 
00113           case L2_LAGRANGE:
00114             return UniquePtr<FEAbstract>(new FE<1,L2_LAGRANGE>(fet));
00115 
00116           case HIERARCHIC:
00117             return UniquePtr<FEAbstract>(new FE<1,HIERARCHIC>(fet));
00118 
00119           case L2_HIERARCHIC:
00120             return UniquePtr<FEAbstract>(new FE<1,L2_HIERARCHIC>(fet));
00121 
00122           case MONOMIAL:
00123             return UniquePtr<FEAbstract>(new FE<1,MONOMIAL>(fet));
00124 
00125 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00126           case SZABAB:
00127             return UniquePtr<FEAbstract>(new FE<1,SZABAB>(fet));
00128 
00129           case BERNSTEIN:
00130             return UniquePtr<FEAbstract>(new FE<1,BERNSTEIN>(fet));
00131 #endif
00132 
00133           case XYZ:
00134             return UniquePtr<FEAbstract>(new FEXYZ<1>(fet));
00135 
00136           case SCALAR:
00137             return UniquePtr<FEAbstract>(new FEScalar<1>(fet));
00138 
00139           default:
00140             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00141           }
00142       }
00143 
00144 
00145       // 2D
00146     case 2:
00147       {
00148         switch (fet.family)
00149           {
00150           case CLOUGH:
00151             return UniquePtr<FEAbstract>(new FE<2,CLOUGH>(fet));
00152 
00153           case HERMITE:
00154             return UniquePtr<FEAbstract>(new FE<2,HERMITE>(fet));
00155 
00156           case LAGRANGE:
00157             return UniquePtr<FEAbstract>(new FE<2,LAGRANGE>(fet));
00158 
00159           case LAGRANGE_VEC:
00160             return UniquePtr<FEAbstract>(new FE<2,LAGRANGE_VEC>(fet));
00161 
00162           case L2_LAGRANGE:
00163             return UniquePtr<FEAbstract>(new FE<2,L2_LAGRANGE>(fet));
00164 
00165           case HIERARCHIC:
00166             return UniquePtr<FEAbstract>(new FE<2,HIERARCHIC>(fet));
00167 
00168           case L2_HIERARCHIC:
00169             return UniquePtr<FEAbstract>(new FE<2,L2_HIERARCHIC>(fet));
00170 
00171           case MONOMIAL:
00172             return UniquePtr<FEAbstract>(new FE<2,MONOMIAL>(fet));
00173 
00174 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00175           case SZABAB:
00176             return UniquePtr<FEAbstract>(new FE<2,SZABAB>(fet));
00177 
00178           case BERNSTEIN:
00179             return UniquePtr<FEAbstract>(new FE<2,BERNSTEIN>(fet));
00180 #endif
00181 
00182           case XYZ:
00183             return UniquePtr<FEAbstract>(new FEXYZ<2>(fet));
00184 
00185           case SCALAR:
00186             return UniquePtr<FEAbstract>(new FEScalar<2>(fet));
00187 
00188           case NEDELEC_ONE:
00189             return UniquePtr<FEAbstract>(new FENedelecOne<2>(fet));
00190 
00191           case SUBDIVISION:
00192             return UniquePtr<FEAbstract>(new FESubdivision(fet));
00193 
00194           default:
00195             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00196           }
00197       }
00198 
00199 
00200       // 3D
00201     case 3:
00202       {
00203         switch (fet.family)
00204           {
00205           case CLOUGH:
00206             libmesh_error_msg("ERROR: Clough-Tocher elements currently only support 1D and 2D");
00207 
00208           case HERMITE:
00209             return UniquePtr<FEAbstract>(new FE<3,HERMITE>(fet));
00210 
00211           case LAGRANGE:
00212             return UniquePtr<FEAbstract>(new FE<3,LAGRANGE>(fet));
00213 
00214           case LAGRANGE_VEC:
00215             return UniquePtr<FEAbstract>(new FE<3,LAGRANGE_VEC>(fet));
00216 
00217           case L2_LAGRANGE:
00218             return UniquePtr<FEAbstract>(new FE<3,L2_LAGRANGE>(fet));
00219 
00220           case HIERARCHIC:
00221             return UniquePtr<FEAbstract>(new FE<3,HIERARCHIC>(fet));
00222 
00223           case L2_HIERARCHIC:
00224             return UniquePtr<FEAbstract>(new FE<3,L2_HIERARCHIC>(fet));
00225 
00226           case MONOMIAL:
00227             return UniquePtr<FEAbstract>(new FE<3,MONOMIAL>(fet));
00228 
00229 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00230           case SZABAB:
00231             return UniquePtr<FEAbstract>(new FE<3,SZABAB>(fet));
00232 
00233           case BERNSTEIN:
00234             return UniquePtr<FEAbstract>(new FE<3,BERNSTEIN>(fet));
00235 #endif
00236 
00237           case XYZ:
00238             return UniquePtr<FEAbstract>(new FEXYZ<3>(fet));
00239 
00240           case SCALAR:
00241             return UniquePtr<FEAbstract>(new FEScalar<3>(fet));
00242 
00243           case NEDELEC_ONE:
00244             return UniquePtr<FEAbstract>(new FENedelecOne<3>(fet));
00245 
00246           default:
00247             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00248           }
00249       }
00250 
00251     default:
00252       libmesh_error_msg("Invalid dimension dim = " << dim);
00253     }
00254 
00255   libmesh_error_msg("We'll never get here!");
00256   return UniquePtr<FEAbstract>();
00257 }
00258 
00259 void FEAbstract::get_refspace_nodes(const ElemType itemType, std::vector<Point>& nodes)
00260 {
00261   switch(itemType)
00262     {
00263     case EDGE2:
00264       {
00265         nodes.resize(2);
00266         nodes[0] = Point (-1.,0.,0.);
00267         nodes[1] = Point (1.,0.,0.);
00268         return;
00269       }
00270     case EDGE3:
00271       {
00272         nodes.resize(3);
00273         nodes[0] = Point (-1.,0.,0.);
00274         nodes[1] = Point (1.,0.,0.);
00275         nodes[2] = Point (0.,0.,0.);
00276         return;
00277       }
00278     case TRI3:
00279       {
00280         nodes.resize(3);
00281         nodes[0] = Point (0.,0.,0.);
00282         nodes[1] = Point (1.,0.,0.);
00283         nodes[2] = Point (0.,1.,0.);
00284         return;
00285       }
00286     case TRI6:
00287       {
00288         nodes.resize(6);
00289         nodes[0] = Point (0.,0.,0.);
00290         nodes[1] = Point (1.,0.,0.);
00291         nodes[2] = Point (0.,1.,0.);
00292         nodes[3] = Point (.5,0.,0.);
00293         nodes[4] = Point (.5,.5,0.);
00294         nodes[5] = Point (0.,.5,0.);
00295         return;
00296       }
00297     case QUAD4:
00298       {
00299         nodes.resize(4);
00300         nodes[0] = Point (-1.,-1.,0.);
00301         nodes[1] = Point (1.,-1.,0.);
00302         nodes[2] = Point (1.,1.,0.);
00303         nodes[3] = Point (-1.,1.,0.);
00304         return;
00305       }
00306     case QUAD8:
00307       {
00308         nodes.resize(8);
00309         nodes[0] = Point (-1.,-1.,0.);
00310         nodes[1] = Point (1.,-1.,0.);
00311         nodes[2] = Point (1.,1.,0.);
00312         nodes[3] = Point (-1.,1.,0.);
00313         nodes[4] = Point (0.,-1.,0.);
00314         nodes[5] = Point (1.,0.,0.);
00315         nodes[6] = Point (0.,1.,0.);
00316         nodes[7] = Point (-1.,0.,0.);
00317         return;
00318       }
00319     case QUAD9:
00320       {
00321         nodes.resize(9);
00322         nodes[0] = Point (-1.,-1.,0.);
00323         nodes[1] = Point (1.,-1.,0.);
00324         nodes[2] = Point (1.,1.,0.);
00325         nodes[3] = Point (-1.,1.,0.);
00326         nodes[4] = Point (0.,-1.,0.);
00327         nodes[5] = Point (1.,0.,0.);
00328         nodes[6] = Point (0.,1.,0.);
00329         nodes[7] = Point (-1.,0.,0.);
00330         nodes[8] = Point (0.,0.,0.);
00331         return;
00332       }
00333     case TET4:
00334       {
00335         nodes.resize(4);
00336         nodes[0] = Point (0.,0.,0.);
00337         nodes[1] = Point (1.,0.,0.);
00338         nodes[2] = Point (0.,1.,0.);
00339         nodes[3] = Point (0.,0.,1.);
00340         return;
00341       }
00342     case TET10:
00343       {
00344         nodes.resize(10);
00345         nodes[0] = Point (0.,0.,0.);
00346         nodes[1] = Point (1.,0.,0.);
00347         nodes[2] = Point (0.,1.,0.);
00348         nodes[3] = Point (0.,0.,1.);
00349         nodes[4] = Point (.5,0.,0.);
00350         nodes[5] = Point (.5,.5,0.);
00351         nodes[6] = Point (0.,.5,0.);
00352         nodes[7] = Point (0.,0.,.5);
00353         nodes[8] = Point (.5,0.,.5);
00354         nodes[9] = Point (0.,.5,.5);
00355         return;
00356       }
00357     case HEX8:
00358       {
00359         nodes.resize(8);
00360         nodes[0] = Point (-1.,-1.,-1.);
00361         nodes[1] = Point (1.,-1.,-1.);
00362         nodes[2] = Point (1.,1.,-1.);
00363         nodes[3] = Point (-1.,1.,-1.);
00364         nodes[4] = Point (-1.,-1.,1.);
00365         nodes[5] = Point (1.,-1.,1.);
00366         nodes[6] = Point (1.,1.,1.);
00367         nodes[7] = Point (-1.,1.,1.);
00368         return;
00369       }
00370     case HEX20:
00371       {
00372         nodes.resize(20);
00373         nodes[0] = Point (-1.,-1.,-1.);
00374         nodes[1] = Point (1.,-1.,-1.);
00375         nodes[2] = Point (1.,1.,-1.);
00376         nodes[3] = Point (-1.,1.,-1.);
00377         nodes[4] = Point (-1.,-1.,1.);
00378         nodes[5] = Point (1.,-1.,1.);
00379         nodes[6] = Point (1.,1.,1.);
00380         nodes[7] = Point (-1.,1.,1.);
00381         nodes[8] = Point (0.,-1.,-1.);
00382         nodes[9] = Point (1.,0.,-1.);
00383         nodes[10] = Point (0.,1.,-1.);
00384         nodes[11] = Point (-1.,0.,-1.);
00385         nodes[12] = Point (-1.,-1.,0.);
00386         nodes[13] = Point (1.,-1.,0.);
00387         nodes[14] = Point (1.,1.,0.);
00388         nodes[15] = Point (-1.,1.,0.);
00389         nodes[16] = Point (0.,-1.,1.);
00390         nodes[17] = Point (1.,0.,1.);
00391         nodes[18] = Point (0.,1.,1.);
00392         nodes[19] = Point (-1.,0.,1.);
00393         return;
00394       }
00395     case HEX27:
00396       {
00397         nodes.resize(27);
00398         nodes[0] = Point (-1.,-1.,-1.);
00399         nodes[1] = Point (1.,-1.,-1.);
00400         nodes[2] = Point (1.,1.,-1.);
00401         nodes[3] = Point (-1.,1.,-1.);
00402         nodes[4] = Point (-1.,-1.,1.);
00403         nodes[5] = Point (1.,-1.,1.);
00404         nodes[6] = Point (1.,1.,1.);
00405         nodes[7] = Point (-1.,1.,1.);
00406         nodes[8] = Point (0.,-1.,-1.);
00407         nodes[9] = Point (1.,0.,-1.);
00408         nodes[10] = Point (0.,1.,-1.);
00409         nodes[11] = Point (-1.,0.,-1.);
00410         nodes[12] = Point (-1.,-1.,0.);
00411         nodes[13] = Point (1.,-1.,0.);
00412         nodes[14] = Point (1.,1.,0.);
00413         nodes[15] = Point (-1.,1.,0.);
00414         nodes[16] = Point (0.,-1.,1.);
00415         nodes[17] = Point (1.,0.,1.);
00416         nodes[18] = Point (0.,1.,1.);
00417         nodes[19] = Point (-1.,0.,1.);
00418         nodes[20] = Point (0.,0.,-1.);
00419         nodes[21] = Point (0.,-1.,0.);
00420         nodes[22] = Point (1.,0.,0.);
00421         nodes[23] = Point (0.,1.,0.);
00422         nodes[24] = Point (-1.,0.,0.);
00423         nodes[25] = Point (0.,0.,1.);
00424         nodes[26] = Point (0.,0.,0.);
00425         return;
00426       }
00427     case PRISM6:
00428       {
00429         nodes.resize(6);
00430         nodes[0] = Point (0.,0.,-1.);
00431         nodes[1] = Point (1.,0.,-1.);
00432         nodes[2] = Point (0.,1.,-1.);
00433         nodes[3] = Point (0.,0.,1.);
00434         nodes[4] = Point (1.,0.,1.);
00435         nodes[5] = Point (0.,1.,1.);
00436         return;
00437       }
00438     case PRISM15:
00439       {
00440         nodes.resize(15);
00441         nodes[0] = Point (0.,0.,-1.);
00442         nodes[1] = Point (1.,0.,-1.);
00443         nodes[2] = Point (0.,1.,-1.);
00444         nodes[3] = Point (0.,0.,1.);
00445         nodes[4] = Point (1.,0.,1.);
00446         nodes[5] = Point (0.,1.,1.);
00447         nodes[6] = Point (.5,0.,-1.);
00448         nodes[7] = Point (.5,.5,-1.);
00449         nodes[8] = Point (0.,.5,-1.);
00450         nodes[9] = Point (0.,0.,0.);
00451         nodes[10] = Point (1.,0.,0.);
00452         nodes[11] = Point (0.,1.,0.);
00453         nodes[12] = Point (.5,0.,1.);
00454         nodes[13] = Point (.5,.5,1.);
00455         nodes[14] = Point (0.,.5,1.);
00456         return;
00457       }
00458     case PRISM18:
00459       {
00460         nodes.resize(18);
00461         nodes[0] = Point (0.,0.,-1.);
00462         nodes[1] = Point (1.,0.,-1.);
00463         nodes[2] = Point (0.,1.,-1.);
00464         nodes[3] = Point (0.,0.,1.);
00465         nodes[4] = Point (1.,0.,1.);
00466         nodes[5] = Point (0.,1.,1.);
00467         nodes[6] = Point (.5,0.,-1.);
00468         nodes[7] = Point (.5,.5,-1.);
00469         nodes[8] = Point (0.,.5,-1.);
00470         nodes[9] = Point (0.,0.,0.);
00471         nodes[10] = Point (1.,0.,0.);
00472         nodes[11] = Point (0.,1.,0.);
00473         nodes[12] = Point (.5,0.,1.);
00474         nodes[13] = Point (.5,.5,1.);
00475         nodes[14] = Point (0.,.5,1.);
00476         nodes[15] = Point (.5,0.,0.);
00477         nodes[16] = Point (.5,.5,0.);
00478         nodes[17] = Point (0.,.5,0.);
00479         return;
00480       }
00481     case PYRAMID5:
00482       {
00483         nodes.resize(5);
00484         nodes[0] = Point (-1.,-1.,0.);
00485         nodes[1] = Point (1.,-1.,0.);
00486         nodes[2] = Point (1.,1.,0.);
00487         nodes[3] = Point (-1.,1.,0.);
00488         nodes[4] = Point (0.,0.,1.);
00489         return;
00490       }
00491     case PYRAMID13:
00492       {
00493         nodes.resize(13);
00494 
00495         // base corners
00496         nodes[0] = Point (-1.,-1.,0.);
00497         nodes[1] = Point (1.,-1.,0.);
00498         nodes[2] = Point (1.,1.,0.);
00499         nodes[3] = Point (-1.,1.,0.);
00500 
00501         // apex
00502         nodes[4] = Point (0.,0.,1.);
00503 
00504         // base midedge
00505         nodes[5] = Point (0.,-1.,0.);
00506         nodes[6] = Point (1.,0.,0.);
00507         nodes[7] = Point (0.,1.,0.);
00508         nodes[8] = Point (-1,0.,0.);
00509 
00510         // lateral midedge
00511         nodes[9] = Point (-.5,-.5,.5);
00512         nodes[10] = Point (.5,-.5,.5);
00513         nodes[11] = Point (.5,.5,.5);
00514         nodes[12] = Point (-.5,.5,.5);
00515 
00516         return;
00517       }
00518     case PYRAMID14:
00519       {
00520         nodes.resize(14);
00521 
00522         // base corners
00523         nodes[0] = Point (-1.,-1.,0.);
00524         nodes[1] = Point (1.,-1.,0.);
00525         nodes[2] = Point (1.,1.,0.);
00526         nodes[3] = Point (-1.,1.,0.);
00527 
00528         // apex
00529         nodes[4] = Point (0.,0.,1.);
00530 
00531         // base midedge
00532         nodes[5] = Point (0.,-1.,0.);
00533         nodes[6] = Point (1.,0.,0.);
00534         nodes[7] = Point (0.,1.,0.);
00535         nodes[8] = Point (-1,0.,0.);
00536 
00537         // lateral midedge
00538         nodes[9] = Point (-.5,-.5,.5);
00539         nodes[10] = Point (.5,-.5,.5);
00540         nodes[11] = Point (.5,.5,.5);
00541         nodes[12] = Point (-.5,.5,.5);
00542 
00543         // base center
00544         nodes[13] = Point (0.,0.,0.);
00545 
00546         return;
00547       }
00548 
00549     default:
00550       libmesh_error_msg("ERROR: Unknown element type " << itemType);
00551     }
00552 }
00553 
00554 bool FEAbstract::on_reference_element(const Point& p, const ElemType t, const Real eps)
00555 {
00556   libmesh_assert_greater_equal (eps, 0.);
00557 
00558   const Real xi   = p(0);
00559 #if LIBMESH_DIM > 1
00560   const Real eta  = p(1);
00561 #else
00562   const Real eta  = 0.;
00563 #endif
00564 #if LIBMESH_DIM > 2
00565   const Real zeta = p(2);
00566 #else
00567   const Real zeta  = 0.;
00568 #endif
00569 
00570   switch (t)
00571     {
00572     case NODEELEM:
00573       {
00574         return (!xi && !eta && !zeta);
00575       }
00576     case EDGE2:
00577     case EDGE3:
00578     case EDGE4:
00579       {
00580         // The reference 1D element is [-1,1].
00581         if ((xi >= -1.-eps) &&
00582             (xi <=  1.+eps))
00583           return true;
00584 
00585         return false;
00586       }
00587 
00588 
00589     case TRI3:
00590     case TRI6:
00591       {
00592         // The reference triangle is isocoles
00593         // and is bound by xi=0, eta=0, and xi+eta=1.
00594         if ((xi  >= 0.-eps) &&
00595             (eta >= 0.-eps) &&
00596             ((xi + eta) <= 1.+eps))
00597           return true;
00598 
00599         return false;
00600       }
00601 
00602 
00603     case QUAD4:
00604     case QUAD8:
00605     case QUAD9:
00606       {
00607         // The reference quadrilateral element is [-1,1]^2.
00608         if ((xi  >= -1.-eps) &&
00609             (xi  <=  1.+eps) &&
00610             (eta >= -1.-eps) &&
00611             (eta <=  1.+eps))
00612           return true;
00613 
00614         return false;
00615       }
00616 
00617 
00618     case TET4:
00619     case TET10:
00620       {
00621         // The reference tetrahedral is isocoles
00622         // and is bound by xi=0, eta=0, zeta=0,
00623         // and xi+eta+zeta=1.
00624         if ((xi   >= 0.-eps) &&
00625             (eta  >= 0.-eps) &&
00626             (zeta >= 0.-eps) &&
00627             ((xi + eta + zeta) <= 1.+eps))
00628           return true;
00629 
00630         return false;
00631       }
00632 
00633 
00634     case HEX8:
00635     case HEX20:
00636     case HEX27:
00637       {
00638         /*
00639           if ((xi   >= -1.) &&
00640           (xi   <=  1.) &&
00641           (eta  >= -1.) &&
00642           (eta  <=  1.) &&
00643           (zeta >= -1.) &&
00644           (zeta <=  1.))
00645           return true;
00646         */
00647 
00648         // The reference hexahedral element is [-1,1]^3.
00649         if ((xi   >= -1.-eps) &&
00650             (xi   <=  1.+eps) &&
00651             (eta  >= -1.-eps) &&
00652             (eta  <=  1.+eps) &&
00653             (zeta >= -1.-eps) &&
00654             (zeta <=  1.+eps))
00655           {
00656             //    libMesh::out << "Strange Point:\n";
00657             //    p.print();
00658             return true;
00659           }
00660 
00661         return false;
00662       }
00663 
00664     case PRISM6:
00665     case PRISM15:
00666     case PRISM18:
00667       {
00668         // Figure this one out...
00669         // inside the reference triange with zeta in [-1,1]
00670         if ((xi   >=  0.-eps) &&
00671             (eta  >=  0.-eps) &&
00672             (zeta >= -1.-eps) &&
00673             (zeta <=  1.+eps) &&
00674             ((xi + eta) <= 1.+eps))
00675           return true;
00676 
00677         return false;
00678       }
00679 
00680 
00681     case PYRAMID5:
00682     case PYRAMID13:
00683     case PYRAMID14:
00684       {
00685         // Check that the point is on the same side of all the faces
00686         // by testing whether:
00687         //
00688         // n_i.(x - x_i) <= 0
00689         //
00690         // for each i, where:
00691         //   n_i is the outward normal of face i,
00692         //   x_i is a point on face i.
00693         if ((-eta - 1. + zeta <= 0.+eps) &&
00694             (  xi - 1. + zeta <= 0.+eps) &&
00695             ( eta - 1. + zeta <= 0.+eps) &&
00696             ( -xi - 1. + zeta <= 0.+eps) &&
00697             (            zeta >= 0.-eps))
00698           return true;
00699 
00700         return false;
00701       }
00702 
00703 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00704     case INFHEX8:
00705       {
00706         // The reference infhex8 is a [-1,1]^3.
00707         if ((xi   >= -1.-eps) &&
00708             (xi   <=  1.+eps) &&
00709             (eta  >= -1.-eps) &&
00710             (eta  <=  1.+eps) &&
00711             (zeta >= -1.-eps) &&
00712             (zeta <=  1.+eps))
00713           {
00714             return true;
00715           }
00716         return false;
00717       }
00718 
00719     case INFPRISM6:
00720       {
00721         // inside the reference triange with zeta in [-1,1]
00722         if ((xi   >=  0.-eps) &&
00723             (eta  >=  0.-eps) &&
00724             (zeta >= -1.-eps) &&
00725             (zeta <=  1.+eps) &&
00726             ((xi + eta) <= 1.+eps))
00727           {
00728             return true;
00729           }
00730 
00731         return false;
00732       }
00733 #endif
00734 
00735     default:
00736       libmesh_error_msg("ERROR: Unknown element type " << t);
00737     }
00738 
00739   // If we get here then the point is _not_ in the
00740   // reference element.   Better return false.
00741 
00742   return false;
00743 }
00744 
00745 
00746 
00747 
00748 void FEAbstract::print_JxW(std::ostream& os) const
00749 {
00750   this->_fe_map->print_JxW(os);
00751 }
00752 
00753 
00754 
00755 void FEAbstract::print_xyz(std::ostream& os) const
00756 {
00757   this->_fe_map->print_xyz(os);
00758 }
00759 
00760 
00761 void FEAbstract::print_info(std::ostream& os) const
00762 {
00763   os << "phi[i][j]: Shape function i at quadrature pt. j" << std::endl;
00764   this->print_phi(os);
00765 
00766   os << "dphi[i][j]: Shape function i's gradient at quadrature pt. j" << std::endl;
00767   this->print_dphi(os);
00768 
00769   os << "XYZ locations of the quadrature pts." << std::endl;
00770   this->print_xyz(os);
00771 
00772   os << "Values of JxW at the quadrature pts." << std::endl;
00773   this->print_JxW(os);
00774 }
00775 
00776 
00777 std::ostream& operator << (std::ostream& os, const FEAbstract& fe)
00778 {
00779   fe.print_info(os);
00780   return os;
00781 }
00782 
00783 
00784 
00785 #ifdef LIBMESH_ENABLE_AMR
00786 
00787 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
00788 void FEAbstract::compute_node_constraints (NodeConstraints &constraints,
00789                                            const Elem* elem)
00790 {
00791   libmesh_assert(elem);
00792 
00793   const unsigned int Dim = elem->dim();
00794 
00795   // Only constrain elements in 2,3D.
00796   if (Dim == 1)
00797     return;
00798 
00799   // Only constrain active and ancestor elements
00800   if (elem->subactive())
00801     return;
00802 
00803   // We currently always use LAGRANGE mappings for geometry
00804   const FEType fe_type(elem->default_order(), LAGRANGE);
00805 
00806   std::vector<const Node*> my_nodes, parent_nodes;
00807 
00808   // Look at the element faces.  Check to see if we need to
00809   // build constraints.
00810   for (unsigned int s=0; s<elem->n_sides(); s++)
00811     if (elem->neighbor(s) != NULL &&
00812         elem->neighbor(s) != remote_elem)
00813       if (elem->neighbor(s)->level() < elem->level()) // constrain dofs shared between
00814         {                                                     // this element and ones coarser
00815           // than this element.
00816           // Get pointers to the elements of interest and its parent.
00817           const Elem* parent = elem->parent();
00818 
00819           // This can't happen...  Only level-0 elements have NULL
00820           // parents, and no level-0 elements can be at a higher
00821           // level than their neighbors!
00822           libmesh_assert(parent);
00823 
00824           const UniquePtr<Elem> my_side     (elem->build_side(s));
00825           const UniquePtr<Elem> parent_side (parent->build_side(s));
00826 
00827           const unsigned int n_side_nodes = my_side->n_nodes();
00828 
00829           my_nodes.clear();
00830           my_nodes.reserve (n_side_nodes);
00831           parent_nodes.clear();
00832           parent_nodes.reserve (n_side_nodes);
00833 
00834           for (unsigned int n=0; n != n_side_nodes; ++n)
00835             my_nodes.push_back(my_side->get_node(n));
00836 
00837           for (unsigned int n=0; n != n_side_nodes; ++n)
00838             parent_nodes.push_back(parent_side->get_node(n));
00839 
00840           for (unsigned int my_side_n=0;
00841                my_side_n < n_side_nodes;
00842                my_side_n++)
00843             {
00844               libmesh_assert_less (my_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type()));
00845 
00846               const Node* my_node = my_nodes[my_side_n];
00847 
00848               // The support point of the DOF
00849               const Point& support_point = *my_node;
00850 
00851               // Figure out where my node lies on their reference element.
00852               const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type,
00853                                                                   parent_side.get(),
00854                                                                   support_point);
00855 
00856               // Compute the parent's side shape function values.
00857               for (unsigned int their_side_n=0;
00858                    their_side_n < n_side_nodes;
00859                    their_side_n++)
00860                 {
00861                   libmesh_assert_less (their_side_n, FEInterface::n_dofs(Dim-1, fe_type, parent_side->type()));
00862 
00863                   const Node* their_node = parent_nodes[their_side_n];
00864                   libmesh_assert(their_node);
00865 
00866                   const Real their_value = FEInterface::shape(Dim-1,
00867                                                               fe_type,
00868                                                               parent_side->type(),
00869                                                               their_side_n,
00870                                                               mapped_point);
00871 
00872                   const Real their_mag = std::abs(their_value);
00873 #ifdef DEBUG
00874                   // Protect for the case u_i ~= u_j,
00875                   // in which case i better equal j.
00876                   if (their_mag > 0.999)
00877                     {
00878                       libmesh_assert_equal_to (my_node, their_node);
00879                       libmesh_assert_less (std::abs(their_value - 1.), 0.001);
00880                     }
00881                   else
00882 #endif
00883                     // To make nodal constraints useful for constructing
00884                     // sparsity patterns faster, we need to get EVERY
00885                     // POSSIBLE constraint coupling identified, even if
00886                     // there is no coupling in the isoparametric
00887                     // Lagrange case.
00888                     if (their_mag < 1.e-5)
00889                       {
00890                         // since we may be running this method concurrently
00891                         // on multiple threads we need to acquire a lock
00892                         // before modifying the shared constraint_row object.
00893                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
00894 
00895                         // A reference to the constraint row.
00896                         NodeConstraintRow& constraint_row = constraints[my_node].first;
00897 
00898                         constraint_row.insert(std::make_pair (their_node,
00899                                                               0.));
00900                       }
00901                   // To get nodal coordinate constraints right, only
00902                   // add non-zero and non-identity values for Lagrange
00903                   // basis functions.
00904                     else // (1.e-5 <= their_mag <= .999)
00905                       {
00906                         // since we may be running this method concurrently
00907                         // on multiple threads we need to acquire a lock
00908                         // before modifying the shared constraint_row object.
00909                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
00910 
00911                         // A reference to the constraint row.
00912                         NodeConstraintRow& constraint_row = constraints[my_node].first;
00913 
00914                         constraint_row.insert(std::make_pair (their_node,
00915                                                               their_value));
00916                       }
00917                 }
00918             }
00919         }
00920 }
00921 
00922 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
00923 
00924 #endif // #ifdef LIBMESH_ENABLE_AMR
00925 
00926 
00927 
00928 #ifdef LIBMESH_ENABLE_PERIODIC
00929 
00930 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
00931 void FEAbstract::compute_periodic_node_constraints (NodeConstraints &constraints,
00932                                                     const PeriodicBoundaries &boundaries,
00933                                                     const MeshBase &mesh,
00934                                                     const PointLocatorBase *point_locator,
00935                                                     const Elem* elem)
00936 {
00937   // Only bother if we truly have periodic boundaries
00938   if (boundaries.empty())
00939     return;
00940 
00941   libmesh_assert(elem);
00942 
00943   // Only constrain active elements with this method
00944   if (!elem->active())
00945     return;
00946 
00947   const unsigned int Dim = elem->dim();
00948 
00949   // We currently always use LAGRANGE mappings for geometry
00950   const FEType fe_type(elem->default_order(), LAGRANGE);
00951 
00952   std::vector<const Node*> my_nodes, neigh_nodes;
00953 
00954   // Look at the element faces.  Check to see if we need to
00955   // build constraints.
00956   for (unsigned short int s=0; s<elem->n_sides(); s++)
00957     {
00958       if (elem->neighbor(s))
00959         continue;
00960 
00961       const std::vector<boundary_id_type>& bc_ids =
00962         mesh.get_boundary_info().boundary_ids (elem, s);
00963       for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it)
00964         {
00965           const boundary_id_type boundary_id = *id_it;
00966           const PeriodicBoundaryBase *periodic = boundaries.boundary(boundary_id);
00967           if (periodic)
00968             {
00969               libmesh_assert(point_locator);
00970 
00971               // Get pointers to the element's neighbor.
00972               const Elem* neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s);
00973 
00974               // h refinement constraints:
00975               // constrain dofs shared between
00976               // this element and ones as coarse
00977               // as or coarser than this element.
00978               if (neigh->level() <= elem->level())
00979                 {
00980                   unsigned int s_neigh =
00981                     mesh.get_boundary_info().side_with_boundary_id(neigh, periodic->pairedboundary);
00982                   libmesh_assert_not_equal_to (s_neigh, libMesh::invalid_uint);
00983 
00984 #ifdef LIBMESH_ENABLE_AMR
00985                   libmesh_assert(neigh->active());
00986 #endif // #ifdef LIBMESH_ENABLE_AMR
00987 
00988                   const UniquePtr<Elem> my_side    (elem->build_side(s));
00989                   const UniquePtr<Elem> neigh_side (neigh->build_side(s_neigh));
00990 
00991                   const unsigned int n_side_nodes = my_side->n_nodes();
00992 
00993                   my_nodes.clear();
00994                   my_nodes.reserve (n_side_nodes);
00995                   neigh_nodes.clear();
00996                   neigh_nodes.reserve (n_side_nodes);
00997 
00998                   for (unsigned int n=0; n != n_side_nodes; ++n)
00999                     my_nodes.push_back(my_side->get_node(n));
01000 
01001                   for (unsigned int n=0; n != n_side_nodes; ++n)
01002                     neigh_nodes.push_back(neigh_side->get_node(n));
01003 
01004                   // Make sure we're not adding recursive constraints
01005                   // due to the redundancy in the way we add periodic
01006                   // boundary constraints, or adding constraints to
01007                   // nodes that already have AMR constraints
01008                   std::vector<bool> skip_constraint(n_side_nodes, false);
01009 
01010                   for (unsigned int my_side_n=0;
01011                        my_side_n < n_side_nodes;
01012                        my_side_n++)
01013                     {
01014                       libmesh_assert_less (my_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type()));
01015 
01016                       const Node* my_node = my_nodes[my_side_n];
01017 
01018                       // Figure out where my node lies on their reference element.
01019                       const Point neigh_point = periodic->get_corresponding_pos(*my_node);
01020 
01021                       const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type,
01022                                                                           neigh_side.get(),
01023                                                                           neigh_point);
01024 
01025                       // If we've already got a constraint on this
01026                       // node, then the periodic constraint is
01027                       // redundant
01028                       {
01029                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
01030 
01031                         if (constraints.count(my_node))
01032                           {
01033                             skip_constraint[my_side_n] = true;
01034                             continue;
01035                           }
01036                       }
01037 
01038                       // Compute the neighbors's side shape function values.
01039                       for (unsigned int their_side_n=0;
01040                            their_side_n < n_side_nodes;
01041                            their_side_n++)
01042                         {
01043                           libmesh_assert_less (their_side_n, FEInterface::n_dofs(Dim-1, fe_type, neigh_side->type()));
01044 
01045                           const Node* their_node = neigh_nodes[their_side_n];
01046 
01047                           // If there's a constraint on an opposing node,
01048                           // we need to see if it's constrained by
01049                           // *our side* making any periodic constraint
01050                           // on us recursive
01051                           {
01052                             Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
01053 
01054                             if (!constraints.count(their_node))
01055                               continue;
01056 
01057                             const NodeConstraintRow& their_constraint_row =
01058                               constraints[their_node].first;
01059 
01060                             for (unsigned int orig_side_n=0;
01061                                  orig_side_n < n_side_nodes;
01062                                  orig_side_n++)
01063                               {
01064                                 libmesh_assert_less (orig_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type()));
01065 
01066                                 const Node* orig_node = my_nodes[orig_side_n];
01067 
01068                                 if (their_constraint_row.count(orig_node))
01069                                   skip_constraint[orig_side_n] = true;
01070                               }
01071                           }
01072                         }
01073                     }
01074                   for (unsigned int my_side_n=0;
01075                        my_side_n < n_side_nodes;
01076                        my_side_n++)
01077                     {
01078                       libmesh_assert_less (my_side_n, FEInterface::n_dofs(Dim-1, fe_type, my_side->type()));
01079 
01080                       if (skip_constraint[my_side_n])
01081                         continue;
01082 
01083                       const Node* my_node = my_nodes[my_side_n];
01084 
01085                       // Figure out where my node lies on their reference element.
01086                       const Point neigh_point = periodic->get_corresponding_pos(*my_node);
01087 
01088                       // Figure out where my node lies on their reference element.
01089                       const Point mapped_point = FEInterface::inverse_map(Dim-1, fe_type,
01090                                                                           neigh_side.get(),
01091                                                                           neigh_point);
01092 
01093                       for (unsigned int their_side_n=0;
01094                            their_side_n < n_side_nodes;
01095                            their_side_n++)
01096                         {
01097                           libmesh_assert_less (their_side_n, FEInterface::n_dofs(Dim-1, fe_type, neigh_side->type()));
01098 
01099                           const Node* their_node = neigh_nodes[their_side_n];
01100                           libmesh_assert(their_node);
01101 
01102                           const Real their_value = FEInterface::shape(Dim-1,
01103                                                                       fe_type,
01104                                                                       neigh_side->type(),
01105                                                                       their_side_n,
01106                                                                       mapped_point);
01107 
01108                           // since we may be running this method concurrently
01109                           // on multiple threads we need to acquire a lock
01110                           // before modifying the shared constraint_row object.
01111                           {
01112                             Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
01113 
01114                             NodeConstraintRow& constraint_row =
01115                               constraints[my_node].first;
01116 
01117                             constraint_row.insert(std::make_pair(their_node,
01118                                                                  their_value));
01119                           }
01120                         }
01121                     }
01122                 }
01123             }
01124         }
01125     }
01126 }
01127 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
01128 
01129 #endif // LIBMESH_ENABLE_PERIODIC
01130 
01131 
01132 } // namespace libMesh