libMesh::SparsityPattern::Build Class Reference

#include <sparsity_pattern.h>

List of all members.

Public Member Functions

 Build (const MeshBase &mesh_in, const DofMap &dof_map_in, const CouplingMatrix *dof_coupling_in, const bool implicit_neighbor_dofs_in, const bool need_full_sparsity_pattern_in)
 Build (Build &other, Threads::split)
void operator() (const ConstElemRange &range)
void join (const Build &other)
void parallel_sync ()

Public Attributes

SparsityPattern::Graph sparsity_pattern
SparsityPattern::NonlocalGraph nonlocal_pattern
std::vector< dof_id_typen_nz
std::vector< dof_id_typen_oz

Private Attributes

const MeshBasemesh
const DofMapdof_map
const CouplingMatrixdof_coupling
const bool implicit_neighbor_dofs
const bool need_full_sparsity_pattern

Detailed Description

This helper class can be called on multiple threads to compute the sparsity pattern (or graph) of the sparse matrix resulting from the discretization. This pattern may be used directly by a particular sparse matrix format (e.g. LaspackMatrix) or indirectly (e.g. PetscMatrix). In the latter case the number of nonzeros per row of the matrix is needed for efficient preallocation. In this case it suffices to provide estimate (but bounding) values, and in this case the threaded method can take some short-cuts for efficiency.

Definition at line 78 of file sparsity_pattern.h.


Constructor & Destructor Documentation

libMesh::SparsityPattern::Build::Build ( const MeshBase mesh_in,
const DofMap dof_map_in,
const CouplingMatrix dof_coupling_in,
const bool  implicit_neighbor_dofs_in,
const bool  need_full_sparsity_pattern_in 
) [inline]

Definition at line 95 of file sparsity_pattern.h.

00099                                                      :
00100       mesh(mesh_in),
00101       dof_map(dof_map_in),
00102       dof_coupling(dof_coupling_in),
00103       implicit_neighbor_dofs(implicit_neighbor_dofs_in),
00104       need_full_sparsity_pattern(need_full_sparsity_pattern_in),
00105       sparsity_pattern(),
00106       nonlocal_pattern(),
00107       n_nz(),
00108       n_oz()
00109     {}

libMesh::SparsityPattern::Build::Build ( Build other,
Threads::split   
) [inline]

Definition at line 111 of file sparsity_pattern.h.

00111                                        :
00112       mesh(other.mesh),
00113       dof_map(other.dof_map),
00114       dof_coupling(other.dof_coupling),
00115       implicit_neighbor_dofs(other.implicit_neighbor_dofs),
00116       need_full_sparsity_pattern(other.need_full_sparsity_pattern),
00117       sparsity_pattern(),
00118       nonlocal_pattern(),
00119       n_nz(),
00120       n_oz()
00121     {}


Member Function Documentation

void libMesh::SparsityPattern::Build::join ( const Build other  ) 

Definition at line 2542 of file dof_map.C.

References dof_map, libMesh::DofMap::end_dof(), libMesh::DofMap::first_dof(), std::min(), libMesh::DofMap::n_dofs(), libMesh::DofMap::n_dofs_on_processor(), n_nz, n_oz, need_full_sparsity_pattern, nonlocal_pattern, libMesh::processor_id(), libMesh::MeshBase::processor_id(), and sparsity_pattern.

02543 {
02544   const processor_id_type proc_id           = mesh.processor_id();
02545   const dof_id_type       n_global_dofs     = dof_map.n_dofs();
02546   const dof_id_type       n_dofs_on_proc    = dof_map.n_dofs_on_processor(proc_id);
02547   const dof_id_type       first_dof_on_proc = dof_map.first_dof(proc_id);
02548   const dof_id_type       end_dof_on_proc   = dof_map.end_dof(proc_id);
02549 
02550   libmesh_assert_equal_to (sparsity_pattern.size(), other.sparsity_pattern.size());
02551   libmesh_assert_equal_to (n_nz.size(), sparsity_pattern.size());
02552   libmesh_assert_equal_to (n_oz.size(), sparsity_pattern.size());
02553 
02554   for (dof_id_type r=0; r<n_dofs_on_proc; r++)
02555     {
02556       // increment the number of on and off-processor nonzeros in this row
02557       // (note this will be an upper bound unless we need the full sparsity pattern)
02558       if (need_full_sparsity_pattern)
02559         {
02560           SparsityPattern::Row       &my_row    = sparsity_pattern[r];
02561           const SparsityPattern::Row &their_row = other.sparsity_pattern[r];
02562 
02563           // simple copy if I have no dofs
02564           if (my_row.empty())
02565             my_row = their_row;
02566 
02567           // otherwise add their DOFs to mine, resort, and re-unique the row
02568           else if (!their_row.empty()) // do nothing for the trivial case where
02569             {                          // their row is empty
02570               my_row.insert (my_row.end(),
02571                              their_row.begin(),
02572                              their_row.end());
02573 
02574               // We cannot use SparsityPattern::sort_row() here because it expects
02575               // the [begin,middle) [middle,end) to be non-overlapping.  This is not
02576               // necessarily the case here, so use std::sort()
02577               std::sort (my_row.begin(), my_row.end());
02578 
02579               my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
02580             }
02581 
02582           // fix the number of on and off-processor nonzeros in this row
02583           n_nz[r] = n_oz[r] = 0;
02584 
02585           for (std::size_t j=0; j<my_row.size(); j++)
02586             if ((my_row[j] < first_dof_on_proc) || (my_row[j] >= end_dof_on_proc))
02587               n_oz[r]++;
02588             else
02589               n_nz[r]++;
02590         }
02591       else
02592         {
02593           n_nz[r] += other.n_nz[r];
02594           n_nz[r] = std::min(n_nz[r], n_dofs_on_proc);
02595           n_oz[r] += other.n_oz[r];
02596           n_oz[r] =std::min(n_oz[r], static_cast<dof_id_type>(n_global_dofs-n_nz[r]));
02597         }
02598     }
02599 
02600   // Move nonlocal row information to ourselves; the other thread
02601   // won't need it in the map after that.
02602   NonlocalGraph::const_iterator it = other.nonlocal_pattern.begin();
02603   for (; it != other.nonlocal_pattern.end(); ++it)
02604     {
02605       const dof_id_type dof_id = it->first;
02606 
02607 #ifndef NDEBUG
02608       processor_id_type dbg_proc_id = 0;
02609       while (dof_id >= dof_map.end_dof(dbg_proc_id))
02610         dbg_proc_id++;
02611       libmesh_assert (dbg_proc_id != libMesh::processor_id());
02612 #endif
02613 
02614       const SparsityPattern::Row &their_row = it->second;
02615 
02616       // We should have no empty values in a map
02617       libmesh_assert (!their_row.empty());
02618 
02619       NonlocalGraph::iterator my_it = nonlocal_pattern.find(it->first);
02620       if (my_it == nonlocal_pattern.end())
02621         {
02622 //          nonlocal_pattern[it->first].swap(their_row);
02623           nonlocal_pattern[it->first] = their_row;
02624         }
02625       else
02626         {
02627           SparsityPattern::Row &my_row = my_it->second;
02628 
02629           my_row.insert (my_row.end(),
02630                          their_row.begin(),
02631                          their_row.end());
02632 
02633           // We cannot use SparsityPattern::sort_row() here because it expects
02634           // the [begin,middle) [middle,end) to be non-overlapping.  This is not
02635           // necessarily the case here, so use std::sort()
02636           std::sort (my_row.begin(), my_row.end());
02637 
02638           my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
02639         }
02640     }
02641 }

void libMesh::SparsityPattern::Build::operator() ( const ConstElemRange range  ) 

Definition at line 2154 of file dof_map.C.

References libMesh::Elem::active_family_tree_by_neighbor(), libMesh::StoredRange< iterator_type, object_type >::begin(), dof_coupling, libMesh::DofMap::dof_indices(), dof_map, libMesh::CouplingMatrix::empty(), libMesh::StoredRange< iterator_type, object_type >::end(), libMesh::DofMap::end_dof(), libMesh::DofMap::find_connected_dofs(), libMesh::DofMap::first_dof(), implicit_neighbor_dofs, libMesh::DofMap::n_dofs_on_processor(), n_nz, n_oz, libMesh::Elem::n_sides(), libMesh::DofMap::n_variables(), need_full_sparsity_pattern, libMesh::Elem::neighbor(), nonlocal_pattern, libMesh::MeshBase::processor_id(), libMesh::CouplingMatrix::size(), libMesh::SparsityPattern::sort_row(), and sparsity_pattern.

02155 {
02156   // Compute the sparsity structure of the global matrix.  This can be
02157   // fed into a PetscMatrix to allocate exacly the number of nonzeros
02158   // necessary to store the matrix.  This algorithm should be linear
02159   // in the (# of elements)*(# nodes per element)
02160   const processor_id_type proc_id           = mesh.processor_id();
02161   const dof_id_type n_dofs_on_proc    = dof_map.n_dofs_on_processor(proc_id);
02162   const dof_id_type first_dof_on_proc = dof_map.first_dof(proc_id);
02163   const dof_id_type end_dof_on_proc   = dof_map.end_dof(proc_id);
02164 
02165   sparsity_pattern.resize(n_dofs_on_proc);
02166 
02167   // If the user did not explicitly specify the DOF coupling
02168   // then all the DOFS are coupled to each other.  Furthermore,
02169   // we can take a shortcut and do this more quickly here.  So
02170   // we use an if-test.
02171   if ((dof_coupling == NULL) || (dof_coupling->empty()))
02172     {
02173       std::vector<dof_id_type>
02174         element_dofs,
02175         neighbor_dofs,
02176         dofs_to_add;
02177 
02178       std::vector<const Elem*> active_neighbors;
02179 
02180       for (ConstElemRange::const_iterator elem_it = range.begin() ; elem_it != range.end(); ++elem_it)
02181         {
02182           const Elem* const elem = *elem_it;
02183 
02184           // Get the global indices of the DOFs with support on this element
02185           dof_map.dof_indices (elem, element_dofs);
02186 #ifdef LIBMESH_ENABLE_CONSTRAINTS
02187           dof_map.find_connected_dofs (element_dofs);
02188 #endif
02189 
02190           // We can be more efficient if we sort the element DOFs
02191           // into increasing order
02192           std::sort(element_dofs.begin(), element_dofs.end());
02193 
02194           const unsigned int n_dofs_on_element =
02195             libmesh_cast_int<unsigned int>(element_dofs.size());
02196 
02197           for (unsigned int i=0; i<n_dofs_on_element; i++)
02198             {
02199               const dof_id_type ig = element_dofs[i];
02200 
02201               SparsityPattern::Row *row;
02202 
02203               // We save non-local row components for now so we can
02204               // communicate them to other processors later.
02205              
02206               if ((ig >= first_dof_on_proc) &&
02207                   (ig <  end_dof_on_proc))
02208                 {
02209                   // This is what I mean
02210                   // libmesh_assert_greater_equal ((ig - first_dof_on_proc), 0);
02211                   // but do the test like this because ig and
02212                   // first_dof_on_proc are unsigned ints
02213                   libmesh_assert_greater_equal (ig, first_dof_on_proc);
02214                   libmesh_assert_less ((ig - first_dof_on_proc), sparsity_pattern.size());
02215 
02216                   row = &sparsity_pattern[ig - first_dof_on_proc];
02217                 }
02218               else
02219                 {
02220                   row = &nonlocal_pattern[ig];
02221                 }
02222 
02223               // If the row is empty we will add *all* the element DOFs,
02224               // so just do that.
02225               if (row->empty())
02226                 {
02227                    row->insert(row->end(),
02228                                element_dofs.begin(),
02229                                element_dofs.end());
02230                 }
02231               else
02232                 {
02233                   // Build a list of the DOF indices not found in the
02234                   // sparsity pattern
02235                   dofs_to_add.clear();
02236 
02237                   // Cache iterators.  Low will move forward, subsequent
02238                   // searches will be on smaller ranges
02239                   SparsityPattern::Row::iterator
02240                     low  = std::lower_bound (row->begin(), row->end(), element_dofs.front()),
02241                     high = std::upper_bound (low,          row->end(), element_dofs.back());
02242 
02243                   for (unsigned int j=0; j<n_dofs_on_element; j++)
02244                     {
02245                       const dof_id_type jg = element_dofs[j];
02246 
02247                       // See if jg is in the sorted range
02248                       std::pair<SparsityPattern::Row::iterator,
02249                                 SparsityPattern::Row::iterator>
02250                         pos = std::equal_range (low, high, jg);
02251 
02252                       // Must add jg if it wasn't found
02253                       if (pos.first == pos.second)
02254                         dofs_to_add.push_back(jg);
02255 
02256                       // pos.first is now a valid lower bound for any
02257                       // remaining element DOFs. (That's why we sorted them.)
02258                       // Use it for the next search
02259                       low = pos.first;
02260                     }
02261 
02262                   // Add to the sparsity pattern
02263                   if (!dofs_to_add.empty())
02264                     {
02265                       const std::size_t old_size = row->size();
02266 
02267                       row->insert (row->end(),
02268                                    dofs_to_add.begin(),
02269                                    dofs_to_add.end());
02270 
02271                       SparsityPattern::sort_row
02272                         (row->begin(), row->begin()+old_size, row->end());
02273                     }
02274                 }
02275 
02276               // Now (possibly) add dofs from neighboring elements
02277               // TODO:[BSK] optimize this like above!
02278               if (implicit_neighbor_dofs)
02279                 for (unsigned int s=0; s<elem->n_sides(); s++)
02280                   if (elem->neighbor(s) != NULL)
02281                     {
02282                       const Elem* const neighbor_0 = elem->neighbor(s);
02283 #ifdef LIBMESH_ENABLE_AMR
02284                       neighbor_0->active_family_tree_by_neighbor(active_neighbors,elem);
02285 #else
02286                       active_neighbors.clear();
02287                       active_neighbors.push_back(neighbor_0);
02288 #endif
02289 
02290                       for (std::size_t a=0; a != active_neighbors.size(); ++a)
02291                         {
02292                           const Elem *neighbor = active_neighbors[a];
02293 
02294                           dof_map.dof_indices (neighbor, neighbor_dofs);
02295 #ifdef LIBMESH_ENABLE_CONSTRAINTS
02296                           dof_map.find_connected_dofs (neighbor_dofs);
02297 #endif
02298                           const std::size_t n_dofs_on_neighbor = neighbor_dofs.size();
02299 
02300                           for (std::size_t j=0; j<n_dofs_on_neighbor; j++)
02301                             {
02302                               const dof_id_type jg = neighbor_dofs[j];
02303 
02304                               // See if jg is in the sorted range
02305                               std::pair<SparsityPattern::Row::iterator,
02306                                         SparsityPattern::Row::iterator>
02307                                 pos = std::equal_range (row->begin(), row->end(), jg);
02308 
02309                               // Insert jg if it wasn't found
02310                               if (pos.first == pos.second)
02311                                 row->insert (pos.first, jg);
02312                             }
02313                         }
02314                     }
02315             }
02316         }
02317     }
02318 
02319   // This is what we do in the case that the user has specified
02320   // explicit DOF coupling.
02321   else
02322     {
02323       libmesh_assert(dof_coupling);
02324       libmesh_assert_equal_to (dof_coupling->size(),
02325                                dof_map.n_variables());
02326 
02327       const unsigned int n_var = dof_map.n_variables();
02328 
02329       std::vector<dof_id_type>
02330         element_dofs_i,
02331         element_dofs_j,
02332         neighbor_dofs,
02333         dofs_to_add;
02334 
02335 
02336       std::vector<const Elem*> active_neighbors;
02337       for (ConstElemRange::const_iterator elem_it = range.begin() ; elem_it != range.end(); ++elem_it)
02338         for (unsigned int vi=0; vi<n_var; vi++)
02339           {
02340             const Elem* const elem = *elem_it;
02341 
02342             // Find element dofs for variable vi
02343             dof_map.dof_indices (elem, element_dofs_i, vi);
02344 #ifdef LIBMESH_ENABLE_CONSTRAINTS
02345             dof_map.find_connected_dofs (element_dofs_i);
02346 #endif
02347 
02348             // We can be more efficient if we sort the element DOFs
02349             // into increasing order
02350             std::sort(element_dofs_i.begin(), element_dofs_i.end());
02351             const unsigned int n_dofs_on_element_i =
02352               libmesh_cast_int<unsigned int>(element_dofs_i.size());
02353 
02354             for (unsigned int vj=0; vj<n_var; vj++)
02355               if ((*dof_coupling)(vi,vj)) // If vi couples to vj
02356                 {
02357                   // Find element dofs for variable vj, note that
02358                   // if vi==vj we already have the dofs.
02359                   if (vi != vj)
02360                     {
02361                       dof_map.dof_indices (elem, element_dofs_j, vj);
02362 #ifdef LIBMESH_ENABLE_CONSTRAINTS
02363                       dof_map.find_connected_dofs (element_dofs_j);
02364 #endif
02365 
02366                       // We can be more efficient if we sort the element DOFs
02367                       // into increasing order
02368                       std::sort (element_dofs_j.begin(), element_dofs_j.end());
02369                     }
02370                   else
02371                     element_dofs_j = element_dofs_i;
02372 
02373                   const unsigned int n_dofs_on_element_j =
02374                     libmesh_cast_int<unsigned int>(element_dofs_j.size());
02375 
02376                   // there might be 0 dofs for the other variable on the same element (when subdomain variables do not overlap) and that's when we do not do anything
02377                   if (n_dofs_on_element_j > 0)
02378                   {
02379                     for (unsigned int i=0; i<n_dofs_on_element_i; i++)
02380                     {
02381                       const dof_id_type ig = element_dofs_i[i];
02382 
02383                       SparsityPattern::Row *row;
02384 
02385                       // We save non-local row components for now so we can
02386                       // communicate them to other processors later.
02387              
02388                       if ((ig >= first_dof_on_proc) &&
02389                           (ig <  end_dof_on_proc))
02390                         {
02391                           // This is what I mean
02392                           // libmesh_assert_greater_equal ((ig - first_dof_on_proc), 0);
02393                           // but do the test like this because ig and
02394                           // first_dof_on_proc are unsigned ints
02395                           libmesh_assert_greater_equal (ig, first_dof_on_proc);
02396                           libmesh_assert_less (ig, (sparsity_pattern.size() +
02397                                         first_dof_on_proc));
02398 
02399                           row = &sparsity_pattern[ig - first_dof_on_proc];
02400                         }
02401                       else
02402                         {
02403                           row = &nonlocal_pattern[ig];
02404                         }
02405 
02406                       // If the row is empty we will add *all* the element j DOFs,
02407                       // so just do that.
02408                       if (row->empty())
02409                         {
02410                           row->insert(row->end(),
02411                                       element_dofs_j.begin(),
02412                                       element_dofs_j.end());
02413                         }
02414                       else
02415                         {
02416                           // Build a list of the DOF indices not found in the
02417                           // sparsity pattern
02418                           dofs_to_add.clear();
02419 
02420                           // Cache iterators.  Low will move forward, subsequent
02421                           // searches will be on smaller ranges
02422                           SparsityPattern::Row::iterator
02423                             low  = std::lower_bound
02424                               (row->begin(), row->end(), element_dofs_j.front()),
02425                             high = std::upper_bound
02426                               (low,          row->end(), element_dofs_j.back());
02427 
02428                           for (unsigned int j=0; j<n_dofs_on_element_j; j++)
02429                             {
02430                               const dof_id_type jg = element_dofs_j[j];
02431 
02432                               // See if jg is in the sorted range
02433                               std::pair<SparsityPattern::Row::iterator,
02434                                         SparsityPattern::Row::iterator>
02435                                 pos = std::equal_range (low, high, jg);
02436 
02437                               // Must add jg if it wasn't found
02438                               if (pos.first == pos.second)
02439                                 dofs_to_add.push_back(jg);
02440 
02441                               // pos.first is now a valid lower bound for any
02442                               // remaining element j DOFs. (That's why we sorted them.)
02443                               // Use it for the next search
02444                               low = pos.first;
02445                             }
02446 
02447                           // Add to the sparsity pattern
02448                           if (!dofs_to_add.empty())
02449                             {
02450                               const std::size_t old_size = row->size();
02451 
02452                               row->insert (row->end(),
02453                                            dofs_to_add.begin(),
02454                                            dofs_to_add.end());
02455 
02456                               SparsityPattern::sort_row
02457                                 (row->begin(), row->begin()+old_size,
02458                                  row->end());
02459                             }
02460                         }
02461                        // Now (possibly) add dofs from neighboring elements
02462                        // TODO:[BSK] optimize this like above!
02463                        if (implicit_neighbor_dofs)
02464                          for (unsigned int s=0; s<elem->n_sides(); s++)
02465                            if (elem->neighbor(s) != NULL)
02466                              {
02467                                const Elem* const neighbor_0 = elem->neighbor(s);
02468 #ifdef LIBMESH_ENABLE_AMR
02469                                neighbor_0->active_family_tree_by_neighbor(active_neighbors,elem);
02470 #else
02471                                active_neighbors.clear();
02472                                active_neighbors.push_back(neighbor_0);
02473 #endif
02474 
02475                                for (std::size_t a=0; a != active_neighbors.size(); ++a)
02476                                  {
02477                                    const Elem *neighbor = active_neighbors[a];
02478 
02479                                    dof_map.dof_indices (neighbor, neighbor_dofs);
02480 #ifdef LIBMESH_ENABLE_CONSTRAINTS
02481                                    dof_map.find_connected_dofs (neighbor_dofs);
02482 #endif
02483                                    const unsigned int n_dofs_on_neighbor =
02484                                      libmesh_cast_int<unsigned int>(neighbor_dofs.size());
02485 
02486                                    for (unsigned int j=0; j<n_dofs_on_neighbor; j++)
02487                                      {
02488                                        const dof_id_type jg = neighbor_dofs[j];
02489 
02490                                        // See if jg is in the sorted range
02491                                        std::pair<SparsityPattern::Row::iterator,
02492                                                  SparsityPattern::Row::iterator>
02493                                          pos = std::equal_range (row->begin(), row->end(), jg);
02494 
02495                                        // Insert jg if it wasn't found
02496                                        if (pos.first == pos.second)
02497                                          row->insert (pos.first, jg);
02498                                      }
02499                                  }
02500                              }
02501                     }
02502                   }
02503                 }
02504           }
02505     }
02506 
02507   // Now a new chunk of sparsity structure is built for all of the
02508   // DOFs connected to our rows of the matrix.
02509 
02510   // If we're building a full sparsity pattern, then we've got
02511   // complete rows to work with, so we can just count them from
02512   // scratch.
02513   if (need_full_sparsity_pattern)
02514     {
02515       n_nz.clear();
02516       n_oz.clear();
02517     }
02518 
02519   n_nz.resize (n_dofs_on_proc, 0);
02520   n_oz.resize (n_dofs_on_proc, 0);
02521 
02522   for (dof_id_type i=0; i<n_dofs_on_proc; i++)
02523     {
02524       // Get the row of the sparsity pattern
02525       SparsityPattern::Row &row = sparsity_pattern[i];
02526 
02527       for (dof_id_type j=0; j<row.size(); j++)
02528         if ((row[j] < first_dof_on_proc) || (row[j] >= end_dof_on_proc))
02529           n_oz[i]++;
02530         else
02531           n_nz[i]++;
02532 
02533       // If we're not building a full sparsity pattern, then we want
02534       // to avoid overcounting these entries as much as possible.
02535       if (!need_full_sparsity_pattern)
02536         row.clear();
02537     }
02538 }

void libMesh::SparsityPattern::Build::parallel_sync (  ) 

Definition at line 2645 of file dof_map.C.

References libMesh::CommWorld, dof_map, libMesh::DofMap::end_dof(), libMesh::DofMap::first_dof(), std::min(), libMesh::DofMap::n_dofs(), libMesh::DofMap::n_dofs_on_processor(), n_nz, n_oz, libMesh::n_processors(), need_full_sparsity_pattern, nonlocal_pattern, libMesh::processor_id(), libMesh::Parallel::Communicator::send_receive(), sparsity_pattern, and libMesh::Parallel::Communicator::verify().

02646 {
02647   parallel_only();
02648   CommWorld.verify(need_full_sparsity_pattern);
02649 
02650   const dof_id_type n_global_dofs   = dof_map.n_dofs();
02651   const dof_id_type n_dofs_on_proc  = dof_map.n_dofs_on_processor(libMesh::processor_id());
02652   const dof_id_type local_first_dof = dof_map.first_dof();
02653   const dof_id_type local_end_dof   = dof_map.end_dof();
02654 
02655   // Trade sparsity rows with other processors
02656   for (processor_id_type p=1; p != libMesh::n_processors(); ++p)
02657     {
02658       // Push to processor procup while receiving from procdown
02659       processor_id_type procup = (libMesh::processor_id() + p) %
02660                                   libMesh::n_processors();
02661       processor_id_type procdown = (libMesh::n_processors() +
02662                                     libMesh::processor_id() - p) %
02663                                     libMesh::n_processors();
02664 
02665       // Pack the sparsity pattern rows to push to procup
02666       std::vector<dof_id_type> pushed_row_ids,
02667                                pushed_row_ids_to_me;
02668       std::vector<std::vector<dof_id_type> > pushed_rows,
02669                                              pushed_rows_to_me;
02670 
02671       // Move nonlocal row information to a structure to send it from;
02672       // we don't need it in the map after that.
02673       NonlocalGraph::iterator it = nonlocal_pattern.begin();
02674       while (it != nonlocal_pattern.end())
02675         {
02676           const dof_id_type dof_id = it->first;
02677           processor_id_type proc_id = 0;
02678           while (dof_id >= dof_map.end_dof(proc_id))
02679             proc_id++;
02680 
02681           libmesh_assert (proc_id != libMesh::processor_id());
02682 
02683           if (proc_id == procup)
02684             {
02685               pushed_row_ids.push_back(dof_id);
02686 
02687               // We can't just do the swap trick here, thanks to the
02688               // differing vector allocators?
02689               pushed_rows.push_back(std::vector<dof_id_type>());
02690               pushed_rows.back().assign
02691                 (it->second.begin(), it->second.end());
02692 
02693               nonlocal_pattern.erase(it++);
02694             }
02695           else
02696             ++it;
02697         }
02698 
02699       CommWorld.send_receive(procup, pushed_row_ids,
02700                              procdown, pushed_row_ids_to_me);
02701       CommWorld.send_receive(procup, pushed_rows,
02702                              procdown, pushed_rows_to_me);
02703       pushed_row_ids.clear();
02704       pushed_rows.clear();
02705 
02706       const std::size_t n_rows = pushed_row_ids_to_me.size();
02707       for (std::size_t i=0; i != n_rows; ++i)
02708         {
02709           const dof_id_type r = pushed_row_ids_to_me[i];
02710           const dof_id_type my_r = r - local_first_dof;
02711 
02712           std::vector<dof_id_type> &their_row = pushed_rows_to_me[i];
02713         
02714           if (need_full_sparsity_pattern)
02715             {
02716               SparsityPattern::Row &my_row =
02717                 sparsity_pattern[my_r];
02718 
02719               // They wouldn't have sent an empty row
02720               libmesh_assert(!their_row.empty());
02721 
02722               // We can end up with an empty row on a dof that touches our
02723               // inactive elements but not our active ones
02724               if (my_row.empty())
02725                 {
02726                   my_row.assign (their_row.begin(),
02727                                  their_row.end());
02728                 }
02729               else
02730                 {
02731                   my_row.insert (my_row.end(),
02732                                  their_row.begin(),
02733                                  their_row.end());
02734 
02735                   // We cannot use SparsityPattern::sort_row() here because it expects
02736                   // the [begin,middle) [middle,end) to be non-overlapping.  This is not
02737                   // necessarily the case here, so use std::sort()
02738                   std::sort (my_row.begin(), my_row.end());
02739 
02740                   my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
02741                 }
02742 
02743               // fix the number of on and off-processor nonzeros in this row
02744               n_nz[my_r] = n_oz[my_r] = 0;
02745 
02746               for (std::size_t j=0; j<my_row.size(); j++)
02747                 if ((my_row[j] < local_first_dof) || (my_row[j] >= local_end_dof))
02748                   n_oz[my_r]++;
02749                 else
02750                   n_nz[my_r]++;
02751             }
02752           else
02753             {
02754               for (std::size_t j=0; j<their_row.size(); j++)
02755                 if ((their_row[j] < local_first_dof) || (their_row[j] >= local_end_dof))
02756                   n_oz[my_r]++;
02757                 else
02758                   n_nz[my_r]++;
02759 
02760               n_nz[my_r] = std::min(n_nz[my_r], n_dofs_on_proc);
02761               n_oz[my_r] = std::min(n_oz[my_r],
02762                                     static_cast<dof_id_type>(n_global_dofs-n_nz[my_r]));
02763             }
02764         }
02765     }
02766 
02767     // We should have sent everything at this point.
02768     libmesh_assert (nonlocal_pattern.empty());
02769 }


Member Data Documentation

Definition at line 83 of file sparsity_pattern.h.

Referenced by operator()().

Definition at line 82 of file sparsity_pattern.h.

Referenced by join(), operator()(), and parallel_sync().

Definition at line 84 of file sparsity_pattern.h.

Referenced by operator()().

Definition at line 81 of file sparsity_pattern.h.

Definition at line 92 of file sparsity_pattern.h.

Referenced by join(), operator()(), and parallel_sync().

Definition at line 93 of file sparsity_pattern.h.

Referenced by join(), operator()(), and parallel_sync().

Definition at line 85 of file sparsity_pattern.h.

Referenced by join(), operator()(), and parallel_sync().


The documentation for this class was generated from the following files:

Site Created By: libMesh Developers
Last modified: February 05 2013 19:55:49 UTC

Hosted By:
SourceForge.net Logo