dof_map.C

Go to the documentation of this file.
00001 // $Id: dof_map.C 3504 2009-10-21 18:58:45Z knezed01 $
00002 
00003 // The libMesh Finite Element Library.
00004 // Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00005   
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License, or (at your option) any later version.
00010   
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public  License for more details.
00015   
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 
00021 
00022 // C++ Includes -------------------------------------
00023 #include <set>
00024 #include <algorithm> // for std::fill, std::equal_range, std::max, std::lower_bound, etc.
00025 
00026 // Local Includes -----------------------------------
00027 #include "coupling_matrix.h"
00028 #include "dense_matrix.h"
00029 #include "dense_vector_base.h"
00030 #include "dof_map.h"
00031 #include "elem.h"
00032 #include "fe_interface.h"
00033 #include "fe_type.h"
00034 #include "fe_base.h" // FEBase::build() for continuity test
00035 #include "libmesh_logging.h"
00036 #include "mesh_base.h"
00037 #include "mesh_tools.h"
00038 #include "numeric_vector.h"
00039 #include "parallel.h"
00040 #include "sparse_matrix.h"
00041 #include "string_to_enum.h"
00042 #include "threads_allocators.h"
00043 
00044 
00045 // ------------------------------------------------------------
00046 // DofMap member functions
00047 
00048 // Destructor
00049 DofMap::~DofMap()
00050 {
00051   this->clear();
00052 }
00053 
00054 
00055 
00056 void DofMap::add_variable (const System::Variable &var)
00057 {
00058   _variables.push_back (var);
00059 }
00060 
00061 
00062 
00063 const System::Variable & DofMap::variable (const unsigned int c) const
00064 {
00065   libmesh_assert (c < _variables.size());
00066 
00067   return _variables[c];
00068 }
00069 
00070 
00071 
00072 Order DofMap::variable_order (const unsigned int c) const
00073 {
00074   libmesh_assert (c < _variables.size());
00075 
00076   return _variables[c].type().order;
00077 }
00078 
00079 
00080 
00081 const FEType& DofMap::variable_type (const unsigned int c) const
00082 {
00083   libmesh_assert (c < _variables.size());
00084 
00085   return _variables[c].type();
00086 }
00087 
00088 
00089 
00090 void DofMap::attach_matrix (SparseMatrix<Number>& matrix)
00091 {
00092   _matrices.push_back(&matrix);
00093   
00094   matrix.attach_dof_map (*this);
00095 }
00096 
00097 
00098 
00099 DofObject* DofMap::node_ptr(MeshBase& mesh, unsigned int i) const
00100 {
00101   return mesh.node_ptr(i);
00102 }
00103 
00104 
00105 
00106 DofObject* DofMap::elem_ptr(MeshBase& mesh, unsigned int i) const
00107 {
00108   return mesh.elem(i);
00109 }
00110 
00111 
00112 
00113 template <typename iterator_type>
00114 void DofMap::set_nonlocal_dof_objects(iterator_type objects_begin,
00115                                       iterator_type objects_end,
00116                                       MeshBase &mesh,
00117                                       dofobject_accessor objects)
00118 {
00119   // This function must be run on all processors at once
00120   parallel_only();
00121 
00122   // First, iterate over local objects to find out how many
00123   // are on each processor
00124   std::vector<unsigned int>
00125     ghost_objects_from_proc(libMesh::n_processors(), 0);
00126 
00127   iterator_type it  = objects_begin;
00128 
00129   for (; it != objects_end; ++it)
00130     {
00131       DofObject *obj = *it;
00132 
00133       if (obj)
00134         {
00135           unsigned int obj_procid = obj->processor_id();
00136           // We'd better be completely partitioned by now
00137           libmesh_assert(obj_procid != DofObject::invalid_processor_id);
00138           ghost_objects_from_proc[obj_procid]++;
00139         }
00140     }
00141 
00142   std::vector<unsigned int> objects_on_proc(libMesh::n_processors(), 0);
00143   Parallel::allgather(ghost_objects_from_proc[libMesh::processor_id()],
00144                       objects_on_proc);
00145 
00146 #ifdef DEBUG
00147   for (unsigned int p=0; p != libMesh::n_processors(); ++p)
00148     libmesh_assert(ghost_objects_from_proc[p] <= objects_on_proc[p]);
00149 #endif
00150 
00151   // Request sets to send to each processor
00152   std::vector<std::vector<unsigned int> >
00153     requested_ids(libMesh::n_processors());
00154 
00155   // We know how many of our objects live on each processor, so
00156   // reserve() space for requests from each.
00157   for (unsigned int p=0; p != libMesh::n_processors(); ++p)
00158     if (p != libMesh::processor_id())
00159       requested_ids[p].reserve(ghost_objects_from_proc[p]);
00160 
00161   for (it = objects_begin; it != objects_end; ++it)
00162     {
00163       DofObject *obj = *it;
00164       if (obj->processor_id() != DofObject::invalid_processor_id)
00165         requested_ids[obj->processor_id()].push_back(obj->id());
00166     }
00167 #ifdef DEBUG
00168   for (unsigned int p=0; p != libMesh::n_processors(); ++p)
00169     libmesh_assert(requested_ids[p].size() == ghost_objects_from_proc[p]);
00170 #endif
00171 
00172   // Next set ghost object n_comps from other processors
00173   for (unsigned int p=1; p != libMesh::n_processors(); ++p)
00174     {
00175       // Trade my requests with processor procup and procdown
00176       unsigned int procup = (libMesh::processor_id() + p) %
00177                              libMesh::n_processors();
00178       unsigned int procdown = (libMesh::n_processors() +
00179                                libMesh::processor_id() - p) %
00180                                libMesh::n_processors();
00181       std::vector<unsigned int> request_to_fill;
00182       Parallel::send_receive(procup, requested_ids[procup],
00183                              procdown, request_to_fill);
00184 
00185       // Fill those requests
00186       const unsigned int n_variables = this->n_variables();
00187 
00188       std::vector<unsigned int> ghost_data
00189         (request_to_fill.size() * 2 * n_variables);
00190 
00191       for (unsigned int i=0; i != request_to_fill.size(); ++i)
00192         {
00193           DofObject *requested = (this->*objects)(mesh, request_to_fill[i]);
00194           libmesh_assert(requested);
00195           libmesh_assert(requested->processor_id() == libMesh::processor_id());
00196           libmesh_assert(requested->n_vars(this->sys_number()) == n_variables);
00197           for (unsigned int v=0; v != n_variables; ++v)
00198             {
00199               unsigned int n_comp =
00200                 requested->n_comp(this->sys_number(), v);
00201               ghost_data[i*2*n_variables+v] = n_comp;
00202               unsigned int first_dof = n_comp ?
00203                 requested->dof_number(this->sys_number(), v, 0) : 0;
00204               libmesh_assert(first_dof != DofObject::invalid_id);
00205               ghost_data[i*2*n_variables+n_variables+v] = first_dof;
00206             }
00207         }
00208 
00209       // Trade back the results
00210       std::vector<unsigned int> filled_request;
00211       Parallel::send_receive(procdown, ghost_data,
00212                              procup, filled_request);
00213 
00214       // And copy the id changes we've now been informed of
00215       libmesh_assert(filled_request.size() ==
00216              requested_ids[procup].size() * 2 * n_variables);
00217       for (unsigned int i=0; i != requested_ids[procup].size(); ++i)
00218         {
00219           DofObject *requested = (this->*objects)(mesh, requested_ids[procup][i]);
00220           libmesh_assert(requested);
00221           libmesh_assert (requested->processor_id() == procup);
00222           for (unsigned int v=0; v != n_variables; ++v)
00223             {
00224               unsigned int n_comp = filled_request[i*2*n_variables+v];
00225               requested->set_n_comp(this->sys_number(), v, n_comp);
00226               if (n_comp)
00227                 {
00228                   unsigned int first_dof = 
00229                     filled_request[i*2*n_variables+n_variables+v];
00230                   libmesh_assert(first_dof != DofObject::invalid_id);
00231                   requested->set_dof_number
00232                     (this->sys_number(), v, 0, first_dof);
00233 
00234                   // don't forget to add these remote dofs to the _send_list
00235                   for (unsigned int comp=0; comp!=n_comp; ++comp)
00236                     _send_list.push_back(first_dof+comp);
00237                 }
00238             }
00239         }
00240     }
00241 
00242 #ifdef DEBUG
00243   // Double check for invalid dofs
00244   for (it = objects_begin; it != objects_end; ++it)
00245     {
00246       DofObject *obj = *it;
00247       libmesh_assert (obj);
00248       unsigned int n_variables = obj->n_vars(this->sys_number());
00249       for (unsigned int v=0; v != n_variables; ++v)
00250         {
00251           unsigned int n_comp =
00252             obj->n_comp(this->sys_number(), v);
00253           unsigned int first_dof = n_comp ?
00254             obj->dof_number(this->sys_number(), v, 0) : 0;
00255           libmesh_assert(first_dof != DofObject::invalid_id);
00256         }
00257     }
00258 #endif
00259 }
00260 
00261 
00262 
00263 void DofMap::reinit(MeshBase& mesh)
00264 {
00265   libmesh_assert (mesh.is_prepared());
00266   
00267   START_LOG("reinit()", "DofMap");
00268   
00269   //this->clear();
00270 
00271   const unsigned int n_var = this->n_variables();
00272 
00273 #ifdef LIBMESH_ENABLE_AMR
00274   
00275   //------------------------------------------------------------
00276   // Clear the old_dof_objects for all the nodes
00277   // and elements so that we can overwrite them
00278   {
00279     MeshBase::node_iterator       node_it  = mesh.nodes_begin();
00280     const MeshBase::node_iterator node_end = mesh.nodes_end();
00281     
00282     for ( ; node_it != node_end; ++node_it)
00283       {
00284         (*node_it)->clear_old_dof_object();
00285         libmesh_assert ((*node_it)->old_dof_object == NULL);
00286       }
00287     
00288     MeshBase::element_iterator       elem_it  = mesh.elements_begin();
00289     const MeshBase::element_iterator elem_end = mesh.elements_end();
00290     
00291     for ( ; elem_it != elem_end; ++elem_it)
00292       {
00293         (*elem_it)->clear_old_dof_object();
00294         libmesh_assert ((*elem_it)->old_dof_object == NULL);
00295       }
00296   }
00297 
00298   
00299   //------------------------------------------------------------
00300   // Set the old_dof_objects for the elements that
00301   // weren't just created, if these old dof objects
00302   // had variables
00303   {
00304     MeshBase::element_iterator       elem_it  = mesh.elements_begin();
00305     const MeshBase::element_iterator elem_end = mesh.elements_end();
00306     
00307     for ( ; elem_it != elem_end; ++elem_it)
00308       {
00309         Elem* elem = *elem_it;
00310 
00311         // Skip the elements that were just refined
00312         if (elem->refinement_flag() == Elem::JUST_REFINED) continue;
00313 
00314         for (unsigned int n=0; n<elem->n_nodes(); n++)
00315           {
00316             Node* node = elem->get_node(n);
00317 
00318             if (node->old_dof_object == NULL)
00319               if (node->has_dofs())
00320                 node->set_old_dof_object();
00321           }
00322 
00323         libmesh_assert (elem->old_dof_object == NULL);
00324 
00325         if (elem->has_dofs())
00326           elem->set_old_dof_object();
00327       }
00328   }
00329 
00330 #endif // #ifdef LIBMESH_ENABLE_AMR
00331 
00332   
00333   //------------------------------------------------------------
00334   // Then set the number of variables for each \p DofObject
00335   // equal to n_variables() for this system.  This will
00336   // handle new \p DofObjects that may have just been created
00337   {
00338     // All the nodes
00339     MeshBase::node_iterator       node_it  = mesh.nodes_begin();
00340     const MeshBase::node_iterator node_end = mesh.nodes_end();
00341 
00342     for ( ; node_it != node_end; ++node_it)
00343       (*node_it)->set_n_vars(this->sys_number(),n_var);
00344 
00345     // All the elements
00346     MeshBase::element_iterator       elem_it  = mesh.elements_begin();
00347     const MeshBase::element_iterator elem_end = mesh.elements_end();
00348 
00349     for ( ; elem_it != elem_end; ++elem_it)
00350       (*elem_it)->set_n_vars(this->sys_number(),n_var);
00351   }
00352 
00353 
00354   // Zero _n_SCALAR_dofs, it will be updated below.
00355   this->_n_SCALAR_dofs = 0;
00356 
00357   //------------------------------------------------------------
00358   // Next allocate space for the DOF indices
00359   for (unsigned int var=0; var<this->n_variables(); var++)
00360     {
00361       const System::Variable &var_description = this->variable(var);
00362       const FEType& base_fe_type              = this->variable_type(var);
00363 
00364       // Don't need to loop over elements for a SCALAR variable
00365       // Just increment _n_SCALAR_dofs
00366       if(base_fe_type.family == SCALAR)
00367       {
00368         this->_n_SCALAR_dofs += base_fe_type.order;
00369         continue;
00370       }
00371 
00372       // This should be constant even on p-refined elements
00373       const bool extra_hanging_dofs =
00374         FEInterface::extra_hanging_dofs(base_fe_type);
00375 
00376       // For all the active elements
00377       MeshBase::element_iterator       elem_it  = mesh.active_elements_begin();
00378       const MeshBase::element_iterator elem_end = mesh.active_elements_end(); 
00379  
00380       // Count vertex degrees of freedom first
00381       for ( ; elem_it != elem_end; ++elem_it)
00382         {
00383           Elem* elem  = *elem_it;
00384           libmesh_assert (elem != NULL);
00385           
00386           // Skip the numbering if this variable is 
00387           // not active on this element's subdoman
00388           if (!var_description.active_on_subdomain(elem->subdomain_id()))
00389             continue;
00390 
00391           const ElemType type = elem->type();
00392           const unsigned int dim = elem->dim();
00393 
00394           FEType fe_type = base_fe_type;
00395 
00396 #ifdef LIBMESH_ENABLE_AMR
00397           // Make sure we haven't done more p refinement than we can
00398           // handle
00399           if (elem->p_level() + base_fe_type.order >
00400               FEInterface::max_order(base_fe_type, type))
00401             {
00402 #  ifdef DEBUG
00403               if (FEInterface::max_order(base_fe_type,type) <
00404                   static_cast<unsigned int>(base_fe_type.order))
00405                 {
00406                   std::cerr << "ERROR: Finite element "
00407                     << Utility::enum_to_string(base_fe_type.family)
00408                     << " on geometric element "
00409                     << Utility::enum_to_string(type) << std::endl
00410                     << "only supports FEInterface::max_order = " 
00411                     << FEInterface::max_order(base_fe_type,type)
00412                     << ", not fe_type.order = " << base_fe_type.order
00413                     << std::endl;
00414 
00415                   libmesh_error();
00416                 }
00417 
00418               std::cerr << "WARNING: Finite element "
00419                     << Utility::enum_to_string(base_fe_type.family)
00420                     << " on geometric element "
00421                     << Utility::enum_to_string(type) << std::endl
00422                     << "could not be p refined past FEInterface::max_order = " 
00423                     << FEInterface::max_order(base_fe_type,type)
00424                     << std::endl;
00425 #  endif
00426               elem->set_p_level(FEInterface::max_order(base_fe_type,type)
00427                                 - base_fe_type.order);
00428             }
00429 #endif
00430 
00431           fe_type.order = static_cast<Order>(fe_type.order +
00432                                              elem->p_level());
00433              
00434           // Allocate the vertex DOFs
00435           for (unsigned int n=0; n<elem->n_nodes(); n++)
00436             {
00437               Node* node = elem->get_node(n);
00438 
00439               if (elem->is_vertex(n))
00440                 {
00441                   const unsigned int old_node_dofs =
00442                     node->n_comp(this->sys_number(), var);
00443 
00444                   const unsigned int vertex_dofs =
00445                     std::max(FEInterface::n_dofs_at_node(dim, fe_type,
00446                                                          type, n),
00447                              old_node_dofs);
00448                   
00449                   // Some discontinuous FEs have no vertex dofs
00450                   if (vertex_dofs > old_node_dofs)
00451                     {
00452                       node->set_n_comp(this->sys_number(), var,
00453                                        vertex_dofs);
00454                       // Abusing dof_number to set a "this is a
00455                       // vertex" flag
00456                       node->set_dof_number(this->sys_number(),
00457                                            var, 0, vertex_dofs);
00458                     }
00459                 }
00460             }
00461         } // done counting vertex dofs
00462 
00463       // count edge & face dofs next
00464       elem_it = mesh.active_elements_begin();
00465 
00466       for ( ; elem_it != elem_end; ++elem_it)
00467         {
00468           Elem* elem = *elem_it;
00469           libmesh_assert (elem != NULL);
00470           
00471           // Skip the numbering if this variable is 
00472           // not active on this element's subdoman
00473           if (!var_description.active_on_subdomain(elem->subdomain_id()))
00474             continue;
00475 
00476           const ElemType type = elem->type();
00477           const unsigned int dim = elem->dim();
00478              
00479           FEType fe_type = base_fe_type;
00480           fe_type.order = static_cast<Order>(fe_type.order +
00481                                              elem->p_level());
00482 
00483           // Allocate the edge and face DOFs
00484           for (unsigned int n=0; n<elem->n_nodes(); n++)
00485             {
00486               Node* node = elem->get_node(n);
00487 
00488               const unsigned int old_node_dofs =
00489                 node->n_comp(this->sys_number(), var);
00490 
00491               const unsigned int vertex_dofs = old_node_dofs?
00492                 node->dof_number (this->sys_number(),var,0):0;
00493 
00494               const unsigned int new_node_dofs =
00495                 FEInterface::n_dofs_at_node(dim, fe_type, type, n);
00496 
00497               // We've already allocated vertex DOFs
00498               if (elem->is_vertex(n))
00499                 {
00500                   libmesh_assert(old_node_dofs >= vertex_dofs);
00501                   libmesh_assert(vertex_dofs >= new_node_dofs);
00502                 }
00503               // We need to allocate the rest
00504               else
00505                 {
00506                   // If this has no dofs yet, it needs no vertex
00507                   // dofs, so we just give it edge or face dofs
00508                   if (!old_node_dofs)
00509                     {
00510                       node->set_n_comp(this->sys_number(), var,
00511                                        new_node_dofs);
00512                       // Abusing dof_number to set a "this has no
00513                       // vertex dofs" flag
00514                       if (new_node_dofs)
00515                         node->set_dof_number(this->sys_number(),
00516                                              var, 0, 0);
00517                     }
00518 
00519                   // If this has dofs, but has no vertex dofs,
00520                   // it may still need more edge or face dofs if
00521                   // we're p-refined.
00522                   else if (vertex_dofs == 0)
00523                     {
00524                       if (new_node_dofs > old_node_dofs)
00525                         {
00526                           node->set_n_comp(this->sys_number(), var,
00527                                            new_node_dofs);
00528                           node->set_dof_number(this->sys_number(),
00529                                                var, 0, vertex_dofs);
00530                         }
00531                     }
00532                   // If this is another element's vertex,
00533                   // add more (non-overlapping) edge/face dofs if
00534                   // necessary
00535                   else if (extra_hanging_dofs)
00536                     {
00537                       if (new_node_dofs > old_node_dofs - vertex_dofs)
00538                         {
00539                           node->set_n_comp(this->sys_number(), var,
00540                                            vertex_dofs + new_node_dofs);
00541                           node->set_dof_number(this->sys_number(),
00542                                                var, 0, vertex_dofs);
00543                         }
00544                     }
00545                   // If this is another element's vertex, add any
00546                   // (overlapping) edge/face dofs if necessary
00547                   else
00548                     {
00549                       libmesh_assert(old_node_dofs >= vertex_dofs);
00550                       if (new_node_dofs > old_node_dofs)
00551                         {
00552                           node->set_n_comp(this->sys_number(), var,
00553                                            new_node_dofs);
00554                           node->set_dof_number(this->sys_number(),
00555                                                var, 0, vertex_dofs);
00556                         }
00557                     }
00558                 }
00559             }
00560           // Allocate the element DOFs
00561           const unsigned int dofs_per_elem =
00562                           FEInterface::n_dofs_per_elem(dim, fe_type,
00563                                                        type);
00564 
00565           elem->set_n_comp(this->sys_number(), var, dofs_per_elem);
00566 
00567         }
00568     }
00569 
00570   // Calling DofMap::reinit() by itself makes little sense,
00571   // so we won't bother with nonlocal DofObjects.
00572   // Those will be fixed by distribute_dofs
00573 /*
00574   //------------------------------------------------------------
00575   // At this point, all n_comp and dof_number values on local
00576   // DofObjects should be correct, but a ParallelMesh might have
00577   // incorrect values on non-local DofObjects.  Let's request the
00578   // correct values from each other processor.
00579 
00580   this->set_nonlocal_n_comps(mesh.nodes_begin(),
00581                              mesh.nodes_end(),
00582                              mesh,
00583                              &DofMap::node_ptr);
00584 
00585   this->set_nonlocal_n_comps(mesh.elements_begin(),
00586                              mesh.elements_end(),
00587                              mesh,
00588                              &DofMap::elem_ptr);
00589 */
00590 
00591   //------------------------------------------------------------
00592   // Finally, clear all the current DOF indices
00593   // (distribute_dofs expects them cleared!)
00594   this->invalidate_dofs(mesh);
00595   
00596   STOP_LOG("reinit()", "DofMap");
00597 }
00598 
00599 
00600 
00601 void DofMap::invalidate_dofs(MeshBase& mesh) const
00602 {
00603   const unsigned int sys_num = this->sys_number();
00604 
00605   // All the nodes
00606   MeshBase::node_iterator       node_it  = mesh.nodes_begin();
00607   const MeshBase::node_iterator node_end = mesh.nodes_end();
00608 
00609   for ( ; node_it != node_end; ++node_it)
00610     (*node_it)->invalidate_dofs(sys_num);
00611   
00612   // All the elements
00613   MeshBase::element_iterator       elem_it  = mesh.active_elements_begin();
00614   const MeshBase::element_iterator elem_end = mesh.active_elements_end(); 
00615 
00616   for ( ; elem_it != elem_end; ++elem_it)
00617     (*elem_it)->invalidate_dofs(sys_num);
00618 }
00619 
00620 
00621 
00622 void DofMap::clear()
00623 {
00624   // we don't want to clear
00625   // the coupling matrix!
00626   // It should not change...
00627   //_dof_coupling->clear();
00628 
00629   _variables.clear();  
00630   _first_df.clear();
00631   _end_df.clear();
00632   _var_first_local_df.clear();
00633   _send_list.clear();
00634   _n_nz.clear();
00635   _n_oz.clear();
00636 
00637 
00638 #ifdef LIBMESH_ENABLE_AMR
00639 
00640   _dof_constraints.clear();
00641   _n_old_dfs = 0;
00642 
00643 #endif
00644 
00645   _matrices.clear();
00646 
00647   _n_dfs = 0;
00648 }
00649 
00650 
00651 
00652 void DofMap::distribute_dofs (MeshBase& mesh)
00653 {
00654   // This function must be run on all processors at once
00655   parallel_only();
00656 
00657   // Log how long it takes to distribute the degrees of freedom
00658   START_LOG("distribute_dofs()", "DofMap");
00659 
00660   libmesh_assert (mesh.is_prepared());
00661 
00662   const unsigned int proc_id = libMesh::processor_id();
00663   const unsigned int n_proc  = libMesh::n_processors();
00664   
00665 //  libmesh_assert (this->n_variables() > 0);
00666   libmesh_assert (proc_id < n_proc);
00667   
00668   // re-init in case the mesh has changed
00669   this->reinit(mesh);
00670   
00671   // By default distribute variables in a
00672   // var-major fashion, but allow run-time
00673   // specification
00674   bool node_major_dofs = libMesh::on_command_line ("--node_major_dofs");
00675 
00676   // The DOF counter, will be incremented as we encounter
00677   // new degrees of freedom
00678   unsigned int next_free_dof = 0;
00679 
00680   // Clear the send list before we rebuild it
00681   _send_list.clear();
00682 
00683   // Set temporary DOF indices on this processor
00684   if (node_major_dofs)
00685     this->distribute_local_dofs_node_major (next_free_dof, mesh);
00686   else
00687     this->distribute_local_dofs_var_major (next_free_dof, mesh);
00688 
00689   // Get DOF counts on all processors
00690   std::vector<unsigned int> dofs_on_proc(n_proc, 0);
00691   Parallel::allgather(next_free_dof, dofs_on_proc);
00692 
00693   // Resize the _first_df and _end_df arrays
00694   _first_df.resize(n_proc);
00695   _end_df.resize (n_proc);
00696 
00697   // Get DOF offsets
00698   _first_df[0] = 0;
00699   for (unsigned int i=1; i < n_proc; ++i)
00700     _first_df[i] = _end_df[i-1] = _first_df[i-1] + dofs_on_proc[i-1];
00701   _end_df[n_proc-1] = _first_df[n_proc-1] + dofs_on_proc[n_proc-1];
00702 
00703   // Clear all the current DOF indices
00704   // (distribute_dofs expects them cleared!)
00705   this->invalidate_dofs(mesh);
00706 
00707   next_free_dof = _first_df[proc_id];
00708 
00709   // Set permanent DOF indices on this processor
00710   if (node_major_dofs)
00711     this->distribute_local_dofs_node_major (next_free_dof, mesh);
00712   else
00713     this->distribute_local_dofs_var_major (next_free_dof, mesh);
00714 
00715   libmesh_assert(next_free_dof == _end_df[proc_id]);
00716 
00717   //------------------------------------------------------------
00718   // At this point, all n_comp and dof_number values on local
00719   // DofObjects should be correct, but a ParallelMesh might have
00720   // incorrect values on non-local DofObjects.  Let's request the
00721   // correct values from each other processor.
00722 
00723   if (libMesh::n_processors() > 1)
00724     {
00725       this->set_nonlocal_dof_objects(mesh.nodes_begin(),
00726                                      mesh.nodes_end(),
00727                                      mesh, &DofMap::node_ptr);
00728 
00729       this->set_nonlocal_dof_objects(mesh.elements_begin(),
00730                                      mesh.elements_end(),
00731                                      mesh, &DofMap::elem_ptr);
00732     }
00733   
00734   // Set the total number of degrees of freedom
00735 #ifdef LIBMESH_ENABLE_AMR
00736   _n_old_dfs = _n_dfs;
00737 #endif
00738   _n_dfs = _end_df[n_proc-1];
00739 
00740   STOP_LOG("distribute_dofs()", "DofMap");
00741 
00742   // Note that in the add_neighbors_to_send_list nodes on processor
00743   // boundaries that are shared by multiple elements are added for
00744   // each element.
00745   this->add_neighbors_to_send_list(mesh);
00746   
00747   // Here we used to clean up that data structure; now System and
00748   // EquationSystems call that for us, after we've added constraint
00749   // dependencies to the send_list too.
00750   // this->sort_send_list ();
00751 }
00752 
00753 
00754 void DofMap::distribute_local_dofs_node_major(unsigned int &next_free_dof,
00755                                               MeshBase& mesh)
00756 {
00757   const unsigned int sys_num = this->sys_number();
00758   const unsigned int n_vars  = this->n_variables();
00759 
00760   // We now only add remote dofs to the _send_list
00761   // unsigned int send_list_size = 0;
00762 
00763   // _var_first_local_df does not work with node_major dofs
00764   _var_first_local_df.resize(n_vars+1);
00765   std::fill (_var_first_local_df.begin(),
00766              _var_first_local_df.end(),
00767              DofObject::invalid_id);
00768 
00769   //-------------------------------------------------------------------------
00770   // First count and assign temporary numbers to local dofs
00771   MeshBase::element_iterator       elem_it  = mesh.active_local_elements_begin();
00772   const MeshBase::element_iterator elem_end = mesh.active_local_elements_end();  
00773   
00774   for ( ; elem_it != elem_end; ++elem_it)
00775     {
00776       // Only number dofs connected to active
00777       // elements on this processor.
00778       Elem* elem                 = *elem_it;
00779       const unsigned int n_nodes = elem->n_nodes();
00780       
00781       // First number the nodal DOFS
00782       for (unsigned int n=0; n<n_nodes; n++)
00783         {
00784           Node* node = elem->get_node(n);
00785 
00786           for (unsigned var=0; var<n_vars; var++)
00787           {
00788               if( (this->variable(var).type().family != SCALAR) &&
00789                   (this->variable(var).active_on_subdomain(elem->subdomain_id())) )
00790               {
00791                 // assign dof numbers (all at once) if this is
00792                 // our node and if they aren't already there
00793                 if ((node->n_comp(sys_num,var) > 0) &&
00794                     (node->processor_id() == libMesh::processor_id()) &&
00795                     (node->dof_number(sys_num,var,0) ==
00796                      DofObject::invalid_id))
00797                   {
00798                     node->set_dof_number(sys_num,
00799                                          var,
00800                                          0,
00801                                          next_free_dof);
00802                     next_free_dof += node->n_comp(sys_num,var);
00803                   }
00804               }
00805           }
00806         }
00807 
00808       // Now number the element DOFS
00809       for (unsigned var=0; var<n_vars; var++)
00810         if ( (this->variable(var).type().family != SCALAR) &&
00811              (this->variable(var).active_on_subdomain(elem->subdomain_id())) )
00812           if (elem->n_comp(sys_num,var) > 0)
00813             {
00814               libmesh_assert (elem->dof_number(sys_num,var,0) ==
00815                               DofObject::invalid_id);
00816 
00817               elem->set_dof_number(sys_num,
00818                                    var,
00819                                    0,
00820                                    next_free_dof);
00821 
00822               next_free_dof += elem->n_comp(sys_num,var);
00823             }
00824     } // done looping over elements
00825 
00826   // Finally, count up the SCALAR dofs
00827   this->_n_SCALAR_dofs = 0;
00828   for (unsigned var=0; var<n_vars; var++)
00829     {
00830       if( this->variable(var).type().family == SCALAR )
00831         {
00832           this->_n_SCALAR_dofs += this->variable(var).type().order;
00833           continue;
00834         }
00835     }
00836 
00837   // Only increment next_free_dof if we're on the processor
00838   // that holds this SCALAR variable
00839   if ( libMesh::processor_id() == (libMesh::n_processors()-1) )
00840     next_free_dof += _n_SCALAR_dofs;
00841 
00842 #ifdef DEBUG
00843 // Make sure we didn't miss any nodes
00844   MeshTools::libmesh_assert_valid_node_procids(mesh);
00845 
00846   MeshBase::node_iterator       node_it  = mesh.local_nodes_begin();
00847   const MeshBase::node_iterator node_end = mesh.local_nodes_end();
00848   for (; node_it != node_end; ++node_it)
00849     {
00850       Node *obj = *node_it;
00851       libmesh_assert(obj);
00852       unsigned int n_variables = obj->n_vars(this->sys_number());
00853       for (unsigned int v=0; v != n_variables; ++v)
00854         {
00855           unsigned int n_comp =
00856             obj->n_comp(this->sys_number(), v);
00857           unsigned int first_dof = n_comp ?
00858             obj->dof_number(this->sys_number(), v, 0) : 0;
00859           libmesh_assert(first_dof != DofObject::invalid_id);
00860         }
00861     }
00862 #endif // DEBUG
00863 }
00864 
00865 
00866 
00867 void DofMap::distribute_local_dofs_var_major(unsigned int &next_free_dof,
00868                                              MeshBase& mesh)
00869 {
00870   const unsigned int sys_num = this->sys_number();
00871   const unsigned int n_vars  = this->n_variables();
00872 
00873   // We now only add remote dofs to the _send_list
00874   // unsigned int send_list_size = 0;
00875 
00876   // We will cache the first local index for each variable
00877   _var_first_local_df.clear();
00878 
00879   //-------------------------------------------------------------------------
00880   // First count and assign temporary numbers to local dofs
00881   for (unsigned var=0; var<n_vars; var++)
00882     {
00883       _var_first_local_df.push_back(next_free_dof);
00884 
00885       const System::Variable var_description = this->variable(var);
00886 
00887       // Skip the SCALAR dofs
00888       if(var_description.type().family == SCALAR)
00889         continue;
00890 
00891       MeshBase::element_iterator       elem_it  = mesh.active_local_elements_begin();
00892       const MeshBase::element_iterator elem_end = mesh.active_local_elements_end();
00893 
00894       for ( ; elem_it != elem_end; ++elem_it)
00895         {
00896           // Only number dofs connected to active
00897           // elements on this processor.
00898           Elem* elem  = *elem_it;
00899 
00900           // ... and only variables which are active on
00901           // on this element's subdomain
00902           if (!var_description.active_on_subdomain(elem->subdomain_id()))
00903             continue;
00904 
00905           const unsigned int n_nodes = elem->n_nodes();
00906           
00907           // First number the nodal DOFS
00908           for (unsigned int n=0; n<n_nodes; n++)
00909             {
00910               Node* node = elem->get_node(n);
00911               
00912               // assign dof numbers (all at once) if this is
00913               // our node and if they aren't already there
00914               if ((node->n_comp(sys_num,var) > 0) &&
00915                   (node->processor_id() == libMesh::processor_id()) &&
00916                   (node->dof_number(sys_num,var,0) ==
00917                    DofObject::invalid_id))
00918                 {
00919                   node->set_dof_number(sys_num,
00920                                        var,
00921                                        0,
00922                                        next_free_dof);
00923                   next_free_dof += node->n_comp(sys_num,var);
00924                 }
00925             }
00926                   
00927           // Now number the element DOFS
00928           if (elem->n_comp(sys_num,var) > 0)
00929             {
00930               libmesh_assert (elem->dof_number(sys_num,var,0) ==
00931                       DofObject::invalid_id);
00932 
00933               elem->set_dof_number(sys_num,
00934                                    var,
00935                                    0,
00936                                    next_free_dof);
00937 
00938               next_free_dof += elem->n_comp(sys_num,var);
00939             }
00940         } // end loop on elements
00941     } // end loop on variables
00942 
00943   // Finally, count up the SCALAR dofs
00944   this->_n_SCALAR_dofs = 0;
00945   for (unsigned var=0; var<n_vars; var++)
00946     {
00947       if( this->variable(var).type().family == SCALAR )
00948         {
00949           this->_n_SCALAR_dofs += this->variable(var).type().order;
00950           continue;
00951         }
00952     }
00953 
00954   // Only increment next_free_dof if we're on the processor
00955   // that holds this SCALAR variable
00956   if ( libMesh::processor_id() == (libMesh::n_processors()-1) )
00957     next_free_dof += _n_SCALAR_dofs;
00958 
00959   // Cache the last local dof number too
00960   _var_first_local_df.push_back(next_free_dof);
00961 
00962 #ifdef DEBUG
00963   // Make sure we didn't miss any nodes
00964   MeshTools::libmesh_assert_valid_node_procids(mesh);
00965 
00966   MeshBase::node_iterator       node_it  = mesh.local_nodes_begin();
00967   const MeshBase::node_iterator node_end = mesh.local_nodes_end();
00968   for (; node_it != node_end; ++node_it)
00969     {
00970       Node *obj = *node_it;
00971       libmesh_assert(obj);
00972       unsigned int n_variables = obj->n_vars(this->sys_number());
00973       for (unsigned int v=0; v != n_variables; ++v)
00974         {
00975           unsigned int n_comp =
00976             obj->n_comp(this->sys_number(), v);
00977           unsigned int first_dof = n_comp ?
00978             obj->dof_number(this->sys_number(), v, 0) : 0;
00979           libmesh_assert(first_dof != DofObject::invalid_id);
00980         }
00981     }
00982 #endif // DEBUG
00983 }
00984 
00985 
00986 
00987 void DofMap::add_neighbors_to_send_list(MeshBase& mesh)
00988 {
00989   START_LOG("add_neighbors_to_send_list()", "DofMap");
00990   
00991   //-------------------------------------------------------------------------
00992   // We need to add the DOFs from elements that live on neighboring processors
00993   // that are neighbors of the elements on the local processor
00994   //-------------------------------------------------------------------------
00995 
00996   MeshBase::const_element_iterator       local_elem_it
00997     = mesh.active_local_elements_begin();
00998   const MeshBase::const_element_iterator local_elem_end
00999     = mesh.active_local_elements_end(); 
01000 
01001   std::vector<bool> node_on_processor(mesh.max_node_id(), false);
01002   std::vector<unsigned int> di;
01003   std::vector<const Elem *> family;
01004 
01005   // Loop over the active local elements, adding all active elements
01006   // that neighbor an active local element to the send list.
01007   for ( ; local_elem_it != local_elem_end; ++local_elem_it)
01008     {
01009       const Elem* elem = *local_elem_it;
01010 
01011       // Flag all the nodes of active local elements as seen
01012       for (unsigned int n=0; n!=elem->n_nodes(); n++)
01013         node_on_processor[elem->node(n)] = true;
01014 
01015       // Loop over the neighbors of those elements
01016       for (unsigned int s=0; s<elem->n_neighbors(); s++)
01017         if (elem->neighbor(s) != NULL)
01018           {
01019             family.clear();
01020             
01021             // Find all the active elements that neighbor elem
01022 #ifdef LIBMESH_ENABLE_AMR
01023             if (!elem->neighbor(s)->active())
01024               elem->neighbor(s)->active_family_tree_by_neighbor(family, elem);
01025             else
01026 #endif
01027               family.push_back(elem->neighbor(s));
01028 
01029             for (unsigned int i=0; i!=family.size(); ++i)
01030               // If the neighbor lives on a different processor
01031               if (family[i]->processor_id() != libMesh::processor_id())
01032                 {
01033                   // Get the DOF indices for this neighboring element
01034                   this->dof_indices (family[i], di);
01035 
01036                   // Insert the remote DOF indices into the send list
01037                   for (unsigned int j=0; j != di.size(); ++j)
01038                     if (di[j] < this->first_dof() ||
01039                         di[j] >= this->end_dof())
01040                       _send_list.push_back(di[j]);
01041                 }
01042           }
01043     }
01044 
01045   // Now loop over all non_local active elements and add any missing
01046   // nodal-only neighbors
01047   MeshBase::const_element_iterator       elem_it
01048     = mesh.active_elements_begin();
01049   const MeshBase::const_element_iterator elem_end
01050     = mesh.active_elements_end();
01051   
01052   for ( ; elem_it != elem_end; ++elem_it)
01053     {
01054       const Elem* elem = *elem_it;
01055 
01056       // If this is one of our elements, we've already added it
01057       if (elem->processor_id() == libMesh::processor_id())
01058         continue;
01059 
01060       // Do we need to add the element DOFs?
01061       bool add_elem_dofs = false;
01062       
01063       // Check all the nodes of the element to see if it
01064       // shares a node with us
01065       for (unsigned int n=0; n!=elem->n_nodes(); n++)
01066         if (node_on_processor[elem->node(n)])
01067           add_elem_dofs = true;
01068 
01069       // Add the element degrees of freedom if it shares at
01070       // least one node.
01071       if (add_elem_dofs)
01072         {
01073           // Get the DOF indices for this neighboring element
01074           this->dof_indices (elem, di);
01075 
01076           // Insert the remote DOF indices into the send list
01077             for (unsigned int j=0; j != di.size(); ++j)
01078               if (di[j] < this->first_dof() ||
01079                   di[j] >= this->end_dof())
01080                 _send_list.push_back(di[j]);
01081         }
01082     }
01083   
01084   STOP_LOG("add_neighbors_to_send_list()", "DofMap");
01085 }
01086 
01087 
01088 
01089 void DofMap::prepare_send_list ()
01090 {
01091   START_LOG("prepare_send_list()", "DofMap");
01092   
01093   // First sort the send list.  After this
01094   // duplicated elements will be adjacent in the
01095   // vector
01096   std::sort(_send_list.begin(), _send_list.end());
01097 
01098   // Now use std::unique to remove duplicate entries  
01099   std::vector<unsigned int>::iterator new_end =
01100     std::unique (_send_list.begin(), _send_list.end());
01101 
01102   // Remove the end of the send_list.  Use the "swap trick"
01103   // from Effective STL
01104   std::vector<unsigned int> (_send_list.begin(), new_end).swap (_send_list);
01105   
01106   STOP_LOG("prepare_send_list()", "DofMap");
01107 }
01108 
01109 
01110 
01111 bool DofMap::use_coupled_neighbor_dofs(const MeshBase& mesh) const
01112 {
01113   // If we were asked on the command line, then we need to
01114   // include sensitivities between neighbor degrees of freedom
01115   bool implicit_neighbor_dofs = 
01116     libMesh::on_command_line ("--implicit_neighbor_dofs");
01117 
01118   // look at all the variables in this system.  If every one is
01119   // discontinuous then the user must be doing DG/FVM, so be nice
01120   // and  force implicit_neighbor_dofs=true
01121   {
01122     bool all_discontinuous_dofs = true;
01123     
01124     for (unsigned int var=0; var<this->n_variables(); var++)
01125       if (FEBase::build (mesh.mesh_dimension(),
01126                          this->variable_type(var))->get_continuity() !=  DISCONTINUOUS)
01127         all_discontinuous_dofs = false;
01128 
01129     if (all_discontinuous_dofs)
01130       implicit_neighbor_dofs = true;
01131   }
01132   
01133   return implicit_neighbor_dofs;
01134 }
01135 
01136 
01137 
01138 void DofMap::compute_sparsity(const MeshBase& mesh)
01139 {
01140   libmesh_assert (mesh.is_prepared());
01141   libmesh_assert (this->n_variables());
01142 
01143   START_LOG("compute_sparsity()", "DofMap");
01144 
01145   // Compute the sparsity structure of the global matrix.  This can be
01146   // fed into a PetscMatrix to allocate exacly the number of nonzeros
01147   // necessary to store the matrix.  This algorithm should be linear
01148   // in the (# of elements)*(# nodes per element)
01149 
01150   // We can be more efficient in the threaded sparsity pattern assembly
01151   // if we don't need the exact pattern.  For some sparse matrix formats
01152   // a good upper bound will suffice.
01153   bool need_full_sparsity_pattern=false;
01154   std::vector<SparseMatrix<Number>* >::iterator
01155     pos = _matrices.begin(),
01156     end = _matrices.end();
01157       
01158   for (; pos != end; ++pos)
01159     if ((*pos)->need_full_sparsity_pattern())
01160       need_full_sparsity_pattern = true;
01161 
01162   // See if we need to include sparsity pattern entries for coupling
01163   // between neighbor dofs
01164   bool implicit_neighbor_dofs = this->use_coupled_neighbor_dofs(mesh);
01165   
01166   // We can compute the sparsity pattern in parallel on multiple
01167   // threads.  The goal is for each thread to compute the full sparsity
01168   // pattern for a subset of elements.  These sparsity patterns can
01169   // be efficiently merged in the SparsityPattern::Build::join()
01170   // method, especially if there is not too much overlap between them.
01171   // Even better, if the full sparsity pattern is not needed then
01172   // the number of nonzeros per row can be estimated from the
01173   // sparsity patterns created on each thread.
01174   SparsityPattern::Build sp (mesh,
01175                              *this,
01176                              _dof_coupling,
01177                              implicit_neighbor_dofs,
01178                              need_full_sparsity_pattern);
01179   
01180   Threads::parallel_reduce (ConstElemRange (mesh.active_elements_begin(),
01181                                             mesh.active_elements_end()), sp);
01182 
01183 #ifndef NDEBUG
01184   // Avoid declaring these variables unless asserts are enabled.
01185   const unsigned int proc_id        = mesh.processor_id();
01186   const unsigned int n_dofs_on_proc = this->n_dofs_on_processor(proc_id);
01187 #endif
01188   libmesh_assert (sp.sparsity_pattern.size() == n_dofs_on_proc);
01189 
01190   // steal the n_nz and n_oz arrays from sp -- it won't need them any more,
01191   // and this is more efficient than copying them.
01192   _n_nz.swap(sp.n_nz);
01193   _n_oz.swap(sp.n_oz);
01194   
01195   STOP_LOG("compute_sparsity()", "DofMap");
01196   
01197   // We are done with the sparsity_pattern.  However, quite a
01198   // lot has gone into computing it.  It is possible that some
01199   // \p SparseMatrix implementations want to see it.  Let them
01200   // see it before we throw it away.
01201   pos = _matrices.begin();
01202   end = _matrices.end();
01203       
01204   for (; pos != end; ++pos)
01205     (*pos)->update_sparsity_pattern (sp.sparsity_pattern);     
01206 }
01207 
01208 
01209 
01210 void DofMap::extract_local_vector (const NumericVector<Number>& Ug,
01211                                    const std::vector<unsigned int>& dof_indices,
01212                                    DenseVectorBase<Number>& Ue) const
01213 {
01214 #ifdef LIBMESH_ENABLE_AMR
01215 
01216   // Trivial mapping
01217   libmesh_assert (dof_indices.size() == Ue.size());
01218   bool has_constrained_dofs = false;
01219 
01220   for (unsigned int il=0; il<dof_indices.size(); il++)
01221     {
01222       const unsigned int ig = dof_indices[il];
01223 
01224       if (this->is_constrained_dof (ig)) has_constrained_dofs = true;
01225       
01226       libmesh_assert ((il >= Ug.first_local_index()) &&
01227               (il <  Ug.last_local_index()));
01228 
01229       Ue.el(il) = Ug(ig);
01230     }
01231 
01232   // If the element has any constrained DOFs then we need
01233   // to account for them in the mapping.  This will handle
01234   // the case that the input vector is not constrained.
01235   if (has_constrained_dofs)
01236     {
01237       // Copy the input DOF indices.
01238       std::vector<unsigned int> constrained_dof_indices(dof_indices);
01239 
01240       DenseMatrix<Number> C;
01241 
01242       this->build_constraint_matrix (C, constrained_dof_indices);
01243 
01244       libmesh_assert (dof_indices.size()             == C.m());
01245       libmesh_assert (constrained_dof_indices.size() == C.n());
01246 
01247       // zero-out Ue
01248       Ue.zero();
01249 
01250       // compute Ue = C Ug, with proper mapping.
01251       for (unsigned int i=0; i<dof_indices.size(); i++)
01252         for (unsigned int j=0; j<constrained_dof_indices.size(); j++)
01253           {
01254             const unsigned int jg = constrained_dof_indices[j];
01255 
01256             libmesh_assert ((jg >= Ug.first_local_index()) &&
01257                     (jg <  Ug.last_local_index()));
01258             
01259             Ue.el(i) += C(i,j)*Ug(jg);      
01260           }
01261     }  
01262    
01263 #else
01264   
01265   // Trivial mapping
01266   libmesh_assert (dof_indices.size() == Ue.size());
01267   
01268   for (unsigned int il=0; il<dof_indices.size(); il++)
01269     {
01270       const unsigned int ig = dof_indices[il];
01271       
01272       libmesh_assert ((ig >= Ug.first_local_index()) && (ig <  Ug.last_local_index()));
01273 
01274       Ue.el(il) = Ug(ig);
01275     }
01276   
01277 #endif
01278 }
01279 
01280 void DofMap::dof_indices (const Elem* const elem,
01281                           std::vector<unsigned int>& di,
01282                           const unsigned int vn) const
01283 {
01284   START_LOG("dof_indices()", "DofMap");
01285   
01286   libmesh_assert (elem != NULL);
01287   
01288   const unsigned int n_nodes = elem->n_nodes();
01289   const ElemType type        = elem->type();
01290   const unsigned int sys_num = this->sys_number();
01291   const unsigned int n_vars  = this->n_variables();
01292   const unsigned int dim     = elem->dim();
01293   
01294   // Clear the DOF indices vector
01295   di.clear();
01296   
01297 #ifdef DEBUG
01298   // Check that sizes match in DEBUG mode
01299   unsigned int tot_size = 0;
01300 #endif
01301 
01302   // Create a vector to indicate which
01303   // SCALAR variables have been requested
01304   std::vector<unsigned int> SCALAR_var_numbers;
01305   SCALAR_var_numbers.clear();
01306 
01307   // Get the dof numbers
01308   for (unsigned int v=0; v<n_vars; v++)
01309     if ((v == vn) || (vn == libMesh::invalid_uint))
01310     {
01311       if(this->variable(v).type().family == SCALAR)
01312       {
01313         // We asked for this variable, so add it to the vector.
01314         SCALAR_var_numbers.push_back(v);
01315 
01316 #ifdef DEBUG
01317         FEType fe_type = this->variable_type(v);
01318         tot_size += FEInterface::n_dofs(dim,
01319                                         fe_type,
01320                                         type);
01321 #endif
01322       }
01323       else
01324       if (this->variable(v).active_on_subdomain(elem->subdomain_id()))
01325         { // Do this for all the variables if one was not specified
01326           // or just for the specified variable
01327 
01328           // Increase the polynomial order on p refined elements
01329           FEType fe_type = this->variable_type(v);
01330           fe_type.order = static_cast<Order>(fe_type.order +
01331                                              elem->p_level());
01332 
01333           const bool extra_hanging_dofs =
01334             FEInterface::extra_hanging_dofs(fe_type);
01335 
01336 #ifdef DEBUG
01337           tot_size += FEInterface::n_dofs(dim,
01338                                           fe_type,
01339                                           type);
01340 #endif
01341         
01342           // Get the node-based DOF numbers
01343           for (unsigned int n=0; n<n_nodes; n++)
01344             {       
01345               const Node* node      = elem->get_node(n);
01346             
01347               // There is a potential problem with h refinement.  Imagine a
01348               // quad9 that has a linear FE on it.  Then, on the hanging side,
01349               // it can falsely identify a DOF at the mid-edge node. This is why
01350               // we call FEInterface instead of node->n_comp() directly.
01351               const unsigned int nc = FEInterface::n_dofs_at_node (dim,
01352                                                                    fe_type,
01353                                                                    type,
01354                                                                    n);
01355 
01356               // If this is a non-vertex on a hanging node with extra
01357               // degrees of freedom, we use the non-vertex dofs (which
01358               // come in reverse order starting from the end, to
01359               // simplify p refinement)
01360               if (extra_hanging_dofs && !elem->is_vertex(n))
01361                 {
01362                   const int dof_offset = node->n_comp(sys_num,v) - nc;
01363 
01364                   // We should never have fewer dofs than necessary on a
01365                   // node unless we're getting indices on a parent element,
01366                   // and we should never need the indices on such a node
01367                   if (dof_offset < 0)
01368                     {
01369                       libmesh_assert(!elem->active());
01370                       di.resize(di.size() + nc, DofObject::invalid_id);
01371                     }
01372                   else
01373                     for (int i=node->n_comp(sys_num,v)-1; i>=dof_offset; i--)
01374                       {
01375                         libmesh_assert (node->dof_number(sys_num,v,i) !=
01376                                         DofObject::invalid_id);
01377                         di.push_back(node->dof_number(sys_num,v,i));
01378                       }
01379                 }
01380               // If this is a vertex or an element without extra hanging
01381               // dofs, our dofs come in forward order coming from the
01382               // beginning
01383               else
01384                 for (unsigned int i=0; i<nc; i++)
01385                   {
01386                     libmesh_assert (node->dof_number(sys_num,v,i) !=
01387                                     DofObject::invalid_id);
01388                     di.push_back(node->dof_number(sys_num,v,i));
01389                   }
01390             }
01391         
01392           // If there are any element-based DOF numbers, get them
01393           const unsigned int nc = FEInterface::n_dofs_per_elem(dim,
01394                                                                fe_type,
01395                                                                type);
01396           // We should never have fewer dofs than necessary on an
01397           // element unless we're getting indices on a parent element,
01398           // and we should never need those indices
01399           if (nc != 0)
01400             {
01401               if (elem->n_systems() > sys_num &&
01402                   nc <= elem->n_comp(sys_num,v))
01403                 {
01404                   for (unsigned int i=0; i<nc; i++)
01405                     {
01406                       libmesh_assert (elem->dof_number(sys_num,v,i) !=
01407                                       DofObject::invalid_id);
01408                     
01409                       di.push_back(elem->dof_number(sys_num,v,i));
01410                     }
01411                 }
01412               else
01413                 {
01414                   libmesh_assert(!elem->active() || fe_type.family == LAGRANGE);
01415                   di.resize(di.size() + nc, DofObject::invalid_id);
01416                 }
01417             }
01418         }
01419       } // end loop over variables
01420 
01421   // Finally append any SCALAR dofs that we asked for.
01422   std::vector<unsigned int> di_new;
01423   std::vector<unsigned int>::iterator it           = SCALAR_var_numbers.begin();
01424   std::vector<unsigned int>::const_iterator it_end = SCALAR_var_numbers.end();
01425   for( ; it != it_end; ++it)
01426   {
01427     this->SCALAR_dof_indices(di_new,*it);
01428     di.insert( di.end(), di_new.begin(), di_new.end());
01429   }
01430 
01431 #ifdef DEBUG
01432     libmesh_assert (tot_size == di.size());
01433 #endif
01434   
01435   STOP_LOG("dof_indices()", "DofMap");  
01436 }
01437 
01438 void DofMap::SCALAR_dof_indices (std::vector<unsigned int>& di,
01439                                  const unsigned int vn,
01440                                  const bool old_dofs) const
01441 {
01442   START_LOG("SCALAR_dof_indices()", "DofMap");
01443 
01444   if(this->variable(vn).type().family != SCALAR)
01445   {
01446     std::cerr << "ERROR: SCALAR_dof_indices called for a non-SCALAR variable."
01447               << std::endl;
01448   }
01449 
01450   // Clear the DOF indices vector
01451   di.clear();
01452 
01453   // First we need to find out the first dof
01454   // index for each SCALAR.
01455   unsigned int first_SCALAR_dof_index = (old_dofs ? n_old_dofs() : n_dofs()) - n_SCALAR_dofs();
01456   std::map<unsigned int, unsigned int> SCALAR_first_dof_index;
01457   SCALAR_first_dof_index.clear();
01458 
01459   // Iterate over _all_ of the SCALARs and store each one's first dof index
01460   // We need to do this since the SCALAR dofs are packed contiguously
01461   for (unsigned int v=0; v<this->n_variables(); v++)
01462     if(this->variable(v).type().family == SCALAR)
01463     {
01464       unsigned int current_n_SCALAR_dofs = this->variable(v).type().order;
01465       SCALAR_first_dof_index.insert(
01466         std::pair<unsigned int, unsigned int>(v,first_SCALAR_dof_index) );
01467       first_SCALAR_dof_index += current_n_SCALAR_dofs;
01468     }
01469 
01470   // Now use vn to index into SCALAR_first_dof_index
01471   std::map<unsigned int, unsigned int>::const_iterator iter =
01472     SCALAR_first_dof_index.find(vn);
01473 
01474 #ifdef DEBUG
01475   libmesh_assert(iter != SCALAR_first_dof_index.end());
01476 #endif
01477 
01478   unsigned int current_first_SCALAR_dof_index = iter->second;
01479 
01480   // Also, get the number of SCALAR dofs from the variable order
01481   unsigned int current_n_SCALAR_dofs = this->variable(vn).type().order;
01482 
01483   for(unsigned int j=0; j<current_n_SCALAR_dofs; j++)
01484   {
01485     unsigned int index = current_first_SCALAR_dof_index+j;
01486     di.push_back(index);
01487   }
01488 
01489   STOP_LOG("SCALAR_dof_indices()", "DofMap");
01490 }
01491 
01492 
01493 #ifdef LIBMESH_ENABLE_AMR
01494 
01495 void DofMap::old_dof_indices (const Elem* const elem,
01496                               std::vector<unsigned int>& di,
01497                               const unsigned int vn) const
01498 {
01499   START_LOG("old_dof_indices()", "DofMap");
01500   
01501   libmesh_assert (elem != NULL);
01502   libmesh_assert (elem->old_dof_object != NULL);
01503             
01504 
01505   const unsigned int n_nodes = elem->n_nodes();
01506   const ElemType type        = elem->type();
01507   const unsigned int sys_num = this->sys_number();
01508   const unsigned int n_vars  = this->n_variables();
01509   const unsigned int dim     = elem->dim();
01510   
01511   // Clear the DOF indices vector.
01512   di.clear();
01513 
01514 #ifdef DEBUG
01515   // Check that sizes match
01516   unsigned int tot_size = 0;
01517 #endif
01518 
01519   // Create a vector to indicate which
01520   // SCALAR variables have been requested
01521   std::vector<unsigned int> SCALAR_var_numbers;
01522   SCALAR_var_numbers.clear();
01523 
01524   // Get the dof numbers
01525   for (unsigned int v=0; v<n_vars; v++)
01526     if ((v == vn) || (vn == libMesh::invalid_uint))
01527     {
01528       if(this->variable(v).type().family == SCALAR)
01529         {
01530           // We asked for this variable, so add it to the vector.
01531           SCALAR_var_numbers.push_back(v);
01532 
01533 #ifdef DEBUG
01534           FEType fe_type = this->variable_type(v);
01535           tot_size += FEInterface::n_dofs(dim,
01536                                           fe_type,
01537                                           type);
01538 #endif
01539         }
01540       else
01541       if (this->variable(v).active_on_subdomain(elem->subdomain_id()))
01542         { // Do this for all the variables if one was not specified
01543           // or just for the specified variable
01544         
01545           // Increase the polynomial order on p refined elements,
01546           // but make sure you get the right polynomial order for
01547           // the OLD degrees of freedom
01548           int p_adjustment = 0;
01549           if (elem->p_refinement_flag() == Elem::JUST_REFINED)
01550             {
01551               libmesh_assert (elem->p_level() > 0);
01552               p_adjustment = -1;
01553             }
01554           else if (elem->p_refinement_flag() == Elem::JUST_COARSENED)
01555             {
01556               p_adjustment = 1;
01557             }
01558           FEType fe_type = this->variable_type(v);
01559           fe_type.order = static_cast<Order>(fe_type.order +
01560                                              elem->p_level() +
01561                                              p_adjustment);
01562 
01563           const bool extra_hanging_dofs =
01564             FEInterface::extra_hanging_dofs(fe_type);
01565 
01566 #ifdef DEBUG
01567           tot_size += FEInterface::n_dofs(dim,
01568                                           fe_type,
01569                                           type);
01570 #endif
01571         
01572           // Get the node-based DOF numbers
01573           for (unsigned int n=0; n<n_nodes; n++)
01574             {
01575               const Node* node      = elem->get_node(n);
01576             
01577               // There is a potential problem with h refinement.  Imagine a
01578               // quad9 that has a linear FE on it.  Then, on the hanging side,
01579               // it can falsely identify a DOF at the mid-edge node. This is why
01580               // we call FEInterface instead of node->n_comp() directly.
01581               const unsigned int nc = FEInterface::n_dofs_at_node (dim,
01582                                                                    fe_type,
01583                                                                    type,
01584                                                                    n);
01585               libmesh_assert (node->old_dof_object != NULL);
01586             
01587               // If this is a non-vertex on a hanging node with extra
01588               // degrees of freedom, we use the non-vertex dofs (which
01589               // come in reverse order starting from the end, to
01590               // simplify p refinement)
01591               if (extra_hanging_dofs && !elem->is_vertex(n))
01592                 {
01593                   const int dof_offset = 
01594                     node->old_dof_object->n_comp(sys_num,v) - nc;
01595             
01596                   // We should never have fewer dofs than necessary on a
01597                   // node unless we're getting indices on a parent element
01598                   // or a just-coarsened element
01599                   if (dof_offset < 0)
01600                     {
01601                       libmesh_assert(!elem->active() || elem->refinement_flag() ==
01602                                      Elem::JUST_COARSENED);
01603                       di.resize(di.size() + nc, DofObject::invalid_id);
01604                     }
01605                   else
01606                     for (int i=node->old_dof_object->n_comp(sys_num,v)-1;
01607                          i>=dof_offset; i--)
01608                       {
01609                         libmesh_assert (node->old_dof_object->dof_number(sys_num,v,i) !=
01610                                         DofObject::invalid_id);
01611                         di.push_back(node->old_dof_object->dof_number(sys_num,v,i));
01612                       }
01613                 }
01614               // If this is a vertex or an element without extra hanging
01615               // dofs, our dofs come in forward order coming from the
01616               // beginning
01617               else
01618                 for (unsigned int i=0; i<nc; i++)
01619                   {
01620                     libmesh_assert (node->old_dof_object->dof_number(sys_num,v,i) !=
01621                                     DofObject::invalid_id);
01622                     di.push_back(node->old_dof_object->dof_number(sys_num,v,i));
01623                   }
01624             }
01625         
01626           // If there are any element-based DOF numbers, get them
01627           const unsigned int nc = FEInterface::n_dofs_per_elem(dim,
01628                                                                fe_type,
01629                                                                type);
01630 
01631           // We should never have fewer dofs than necessary on an
01632           // element unless we're getting indices on a parent element
01633           // or a just-coarsened element
01634           if (nc != 0)
01635             {
01636               if (elem->old_dof_object->n_systems() > sys_num &&
01637                   nc <= elem->old_dof_object->n_comp(sys_num,v))
01638                 {
01639                   libmesh_assert (elem->old_dof_object != NULL);
01640                 
01641                   for (unsigned int i=0; i<nc; i++)
01642                     {
01643                       libmesh_assert (elem->old_dof_object->dof_number(sys_num,v,i) !=
01644                                       DofObject::invalid_id);
01645                     
01646                       di.push_back(elem->old_dof_object->dof_number(sys_num,v,i));
01647                     }
01648                 }
01649               else
01650                 {
01651                   libmesh_assert(!elem->active() || fe_type.family == LAGRANGE ||
01652                                  elem->refinement_flag() == Elem::JUST_COARSENED);
01653                   di.resize(di.size() + nc, DofObject::invalid_id);
01654                 }
01655             }
01656         }
01657     } // end loop over variables
01658 
01659   // Finally append any SCALAR dofs that we asked for.
01660   std::vector<unsigned int> di_new;
01661   std::vector<unsigned int>::iterator it           = SCALAR_var_numbers.begin();
01662   std::vector<unsigned int>::const_iterator it_end = SCALAR_var_numbers.end();
01663   for( ; it != it_end; ++it)
01664   {
01665     this->SCALAR_dof_indices(di_new,*it,true);
01666     di.insert( di.end(), di_new.begin(), di_new.end());
01667   }
01668   
01669 #ifdef DEBUG
01670   libmesh_assert (tot_size == di.size());
01671 #endif
01672   
01673   STOP_LOG("old_dof_indices()", "DofMap");  
01674 }
01675 
01676 
01677 
01678 /*
01679 void DofMap::augment_send_list_for_projection(const MeshBase& mesh)
01680 {
01681   // Loop over the active local elements in the mesh.
01682   // If the element was just refined and its parent lives
01683   // on a different processor then we need to augment the
01684   // _send_list with the parent's DOF indices so that we
01685   // can access the parent's data for computing solution
01686   // projections, etc...
01687 
01688   // The DOF indices for the parent
01689   std::vector<unsigned int> di;
01690 
01691   // Flag telling us if we need to re-sort the send_list.
01692   // Note we won't need to re-sort unless a child with a
01693   // parent belonging to a different processor is found
01694   bool needs_sorting = false;
01695   
01696   
01697   MeshBase::const_element_iterator       elem_it  = mesh.active_local_elements_begin();
01698   const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); 
01699 
01700   for ( ; elem_it != elem_end; ++elem_it)
01701     {
01702       const Elem* const elem   = *elem_it;
01703 
01704       // We only need to consider the children that
01705       // were just refined
01706       if (elem->refinement_flag() != Elem::JUST_REFINED) continue;
01707       
01708       const Elem* const parent = elem->parent();
01709 
01710       // If the parent lives on another processor
01711       // than the child
01712       if (parent != NULL)
01713         if (parent->processor_id() != elem->processor_id())
01714           {
01715             // Get the DOF indices for the parent
01716             this->dof_indices (parent, di);
01717 
01718             // Insert the DOF indices into the send list
01719             _send_list.insert (_send_list.end(),
01720                                di.begin(), di.end());
01721 
01722             // We will need to re-sort the send list
01723             needs_sorting = true;           
01724           }
01725     }
01726 
01727   // The send-list might need to be sorted again.
01728   if (needs_sorting) this->sort_send_list ();
01729 }
01730 */
01731 
01732 #endif // LIBMESH_ENABLE_AMR
01733 
01734 
01735 #if defined(LIBMESH_ENABLE_AMR) || defined(LIBMESH_ENABLE_PERIODIC)
01736 
01737 void DofMap::find_connected_dofs (std::vector<unsigned int>& elem_dofs) const
01738 {
01739   typedef std::set<unsigned int> RCSet;
01740 
01741   // First insert the DOFS we already depend on into the set.  
01742   RCSet dof_set (elem_dofs.begin(), elem_dofs.end());
01743 
01744   bool done = true;
01745     
01746   // Next insert any dofs those might be constrained in terms
01747   // of.  Note that in this case we may not be done:  Those may
01748   // in turn depend on others.  So, we need to repeat this process
01749   // in that case until the system depends only on unconstrained
01750   // degrees of freedom.
01751   for (unsigned int i=0; i<elem_dofs.size(); i++)
01752     if (this->is_constrained_dof(elem_dofs[i]))
01753       {
01754         // If the DOF is constrained
01755         DofConstraints::const_iterator
01756           pos = _dof_constraints.find(elem_dofs[i]);
01757         
01758         libmesh_assert (pos != _dof_constraints.end());
01759         
01760         const DofConstraintRow& constraint_row = pos->second;
01761         
01762 // adaptive p refinement currently gives us lots of empty constraint
01763 // rows - we should optimize those DoFs away in the future.  [RHS]
01764 //      libmesh_assert (!constraint_row.empty());
01765         
01766         DofConstraintRow::const_iterator it     = constraint_row.begin();
01767         DofConstraintRow::const_iterator it_end = constraint_row.end();
01768         
01769         
01770         // Add the DOFs this dof is constrained in terms of.
01771         // note that these dofs might also be constrained, so
01772         // we will need to call this function recursively.
01773         for ( ; it != it_end; ++it)
01774           if (!dof_set.count (it->first))
01775             {
01776               dof_set.insert (it->first);
01777               done = false;
01778             }
01779         }
01780   
01781   
01782   // If not done then we need to do more work
01783   // (obviously :-) )!
01784   if (!done)
01785     {
01786       // Fill the vector with the contents of the set
01787       elem_dofs.clear();      
01788       elem_dofs.insert (elem_dofs.end(),
01789                         dof_set.begin(), dof_set.end());
01790       
01791 
01792       // May need to do this recursively.  It is possible
01793       // that we just replaced a constrained DOF with another
01794       // constrained DOF.
01795       this->find_connected_dofs (elem_dofs);
01796       
01797     } // end if (!done)
01798 }
01799 
01800 #endif // LIBMESH_ENABLE_AMR || LIBMESH_ENABLE_PERIODIC
01801 
01802 
01803 
01804 #if defined(__GNUC__) && (__GNUC__ < 4) && !defined(__INTEL_COMPILER)
01805 
01806 void SparsityPattern::_dummy_function(void)
01807 {
01808 }
01809 
01810 #endif
01811 
01812 
01813 
01814 void SparsityPattern::Build::operator()(const ConstElemRange &range)
01815 {
01816   // Compute the sparsity structure of the global matrix.  This can be
01817   // fed into a PetscMatrix to allocate exacly the number of nonzeros
01818   // necessary to store the matrix.  This algorithm should be linear
01819   // in the (# of elements)*(# nodes per element)
01820   const unsigned int proc_id           = mesh.processor_id();
01821   const unsigned int n_dofs_on_proc    = dof_map.n_dofs_on_processor(proc_id);
01822   const unsigned int first_dof_on_proc = dof_map.first_dof(proc_id);
01823   const unsigned int end_dof_on_proc   = dof_map.end_dof(proc_id);
01824 
01825   sparsity_pattern.resize(n_dofs_on_proc);
01826   
01827   // If the user did not explicitly specify the DOF coupling
01828   // then all the DOFS are coupled to each other.  Furthermore,
01829   // we can take a shortcut and do this more quickly here.  So
01830   // we use an if-test.
01831   if ((dof_coupling == NULL) || (dof_coupling->empty()))
01832     {
01833       std::vector<unsigned int>
01834         element_dofs,
01835         neighbor_dofs,
01836         dofs_to_add;
01837 
01838       std::vector<const Elem*> active_neighbors;
01839 
01840       for (ConstElemRange::const_iterator elem_it = range.begin() ; elem_it != range.end(); ++elem_it)
01841         {
01842           const Elem* const elem = *elem_it;
01843 
01844           // Get the global indices of the DOFs with support on this element
01845           dof_map.dof_indices (elem, element_dofs);
01846 #if defined(LIBMESH_ENABLE_AMR) || defined(LIBMESH_ENABLE_PERIODIC)
01847           dof_map.find_connected_dofs (element_dofs);
01848 #endif
01849 
01850           // We can be more efficient if we sort the element DOFs
01851           // into increasing order
01852           std::sort(element_dofs.begin(), element_dofs.end());
01853           
01854           const unsigned int n_dofs_on_element = element_dofs.size();
01855             
01856           for (unsigned int i=0; i<n_dofs_on_element; i++)
01857             {
01858               const unsigned int ig = element_dofs[i];
01859               
01860               // Only bother if this matrix row will be stored
01861               // on this processor.
01862               if ((ig >= first_dof_on_proc) &&
01863                   (ig <  end_dof_on_proc))
01864                 {
01865                   // This is what I mean
01866                   // libmesh_assert ((ig - first_dof_on_proc) >= 0);
01867                   // but do the test like this because ig and
01868                   // first_dof_on_proc are unsigned ints
01869                   libmesh_assert (ig >= first_dof_on_proc);
01870                   libmesh_assert ((ig - first_dof_on_proc) < sparsity_pattern.size());
01871                   
01872                   SparsityPattern::Row &row = sparsity_pattern[ig - first_dof_on_proc];
01873 
01874                   // If the row is empty we will add *all* the element DOFs,
01875                   // so just do that.
01876                   if (row.empty())
01877                     {
01878                       row.insert(row.end(),
01879                                  element_dofs.begin(),
01880                                  element_dofs.end());
01881                     }
01882                   else
01883                     {             
01884                       // Build a list of the DOF indices not found in the
01885                       // sparsity pattern
01886                       dofs_to_add.clear();
01887 
01888                       // Cache iterators.  Low will move forward, subsequent
01889                       // searches will be on smaller ranges
01890                       SparsityPattern::Row::iterator
01891                         low  = std::lower_bound (row.begin(), row.end(), element_dofs.front()),
01892                         high = std::upper_bound (low,         row.end(), element_dofs.back());
01893                   
01894                       for (unsigned int j=0; j<n_dofs_on_element; j++)
01895                         {
01896                           const unsigned int jg = element_dofs[j];
01897                           
01898                           // See if jg is in the sorted range
01899                           std::pair<SparsityPattern::Row::iterator,
01900                                     SparsityPattern::Row::iterator>
01901                             pos = std::equal_range (low, high, jg);
01902                         
01903                           // Must add jg if it wasn't found
01904                           if (pos.first == pos.second)
01905                             dofs_to_add.push_back(jg);
01906                         
01907                           // pos.first is now a valid lower bound for any
01908                           // remaining element DOFs. (That's why we sorted them.)
01909                           // Use it for the next search
01910                           low = pos.first;
01911                         }
01912 
01913                       // Add to the sparsity pattern
01914                       if (!dofs_to_add.empty())
01915                         {
01916                           const unsigned int old_size = row.size();
01917                           
01918                           row.insert (row.end(),
01919                                       dofs_to_add.begin(),
01920                                       dofs_to_add.end());
01921                       
01922                           SparsityPattern::sort_row (row.begin(), row.begin()+old_size, row.end());
01923                         }
01924                     }
01925                   
01926                   // Now (possibly) add dofs from neighboring elements
01927                   // TODO:[BSK] optimize this like above!
01928                   if (implicit_neighbor_dofs)
01929                     for (unsigned int s=0; s<elem->n_sides(); s++)
01930                       if (elem->neighbor(s) != NULL)
01931                         {
01932                           const Elem* const neighbor_0 = elem->neighbor(s);
01933 #ifdef LIBMESH_ENABLE_AMR
01934                           neighbor_0->active_family_tree_by_neighbor(active_neighbors,elem);
01935 #else
01936                           active_neighbors.clear();
01937                           active_neighbors.push_back(neighbor_0);
01938 #endif
01939                           
01940                           for (unsigned int a=0; a != active_neighbors.size(); ++a)
01941                             {
01942                               const Elem *neighbor = active_neighbors[a];
01943                               
01944                               dof_map.dof_indices (neighbor, neighbor_dofs);
01945 #if defined(LIBMESH_ENABLE_AMR) || defined(LIBMESH_ENABLE_PERIODIC)
01946                               dof_map.find_connected_dofs (neighbor_dofs);
01947 #endif                        
01948                               const unsigned int n_dofs_on_neighbor = neighbor_dofs.size();
01949                               
01950                               for (unsigned int j=0; j<n_dofs_on_neighbor; j++)
01951                                 {
01952                                   const unsigned int jg = neighbor_dofs[j];
01953                                   
01954                                   // See if jg is in the sorted range
01955                                   std::pair<SparsityPattern::Row::iterator,
01956                                             SparsityPattern::Row::iterator>
01957                                     pos = std::equal_range (row.begin(), row.end(), jg);
01958                                 
01959                                   // Insert jg if it wasn't found
01960                                   if (pos.first == pos.second)
01961                                     row.insert (pos.first, jg);
01962                                 }    
01963                             }
01964                         }
01965                 }
01966             }
01967         }             
01968     } 
01969 
01970 
01971   
01972   // This is what we do in the case that the user has specified
01973   // explicit DOF coupling.
01974   else
01975     {
01976       libmesh_assert (dof_coupling != NULL);
01977       libmesh_assert (dof_coupling->size() ==
01978                       dof_map.n_variables());
01979       
01980       const unsigned int n_var = dof_map.n_variables();
01981       
01982       std::vector<unsigned int>
01983         element_dofs_i,
01984         element_dofs_j,
01985         dofs_to_add;
01986 
01987 
01988       for (ConstElemRange::const_iterator elem_it = range.begin() ; elem_it != range.end(); ++elem_it)
01989         for (unsigned int vi=0; vi<n_var; vi++)
01990           {
01991             const Elem* const elem = *elem_it;
01992             
01993             // Find element dofs for variable vi
01994             dof_map.dof_indices (elem, element_dofs_i, vi);
01995 #if defined(LIBMESH_ENABLE_AMR) || defined(LIBMESH_ENABLE_PERIODIC)
01996             dof_map.find_connected_dofs (element_dofs_i);
01997 #endif
01998 
01999             // We can be more efficient if we sort the element DOFs
02000             // into increasing order
02001             std::sort(element_dofs_i.begin(), element_dofs_i.end());
02002             const unsigned int n_dofs_on_element_i = element_dofs_i.size();
02003             
02004             for (unsigned int vj=0; vj<n_var; vj++)
02005               if ((*dof_coupling)(vi,vj)) // If vi couples to vj
02006                 {
02007                   // Find element dofs for variable vj, note that
02008                   // if vi==vj we already have the dofs.
02009                   if (vi != vj)
02010                     {
02011                       dof_map.dof_indices (elem, element_dofs_j, vj);
02012 #if defined(LIBMESH_ENABLE_AMR) || defined(LIBMESH_ENABLE_PERIODIC)
02013                       dof_map.find_connected_dofs (element_dofs_j);
02014 #endif
02015 
02016                       // We can be more efficient if we sort the element DOFs
02017                       // into increasing order
02018                       std::sort (element_dofs_j.begin(), element_dofs_j.end());
02019                     }
02020                   else
02021                     element_dofs_j = element_dofs_i;
02022                   
02023                   const unsigned int n_dofs_on_element_j =
02024                     element_dofs_j.size();
02025                   
02026                   for (unsigned int i=0; i<n_dofs_on_element_i; i++)
02027                     {
02028                       const unsigned int ig = element_dofs_i[i];
02029                       
02030                       // We are only interested in computing the sparsity pattern
02031                       // for the rows in [range.begin(),range.end()).  So, if this
02032                       // element's DOFs are not in that range just go ahead to the
02033                       // next one.
02034                       //              
02035                       // Also, only bother if this matrix row will be stored
02036                       // on this processor.
02037                       if ((ig >= first_dof_on_proc) &&
02038                           (ig <  end_dof_on_proc))                      
02039                         {
02040                           // This is what I mean
02041                           // libmesh_assert ((ig - first_dof_on_proc) >= 0);
02042                           // but do the test like this because ig and
02043                           // first_dof_on_proc are unsigned ints
02044                           libmesh_assert (ig >= first_dof_on_proc);
02045                           libmesh_assert (ig < (sparsity_pattern.size() +
02046                                         first_dof_on_proc));
02047                           
02048                           SparsityPattern::Row &row = sparsity_pattern[ig - first_dof_on_proc];
02049 
02050                           // If the row is empty we will add *all* the element j DOFs,
02051                           // so just do that.
02052                           if (row.empty())
02053                             {
02054                               row.insert(row.end(),
02055                                          element_dofs_j.begin(),
02056                                          element_dofs_j.end());
02057                             }
02058                           else
02059                             {             
02060                               // Build a list of the DOF indices not found in the
02061                               // sparsity pattern
02062                               dofs_to_add.clear();
02063 
02064                               // Cache iterators.  Low will move forward, subsequent
02065                               // searches will be on smaller ranges
02066                               SparsityPattern::Row::iterator
02067                                 low  = std::lower_bound (row.begin(), row.end(), element_dofs_j.front()),
02068                                 high = std::upper_bound (low,         row.end(), element_dofs_j.back());
02069 
02070                               for (unsigned int j=0; j<n_dofs_on_element_j; j++)
02071                                 {
02072                                   const unsigned int jg = element_dofs_j[j];
02073                                   
02074                                   // See if jg is in the sorted range
02075                                   std::pair<SparsityPattern::Row::iterator,
02076                                             SparsityPattern::Row::iterator>
02077                                     pos = std::equal_range (low, high, jg);
02078                               
02079                                   // Must add jg if it wasn't found
02080                                   if (pos.first == pos.second)
02081                                     dofs_to_add.push_back(jg);
02082                                 
02083                                   // pos.first is now a valid lower bound for any
02084                                   // remaining element j DOFs. (That's why we sorted them.)
02085                                   // Use it for the next search
02086                                   low = pos.first;
02087                                 }
02088                               
02089                               // Add to the sparsity pattern
02090                               if (!dofs_to_add.empty())
02091                                 {
02092                                   const unsigned int old_size = row.size();
02093                                   
02094                                   row.insert (row.end(),
02095                                               dofs_to_add.begin(),
02096                                               dofs_to_add.end());
02097                       
02098                                   SparsityPattern::sort_row (row.begin(), row.begin()+old_size, row.end());
02099                                 }
02100                             }
02101                         }
02102                     }
02103                 }
02104           }
02105     }
02106   
02107   // Now the full sparsity structure is built for all of the
02108   // DOFs connected to our rows of the matrix.
02109   n_nz.resize (n_dofs_on_proc);
02110   n_oz.resize (n_dofs_on_proc);
02111 
02112   // First zero the counters.
02113   std::fill(n_nz.begin(), n_nz.end(), 0);
02114   std::fill(n_oz.begin(), n_oz.end(), 0);
02115   
02116   for (unsigned int i=0; i<n_dofs_on_proc; i++)
02117     {
02118       // Get the row of the sparsity pattern
02119       const SparsityPattern::Row &row = sparsity_pattern[i];
02120 
02121       for (unsigned int j=0; j<row.size(); j++)
02122         if ((row[j] < first_dof_on_proc) || (row[j] >= end_dof_on_proc))
02123           n_oz[i]++;
02124         else
02125           n_nz[i]++;
02126     }
02127 }
02128 
02129 
02130 
02131 void SparsityPattern::Build::join (const SparsityPattern::Build &other)
02132 {
02133   const unsigned int proc_id           = mesh.processor_id();
02134   const unsigned int n_global_dofs     = dof_map.n_dofs();
02135   const unsigned int n_dofs_on_proc    = dof_map.n_dofs_on_processor(proc_id);
02136   const unsigned int first_dof_on_proc = dof_map.first_dof(proc_id);
02137   const unsigned int end_dof_on_proc   = dof_map.end_dof(proc_id);
02138 
02139   libmesh_assert (sparsity_pattern.size() ==  other.sparsity_pattern.size());
02140   libmesh_assert (n_nz.size() == sparsity_pattern.size());
02141   libmesh_assert (n_oz.size() == sparsity_pattern.size());
02142   
02143   for (unsigned int r=0; r<n_dofs_on_proc; r++)
02144     {
02145       // incriment the number of on and off-processor nonzeros in this row
02146       // (note this will be an upper bound unless we need the full sparsity pattern)
02147       n_nz[r] += other.n_nz[r];  n_nz[r] = std::min(n_nz[r], n_dofs_on_proc);
02148       n_oz[r] += other.n_oz[r];  n_oz[r] = std::min(n_oz[r], n_global_dofs-n_nz[r]);
02149 
02150       if (need_full_sparsity_pattern)
02151         {
02152           SparsityPattern::Row       &my_row    = sparsity_pattern[r];
02153           const SparsityPattern::Row &their_row = other.sparsity_pattern[r];
02154       
02155           // simple copy if I have no dofs
02156           if (my_row.empty())
02157             my_row = their_row;
02158           
02159           // otherwise add their DOFs to mine, resort, and re-unique the row
02160           else if (!their_row.empty()) // do nothing for the trivial case where 
02161             {                          // their row is empty
02162               my_row.insert (my_row.end(),
02163                              their_row.begin(),
02164                              their_row.end());
02165 
02166               // We cannot use SparsityPattern::sort_row() here because it expects
02167               // the [begin,middle) [middle,end) to be non-overlapping.  This is not
02168               // necessarily the case here, so use std::sort()
02169               std::sort (my_row.begin(), my_row.end());
02170          
02171               my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
02172             }
02173 
02174           // fix the number of on and off-processor nonzeros in this row
02175           n_nz[r] = n_oz[r] = 0;
02176           
02177           for (unsigned int j=0; j<my_row.size(); j++)
02178             if ((my_row[j] < first_dof_on_proc) || (my_row[j] >= end_dof_on_proc))
02179               n_oz[r]++;
02180             else
02181               n_nz[r]++;
02182         }
02183     }
02184 }

Site Created By: libMesh Developers
Last modified: November 25 2009 03:43:40.

Hosted By:
SourceForge.net Logo