libMesh::Parallel::Sort< KeyType, IdxType > Class Template Reference

#include <parallel_sort.h>

List of all members.

Public Member Functions

 Sort (std::vector< KeyType > &d, const processor_id_type n_procs=libMesh::n_processors(), const processor_id_type proc_id=libMesh::processor_id())
void sort ()
const std::vector< KeyType > & bin ()
template<>
void binsort ()
template<>
void communicate_bins ()

Private Member Functions

void binsort ()
void communicate_bins ()
void sort_local_bin ()

Private Attributes

const processor_id_type _n_procs
const processor_id_type _proc_id
bool _bin_is_sorted
std::vector< KeyType > & _data
std::vector< IdxType > _local_bin_sizes
std::vector< KeyType > _my_bin

Detailed Description

template<typename KeyType, typename IdxType = unsigned int>
class libMesh::Parallel::Sort< KeyType, IdxType >

The parallel sorting method is templated on the type of data which is to be sorted. It may later be templated on other things if we are ambitious. This class knows about MPI, and knows how many processors there are. It is responsible for transmitting data between the processors and ensuring that the data is properly sorted between all the processors. We assume that a Sort is instantiated on all processors.

Definition at line 47 of file parallel_sort.h.


Constructor & Destructor Documentation

template<typename KeyType , typename IdxType >
libMesh::Parallel::Sort< KeyType, IdxType >::Sort ( std::vector< KeyType > &  d,
const processor_id_type  n_procs = libMesh::n_processors(),
const processor_id_type  proc_id = libMesh::processor_id() 
) [inline]

Constructor takes the number of processors, the processor id, and a reference to a vector of data to be sorted. This vector is sorted by the constructor, therefore, construction of a Sort object takes O(nlogn) time, where n is the length of the vector.

Definition at line 44 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_data, libMesh::Parallel::Sort< KeyType, IdxType >::_local_bin_sizes, libMesh::Parallel::Sort< KeyType, IdxType >::_n_procs, and libMesh::Parallel::Sort< KeyType, IdxType >::sort().

00046                                                              :
00047   _n_procs(n_procs),
00048   _proc_id(proc_id),
00049   _bin_is_sorted(false),
00050   _data(d)
00051 {
00052   std::sort(_data.begin(), _data.end());
00053 
00054   // Allocate storage
00055   _local_bin_sizes.resize(_n_procs);
00056 }


Member Function Documentation

template<typename KeyType , typename IdxType >
const std::vector< KeyType > & libMesh::Parallel::Sort< KeyType, IdxType >::bin (  )  [inline]

Return a constant reference to _my_bin. This allows us to do things like check if sorting was successful by printing _my_bin.

Definition at line 355 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_bin_is_sorted, libMesh::Parallel::Sort< KeyType, IdxType >::_my_bin, and libMesh::out.

Referenced by libMesh::MeshCommunication::assign_global_indices(), and libMesh::MeshCommunication::find_global_indices().

00356 {
00357   if (!_bin_is_sorted)
00358     {
00359       libMesh::out << "Warning! Bin is not yet sorted!" << std::endl;
00360     }
00361 
00362   return _my_bin;
00363 }

template<>
void libMesh::Parallel::Sort< Hilbert::HilbertIndices, unsigned int >::binsort (  )  [inline]

Definition at line 133 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_data, libMesh::Parallel::Sort< KeyType, IdxType >::_local_bin_sizes, libMesh::Parallel::Sort< KeyType, IdxType >::_n_procs, libMesh::Parallel::BinSorter< KeyType, IdxType >::binsort(), libMesh::COMM_WORLD, and libMesh::Parallel::BinSorter< KeyType, IdxType >::sizeof_bin().

00134 {
00135   // Find the global min and max from all the
00136   // processors.  Do this using MPI_Allreduce.
00137   Hilbert::HilbertIndices
00138     local_min,  local_max,
00139     global_min, global_max;
00140 
00141   if (_data.empty())
00142     {
00143       local_min.rack0 = local_min.rack1 = local_min.rack2 = static_cast<Hilbert::inttype>(-1);
00144       local_max.rack0 = local_max.rack1 = local_max.rack2 = 0;
00145     }
00146   else
00147     {
00148       local_min = _data.front();
00149       local_max = _data.back();
00150     }
00151 
00152   MPI_Op hilbert_max, hilbert_min;
00153 
00154   MPI_Op_create       ((MPI_User_function*)__hilbert_max_op, true, &hilbert_max);
00155   MPI_Op_create       ((MPI_User_function*)__hilbert_min_op, true, &hilbert_min);
00156 
00157   // Communicate to determine the global
00158   // min and max for all processors.
00159   MPI_Allreduce(&local_min,
00160                 &global_min,
00161                 1,
00162                 Parallel::StandardType<Hilbert::HilbertIndices>(),
00163                 hilbert_min,
00164                 libMesh::COMM_WORLD);
00165 
00166   MPI_Allreduce(&local_max,
00167                 &global_max,
00168                 1,
00169                 Parallel::StandardType<Hilbert::HilbertIndices>(),
00170                 hilbert_max,
00171                 libMesh::COMM_WORLD);
00172 
00173   MPI_Op_free   (&hilbert_max);
00174   MPI_Op_free   (&hilbert_min);
00175 
00176   // Bin-Sort based on the global min and max
00177   Parallel::BinSorter<Hilbert::HilbertIndices> bs(_data);
00178   bs.binsort(_n_procs, global_max, global_min);
00179 
00180   // Now save the local bin sizes in a vector so
00181   // we don't have to keep around the BinSorter.
00182   for (processor_id_type i=0; i<_n_procs; ++i)
00183     _local_bin_sizes[i] = bs.sizeof_bin(i);
00184 }

template<typename KeyType , typename IdxType >
void libMesh::Parallel::Sort< KeyType, IdxType >::binsort (  )  [inline, private]

Sorts the local data into bins across all processors. Right now it constructs a BenSorter<KeyType> object. In the future this could be a template parameter.

Definition at line 99 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_data, libMesh::Parallel::Sort< KeyType, IdxType >::_local_bin_sizes, libMesh::Parallel::Sort< KeyType, IdxType >::_n_procs, libMesh::Parallel::BinSorter< KeyType, IdxType >::binsort(), libMesh::CommWorld, libMesh::Parallel::Communicator::max(), and libMesh::Parallel::BinSorter< KeyType, IdxType >::sizeof_bin().

Referenced by libMesh::Parallel::Sort< KeyType, IdxType >::sort().

00100 {
00101   // Find the global min and max from all the
00102   // processors.
00103   std::vector<KeyType> global_min_max(2);
00104 
00105   // Insert the local min and max for this processor
00106   global_min_max[0] = -_data.front();
00107   global_min_max[1] =  _data.back();
00108 
00109   // Communicate to determine the global
00110   // min and max for all processors.
00111   CommWorld.max(global_min_max);
00112 
00113   // Multiply the min by -1 to obtain the true min
00114   global_min_max[0] *= -1;
00115 
00116   // Bin-Sort based on the global min and max
00117   Parallel::BinSorter<KeyType> bs(_data);
00118   bs.binsort(_n_procs, global_min_max[1], global_min_max[0]);
00119 
00120   // Now save the local bin sizes in a vector so
00121   // we don't have to keep around the BinSorter.
00122   for (processor_id_type i=0; i<_n_procs; ++i)
00123     _local_bin_sizes[i] = bs.sizeof_bin(i);
00124 }

template<>
void libMesh::Parallel::Sort< Hilbert::HilbertIndices, unsigned int >::communicate_bins (  )  [inline]

Definition at line 262 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_data, libMesh::Parallel::Sort< KeyType, IdxType >::_local_bin_sizes, libMesh::Parallel::Sort< KeyType, IdxType >::_my_bin, libMesh::Parallel::Sort< KeyType, IdxType >::_n_procs, libMesh::Parallel::Sort< KeyType, IdxType >::_proc_id, and libMesh::COMM_WORLD.

00263 {
00264   // Create storage for the global bin sizes.  This
00265   // is the number of keys which will be held in
00266   // each bin over all processors.
00267   std::vector<unsigned int> global_bin_sizes(_n_procs);
00268 
00269   libmesh_assert_equal_to (_local_bin_sizes.size(), global_bin_sizes.size());
00270 
00271   // Sum to find the total number of entries in each bin.
00272   // This is stored in global_bin_sizes.  Note, we
00273   // explicitly know that we are communicating MPI_UNSIGNED's here.
00274   MPI_Allreduce(&_local_bin_sizes[0],
00275                 &global_bin_sizes[0],
00276                 _n_procs,
00277                 MPI_UNSIGNED,
00278                 MPI_SUM,
00279                 libMesh::COMM_WORLD);
00280 
00281   // Create a vector to temporarily hold the results of MPI_Gatherv
00282   // calls.  The vector dest  may be saved away to _my_bin depending on which
00283   // processor is being MPI_Gatherv'd.
00284   std::vector<Hilbert::HilbertIndices> sendbuf, dest;
00285 
00286   unsigned int local_offset = 0;
00287 
00288   for (unsigned int i=0; i<_n_procs; ++i)
00289     {
00290       // Vector to receive the total bin size for each
00291       // processor.  Processor i's bin size will be
00292       // held in proc_bin_size[i]
00293       std::vector<unsigned int> proc_bin_size(_n_procs);
00294 
00295       // Find the number of contributions coming from each
00296       // processor for this bin.  Note: Allgather combines
00297       // the MPI_Gather and MPI_Bcast operations into one.
00298       // Note: Here again we know that we are communicating
00299       // MPI_UNSIGNED's so there is no need to check the MPI_traits.
00300       MPI_Allgather(&_local_bin_sizes[i], // Source: # of entries on this proc in bin i
00301                     1,                    // Number of items to gather
00302                     MPI_UNSIGNED,
00303                     &proc_bin_size[0],    // Destination: Total # of entries in bin i
00304                     1,
00305                     MPI_UNSIGNED,
00306                     libMesh::COMM_WORLD);
00307 
00308       // Compute the offsets into my_bin for each processor's
00309       // portion of the bin.  These are basically partial sums
00310       // of the proc_bin_size vector.
00311       std::vector<unsigned int> displacements(_n_procs);
00312       for (unsigned int j=1; j<_n_procs; ++j)
00313         displacements[j] = proc_bin_size[j-1] + displacements[j-1];
00314 
00315       // Resize the destination buffer
00316       dest.resize (global_bin_sizes[i]);
00317 
00318       MPI_Gatherv((_data.size() > local_offset) ?
00319                     &_data[local_offset] :
00320                     NULL,                   // Points to the beginning of the bin to be sent
00321                   _local_bin_sizes[i],      // How much data is in the bin being sent.
00322                   Parallel::StandardType<Hilbert::HilbertIndices>(), // The data type we are sorting
00323                   (dest.empty()) ?
00324                     NULL :
00325                     &dest[0],               // Enough storage to hold all bin contributions
00326                   (int*) &proc_bin_size[0], // How much is to be received from each processor
00327                   (int*) &displacements[0], // Offsets into the receive buffer
00328                   Parallel::StandardType<Hilbert::HilbertIndices>(), // The data type we are sorting
00329                   i,                        // The root process (we do this once for each proc)
00330                   libMesh::COMM_WORLD);
00331 
00332       // Copy the destination buffer if it
00333       // corresponds to the bin for this processor
00334       if (i == _proc_id)
00335         _my_bin = dest;
00336 
00337       // Increment the local offset counter
00338       local_offset += _local_bin_sizes[i];
00339     }
00340 }

template<typename KeyType , typename IdxType >
void libMesh::Parallel::Sort< KeyType, IdxType >::communicate_bins (  )  [inline, private]

Communicates the bins from each processor to the appropriate processor. By the time this function is finished, each processor will hold only its own bin(s).

Definition at line 190 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_data, libMesh::Parallel::Sort< KeyType, IdxType >::_local_bin_sizes, libMesh::Parallel::Sort< KeyType, IdxType >::_my_bin, libMesh::Parallel::Sort< KeyType, IdxType >::_n_procs, libMesh::Parallel::Sort< KeyType, IdxType >::_proc_id, libMesh::Parallel::allgather(), libMesh::COMM_WORLD, libMesh::CommWorld, and libMesh::Parallel::Communicator::sum().

Referenced by libMesh::Parallel::Sort< KeyType, IdxType >::sort().

00191 {
00192 #ifdef LIBMESH_HAVE_MPI
00193   // Create storage for the global bin sizes.  This
00194   // is the number of keys which will be held in
00195   // each bin over all processors.
00196   std::vector<IdxType> global_bin_sizes = _local_bin_sizes;
00197 
00198   // Sum to find the total number of entries in each bin.
00199   CommWorld.sum(global_bin_sizes);
00200 
00201   // Create a vector to temporarily hold the results of MPI_Gatherv
00202   // calls.  The vector dest  may be saved away to _my_bin depending on which
00203   // processor is being MPI_Gatherv'd.
00204   std::vector<KeyType> dest;
00205 
00206   IdxType local_offset = 0;
00207 
00208   for (processor_id_type i=0; i<_n_procs; ++i)
00209     {
00210       // Vector to receive the total bin size for each
00211       // processor.  Processor i's bin size will be
00212       // held in proc_bin_size[i]
00213       std::vector<IdxType> proc_bin_size;
00214 
00215       // Find the number of contributions coming from each
00216       // processor for this bin.  Note: allgather combines
00217       // the MPI_Gather and MPI_Bcast operations into one.
00218       Parallel::allgather(_local_bin_sizes[i], proc_bin_size);
00219 
00220       // Compute the offsets into my_bin for each processor's
00221       // portion of the bin.  These are basically partial sums
00222       // of the proc_bin_size vector.
00223       std::vector<IdxType> displacements(_n_procs);
00224       for (processor_id_type j=1; j<_n_procs; ++j)
00225         displacements[j] = proc_bin_size[j-1] + displacements[j-1];
00226 
00227       // Resize the destination buffer
00228       dest.resize (global_bin_sizes[i]);
00229 
00230       MPI_Gatherv((_data.size() > local_offset) ?
00231                     &_data[local_offset] :
00232                     NULL,                            // Points to the beginning of the bin to be sent
00233                   _local_bin_sizes[i],               // How much data is in the bin being sent.
00234                   Parallel::StandardType<KeyType>(), // The data type we are sorting
00235                   (dest.empty()) ?
00236                     NULL :
00237                     &dest[0],                        // Enough storage to hold all bin contributions
00238                   (int*) &proc_bin_size[0],          // How much is to be received from each processor
00239                   (int*) &displacements[0],          // Offsets into the receive buffer
00240                   Parallel::StandardType<KeyType>(), // The data type we are sorting
00241                   i,                                 // The root process (we do this once for each proc)
00242                   libMesh::COMM_WORLD);
00243 
00244       // Copy the destination buffer if it
00245       // corresponds to the bin for this processor
00246       if (i == _proc_id)
00247         _my_bin = dest;
00248 
00249       // Increment the local offset counter
00250       local_offset += _local_bin_sizes[i];
00251     }
00252 #endif // LIBMESH_HAVE_MPI
00253 }

template<typename KeyType , typename IdxType >
void libMesh::Parallel::Sort< KeyType, IdxType >::sort (  )  [inline]

This is the only method which needs to be called by the user. Its only responsibility is to call three private methods in the correct order.

Definition at line 61 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_bin_is_sorted, libMesh::Parallel::Sort< KeyType, IdxType >::_data, libMesh::Parallel::Sort< KeyType, IdxType >::_local_bin_sizes, libMesh::Parallel::Sort< KeyType, IdxType >::_my_bin, libMesh::Parallel::Communicator::allgather(), libMesh::Parallel::Sort< KeyType, IdxType >::binsort(), libMesh::Parallel::Sort< KeyType, IdxType >::communicate_bins(), libMesh::CommWorld, libMesh::n_processors(), libMesh::Parallel::Sort< KeyType, IdxType >::sort_local_bin(), and libMesh::Parallel::Communicator::sum().

Referenced by libMesh::MeshCommunication::assign_global_indices(), libMesh::MeshCommunication::find_global_indices(), libMesh::Parallel::Sort< KeyType, IdxType >::Sort(), and libMesh::Parallel::Sort< KeyType, IdxType >::sort_local_bin().

00062 {
00063   // Find the global data size.  The sorting
00064   // algorithms assume they have a range to
00065   // work with, so catch the degenerate cases here
00066   IdxType global_data_size = libmesh_cast_int<IdxType>(_data.size());
00067 
00068   CommWorld.sum (global_data_size);
00069 
00070   if (global_data_size < 2)
00071     {
00072       // the entire global range is either empty
00073       // or contains only one element
00074       _my_bin = _data;
00075 
00076       CommWorld.allgather (static_cast<IdxType>(_my_bin.size()),
00077                            _local_bin_sizes);
00078     }
00079   else
00080     {
00081       if (libMesh::n_processors() > 1)
00082         {
00083           this->binsort();
00084           this->communicate_bins();
00085         }
00086       else
00087         _my_bin = _data;
00088 
00089       this->sort_local_bin();
00090     }
00091 
00092   // Set sorted flag to true
00093   _bin_is_sorted = true;
00094 }

template<typename KeyType , typename IdxType >
void libMesh::Parallel::Sort< KeyType, IdxType >::sort_local_bin (  )  [inline, private]

After all the bins have been communicated, we can sort our local bin. This is nothing more than a call to std::sort

Definition at line 347 of file parallel_sort.C.

References libMesh::Parallel::Sort< KeyType, IdxType >::_my_bin, and libMesh::Parallel::Sort< KeyType, IdxType >::sort().

Referenced by libMesh::Parallel::Sort< KeyType, IdxType >::sort().

00348 {
00349   std::sort(_my_bin.begin(), _my_bin.end());
00350 }


Member Data Documentation

template<typename KeyType, typename IdxType = unsigned int>
bool libMesh::Parallel::Sort< KeyType, IdxType >::_bin_is_sorted [private]

Flag which lets you know if sorting is complete

Definition at line 93 of file parallel_sort.h.

Referenced by libMesh::Parallel::Sort< KeyType, IdxType >::bin(), and libMesh::Parallel::Sort< KeyType, IdxType >::sort().

template<typename KeyType, typename IdxType = unsigned int>
std::vector<KeyType>& libMesh::Parallel::Sort< KeyType, IdxType >::_data [private]
template<typename KeyType, typename IdxType = unsigned int>
std::vector<IdxType> libMesh::Parallel::Sort< KeyType, IdxType >::_local_bin_sizes [private]
template<typename KeyType, typename IdxType = unsigned int>
std::vector<KeyType> libMesh::Parallel::Sort< KeyType, IdxType >::_my_bin [private]

The bin which will eventually be held by this processor. It may be shorter or longer than _data. It will be dynamically resized when it is needed.

Definition at line 115 of file parallel_sort.h.

Referenced by libMesh::Parallel::Sort< KeyType, IdxType >::bin(), libMesh::Parallel::Sort< KeyType, IdxType >::communicate_bins(), libMesh::Parallel::Sort< KeyType, IdxType >::sort(), and libMesh::Parallel::Sort< KeyType, IdxType >::sort_local_bin().

template<typename KeyType, typename IdxType = unsigned int>
const processor_id_type libMesh::Parallel::Sort< KeyType, IdxType >::_n_procs [private]
template<typename KeyType, typename IdxType = unsigned int>
const processor_id_type libMesh::Parallel::Sort< KeyType, IdxType >::_proc_id [private]

The identity of this processor.

Definition at line 88 of file parallel_sort.h.

Referenced by libMesh::Parallel::Sort< KeyType, IdxType >::communicate_bins().


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

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

Hosted By:
SourceForge.net Logo