$extrastylesheet
fe_base.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/inf_fe.h"
00023 #include "libmesh/libmesh_logging.h"
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_boundary_base.h"
00034 #include "libmesh/periodic_boundaries.h"
00035 #include "libmesh/quadrature.h"
00036 #include "libmesh/quadrature_gauss.h"
00037 #include "libmesh/tensor_value.h"
00038 #include "libmesh/threads.h"
00039 
00040 // Anonymous namespace, for a helper function for periodic boundary
00041 // constraint calculations
00042 namespace
00043 {
00044 using namespace libMesh;
00045 
00046 // Find the "primary" element around a boundary point:
00047 const Elem* primary_boundary_point_neighbor
00048 (const Elem* elem,
00049  const Point& p,
00050  const BoundaryInfo& boundary_info,
00051  const std::set<boundary_id_type>& boundary_ids)
00052 {
00053   // If we don't find a better alternative, the user will have
00054   // provided the primary element
00055   const Elem *primary = elem;
00056 
00057   std::set<const Elem*> point_neighbors;
00058   elem->find_point_neighbors(p, point_neighbors);
00059   for (std::set<const Elem*>::const_iterator point_neighbors_iter =
00060          point_neighbors.begin();
00061        point_neighbors_iter != point_neighbors.end(); ++point_neighbors_iter)
00062     {
00063       const Elem* pt_neighbor = *point_neighbors_iter;
00064 
00065       // If this point neighbor isn't at least
00066       // as coarse as the current primary elem, or if it is at
00067       // the same level but has a lower id, then
00068       // we won't defer to it.
00069       if ((pt_neighbor->level() > primary->level()) ||
00070           (pt_neighbor->level() == primary->level() &&
00071            pt_neighbor->id() < primary->id()))
00072         continue;
00073 
00074       // Otherwise, we will defer to the point neighbor, but only if
00075       // one of its sides is on a relevant boundary and that side
00076       // contains this vertex
00077       bool vertex_on_periodic_side = false;
00078       for (unsigned short int ns = 0;
00079            ns != pt_neighbor->n_sides(); ++ns)
00080         {
00081           const std::vector<boundary_id_type> bc_ids =
00082             boundary_info.boundary_ids (pt_neighbor, ns);
00083 
00084           bool on_relevant_boundary = false;
00085           for (std::set<boundary_id_type>::const_iterator i =
00086                  boundary_ids.begin(); i != boundary_ids.end(); ++i)
00087             if (std::find(bc_ids.begin(), bc_ids.end(), *i)
00088                 != bc_ids.end())
00089               on_relevant_boundary = true;
00090 
00091           if (!on_relevant_boundary)
00092             continue;
00093 
00094           if (!pt_neighbor->build_side(ns)->contains_point(p))
00095             continue;
00096 
00097           vertex_on_periodic_side = true;
00098           break;
00099         }
00100 
00101       if (vertex_on_periodic_side)
00102         primary = pt_neighbor;
00103     }
00104 
00105   return primary;
00106 }
00107 
00108 // Find the "primary" element around a boundary edge:
00109 const Elem* primary_boundary_edge_neighbor
00110 (const Elem* elem,
00111  const Point& p1,
00112  const Point& p2,
00113  const BoundaryInfo& boundary_info,
00114  const std::set<boundary_id_type>& boundary_ids)
00115 {
00116   // If we don't find a better alternative, the user will have
00117   // provided the primary element
00118   const Elem *primary = elem;
00119 
00120   std::set<const Elem*> edge_neighbors;
00121   elem->find_edge_neighbors(p1, p2, edge_neighbors);
00122   for (std::set<const Elem*>::const_iterator edge_neighbors_iter =
00123          edge_neighbors.begin();
00124        edge_neighbors_iter != edge_neighbors.end(); ++edge_neighbors_iter)
00125     {
00126       const Elem* e_neighbor = *edge_neighbors_iter;
00127 
00128       // If this edge neighbor isn't at least
00129       // as coarse as the current primary elem, or if it is at
00130       // the same level but has a lower id, then
00131       // we won't defer to it.
00132       if ((e_neighbor->level() > primary->level()) ||
00133           (e_neighbor->level() == primary->level() &&
00134            e_neighbor->id() < primary->id()))
00135         continue;
00136 
00137       // Otherwise, we will defer to the edge neighbor, but only if
00138       // one of its sides is on this periodic boundary and that
00139       // side contains this edge
00140       bool vertex_on_periodic_side = false;
00141       for (unsigned short int ns = 0;
00142            ns != e_neighbor->n_sides(); ++ns)
00143         {
00144           const std::vector<boundary_id_type>& bc_ids =
00145             boundary_info.boundary_ids (e_neighbor, ns);
00146 
00147           bool on_relevant_boundary = false;
00148           for (std::set<boundary_id_type>::const_iterator i =
00149                  boundary_ids.begin(); i != boundary_ids.end(); ++i)
00150             if (std::find(bc_ids.begin(), bc_ids.end(), *i)
00151                 != bc_ids.end())
00152               on_relevant_boundary = true;
00153 
00154           if (!on_relevant_boundary)
00155             continue;
00156 
00157           UniquePtr<Elem> periodic_side = e_neighbor->build_side(ns);
00158           if (!(periodic_side->contains_point(p1) &&
00159                 periodic_side->contains_point(p2)))
00160             continue;
00161 
00162           vertex_on_periodic_side = true;
00163           break;
00164         }
00165 
00166       if (vertex_on_periodic_side)
00167         primary = e_neighbor;
00168     }
00169 
00170   return primary;
00171 }
00172 
00173 }
00174 
00175 namespace libMesh
00176 {
00177 
00178 
00179 
00180 // ------------------------------------------------------------
00181 // FEBase class members
00182 template <>
00183 UniquePtr<FEGenericBase<Real> >
00184 FEGenericBase<Real>::build (const unsigned int dim,
00185                             const FEType& fet)
00186 {
00187   switch (dim)
00188     {
00189       // 0D
00190     case 0:
00191       {
00192         switch (fet.family)
00193           {
00194           case CLOUGH:
00195             return UniquePtr<FEBase>(new FE<0,CLOUGH>(fet));
00196 
00197           case HERMITE:
00198             return UniquePtr<FEBase>(new FE<0,HERMITE>(fet));
00199 
00200           case LAGRANGE:
00201             return UniquePtr<FEBase>(new FE<0,LAGRANGE>(fet));
00202 
00203           case L2_LAGRANGE:
00204             return UniquePtr<FEBase>(new FE<0,L2_LAGRANGE>(fet));
00205 
00206           case HIERARCHIC:
00207             return UniquePtr<FEBase>(new FE<0,HIERARCHIC>(fet));
00208 
00209           case L2_HIERARCHIC:
00210             return UniquePtr<FEBase>(new FE<0,L2_HIERARCHIC>(fet));
00211 
00212           case MONOMIAL:
00213             return UniquePtr<FEBase>(new FE<0,MONOMIAL>(fet));
00214 
00215 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00216           case SZABAB:
00217             return UniquePtr<FEBase>(new FE<0,SZABAB>(fet));
00218 
00219           case BERNSTEIN:
00220             return UniquePtr<FEBase>(new FE<0,BERNSTEIN>(fet));
00221 #endif
00222 
00223           case XYZ:
00224             return UniquePtr<FEBase>(new FEXYZ<0>(fet));
00225 
00226           case SCALAR:
00227             return UniquePtr<FEBase>(new FEScalar<0>(fet));
00228 
00229           default:
00230             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00231           }
00232       }
00233       // 1D
00234     case 1:
00235       {
00236         switch (fet.family)
00237           {
00238           case CLOUGH:
00239             return UniquePtr<FEBase>(new FE<1,CLOUGH>(fet));
00240 
00241           case HERMITE:
00242             return UniquePtr<FEBase>(new FE<1,HERMITE>(fet));
00243 
00244           case LAGRANGE:
00245             return UniquePtr<FEBase>(new FE<1,LAGRANGE>(fet));
00246 
00247           case L2_LAGRANGE:
00248             return UniquePtr<FEBase>(new FE<1,L2_LAGRANGE>(fet));
00249 
00250           case HIERARCHIC:
00251             return UniquePtr<FEBase>(new FE<1,HIERARCHIC>(fet));
00252 
00253           case L2_HIERARCHIC:
00254             return UniquePtr<FEBase>(new FE<1,L2_HIERARCHIC>(fet));
00255 
00256           case MONOMIAL:
00257             return UniquePtr<FEBase>(new FE<1,MONOMIAL>(fet));
00258 
00259 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00260           case SZABAB:
00261             return UniquePtr<FEBase>(new FE<1,SZABAB>(fet));
00262 
00263           case BERNSTEIN:
00264             return UniquePtr<FEBase>(new FE<1,BERNSTEIN>(fet));
00265 #endif
00266 
00267           case XYZ:
00268             return UniquePtr<FEBase>(new FEXYZ<1>(fet));
00269 
00270           case SCALAR:
00271             return UniquePtr<FEBase>(new FEScalar<1>(fet));
00272 
00273           default:
00274             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00275           }
00276       }
00277 
00278 
00279       // 2D
00280     case 2:
00281       {
00282         switch (fet.family)
00283           {
00284           case CLOUGH:
00285             return UniquePtr<FEBase>(new FE<2,CLOUGH>(fet));
00286 
00287           case HERMITE:
00288             return UniquePtr<FEBase>(new FE<2,HERMITE>(fet));
00289 
00290           case LAGRANGE:
00291             return UniquePtr<FEBase>(new FE<2,LAGRANGE>(fet));
00292 
00293           case L2_LAGRANGE:
00294             return UniquePtr<FEBase>(new FE<2,L2_LAGRANGE>(fet));
00295 
00296           case HIERARCHIC:
00297             return UniquePtr<FEBase>(new FE<2,HIERARCHIC>(fet));
00298 
00299           case L2_HIERARCHIC:
00300             return UniquePtr<FEBase>(new FE<2,L2_HIERARCHIC>(fet));
00301 
00302           case MONOMIAL:
00303             return UniquePtr<FEBase>(new FE<2,MONOMIAL>(fet));
00304 
00305 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00306           case SZABAB:
00307             return UniquePtr<FEBase>(new FE<2,SZABAB>(fet));
00308 
00309           case BERNSTEIN:
00310             return UniquePtr<FEBase>(new FE<2,BERNSTEIN>(fet));
00311 #endif
00312 
00313           case XYZ:
00314             return UniquePtr<FEBase>(new FEXYZ<2>(fet));
00315 
00316           case SCALAR:
00317             return UniquePtr<FEBase>(new FEScalar<2>(fet));
00318 
00319           case SUBDIVISION:
00320             return UniquePtr<FEBase>(new FESubdivision(fet));
00321 
00322           default:
00323             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00324           }
00325       }
00326 
00327 
00328       // 3D
00329     case 3:
00330       {
00331         switch (fet.family)
00332           {
00333           case CLOUGH:
00334             libmesh_error_msg("ERROR: Clough-Tocher elements currently only support 1D and 2D");
00335 
00336           case HERMITE:
00337             return UniquePtr<FEBase>(new FE<3,HERMITE>(fet));
00338 
00339           case LAGRANGE:
00340             return UniquePtr<FEBase>(new FE<3,LAGRANGE>(fet));
00341 
00342           case L2_LAGRANGE:
00343             return UniquePtr<FEBase>(new FE<3,L2_LAGRANGE>(fet));
00344 
00345           case HIERARCHIC:
00346             return UniquePtr<FEBase>(new FE<3,HIERARCHIC>(fet));
00347 
00348           case L2_HIERARCHIC:
00349             return UniquePtr<FEBase>(new FE<3,L2_HIERARCHIC>(fet));
00350 
00351           case MONOMIAL:
00352             return UniquePtr<FEBase>(new FE<3,MONOMIAL>(fet));
00353 
00354 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
00355           case SZABAB:
00356             return UniquePtr<FEBase>(new FE<3,SZABAB>(fet));
00357 
00358           case BERNSTEIN:
00359             return UniquePtr<FEBase>(new FE<3,BERNSTEIN>(fet));
00360 #endif
00361 
00362           case XYZ:
00363             return UniquePtr<FEBase>(new FEXYZ<3>(fet));
00364 
00365           case SCALAR:
00366             return UniquePtr<FEBase>(new FEScalar<3>(fet));
00367 
00368           default:
00369             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00370           }
00371       }
00372 
00373     default:
00374       libmesh_error_msg("Invalid dimension dim = " << dim);
00375     }
00376 
00377   libmesh_error_msg("We'll never get here!");
00378   return UniquePtr<FEBase>();
00379 }
00380 
00381 
00382 
00383 template <>
00384 UniquePtr<FEGenericBase<RealGradient> >
00385 FEGenericBase<RealGradient>::build (const unsigned int dim,
00386                                     const FEType& fet)
00387 {
00388   switch (dim)
00389     {
00390       // 0D
00391     case 0:
00392       {
00393         switch (fet.family)
00394           {
00395           case LAGRANGE_VEC:
00396             return UniquePtr<FEVectorBase>(new FELagrangeVec<0>(fet));
00397 
00398           default:
00399             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00400           }
00401       }
00402     case 1:
00403       {
00404         switch (fet.family)
00405           {
00406           case LAGRANGE_VEC:
00407             return UniquePtr<FEVectorBase>(new FELagrangeVec<1>(fet));
00408 
00409           default:
00410             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00411           }
00412       }
00413     case 2:
00414       {
00415         switch (fet.family)
00416           {
00417           case LAGRANGE_VEC:
00418             return UniquePtr<FEVectorBase>(new FELagrangeVec<2>(fet));
00419 
00420           case NEDELEC_ONE:
00421             return UniquePtr<FEVectorBase>(new FENedelecOne<2>(fet));
00422 
00423           default:
00424             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00425           }
00426       }
00427     case 3:
00428       {
00429         switch (fet.family)
00430           {
00431           case LAGRANGE_VEC:
00432             return UniquePtr<FEVectorBase>(new FELagrangeVec<3>(fet));
00433 
00434           case NEDELEC_ONE:
00435             return UniquePtr<FEVectorBase>(new FENedelecOne<3>(fet));
00436 
00437           default:
00438             libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
00439           }
00440       }
00441 
00442     default:
00443       libmesh_error_msg("Invalid dimension dim = " << dim);
00444     } // switch(dim)
00445 
00446   libmesh_error_msg("We'll never get here!");
00447   return UniquePtr<FEVectorBase>();
00448 }
00449 
00450 
00451 
00452 
00453 
00454 
00455 
00456 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00457 
00458 
00459 template <>
00460 UniquePtr<FEGenericBase<Real> >
00461 FEGenericBase<Real>::build_InfFE (const unsigned int dim,
00462                                   const FEType& fet)
00463 {
00464   switch (dim)
00465     {
00466 
00467       // 1D
00468     case 1:
00469       {
00470         switch (fet.radial_family)
00471           {
00472           case INFINITE_MAP:
00473             libmesh_error_msg("ERROR: Can't build an infinite element with FEFamily = " << fet.radial_family);
00474 
00475           case JACOBI_20_00:
00476             {
00477               switch (fet.inf_map)
00478                 {
00479                 case CARTESIAN:
00480                   return UniquePtr<FEBase>(new InfFE<1,JACOBI_20_00,CARTESIAN>(fet));
00481 
00482                 default:
00483                   libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
00484                 }
00485             }
00486 
00487           case JACOBI_30_00:
00488             {
00489               switch (fet.inf_map)
00490                 {
00491                 case CARTESIAN:
00492                   return UniquePtr<FEBase>(new InfFE<1,JACOBI_30_00,CARTESIAN>(fet));
00493 
00494                 default:
00495                   libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
00496                 }
00497             }
00498 
00499           case LEGENDRE:
00500             {
00501               switch (fet.inf_map)
00502                 {
00503                 case CARTESIAN:
00504                   return UniquePtr<FEBase>(new InfFE<1,LEGENDRE,CARTESIAN>(fet));
00505 
00506                 default:
00507                   libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
00508                 }
00509             }
00510 
00511           case LAGRANGE:
00512             {
00513               switch (fet.inf_map)
00514                 {
00515                 case CARTESIAN:
00516                   return UniquePtr<FEBase>(new InfFE<1,LAGRANGE,CARTESIAN>(fet));
00517 
00518                 default:
00519                   libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
00520                 }
00521             }
00522 
00523           default:
00524             libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family);
00525           }
00526       }
00527 
00528 
00529 
00530 
00531       // 2D
00532     case 2:
00533       {
00534         switch (fet.radial_family)
00535           {
00536           case INFINITE_MAP:
00537             libmesh_error_msg("ERROR: Can't build an infinite element with FEFamily = " << fet.radial_family);
00538 
00539           case JACOBI_20_00:
00540             {
00541               switch (fet.inf_map)
00542                 {
00543                 case CARTESIAN:
00544                   return UniquePtr<FEBase>(new InfFE<2,JACOBI_20_00,CARTESIAN>(fet));
00545 
00546                 default:
00547                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00548                 }
00549             }
00550 
00551           case JACOBI_30_00:
00552             {
00553               switch (fet.inf_map)
00554                 {
00555                 case CARTESIAN:
00556                   return UniquePtr<FEBase>(new InfFE<2,JACOBI_30_00,CARTESIAN>(fet));
00557 
00558                 default:
00559                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00560                 }
00561             }
00562 
00563           case LEGENDRE:
00564             {
00565               switch (fet.inf_map)
00566                 {
00567                 case CARTESIAN:
00568                   return UniquePtr<FEBase>(new InfFE<2,LEGENDRE,CARTESIAN>(fet));
00569 
00570                 default:
00571                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00572                 }
00573             }
00574 
00575           case LAGRANGE:
00576             {
00577               switch (fet.inf_map)
00578                 {
00579                 case CARTESIAN:
00580                   return UniquePtr<FEBase>(new InfFE<2,LAGRANGE,CARTESIAN>(fet));
00581 
00582                 default:
00583                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00584                 }
00585             }
00586 
00587           default:
00588             libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family);
00589           }
00590       }
00591 
00592 
00593 
00594 
00595       // 3D
00596     case 3:
00597       {
00598         switch (fet.radial_family)
00599           {
00600           case INFINITE_MAP:
00601             libmesh_error_msg("ERROR: Don't build an infinite element with FEFamily = " << fet.radial_family);
00602 
00603           case JACOBI_20_00:
00604             {
00605               switch (fet.inf_map)
00606                 {
00607                 case CARTESIAN:
00608                   return UniquePtr<FEBase>(new InfFE<3,JACOBI_20_00,CARTESIAN>(fet));
00609 
00610                 default:
00611                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00612                 }
00613             }
00614 
00615           case JACOBI_30_00:
00616             {
00617               switch (fet.inf_map)
00618                 {
00619                 case CARTESIAN:
00620                   return UniquePtr<FEBase>(new InfFE<3,JACOBI_30_00,CARTESIAN>(fet));
00621 
00622                 default:
00623                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00624                 }
00625             }
00626 
00627           case LEGENDRE:
00628             {
00629               switch (fet.inf_map)
00630                 {
00631                 case CARTESIAN:
00632                   return UniquePtr<FEBase>(new InfFE<3,LEGENDRE,CARTESIAN>(fet));
00633 
00634                 default:
00635                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00636                 }
00637             }
00638 
00639           case LAGRANGE:
00640             {
00641               switch (fet.inf_map)
00642                 {
00643                 case CARTESIAN:
00644                   return UniquePtr<FEBase>(new InfFE<3,LAGRANGE,CARTESIAN>(fet));
00645 
00646                 default:
00647                   libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
00648                 }
00649             }
00650 
00651           default:
00652             libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family);
00653           }
00654       }
00655 
00656     default:
00657       libmesh_error_msg("Invalid dimension dim = " << dim);
00658     }
00659 
00660   libmesh_error_msg("We'll never get here!");
00661   return UniquePtr<FEBase>();
00662 }
00663 
00664 
00665 
00666 template <>
00667 UniquePtr<FEGenericBase<RealGradient> >
00668 FEGenericBase<RealGradient>::build_InfFE (const unsigned int,
00669                                           const FEType& )
00670 {
00671   // No vector types defined... YET.
00672   libmesh_not_implemented();
00673   return UniquePtr<FEVectorBase>();
00674 }
00675 
00676 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00677 
00678 
00679 template <typename OutputType>
00680 void FEGenericBase<OutputType> ::compute_shape_functions (const Elem* elem,
00681                                                           const std::vector<Point>& qp)
00682 {
00683   //-------------------------------------------------------------------------
00684   // Compute the shape function values (and derivatives)
00685   // at the Quadrature points.  Note that the actual values
00686   // have already been computed via init_shape_functions
00687 
00688   // Start logging the shape function computation
00689   START_LOG("compute_shape_functions()", "FE");
00690 
00691   calculations_started = true;
00692 
00693   // If the user forgot to request anything, we'll be safe and
00694   // calculate everything:
00695 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00696   if (!calculate_phi && !calculate_dphi && !calculate_d2phi && !calculate_curl_phi && !calculate_div_phi)
00697     {
00698       calculate_phi = calculate_dphi = calculate_d2phi = true;
00699       // Only compute curl, div for vector-valued elements
00700       if( TypesEqual<OutputType,RealGradient>::value )
00701         {
00702           calculate_curl_phi = true;
00703           calculate_div_phi  = true;
00704         }
00705     }
00706 #else
00707   if (!calculate_phi && !calculate_dphi && !calculate_curl_phi && !calculate_div_phi)
00708     {
00709       calculate_phi = calculate_dphi = true;
00710       // Only compute curl for vector-valued elements
00711       if( TypesEqual<OutputType,RealGradient>::value )
00712         {
00713           calculate_curl_phi = true;
00714           calculate_div_phi  = true;
00715         }
00716     }
00717 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
00718 
00719 
00720   if( calculate_phi )
00721     this->_fe_trans->map_phi( this->dim, elem, qp, (*this), this->phi );
00722 
00723   if( calculate_dphi )
00724     this->_fe_trans->map_dphi( this->dim, elem, qp, (*this), this->dphi,
00725                                this->dphidx, this->dphidy, this->dphidz );
00726 
00727 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00728   if( calculate_d2phi )
00729     this->_fe_trans->map_d2phi( this->dim, elem, qp, (*this), this->d2phi,
00730                                 this->d2phidx2, this->d2phidxdy, this->d2phidxdz,
00731                                 this->d2phidy2, this->d2phidydz, this->d2phidz2 );
00732 #endif //LIBMESH_ENABLE_SECOND_DERIVATIVES
00733 
00734   // Only compute curl for vector-valued elements
00735   if( calculate_curl_phi && TypesEqual<OutputType,RealGradient>::value )
00736     this->_fe_trans->map_curl( this->dim, elem, qp, (*this), this->curl_phi );
00737 
00738   // Only compute div for vector-valued elements
00739   if( calculate_div_phi && TypesEqual<OutputType,RealGradient>::value )
00740     this->_fe_trans->map_div( this->dim, elem, qp, (*this), this->div_phi );
00741 
00742   // Stop logging the shape function computation
00743   STOP_LOG("compute_shape_functions()", "FE");
00744 }
00745 
00746 
00747 template <typename OutputType>
00748 void FEGenericBase<OutputType>::print_phi(std::ostream& os) const
00749 {
00750   for (unsigned int i=0; i<phi.size(); ++i)
00751     for (unsigned int j=0; j<phi[i].size(); ++j)
00752       os << " phi[" << i << "][" << j << "]=" << phi[i][j] << std::endl;
00753 }
00754 
00755 
00756 
00757 
00758 template <typename OutputType>
00759 void FEGenericBase<OutputType>::print_dphi(std::ostream& os) const
00760 {
00761   for (unsigned int i=0; i<dphi.size(); ++i)
00762     for (unsigned int j=0; j<dphi[i].size(); ++j)
00763       os << " dphi[" << i << "][" << j << "]=" << dphi[i][j];
00764 }
00765 
00766 
00767 
00768 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00769 
00770 
00771 template <typename OutputType>
00772 void FEGenericBase<OutputType>::print_d2phi(std::ostream& os) const
00773 {
00774   for (unsigned int i=0; i<dphi.size(); ++i)
00775     for (unsigned int j=0; j<dphi[i].size(); ++j)
00776       os << " d2phi[" << i << "][" << j << "]=" << d2phi[i][j];
00777 }
00778 
00779 #endif
00780 
00781 
00782 
00783 #ifdef LIBMESH_ENABLE_AMR
00784 
00785 template <typename OutputType>
00786 void
00787 FEGenericBase<OutputType>::coarsened_dof_values(const NumericVector<Number> &old_vector,
00788                                                 const DofMap &dof_map,
00789                                                 const Elem *elem,
00790                                                 DenseVector<Number> &Ue,
00791                                                 const unsigned int var,
00792                                                 const bool use_old_dof_indices)
00793 {
00794   // Side/edge local DOF indices
00795   std::vector<unsigned int> new_side_dofs, old_side_dofs;
00796 
00797   // FIXME: what about 2D shells in 3D space?
00798   unsigned int dim = elem->dim();
00799 
00800   // We use local FE objects for now
00801   // FIXME: we should use more, external objects instead for efficiency
00802   const FEType& base_fe_type = dof_map.variable_type(var);
00803   UniquePtr<FEGenericBase<OutputShape> > fe
00804     (FEGenericBase<OutputShape>::build(dim, base_fe_type));
00805   UniquePtr<FEGenericBase<OutputShape> > fe_coarse
00806     (FEGenericBase<OutputShape>::build(dim, base_fe_type));
00807 
00808   UniquePtr<QBase> qrule     (base_fe_type.default_quadrature_rule(dim));
00809   UniquePtr<QBase> qedgerule (base_fe_type.default_quadrature_rule(1));
00810   UniquePtr<QBase> qsiderule (base_fe_type.default_quadrature_rule(dim-1));
00811   std::vector<Point> coarse_qpoints;
00812 
00813   // The values of the shape functions at the quadrature
00814   // points
00815   const std::vector<std::vector<OutputShape> >& phi_values =
00816     fe->get_phi();
00817   const std::vector<std::vector<OutputShape> >& phi_coarse =
00818     fe_coarse->get_phi();
00819 
00820   // The gradients of the shape functions at the quadrature
00821   // points on the child element.
00822   const std::vector<std::vector<OutputGradient> > *dphi_values =
00823     NULL;
00824   const std::vector<std::vector<OutputGradient> > *dphi_coarse =
00825     NULL;
00826 
00827   const FEContinuity cont = fe->get_continuity();
00828 
00829   if (cont == C_ONE)
00830     {
00831       const std::vector<std::vector<OutputGradient> >&
00832         ref_dphi_values = fe->get_dphi();
00833       dphi_values = &ref_dphi_values;
00834       const std::vector<std::vector<OutputGradient> >&
00835         ref_dphi_coarse = fe_coarse->get_dphi();
00836       dphi_coarse = &ref_dphi_coarse;
00837     }
00838 
00839   // The Jacobian * quadrature weight at the quadrature points
00840   const std::vector<Real>& JxW =
00841     fe->get_JxW();
00842 
00843   // The XYZ locations of the quadrature points on the
00844   // child element
00845   const std::vector<Point>& xyz_values =
00846     fe->get_xyz();
00847 
00848 
00849 
00850   FEType fe_type = base_fe_type, temp_fe_type;
00851   const ElemType elem_type = elem->type();
00852   fe_type.order = static_cast<Order>(fe_type.order +
00853                                      elem->max_descendant_p_level());
00854 
00855   // Number of nodes on parent element
00856   const unsigned int n_nodes = elem->n_nodes();
00857 
00858   // Number of dofs on parent element
00859   const unsigned int new_n_dofs =
00860     FEInterface::n_dofs(dim, fe_type, elem_type);
00861 
00862   // Fixed vs. free DoFs on edge/face projections
00863   std::vector<char> dof_is_fixed(new_n_dofs, false); // bools
00864   std::vector<int> free_dof(new_n_dofs, 0);
00865 
00866   DenseMatrix<Real> Ke;
00867   DenseVector<Number> Fe;
00868   Ue.resize(new_n_dofs); Ue.zero();
00869 
00870 
00871   // When coarsening, in general, we need a series of
00872   // projections to ensure a unique and continuous
00873   // solution.  We start by interpolating nodes, then
00874   // hold those fixed and project edges, then
00875   // hold those fixed and project faces, then
00876   // hold those fixed and project interiors
00877 
00878   // Copy node values first
00879   {
00880     std::vector<dof_id_type> node_dof_indices;
00881     if (use_old_dof_indices)
00882       dof_map.old_dof_indices (elem, node_dof_indices, var);
00883     else
00884       dof_map.dof_indices (elem, node_dof_indices, var);
00885 
00886     unsigned int current_dof = 0;
00887     for (unsigned int n=0; n!= n_nodes; ++n)
00888       {
00889         // FIXME: this should go through the DofMap,
00890         // not duplicate dof_indices code badly!
00891         const unsigned int my_nc =
00892           FEInterface::n_dofs_at_node (dim, fe_type,
00893                                        elem_type, n);
00894         if (!elem->is_vertex(n))
00895           {
00896             current_dof += my_nc;
00897             continue;
00898           }
00899 
00900         temp_fe_type = base_fe_type;
00901         // We're assuming here that child n shares vertex n,
00902         // which is wrong on non-simplices right now
00903         // ... but this code isn't necessary except on elements
00904         // where p refinement creates more vertex dofs; we have
00905         // no such elements yet.
00906         /*
00907           if (elem->child(n)->p_level() < elem->p_level())
00908           {
00909           temp_fe_type.order =
00910           static_cast<Order>(temp_fe_type.order +
00911           elem->child(n)->p_level());
00912           }
00913         */
00914         const unsigned int nc =
00915           FEInterface::n_dofs_at_node (dim, temp_fe_type,
00916                                        elem_type, n);
00917         for (unsigned int i=0; i!= nc; ++i)
00918           {
00919             Ue(current_dof) =
00920               old_vector(node_dof_indices[current_dof]);
00921             dof_is_fixed[current_dof] = true;
00922             current_dof++;
00923           }
00924       }
00925   }
00926 
00927   // In 3D, project any edge values next
00928   if (dim > 2 && cont != DISCONTINUOUS)
00929     for (unsigned int e=0; e != elem->n_edges(); ++e)
00930       {
00931         FEInterface::dofs_on_edge(elem, dim, fe_type,
00932                                   e, new_side_dofs);
00933 
00934         // Some edge dofs are on nodes and already
00935         // fixed, others are free to calculate
00936         unsigned int free_dofs = 0;
00937         for (unsigned int i=0; i !=
00938                new_side_dofs.size(); ++i)
00939           if (!dof_is_fixed[new_side_dofs[i]])
00940             free_dof[free_dofs++] = i;
00941         Ke.resize (free_dofs, free_dofs); Ke.zero();
00942         Fe.resize (free_dofs); Fe.zero();
00943         // The new edge coefficients
00944         DenseVector<Number> Uedge(free_dofs);
00945 
00946         // Add projection terms from each child sharing
00947         // this edge
00948         for (unsigned int c=0; c != elem->n_children();
00949              ++c)
00950           {
00951             if (!elem->is_child_on_edge(c,e))
00952               continue;
00953             Elem *child = elem->child(c);
00954 
00955             std::vector<dof_id_type> child_dof_indices;
00956             if (use_old_dof_indices)
00957               dof_map.old_dof_indices (child,
00958                                        child_dof_indices, var);
00959             else
00960               dof_map.dof_indices (child,
00961                                    child_dof_indices, var);
00962             const unsigned int child_n_dofs =
00963               cast_int<unsigned int>
00964               (child_dof_indices.size());
00965 
00966             temp_fe_type = base_fe_type;
00967             temp_fe_type.order =
00968               static_cast<Order>(temp_fe_type.order +
00969                                  child->p_level());
00970 
00971             FEInterface::dofs_on_edge(child, dim,
00972                                       temp_fe_type, e, old_side_dofs);
00973 
00974             // Initialize both child and parent FE data
00975             // on the child's edge
00976             fe->attach_quadrature_rule (qedgerule.get());
00977             fe->edge_reinit (child, e);
00978             const unsigned int n_qp = qedgerule->n_points();
00979 
00980             FEInterface::inverse_map (dim, fe_type, elem,
00981                                       xyz_values, coarse_qpoints);
00982 
00983             fe_coarse->reinit(elem, &coarse_qpoints);
00984 
00985             // Loop over the quadrature points
00986             for (unsigned int qp=0; qp<n_qp; qp++)
00987               {
00988                 // solution value at the quadrature point
00989                 OutputNumber fineval = libMesh::zero;
00990                 // solution grad at the quadrature point
00991                 OutputNumberGradient finegrad;
00992 
00993                 // Sum the solution values * the DOF
00994                 // values at the quadrature point to
00995                 // get the solution value and gradient.
00996                 for (unsigned int i=0; i<child_n_dofs;
00997                      i++)
00998                   {
00999                     fineval +=
01000                       (old_vector(child_dof_indices[i])*
01001                        phi_values[i][qp]);
01002                     if (cont == C_ONE)
01003                       finegrad += (*dphi_values)[i][qp] *
01004                         old_vector(child_dof_indices[i]);
01005                   }
01006 
01007                 // Form edge projection matrix
01008                 for (unsigned int sidei=0, freei=0;
01009                      sidei != new_side_dofs.size();
01010                      ++sidei)
01011                   {
01012                     unsigned int i = new_side_dofs[sidei];
01013                     // fixed DoFs aren't test functions
01014                     if (dof_is_fixed[i])
01015                       continue;
01016                     for (unsigned int sidej=0, freej=0;
01017                          sidej != new_side_dofs.size();
01018                          ++sidej)
01019                       {
01020                         unsigned int j =
01021                           new_side_dofs[sidej];
01022                         if (dof_is_fixed[j])
01023                           Fe(freei) -=
01024                             TensorTools::inner_product(phi_coarse[i][qp],
01025                                                        phi_coarse[j][qp]) *
01026                             JxW[qp] * Ue(j);
01027                         else
01028                           Ke(freei,freej) +=
01029                             TensorTools::inner_product(phi_coarse[i][qp],
01030                                                        phi_coarse[j][qp]) *
01031                             JxW[qp];
01032                         if (cont == C_ONE)
01033                           {
01034                             if (dof_is_fixed[j])
01035                               Fe(freei) -=
01036                                 TensorTools::inner_product((*dphi_coarse)[i][qp],
01037                                                            (*dphi_coarse)[j][qp]) *
01038                                 JxW[qp] * Ue(j);
01039                             else
01040                               Ke(freei,freej) +=
01041                                 TensorTools::inner_product((*dphi_coarse)[i][qp],
01042                                                            (*dphi_coarse)[j][qp]) *
01043                                 JxW[qp];
01044                           }
01045                         if (!dof_is_fixed[j])
01046                           freej++;
01047                       }
01048                     Fe(freei) += TensorTools::inner_product(phi_coarse[i][qp],
01049                                                             fineval) * JxW[qp];
01050                     if (cont == C_ONE)
01051                       Fe(freei) +=
01052                         TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp];
01053                     freei++;
01054                   }
01055               }
01056           }
01057         Ke.cholesky_solve(Fe, Uedge);
01058 
01059         // Transfer new edge solutions to element
01060         for (unsigned int i=0; i != free_dofs; ++i)
01061           {
01062             Number &ui = Ue(new_side_dofs[free_dof[i]]);
01063             libmesh_assert(std::abs(ui) < TOLERANCE ||
01064                            std::abs(ui - Uedge(i)) < TOLERANCE);
01065             ui = Uedge(i);
01066             dof_is_fixed[new_side_dofs[free_dof[i]]] =
01067               true;
01068           }
01069       }
01070 
01071   // Project any side values (edges in 2D, faces in 3D)
01072   if (dim > 1 && cont != DISCONTINUOUS)
01073     for (unsigned int s=0; s != elem->n_sides(); ++s)
01074       {
01075         FEInterface::dofs_on_side(elem, dim, fe_type,
01076                                   s, new_side_dofs);
01077 
01078         // Some side dofs are on nodes/edges and already
01079         // fixed, others are free to calculate
01080         unsigned int free_dofs = 0;
01081         for (unsigned int i=0; i !=
01082                new_side_dofs.size(); ++i)
01083           if (!dof_is_fixed[new_side_dofs[i]])
01084             free_dof[free_dofs++] = i;
01085         Ke.resize (free_dofs, free_dofs); Ke.zero();
01086         Fe.resize (free_dofs); Fe.zero();
01087         // The new side coefficients
01088         DenseVector<Number> Uside(free_dofs);
01089 
01090         // Add projection terms from each child sharing
01091         // this side
01092         for (unsigned int c=0; c != elem->n_children();
01093              ++c)
01094           {
01095             if (!elem->is_child_on_side(c,s))
01096               continue;
01097             Elem *child = elem->child(c);
01098 
01099             std::vector<dof_id_type> child_dof_indices;
01100             if (use_old_dof_indices)
01101               dof_map.old_dof_indices (child,
01102                                        child_dof_indices, var);
01103             else
01104               dof_map.dof_indices (child,
01105                                    child_dof_indices, var);
01106             const unsigned int child_n_dofs =
01107               cast_int<unsigned int>
01108               (child_dof_indices.size());
01109 
01110             temp_fe_type = base_fe_type;
01111             temp_fe_type.order =
01112               static_cast<Order>(temp_fe_type.order +
01113                                  child->p_level());
01114 
01115             FEInterface::dofs_on_side(child, dim,
01116                                       temp_fe_type, s, old_side_dofs);
01117 
01118             // Initialize both child and parent FE data
01119             // on the child's side
01120             fe->attach_quadrature_rule (qsiderule.get());
01121             fe->reinit (child, s);
01122             const unsigned int n_qp = qsiderule->n_points();
01123 
01124             FEInterface::inverse_map (dim, fe_type, elem,
01125                                       xyz_values, coarse_qpoints);
01126 
01127             fe_coarse->reinit(elem, &coarse_qpoints);
01128 
01129             // Loop over the quadrature points
01130             for (unsigned int qp=0; qp<n_qp; qp++)
01131               {
01132                 // solution value at the quadrature point
01133                 OutputNumber fineval = libMesh::zero;
01134                 // solution grad at the quadrature point
01135                 OutputNumberGradient finegrad;
01136 
01137                 // Sum the solution values * the DOF
01138                 // values at the quadrature point to
01139                 // get the solution value and gradient.
01140                 for (unsigned int i=0; i<child_n_dofs;
01141                      i++)
01142                   {
01143                     fineval +=
01144                       old_vector(child_dof_indices[i]) *
01145                       phi_values[i][qp];
01146                     if (cont == C_ONE)
01147                       finegrad += (*dphi_values)[i][qp] *
01148                         old_vector(child_dof_indices[i]);
01149                   }
01150 
01151                 // Form side projection matrix
01152                 for (unsigned int sidei=0, freei=0;
01153                      sidei != new_side_dofs.size();
01154                      ++sidei)
01155                   {
01156                     unsigned int i = new_side_dofs[sidei];
01157                     // fixed DoFs aren't test functions
01158                     if (dof_is_fixed[i])
01159                       continue;
01160                     for (unsigned int sidej=0, freej=0;
01161                          sidej != new_side_dofs.size();
01162                          ++sidej)
01163                       {
01164                         unsigned int j =
01165                           new_side_dofs[sidej];
01166                         if (dof_is_fixed[j])
01167                           Fe(freei) -=
01168                             TensorTools::inner_product(phi_coarse[i][qp],
01169                                                        phi_coarse[j][qp]) *
01170                             JxW[qp] * Ue(j);
01171                         else
01172                           Ke(freei,freej) +=
01173                             TensorTools::inner_product(phi_coarse[i][qp],
01174                                                        phi_coarse[j][qp]) *
01175                             JxW[qp];
01176                         if (cont == C_ONE)
01177                           {
01178                             if (dof_is_fixed[j])
01179                               Fe(freei) -=
01180                                 TensorTools::inner_product((*dphi_coarse)[i][qp],
01181                                                            (*dphi_coarse)[j][qp]) *
01182                                 JxW[qp] * Ue(j);
01183                             else
01184                               Ke(freei,freej) +=
01185                                 TensorTools::inner_product((*dphi_coarse)[i][qp],
01186                                                            (*dphi_coarse)[j][qp]) *
01187                                 JxW[qp];
01188                           }
01189                         if (!dof_is_fixed[j])
01190                           freej++;
01191                       }
01192                     Fe(freei) += TensorTools::inner_product(fineval, phi_coarse[i][qp]) * JxW[qp];
01193                     if (cont == C_ONE)
01194                       Fe(freei) +=
01195                         TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp];
01196                     freei++;
01197                   }
01198               }
01199           }
01200         Ke.cholesky_solve(Fe, Uside);
01201 
01202         // Transfer new side solutions to element
01203         for (unsigned int i=0; i != free_dofs; ++i)
01204           {
01205             Number &ui = Ue(new_side_dofs[free_dof[i]]);
01206             libmesh_assert(std::abs(ui) < TOLERANCE ||
01207                            std::abs(ui - Uside(i)) < TOLERANCE);
01208             ui = Uside(i);
01209             dof_is_fixed[new_side_dofs[free_dof[i]]] =
01210               true;
01211           }
01212       }
01213 
01214   // Project the interior values, finally
01215 
01216   // Some interior dofs are on nodes/edges/sides and
01217   // already fixed, others are free to calculate
01218   unsigned int free_dofs = 0;
01219   for (unsigned int i=0; i != new_n_dofs; ++i)
01220     if (!dof_is_fixed[i])
01221       free_dof[free_dofs++] = i;
01222   Ke.resize (free_dofs, free_dofs); Ke.zero();
01223   Fe.resize (free_dofs); Fe.zero();
01224   // The new interior coefficients
01225   DenseVector<Number> Uint(free_dofs);
01226 
01227   // Add projection terms from each child
01228   for (unsigned int c=0; c != elem->n_children(); ++c)
01229     {
01230       Elem *child = elem->child(c);
01231 
01232       std::vector<dof_id_type> child_dof_indices;
01233       if (use_old_dof_indices)
01234         dof_map.old_dof_indices (child,
01235                                  child_dof_indices, var);
01236       else
01237         dof_map.dof_indices (child,
01238                              child_dof_indices, var);
01239       const unsigned int child_n_dofs =
01240         cast_int<unsigned int>
01241         (child_dof_indices.size());
01242 
01243       // Initialize both child and parent FE data
01244       // on the child's quadrature points
01245       fe->attach_quadrature_rule (qrule.get());
01246       fe->reinit (child);
01247       const unsigned int n_qp = qrule->n_points();
01248 
01249       FEInterface::inverse_map (dim, fe_type, elem,
01250                                 xyz_values, coarse_qpoints);
01251 
01252       fe_coarse->reinit(elem, &coarse_qpoints);
01253 
01254       // Loop over the quadrature points
01255       for (unsigned int qp=0; qp<n_qp; qp++)
01256         {
01257           // solution value at the quadrature point
01258           OutputNumber fineval = libMesh::zero;
01259           // solution grad at the quadrature point
01260           OutputNumberGradient finegrad;
01261 
01262           // Sum the solution values * the DOF
01263           // values at the quadrature point to
01264           // get the solution value and gradient.
01265           for (unsigned int i=0; i<child_n_dofs; i++)
01266             {
01267               fineval +=
01268                 (old_vector(child_dof_indices[i]) *
01269                  phi_values[i][qp]);
01270               if (cont == C_ONE)
01271                 finegrad += (*dphi_values)[i][qp] *
01272                   old_vector(child_dof_indices[i]);
01273             }
01274 
01275           // Form interior projection matrix
01276           for (unsigned int i=0, freei=0;
01277                i != new_n_dofs; ++i)
01278             {
01279               // fixed DoFs aren't test functions
01280               if (dof_is_fixed[i])
01281                 continue;
01282               for (unsigned int j=0, freej=0; j !=
01283                      new_n_dofs; ++j)
01284                 {
01285                   if (dof_is_fixed[j])
01286                     Fe(freei) -=
01287                       TensorTools::inner_product(phi_coarse[i][qp],
01288                                                  phi_coarse[j][qp]) *
01289                       JxW[qp] * Ue(j);
01290                   else
01291                     Ke(freei,freej) +=
01292                       TensorTools::inner_product(phi_coarse[i][qp],
01293                                                  phi_coarse[j][qp]) *
01294                       JxW[qp];
01295                   if (cont == C_ONE)
01296                     {
01297                       if (dof_is_fixed[j])
01298                         Fe(freei) -=
01299                           TensorTools::inner_product((*dphi_coarse)[i][qp],
01300                                                      (*dphi_coarse)[j][qp]) *
01301                           JxW[qp] * Ue(j);
01302                       else
01303                         Ke(freei,freej) +=
01304                           TensorTools::inner_product((*dphi_coarse)[i][qp],
01305                                                      (*dphi_coarse)[j][qp]) *
01306                           JxW[qp];
01307                     }
01308                   if (!dof_is_fixed[j])
01309                     freej++;
01310                 }
01311               Fe(freei) += TensorTools::inner_product(phi_coarse[i][qp], fineval) *
01312                 JxW[qp];
01313               if (cont == C_ONE)
01314                 Fe(freei) += TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp];
01315               freei++;
01316             }
01317         }
01318     }
01319   Ke.cholesky_solve(Fe, Uint);
01320 
01321   // Transfer new interior solutions to element
01322   for (unsigned int i=0; i != free_dofs; ++i)
01323     {
01324       Number &ui = Ue(free_dof[i]);
01325       libmesh_assert(std::abs(ui) < TOLERANCE ||
01326                      std::abs(ui - Uint(i)) < TOLERANCE);
01327       ui = Uint(i);
01328       // We should be fixing all dofs by now; no need to keep track of
01329       // that unless we're debugging
01330 #ifndef NDEBUG
01331       dof_is_fixed[free_dof[i]] = true;
01332 #endif
01333     }
01334 
01335 #ifndef NDEBUG
01336   // Make sure every DoF got reached!
01337   for (unsigned int i=0; i != new_n_dofs; ++i)
01338     libmesh_assert(dof_is_fixed[i]);
01339 #endif
01340 }
01341 
01342 
01343 
01344 template <typename OutputType>
01345 void
01346 FEGenericBase<OutputType>::compute_proj_constraints (DofConstraints &constraints,
01347                                                      DofMap &dof_map,
01348                                                      const unsigned int variable_number,
01349                                                      const Elem* elem)
01350 {
01351   libmesh_assert(elem);
01352 
01353   const unsigned int Dim = elem->dim();
01354 
01355   // Only constrain elements in 2,3D.
01356   if (Dim == 1)
01357     return;
01358 
01359   // Only constrain active elements with this method
01360   if (!elem->active())
01361     return;
01362 
01363   const FEType& base_fe_type = dof_map.variable_type(variable_number);
01364 
01365   // Construct FE objects for this element and its neighbors.
01366   UniquePtr<FEGenericBase<OutputShape> > my_fe
01367     (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
01368   const FEContinuity cont = my_fe->get_continuity();
01369 
01370   // We don't need to constrain discontinuous elements
01371   if (cont == DISCONTINUOUS)
01372     return;
01373   libmesh_assert (cont == C_ZERO || cont == C_ONE);
01374 
01375   UniquePtr<FEGenericBase<OutputShape> > neigh_fe
01376     (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
01377 
01378   QGauss my_qface(Dim-1, base_fe_type.default_quadrature_order());
01379   my_fe->attach_quadrature_rule (&my_qface);
01380   std::vector<Point> neigh_qface;
01381 
01382   const std::vector<Real>& JxW = my_fe->get_JxW();
01383   const std::vector<Point>& q_point = my_fe->get_xyz();
01384   const std::vector<std::vector<OutputShape> >& phi = my_fe->get_phi();
01385   const std::vector<std::vector<OutputShape> >& neigh_phi =
01386     neigh_fe->get_phi();
01387   const std::vector<Point> *face_normals = NULL;
01388   const std::vector<std::vector<OutputGradient> > *dphi = NULL;
01389   const std::vector<std::vector<OutputGradient> > *neigh_dphi = NULL;
01390 
01391   std::vector<dof_id_type> my_dof_indices, neigh_dof_indices;
01392   std::vector<unsigned int> my_side_dofs, neigh_side_dofs;
01393 
01394   if (cont != C_ZERO)
01395     {
01396       const std::vector<Point>& ref_face_normals =
01397         my_fe->get_normals();
01398       face_normals = &ref_face_normals;
01399       const std::vector<std::vector<OutputGradient> >& ref_dphi =
01400         my_fe->get_dphi();
01401       dphi = &ref_dphi;
01402       const std::vector<std::vector<OutputGradient> >& ref_neigh_dphi =
01403         neigh_fe->get_dphi();
01404       neigh_dphi = &ref_neigh_dphi;
01405     }
01406 
01407   DenseMatrix<Real> Ke;
01408   DenseVector<Real> Fe;
01409   std::vector<DenseVector<Real> > Ue;
01410 
01411   // Look at the element faces.  Check to see if we need to
01412   // build constraints.
01413   for (unsigned int s=0; s<elem->n_sides(); s++)
01414     if (elem->neighbor(s) != NULL)
01415       {
01416         // Get pointers to the element's neighbor.
01417         const Elem* neigh = elem->neighbor(s);
01418 
01419         // h refinement constraints:
01420         // constrain dofs shared between
01421         // this element and ones coarser
01422         // than this element.
01423         if (neigh->level() < elem->level())
01424           {
01425             unsigned int s_neigh = neigh->which_neighbor_am_i(elem);
01426             libmesh_assert_less (s_neigh, neigh->n_neighbors());
01427 
01428             // Find the minimum p level; we build the h constraint
01429             // matrix with this and then constrain away all higher p
01430             // DoFs.
01431             libmesh_assert(neigh->active());
01432             const unsigned int min_p_level =
01433               std::min(elem->p_level(), neigh->p_level());
01434 
01435             // we may need to make the FE objects reinit with the
01436             // minimum shared p_level
01437             // FIXME - I hate using const_cast<> and avoiding
01438             // accessor functions; there's got to be a
01439             // better way to do this!
01440             const unsigned int old_elem_level = elem->p_level();
01441             if (old_elem_level != min_p_level)
01442               (const_cast<Elem *>(elem))->hack_p_level(min_p_level);
01443             const unsigned int old_neigh_level = neigh->p_level();
01444             if (old_neigh_level != min_p_level)
01445               (const_cast<Elem *>(neigh))->hack_p_level(min_p_level);
01446 
01447             my_fe->reinit(elem, s);
01448 
01449             // This function gets called element-by-element, so there
01450             // will be a lot of memory allocation going on.  We can
01451             // at least minimize this for the case of the dof indices
01452             // by efficiently preallocating the requisite storage.
01453             // n_nodes is not necessarily n_dofs, but it is better
01454             // than nothing!
01455             my_dof_indices.reserve    (elem->n_nodes());
01456             neigh_dof_indices.reserve (neigh->n_nodes());
01457 
01458             dof_map.dof_indices (elem, my_dof_indices,
01459                                  variable_number);
01460             dof_map.dof_indices (neigh, neigh_dof_indices,
01461                                  variable_number);
01462 
01463             const unsigned int n_qp = my_qface.n_points();
01464 
01465             FEInterface::inverse_map (Dim, base_fe_type, neigh,
01466                                       q_point, neigh_qface);
01467 
01468             neigh_fe->reinit(neigh, &neigh_qface);
01469 
01470             // We're only concerned with DOFs whose values (and/or first
01471             // derivatives for C1 elements) are supported on side nodes
01472             FEInterface::dofs_on_side(elem,  Dim, base_fe_type, s,       my_side_dofs);
01473             FEInterface::dofs_on_side(neigh, Dim, base_fe_type, s_neigh, neigh_side_dofs);
01474 
01475             // We're done with functions that examine Elem::p_level(),
01476             // so let's unhack those levels
01477             if (elem->p_level() != old_elem_level)
01478               (const_cast<Elem *>(elem))->hack_p_level(old_elem_level);
01479             if (neigh->p_level() != old_neigh_level)
01480               (const_cast<Elem *>(neigh))->hack_p_level(old_neigh_level);
01481 
01482             const unsigned int n_side_dofs =
01483               cast_int<unsigned int>(my_side_dofs.size());
01484             libmesh_assert_equal_to (n_side_dofs, neigh_side_dofs.size());
01485 
01486             Ke.resize (n_side_dofs, n_side_dofs);
01487             Ue.resize(n_side_dofs);
01488 
01489             // Form the projection matrix, (inner product of fine basis
01490             // functions against fine test functions)
01491             for (unsigned int is = 0; is != n_side_dofs; ++is)
01492               {
01493                 const unsigned int i = my_side_dofs[is];
01494                 for (unsigned int js = 0; js != n_side_dofs; ++js)
01495                   {
01496                     const unsigned int j = my_side_dofs[js];
01497                     for (unsigned int qp = 0; qp != n_qp; ++qp)
01498                       {
01499                         Ke(is,js) += JxW[qp] * TensorTools::inner_product(phi[i][qp], phi[j][qp]);
01500                         if (cont != C_ZERO)
01501                           Ke(is,js) += JxW[qp] *
01502                             TensorTools::inner_product((*dphi)[i][qp] *
01503                                                        (*face_normals)[qp],
01504                                                        (*dphi)[j][qp] *
01505                                                        (*face_normals)[qp]);
01506                       }
01507                   }
01508               }
01509 
01510             // Form the right hand sides, (inner product of coarse basis
01511             // functions against fine test functions)
01512             for (unsigned int is = 0; is != n_side_dofs; ++is)
01513               {
01514                 const unsigned int i = neigh_side_dofs[is];
01515                 Fe.resize (n_side_dofs);
01516                 for (unsigned int js = 0; js != n_side_dofs; ++js)
01517                   {
01518                     const unsigned int j = my_side_dofs[js];
01519                     for (unsigned int qp = 0; qp != n_qp; ++qp)
01520                       {
01521                         Fe(js) += JxW[qp] *
01522                           TensorTools::inner_product(neigh_phi[i][qp],
01523                                                      phi[j][qp]);
01524                         if (cont != C_ZERO)
01525                           Fe(js) += JxW[qp] *
01526                             TensorTools::inner_product((*neigh_dphi)[i][qp] *
01527                                                        (*face_normals)[qp],
01528                                                        (*dphi)[j][qp] *
01529                                                        (*face_normals)[qp]);
01530                       }
01531                   }
01532                 Ke.cholesky_solve(Fe, Ue[is]);
01533               }
01534 
01535             for (unsigned int js = 0; js != n_side_dofs; ++js)
01536               {
01537                 const unsigned int j = my_side_dofs[js];
01538                 const dof_id_type my_dof_g = my_dof_indices[j];
01539                 libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id);
01540 
01541                 // Hunt for "constraining against myself" cases before
01542                 // we bother creating a constraint row
01543                 bool self_constraint = false;
01544                 for (unsigned int is = 0; is != n_side_dofs; ++is)
01545                   {
01546                     const unsigned int i = neigh_side_dofs[is];
01547                     const dof_id_type their_dof_g = neigh_dof_indices[i];
01548                     libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
01549 
01550                     if (their_dof_g == my_dof_g)
01551                       {
01552 #ifndef NDEBUG
01553                         const Real their_dof_value = Ue[is](js);
01554                         libmesh_assert_less (std::abs(their_dof_value-1.),
01555                                              10*TOLERANCE);
01556 
01557                         for (unsigned int k = 0; k != n_side_dofs; ++k)
01558                           libmesh_assert(k == is ||
01559                                          std::abs(Ue[k](js)) <
01560                                          10*TOLERANCE);
01561 #endif
01562 
01563                         self_constraint = true;
01564                         break;
01565                       }
01566                   }
01567 
01568                 if (self_constraint)
01569                   continue;
01570 
01571                 DofConstraintRow* constraint_row;
01572 
01573                 // we may be running constraint methods concurrently
01574                 // on multiple threads, so we need a lock to
01575                 // ensure that this constraint is "ours"
01576                 {
01577                   Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
01578 
01579                   if (dof_map.is_constrained_dof(my_dof_g))
01580                     continue;
01581 
01582                   constraint_row = &(constraints[my_dof_g]);
01583                   libmesh_assert(constraint_row->empty());
01584                 }
01585 
01586                 for (unsigned int is = 0; is != n_side_dofs; ++is)
01587                   {
01588                     const unsigned int i = neigh_side_dofs[is];
01589                     const dof_id_type their_dof_g = neigh_dof_indices[i];
01590                     libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
01591                     libmesh_assert_not_equal_to (their_dof_g, my_dof_g);
01592 
01593                     const Real their_dof_value = Ue[is](js);
01594 
01595                     if (std::abs(their_dof_value) < 10*TOLERANCE)
01596                       continue;
01597 
01598                     constraint_row->insert(std::make_pair(their_dof_g,
01599                                                           their_dof_value));
01600                   }
01601               }
01602           }
01603         // p refinement constraints:
01604         // constrain dofs shared between
01605         // active elements and neighbors with
01606         // lower polynomial degrees
01607         const unsigned int min_p_level =
01608           neigh->min_p_level_by_neighbor(elem, elem->p_level());
01609         if (min_p_level < elem->p_level())
01610           {
01611             // Adaptive p refinement of non-hierarchic bases will
01612             // require more coding
01613             libmesh_assert(my_fe->is_hierarchic());
01614             dof_map.constrain_p_dofs(variable_number, elem,
01615                                      s, min_p_level);
01616           }
01617       }
01618 }
01619 
01620 #endif // #ifdef LIBMESH_ENABLE_AMR
01621 
01622 
01623 
01624 #ifdef LIBMESH_ENABLE_PERIODIC
01625 template <typename OutputType>
01626 void
01627 FEGenericBase<OutputType>::
01628 compute_periodic_constraints (DofConstraints &constraints,
01629                               DofMap &dof_map,
01630                               const PeriodicBoundaries &boundaries,
01631                               const MeshBase &mesh,
01632                               const PointLocatorBase *point_locator,
01633                               const unsigned int variable_number,
01634                               const Elem* elem)
01635 {
01636   // Only bother if we truly have periodic boundaries
01637   if (boundaries.empty())
01638     return;
01639 
01640   libmesh_assert(elem);
01641 
01642   // Only constrain active elements with this method
01643   if (!elem->active())
01644     return;
01645 
01646   const unsigned int Dim = elem->dim();
01647 
01648   // We need sys_number and variable_number for DofObject methods
01649   // later
01650   const unsigned int sys_number = dof_map.sys_number();
01651 
01652   const FEType& base_fe_type = dof_map.variable_type(variable_number);
01653 
01654   // Construct FE objects for this element and its pseudo-neighbors.
01655   UniquePtr<FEGenericBase<OutputShape> > my_fe
01656     (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
01657   const FEContinuity cont = my_fe->get_continuity();
01658 
01659   // We don't need to constrain discontinuous elements
01660   if (cont == DISCONTINUOUS)
01661     return;
01662   libmesh_assert (cont == C_ZERO || cont == C_ONE);
01663 
01664   // We'll use element size to generate relative tolerances later
01665   const Real primary_hmin = elem->hmin();
01666 
01667   UniquePtr<FEGenericBase<OutputShape> > neigh_fe
01668     (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
01669 
01670   QGauss my_qface(Dim-1, base_fe_type.default_quadrature_order());
01671   my_fe->attach_quadrature_rule (&my_qface);
01672   std::vector<Point> neigh_qface;
01673 
01674   const std::vector<Real>& JxW = my_fe->get_JxW();
01675   const std::vector<Point>& q_point = my_fe->get_xyz();
01676   const std::vector<std::vector<OutputShape> >& phi = my_fe->get_phi();
01677   const std::vector<std::vector<OutputShape> >& neigh_phi =
01678     neigh_fe->get_phi();
01679   const std::vector<Point> *face_normals = NULL;
01680   const std::vector<std::vector<OutputGradient> > *dphi = NULL;
01681   const std::vector<std::vector<OutputGradient> > *neigh_dphi = NULL;
01682   std::vector<dof_id_type> my_dof_indices, neigh_dof_indices;
01683   std::vector<unsigned int> my_side_dofs, neigh_side_dofs;
01684 
01685   if (cont != C_ZERO)
01686     {
01687       const std::vector<Point>& ref_face_normals =
01688         my_fe->get_normals();
01689       face_normals = &ref_face_normals;
01690       const std::vector<std::vector<OutputGradient> >& ref_dphi =
01691         my_fe->get_dphi();
01692       dphi = &ref_dphi;
01693       const std::vector<std::vector<OutputGradient> >& ref_neigh_dphi =
01694         neigh_fe->get_dphi();
01695       neigh_dphi = &ref_neigh_dphi;
01696     }
01697 
01698   DenseMatrix<Real> Ke;
01699   DenseVector<Real> Fe;
01700   std::vector<DenseVector<Real> > Ue;
01701 
01702   // Look at the element faces.  Check to see if we need to
01703   // build constraints.
01704   for (unsigned short int s=0; s<elem->n_sides(); s++)
01705     {
01706       if (elem->neighbor(s))
01707         continue;
01708 
01709       const std::vector<boundary_id_type>& bc_ids =
01710         mesh.get_boundary_info().boundary_ids (elem, s);
01711       for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it)
01712         {
01713           const boundary_id_type boundary_id = *id_it;
01714           const PeriodicBoundaryBase *periodic = boundaries.boundary(boundary_id);
01715           if (periodic && periodic->is_my_variable(variable_number))
01716             {
01717               libmesh_assert(point_locator);
01718 
01719               // Get pointers to the element's neighbor.
01720               const Elem* neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s);
01721 
01722               if (neigh == NULL)
01723                 libmesh_error_msg("PeriodicBoundaries point locator object returned NULL!");
01724 
01725               // periodic (and possibly h refinement) constraints:
01726               // constrain dofs shared between
01727               // this element and ones as coarse
01728               // as or coarser than this element.
01729               if (neigh->level() <= elem->level())
01730                 {
01731                   unsigned int s_neigh =
01732                     mesh.get_boundary_info().side_with_boundary_id(neigh, periodic->pairedboundary);
01733                   libmesh_assert_not_equal_to (s_neigh, libMesh::invalid_uint);
01734 
01735 #ifdef LIBMESH_ENABLE_AMR
01736                   // Find the minimum p level; we build the h constraint
01737                   // matrix with this and then constrain away all higher p
01738                   // DoFs.
01739                   libmesh_assert(neigh->active());
01740                   const unsigned int min_p_level =
01741                     std::min(elem->p_level(), neigh->p_level());
01742 
01743                   // we may need to make the FE objects reinit with the
01744                   // minimum shared p_level
01745                   // FIXME - I hate using const_cast<> and avoiding
01746                   // accessor functions; there's got to be a
01747                   // better way to do this!
01748                   const unsigned int old_elem_level = elem->p_level();
01749                   if (old_elem_level != min_p_level)
01750                     (const_cast<Elem *>(elem))->hack_p_level(min_p_level);
01751                   const unsigned int old_neigh_level = neigh->p_level();
01752                   if (old_neigh_level != min_p_level)
01753                     (const_cast<Elem *>(neigh))->hack_p_level(min_p_level);
01754 #endif // #ifdef LIBMESH_ENABLE_AMR
01755 
01756                   // We can do a projection with a single integration,
01757                   // due to the assumption of nested finite element
01758                   // subspaces.
01759                   // FIXME: it might be more efficient to do nodes,
01760                   // then edges, then side, to reduce the size of the
01761                   // Cholesky factorization(s)
01762                   my_fe->reinit(elem, s);
01763 
01764                   dof_map.dof_indices (elem, my_dof_indices,
01765                                        variable_number);
01766                   dof_map.dof_indices (neigh, neigh_dof_indices,
01767                                        variable_number);
01768 
01769                   const unsigned int n_qp = my_qface.n_points();
01770 
01771                   // Translate the quadrature points over to the
01772                   // neighbor's boundary
01773                   std::vector<Point> neigh_point(q_point.size());
01774                   for (unsigned int i=0; i != neigh_point.size(); ++i)
01775                     neigh_point[i] = periodic->get_corresponding_pos(q_point[i]);
01776 
01777                   FEInterface::inverse_map (Dim, base_fe_type, neigh,
01778                                             neigh_point, neigh_qface);
01779 
01780                   neigh_fe->reinit(neigh, &neigh_qface);
01781 
01782                   // We're only concerned with DOFs whose values (and/or first
01783                   // derivatives for C1 elements) are supported on side nodes
01784                   FEInterface::dofs_on_side(elem, Dim, base_fe_type, s, my_side_dofs);
01785                   FEInterface::dofs_on_side(neigh, Dim, base_fe_type, s_neigh, neigh_side_dofs);
01786 
01787                   // We're done with functions that examine Elem::p_level(),
01788                   // so let's unhack those levels
01789 #ifdef LIBMESH_ENABLE_AMR
01790                   if (elem->p_level() != old_elem_level)
01791                     (const_cast<Elem *>(elem))->hack_p_level(old_elem_level);
01792                   if (neigh->p_level() != old_neigh_level)
01793                     (const_cast<Elem *>(neigh))->hack_p_level(old_neigh_level);
01794 #endif // #ifdef LIBMESH_ENABLE_AMR
01795 
01796                   const unsigned int n_side_dofs =
01797                     cast_int<unsigned int>
01798                     (my_side_dofs.size());
01799                   libmesh_assert_equal_to (n_side_dofs, neigh_side_dofs.size());
01800 
01801                   Ke.resize (n_side_dofs, n_side_dofs);
01802                   Ue.resize(n_side_dofs);
01803 
01804                   // Form the projection matrix, (inner product of fine basis
01805                   // functions against fine test functions)
01806                   for (unsigned int is = 0; is != n_side_dofs; ++is)
01807                     {
01808                       const unsigned int i = my_side_dofs[is];
01809                       for (unsigned int js = 0; js != n_side_dofs; ++js)
01810                         {
01811                           const unsigned int j = my_side_dofs[js];
01812                           for (unsigned int qp = 0; qp != n_qp; ++qp)
01813                             {
01814                               Ke(is,js) += JxW[qp] *
01815                                 TensorTools::inner_product(phi[i][qp],
01816                                                            phi[j][qp]);
01817                               if (cont != C_ZERO)
01818                                 Ke(is,js) += JxW[qp] *
01819                                   TensorTools::inner_product((*dphi)[i][qp] *
01820                                                              (*face_normals)[qp],
01821                                                              (*dphi)[j][qp] *
01822                                                              (*face_normals)[qp]);
01823                             }
01824                         }
01825                     }
01826 
01827                   // Form the right hand sides, (inner product of coarse basis
01828                   // functions against fine test functions)
01829                   for (unsigned int is = 0; is != n_side_dofs; ++is)
01830                     {
01831                       const unsigned int i = neigh_side_dofs[is];
01832                       Fe.resize (n_side_dofs);
01833                       for (unsigned int js = 0; js != n_side_dofs; ++js)
01834                         {
01835                           const unsigned int j = my_side_dofs[js];
01836                           for (unsigned int qp = 0; qp != n_qp; ++qp)
01837                             {
01838                               Fe(js) += JxW[qp] *
01839                                 TensorTools::inner_product(neigh_phi[i][qp],
01840                                                            phi[j][qp]);
01841                               if (cont != C_ZERO)
01842                                 Fe(js) += JxW[qp] *
01843                                   TensorTools::inner_product((*neigh_dphi)[i][qp] *
01844                                                              (*face_normals)[qp],
01845                                                              (*dphi)[j][qp] *
01846                                                              (*face_normals)[qp]);
01847                             }
01848                         }
01849                       Ke.cholesky_solve(Fe, Ue[is]);
01850                     }
01851 
01852                   // Make sure we're not adding recursive constraints
01853                   // due to the redundancy in the way we add periodic
01854                   // boundary constraints
01855                   //
01856                   // In order for this to work while threaded or on
01857                   // distributed meshes, we need a rigorous way to
01858                   // avoid recursive constraints.  Here it is:
01859                   //
01860                   // For vertex DoFs, if there is a "prior" element
01861                   // (i.e. a coarser element or an equally refined
01862                   // element with a lower id) on this boundary which
01863                   // contains the vertex point, then we will avoid
01864                   // generating constraints; the prior element (or
01865                   // something prior to it) may do so.  If we are the
01866                   // most prior (or "primary") element on this
01867                   // boundary sharing this point, then we look at the
01868                   // boundary periodic to us, we find the primary
01869                   // element there, and if that primary is coarser or
01870                   // equal-but-lower-id, then our vertex dofs are
01871                   // constrained in terms of that element.
01872                   //
01873                   // For edge DoFs, if there is a coarser element
01874                   // on this boundary sharing this edge, then we will
01875                   // avoid generating constraints (we will be
01876                   // constrained indirectly via AMR constraints
01877                   // connecting us to the coarser element's DoFs).  If
01878                   // we are the coarsest element sharing this edge,
01879                   // then we generate constraints if and only if we
01880                   // are finer than the coarsest element on the
01881                   // boundary periodic to us sharing the corresponding
01882                   // periodic edge, or if we are at equal level but
01883                   // our edge nodes have higher ids than the periodic
01884                   // edge nodes (sorted from highest to lowest, then
01885                   // compared lexicographically)
01886                   //
01887                   // For face DoFs, we generate constraints if we are
01888                   // finer than our periodic neighbor, or if we are at
01889                   // equal level but our element id is higher than its
01890                   // element id.
01891                   //
01892                   // If the primary neighbor is also the current elem
01893                   // (a 1-element-thick mesh) then we choose which
01894                   // vertex dofs to constrain via lexicographic
01895                   // ordering on point locations
01896 
01897                   // FIXME: This code doesn't yet properly handle
01898                   // cases where multiple different periodic BCs
01899                   // intersect.
01900                   std::set<dof_id_type> my_constrained_dofs;
01901 
01902                   for (unsigned int n = 0; n != elem->n_nodes(); ++n)
01903                     {
01904                       if (!elem->is_node_on_side(n,s))
01905                         continue;
01906 
01907                       const Node* my_node = elem->get_node(n);
01908 
01909                       if (elem->is_vertex(n))
01910                         {
01911                           // Find all boundary ids that include this
01912                           // point and have periodic boundary
01913                           // conditions for this variable
01914                           std::set<boundary_id_type> point_bcids;
01915 
01916                           for (unsigned int new_s = 0; new_s !=
01917                                  elem->n_sides(); ++new_s)
01918                             {
01919                               if (!elem->is_node_on_side(n,new_s))
01920                                 continue;
01921 
01922                               const std::vector<boundary_id_type> new_bc_ids =
01923                                 mesh.get_boundary_info().boundary_ids (elem, s);
01924                               for (std::vector<boundary_id_type>::const_iterator
01925                                      new_id_it=new_bc_ids.begin(); new_id_it!=new_bc_ids.end(); ++new_id_it)
01926                                 {
01927                                   const boundary_id_type new_boundary_id = *new_id_it;
01928                                   const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id);
01929                                   if (new_periodic && new_periodic->is_my_variable(variable_number))
01930                                     {
01931                                       point_bcids.insert(new_boundary_id);
01932                                     }
01933                                 }
01934                             }
01935 
01936                           // See if this vertex has point neighbors to
01937                           // defer to
01938                           if (primary_boundary_point_neighbor
01939                               (elem, *my_node, mesh.get_boundary_info(), point_bcids)
01940                               != elem)
01941                             continue;
01942 
01943                           // Find the complementary boundary id set
01944                           std::set<boundary_id_type> point_pairedids;
01945                           for (std::set<boundary_id_type>::const_iterator i =
01946                                  point_bcids.begin(); i != point_bcids.end(); ++i)
01947                             {
01948                               const boundary_id_type new_boundary_id = *i;
01949                               const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id);
01950                               point_pairedids.insert(new_periodic->pairedboundary);
01951                             }
01952 
01953                           // What do we want to constrain against?
01954                           const Elem* primary_elem = NULL;
01955                           const Elem* main_neigh = NULL;
01956                           Point main_pt = *my_node,
01957                             primary_pt = *my_node;
01958 
01959                           for (std::set<boundary_id_type>::const_iterator i =
01960                                  point_bcids.begin(); i != point_bcids.end(); ++i)
01961                             {
01962                               // Find the corresponding periodic point and
01963                               // its primary neighbor
01964                               const boundary_id_type new_boundary_id = *i;
01965                               const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id);
01966 
01967                               const Point neigh_pt =
01968                                 new_periodic->get_corresponding_pos(*my_node);
01969 
01970                               // If the point is getting constrained
01971                               // to itself by this PBC then we don't
01972                               // generate any constraints
01973                               if (neigh_pt.absolute_fuzzy_equals
01974                                   (*my_node, primary_hmin*TOLERANCE))
01975                                 continue;
01976 
01977                               // Otherwise we'll have a constraint in
01978                               // one direction or another
01979                               if (!primary_elem)
01980                                 primary_elem = elem;
01981 
01982                               const Elem *primary_neigh =
01983                                 primary_boundary_point_neighbor(neigh, neigh_pt,
01984                                                                 mesh.get_boundary_info(),
01985                                                                 point_pairedids);
01986 
01987                               libmesh_assert(primary_neigh);
01988 
01989                               if (new_boundary_id == boundary_id)
01990                                 {
01991                                   main_neigh = primary_neigh;
01992                                   main_pt = neigh_pt;
01993                                 }
01994 
01995                               // Finer elements will get constrained in
01996                               // terms of coarser neighbors, not the
01997                               // other way around
01998                               if ((primary_neigh->level() > primary_elem->level()) ||
01999 
02000                                   // For equal-level elements, the one with
02001                                   // higher id gets constrained in terms of
02002                                   // the one with lower id
02003                                   (primary_neigh->level() == primary_elem->level() &&
02004                                    primary_neigh->id() > primary_elem->id()) ||
02005 
02006                                   // On a one-element-thick mesh, we compare
02007                                   // points to see what side gets constrained
02008                                   (primary_neigh == primary_elem &&
02009                                    (neigh_pt > primary_pt)))
02010                                 continue;
02011 
02012                               primary_elem = primary_neigh;
02013                               primary_pt = neigh_pt;
02014                             }
02015 
02016                           if (!primary_elem ||
02017                               primary_elem != main_neigh ||
02018                               primary_pt != main_pt)
02019                             continue;
02020                         }
02021                       else if (elem->is_edge(n))
02022                         {
02023                           // Find which edge we're on
02024                           unsigned int e=0;
02025                           for (; e != elem->n_edges(); ++e)
02026                             {
02027                               if (elem->is_node_on_edge(n,e))
02028                                 break;
02029                             }
02030                           libmesh_assert_less (e, elem->n_edges());
02031 
02032                           // Find the edge end nodes
02033                           Node *e1 = NULL,
02034                             *e2 = NULL;
02035                           for (unsigned int nn = 0; nn != elem->n_nodes(); ++nn)
02036                             {
02037                               if (nn == n)
02038                                 continue;
02039 
02040                               if (elem->is_node_on_edge(nn, e))
02041                                 {
02042                                   if (e1 == NULL)
02043                                     {
02044                                       e1 = elem->get_node(nn);
02045                                     }
02046                                   else
02047                                     {
02048                                       e2 = elem->get_node(nn);
02049                                       break;
02050                                     }
02051                                 }
02052                             }
02053                           libmesh_assert (e1 && e2);
02054 
02055                           // Find all boundary ids that include this
02056                           // edge and have periodic boundary
02057                           // conditions for this variable
02058                           std::set<boundary_id_type> edge_bcids;
02059 
02060                           for (unsigned int new_s = 0; new_s !=
02061                                  elem->n_sides(); ++new_s)
02062                             {
02063                               if (!elem->is_node_on_side(n,new_s))
02064                                 continue;
02065 
02066                               const std::vector<boundary_id_type>& new_bc_ids =
02067                                 mesh.get_boundary_info().boundary_ids (elem, s);
02068                               for (std::vector<boundary_id_type>::const_iterator
02069                                      new_id_it=new_bc_ids.begin(); new_id_it!=new_bc_ids.end(); ++new_id_it)
02070                                 {
02071                                   const boundary_id_type new_boundary_id = *new_id_it;
02072                                   const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id);
02073                                   if (new_periodic && new_periodic->is_my_variable(variable_number))
02074                                     {
02075                                       edge_bcids.insert(new_boundary_id);
02076                                     }
02077                                 }
02078                             }
02079 
02080 
02081                           // See if this edge has neighbors to defer to
02082                           if (primary_boundary_edge_neighbor
02083                               (elem, *e1, *e2, mesh.get_boundary_info(), edge_bcids)
02084                               != elem)
02085                             continue;
02086 
02087                           // Find the complementary boundary id set
02088                           std::set<boundary_id_type> edge_pairedids;
02089                           for (std::set<boundary_id_type>::const_iterator i =
02090                                  edge_bcids.begin(); i != edge_bcids.end(); ++i)
02091                             {
02092                               const boundary_id_type new_boundary_id = *i;
02093                               const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id);
02094                               edge_pairedids.insert(new_periodic->pairedboundary);
02095                             }
02096 
02097                           // What do we want to constrain against?
02098                           const Elem* primary_elem = NULL;
02099                           const Elem* main_neigh = NULL;
02100                           Point main_pt1 = *e1,
02101                             main_pt2 = *e2,
02102                             primary_pt1 = *e1,
02103                             primary_pt2 = *e2;
02104 
02105                           for (std::set<boundary_id_type>::const_iterator i =
02106                                  edge_bcids.begin(); i != edge_bcids.end(); ++i)
02107                             {
02108                               // Find the corresponding periodic edge and
02109                               // its primary neighbor
02110                               const boundary_id_type new_boundary_id = *i;
02111                               const PeriodicBoundaryBase *new_periodic = boundaries.boundary(new_boundary_id);
02112 
02113                               Point neigh_pt1 = new_periodic->get_corresponding_pos(*e1),
02114                                 neigh_pt2 = new_periodic->get_corresponding_pos(*e2);
02115 
02116                               // If the edge is getting constrained
02117                               // to itself by this PBC then we don't
02118                               // generate any constraints
02119                               if (neigh_pt1.absolute_fuzzy_equals
02120                                   (*e1, primary_hmin*TOLERANCE) &&
02121                                   neigh_pt2.absolute_fuzzy_equals
02122                                   (*e2, primary_hmin*TOLERANCE))
02123                                 continue;
02124 
02125                               // Otherwise we'll have a constraint in
02126                               // one direction or another
02127                               if (!primary_elem)
02128                                 primary_elem = elem;
02129 
02130                               const Elem *primary_neigh = primary_boundary_edge_neighbor
02131                                 (neigh, neigh_pt1, neigh_pt2,
02132                                  mesh.get_boundary_info(), edge_pairedids);
02133 
02134                               libmesh_assert(primary_neigh);
02135 
02136                               if (new_boundary_id == boundary_id)
02137                                 {
02138                                   main_neigh = primary_neigh;
02139                                   main_pt1 = neigh_pt1;
02140                                   main_pt2 = neigh_pt2;
02141                                 }
02142 
02143                               // If we have a one-element thick mesh,
02144                               // we'll need to sort our points to get a
02145                               // consistent ordering rule
02146                               //
02147                               // Use >= in this test to make sure that,
02148                               // for angular constraints, no node gets
02149                               // constrained to itself.
02150                               if (primary_neigh == primary_elem)
02151                                 {
02152                                   if (primary_pt1 > primary_pt2)
02153                                     std::swap(primary_pt1, primary_pt2);
02154                                   if (neigh_pt1 > neigh_pt2)
02155                                     std::swap(neigh_pt1, neigh_pt2);
02156 
02157                                   if (neigh_pt2 >= primary_pt2)
02158                                     continue;
02159                                 }
02160 
02161                               // Otherwise:
02162                               // Finer elements will get constrained in
02163                               // terms of coarser ones, not the other way
02164                               // around
02165                               if ((primary_neigh->level() > primary_elem->level()) ||
02166 
02167                                   // For equal-level elements, the one with
02168                                   // higher id gets constrained in terms of
02169                                   // the one with lower id
02170                                   (primary_neigh->level() == primary_elem->level() &&
02171                                    primary_neigh->id() > primary_elem->id()))
02172                                 continue;
02173 
02174                               primary_elem = primary_neigh;
02175                               primary_pt1 = neigh_pt1;
02176                               primary_pt2 = neigh_pt2;
02177                             }
02178 
02179                           if (!primary_elem ||
02180                               primary_elem != main_neigh ||
02181                               primary_pt1 != main_pt1 ||
02182                               primary_pt2 != main_pt2)
02183                             continue;
02184                         }
02185                       else if (elem->is_face(n))
02186                         {
02187                           // If we have a one-element thick mesh,
02188                           // use the ordering of the face node and its
02189                           // periodic counterpart to determine what
02190                           // gets constrained
02191                           if (neigh == elem)
02192                             {
02193                               const Point neigh_pt =
02194                                 periodic->get_corresponding_pos(*my_node);
02195                               if (neigh_pt > *my_node)
02196                                 continue;
02197                             }
02198 
02199                           // Otherwise:
02200                           // Finer elements will get constrained in
02201                           // terms of coarser ones, not the other way
02202                           // around
02203                           if ((neigh->level() > elem->level()) ||
02204 
02205                               // For equal-level elements, the one with
02206                               // higher id gets constrained in terms of
02207                               // the one with lower id
02208                               (neigh->level() == elem->level() &&
02209                                neigh->id() > elem->id()))
02210                             continue;
02211                         }
02212 
02213                       // If we made it here without hitting a continue
02214                       // statement, then we're at a node whose dofs
02215                       // should be constrained by this element's
02216                       // calculations.
02217                       const unsigned int n_comp =
02218                         my_node->n_comp(sys_number, variable_number);
02219 
02220                       for (unsigned int i=0; i != n_comp; ++i)
02221                         my_constrained_dofs.insert
02222                           (my_node->dof_number
02223                            (sys_number, variable_number, i));
02224                     }
02225 
02226                   // FIXME: old code for disambiguating periodic BCs:
02227                   // this is not threadsafe nor safe to run on a
02228                   // non-serialized mesh.
02229                   /*
02230                     std::vector<bool> recursive_constraint(n_side_dofs, false);
02231 
02232                     for (unsigned int is = 0; is != n_side_dofs; ++is)
02233                     {
02234                     const unsigned int i = neigh_side_dofs[is];
02235                     const dof_id_type their_dof_g = neigh_dof_indices[i];
02236                     libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
02237 
02238                     {
02239                     Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
02240 
02241                     if (!dof_map.is_constrained_dof(their_dof_g))
02242                     continue;
02243                     }
02244 
02245                     DofConstraintRow& their_constraint_row =
02246                     constraints[their_dof_g].first;
02247 
02248                     for (unsigned int js = 0; js != n_side_dofs; ++js)
02249                     {
02250                     const unsigned int j = my_side_dofs[js];
02251                     const dof_id_type my_dof_g = my_dof_indices[j];
02252                     libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id);
02253 
02254                     if (their_constraint_row.count(my_dof_g))
02255                     recursive_constraint[js] = true;
02256                     }
02257                     }
02258                   */
02259 
02260                   for (unsigned int js = 0; js != n_side_dofs; ++js)
02261                     {
02262                       // FIXME: old code path
02263                       // if (recursive_constraint[js])
02264                       //  continue;
02265 
02266                       const unsigned int j = my_side_dofs[js];
02267                       const dof_id_type my_dof_g = my_dof_indices[j];
02268                       libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id);
02269 
02270                       // FIXME: new code path
02271                       if (!my_constrained_dofs.count(my_dof_g))
02272                         continue;
02273 
02274                       DofConstraintRow* constraint_row;
02275 
02276                       // we may be running constraint methods concurretly
02277                       // on multiple threads, so we need a lock to
02278                       // ensure that this constraint is "ours"
02279                       {
02280                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
02281 
02282                         if (dof_map.is_constrained_dof(my_dof_g))
02283                           continue;
02284 
02285                         constraint_row = &(constraints[my_dof_g]);
02286                         libmesh_assert(constraint_row->empty());
02287                       }
02288 
02289                       for (unsigned int is = 0; is != n_side_dofs; ++is)
02290                         {
02291                           const unsigned int i = neigh_side_dofs[is];
02292                           const dof_id_type their_dof_g = neigh_dof_indices[i];
02293                           libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
02294 
02295                           // Periodic constraints should never be
02296                           // self-constraints
02297                           // libmesh_assert_not_equal_to (their_dof_g, my_dof_g);
02298 
02299                           const Real their_dof_value = Ue[is](js);
02300 
02301                           if (their_dof_g == my_dof_g)
02302                             {
02303                               libmesh_assert_less (std::abs(their_dof_value-1.), 1.e-5);
02304                               for (unsigned int k = 0; k != n_side_dofs; ++k)
02305                                 libmesh_assert(k == is || std::abs(Ue[k](js)) < 1.e-5);
02306                               continue;
02307                             }
02308 
02309                           if (std::abs(their_dof_value) < 10*TOLERANCE)
02310                             continue;
02311 
02312                           constraint_row->insert(std::make_pair(their_dof_g,
02313                                                                 their_dof_value));
02314                         }
02315                     }
02316                 }
02317               // p refinement constraints:
02318               // constrain dofs shared between
02319               // active elements and neighbors with
02320               // lower polynomial degrees
02321 #ifdef LIBMESH_ENABLE_AMR
02322               const unsigned int min_p_level =
02323                 neigh->min_p_level_by_neighbor(elem, elem->p_level());
02324               if (min_p_level < elem->p_level())
02325                 {
02326                   // Adaptive p refinement of non-hierarchic bases will
02327                   // require more coding
02328                   libmesh_assert(my_fe->is_hierarchic());
02329                   dof_map.constrain_p_dofs(variable_number, elem,
02330                                            s, min_p_level);
02331                 }
02332 #endif // #ifdef LIBMESH_ENABLE_AMR
02333             }
02334         }
02335     }
02336 }
02337 
02338 #endif // LIBMESH_ENABLE_PERIODIC
02339 
02340 // ------------------------------------------------------------
02341 // Explicit instantiations
02342 template class FEGenericBase<Real>;
02343 template class FEGenericBase<RealGradient>;
02344 
02345 } // namespace libMesh