$extrastylesheet
dof_map_constraints.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 // C++ Includes -------------------------------------
00019 #include <set>
00020 #include <algorithm> // for std::count, std::fill
00021 #include <sstream>
00022 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
00023 #include <cmath>
00024 
00025 // Local Includes -----------------------------------
00026 #include "libmesh/boundary_info.h" // needed for dirichlet constraints
00027 #include "libmesh/dense_matrix.h"
00028 #include "libmesh/dense_vector.h"
00029 #include "libmesh/dirichlet_boundaries.h"
00030 #include "libmesh/dof_map.h"
00031 #include "libmesh/elem.h"
00032 #include "libmesh/elem_range.h"
00033 #include "libmesh/fe_base.h"
00034 #include "libmesh/fe_interface.h"
00035 #include "libmesh/fe_type.h"
00036 #include "libmesh/libmesh_logging.h"
00037 #include "libmesh/mesh_base.h"
00038 #include "libmesh/mesh_inserter_iterator.h"
00039 #include "libmesh/numeric_vector.h" // for enforce_constraints_exactly()
00040 #include "libmesh/parallel.h"
00041 #include "libmesh/parallel_algebra.h"
00042 #include "libmesh/parallel_elem.h"
00043 #include "libmesh/parallel_node.h"
00044 #include "libmesh/periodic_boundaries.h"
00045 #include "libmesh/periodic_boundary.h"
00046 #include "libmesh/periodic_boundary_base.h"
00047 #include "libmesh/point_locator_base.h"
00048 #include "libmesh/quadrature.h" // for dirichlet constraints
00049 #include "libmesh/raw_accessor.h"
00050 #include "libmesh/sparse_matrix.h" // needed to constrain adjoint rhs
00051 #include "libmesh/system.h" // needed by enforce_constraints_exactly()
00052 #include "libmesh/threads.h"
00053 #include "libmesh/tensor_tools.h"
00054 
00055 
00056 // Anonymous namespace to hold helper classes
00057 namespace {
00058 
00059 using namespace libMesh;
00060 
00061 class ComputeConstraints
00062 {
00063 public:
00064   ComputeConstraints (DofConstraints &constraints,
00065                       DofMap &dof_map,
00066 #ifdef LIBMESH_ENABLE_PERIODIC
00067                       PeriodicBoundaries &periodic_boundaries,
00068 #endif
00069                       const MeshBase &mesh,
00070                       const unsigned int variable_number) :
00071     _constraints(constraints),
00072     _dof_map(dof_map),
00073 #ifdef LIBMESH_ENABLE_PERIODIC
00074     _periodic_boundaries(periodic_boundaries),
00075 #endif
00076     _mesh(mesh),
00077     _variable_number(variable_number)
00078   {}
00079 
00080   void operator()(const ConstElemRange &range) const
00081   {
00082     const Variable &var_description = _dof_map.variable(_variable_number);
00083 
00084 #ifdef LIBMESH_ENABLE_PERIODIC
00085     UniquePtr<PointLocatorBase> point_locator;
00086     const bool have_periodic_boundaries =
00087       !_periodic_boundaries.empty();
00088     if (have_periodic_boundaries && !range.empty())
00089       point_locator = _mesh.sub_point_locator();
00090 #endif
00091 
00092     for (ConstElemRange::const_iterator it = range.begin(); it!=range.end(); ++it)
00093       if (var_description.active_on_subdomain((*it)->subdomain_id()))
00094         {
00095 #ifdef LIBMESH_ENABLE_AMR
00096           FEInterface::compute_constraints (_constraints,
00097                                             _dof_map,
00098                                             _variable_number,
00099                                             *it);
00100 #endif
00101 #ifdef LIBMESH_ENABLE_PERIODIC
00102           // FIXME: periodic constraints won't work on a non-serial
00103           // mesh unless it's kept ghost elements from opposing
00104           // boundaries!
00105           if (have_periodic_boundaries)
00106             FEInterface::compute_periodic_constraints (_constraints,
00107                                                        _dof_map,
00108                                                        _periodic_boundaries,
00109                                                        _mesh,
00110                                                        point_locator.get(),
00111                                                        _variable_number,
00112                                                        *it);
00113 #endif
00114         }
00115   }
00116 
00117 private:
00118   DofConstraints &_constraints;
00119   DofMap &_dof_map;
00120 #ifdef LIBMESH_ENABLE_PERIODIC
00121   PeriodicBoundaries &_periodic_boundaries;
00122 #endif
00123   const MeshBase &_mesh;
00124   const unsigned int _variable_number;
00125 };
00126 
00127 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
00128 class ComputeNodeConstraints
00129 {
00130 public:
00131   ComputeNodeConstraints (NodeConstraints &node_constraints,
00132                           DofMap &dof_map,
00133 #ifdef LIBMESH_ENABLE_PERIODIC
00134                           PeriodicBoundaries &periodic_boundaries,
00135 #endif
00136                           const MeshBase &mesh) :
00137     _node_constraints(node_constraints),
00138     _dof_map(dof_map),
00139 #ifdef LIBMESH_ENABLE_PERIODIC
00140     _periodic_boundaries(periodic_boundaries),
00141 #endif
00142     _mesh(mesh)
00143   {}
00144 
00145   void operator()(const ConstElemRange &range) const
00146   {
00147 #ifdef LIBMESH_ENABLE_PERIODIC
00148     UniquePtr<PointLocatorBase> point_locator;
00149     bool have_periodic_boundaries = !_periodic_boundaries.empty();
00150     if (have_periodic_boundaries && !range.empty())
00151       point_locator = _mesh.sub_point_locator();
00152 #endif
00153 
00154     for (ConstElemRange::const_iterator it = range.begin(); it!=range.end(); ++it)
00155       {
00156 #ifdef LIBMESH_ENABLE_AMR
00157         FEBase::compute_node_constraints (_node_constraints, *it);
00158 #endif
00159 #ifdef LIBMESH_ENABLE_PERIODIC
00160         // FIXME: periodic constraints won't work on a non-serial
00161         // mesh unless it's kept ghost elements from opposing
00162         // boundaries!
00163         if (have_periodic_boundaries)
00164           FEBase::compute_periodic_node_constraints (_node_constraints,
00165                                                      _periodic_boundaries,
00166                                                      _mesh,
00167                                                      point_locator.get(),
00168                                                      *it);
00169 #endif
00170       }
00171   }
00172 
00173 private:
00174   NodeConstraints &_node_constraints;
00175   DofMap &_dof_map;
00176 #ifdef LIBMESH_ENABLE_PERIODIC
00177   PeriodicBoundaries &_periodic_boundaries;
00178 #endif
00179   const MeshBase &_mesh;
00180 };
00181 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
00182 
00183 
00184 #ifdef LIBMESH_ENABLE_DIRICHLET
00185 
00189 class AddConstraint
00190 {
00191 protected:
00192   DofMap                  &dof_map;
00193 
00194 public:
00195   AddConstraint(DofMap &dof_map_in) : dof_map(dof_map_in) {}
00196 
00197   virtual void operator()(dof_id_type dof_number,
00198                           const DofConstraintRow& constraint_row,
00199                           const Number constraint_rhs) const = 0;
00200 };
00201 
00202 class AddPrimalConstraint : public AddConstraint
00203 {
00204 public:
00205   AddPrimalConstraint(DofMap &dof_map_in) : AddConstraint(dof_map_in) {}
00206 
00207   virtual void operator()(dof_id_type dof_number,
00208                           const DofConstraintRow& constraint_row,
00209                           const Number constraint_rhs) const
00210   {
00211     if (!dof_map.is_constrained_dof(dof_number))
00212       dof_map.add_constraint_row (dof_number, constraint_row,
00213                                   constraint_rhs, true);
00214   }
00215 };
00216 
00217 class AddAdjointConstraint : public AddConstraint
00218 {
00219 private:
00220   const unsigned int qoi_index;
00221 
00222 public:
00223   AddAdjointConstraint(DofMap &dof_map_in, unsigned int qoi_index_in)
00224     : AddConstraint(dof_map_in), qoi_index(qoi_index_in) {}
00225 
00226   virtual void operator()(dof_id_type dof_number,
00227                           const DofConstraintRow& constraint_row,
00228                           const Number constraint_rhs) const
00229   {
00230     dof_map.add_adjoint_constraint_row
00231       (qoi_index, dof_number, constraint_row, constraint_rhs,
00232        true);
00233   }
00234 };
00235 
00236 
00237 
00243 class ConstrainDirichlet
00244 {
00245 private:
00246   DofMap                  &dof_map;
00247   const MeshBase          &mesh;
00248   const Real               time;
00249   const DirichletBoundary  dirichlet;
00250 
00251   const AddConstraint     &add_fn;
00252 
00253   static Number f_component (FunctionBase<Number> *f,
00254                              FEMFunctionBase<Number> *f_fem,
00255                              const FEMContext* c,
00256                              unsigned int i,
00257                              const Point& p,
00258                              Real time)
00259   {
00260     if (f_fem)
00261       {
00262         if (c)
00263           return f_fem->component(*c, i, p, time);
00264         else
00265           return std::numeric_limits<Real>::quiet_NaN();
00266       }
00267     return f->component(i, p, time);
00268   }
00269 
00270   static Gradient g_component (FunctionBase<Gradient> *g,
00271                                FEMFunctionBase<Gradient> *g_fem,
00272                                const FEMContext* c,
00273                                unsigned int i,
00274                                const Point& p,
00275                                Real time)
00276   {
00277     if (g_fem)
00278       {
00279         if (c)
00280           return g_fem->component(*c, i, p, time);
00281         else
00282           return std::numeric_limits<Real>::quiet_NaN();
00283       }
00284     return g->component(i, p, time);
00285   }
00286 
00287   template<typename OutputType>
00288   void apply_dirichlet_impl( const ConstElemRange &range,
00289                              const unsigned int var, const Variable&variable,
00290                              const FEType& fe_type ) const
00291   {
00292     typedef OutputType                                                      OutputShape;
00293     typedef typename TensorTools::IncrementRank<OutputShape>::type          OutputGradient;
00294     //typedef typename TensorTools::IncrementRank<OutputGradient>::type       OutputTensor;
00295     typedef typename TensorTools::MakeNumber<OutputShape>::type             OutputNumber;
00296     typedef typename TensorTools::IncrementRank<OutputNumber>::type         OutputNumberGradient;
00297     //typedef typename TensorTools::IncrementRank<OutputNumberGradient>::type OutputNumberTensor;
00298 
00299     FunctionBase<Number> *f = dirichlet.f.get();
00300     FunctionBase<Gradient> *g = dirichlet.g.get();
00301 
00302     FEMFunctionBase<Number> *f_fem = dirichlet.f_fem.get();
00303     FEMFunctionBase<Gradient> *g_fem = dirichlet.g_fem.get();
00304 
00305     const System *f_system = dirichlet.f_system;
00306 
00307     const std::set<boundary_id_type> &b = dirichlet.b;
00308 
00309     // We need data to project
00310     libmesh_assert(f || f_fem);
00311     libmesh_assert(!(f && f_fem));
00312 
00313     // Iff our data depends on a system, we should have it.
00314     libmesh_assert(!(f && f_system));
00315     libmesh_assert(!(f_fem && !f_system));
00316 
00317     // The element matrix and RHS for projections.
00318     // Note that Ke is always real-valued, whereas
00319     // Fe may be complex valued if complex number
00320     // support is enabled
00321     DenseMatrix<Real> Ke;
00322     DenseVector<Number> Fe;
00323     // The new element coefficients
00324     DenseVector<Number> Ue;
00325 
00326     // The dimensionality of the current mesh
00327     const unsigned int dim = mesh.mesh_dimension();
00328 
00329     // Boundary info for the current mesh
00330     const BoundaryInfo& boundary_info = mesh.get_boundary_info();
00331 
00332     unsigned int n_vec_dim = FEInterface::n_vec_dim(mesh, fe_type);
00333 
00334     const unsigned int var_component =
00335       variable.first_scalar_number();
00336 
00337     // Get FE objects of the appropriate type
00338     UniquePtr<FEGenericBase<OutputType> > fe = FEGenericBase<OutputType>::build(dim, fe_type);
00339 
00340     // Prepare variables for projection
00341     UniquePtr<QBase> qedgerule (fe_type.default_quadrature_rule(1));
00342     UniquePtr<QBase> qsiderule (fe_type.default_quadrature_rule(dim-1));
00343 
00344     // The values of the shape functions at the quadrature
00345     // points
00346     const std::vector<std::vector<OutputShape> >& phi = fe->get_phi();
00347 
00348     // The gradients of the shape functions at the quadrature
00349     // points on the child element.
00350     const std::vector<std::vector<OutputGradient> > *dphi = NULL;
00351 
00352     const FEContinuity cont = fe->get_continuity();
00353 
00354     if (cont == C_ONE)
00355       {
00356         // We'll need gradient data for a C1 projection
00357         libmesh_assert(g || g_fem);
00358 
00359         // We currently demand that either neither nor both function
00360         // object depend on current FEM data.
00361         libmesh_assert(!(g && g_fem));
00362         libmesh_assert(!(f && g_fem));
00363         libmesh_assert(!(f_fem && g));
00364 
00365         const std::vector<std::vector<OutputGradient> >&
00366           ref_dphi = fe->get_dphi();
00367         dphi = &ref_dphi;
00368       }
00369 
00370     // The Jacobian * quadrature weight at the quadrature points
00371     const std::vector<Real>& JxW =
00372       fe->get_JxW();
00373 
00374     // The XYZ locations of the quadrature points
00375     const std::vector<Point>& xyz_values =
00376       fe->get_xyz();
00377 
00378     // The global DOF indices
00379     std::vector<dof_id_type> dof_indices;
00380     // Side/edge local DOF indices
00381     std::vector<unsigned int> side_dofs;
00382 
00383     // If our supplied functions require a FEMContext, and if we have
00384     // an initialized solution to use with that FEMContext, then
00385     // create one
00386     UniquePtr<FEMContext> context;
00387     if (f_fem)
00388       {
00389         libmesh_assert(f_system);
00390         if (f_system->current_local_solution->initialized())
00391           {
00392             context = UniquePtr<FEMContext>(new FEMContext(*f_system));
00393             f_fem->init_context(*context);
00394             if (g_fem)
00395               g_fem->init_context(*context);
00396           }
00397       }
00398 
00399     // Iterate over all the elements in the range
00400     for (ConstElemRange::const_iterator elem_it=range.begin(); elem_it != range.end(); ++elem_it)
00401       {
00402         const Elem* elem = *elem_it;
00403 
00404         // We only calculate Dirichlet constraints on active
00405         // elements
00406         if (!elem->active())
00407           continue;
00408 
00409         // Per-subdomain variables don't need to be projected on
00410         // elements where they're not active
00411         if (!variable.active_on_subdomain(elem->subdomain_id()))
00412           continue;
00413 
00414         // There's a chicken-and-egg problem with FEMFunction-based
00415         // Dirichlet constraints: we can't evaluate the FEMFunction
00416         // until we have an initialized local solution vector, we
00417         // can't initialize local solution vectors until we have a
00418         // send list, and we can't generate a send list until we know
00419         // all our constraints
00420         //
00421         // We don't generate constraints on uninitialized systems;
00422         // currently user code will have to reinit() before any
00423         // FEMFunction-based constraints will be correct.  This should
00424         // be fine, since user code would want to reinit() after
00425         // setting initial conditions anyway.
00426         if (f_system && context.get())
00427           context->pre_fe_reinit(*f_system, elem);
00428 
00429         // Find out which nodes, edges and sides are on a requested
00430         // boundary:
00431         std::vector<bool> is_boundary_node(elem->n_nodes(), false),
00432           is_boundary_edge(elem->n_edges(), false),
00433           is_boundary_side(elem->n_sides(), false);
00434         for (unsigned char s=0; s != elem->n_sides(); ++s)
00435           {
00436             // First see if this side has been requested
00437             const std::vector<boundary_id_type>& bc_ids =
00438               boundary_info.boundary_ids (elem, s);
00439             bool do_this_side = false;
00440             for (std::size_t i=0; i != bc_ids.size(); ++i)
00441               if (b.count(bc_ids[i]))
00442                 {
00443                   do_this_side = true;
00444                   break;
00445                 }
00446             if (!do_this_side)
00447               continue;
00448 
00449             is_boundary_side[s] = true;
00450 
00451             // Then see what nodes and what edges are on it
00452             for (unsigned int n=0; n != elem->n_nodes(); ++n)
00453               if (elem->is_node_on_side(n,s))
00454                 is_boundary_node[n] = true;
00455             for (unsigned int e=0; e != elem->n_edges(); ++e)
00456               if (elem->is_edge_on_side(e,s))
00457                 is_boundary_edge[e] = true;
00458           }
00459 
00460         // We can also impose Dirichlet boundary conditions on nodes, so we should
00461         // also independently check whether the nodes have been requested
00462         for (unsigned int n=0; n != elem->n_nodes(); ++n)
00463           {
00464             const std::vector<boundary_id_type>& bc_ids =
00465               boundary_info.boundary_ids (elem->get_node(n));
00466 
00467             for (std::size_t i=0; i != bc_ids.size(); ++i)
00468               if (b.count(bc_ids[i]))
00469                 is_boundary_node[n] = true;
00470           }
00471 
00472         // We can also impose Dirichlet boundary conditions on edges, so we should
00473         // also independently check whether the edges have been requested
00474         for (unsigned short e=0; e != elem->n_edges(); ++e)
00475           {
00476             const std::vector<boundary_id_type>& bc_ids =
00477               boundary_info.edge_boundary_ids (elem, e);
00478 
00479             for (std::size_t i=0; i != bc_ids.size(); ++i)
00480               if (b.count(bc_ids[i]))
00481                 is_boundary_edge[e] = true;
00482           }
00483 
00484         // Update the DOF indices for this element based on
00485         // the current mesh
00486         dof_map.dof_indices (elem, dof_indices, var);
00487 
00488         // The number of DOFs on the element
00489         const unsigned int n_dofs =
00490           cast_int<unsigned int>(dof_indices.size());
00491 
00492         // Fixed vs. free DoFs on edge/face projections
00493         std::vector<char> dof_is_fixed(n_dofs, false); // bools
00494         std::vector<int> free_dof(n_dofs, 0);
00495 
00496         // The element type
00497         const ElemType elem_type = elem->type();
00498 
00499         // The number of nodes on the new element
00500         const unsigned int n_nodes = elem->n_nodes();
00501 
00502         // Zero the interpolated values
00503         Ue.resize (n_dofs); Ue.zero();
00504 
00505         // In general, we need a series of
00506         // projections to ensure a unique and continuous
00507         // solution.  We start by interpolating boundary nodes, then
00508         // hold those fixed and project boundary edges, then hold
00509         // those fixed and project boundary faces,
00510 
00511         // Interpolate node values first
00512         unsigned int current_dof = 0;
00513         for (unsigned int n=0; n!= n_nodes; ++n)
00514           {
00515             // FIXME: this should go through the DofMap,
00516             // not duplicate dof_indices code badly!
00517             const unsigned int nc =
00518               FEInterface::n_dofs_at_node (dim, fe_type, elem_type,
00519                                            n);
00520             if (!elem->is_vertex(n) || !is_boundary_node[n])
00521               {
00522                 current_dof += nc;
00523                 continue;
00524               }
00525             if (cont == DISCONTINUOUS)
00526               {
00527                 libmesh_assert_equal_to (nc, 0);
00528               }
00529             // Assume that C_ZERO elements have a single nodal
00530             // value shape function
00531             else if (cont == C_ZERO)
00532               {
00533                 libmesh_assert_equal_to (nc, n_vec_dim);
00534                 for( unsigned int c = 0; c < n_vec_dim; c++ )
00535                   {
00536                     Ue(current_dof+c) =
00537                       f_component(f, f_fem, context.get(), var_component+c,
00538                                   elem->point(n), time);
00539                     dof_is_fixed[current_dof+c] = true;
00540                   }
00541                 current_dof += n_vec_dim;
00542               }
00543             // The hermite element vertex shape functions are weird
00544             else if (fe_type.family == HERMITE)
00545               {
00546                 Ue(current_dof) =
00547                   f_component(f, f_fem, context.get(), var_component,
00548                               elem->point(n), time);
00549                 dof_is_fixed[current_dof] = true;
00550                 current_dof++;
00551                 Gradient grad =
00552                   g_component(g, g_fem, context.get(), var_component,
00553                               elem->point(n), time);
00554                 // x derivative
00555                 Ue(current_dof) = grad(0);
00556                 dof_is_fixed[current_dof] = true;
00557                 current_dof++;
00558                 if (dim > 1)
00559                   {
00560                     // We'll finite difference mixed derivatives
00561                     Point nxminus = elem->point(n),
00562                       nxplus = elem->point(n);
00563                     nxminus(0) -= TOLERANCE;
00564                     nxplus(0) += TOLERANCE;
00565                     Gradient gxminus =
00566                       g_component(g, g_fem, context.get(), var_component,
00567                                   nxminus, time);
00568                     Gradient gxplus =
00569                       g_component(g, g_fem, context.get(), var_component,
00570                                   nxplus, time);
00571                     // y derivative
00572                     Ue(current_dof) = grad(1);
00573                     dof_is_fixed[current_dof] = true;
00574                     current_dof++;
00575                     // xy derivative
00576                     Ue(current_dof) = (gxplus(1) - gxminus(1))
00577                       / 2. / TOLERANCE;
00578                     dof_is_fixed[current_dof] = true;
00579                     current_dof++;
00580 
00581                     if (dim > 2)
00582                       {
00583                         // z derivative
00584                         Ue(current_dof) = grad(2);
00585                         dof_is_fixed[current_dof] = true;
00586                         current_dof++;
00587                         // xz derivative
00588                         Ue(current_dof) = (gxplus(2) - gxminus(2))
00589                           / 2. / TOLERANCE;
00590                         dof_is_fixed[current_dof] = true;
00591                         current_dof++;
00592                         // We need new points for yz
00593                         Point nyminus = elem->point(n),
00594                           nyplus = elem->point(n);
00595                         nyminus(1) -= TOLERANCE;
00596                         nyplus(1) += TOLERANCE;
00597                         Gradient gyminus =
00598                           g_component(g, g_fem, context.get(), var_component,
00599                                       nyminus, time);
00600                         Gradient gyplus =
00601                           g_component(g, g_fem, context.get(), var_component,
00602                                       nyplus, time);
00603                         // xz derivative
00604                         Ue(current_dof) = (gyplus(2) - gyminus(2))
00605                           / 2. / TOLERANCE;
00606                         dof_is_fixed[current_dof] = true;
00607                         current_dof++;
00608                         // Getting a 2nd order xyz is more tedious
00609                         Point nxmym = elem->point(n),
00610                           nxmyp = elem->point(n),
00611                           nxpym = elem->point(n),
00612                           nxpyp = elem->point(n);
00613                         nxmym(0) -= TOLERANCE;
00614                         nxmym(1) -= TOLERANCE;
00615                         nxmyp(0) -= TOLERANCE;
00616                         nxmyp(1) += TOLERANCE;
00617                         nxpym(0) += TOLERANCE;
00618                         nxpym(1) -= TOLERANCE;
00619                         nxpyp(0) += TOLERANCE;
00620                         nxpyp(1) += TOLERANCE;
00621                         Gradient gxmym =
00622                           g_component(g, g_fem, context.get(), var_component,
00623                                       nxmym, time);
00624                         Gradient gxmyp =
00625                           g_component(g, g_fem, context.get(), var_component,
00626                                       nxmyp, time);
00627                         Gradient gxpym =
00628                           g_component(g, g_fem, context.get(), var_component,
00629                                       nxpym, time);
00630                         Gradient gxpyp =
00631                           g_component(g, g_fem, context.get(), var_component,
00632                                       nxpyp, time);
00633                         Number gxzplus = (gxpyp(2) - gxmyp(2))
00634                           / 2. / TOLERANCE;
00635                         Number gxzminus = (gxpym(2) - gxmym(2))
00636                           / 2. / TOLERANCE;
00637                         // xyz derivative
00638                         Ue(current_dof) = (gxzplus - gxzminus)
00639                           / 2. / TOLERANCE;
00640                         dof_is_fixed[current_dof] = true;
00641                         current_dof++;
00642                       }
00643                   }
00644               }
00645             // Assume that other C_ONE elements have a single nodal
00646             // value shape function and nodal gradient component
00647             // shape functions
00648             else if (cont == C_ONE)
00649               {
00650                 libmesh_assert_equal_to (nc, 1 + dim);
00651                 Ue(current_dof) =
00652                   f_component(f, f_fem, context.get(), var_component,
00653                               elem->point(n), time);
00654                 dof_is_fixed[current_dof] = true;
00655                 current_dof++;
00656                 Gradient grad =
00657                   g_component(g, g_fem, context.get(), var_component,
00658                               elem->point(n), time);
00659                 for (unsigned int i=0; i!= dim; ++i)
00660                   {
00661                     Ue(current_dof) = grad(i);
00662                     dof_is_fixed[current_dof] = true;
00663                     current_dof++;
00664                   }
00665               }
00666             else
00667               libmesh_error_msg("Unknown continuity cont = " << cont);
00668           }
00669 
00670         // In 3D, project any edge values next
00671         if (dim > 2 && cont != DISCONTINUOUS)
00672           for (unsigned int e=0; e != elem->n_edges(); ++e)
00673             {
00674               if (!is_boundary_edge[e])
00675                 continue;
00676 
00677               FEInterface::dofs_on_edge(elem, dim, fe_type, e,
00678                                         side_dofs);
00679 
00680               // Some edge dofs are on nodes and already
00681               // fixed, others are free to calculate
00682               unsigned int free_dofs = 0;
00683               for (unsigned int i=0; i != side_dofs.size(); ++i)
00684                 if (!dof_is_fixed[side_dofs[i]])
00685                   free_dof[free_dofs++] = i;
00686 
00687               // There may be nothing to project
00688               if (!free_dofs)
00689                 continue;
00690 
00691               Ke.resize (free_dofs, free_dofs); Ke.zero();
00692               Fe.resize (free_dofs); Fe.zero();
00693               // The new edge coefficients
00694               DenseVector<Number> Uedge(free_dofs);
00695 
00696               // Initialize FE data on the edge
00697               fe->attach_quadrature_rule (qedgerule.get());
00698               fe->edge_reinit (elem, e);
00699               const unsigned int n_qp = qedgerule->n_points();
00700 
00701               // Loop over the quadrature points
00702               for (unsigned int qp=0; qp<n_qp; qp++)
00703                 {
00704                   // solution at the quadrature point
00705                   OutputNumber fineval = 0;
00706                   libMesh::RawAccessor<OutputNumber> f_accessor( fineval, dim );
00707 
00708                   for( unsigned int c = 0; c < n_vec_dim; c++)
00709                     f_accessor(c) =
00710                       f_component(f, f_fem, context.get(), var_component+c,
00711                                   xyz_values[qp], time);
00712 
00713                   // solution grad at the quadrature point
00714                   OutputNumberGradient finegrad;
00715                   libMesh::RawAccessor<OutputNumberGradient> g_accessor( finegrad, dim );
00716 
00717                   unsigned int g_rank;
00718                   switch( FEInterface::field_type( fe_type ) )
00719                     {
00720                     case TYPE_SCALAR:
00721                       {
00722                         g_rank = 1;
00723                         break;
00724                       }
00725                     case TYPE_VECTOR:
00726                       {
00727                         g_rank = 2;
00728                         break;
00729                       }
00730                     default:
00731                       libmesh_error_msg("Unknown field type!");
00732                     }
00733 
00734                   if (cont == C_ONE)
00735                     for( unsigned int c = 0; c < n_vec_dim; c++)
00736                       for( unsigned int d = 0; d < g_rank; d++ )
00737                         g_accessor(c + d*dim ) =
00738                           g_component(g, g_fem, context.get(), var_component,
00739                                       xyz_values[qp], time)(c);
00740 
00741                   // Form edge projection matrix
00742                   for (unsigned int sidei=0, freei=0;
00743                        sidei != side_dofs.size(); ++sidei)
00744                     {
00745                       unsigned int i = side_dofs[sidei];
00746                       // fixed DoFs aren't test functions
00747                       if (dof_is_fixed[i])
00748                         continue;
00749                       for (unsigned int sidej=0, freej=0;
00750                            sidej != side_dofs.size(); ++sidej)
00751                         {
00752                           unsigned int j = side_dofs[sidej];
00753                           if (dof_is_fixed[j])
00754                             Fe(freei) -= phi[i][qp] * phi[j][qp] *
00755                               JxW[qp] * Ue(j);
00756                           else
00757                             Ke(freei,freej) += phi[i][qp] *
00758                               phi[j][qp] * JxW[qp];
00759                           if (cont == C_ONE)
00760                             {
00761                               if (dof_is_fixed[j])
00762                                 Fe(freei) -= ((*dphi)[i][qp].contract((*dphi)[j][qp]) ) *
00763                                   JxW[qp] * Ue(j);
00764                               else
00765                                 Ke(freei,freej) += ((*dphi)[i][qp].contract((*dphi)[j][qp]))
00766                                   * JxW[qp];
00767                             }
00768                           if (!dof_is_fixed[j])
00769                             freej++;
00770                         }
00771                       Fe(freei) += phi[i][qp] * fineval * JxW[qp];
00772                       if (cont == C_ONE)
00773                         Fe(freei) += (finegrad.contract( (*dphi)[i][qp]) ) *
00774                           JxW[qp];
00775                       freei++;
00776                     }
00777                 }
00778 
00779               Ke.cholesky_solve(Fe, Uedge);
00780 
00781               // Transfer new edge solutions to element
00782               for (unsigned int i=0; i != free_dofs; ++i)
00783                 {
00784                   Number &ui = Ue(side_dofs[free_dof[i]]);
00785                   libmesh_assert(std::abs(ui) < TOLERANCE ||
00786                                  std::abs(ui - Uedge(i)) < TOLERANCE);
00787                   ui = Uedge(i);
00788                   dof_is_fixed[side_dofs[free_dof[i]]] = true;
00789                 }
00790             }
00791 
00792         // Project any side values (edges in 2D, faces in 3D)
00793         if (dim > 1 && cont != DISCONTINUOUS)
00794           for (unsigned int s=0; s != elem->n_sides(); ++s)
00795             {
00796               if (!is_boundary_side[s])
00797                 continue;
00798 
00799               FEInterface::dofs_on_side(elem, dim, fe_type, s,
00800                                         side_dofs);
00801 
00802               // Some side dofs are on nodes/edges and already
00803               // fixed, others are free to calculate
00804               unsigned int free_dofs = 0;
00805               for (unsigned int i=0; i != side_dofs.size(); ++i)
00806                 if (!dof_is_fixed[side_dofs[i]])
00807                   free_dof[free_dofs++] = i;
00808 
00809               // There may be nothing to project
00810               if (!free_dofs)
00811                 continue;
00812 
00813               Ke.resize (free_dofs, free_dofs); Ke.zero();
00814               Fe.resize (free_dofs); Fe.zero();
00815               // The new side coefficients
00816               DenseVector<Number> Uside(free_dofs);
00817 
00818               // Initialize FE data on the side
00819               fe->attach_quadrature_rule (qsiderule.get());
00820               fe->reinit (elem, s);
00821               const unsigned int n_qp = qsiderule->n_points();
00822 
00823               // Loop over the quadrature points
00824               for (unsigned int qp=0; qp<n_qp; qp++)
00825                 {
00826                   // solution at the quadrature point
00827                   OutputNumber fineval = 0;
00828                   libMesh::RawAccessor<OutputNumber> f_accessor( fineval, dim );
00829 
00830                   for( unsigned int c = 0; c < n_vec_dim; c++)
00831                     f_accessor(c) =
00832                       f_component(f, f_fem, context.get(), var_component+c,
00833                                   xyz_values[qp], time);
00834 
00835                   // solution grad at the quadrature point
00836                   OutputNumberGradient finegrad;
00837                   libMesh::RawAccessor<OutputNumberGradient> g_accessor( finegrad, dim );
00838 
00839                   unsigned int g_rank;
00840                   switch( FEInterface::field_type( fe_type ) )
00841                     {
00842                     case TYPE_SCALAR:
00843                       {
00844                         g_rank = 1;
00845                         break;
00846                       }
00847                     case TYPE_VECTOR:
00848                       {
00849                         g_rank = 2;
00850                         break;
00851                       }
00852                     default:
00853                       libmesh_error_msg("Unknown field type!");
00854                     }
00855 
00856                   if (cont == C_ONE)
00857                     for( unsigned int c = 0; c < n_vec_dim; c++)
00858                       for( unsigned int d = 0; d < g_rank; d++ )
00859                         g_accessor(c + d*dim ) =
00860                           g_component(g, g_fem, context.get(), var_component,
00861                                       xyz_values[qp], time)(c);
00862 
00863                   // Form side projection matrix
00864                   for (unsigned int sidei=0, freei=0;
00865                        sidei != side_dofs.size(); ++sidei)
00866                     {
00867                       unsigned int i = side_dofs[sidei];
00868                       // fixed DoFs aren't test functions
00869                       if (dof_is_fixed[i])
00870                         continue;
00871                       for (unsigned int sidej=0, freej=0;
00872                            sidej != side_dofs.size(); ++sidej)
00873                         {
00874                           unsigned int j = side_dofs[sidej];
00875                           if (dof_is_fixed[j])
00876                             Fe(freei) -= phi[i][qp] * phi[j][qp] *
00877                               JxW[qp] * Ue(j);
00878                           else
00879                             Ke(freei,freej) += phi[i][qp] *
00880                               phi[j][qp] * JxW[qp];
00881                           if (cont == C_ONE)
00882                             {
00883                               if (dof_is_fixed[j])
00884                                 Fe(freei) -= ((*dphi)[i][qp].contract((*dphi)[j][qp])) *
00885                                   JxW[qp] * Ue(j);
00886                               else
00887                                 Ke(freei,freej) += ((*dphi)[i][qp].contract((*dphi)[j][qp]))
00888                                   * JxW[qp];
00889                             }
00890                           if (!dof_is_fixed[j])
00891                             freej++;
00892                         }
00893                       Fe(freei) += (fineval * phi[i][qp]) * JxW[qp];
00894                       if (cont == C_ONE)
00895                         Fe(freei) += (finegrad.contract((*dphi)[i][qp])) *
00896                           JxW[qp];
00897                       freei++;
00898                     }
00899                 }
00900 
00901               Ke.cholesky_solve(Fe, Uside);
00902 
00903               // Transfer new side solutions to element
00904               for (unsigned int i=0; i != free_dofs; ++i)
00905                 {
00906                   Number &ui = Ue(side_dofs[free_dof[i]]);
00907                   libmesh_assert(std::abs(ui) < TOLERANCE ||
00908                                  std::abs(ui - Uside(i)) < TOLERANCE);
00909                   ui = Uside(i);
00910                   dof_is_fixed[side_dofs[free_dof[i]]] = true;
00911                 }
00912             }
00913 
00914         // Lock the DofConstraints since it is shared among threads.
00915         {
00916           Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
00917 
00918           for (unsigned int i = 0; i < n_dofs; i++)
00919             {
00920               DofConstraintRow empty_row;
00921               if (dof_is_fixed[i] && !libmesh_isnan(Ue(i)))
00922                 add_fn (dof_indices[i], empty_row, Ue(i));
00923             }
00924         }
00925       }
00926 
00927   } // apply_dirichlet_impl
00928 
00929 public:
00930   ConstrainDirichlet (DofMap &dof_map_in,
00931                       const MeshBase &mesh_in,
00932                       const Real time_in,
00933                       const DirichletBoundary &dirichlet_in,
00934                       const AddConstraint& add_in) :
00935     dof_map(dof_map_in),
00936     mesh(mesh_in),
00937     time(time_in),
00938     dirichlet(dirichlet_in),
00939     add_fn(add_in) { }
00940 
00941   ConstrainDirichlet (const ConstrainDirichlet &in) :
00942     dof_map(in.dof_map),
00943     mesh(in.mesh),
00944     time(in.time),
00945     dirichlet(in.dirichlet),
00946     add_fn(in.add_fn) { }
00947 
00948   void operator()(const ConstElemRange &range) const
00949   {
00956     // Loop over all the variables we've been requested to project
00957     for (unsigned int v=0; v!=dirichlet.variables.size(); v++)
00958       {
00959         const unsigned int var = dirichlet.variables[v];
00960 
00961         const Variable& variable = dof_map.variable(var);
00962 
00963         const FEType& fe_type = variable.type();
00964 
00965         if (fe_type.family == SCALAR)
00966           continue;
00967 
00968         switch( FEInterface::field_type( fe_type ) )
00969           {
00970           case TYPE_SCALAR:
00971             {
00972               this->apply_dirichlet_impl<Real>( range, var, variable, fe_type );
00973               break;
00974             }
00975           case TYPE_VECTOR:
00976             {
00977               this->apply_dirichlet_impl<RealGradient>( range, var, variable, fe_type );
00978               break;
00979             }
00980           default:
00981             libmesh_error_msg("Unknown field type!");
00982           }
00983 
00984       }
00985   }
00986 
00987 }; // class ConstrainDirichlet
00988 
00989 
00990 #endif // LIBMESH_ENABLE_DIRICHLET
00991 
00992 
00993 } // anonymous namespace
00994 
00995 
00996 
00997 namespace libMesh
00998 {
00999 
01000 // ------------------------------------------------------------
01001 // DofMap member functions
01002 
01003 #ifdef LIBMESH_ENABLE_CONSTRAINTS
01004 
01005 
01006 dof_id_type DofMap::n_constrained_dofs() const
01007 {
01008   parallel_object_only();
01009 
01010   dof_id_type nc_dofs = this->n_local_constrained_dofs();
01011   this->comm().sum(nc_dofs);
01012   return nc_dofs;
01013 }
01014 
01015 
01016 dof_id_type DofMap::n_local_constrained_dofs() const
01017 {
01018   const DofConstraints::const_iterator lower =
01019     _dof_constraints.lower_bound(this->first_dof()),
01020     upper =
01021     _dof_constraints.upper_bound(this->end_dof()-1);
01022 
01023   return cast_int<dof_id_type>(std::distance(lower, upper));
01024 }
01025 
01026 
01027 
01028 void DofMap::create_dof_constraints(const MeshBase& mesh, Real time)
01029 {
01030   parallel_object_only();
01031 
01032   START_LOG("create_dof_constraints()", "DofMap");
01033 
01034   libmesh_assert (mesh.is_prepared());
01035 
01036   // We might get constraint equations from AMR hanging nodes in 2D/3D
01037   // or from boundary conditions in any dimension
01038   const bool possible_local_constraints = false
01039 #ifdef LIBMESH_ENABLE_AMR
01040     || mesh.mesh_dimension() > 1
01041 #endif
01042 #ifdef LIBMESH_ENABLE_PERIODIC
01043     || !_periodic_boundaries->empty()
01044 #endif
01045 #ifdef LIBMESH_ENABLE_DIRICHLET
01046     || !_dirichlet_boundaries->empty()
01047 #endif
01048     ;
01049 
01050   // Even if we don't have constraints, another processor might.
01051   bool possible_global_constraints = possible_local_constraints;
01052 #if defined(LIBMESH_ENABLE_PERIODIC) || defined(LIBMESH_ENABLE_DIRICHLET) || defined(LIBMESH_ENABLE_AMR)
01053   libmesh_assert(this->comm().verify(mesh.is_serial()));
01054 
01055   this->comm().max(possible_global_constraints);
01056 #endif
01057 
01058   if (!possible_global_constraints)
01059     {
01060       // Clear out any old constraints; maybe the user just deleted
01061       // their last remaining dirichlet/periodic/user constraint?
01062 #ifdef LIBMESH_ENABLE_CONSTRAINTS
01063       _dof_constraints.clear();
01064       _stashed_dof_constraints.clear();
01065       _primal_constraint_values.clear();
01066       _adjoint_constraint_values.clear();
01067 #endif
01068 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
01069       _node_constraints.clear();
01070 #endif
01071 
01072       // make sure we stop logging though
01073       STOP_LOG("create_dof_constraints()", "DofMap");
01074       return;
01075     }
01076 
01077   // Here we build the hanging node constraints.  This is done
01078   // by enforcing the condition u_a = u_b along hanging sides.
01079   // u_a = u_b is collocated at the nodes of side a, which gives
01080   // one row of the constraint matrix.
01081 
01082   // Processors only compute their local constraints
01083   ConstElemRange range (mesh.local_elements_begin(),
01084                         mesh.local_elements_end());
01085 
01086   // Global computation fails if we're using a FEMFunctionBase BC on a
01087   // SerialMesh in parallel
01088   // ConstElemRange range (mesh.elements_begin(),
01089   //                       mesh.elements_end());
01090 
01091   // compute_periodic_constraints requires a point_locator() from our
01092   // Mesh, but point_locator() construction is parallel and threaded.
01093   // Rather than nest threads within threads we'll make sure it's
01094   // preconstructed.
01095 #ifdef LIBMESH_ENABLE_PERIODIC
01096   bool need_point_locator = !_periodic_boundaries->empty() && !range.empty();
01097 
01098   this->comm().max(need_point_locator);
01099 
01100   if (need_point_locator)
01101     mesh.sub_point_locator();
01102 #endif
01103 
01104 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
01105   // recalculate node constraints from scratch
01106   _node_constraints.clear();
01107 
01108   Threads::parallel_for (range,
01109                          ComputeNodeConstraints (_node_constraints,
01110                                                  *this,
01111 #ifdef LIBMESH_ENABLE_PERIODIC
01112                                                  *_periodic_boundaries,
01113 #endif
01114                                                  mesh));
01115 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
01116 
01117 
01118   // recalculate dof constraints from scratch
01119   _dof_constraints.clear();
01120   _stashed_dof_constraints.clear();
01121   _primal_constraint_values.clear();
01122   _adjoint_constraint_values.clear();
01123 
01124   // Look at all the variables in the system.  Reset the element
01125   // range at each iteration -- there is no need to reconstruct it.
01126   for (unsigned int variable_number=0; variable_number<this->n_variables();
01127        ++variable_number, range.reset())
01128     Threads::parallel_for (range,
01129                            ComputeConstraints (_dof_constraints,
01130                                                *this,
01131 #ifdef LIBMESH_ENABLE_PERIODIC
01132                                                *_periodic_boundaries,
01133 #endif
01134                                                mesh,
01135                                                variable_number));
01136 
01137 #ifdef LIBMESH_ENABLE_DIRICHLET
01138   for (DirichletBoundaries::iterator
01139          i = _dirichlet_boundaries->begin();
01140        i != _dirichlet_boundaries->end(); ++i, range.reset())
01141     {
01142       Threads::parallel_for
01143         (range,
01144          ConstrainDirichlet(*this, mesh, time, **i,
01145                             AddPrimalConstraint(*this))
01146          );
01147     }
01148 
01149   for (unsigned int qoi_index = 0;
01150        qoi_index != _adjoint_dirichlet_boundaries.size();
01151        ++qoi_index)
01152     {
01153       for (DirichletBoundaries::iterator
01154              i = _adjoint_dirichlet_boundaries[qoi_index]->begin();
01155            i != _adjoint_dirichlet_boundaries[qoi_index]->end();
01156            ++i, range.reset())
01157         {
01158           Threads::parallel_for
01159             (range,
01160              ConstrainDirichlet(*this, mesh, time, **i,
01161                                 AddAdjointConstraint(*this, qoi_index))
01162              );
01163         }
01164     }
01165 
01166 #endif // LIBMESH_ENABLE_DIRICHLET
01167 
01168   STOP_LOG("create_dof_constraints()", "DofMap");
01169 }
01170 
01171 
01172 
01173 void DofMap::add_constraint_row (const dof_id_type dof_number,
01174                                  const DofConstraintRow& constraint_row,
01175                                  const Number constraint_rhs,
01176                                  const bool forbid_constraint_overwrite)
01177 {
01178   // Optionally allow the user to overwrite constraints.  Defaults to false.
01179   if (forbid_constraint_overwrite)
01180     if (this->is_constrained_dof(dof_number))
01181       libmesh_error_msg("ERROR: DOF " << dof_number << " was already constrained!");
01182 
01183   _dof_constraints.insert(std::make_pair(dof_number, constraint_row));
01184   _primal_constraint_values.insert(std::make_pair(dof_number, constraint_rhs));
01185 }
01186 
01187 
01188 void DofMap::add_adjoint_constraint_row (const unsigned int qoi_index,
01189                                          const dof_id_type dof_number,
01190                                          const DofConstraintRow& /*constraint_row*/,
01191                                          const Number constraint_rhs,
01192                                          const bool forbid_constraint_overwrite)
01193 {
01194   // Optionally allow the user to overwrite constraints.  Defaults to false.
01195   if (forbid_constraint_overwrite)
01196     {
01197       if (!this->is_constrained_dof(dof_number))
01198         libmesh_error_msg("ERROR: DOF " << dof_number << " has no corresponding primal constraint!");
01199 #ifndef NDEBUG
01200       // No way to do this without a non-normalized tolerance?
01201       /*
01202       // If the user passed in more than just the rhs, let's check the
01203       // coefficients for consistency
01204       if (!constraint_row.empty())
01205       {
01206       DofConstraintRow row = _dof_constraints[dof_number];
01207       for (DofConstraintRow::const_iterator pos=row.begin();
01208       pos != row.end(); ++pos)
01209       {
01210       libmesh_assert(constraint_row.find(pos->first)->second
01211       == pos->second);
01212       }
01213       }
01214 
01215       if (_adjoint_constraint_values[qoi_index].find(dof_number) !=
01216       _adjoint_constraint_values[qoi_index].end())
01217       libmesh_assert_equal_to
01218       (_adjoint_constraint_values[qoi_index][dof_number],
01219       constraint_rhs);
01220       */
01221 #endif
01222     }
01223 
01224   // Creates the map of rhs values if it doesn't already exist; then
01225   // adds the current value to that map
01226   _adjoint_constraint_values[qoi_index].insert(std::make_pair(dof_number, constraint_rhs));
01227 }
01228 
01229 
01230 
01231 
01232 void DofMap::print_dof_constraints(std::ostream& os,
01233                                    bool print_nonlocal) const
01234 {
01235   parallel_object_only();
01236 
01237   std::string local_constraints =
01238     this->get_local_constraints(print_nonlocal);
01239 
01240   if (this->processor_id())
01241     {
01242       this->comm().send(0, local_constraints);
01243     }
01244   else
01245     {
01246       os << "Processor 0:\n";
01247       os << local_constraints;
01248 
01249       for (processor_id_type i=1; i<this->n_processors(); ++i)
01250         {
01251           this->comm().receive(i, local_constraints);
01252           os << "Processor " << i << ":\n";
01253           os << local_constraints;
01254         }
01255     }
01256 }
01257 
01258 std::string DofMap::get_local_constraints(bool print_nonlocal) const
01259 {
01260   std::ostringstream os;
01261 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
01262   if (print_nonlocal)
01263     os << "All ";
01264   else
01265     os << "Local ";
01266 
01267   os << "Node Constraints:"
01268      << std::endl;
01269 
01270   for (NodeConstraints::const_iterator it=_node_constraints.begin();
01271        it != _node_constraints.end(); ++it)
01272     {
01273       const Node *node = it->first;
01274 
01275       // Skip non-local nodes if requested
01276       if (!print_nonlocal &&
01277           node->processor_id() != this->processor_id())
01278         continue;
01279 
01280       const NodeConstraintRow& row = it->second.first;
01281       const Point& offset = it->second.second;
01282 
01283       os << "Constraints for Node id " << node->id()
01284          << ": \t";
01285 
01286       for (NodeConstraintRow::const_iterator pos=row.begin();
01287            pos != row.end(); ++pos)
01288         os << " (" << pos->first->id() << ","
01289            << pos->second << ")\t";
01290 
01291       os << "rhs: " << offset;
01292 
01293       os << std::endl;
01294     }
01295 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
01296 
01297   if (print_nonlocal)
01298     os << "All ";
01299   else
01300     os << "Local ";
01301 
01302   os << "DoF Constraints:"
01303      << std::endl;
01304 
01305   for (DofConstraints::const_iterator it=_dof_constraints.begin();
01306        it != _dof_constraints.end(); ++it)
01307     {
01308       const dof_id_type i = it->first;
01309 
01310       // Skip non-local dofs if requested
01311       if (!print_nonlocal &&
01312           ((i < this->first_dof()) ||
01313            (i >= this->end_dof())))
01314         continue;
01315 
01316       const DofConstraintRow& row = it->second;
01317       DofConstraintValueMap::const_iterator rhsit =
01318         _primal_constraint_values.find(i);
01319       const Number rhs = (rhsit == _primal_constraint_values.end()) ?
01320         0 : rhsit->second;
01321 
01322       os << "Constraints for DoF " << i
01323          << ": \t";
01324 
01325       for (DofConstraintRow::const_iterator pos=row.begin();
01326            pos != row.end(); ++pos)
01327         os << " (" << pos->first << ","
01328            << pos->second << ")\t";
01329 
01330       os << "rhs: " << rhs;
01331 
01332       os << std::endl;
01333     }
01334 
01335   for (unsigned int qoi_index = 0;
01336        qoi_index != _adjoint_dirichlet_boundaries.size();
01337        ++qoi_index)
01338     {
01339       os << "Adjoint " << qoi_index << " DoF rhs values:"
01340          << std::endl;
01341 
01342       AdjointDofConstraintValues::const_iterator adjoint_map_it =
01343         _adjoint_constraint_values.find(qoi_index);
01344 
01345       if (adjoint_map_it != _adjoint_constraint_values.end())
01346         for (DofConstraintValueMap::const_iterator
01347                it=adjoint_map_it->second.begin();
01348              it != adjoint_map_it->second.end(); ++it)
01349           {
01350             const dof_id_type i = it->first;
01351 
01352             // Skip non-local dofs if requested
01353             if (!print_nonlocal &&
01354                 ((i < this->first_dof()) ||
01355                  (i >= this->end_dof())))
01356               continue;
01357 
01358             const Number rhs = it->second;
01359 
01360             os << "RHS for DoF " << i
01361                << ": " << rhs;
01362 
01363             os << std::endl;
01364           }
01365     }
01366 
01367   return os.str();
01368 }
01369 
01370 
01371 
01372 void DofMap::constrain_element_matrix (DenseMatrix<Number>& matrix,
01373                                        std::vector<dof_id_type>& elem_dofs,
01374                                        bool asymmetric_constraint_rows) const
01375 {
01376   libmesh_assert_equal_to (elem_dofs.size(), matrix.m());
01377   libmesh_assert_equal_to (elem_dofs.size(), matrix.n());
01378 
01379   // check for easy return
01380   if (this->_dof_constraints.empty())
01381     return;
01382 
01383   // The constrained matrix is built up as C^T K C.
01384   DenseMatrix<Number> C;
01385 
01386 
01387   this->build_constraint_matrix (C, elem_dofs);
01388 
01389   START_LOG("constrain_elem_matrix()", "DofMap");
01390 
01391   // It is possible that the matrix is not constrained at all.
01392   if ((C.m() == matrix.m()) &&
01393       (C.n() == elem_dofs.size())) // It the matrix is constrained
01394     {
01395       // Compute the matrix-matrix-matrix product C^T K C
01396       matrix.left_multiply_transpose  (C);
01397       matrix.right_multiply (C);
01398 
01399 
01400       libmesh_assert_equal_to (matrix.m(), matrix.n());
01401       libmesh_assert_equal_to (matrix.m(), elem_dofs.size());
01402       libmesh_assert_equal_to (matrix.n(), elem_dofs.size());
01403 
01404 
01405       for (unsigned int i=0; i<elem_dofs.size(); i++)
01406         // If the DOF is constrained
01407         if (this->is_constrained_dof(elem_dofs[i]))
01408           {
01409             for (unsigned int j=0; j<matrix.n(); j++)
01410               matrix(i,j) = 0.;
01411 
01412             matrix(i,i) = 1.;
01413 
01414             if (asymmetric_constraint_rows)
01415               {
01416                 DofConstraints::const_iterator
01417                   pos = _dof_constraints.find(elem_dofs[i]);
01418 
01419                 libmesh_assert (pos != _dof_constraints.end());
01420 
01421                 const DofConstraintRow& constraint_row = pos->second;
01422 
01423                 // This is an overzealous assertion in the presence of
01424                 // heterogenous constraints: we now can constrain "u_i = c"
01425                 // with no other u_j terms involved.
01426                 //
01427                 // libmesh_assert (!constraint_row.empty());
01428 
01429                 for (DofConstraintRow::const_iterator
01430                        it=constraint_row.begin(); it != constraint_row.end();
01431                      ++it)
01432                   for (unsigned int j=0; j<elem_dofs.size(); j++)
01433                     if (elem_dofs[j] == it->first)
01434                       matrix(i,j) = -it->second;
01435               }
01436           }
01437     } // end if is constrained...
01438 
01439   STOP_LOG("constrain_elem_matrix()", "DofMap");
01440 }
01441 
01442 
01443 
01444 void DofMap::constrain_element_matrix_and_vector (DenseMatrix<Number>& matrix,
01445                                                   DenseVector<Number>& rhs,
01446                                                   std::vector<dof_id_type>& elem_dofs,
01447                                                   bool asymmetric_constraint_rows) const
01448 {
01449   libmesh_assert_equal_to (elem_dofs.size(), matrix.m());
01450   libmesh_assert_equal_to (elem_dofs.size(), matrix.n());
01451   libmesh_assert_equal_to (elem_dofs.size(), rhs.size());
01452 
01453   // check for easy return
01454   if (this->_dof_constraints.empty())
01455     return;
01456 
01457   // The constrained matrix is built up as C^T K C.
01458   // The constrained RHS is built up as C^T F
01459   DenseMatrix<Number> C;
01460 
01461   this->build_constraint_matrix (C, elem_dofs);
01462 
01463   START_LOG("cnstrn_elem_mat_vec()", "DofMap");
01464 
01465   // It is possible that the matrix is not constrained at all.
01466   if ((C.m() == matrix.m()) &&
01467       (C.n() == elem_dofs.size())) // It the matrix is constrained
01468     {
01469       // Compute the matrix-matrix-matrix product C^T K C
01470       matrix.left_multiply_transpose  (C);
01471       matrix.right_multiply (C);
01472 
01473 
01474       libmesh_assert_equal_to (matrix.m(), matrix.n());
01475       libmesh_assert_equal_to (matrix.m(), elem_dofs.size());
01476       libmesh_assert_equal_to (matrix.n(), elem_dofs.size());
01477 
01478 
01479       for (unsigned int i=0; i<elem_dofs.size(); i++)
01480         if (this->is_constrained_dof(elem_dofs[i]))
01481           {
01482             for (unsigned int j=0; j<matrix.n(); j++)
01483               matrix(i,j) = 0.;
01484 
01485             // If the DOF is constrained
01486             matrix(i,i) = 1.;
01487 
01488             // This will put a nonsymmetric entry in the constraint
01489             // row to ensure that the linear system produces the
01490             // correct value for the constrained DOF.
01491             if (asymmetric_constraint_rows)
01492               {
01493                 DofConstraints::const_iterator
01494                   pos = _dof_constraints.find(elem_dofs[i]);
01495 
01496                 libmesh_assert (pos != _dof_constraints.end());
01497 
01498                 const DofConstraintRow& constraint_row = pos->second;
01499 
01500                 // p refinement creates empty constraint rows
01501                 //    libmesh_assert (!constraint_row.empty());
01502 
01503                 for (DofConstraintRow::const_iterator
01504                        it=constraint_row.begin(); it != constraint_row.end();
01505                      ++it)
01506                   for (unsigned int j=0; j<elem_dofs.size(); j++)
01507                     if (elem_dofs[j] == it->first)
01508                       matrix(i,j) = -it->second;
01509               }
01510           }
01511 
01512 
01513       // Compute the matrix-vector product C^T F
01514       DenseVector<Number> old_rhs(rhs);
01515 
01516       // compute matrix/vector product
01517       C.vector_mult_transpose(rhs, old_rhs);
01518     } // end if is constrained...
01519 
01520   STOP_LOG("cnstrn_elem_mat_vec()", "DofMap");
01521 }
01522 
01523 
01524 
01525 void DofMap::heterogenously_constrain_element_matrix_and_vector
01526 (DenseMatrix<Number>& matrix,
01527  DenseVector<Number>& rhs,
01528  std::vector<dof_id_type>& elem_dofs,
01529  bool asymmetric_constraint_rows,
01530  int qoi_index) const
01531 {
01532   libmesh_assert_equal_to (elem_dofs.size(), matrix.m());
01533   libmesh_assert_equal_to (elem_dofs.size(), matrix.n());
01534   libmesh_assert_equal_to (elem_dofs.size(), rhs.size());
01535 
01536   // check for easy return
01537   if (this->_dof_constraints.empty())
01538     return;
01539 
01540   // The constrained matrix is built up as C^T K C.
01541   // The constrained RHS is built up as C^T (F - K H)
01542   DenseMatrix<Number> C;
01543   DenseVector<Number> H;
01544 
01545   this->build_constraint_matrix_and_vector (C, H, elem_dofs, qoi_index);
01546 
01547   START_LOG("hetero_cnstrn_elem_mat_vec()", "DofMap");
01548 
01549   // It is possible that the matrix is not constrained at all.
01550   if ((C.m() == matrix.m()) &&
01551       (C.n() == elem_dofs.size())) // It the matrix is constrained
01552     {
01553       // We may have rhs values to use later
01554       const DofConstraintValueMap *rhs_values = NULL;
01555       if (qoi_index < 0)
01556         rhs_values = &_primal_constraint_values;
01557       else
01558         {
01559           const AdjointDofConstraintValues::const_iterator
01560             it = _adjoint_constraint_values.find(qoi_index);
01561           if (it != _adjoint_constraint_values.end())
01562             rhs_values = &it->second;
01563         }
01564 
01565       // Compute matrix/vector product K H
01566       DenseVector<Number> KH;
01567       matrix.vector_mult(KH, H);
01568 
01569       // Compute the matrix-vector product C^T (F - KH)
01570       DenseVector<Number> F_minus_KH(rhs);
01571       F_minus_KH -= KH;
01572       C.vector_mult_transpose(rhs, F_minus_KH);
01573 
01574       // Compute the matrix-matrix-matrix product C^T K C
01575       matrix.left_multiply_transpose  (C);
01576       matrix.right_multiply (C);
01577 
01578       libmesh_assert_equal_to (matrix.m(), matrix.n());
01579       libmesh_assert_equal_to (matrix.m(), elem_dofs.size());
01580       libmesh_assert_equal_to (matrix.n(), elem_dofs.size());
01581 
01582       for (unsigned int i=0; i<elem_dofs.size(); i++)
01583         {
01584           const dof_id_type dof_id = elem_dofs[i];
01585 
01586           if (this->is_constrained_dof(dof_id))
01587             {
01588               for (unsigned int j=0; j<matrix.n(); j++)
01589                 matrix(i,j) = 0.;
01590 
01591               // If the DOF is constrained
01592               matrix(i,i) = 1.;
01593 
01594               // This will put a nonsymmetric entry in the constraint
01595               // row to ensure that the linear system produces the
01596               // correct value for the constrained DOF.
01597               if (asymmetric_constraint_rows)
01598                 {
01599                   DofConstraints::const_iterator
01600                     pos = _dof_constraints.find(dof_id);
01601 
01602                   libmesh_assert (pos != _dof_constraints.end());
01603 
01604                   const DofConstraintRow& constraint_row = pos->second;
01605 
01606                   for (DofConstraintRow::const_iterator
01607                          it=constraint_row.begin(); it != constraint_row.end();
01608                        ++it)
01609                     for (unsigned int j=0; j<elem_dofs.size(); j++)
01610                       if (elem_dofs[j] == it->first)
01611                         matrix(i,j) = -it->second;
01612 
01613                   if (rhs_values)
01614                     {
01615                       const DofConstraintValueMap::const_iterator valpos =
01616                         rhs_values->find(dof_id);
01617 
01618                       rhs(i) = (valpos == rhs_values->end()) ?
01619                         0 : valpos->second;
01620                     }
01621                 }
01622               else
01623                 rhs(i) = 0.;
01624             }
01625         }
01626 
01627     } // end if is constrained...
01628 
01629   STOP_LOG("hetero_cnstrn_elem_mat_vec()", "DofMap");
01630 }
01631 
01632 
01633 
01634 void DofMap::heterogenously_constrain_element_vector
01635 (const DenseMatrix<Number>& matrix,
01636  DenseVector<Number>& rhs,
01637  std::vector<dof_id_type>& elem_dofs,
01638  bool asymmetric_constraint_rows,
01639  int qoi_index) const
01640 {
01641   libmesh_assert_equal_to (elem_dofs.size(), matrix.m());
01642   libmesh_assert_equal_to (elem_dofs.size(), matrix.n());
01643   libmesh_assert_equal_to (elem_dofs.size(), rhs.size());
01644 
01645   // check for easy return
01646   if (this->_dof_constraints.empty())
01647     return;
01648 
01649   // The constrained matrix is built up as C^T K C.
01650   // The constrained RHS is built up as C^T (F - K H)
01651   DenseMatrix<Number> C;
01652   DenseVector<Number> H;
01653 
01654   this->build_constraint_matrix_and_vector (C, H, elem_dofs, qoi_index);
01655 
01656   START_LOG("hetero_cnstrn_elem_vec()", "DofMap");
01657 
01658   // It is possible that the matrix is not constrained at all.
01659   if ((C.m() == matrix.m()) &&
01660       (C.n() == elem_dofs.size())) // It the matrix is constrained
01661     {
01662       // We may have rhs values to use later
01663       const DofConstraintValueMap *rhs_values = NULL;
01664       if (qoi_index < 0)
01665         rhs_values = &_primal_constraint_values;
01666       else
01667         {
01668           const AdjointDofConstraintValues::const_iterator
01669             it = _adjoint_constraint_values.find(qoi_index);
01670           if (it != _adjoint_constraint_values.end())
01671             rhs_values = &it->second;
01672         }
01673 
01674       // Compute matrix/vector product K H
01675       DenseVector<Number> KH;
01676       matrix.vector_mult(KH, H);
01677 
01678       // Compute the matrix-vector product C^T (F - KH)
01679       DenseVector<Number> F_minus_KH(rhs);
01680       F_minus_KH -= KH;
01681       C.vector_mult_transpose(rhs, F_minus_KH);
01682 
01683       for (unsigned int i=0; i<elem_dofs.size(); i++)
01684         {
01685           const dof_id_type dof_id = elem_dofs[i];
01686 
01687           if (this->is_constrained_dof(dof_id))
01688             {
01689               // This will put a nonsymmetric entry in the constraint
01690               // row to ensure that the linear system produces the
01691               // correct value for the constrained DOF.
01692               if (asymmetric_constraint_rows && rhs_values)
01693                 {
01694                   const DofConstraintValueMap::const_iterator valpos =
01695                     rhs_values->find(dof_id);
01696 
01697                   rhs(i) = (valpos == rhs_values->end()) ?
01698                     0 : valpos->second;
01699                 }
01700               else
01701                 rhs(i) = 0.;
01702             }
01703         }
01704 
01705     } // end if is constrained...
01706 
01707   STOP_LOG("hetero_cnstrn_elem_vec()", "DofMap");
01708 }
01709 
01710 
01711 
01712 
01713 void DofMap::constrain_element_matrix (DenseMatrix<Number>& matrix,
01714                                        std::vector<dof_id_type>& row_dofs,
01715                                        std::vector<dof_id_type>& col_dofs,
01716                                        bool asymmetric_constraint_rows) const
01717 {
01718   libmesh_assert_equal_to (row_dofs.size(), matrix.m());
01719   libmesh_assert_equal_to (col_dofs.size(), matrix.n());
01720 
01721   // check for easy return
01722   if (this->_dof_constraints.empty())
01723     return;
01724 
01725   // The constrained matrix is built up as R^T K C.
01726   DenseMatrix<Number> R;
01727   DenseMatrix<Number> C;
01728 
01729   // Safeguard against the user passing us the same
01730   // object for row_dofs and col_dofs.  If that is done
01731   // the calls to build_matrix would fail
01732   std::vector<dof_id_type> orig_row_dofs(row_dofs);
01733   std::vector<dof_id_type> orig_col_dofs(col_dofs);
01734 
01735   this->build_constraint_matrix (R, orig_row_dofs);
01736   this->build_constraint_matrix (C, orig_col_dofs);
01737 
01738   START_LOG("constrain_elem_matrix()", "DofMap");
01739 
01740   row_dofs = orig_row_dofs;
01741   col_dofs = orig_col_dofs;
01742 
01743 
01744   // It is possible that the matrix is not constrained at all.
01745   if ((R.m() == matrix.m()) &&
01746       (R.n() == row_dofs.size()) &&
01747       (C.m() == matrix.n()) &&
01748       (C.n() == col_dofs.size())) // If the matrix is constrained
01749     {
01750       // K_constrained = R^T K C
01751       matrix.left_multiply_transpose  (R);
01752       matrix.right_multiply (C);
01753 
01754 
01755       libmesh_assert_equal_to (matrix.m(), row_dofs.size());
01756       libmesh_assert_equal_to (matrix.n(), col_dofs.size());
01757 
01758 
01759       for (unsigned int i=0; i<row_dofs.size(); i++)
01760         if (this->is_constrained_dof(row_dofs[i]))
01761           {
01762             for (unsigned int j=0; j<matrix.n(); j++)
01763               {
01764                 if(row_dofs[i] != col_dofs[j])
01765                   matrix(i,j) = 0.;
01766                 else // If the DOF is constrained
01767                   matrix(i,j) = 1.;
01768               }
01769 
01770             if (asymmetric_constraint_rows)
01771               {
01772                 DofConstraints::const_iterator
01773                   pos = _dof_constraints.find(row_dofs[i]);
01774 
01775                 libmesh_assert (pos != _dof_constraints.end());
01776 
01777                 const DofConstraintRow& constraint_row = pos->second;
01778 
01779                 libmesh_assert (!constraint_row.empty());
01780 
01781                 for (DofConstraintRow::const_iterator
01782                        it=constraint_row.begin(); it != constraint_row.end();
01783                      ++it)
01784                   for (unsigned int j=0; j<col_dofs.size(); j++)
01785                     if (col_dofs[j] == it->first)
01786                       matrix(i,j) = -it->second;
01787               }
01788           }
01789     } // end if is constrained...
01790 
01791   STOP_LOG("constrain_elem_matrix()", "DofMap");
01792 }
01793 
01794 
01795 
01796 void DofMap::constrain_element_vector (DenseVector<Number>&       rhs,
01797                                        std::vector<dof_id_type>& row_dofs,
01798                                        bool) const
01799 {
01800   libmesh_assert_equal_to (rhs.size(), row_dofs.size());
01801 
01802   // check for easy return
01803   if (this->_dof_constraints.empty())
01804     return;
01805 
01806   // The constrained RHS is built up as R^T F.
01807   DenseMatrix<Number> R;
01808 
01809   this->build_constraint_matrix (R, row_dofs);
01810 
01811   START_LOG("constrain_elem_vector()", "DofMap");
01812 
01813   // It is possible that the vector is not constrained at all.
01814   if ((R.m() == rhs.size()) &&
01815       (R.n() == row_dofs.size())) // if the RHS is constrained
01816     {
01817       // Compute the matrix-vector product
01818       DenseVector<Number> old_rhs(rhs);
01819       R.vector_mult_transpose(rhs, old_rhs);
01820 
01821       libmesh_assert_equal_to (row_dofs.size(), rhs.size());
01822 
01823       for (unsigned int i=0; i<row_dofs.size(); i++)
01824         if (this->is_constrained_dof(row_dofs[i]))
01825           {
01826             // If the DOF is constrained
01827             libmesh_assert (_dof_constraints.find(row_dofs[i]) != _dof_constraints.end());
01828 
01829             rhs(i) = 0;
01830           }
01831     } // end if the RHS is constrained.
01832 
01833   STOP_LOG("constrain_elem_vector()", "DofMap");
01834 }
01835 
01836 
01837 
01838 void DofMap::constrain_element_dyad_matrix (DenseVector<Number>& v,
01839                                             DenseVector<Number>& w,
01840                                             std::vector<dof_id_type>& row_dofs,
01841                                             bool) const
01842 {
01843   libmesh_assert_equal_to (v.size(), row_dofs.size());
01844   libmesh_assert_equal_to (w.size(), row_dofs.size());
01845 
01846   // check for easy return
01847   if (this->_dof_constraints.empty())
01848     return;
01849 
01850   // The constrained RHS is built up as R^T F.
01851   DenseMatrix<Number> R;
01852 
01853   this->build_constraint_matrix (R, row_dofs);
01854 
01855   START_LOG("cnstrn_elem_dyad_mat()", "DofMap");
01856 
01857   // It is possible that the vector is not constrained at all.
01858   if ((R.m() == v.size()) &&
01859       (R.n() == row_dofs.size())) // if the RHS is constrained
01860     {
01861       // Compute the matrix-vector products
01862       DenseVector<Number> old_v(v);
01863       DenseVector<Number> old_w(w);
01864 
01865       // compute matrix/vector product
01866       R.vector_mult_transpose(v, old_v);
01867       R.vector_mult_transpose(w, old_w);
01868 
01869       libmesh_assert_equal_to (row_dofs.size(), v.size());
01870       libmesh_assert_equal_to (row_dofs.size(), w.size());
01871 
01872       /* Constrain only v, not w.  */
01873 
01874       for (unsigned int i=0; i<row_dofs.size(); i++)
01875         if (this->is_constrained_dof(row_dofs[i]))
01876           {
01877             // If the DOF is constrained
01878             libmesh_assert (_dof_constraints.find(row_dofs[i]) != _dof_constraints.end());
01879 
01880             v(i) = 0;
01881           }
01882     } // end if the RHS is constrained.
01883 
01884   STOP_LOG("cnstrn_elem_dyad_mat()", "DofMap");
01885 }
01886 
01887 
01888 
01889 void DofMap::constrain_nothing (std::vector<dof_id_type>& dofs) const
01890 {
01891   // check for easy return
01892   if (this->_dof_constraints.empty())
01893     return;
01894 
01895   // All the work is done by \p build_constraint_matrix.  We just need
01896   // a dummy matrix.
01897   DenseMatrix<Number> R;
01898   this->build_constraint_matrix (R, dofs);
01899 }
01900 
01901 
01902 
01903 void DofMap::enforce_constraints_exactly (const System &system,
01904                                           NumericVector<Number> *v,
01905                                           bool homogeneous) const
01906 {
01907   parallel_object_only();
01908 
01909   if (!this->n_constrained_dofs())
01910     return;
01911 
01912   START_LOG("enforce_constraints_exactly()","DofMap");
01913 
01914   if (!v)
01915     v = system.solution.get();
01916 
01917   NumericVector<Number> *v_local  = NULL; // will be initialized below
01918   NumericVector<Number> *v_global = NULL; // will be initialized below
01919   UniquePtr<NumericVector<Number> > v_built;
01920   if (v->type() == SERIAL)
01921     {
01922       v_built = NumericVector<Number>::build(this->comm());
01923       v_built->init(this->n_dofs(), this->n_local_dofs(), true, PARALLEL);
01924       v_built->close();
01925 
01926       for (dof_id_type i=v_built->first_local_index();
01927            i<v_built->last_local_index(); i++)
01928         v_built->set(i, (*v)(i));
01929       v_built->close();
01930       v_global = v_built.get();
01931 
01932       v_local = v;
01933       libmesh_assert (v_local->closed());
01934     }
01935   else if (v->type() == PARALLEL)
01936     {
01937       v_built = NumericVector<Number>::build(this->comm());
01938       v_built->init (v->size(), v->size(), true, SERIAL);
01939       v->localize(*v_built);
01940       v_built->close();
01941       v_local = v_built.get();
01942 
01943       v_global = v;
01944     }
01945   else if (v->type() == GHOSTED)
01946     {
01947       v_local = v;
01948       v_global = v;
01949     }
01950   else // unknown v->type()
01951     libmesh_error_msg("ERROR: Unknown v->type() == " << v->type());
01952 
01953   // We should never hit these asserts because we should error-out in
01954   // else clause above.  Just to be sure we don't try to use v_local
01955   // and v_global uninitialized...
01956   libmesh_assert(v_local);
01957   libmesh_assert(v_global);
01958   libmesh_assert_equal_to (this, &(system.get_dof_map()));
01959 
01960   DofConstraints::const_iterator c_it = _dof_constraints.begin();
01961   const DofConstraints::const_iterator c_end = _dof_constraints.end();
01962 
01963   for ( ; c_it != c_end; ++c_it)
01964     {
01965       dof_id_type constrained_dof = c_it->first;
01966       if (constrained_dof < this->first_dof() ||
01967           constrained_dof >= this->end_dof())
01968         continue;
01969 
01970       const DofConstraintRow constraint_row = c_it->second;
01971 
01972       Number exact_value = 0;
01973       if (!homogeneous)
01974         {
01975           DofConstraintValueMap::const_iterator rhsit =
01976             _primal_constraint_values.find(constrained_dof);
01977           if (rhsit != _primal_constraint_values.end())
01978             exact_value = rhsit->second;
01979         }
01980       for (DofConstraintRow::const_iterator
01981              j=constraint_row.begin(); j != constraint_row.end();
01982            ++j)
01983         exact_value += j->second * (*v_local)(j->first);
01984 
01985       v_global->set(constrained_dof, exact_value);
01986     }
01987 
01988   // If the old vector was serial, we probably need to send our values
01989   // to other processors
01990   if (v->type() == SERIAL)
01991     {
01992 #ifndef NDEBUG
01993       v_global->close();
01994 #endif
01995       v_global->localize (*v);
01996     }
01997   v->close();
01998 
01999   STOP_LOG("enforce_constraints_exactly()","DofMap");
02000 }
02001 
02002 
02003 
02004 void DofMap::enforce_adjoint_constraints_exactly
02005 (NumericVector<Number> &v,
02006  unsigned int q) const
02007 {
02008   parallel_object_only();
02009 
02010   if (!this->n_constrained_dofs())
02011     return;
02012 
02013   START_LOG("enforce_adjoint_constraints_exactly()","DofMap");
02014 
02015   NumericVector<Number> *v_local  = NULL; // will be initialized below
02016   NumericVector<Number> *v_global = NULL; // will be initialized below
02017   UniquePtr<NumericVector<Number> > v_built;
02018   if (v.type() == SERIAL)
02019     {
02020       v_built = NumericVector<Number>::build(this->comm());
02021       v_built->init(this->n_dofs(), this->n_local_dofs(), true, PARALLEL);
02022       v_built->close();
02023 
02024       for (dof_id_type i=v_built->first_local_index();
02025            i<v_built->last_local_index(); i++)
02026         v_built->set(i, v(i));
02027       v_built->close();
02028       v_global = v_built.get();
02029 
02030       v_local = &v;
02031       libmesh_assert (v_local->closed());
02032     }
02033   else if (v.type() == PARALLEL)
02034     {
02035       v_built = NumericVector<Number>::build(this->comm());
02036       v_built->init (v.size(), v.size(), true, SERIAL);
02037       v.localize(*v_built);
02038       v_built->close();
02039       v_local = v_built.get();
02040 
02041       v_global = &v;
02042     }
02043   else if (v.type() == GHOSTED)
02044     {
02045       v_local = &v;
02046       v_global = &v;
02047     }
02048   else // unknown v.type()
02049     libmesh_error_msg("ERROR: Unknown v.type() == " << v.type());
02050 
02051   // We should never hit these asserts because we should error-out in
02052   // else clause above.  Just to be sure we don't try to use v_local
02053   // and v_global uninitialized...
02054   libmesh_assert(v_local);
02055   libmesh_assert(v_global);
02056 
02057   // Do we have any non_homogeneous constraints?
02058   const AdjointDofConstraintValues::const_iterator
02059     adjoint_constraint_map_it = _adjoint_constraint_values.find(q);
02060   const DofConstraintValueMap *constraint_map =
02061     (adjoint_constraint_map_it == _adjoint_constraint_values.end()) ?
02062     NULL : &adjoint_constraint_map_it->second;
02063 
02064   DofConstraints::const_iterator c_it = _dof_constraints.begin();
02065   const DofConstraints::const_iterator c_end = _dof_constraints.end();
02066 
02067   for ( ; c_it != c_end; ++c_it)
02068     {
02069       dof_id_type constrained_dof = c_it->first;
02070       if (constrained_dof < this->first_dof() ||
02071           constrained_dof >= this->end_dof())
02072         continue;
02073 
02074       const DofConstraintRow constraint_row = c_it->second;
02075 
02076       Number exact_value = 0;
02077       if (constraint_map)
02078         {
02079           const DofConstraintValueMap::const_iterator
02080             adjoint_constraint_it =
02081             constraint_map->find(constrained_dof);
02082           if (adjoint_constraint_it != constraint_map->end())
02083             exact_value = adjoint_constraint_it->second;
02084         }
02085 
02086       for (DofConstraintRow::const_iterator
02087              j=constraint_row.begin(); j != constraint_row.end();
02088            ++j)
02089         exact_value += j->second * (*v_local)(j->first);
02090 
02091       v_global->set(constrained_dof, exact_value);
02092     }
02093 
02094   // If the old vector was serial, we probably need to send our values
02095   // to other processors
02096   if (v.type() == SERIAL)
02097     {
02098 #ifndef NDEBUG
02099       v_global->close();
02100 #endif
02101       v_global->localize (v);
02102     }
02103   v.close();
02104 
02105   STOP_LOG("enforce_adjoint_constraints_exactly()","DofMap");
02106 }
02107 
02108 
02109 
02110 std::pair<Real, Real>
02111 DofMap::max_constraint_error (const System &system,
02112                               NumericVector<Number> *v) const
02113 {
02114   if (!v)
02115     v = system.solution.get();
02116   NumericVector<Number> &vec = *v;
02117 
02118   // We'll assume the vector is closed
02119   libmesh_assert (vec.closed());
02120 
02121   Real max_absolute_error = 0., max_relative_error = 0.;
02122 
02123   const MeshBase &mesh = system.get_mesh();
02124 
02125   libmesh_assert_equal_to (this, &(system.get_dof_map()));
02126 
02127   // indices on each element
02128   std::vector<dof_id_type> local_dof_indices;
02129 
02130   MeshBase::const_element_iterator       elem_it  =
02131     mesh.active_local_elements_begin();
02132   const MeshBase::const_element_iterator elem_end =
02133     mesh.active_local_elements_end();
02134 
02135   for ( ; elem_it != elem_end; ++elem_it)
02136     {
02137       const Elem* elem = *elem_it;
02138 
02139       this->dof_indices(elem, local_dof_indices);
02140       std::vector<dof_id_type> raw_dof_indices = local_dof_indices;
02141 
02142       // Constraint matrix for each element
02143       DenseMatrix<Number> C;
02144 
02145       this->build_constraint_matrix (C, local_dof_indices);
02146 
02147       // Continue if the element is unconstrained
02148       if (!C.m())
02149         continue;
02150 
02151       libmesh_assert_equal_to (C.m(), raw_dof_indices.size());
02152       libmesh_assert_equal_to (C.n(), local_dof_indices.size());
02153 
02154       for (unsigned int i=0; i!=C.m(); ++i)
02155         {
02156           // Recalculate any constrained dof owned by this processor
02157           dof_id_type global_dof = raw_dof_indices[i];
02158           if (this->is_constrained_dof(global_dof) &&
02159               global_dof >= vec.first_local_index() &&
02160               global_dof < vec.last_local_index())
02161             {
02162               DofConstraints::const_iterator
02163                 pos = _dof_constraints.find(global_dof);
02164 
02165               libmesh_assert (pos != _dof_constraints.end());
02166 
02167               Number exact_value = 0;
02168               DofConstraintValueMap::const_iterator rhsit =
02169                 _primal_constraint_values.find(global_dof);
02170               if (rhsit != _primal_constraint_values.end())
02171                 exact_value = rhsit->second;
02172 
02173               for (unsigned int j=0; j!=C.n(); ++j)
02174                 {
02175                   if (local_dof_indices[j] != global_dof)
02176                     exact_value += C(i,j) *
02177                       vec(local_dof_indices[j]);
02178                 }
02179 
02180               max_absolute_error = std::max(max_absolute_error,
02181                                             std::abs(vec(global_dof) - exact_value));
02182               max_relative_error = std::max(max_relative_error,
02183                                             std::abs(vec(global_dof) - exact_value)
02184                                             / std::abs(exact_value));
02185             }
02186         }
02187     }
02188 
02189   return std::pair<Real, Real>(max_absolute_error, max_relative_error);
02190 }
02191 
02192 
02193 
02194 void DofMap::build_constraint_matrix (DenseMatrix<Number>& C,
02195                                       std::vector<dof_id_type>& elem_dofs,
02196                                       const bool called_recursively) const
02197 {
02198   if (!called_recursively) START_LOG("build_constraint_matrix()", "DofMap");
02199 
02200   // Create a set containing the DOFs we already depend on
02201   typedef std::set<dof_id_type> RCSet;
02202   RCSet dof_set;
02203 
02204   bool we_have_constraints = false;
02205 
02206   // Next insert any other dofs the current dofs might be constrained
02207   // in terms of.  Note that in this case we may not be done: Those
02208   // may in turn depend on others.  So, we need to repeat this process
02209   // in that case until the system depends only on unconstrained
02210   // degrees of freedom.
02211   for (unsigned int i=0; i<elem_dofs.size(); i++)
02212     if (this->is_constrained_dof(elem_dofs[i]))
02213       {
02214         we_have_constraints = true;
02215 
02216         // If the DOF is constrained
02217         DofConstraints::const_iterator
02218           pos = _dof_constraints.find(elem_dofs[i]);
02219 
02220         libmesh_assert (pos != _dof_constraints.end());
02221 
02222         const DofConstraintRow& constraint_row = pos->second;
02223 
02224         // Constraint rows in p refinement may be empty
02225         //libmesh_assert (!constraint_row.empty());
02226 
02227         for (DofConstraintRow::const_iterator
02228                it=constraint_row.begin(); it != constraint_row.end();
02229              ++it)
02230           dof_set.insert (it->first);
02231       }
02232 
02233   // May be safe to return at this point
02234   // (but remember to stop the perflog)
02235   if (!we_have_constraints)
02236     {
02237       STOP_LOG("build_constraint_matrix()", "DofMap");
02238       return;
02239     }
02240 
02241   for (unsigned int i=0; i != elem_dofs.size(); ++i)
02242     dof_set.erase (elem_dofs[i]);
02243 
02244   // If we added any DOFS then we need to do this recursively.
02245   // It is possible that we just added a DOF that is also
02246   // constrained!
02247   //
02248   // Also, we need to handle the special case of an element having DOFs
02249   // constrained in terms of other, local DOFs
02250   if (!dof_set.empty() ||  // case 1: constrained in terms of other DOFs
02251       !called_recursively) // case 2: constrained in terms of our own DOFs
02252     {
02253       const unsigned int old_size =
02254         cast_int<unsigned int>(elem_dofs.size());
02255 
02256       // Add new dependency dofs to the end of the current dof set
02257       elem_dofs.insert(elem_dofs.end(),
02258                        dof_set.begin(), dof_set.end());
02259 
02260       // Now we can build the constraint matrix.
02261       // Note that resize also zeros for a DenseMatrix<Number>.
02262       C.resize (old_size,
02263                 cast_int<unsigned int>(elem_dofs.size()));
02264 
02265       // Create the C constraint matrix.
02266       for (unsigned int i=0; i != old_size; i++)
02267         if (this->is_constrained_dof(elem_dofs[i]))
02268           {
02269             // If the DOF is constrained
02270             DofConstraints::const_iterator
02271               pos = _dof_constraints.find(elem_dofs[i]);
02272 
02273             libmesh_assert (pos != _dof_constraints.end());
02274 
02275             const DofConstraintRow& constraint_row = pos->second;
02276 
02277             // p refinement creates empty constraint rows
02278             //    libmesh_assert (!constraint_row.empty());
02279 
02280             for (DofConstraintRow::const_iterator
02281                    it=constraint_row.begin(); it != constraint_row.end();
02282                  ++it)
02283               for (unsigned int j=0; j != elem_dofs.size(); j++)
02284                 if (elem_dofs[j] == it->first)
02285                   C(i,j) = it->second;
02286           }
02287         else
02288           {
02289             C(i,i) = 1.;
02290           }
02291 
02292       // May need to do this recursively.  It is possible
02293       // that we just replaced a constrained DOF with another
02294       // constrained DOF.
02295       DenseMatrix<Number> Cnew;
02296 
02297       this->build_constraint_matrix (Cnew, elem_dofs, true);
02298 
02299       if ((C.n() == Cnew.m()) &&
02300           (Cnew.n() == elem_dofs.size())) // If the constraint matrix
02301         C.right_multiply(Cnew);           // is constrained...
02302 
02303       libmesh_assert_equal_to (C.n(), elem_dofs.size());
02304     }
02305 
02306   if (!called_recursively) STOP_LOG("build_constraint_matrix()", "DofMap");
02307 }
02308 
02309 
02310 
02311 void DofMap::build_constraint_matrix_and_vector
02312 (DenseMatrix<Number>& C,
02313  DenseVector<Number>& H,
02314  std::vector<dof_id_type>& elem_dofs,
02315  int qoi_index,
02316  const bool called_recursively) const
02317 {
02318   if (!called_recursively)
02319     START_LOG("build_constraint_matrix_and_vector()", "DofMap");
02320 
02321   // Create a set containing the DOFs we already depend on
02322   typedef std::set<dof_id_type> RCSet;
02323   RCSet dof_set;
02324 
02325   bool we_have_constraints = false;
02326 
02327   // Next insert any other dofs the current dofs might be constrained
02328   // in terms of.  Note that in this case we may not be done: Those
02329   // may in turn depend on others.  So, we need to repeat this process
02330   // in that case until the system depends only on unconstrained
02331   // degrees of freedom.
02332   for (unsigned int i=0; i<elem_dofs.size(); i++)
02333     if (this->is_constrained_dof(elem_dofs[i]))
02334       {
02335         we_have_constraints = true;
02336 
02337         // If the DOF is constrained
02338         DofConstraints::const_iterator
02339           pos = _dof_constraints.find(elem_dofs[i]);
02340 
02341         libmesh_assert (pos != _dof_constraints.end());
02342 
02343         const DofConstraintRow& constraint_row = pos->second;
02344 
02345         // Constraint rows in p refinement may be empty
02346         //libmesh_assert (!constraint_row.empty());
02347 
02348         for (DofConstraintRow::const_iterator
02349                it=constraint_row.begin(); it != constraint_row.end();
02350              ++it)
02351           dof_set.insert (it->first);
02352       }
02353 
02354   // May be safe to return at this point
02355   // (but remember to stop the perflog)
02356   if (!we_have_constraints)
02357     {
02358       STOP_LOG("build_constraint_matrix_and_vector()", "DofMap");
02359       return;
02360     }
02361 
02362   for (unsigned int i=0; i != elem_dofs.size(); ++i)
02363     dof_set.erase (elem_dofs[i]);
02364 
02365   // If we added any DOFS then we need to do this recursively.
02366   // It is possible that we just added a DOF that is also
02367   // constrained!
02368   //
02369   // Also, we need to handle the special case of an element having DOFs
02370   // constrained in terms of other, local DOFs
02371   if (!dof_set.empty() ||  // case 1: constrained in terms of other DOFs
02372       !called_recursively) // case 2: constrained in terms of our own DOFs
02373     {
02374       const DofConstraintValueMap *rhs_values = NULL;
02375       if (qoi_index < 0)
02376         rhs_values = &_primal_constraint_values;
02377       else
02378         {
02379           const AdjointDofConstraintValues::const_iterator
02380             it = _adjoint_constraint_values.find(qoi_index);
02381           if (it != _adjoint_constraint_values.end())
02382             rhs_values = &it->second;
02383         }
02384 
02385       const unsigned int old_size =
02386         cast_int<unsigned int>(elem_dofs.size());
02387 
02388       // Add new dependency dofs to the end of the current dof set
02389       elem_dofs.insert(elem_dofs.end(),
02390                        dof_set.begin(), dof_set.end());
02391 
02392       // Now we can build the constraint matrix and vector.
02393       // Note that resize also zeros for a DenseMatrix and DenseVector
02394       C.resize (old_size,
02395                 cast_int<unsigned int>(elem_dofs.size()));
02396       H.resize (old_size);
02397 
02398       // Create the C constraint matrix.
02399       for (unsigned int i=0; i != old_size; i++)
02400         if (this->is_constrained_dof(elem_dofs[i]))
02401           {
02402             // If the DOF is constrained
02403             DofConstraints::const_iterator
02404               pos = _dof_constraints.find(elem_dofs[i]);
02405 
02406             libmesh_assert (pos != _dof_constraints.end());
02407 
02408             const DofConstraintRow& constraint_row = pos->second;
02409 
02410             // p refinement creates empty constraint rows
02411             //    libmesh_assert (!constraint_row.empty());
02412 
02413             for (DofConstraintRow::const_iterator
02414                    it=constraint_row.begin(); it != constraint_row.end();
02415                  ++it)
02416               for (unsigned int j=0; j != elem_dofs.size(); j++)
02417                 if (elem_dofs[j] == it->first)
02418                   C(i,j) = it->second;
02419 
02420             if (rhs_values)
02421               {
02422                 DofConstraintValueMap::const_iterator rhsit =
02423                   rhs_values->find(elem_dofs[i]);
02424                 if (rhsit != rhs_values->end())
02425                   H(i) = rhsit->second;
02426               }
02427           }
02428         else
02429           {
02430             C(i,i) = 1.;
02431           }
02432 
02433       // May need to do this recursively.  It is possible
02434       // that we just replaced a constrained DOF with another
02435       // constrained DOF.
02436       DenseMatrix<Number> Cnew;
02437       DenseVector<Number> Hnew;
02438 
02439       this->build_constraint_matrix_and_vector (Cnew, Hnew, elem_dofs,
02440                                                 qoi_index, true);
02441 
02442       if ((C.n() == Cnew.m()) &&          // If the constraint matrix
02443           (Cnew.n() == elem_dofs.size())) // is constrained...
02444         {
02445           C.right_multiply(Cnew);
02446 
02447           // If x = Cy + h and y = Dz + g
02448           // Then x = (CD)z + (Cg + h)
02449           C.vector_mult_add(H, 1, Hnew);
02450         }
02451 
02452       libmesh_assert_equal_to (C.n(), elem_dofs.size());
02453     }
02454 
02455   if (!called_recursively)
02456     STOP_LOG("build_constraint_matrix_and_vector()", "DofMap");
02457 }
02458 
02459 
02460 void DofMap::allgather_recursive_constraints(MeshBase& mesh)
02461 {
02462   // This function must be run on all processors at once
02463   parallel_object_only();
02464 
02465   // Return immediately if there's nothing to gather
02466   if (this->n_processors() == 1)
02467     return;
02468 
02469   // We might get to return immediately if none of the processors
02470   // found any constraints
02471   unsigned int has_constraints = !_dof_constraints.empty()
02472 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02473     || !_node_constraints.empty()
02474 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
02475     ;
02476   this->comm().max(has_constraints);
02477   if (!has_constraints)
02478     return;
02479 
02480   // If we have heterogenous adjoint constraints we need to
02481   // communicate those too.
02482   const unsigned int max_qoi_num =
02483     _adjoint_constraint_values.empty() ?
02484     0 : _adjoint_constraint_values.rbegin()->first;
02485 
02486   // We might have calculated constraints for constrained dofs
02487   // which have support on other processors.
02488   // Push these out first.
02489   {
02490     std::vector<std::set<dof_id_type> > pushed_ids(this->n_processors());
02491 
02492 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02493     std::vector<std::set<dof_id_type> > pushed_node_ids(this->n_processors());
02494 #endif
02495 
02496     const unsigned int sys_num = this->sys_number();
02497 
02498     MeshBase::element_iterator
02499       foreign_elem_it  = mesh.active_not_local_elements_begin(),
02500       foreign_elem_end = mesh.active_not_local_elements_end();
02501 
02502     // Collect the constraints to push to each processor
02503     for (; foreign_elem_it != foreign_elem_end; ++foreign_elem_it)
02504       {
02505         const Elem *elem = *foreign_elem_it;
02506 
02507         // Just checking dof_indices on the foreign element isn't
02508         // enough.  Consider a central hanging node between a coarse
02509         // Q2/Q1 element and its finer neighbors on a higher-ranked
02510         // processor.  The coarse element's processor will own the node,
02511         // and will thereby own the pressure dof on that node, despite
02512         // the fact that that pressure dof doesn't directly exist on the
02513         // coarse element!
02514         //
02515         // So, we loop through dofs manually.
02516 
02517         {
02518           const unsigned int n_vars = elem->n_vars(sys_num);
02519           for (unsigned int v=0; v != n_vars; ++v)
02520             {
02521               const unsigned int n_comp = elem->n_comp(sys_num,v);
02522               for (unsigned int c=0; c != n_comp; ++c)
02523                 {
02524                   const unsigned int id =
02525                     elem->dof_number(sys_num,v,c);
02526                   if (this->is_constrained_dof(id))
02527                     pushed_ids[elem->processor_id()].insert(id);
02528                 }
02529             }
02530         }
02531 
02532         for (unsigned int n=0; n != elem->n_nodes(); ++n)
02533           {
02534             const Node *node = elem->get_node(n);
02535             const unsigned int n_vars = node->n_vars(sys_num);
02536             for (unsigned int v=0; v != n_vars; ++v)
02537               {
02538                 const unsigned int n_comp = node->n_comp(sys_num,v);
02539                 for (unsigned int c=0; c != n_comp; ++c)
02540                   {
02541                     const unsigned int id =
02542                       node->dof_number(sys_num,v,c);
02543                     if (this->is_constrained_dof(id))
02544                       pushed_ids[elem->processor_id()].insert(id);
02545                   }
02546               }
02547           }
02548 
02549 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02550         for (unsigned int n=0; n != elem->n_nodes(); ++n)
02551           if (this->is_constrained_node(elem->get_node(n)))
02552             pushed_node_ids[elem->processor_id()].insert(elem->node(n));
02553 #endif
02554       }
02555 
02556     // Now trade constraint rows
02557     for (processor_id_type p = 0; p != this->n_processors(); ++p)
02558       {
02559         // Push to processor procup while receiving from procdown
02560         processor_id_type procup =
02561           cast_int<processor_id_type>((this->processor_id() + p) %
02562                                       this->n_processors());
02563         processor_id_type procdown =
02564           cast_int<processor_id_type>((this->n_processors() +
02565                                        this->processor_id() - p) %
02566                                       this->n_processors());
02567 
02568         // Pack the dof constraint rows and rhs's to push to procup
02569         const std::size_t pushed_ids_size = pushed_ids[procup].size();
02570         std::vector<std::vector<dof_id_type> > pushed_keys(pushed_ids_size);
02571         std::vector<std::vector<Real> > pushed_vals(pushed_ids_size);
02572         std::vector<Number> pushed_rhss(pushed_ids_size);
02573 
02574         std::vector<std::vector<Number> >
02575           pushed_adj_rhss(max_qoi_num,
02576                           std::vector<Number>(pushed_ids_size));
02577         std::set<dof_id_type>::const_iterator it = pushed_ids[procup].begin();
02578         for (std::size_t i = 0; it != pushed_ids[procup].end();
02579              ++i, ++it)
02580           {
02581             const dof_id_type pushed_id = *it;
02582             DofConstraintRow &row = _dof_constraints[pushed_id];
02583             std::size_t row_size = row.size();
02584             pushed_keys[i].reserve(row_size);
02585             pushed_vals[i].reserve(row_size);
02586             for (DofConstraintRow::iterator j = row.begin();
02587                  j != row.end(); ++j)
02588               {
02589                 pushed_keys[i].push_back(j->first);
02590                 pushed_vals[i].push_back(j->second);
02591               }
02592 
02593             DofConstraintValueMap::const_iterator rhsit =
02594               _primal_constraint_values.find(pushed_id);
02595             pushed_rhss[i] =
02596               (rhsit == _primal_constraint_values.end()) ?
02597               0 : rhsit->second;
02598 
02599             for (unsigned int q = 0; q != max_qoi_num; ++q)
02600               {
02601                 AdjointDofConstraintValues::const_iterator adjoint_map_it =
02602                   _adjoint_constraint_values.find(q);
02603 
02604                 if (adjoint_map_it == _adjoint_constraint_values.end())
02605                   continue;
02606 
02607                 const DofConstraintValueMap &constraint_map =
02608                   adjoint_map_it->second;
02609 
02610                 DofConstraintValueMap::const_iterator rhsit =
02611                   constraint_map.find(pushed_id);
02612 
02613                 pushed_adj_rhss[q][i] =
02614                   (rhsit == constraint_map.end()) ?
02615                   0 : rhsit->second;
02616               }
02617           }
02618 
02619 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02620         // Pack the node constraint rows to push to procup
02621         const std::size_t pushed_nodes_size = pushed_node_ids[procup].size();
02622         std::vector<std::vector<dof_id_type> > pushed_node_keys(pushed_nodes_size);
02623         std::vector<std::vector<Real> > pushed_node_vals(pushed_nodes_size);
02624         std::vector<Point> pushed_node_offsets(pushed_nodes_size);
02625         std::set<dof_id_type>::const_iterator node_it = pushed_node_ids[procup].begin();
02626         for (std::size_t i = 0; node_it != pushed_node_ids[procup].end();
02627              ++i, ++node_it)
02628           {
02629             const Node *node = mesh.node_ptr(*node_it);
02630             NodeConstraintRow &row = _node_constraints[node].first;
02631             std::size_t row_size = row.size();
02632             pushed_node_keys[i].reserve(row_size);
02633             pushed_node_vals[i].reserve(row_size);
02634             for (NodeConstraintRow::iterator j = row.begin();
02635                  j != row.end(); ++j)
02636               {
02637                 pushed_node_keys[i].push_back(j->first->id());
02638                 pushed_node_vals[i].push_back(j->second);
02639               }
02640             pushed_node_offsets[i] = _node_constraints[node].second;
02641           }
02642 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
02643 
02644         // Trade pushed dof constraint rows
02645         std::vector<dof_id_type> pushed_ids_from_me
02646           (pushed_ids[procup].begin(), pushed_ids[procup].end());
02647         std::vector<dof_id_type> pushed_ids_to_me;
02648         std::vector<std::vector<dof_id_type> > pushed_keys_to_me;
02649         std::vector<std::vector<Real> > pushed_vals_to_me;
02650         std::vector<Number> pushed_rhss_to_me;
02651         std::vector<std::vector<Number> > pushed_adj_rhss_to_me;
02652         this->comm().send_receive(procup, pushed_ids_from_me,
02653                                   procdown, pushed_ids_to_me);
02654         this->comm().send_receive(procup, pushed_keys,
02655                                   procdown, pushed_keys_to_me);
02656         this->comm().send_receive(procup, pushed_vals,
02657                                   procdown, pushed_vals_to_me);
02658         this->comm().send_receive(procup, pushed_rhss,
02659                                   procdown, pushed_rhss_to_me);
02660         this->comm().send_receive(procup, pushed_adj_rhss,
02661                                   procdown, pushed_adj_rhss_to_me);
02662         libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_keys_to_me.size());
02663         libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_vals_to_me.size());
02664         libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_rhss_to_me.size());
02665 
02666 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02667         // Trade pushed node constraint rows
02668         std::vector<dof_id_type> pushed_node_ids_from_me
02669           (pushed_node_ids[procup].begin(), pushed_node_ids[procup].end());
02670         std::vector<dof_id_type> pushed_node_ids_to_me;
02671         std::vector<std::vector<dof_id_type> > pushed_node_keys_to_me;
02672         std::vector<std::vector<Real> > pushed_node_vals_to_me;
02673         std::vector<Point> pushed_node_offsets_to_me;
02674         this->comm().send_receive(procup, pushed_node_ids_from_me,
02675                                   procdown, pushed_node_ids_to_me);
02676         this->comm().send_receive(procup, pushed_node_keys,
02677                                   procdown, pushed_node_keys_to_me);
02678         this->comm().send_receive(procup, pushed_node_vals,
02679                                   procdown, pushed_node_vals_to_me);
02680         this->comm().send_receive(procup, pushed_node_offsets,
02681                                   procdown, pushed_node_offsets_to_me);
02682 
02683         // Note that we aren't doing a send_receive on the Nodes
02684         // themselves.  At this point we should only be pushing out
02685         // "raw" constraints, and there should be no
02686         // constrained-by-constrained-by-etc. situations that could
02687         // involve non-semilocal nodes.
02688 
02689         libmesh_assert_equal_to (pushed_node_ids_to_me.size(), pushed_node_keys_to_me.size());
02690         libmesh_assert_equal_to (pushed_node_ids_to_me.size(), pushed_node_vals_to_me.size());
02691         libmesh_assert_equal_to (pushed_node_ids_to_me.size(), pushed_node_offsets_to_me.size());
02692 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
02693 
02694         // Add the dof constraints that I've been sent
02695         for (std::size_t i = 0; i != pushed_ids_to_me.size(); ++i)
02696           {
02697             libmesh_assert_equal_to (pushed_keys_to_me[i].size(), pushed_vals_to_me[i].size());
02698 
02699             dof_id_type constrained = pushed_ids_to_me[i];
02700 
02701             // If we don't already have a constraint for this dof,
02702             // add the one we were sent
02703             if (!this->is_constrained_dof(constrained))
02704               {
02705                 DofConstraintRow &row = _dof_constraints[constrained];
02706                 for (std::size_t j = 0; j != pushed_keys_to_me[i].size(); ++j)
02707                   {
02708                     row[pushed_keys_to_me[i][j]] = pushed_vals_to_me[i][j];
02709                   }
02710                 if (libmesh_isnan(pushed_rhss_to_me[i]))
02711                   libmesh_assert(pushed_keys_to_me[i].empty());
02712                 if (pushed_rhss_to_me[i] != Number(0))
02713                   _primal_constraint_values[constrained] = pushed_rhss_to_me[i];
02714                 else
02715                   _primal_constraint_values.erase(constrained);
02716 
02717                 for (unsigned int q = 0; q != max_qoi_num; ++q)
02718                   {
02719                     AdjointDofConstraintValues::iterator adjoint_map_it =
02720                       _adjoint_constraint_values.find(q);
02721 
02722                     if ((adjoint_map_it == _adjoint_constraint_values.end()) &&
02723                         pushed_adj_rhss_to_me[q][constrained] == Number(0))
02724                       continue;
02725 
02726                     if (adjoint_map_it == _adjoint_constraint_values.end())
02727                       adjoint_map_it = _adjoint_constraint_values.insert
02728                         (std::make_pair(q,DofConstraintValueMap())).first;
02729 
02730                     DofConstraintValueMap &constraint_map =
02731                       adjoint_map_it->second;
02732 
02733                     if (pushed_adj_rhss_to_me[q][i] != Number(0))
02734                       constraint_map[constrained] =
02735                         pushed_adj_rhss_to_me[q][i];
02736                     else
02737                       constraint_map.erase(constrained);
02738                   }
02739               }
02740           }
02741 
02742 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02743         // Add the node constraints that I've been sent
02744         for (std::size_t i = 0; i != pushed_node_ids_to_me.size(); ++i)
02745           {
02746             libmesh_assert_equal_to (pushed_node_keys_to_me[i].size(), pushed_node_vals_to_me[i].size());
02747 
02748             dof_id_type constrained_id = pushed_node_ids_to_me[i];
02749 
02750             // If we don't already have a constraint for this node,
02751             // add the one we were sent
02752             const Node *constrained = mesh.node_ptr(constrained_id);
02753             if (!this->is_constrained_node(constrained))
02754               {
02755                 NodeConstraintRow &row = _node_constraints[constrained].first;
02756                 for (std::size_t j = 0; j != pushed_node_keys_to_me[i].size(); ++j)
02757                   {
02758                     const Node *key_node = mesh.node_ptr(pushed_node_keys_to_me[i][j]);
02759                     libmesh_assert(key_node);
02760                     row[key_node] = pushed_node_vals_to_me[i][j];
02761                   }
02762                 _node_constraints[constrained].second = pushed_node_offsets_to_me[i];
02763               }
02764           }
02765 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
02766       }
02767   }
02768 
02769   // Now start checking for any other constraints we need
02770   // to know about, requesting them recursively.
02771 
02772   // Create sets containing the DOFs and nodes we already depend on
02773   typedef std::set<dof_id_type> DoF_RCSet;
02774   DoF_RCSet unexpanded_dofs;
02775 
02776   for (DofConstraints::iterator i = _dof_constraints.begin();
02777        i != _dof_constraints.end(); ++i)
02778     {
02779       unexpanded_dofs.insert(i->first);
02780     }
02781 
02782   typedef std::set<const Node *> Node_RCSet;
02783   Node_RCSet unexpanded_nodes;
02784 
02785 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02786   for (NodeConstraints::iterator i = _node_constraints.begin();
02787        i != _node_constraints.end(); ++i)
02788     {
02789       unexpanded_nodes.insert(i->first);
02790     }
02791 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
02792 
02793   // We have to keep recursing while the unexpanded set is
02794   // nonempty on *any* processor
02795   bool unexpanded_set_nonempty = !unexpanded_dofs.empty() ||
02796     !unexpanded_nodes.empty();
02797   this->comm().max(unexpanded_set_nonempty);
02798 
02799   while (unexpanded_set_nonempty)
02800     {
02801       // Let's make sure we don't lose sync in this loop.
02802       parallel_object_only();
02803 
02804       // Request sets
02805       DoF_RCSet   dof_request_set;
02806       Node_RCSet node_request_set;
02807 
02808       // Request sets to send to each processor
02809       std::vector<std::vector<dof_id_type> >
02810         requested_dof_ids(this->n_processors()),
02811         requested_node_ids(this->n_processors());
02812 
02813       // And the sizes of each
02814       std::vector<dof_id_type>
02815         dof_ids_on_proc(this->n_processors(), 0),
02816         node_ids_on_proc(this->n_processors(), 0);
02817 
02818       // Fill (and thereby sort and uniq!) the main request sets
02819       for (DoF_RCSet::iterator i = unexpanded_dofs.begin();
02820            i != unexpanded_dofs.end(); ++i)
02821         {
02822           DofConstraintRow &row = _dof_constraints[*i];
02823           for (DofConstraintRow::iterator j = row.begin();
02824                j != row.end(); ++j)
02825             {
02826               const dof_id_type constraining_dof = j->first;
02827 
02828               // If it's non-local and we haven't already got a
02829               // constraint for it, we might need to ask for one
02830               if (((constraining_dof < this->first_dof()) ||
02831                    (constraining_dof >= this->end_dof())) &&
02832                   !_dof_constraints.count(constraining_dof))
02833                 dof_request_set.insert(constraining_dof);
02834             }
02835         }
02836 
02837 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02838       for (Node_RCSet::iterator i = unexpanded_nodes.begin();
02839            i != unexpanded_nodes.end(); ++i)
02840         {
02841           NodeConstraintRow &row = _node_constraints[*i].first;
02842           for (NodeConstraintRow::iterator j = row.begin();
02843                j != row.end(); ++j)
02844             {
02845               const Node* const node = j->first;
02846               libmesh_assert(node);
02847 
02848               // If it's non-local and we haven't already got a
02849               // constraint for it, we might need to ask for one
02850               if ((node->processor_id() != this->processor_id()) &&
02851                   !_node_constraints.count(node))
02852                 node_request_set.insert(node);
02853             }
02854         }
02855 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
02856 
02857       // Clear the unexpanded constraint sets; we're about to expand
02858       // them
02859       unexpanded_dofs.clear();
02860       unexpanded_nodes.clear();
02861 
02862       // Count requests by processor
02863       processor_id_type proc_id = 0;
02864       for (DoF_RCSet::iterator i = dof_request_set.begin();
02865            i != dof_request_set.end(); ++i)
02866         {
02867           while (*i >= _end_df[proc_id])
02868             proc_id++;
02869           dof_ids_on_proc[proc_id]++;
02870         }
02871 
02872       for (Node_RCSet::iterator i = node_request_set.begin();
02873            i != node_request_set.end(); ++i)
02874         {
02875           libmesh_assert(*i);
02876           libmesh_assert_less ((*i)->processor_id(), this->n_processors());
02877           node_ids_on_proc[(*i)->processor_id()]++;
02878         }
02879 
02880       for (processor_id_type p = 0; p != this->n_processors(); ++p)
02881         {
02882           requested_dof_ids[p].reserve(dof_ids_on_proc[p]);
02883           requested_node_ids[p].reserve(node_ids_on_proc[p]);
02884         }
02885 
02886       // Prepare each processor's request set
02887       proc_id = 0;
02888       for (DoF_RCSet::iterator i = dof_request_set.begin();
02889            i != dof_request_set.end(); ++i)
02890         {
02891           while (*i >= _end_df[proc_id])
02892             proc_id++;
02893           requested_dof_ids[proc_id].push_back(*i);
02894         }
02895 
02896       for (Node_RCSet::iterator i = node_request_set.begin();
02897            i != node_request_set.end(); ++i)
02898         {
02899           requested_node_ids[(*i)->processor_id()].push_back((*i)->id());
02900         }
02901 
02902       // Now request constraint rows from other processors
02903       for (processor_id_type p=1; p != this->n_processors(); ++p)
02904         {
02905           // Trade my requests with processor procup and procdown
02906           processor_id_type procup =
02907             cast_int<processor_id_type>((this->processor_id() + p) %
02908                                         this->n_processors());
02909           processor_id_type procdown =
02910             cast_int<processor_id_type>((this->n_processors() +
02911                                          this->processor_id() - p) %
02912                                         this->n_processors());
02913           std::vector<dof_id_type> dof_request_to_fill,
02914             node_request_to_fill;
02915 
02916           this->comm().send_receive(procup, requested_dof_ids[procup],
02917                                     procdown, dof_request_to_fill);
02918           this->comm().send_receive(procup, requested_node_ids[procup],
02919                                     procdown, node_request_to_fill);
02920 
02921           // Fill those requests
02922           std::vector<std::vector<dof_id_type> > dof_row_keys(dof_request_to_fill.size()),
02923             node_row_keys(node_request_to_fill.size());
02924 
02925           std::vector<std::vector<Real> > dof_row_vals(dof_request_to_fill.size()),
02926             node_row_vals(node_request_to_fill.size());
02927           std::vector<Number> dof_row_rhss(dof_request_to_fill.size());
02928           std::vector<std::vector<Number> >
02929             dof_adj_rhss(max_qoi_num,
02930                          std::vector<Number>(dof_request_to_fill.size()));
02931           std::vector<Point>  node_row_rhss(node_request_to_fill.size());
02932           for (std::size_t i=0; i != dof_request_to_fill.size(); ++i)
02933             {
02934               dof_id_type constrained = dof_request_to_fill[i];
02935               if (_dof_constraints.count(constrained))
02936                 {
02937                   DofConstraintRow &row = _dof_constraints[constrained];
02938                   std::size_t row_size = row.size();
02939                   dof_row_keys[i].reserve(row_size);
02940                   dof_row_vals[i].reserve(row_size);
02941                   for (DofConstraintRow::iterator j = row.begin();
02942                        j != row.end(); ++j)
02943                     {
02944                       dof_row_keys[i].push_back(j->first);
02945                       dof_row_vals[i].push_back(j->second);
02946 
02947                       // We should never have a 0 constraint
02948                       // coefficient; that's implicit via sparse
02949                       // constraint storage
02950                       libmesh_assert(j->second);
02951                     }
02952                   DofConstraintValueMap::const_iterator rhsit =
02953                     _primal_constraint_values.find(constrained);
02954                   dof_row_rhss[i] = (rhsit == _primal_constraint_values.end()) ?
02955                     0 : rhsit->second;
02956 
02957                   for (unsigned int q = 0; q != max_qoi_num; ++q)
02958                     {
02959                       AdjointDofConstraintValues::const_iterator adjoint_map_it =
02960                         _adjoint_constraint_values.find(q);
02961 
02962                       if (adjoint_map_it == _adjoint_constraint_values.end())
02963                         continue;
02964 
02965                       const DofConstraintValueMap &constraint_map =
02966                         adjoint_map_it->second;
02967 
02968                       DofConstraintValueMap::const_iterator rhsit =
02969                         constraint_map.find(constrained);
02970                       dof_adj_rhss[q][i] = (rhsit == constraint_map.end()) ?
02971                         0 : rhsit->second;
02972                     }
02973                 }
02974               else
02975                 {
02976                   // Get NaN from Real, where it should exist, not
02977                   // from Number, which may be std::complex, in which
02978                   // case quiet_NaN() silently returns zero, rather
02979                   // than sanely returning NaN or throwing an
02980                   // exception or sending Stroustrop hate mail.
02981                   dof_row_rhss[i] =
02982                     std::numeric_limits<Real>::quiet_NaN();
02983 
02984                   // Make sure we don't get caught by "!isnan(NaN)"
02985                   // bugs again.
02986                   libmesh_assert(libmesh_isnan(dof_row_rhss[i]));
02987                 }
02988             }
02989 
02990 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
02991           // FIXME - this could be an unordered set, given a
02992           // hash<pointers> specialization
02993           std::set<const Node*> nodes_requested;
02994 
02995           for (std::size_t i=0; i != node_request_to_fill.size(); ++i)
02996             {
02997               dof_id_type constrained_id = node_request_to_fill[i];
02998               const Node *constrained_node = mesh.node_ptr(constrained_id);
02999               if (_node_constraints.count(constrained_node))
03000                 {
03001                   const NodeConstraintRow &row = _node_constraints[constrained_node].first;
03002                   std::size_t row_size = row.size();
03003                   node_row_keys[i].reserve(row_size);
03004                   node_row_vals[i].reserve(row_size);
03005                   for (NodeConstraintRow::const_iterator j = row.begin();
03006                        j != row.end(); ++j)
03007                     {
03008                       const Node* node = j->first;
03009                       node_row_keys[i].push_back(node->id());
03010                       node_row_vals[i].push_back(j->second);
03011 
03012                       // If we're not sure whether our send
03013                       // destination already has this node, let's give
03014                       // it a copy.
03015                       if (node->processor_id() != procdown)
03016                         nodes_requested.insert(node);
03017 
03018                       // We can have 0 nodal constraint
03019                       // coefficients, where no Lagrange constrant
03020                       // exists but non-Lagrange basis constraints
03021                       // might.
03022                       // libmesh_assert(j->second);
03023                     }
03024                   node_row_rhss[i] = _node_constraints[constrained_node].second;
03025                 }
03026             }
03027 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03028 
03029           // Trade back the results
03030           std::vector<std::vector<dof_id_type> > dof_filled_keys,
03031             node_filled_keys;
03032           std::vector<std::vector<Real> > dof_filled_vals,
03033             node_filled_vals;
03034           std::vector<Number> dof_filled_rhss;
03035           std::vector<std::vector<Number> > adj_filled_rhss;
03036           std::vector<Point> node_filled_rhss;
03037           this->comm().send_receive(procdown, dof_row_keys,
03038                                     procup, dof_filled_keys);
03039           this->comm().send_receive(procdown, dof_row_vals,
03040                                     procup, dof_filled_vals);
03041           this->comm().send_receive(procdown, dof_row_rhss,
03042                                     procup, dof_filled_rhss);
03043           this->comm().send_receive(procdown, dof_adj_rhss,
03044                                     procup, adj_filled_rhss);
03045 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03046           this->comm().send_receive(procdown, node_row_keys,
03047                                     procup, node_filled_keys);
03048           this->comm().send_receive(procdown, node_row_vals,
03049                                     procup, node_filled_vals);
03050           this->comm().send_receive(procdown, node_row_rhss,
03051                                     procup, node_filled_rhss);
03052 
03053           // Constraining nodes might not even exist on our subset of
03054           // a distributed mesh, so let's make them exist.
03055           if (!mesh.is_serial())
03056             this->comm().send_receive_packed_range
03057               (procdown, &mesh, nodes_requested.begin(), nodes_requested.end(),
03058                procup,   &mesh, mesh_inserter_iterator<Node>(mesh));
03059 
03060 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03061           libmesh_assert_equal_to (dof_filled_keys.size(), requested_dof_ids[procup].size());
03062           libmesh_assert_equal_to (dof_filled_vals.size(), requested_dof_ids[procup].size());
03063           libmesh_assert_equal_to (dof_filled_rhss.size(), requested_dof_ids[procup].size());
03064 #ifndef NDEBUG
03065           for (unsigned int q=0; q != adj_filled_rhss.size(); ++q)
03066             libmesh_assert_equal_to (adj_filled_rhss[q].size(), requested_dof_ids[procup].size());
03067 #endif
03068           libmesh_assert_equal_to (node_filled_keys.size(), requested_node_ids[procup].size());
03069           libmesh_assert_equal_to (node_filled_vals.size(), requested_node_ids[procup].size());
03070           libmesh_assert_equal_to (node_filled_rhss.size(), requested_node_ids[procup].size());
03071 
03072           // Add any new constraint rows we've found
03073           for (std::size_t i=0; i != requested_dof_ids[procup].size(); ++i)
03074             {
03075               libmesh_assert_equal_to (dof_filled_keys[i].size(), dof_filled_vals[i].size());
03076               if (!libmesh_isnan(dof_filled_rhss[i]))
03077                 {
03078                   dof_id_type constrained = requested_dof_ids[procup][i];
03079                   DofConstraintRow &row = _dof_constraints[constrained];
03080                   for (std::size_t j = 0; j != dof_filled_keys[i].size(); ++j)
03081                     row[dof_filled_keys[i][j]] = dof_filled_vals[i][j];
03082                   if (dof_filled_rhss[i] != Number(0))
03083                     _primal_constraint_values[constrained] = dof_filled_rhss[i];
03084                   else
03085                     _primal_constraint_values.erase(constrained);
03086 
03087                   for (unsigned int q = 0; q != max_qoi_num; ++q)
03088                     {
03089                       AdjointDofConstraintValues::iterator adjoint_map_it =
03090                         _adjoint_constraint_values.find(q);
03091 
03092                       if ((adjoint_map_it == _adjoint_constraint_values.end()) &&
03093                           adj_filled_rhss[q][constrained] == Number(0))
03094                         continue;
03095 
03096                       if (adjoint_map_it == _adjoint_constraint_values.end())
03097                         adjoint_map_it = _adjoint_constraint_values.insert
03098                           (std::make_pair(q,DofConstraintValueMap())).first;
03099 
03100                       DofConstraintValueMap &constraint_map =
03101                         adjoint_map_it->second;
03102 
03103                       if (adj_filled_rhss[q][i] != Number(0))
03104                         constraint_map[constrained] =
03105                           adj_filled_rhss[q][i];
03106                       else
03107                         constraint_map.erase(constrained);
03108                     }
03109 
03110                   // And prepare to check for more recursive constraints
03111                   if (!dof_filled_keys[i].empty())
03112                     unexpanded_dofs.insert(constrained);
03113                 }
03114             }
03115 
03116 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03117           for (std::size_t i=0; i != requested_node_ids[procup].size(); ++i)
03118             {
03119               libmesh_assert_equal_to (node_filled_keys[i].size(), node_filled_vals[i].size());
03120               if (!node_filled_keys[i].empty())
03121                 {
03122                   dof_id_type constrained_id = requested_node_ids[procup][i];
03123                   const Node* constrained_node = mesh.node_ptr(constrained_id);
03124                   NodeConstraintRow &row = _node_constraints[constrained_node].first;
03125                   for (std::size_t j = 0; j != node_filled_keys[i].size(); ++j)
03126                     {
03127                       const Node* key_node =
03128                         mesh.node_ptr(node_filled_keys[i][j]);
03129                       libmesh_assert(key_node);
03130                       row[key_node] = node_filled_vals[i][j];
03131                     }
03132                   _node_constraints[constrained_node].second = node_filled_rhss[i];
03133 
03134                   // And prepare to check for more recursive constraints
03135                   unexpanded_nodes.insert(constrained_node);
03136                 }
03137             }
03138 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03139         }
03140 
03141       // We have to keep recursing while the unexpanded set is
03142       // nonempty on *any* processor
03143       unexpanded_set_nonempty = !unexpanded_dofs.empty() ||
03144         !unexpanded_nodes.empty();
03145       this->comm().max(unexpanded_set_nonempty);
03146     }
03147 }
03148 
03149 
03150 
03151 void DofMap::process_constraints (MeshBase& mesh)
03152 {
03153   // We've computed our local constraints, but they may depend on
03154   // non-local constraints that we'll need to take into account.
03155   this->allgather_recursive_constraints(mesh);
03156 
03157   // Create a set containing the DOFs we already depend on
03158   typedef std::set<dof_id_type> RCSet;
03159   RCSet unexpanded_set;
03160 
03161   for (DofConstraints::iterator i = _dof_constraints.begin();
03162        i != _dof_constraints.end(); ++i)
03163     unexpanded_set.insert(i->first);
03164 
03165   while (!unexpanded_set.empty())
03166     for (RCSet::iterator i = unexpanded_set.begin();
03167          i != unexpanded_set.end(); /* nothing */)
03168       {
03169         // If the DOF is constrained
03170         DofConstraints::iterator
03171           pos = _dof_constraints.find(*i);
03172 
03173         libmesh_assert (pos != _dof_constraints.end());
03174 
03175         DofConstraintRow& constraint_row = pos->second;
03176 
03177         DofConstraintValueMap::iterator rhsit =
03178           _primal_constraint_values.find(*i);
03179         Number constraint_rhs = (rhsit == _primal_constraint_values.end()) ?
03180           0 : rhsit->second;
03181 
03182         std::vector<dof_id_type> constraints_to_expand;
03183 
03184         for (DofConstraintRow::const_iterator
03185                it=constraint_row.begin(); it != constraint_row.end();
03186              ++it)
03187           if (it->first != *i && this->is_constrained_dof(it->first))
03188             {
03189               unexpanded_set.insert(it->first);
03190               constraints_to_expand.push_back(it->first);
03191             }
03192 
03193         for (std::size_t j = 0; j != constraints_to_expand.size();
03194              ++j)
03195           {
03196             dof_id_type expandable = constraints_to_expand[j];
03197 
03198             const Real this_coef = constraint_row[expandable];
03199 
03200             DofConstraints::const_iterator
03201               subpos = _dof_constraints.find(expandable);
03202 
03203             libmesh_assert (subpos != _dof_constraints.end());
03204 
03205             const DofConstraintRow& subconstraint_row = subpos->second;
03206 
03207             for (DofConstraintRow::const_iterator
03208                    it=subconstraint_row.begin();
03209                  it != subconstraint_row.end(); ++it)
03210               {
03211                 constraint_row[it->first] += it->second * this_coef;
03212               }
03213             DofConstraintValueMap::const_iterator subrhsit =
03214               _primal_constraint_values.find(expandable);
03215             if (subrhsit != _primal_constraint_values.end())
03216               constraint_rhs += subrhsit->second * this_coef;
03217 
03218             constraint_row.erase(expandable);
03219           }
03220 
03221         if (rhsit == _primal_constraint_values.end())
03222           {
03223             if (constraint_rhs != Number(0))
03224               _primal_constraint_values[*i] = constraint_rhs;
03225             else
03226               _primal_constraint_values.erase(*i);
03227           }
03228         else
03229           {
03230             if (constraint_rhs != Number(0))
03231               rhsit->second = constraint_rhs;
03232             else
03233               _primal_constraint_values.erase(rhsit);
03234           }
03235 
03236         if (constraints_to_expand.empty())
03237           unexpanded_set.erase(i++);
03238         else
03239           ++i;
03240       }
03241 
03242   // In parallel we can't guarantee that nodes/dofs which constrain
03243   // others are on processors which are aware of that constraint, yet
03244   // we need such awareness for sparsity pattern generation.  So send
03245   // other processors any constraints they might need to know about.
03246   this->scatter_constraints(mesh);
03247 
03248   // Now that we have our root constraint dependencies sorted out, add
03249   // them to the send_list
03250   this->add_constraints_to_send_list();
03251 }
03252 
03253 
03254 void DofMap::scatter_constraints(MeshBase& mesh)
03255 {
03256   // At this point each processor with a constrained node knows
03257   // the corresponding constraint row, but we also need each processor
03258   // with a constrainer node to know the corresponding row(s).
03259 
03260   // This function must be run on all processors at once
03261   parallel_object_only();
03262 
03263   // Return immediately if there's nothing to gather
03264   if (this->n_processors() == 1)
03265     return;
03266 
03267   // We might get to return immediately if none of the processors
03268   // found any constraints
03269   unsigned int has_constraints = !_dof_constraints.empty()
03270 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03271     || !_node_constraints.empty()
03272 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03273     ;
03274   this->comm().max(has_constraints);
03275   if (!has_constraints)
03276     return;
03277 
03278 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03279   std::vector<std::set<dof_id_type> > pushed_node_ids(this->n_processors());
03280 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03281 
03282   std::vector<std::set<dof_id_type> > pushed_ids(this->n_processors());
03283 
03284   // Collect the dof constraints I need to push to each processor
03285   dof_id_type constrained_proc_id = 0;
03286   for (DofConstraints::iterator i = _dof_constraints.begin();
03287        i != _dof_constraints.end(); ++i)
03288     {
03289       const dof_id_type constrained = i->first;
03290       while (constrained >= _end_df[constrained_proc_id])
03291         constrained_proc_id++;
03292 
03293       if (constrained_proc_id != this->processor_id())
03294         continue;
03295 
03296       DofConstraintRow &row = i->second;
03297       for (DofConstraintRow::iterator j = row.begin();
03298            j != row.end(); ++j)
03299         {
03300           const dof_id_type constraining = j->first;
03301 
03302           processor_id_type constraining_proc_id = 0;
03303           while (constraining >= _end_df[constraining_proc_id])
03304             constraining_proc_id++;
03305 
03306           if (constraining_proc_id != this->processor_id() &&
03307               constraining_proc_id != constrained_proc_id)
03308             pushed_ids[constraining_proc_id].insert(constrained);
03309         }
03310     }
03311 
03312 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03313   // Collect the node constraints to push to each processor
03314   for (NodeConstraints::iterator i = _node_constraints.begin();
03315        i != _node_constraints.end(); ++i)
03316     {
03317       const Node *constrained = i->first;
03318 
03319       if (constrained->processor_id() != this->processor_id())
03320         continue;
03321 
03322       NodeConstraintRow &row = i->second.first;
03323       for (NodeConstraintRow::iterator j = row.begin();
03324            j != row.end(); ++j)
03325         {
03326           const Node *constraining = j->first;
03327 
03328           if (constraining->processor_id() != this->processor_id() &&
03329               constraining->processor_id() != constrained->processor_id())
03330             pushed_node_ids[constraining->processor_id()].insert(constrained->id());
03331         }
03332     }
03333 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03334 
03335   // Now trade constraint rows
03336   for (processor_id_type p = 0; p != this->n_processors(); ++p)
03337     {
03338       // Push to processor procup while receiving from procdown
03339       processor_id_type procup =
03340         cast_int<processor_id_type>((this->processor_id() + p) %
03341                                     this->n_processors());
03342       processor_id_type procdown =
03343         cast_int<processor_id_type>((this->n_processors() +
03344                                      this->processor_id() - p) %
03345                                     this->n_processors());
03346 
03347       // Pack the dof constraint rows and rhs's to push to procup
03348       const std::size_t pushed_ids_size = pushed_ids[procup].size();
03349       std::vector<std::vector<dof_id_type> > pushed_keys(pushed_ids_size);
03350       std::vector<std::vector<Real> > pushed_vals(pushed_ids_size);
03351       std::vector<Number> pushed_rhss(pushed_ids_size);
03352 
03353       std::set<dof_id_type>::const_iterator it;
03354       std::size_t push_i;
03355       for (push_i = 0, it = pushed_ids[procup].begin();
03356            it != pushed_ids[procup].end(); ++push_i, ++it)
03357         {
03358           const dof_id_type constrained = *it;
03359           DofConstraintRow &row = _dof_constraints[constrained];
03360           std::size_t row_size = row.size();
03361           pushed_keys[push_i].reserve(row_size);
03362           pushed_vals[push_i].reserve(row_size);
03363           for (DofConstraintRow::iterator j = row.begin();
03364                j != row.end(); ++j)
03365             {
03366               pushed_keys[push_i].push_back(j->first);
03367               pushed_vals[push_i].push_back(j->second);
03368             }
03369 
03370           DofConstraintValueMap::const_iterator rhsit =
03371             _primal_constraint_values.find(constrained);
03372           pushed_rhss[push_i] = (rhsit == _primal_constraint_values.end()) ?
03373             0 : rhsit->second;
03374         }
03375 
03376 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03377       // Pack the node constraint rows to push to procup
03378       const std::size_t pushed_node_ids_size = pushed_node_ids[procup].size();
03379       std::vector<std::vector<dof_id_type> > pushed_node_keys(pushed_node_ids_size);
03380       std::vector<std::vector<Real> > pushed_node_vals(pushed_node_ids_size);
03381       std::vector<Point> pushed_node_offsets(pushed_node_ids_size);
03382       std::set<const Node*> pushed_nodes;
03383 
03384       for (push_i = 0, it = pushed_node_ids[procup].begin();
03385            it != pushed_node_ids[procup].end(); ++push_i, ++it)
03386         {
03387           const Node *constrained = mesh.node_ptr(*it);
03388 
03389           if (constrained->processor_id() != procdown)
03390             pushed_nodes.insert(constrained);
03391 
03392           NodeConstraintRow &row = _node_constraints[constrained].first;
03393           std::size_t row_size = row.size();
03394           pushed_node_keys[push_i].reserve(row_size);
03395           pushed_node_vals[push_i].reserve(row_size);
03396           for (NodeConstraintRow::iterator j = row.begin();
03397                j != row.end(); ++j)
03398             {
03399               const Node* constraining = j->first;
03400 
03401               pushed_node_keys[push_i].push_back(constraining->id());
03402               pushed_node_vals[push_i].push_back(j->second);
03403 
03404               if (constraining->processor_id() != procup)
03405                 pushed_nodes.insert(constraining);
03406             }
03407           pushed_node_offsets[push_i] = _node_constraints[constrained].second;
03408         }
03409 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03410 
03411       // Trade pushed dof constraint rows
03412       std::vector<dof_id_type> pushed_ids_from_me
03413         (pushed_ids[procup].begin(), pushed_ids[procup].end());
03414       std::vector<dof_id_type> pushed_ids_to_me;
03415       std::vector<std::vector<dof_id_type> > pushed_keys_to_me;
03416       std::vector<std::vector<Real> > pushed_vals_to_me;
03417       std::vector<Number> pushed_rhss_to_me;
03418       this->comm().send_receive(procup, pushed_ids_from_me,
03419                                 procdown, pushed_ids_to_me);
03420       this->comm().send_receive(procup, pushed_keys,
03421                                 procdown, pushed_keys_to_me);
03422       this->comm().send_receive(procup, pushed_vals,
03423                                 procdown, pushed_vals_to_me);
03424       this->comm().send_receive(procup, pushed_rhss,
03425                                 procdown, pushed_rhss_to_me);
03426       libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_keys_to_me.size());
03427       libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_vals_to_me.size());
03428       libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_rhss_to_me.size());
03429 
03430 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03431       // Trade pushed node constraint rows
03432       std::vector<dof_id_type> pushed_node_ids_from_me
03433         (pushed_node_ids[procup].begin(), pushed_node_ids[procup].end());
03434       std::vector<dof_id_type> pushed_node_ids_to_me;
03435       std::vector<std::vector<dof_id_type> > pushed_node_keys_to_me;
03436       std::vector<std::vector<Real> > pushed_node_vals_to_me;
03437       std::vector<Point> pushed_node_offsets_to_me;
03438       this->comm().send_receive(procup, pushed_node_ids_from_me,
03439                                 procdown, pushed_node_ids_to_me);
03440       this->comm().send_receive(procup, pushed_node_keys,
03441                                 procdown, pushed_node_keys_to_me);
03442       this->comm().send_receive(procup, pushed_node_vals,
03443                                 procdown, pushed_node_vals_to_me);
03444       this->comm().send_receive(procup, pushed_node_offsets,
03445                                 procdown, pushed_node_offsets_to_me);
03446 
03447       // Constraining nodes might not even exist on our subset of
03448       // a distributed mesh, so let's make them exist.
03449       if (!mesh.is_serial())
03450         this->comm().send_receive_packed_range
03451           (procup, &mesh, pushed_nodes.begin(), pushed_nodes.end(),
03452            procdown, &mesh, mesh_inserter_iterator<Node>(mesh));
03453 
03454       libmesh_assert_equal_to (pushed_node_ids_to_me.size(), pushed_node_keys_to_me.size());
03455       libmesh_assert_equal_to (pushed_node_ids_to_me.size(), pushed_node_vals_to_me.size());
03456       libmesh_assert_equal_to (pushed_node_ids_to_me.size(), pushed_node_offsets_to_me.size());
03457 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03458 
03459       // Add the dof constraints that I've been sent
03460       for (std::size_t i = 0; i != pushed_ids_to_me.size(); ++i)
03461         {
03462           libmesh_assert_equal_to (pushed_keys_to_me[i].size(), pushed_vals_to_me[i].size());
03463 
03464           dof_id_type constrained = pushed_ids_to_me[i];
03465 
03466           // If we don't already have a constraint for this dof,
03467           // add the one we were sent
03468           if (!this->is_constrained_dof(constrained))
03469             {
03470               DofConstraintRow &row = _dof_constraints[constrained];
03471               for (std::size_t j = 0; j != pushed_keys_to_me[i].size(); ++j)
03472                 {
03473                   row[pushed_keys_to_me[i][j]] = pushed_vals_to_me[i][j];
03474                 }
03475               if (pushed_rhss_to_me[i] != Number(0))
03476                 _primal_constraint_values[constrained] = pushed_rhss_to_me[i];
03477               else
03478                 _primal_constraint_values.erase(constrained);
03479             }
03480         }
03481 
03482 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
03483       // Add the node constraints that I've been sent
03484       for (std::size_t i = 0; i != pushed_node_ids_to_me.size(); ++i)
03485         {
03486           libmesh_assert_equal_to (pushed_node_keys_to_me[i].size(), pushed_node_vals_to_me[i].size());
03487 
03488           dof_id_type constrained_id = pushed_node_ids_to_me[i];
03489 
03490           // If we don't already have a constraint for this node,
03491           // add the one we were sent
03492           const Node *constrained = mesh.node_ptr(constrained_id);
03493           if (!this->is_constrained_node(constrained))
03494             {
03495               NodeConstraintRow &row = _node_constraints[constrained].first;
03496               for (std::size_t j = 0; j != pushed_node_keys_to_me[i].size(); ++j)
03497                 {
03498                   const Node *key_node = mesh.node_ptr(pushed_node_keys_to_me[i][j]);
03499                   libmesh_assert(key_node);
03500                   row[key_node] = pushed_node_vals_to_me[i][j];
03501                 }
03502               _node_constraints[constrained].second = pushed_node_offsets_to_me[i];
03503             }
03504         }
03505 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
03506     }
03507 
03508   // Next we need to push constraints to processors which don't own
03509   // the constrained dof, don't own the constraining dof, but own an
03510   // element supporting the constraining dof.
03511   //
03512   // We need to be able to quickly look up constrained dof ids by what
03513   // constrains them, so that we can handle the case where we see a
03514   // foreign element containing one of our constraining DoF ids and we
03515   // need to push that constraint.
03516   //
03517   // Getting distributed adaptive sparsity patterns right is hard.
03518 
03519   typedef std::map<dof_id_type, std::set<dof_id_type> > DofConstrainsMap;
03520   DofConstrainsMap dof_id_constrains;
03521 
03522   for (DofConstraints::iterator i = _dof_constraints.begin();
03523        i != _dof_constraints.end(); ++i)
03524     {
03525       const dof_id_type constrained = i->first;
03526       DofConstraintRow &row = i->second;
03527       for (DofConstraintRow::iterator j = row.begin();
03528            j != row.end(); ++j)
03529         {
03530           const dof_id_type constraining = j->first;
03531 
03532           dof_id_type constraining_proc_id = 0;
03533           while (constraining >= _end_df[constraining_proc_id])
03534             constraining_proc_id++;
03535 
03536           if (constraining_proc_id == this->processor_id())
03537             dof_id_constrains[constraining].insert(constrained);
03538         }
03539     }
03540 
03541   // Loop over all foreign elements, find any supporting our
03542   // constrained dof indices.
03543   pushed_ids.clear();
03544   pushed_ids.resize(this->n_processors());
03545 
03546   MeshBase::const_element_iterator it = mesh.active_not_local_elements_begin(),
03547     end = mesh.active_not_local_elements_end();
03548   for (; it != end; ++it)
03549     {
03550       const Elem *elem = *it;
03551 
03552       std::vector<dof_id_type> my_dof_indices;
03553       this->dof_indices (elem, my_dof_indices);
03554 
03555       for (std::size_t i=0; i != my_dof_indices.size(); ++i)
03556         {
03557           DofConstrainsMap::const_iterator dcmi =
03558             dof_id_constrains.find(my_dof_indices[i]);
03559           if (dcmi != dof_id_constrains.end())
03560             {
03561               for (DofConstrainsMap::mapped_type::const_iterator mti =
03562                      dcmi->second.begin();
03563                    mti != dcmi->second.end(); ++mti)
03564                 {
03565                   const dof_id_type constrained = *mti;
03566 
03567                   dof_id_type the_constrained_proc_id = 0;
03568                   while (constrained >= _end_df[the_constrained_proc_id])
03569                     the_constrained_proc_id++;
03570 
03571                   const dof_id_type elemproc = elem->processor_id();
03572                   if (elemproc != the_constrained_proc_id)
03573                     pushed_ids[elemproc].insert(constrained);
03574                 }
03575             }
03576         }
03577     }
03578 
03579   // One last trade of constraint rows
03580   for (processor_id_type p = 0; p != this->n_processors(); ++p)
03581     {
03582       // Push to processor procup while receiving from procdown
03583       processor_id_type procup =
03584         cast_int<processor_id_type>((this->processor_id() + p) %
03585                                     this->n_processors());
03586       processor_id_type procdown =
03587         cast_int<processor_id_type>((this->n_processors() +
03588                                      this->processor_id() - p) %
03589                                     this->n_processors());
03590 
03591       // Pack the dof constraint rows and rhs's to push to procup
03592       const std::size_t pushed_ids_size = pushed_ids[procup].size();
03593       std::vector<std::vector<dof_id_type> > pushed_keys(pushed_ids_size);
03594       std::vector<std::vector<Real> > pushed_vals(pushed_ids_size);
03595       std::vector<Number> pushed_rhss(pushed_ids_size);
03596 
03597       // As long as we're declaring them outside the loop, let's initialize them too!
03598       std::set<dof_id_type>::const_iterator pushed_ids_iter = pushed_ids[procup].begin();
03599       std::size_t push_i = 0;
03600       for ( ; pushed_ids_iter != pushed_ids[procup].end(); ++push_i, ++pushed_ids_iter)
03601         {
03602           const dof_id_type constrained = *pushed_ids_iter;
03603           DofConstraintRow &row = _dof_constraints[constrained];
03604           std::size_t row_size = row.size();
03605           pushed_keys[push_i].reserve(row_size);
03606           pushed_vals[push_i].reserve(row_size);
03607           for (DofConstraintRow::iterator j = row.begin();
03608                j != row.end(); ++j)
03609             {
03610               pushed_keys[push_i].push_back(j->first);
03611               pushed_vals[push_i].push_back(j->second);
03612             }
03613 
03614           DofConstraintValueMap::const_iterator rhsit =
03615             _primal_constraint_values.find(constrained);
03616           pushed_rhss[push_i] = (rhsit == _primal_constraint_values.end()) ?
03617             0 : rhsit->second;
03618         }
03619 
03620       // Trade pushed dof constraint rows
03621       std::vector<dof_id_type> pushed_ids_from_me
03622         (pushed_ids[procup].begin(), pushed_ids[procup].end());
03623       std::vector<dof_id_type> pushed_ids_to_me;
03624       std::vector<std::vector<dof_id_type> > pushed_keys_to_me;
03625       std::vector<std::vector<Real> > pushed_vals_to_me;
03626       std::vector<Number> pushed_rhss_to_me;
03627       this->comm().send_receive(procup, pushed_ids_from_me,
03628                                 procdown, pushed_ids_to_me);
03629       this->comm().send_receive(procup, pushed_keys,
03630                                 procdown, pushed_keys_to_me);
03631       this->comm().send_receive(procup, pushed_vals,
03632                                 procdown, pushed_vals_to_me);
03633       this->comm().send_receive(procup, pushed_rhss,
03634                                 procdown, pushed_rhss_to_me);
03635       libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_keys_to_me.size());
03636       libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_vals_to_me.size());
03637       libmesh_assert_equal_to (pushed_ids_to_me.size(), pushed_rhss_to_me.size());
03638 
03639       // Add the dof constraints that I've been sent
03640       for (std::size_t i = 0; i != pushed_ids_to_me.size(); ++i)
03641         {
03642           libmesh_assert_equal_to (pushed_keys_to_me[i].size(), pushed_vals_to_me[i].size());
03643 
03644           dof_id_type constrained = pushed_ids_to_me[i];
03645 
03646           // If we don't already have a constraint for this dof,
03647           // add the one we were sent
03648           if (!this->is_constrained_dof(constrained))
03649             {
03650               DofConstraintRow &row = _dof_constraints[constrained];
03651               for (std::size_t j = 0; j != pushed_keys_to_me[i].size(); ++j)
03652                 {
03653                   row[pushed_keys_to_me[i][j]] = pushed_vals_to_me[i][j];
03654                 }
03655 
03656               if (pushed_rhss_to_me[i] != Number(0))
03657                 _primal_constraint_values[constrained] = pushed_rhss_to_me[i];
03658               else
03659                 _primal_constraint_values.erase(constrained);
03660             }
03661         }
03662     }
03663 }
03664 
03665 
03666 void DofMap::add_constraints_to_send_list()
03667 {
03668   // This function must be run on all processors at once
03669   parallel_object_only();
03670 
03671   // Return immediately if there's nothing to gather
03672   if (this->n_processors() == 1)
03673     return;
03674 
03675   // We might get to return immediately if none of the processors
03676   // found any constraints
03677   unsigned int has_constraints = !_dof_constraints.empty();
03678   this->comm().max(has_constraints);
03679   if (!has_constraints)
03680     return;
03681 
03682   for (DofConstraints::iterator i = _dof_constraints.begin();
03683        i != _dof_constraints.end(); ++i)
03684     {
03685       dof_id_type constrained_dof = i->first;
03686 
03687       // We only need the dependencies of our own constrained dofs
03688       if (constrained_dof < this->first_dof() ||
03689           constrained_dof >= this->end_dof())
03690         continue;
03691 
03692       DofConstraintRow& constraint_row = i->second;
03693       for (DofConstraintRow::const_iterator
03694              j=constraint_row.begin(); j != constraint_row.end();
03695            ++j)
03696         {
03697           dof_id_type constraint_dependency = j->first;
03698 
03699           // No point in adding one of our own dofs to the send_list
03700           if (constraint_dependency >= this->first_dof() &&
03701               constraint_dependency < this->end_dof())
03702             continue;
03703 
03704           _send_list.push_back(constraint_dependency);
03705         }
03706     }
03707 }
03708 
03709 
03710 
03711 #endif // LIBMESH_ENABLE_CONSTRAINTS
03712 
03713 
03714 #ifdef LIBMESH_ENABLE_AMR
03715 
03716 void DofMap::constrain_p_dofs (unsigned int var,
03717                                const Elem *elem,
03718                                unsigned int s,
03719                                unsigned int p)
03720 {
03721   // We're constraining dofs on elem which correspond to p refinement
03722   // levels above p - this only makes sense if elem's p refinement
03723   // level is above p.
03724   libmesh_assert_greater (elem->p_level(), p);
03725   libmesh_assert_less (s, elem->n_sides());
03726 
03727   const unsigned int sys_num = this->sys_number();
03728   const unsigned int dim = elem->dim();
03729   ElemType type = elem->type();
03730   FEType low_p_fe_type = this->variable_type(var);
03731   FEType high_p_fe_type = this->variable_type(var);
03732   low_p_fe_type.order = static_cast<Order>(low_p_fe_type.order + p);
03733   high_p_fe_type.order = static_cast<Order>(high_p_fe_type.order +
03734                                             elem->p_level());
03735 
03736   const unsigned int n_nodes = elem->n_nodes();
03737   for (unsigned int n = 0; n != n_nodes; ++n)
03738     if (elem->is_node_on_side(n, s))
03739       {
03740         const Node * const node = elem->get_node(n);
03741         const unsigned int low_nc =
03742           FEInterface::n_dofs_at_node (dim, low_p_fe_type, type, n);
03743         const unsigned int high_nc =
03744           FEInterface::n_dofs_at_node (dim, high_p_fe_type, type, n);
03745 
03746         // since we may be running this method concurrently
03747         // on multiple threads we need to acquire a lock
03748         // before modifying the _dof_constraints object.
03749         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
03750 
03751         if (elem->is_vertex(n))
03752           {
03753             // Add "this is zero" constraint rows for high p vertex
03754             // dofs
03755             for (unsigned int i = low_nc; i != high_nc; ++i)
03756               {
03757                 _dof_constraints[node->dof_number(sys_num,var,i)].clear();
03758                 _primal_constraint_values.erase(node->dof_number(sys_num,var,i));
03759               }
03760           }
03761         else
03762           {
03763             const unsigned int total_dofs = node->n_comp(sys_num, var);
03764             libmesh_assert_greater_equal (total_dofs, high_nc);
03765             // Add "this is zero" constraint rows for high p
03766             // non-vertex dofs, which are numbered in reverse
03767             for (unsigned int j = low_nc; j != high_nc; ++j)
03768               {
03769                 const unsigned int i = total_dofs - j - 1;
03770                 _dof_constraints[node->dof_number(sys_num,var,i)].clear();
03771                 _primal_constraint_values.erase(node->dof_number(sys_num,var,i));
03772               }
03773           }
03774       }
03775 }
03776 
03777 #endif // LIBMESH_ENABLE_AMR
03778 
03779 
03780 #ifdef LIBMESH_ENABLE_DIRICHLET
03781 void DofMap::add_dirichlet_boundary (const DirichletBoundary& dirichlet_boundary)
03782 {
03783   _dirichlet_boundaries->push_back(new DirichletBoundary(dirichlet_boundary));
03784 }
03785 
03786 
03787 void DofMap::add_adjoint_dirichlet_boundary
03788 (const DirichletBoundary& dirichlet_boundary,
03789  unsigned int qoi_index)
03790 {
03791   unsigned int old_size = cast_int<unsigned int>
03792     (_adjoint_dirichlet_boundaries.size());
03793   for (unsigned int i = old_size; i <= qoi_index; ++i)
03794     _adjoint_dirichlet_boundaries.push_back(new DirichletBoundaries());
03795 
03796   _adjoint_dirichlet_boundaries[qoi_index]->push_back
03797     (new DirichletBoundary(dirichlet_boundary));
03798 }
03799 
03800 
03801 bool DofMap::has_adjoint_dirichlet_boundaries(unsigned int q) const
03802 {
03803   if (_adjoint_dirichlet_boundaries.size() > q)
03804     return true;
03805 
03806   return false;
03807 }
03808 
03809 
03810 const DirichletBoundaries *
03811 DofMap::get_adjoint_dirichlet_boundaries(unsigned int q) const
03812 {
03813   libmesh_assert_greater(_adjoint_dirichlet_boundaries.size(),q);
03814   return _adjoint_dirichlet_boundaries[q];
03815 }
03816 
03817 
03818 DirichletBoundaries *
03819 DofMap::get_adjoint_dirichlet_boundaries(unsigned int q)
03820 {
03821   unsigned int old_size = cast_int<unsigned int>
03822     (_adjoint_dirichlet_boundaries.size());
03823   for (unsigned int i = old_size; i <= q; ++i)
03824     _adjoint_dirichlet_boundaries.push_back(new DirichletBoundaries());
03825 
03826   return _adjoint_dirichlet_boundaries[q];
03827 }
03828 
03829 
03830 void DofMap::remove_dirichlet_boundary (const DirichletBoundary& boundary_to_remove)
03831 {
03832   // Find a boundary condition matching the one to be removed
03833   std::vector<DirichletBoundary *>::iterator it = _dirichlet_boundaries->begin();
03834   std::vector<DirichletBoundary *>::iterator end = _dirichlet_boundaries->end();
03835   for (; it != end; ++it)
03836     {
03837       DirichletBoundary *bdy = *it;
03838 
03839       if ((bdy->b == boundary_to_remove.b) &&
03840           bdy->variables == boundary_to_remove.variables)
03841         break;
03842     }
03843 
03844   // Delete it and remove it
03845   libmesh_assert (it != end);
03846   delete *it;
03847   _dirichlet_boundaries->erase(it);
03848 }
03849 
03850 
03851 void DofMap::remove_adjoint_dirichlet_boundary (const DirichletBoundary& boundary_to_remove,
03852                                                 unsigned int qoi_index)
03853 {
03854   libmesh_assert_greater(_adjoint_dirichlet_boundaries.size(),
03855                          qoi_index);
03856 
03857   // Find a boundary condition matching the one to be removed
03858   std::vector<DirichletBoundary *>::iterator it =
03859     _adjoint_dirichlet_boundaries[qoi_index]->begin();
03860   std::vector<DirichletBoundary *>::iterator end =
03861     _adjoint_dirichlet_boundaries[qoi_index]->end();
03862   for (; it != end; ++it)
03863     {
03864       DirichletBoundary *bdy = *it;
03865 
03866       if ((bdy->b == boundary_to_remove.b) &&
03867           bdy->variables == boundary_to_remove.variables)
03868         break;
03869     }
03870 
03871   // Delete it and remove it
03872   libmesh_assert (it != end);
03873   delete *it;
03874   _adjoint_dirichlet_boundaries[qoi_index]->erase(it);
03875 }
03876 
03877 
03878 DirichletBoundaries::~DirichletBoundaries()
03879 {
03880   for (std::vector<DirichletBoundary *>::iterator it = begin(); it != end(); ++it)
03881     delete *it;
03882 }
03883 
03884 #endif // LIBMESH_ENABLE_DIRICHLET
03885 
03886 
03887 #ifdef LIBMESH_ENABLE_PERIODIC
03888 
03889 void DofMap::add_periodic_boundary (const PeriodicBoundaryBase& periodic_boundary)
03890 {
03891   // See if we already have a periodic boundary associated myboundary...
03892   PeriodicBoundaryBase* existing_boundary = _periodic_boundaries->boundary(periodic_boundary.myboundary);
03893 
03894   if ( existing_boundary == NULL )
03895     {
03896       // ...if not, clone the input (and its inverse) and add them to the PeriodicBoundaries object
03897       PeriodicBoundaryBase* boundary = periodic_boundary.clone().release();
03898       PeriodicBoundaryBase* inverse_boundary = periodic_boundary.clone(PeriodicBoundaryBase::INVERSE).release();
03899 
03900       // _periodic_boundaries takes ownership of the pointers
03901       _periodic_boundaries->insert(std::make_pair(boundary->myboundary, boundary));
03902       _periodic_boundaries->insert(std::make_pair(inverse_boundary->myboundary, inverse_boundary));
03903     }
03904   else
03905     {
03906       // ...otherwise, merge this object's variable IDs with the existing boundary object's.
03907       existing_boundary->merge(periodic_boundary);
03908 
03909       // Do the same merging process for the inverse boundary.  Note: the inverse better already exist!
03910       PeriodicBoundaryBase* inverse_boundary = _periodic_boundaries->boundary(periodic_boundary.pairedboundary);
03911       libmesh_assert(inverse_boundary);
03912       inverse_boundary->merge(periodic_boundary);
03913     }
03914 }
03915 
03916 
03917 
03918 
03919 void DofMap::add_periodic_boundary (const PeriodicBoundaryBase& boundary, const PeriodicBoundaryBase& inverse_boundary)
03920 {
03921   libmesh_assert_equal_to (boundary.myboundary, inverse_boundary.pairedboundary);
03922   libmesh_assert_equal_to (boundary.pairedboundary, inverse_boundary.myboundary);
03923 
03924   // Allocate copies on the heap.  The _periodic_boundaries object will manage this memory.
03925   // Note: this also means that the copy constructor for the PeriodicBoundary (or user class
03926   // derived therefrom) must be implemented!
03927   // PeriodicBoundary* p_boundary = new PeriodicBoundary(boundary);
03928   // PeriodicBoundary* p_inverse_boundary = new PeriodicBoundary(inverse_boundary);
03929 
03930   // We can't use normal copy construction since this leads to slicing with derived classes.
03931   // Use clone() "virtual constructor" instead.  But, this *requires* user to override the clone()
03932   // method.  Note also that clone() allocates memory.  In this case, the _periodic_boundaries object
03933   // takes responsibility for cleanup.
03934   PeriodicBoundaryBase* p_boundary = boundary.clone().release();
03935   PeriodicBoundaryBase* p_inverse_boundary = inverse_boundary.clone().release();
03936 
03937   // Add the periodic boundary and its inverse to the PeriodicBoundaries data structure.  The
03938   // PeriodicBoundaries data structure takes ownership of the pointers.
03939   _periodic_boundaries->insert(std::make_pair(p_boundary->myboundary, p_boundary));
03940   _periodic_boundaries->insert(std::make_pair(p_inverse_boundary->myboundary, p_inverse_boundary));
03941 }
03942 
03943 
03944 #endif
03945 
03946 
03947 } // namespace libMesh