src/utility/parallel_tools.h

Go to the documentation of this file.
00001 #ifndef ParallelTools_h
00002 #define ParallelTools_h
00003 #include <cassert>
00004 #include <algorithm>
00005 #include <iostream>
00006 #include <map>
00007 #include <utility>
00008 #include <sstream>
00009 #include <vector>
00010 #include "mpi.h"
00011 #include "utility/triple.h"
00012 #include "tetmesh/entity.h"
00013 #include "myrlog.h"
00014 
00015 namespace parallel {
00016 
00017   //using namespace std;
00018 using mesh::id_t;
00019 
00023 template <typename T>
00024 class Mpi_DType {
00025 };
00026 
00027 template <>
00028 class Mpi_DType<int> {
00029     static const MPI_Datatype mpi_dtype;
00030 };
00031 
00032 template <>
00033 class Mpi_DType<unsigned int> {
00034     static const MPI_Datatype mpi_dtype;
00035 };
00036 
00037 template <>
00038 class Mpi_DType<unsigned long> {
00039     static const MPI_Datatype mpi_dtype;
00040 };
00041 
00042 /*
00043  * Template specialisations for determine_proc_of_this_element.
00044  */
00045 
00046 template<typename T>
00047 int determine_proc_of_this_element(T nodes, std::vector<int>& procs);
00048 
00049 template<>
00050 int determine_proc_of_this_element<std::pair<id_t, id_t> >(std::pair<id_t, id_t> nodes, std::vector<int>& procs);
00051 
00052 template<>
00053 int determine_proc_of_this_element<utility::triple<id_t, id_t, id_t> >(utility::triple<id_t, id_t, id_t> nodes, std::vector<int>& procs);
00054 
00055 template<>
00056 int determine_proc_of_this_element<id_t>(id_t node, std::vector<int>& procs);
00057 
00075 template <typename T>
00076 int assign_gids(std::vector<T>& elements, 
00077                 std::vector<id_t>& gids, 
00078                 std::vector<int>& elem_counts,
00079                 std::vector<int>& elem_displs,
00080                 MPI_Comm comm) 
00081 {
00082     gids.clear();
00083         
00084     int mpi_rank, mpi_size; 
00085     MPI_Comm_rank(comm, &mpi_rank);      
00086     MPI_Comm_size(comm, &mpi_size);
00087     
00088     // Sort elements to facilitate a binary search later on
00089     std::sort(elements.begin(), elements.end());
00090     
00091     // Obtain recvbuf containing all T's on all processors. The processor ID of the processor 
00092     // that sent a particular T is availible from MPI support stuff
00093     std::vector<int> recvcounts, recvbuf_displs;
00094     unsigned int recvbuf_size = set_counts_displs(elements.size(), recvcounts, recvbuf_displs, comm);                     
00095     std::vector<T> recvbuf(recvbuf_size);
00096     
00097     // Byte stuff.
00098     int sendcount_bytes = elements.size() * sizeof(T);
00099     int* recvcounts_bytes = new int[mpi_size];
00100     for (int i = 0; i < mpi_size; i ++)
00101         recvcounts_bytes[i] = recvcounts[i] * sizeof(T);   
00102     
00103     int* displs_bytes = new int[mpi_size];
00104     displs_bytes[0] = 0;
00105     for (int i = 1; i < mpi_size; i++)
00106         displs_bytes[i] = displs_bytes[i-1] + recvcounts_bytes[i-1];            
00107     
00108     MPI_Allgatherv (&elements[0], sendcount_bytes, MPI_BYTE, &recvbuf[0], recvcounts_bytes, displs_bytes, MPI_BYTE, comm);
00109     delete[] recvcounts_bytes;
00110     delete[] displs_bytes;
00111     
00112     gids.resize(recvbuf_size);
00113     
00114     // Construct multimap containing as keys the T objects 
00115     // and as values the processor ID's of processors claiming that object
00116     std::multimap<T,int> procs_claiming_element;
00117     typename std::vector<T>::iterator current_elem = recvbuf.begin();
00118     for (int proc_id = 0; proc_id < mpi_size; proc_id++) {
00119         for (int elem_lid = 0; elem_lid < recvcounts[proc_id]; elem_lid++) {
00120             std::pair<T, int> p(*current_elem, proc_id);
00121             procs_claiming_element.insert(p);
00122             ++current_elem;
00123         }
00124     }
00125     
00126     /*  Determine processor for each unique T by creating a vector of size 
00127     recvbuf containing the target processor of the elements in recvbuf */     
00129     std::vector<int> proc_owning_element;
00130     for (typename std::vector<T>::iterator it = recvbuf.begin(); it != recvbuf.end(); ++it) {
00131         std::vector<int> claimers;
00132         std::pair<typename std::multimap<T,int>::iterator, typename std::multimap<T,int>::iterator> range = procs_claiming_element.equal_range(*it);
00133         for (typename std::multimap<T,int>::iterator j = range.first; j != range.second; ++j)
00134             claimers.push_back((*j).second);
00135         assert (claimers.size() >= 2);
00136         proc_owning_element.push_back(determine_proc_of_this_element<T>(*it, claimers));
00137     }
00138     
00139 #if 0
00140     for (typename std::multimap<T,int>::iterator it = procs_claiming_element.begin(); it != procs_claiming_element.end(); ++it) {
00141         ostringstream buf;
00142         buf << (*it).first;
00143         rDebugAll("elem %s claimed by p%02d", buf.str().c_str(), (*it).second);
00144     }
00145     for (unsigned int i = 0; i < proc_owning_element.size(); i++) 
00146         cout << proc_owning_element[i] << " "; cout << endl;
00147 #endif
00148     
00149     // Calculate number of elements per processor and global ID offset for each processor
00150     elem_counts.clear();
00151     elem_counts.resize(mpi_size);
00152     id_t element_counter = 0;
00153     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00154         elem_counts[i_proc] = 0;
00155         for (int j_elem = 0; j_elem < recvcounts[i_proc]; j_elem++) {            
00156             if (proc_owning_element[element_counter] == i_proc)
00157                 elem_counts[i_proc]++;
00158             element_counter ++;
00159         }
00160     }
00161     elem_displs.resize(mpi_size);
00162     elem_displs[0] = 0;
00163     for (int i = 1; i < mpi_size; i++)
00164         elem_displs[i] = elem_displs[i-1] + elem_counts[i-1];
00165     int num_global_ids = elem_displs[mpi_size - 1] + elem_counts[mpi_size - 1];
00166 
00167 #if 0
00168     cout << "Recvcounts: "; for(int i = 0; i < mpi_size; i++) cout << recvcounts[i] << " "; cout << "." << endl;
00169     cout << "Elements_per_proc: "; for(int i = 0; i < mpi_size; i++) cout << elem_counts[i] << " "; cout << "." << endl;
00170     cout << "Offsets: "; for(int i = 0; i < mpi_size; i++) cout << elem_displs[i] << " "; cout << "." << endl;
00171 #endif
00172     
00173     // Assign local ID's to local elements in recvbuf in a consecutive manner
00174     std::vector<id_t> unmoved_local_ids(recvbuf_size);    
00175     element_counter = 0;
00176     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00177         int id_counter = 0;
00178         for (int j_elems = 0; j_elems < recvcounts[i_proc]; j_elems++) {
00179             if (proc_owning_element[element_counter] == i_proc) {
00180                 unmoved_local_ids[element_counter] = id_counter;
00181                 id_counter++;
00182             } else {
00183                 unmoved_local_ids[element_counter] = mesh::ID_NONE;
00184             }
00185             element_counter++;
00186         }
00187         assert(id_counter == elem_counts[i_proc]);
00188     }
00189     assert (element_counter == recvbuf_size);
00190     
00191     // Assign global ID's of local elements in recvbuf (store in gids vector)
00192     element_counter = 0;
00193     int nof_assigned_elements = 0;
00194     std::vector<id_t> unassigned_elements;
00195     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00196         for (int j_elems = 0; j_elems < recvcounts[i_proc]; j_elems++) {
00197             if (unmoved_local_ids[element_counter] != mesh::ID_NONE) {
00198                 gids[element_counter] = unmoved_local_ids[element_counter] + elem_displs[i_proc];
00199                 nof_assigned_elements++;
00200             } else {
00201                 gids[element_counter] = mesh::ID_NONE;
00202                 unassigned_elements.push_back(element_counter);
00203             }
00204         element_counter++;
00205         }
00206     }
00207     assert (element_counter == recvbuf_size);
00208     
00209     // Assign gids of remote elements in recvbuf (using binary search)
00210     for(std::vector<id_t>::iterator it = unassigned_elements.begin(); it != unassigned_elements.end(); ++it) {
00211        //for (typename std::vector<T>::iterator it = recvbuf.begin(); it != recvbuf.end(); ++it) {
00212         T elem = recvbuf[*it];
00213         int owner = proc_owning_element[*it];
00214         typename std::vector<T>::iterator search_start_point = recvbuf.begin() + recvbuf_displs[owner];
00215         typename std::vector<T>::iterator search_end_point = search_start_point + recvcounts[owner];
00216         std::pair<typename std::vector<T>::iterator, typename std::vector<T>::iterator> result = equal_range(search_start_point, search_end_point, elem);
00217         assert (result.second - result.first == 1); //Want to find exactly one element.
00218         gids[*it] = gids[result.first - recvbuf.begin()];
00219     }    
00220 #if 0
00221     element_counter = 0;
00222     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00223         for (int j_elems = 0; j_elems < recvcounts[i_proc]; j_elems++) {
00224             if (mpi_rank == 1)
00225                 rDebugAll("iproc=%02d, gids[%2d]=%2d", i_proc, element_counter, gids[element_counter]);
00226             element_counter ++;
00227         }
00228     }    
00229 #endif
00230     if (recvbuf_displs[mpi_rank] != 0) {
00231         for (int i = 0; i < recvcounts[mpi_rank]; ++ i)
00232             gids[i] = gids[i + recvbuf_displs[mpi_rank]];
00233         gids.resize(recvcounts[mpi_rank]);
00234     }
00235             
00236     return num_global_ids;
00237 }
00238 
00257 template <typename T>
00258 int assign_gids2(bool* my_claims,
00259                  std::vector<T>& elements,
00260                  std::vector<id_t>& gids, 
00261                  std::vector<int>& elem_counts,
00262                  std::vector<int>& elem_displs,
00263                  MPI_Comm comm) 
00264 {
00265     gids.clear();
00266         
00267     int mpi_rank, mpi_size; 
00268     MPI_Comm_rank(comm, &mpi_rank);      
00269     MPI_Comm_size(comm, &mpi_size);
00270         
00271     // ----------------------------------------------------------------------------------------
00272     // Gather "elements" from all processors:
00273     std::vector<int> recvcounts, recvbuf_displs;
00274     unsigned int recvbuf_size = set_counts_displs(elements.size(), recvcounts, recvbuf_displs, comm);                     
00275     std::vector<T> recvbuf(recvbuf_size);
00276     
00277     // Byte stuff.
00278     int sendcount_bytes = elements.size() * sizeof(T);
00279     int* recvcounts_bytes = new int[mpi_size];
00280     int* displs_bytes = new int[mpi_size];
00281     for (int i = 0; i < mpi_size; i ++) {
00282         recvcounts_bytes[i] = recvcounts[i] * sizeof(T);
00283         displs_bytes[i] = recvbuf_displs[i] * sizeof(T);
00284     }
00285             
00286     MPI_Allgatherv (&elements[0], sendcount_bytes, MPI_BYTE, &recvbuf[0], recvcounts_bytes, displs_bytes, MPI_BYTE, comm);
00287     delete[] recvcounts_bytes;
00288     delete[] displs_bytes;
00289     
00290     // ----------------------------------------------------------------------------------------
00291     // Gather claim vectors from all processors
00292     bool* all_claims = new bool[recvbuf_size];
00293     assert(sizeof(bool) == 1);
00294     MPI_Allgatherv(my_claims, elements.size(), MPI_BYTE, all_claims, &recvcounts[0], &recvbuf_displs[0], MPI_BYTE, comm);
00295 
00296     // ----------------------------------------------------------------------------------------
00297     // Construct multimap: (element) -> (ids claiming processors...)
00298     std::multimap<T,int> procs_claiming_element;
00299     typename std::vector<T>::iterator current_elem = recvbuf.begin();
00300     bool* current_claim = all_claims;
00301     for (int proc_id = 0; proc_id < mpi_size; proc_id++) {
00302         for (int elem_lid = 0; elem_lid < recvcounts[proc_id]; elem_lid++) {
00303             if (*current_claim) {
00304                 std::pair<T, int> p(*current_elem, proc_id);
00305                 procs_claiming_element.insert(p);
00306             }
00307             ++ current_elem;
00308             ++ current_claim;
00309         }
00310     }
00311     delete all_claims;
00312 
00313     // ----------------------------------------------------------------------------------------
00314     // Sort elements for each processor to facilitate a binary search later on.
00315     for (int proc_id = 0; proc_id < mpi_size; ++ proc_id) {
00316         typename std::vector<T>::iterator sort_start_point = recvbuf.begin() + recvbuf_displs[proc_id];
00317         typename std::vector<T>::iterator sort_end_point = sort_start_point + recvcounts[proc_id];
00318         std::sort(sort_start_point, sort_end_point);
00319     }
00320     // elements must be ordered in the same way as the corresponding block in recvbuf.
00321     std::sort(elements.begin(), elements.end());
00322     
00323     // ----------------------------------------------------------------------------------------
00324     // Determine owning processor for each element in revbuf.
00325     
00327     std::vector<int> proc_owning_element;
00328     for (typename std::vector<T>::iterator it = recvbuf.begin(); it != recvbuf.end(); ++it) {
00329         std::vector<int> claimers;
00330         std::pair<typename std::multimap<T,int>::iterator, typename std::multimap<T,int>::iterator> range = procs_claiming_element.equal_range(*it);
00331         for (typename std::multimap<T,int>::iterator j = range.first; j != range.second; ++j)
00332             claimers.push_back((*j).second);
00333         // At least one processor must claim the element.
00334 #if 1
00335         if (claimers.size() == 0) {
00336             rErrorAll("edge (%d, %d) is not claimed", (*it).first, (*it).second);   
00337         }
00338 #endif
00339         assert (claimers.size() >= 1); 
00340         proc_owning_element.push_back(determine_proc_of_this_element<T>(*it, claimers));
00341     }
00342     
00343 #if 0
00344     for (typename std::multimap<T,int>::iterator it = procs_claiming_element.begin(); it != procs_claiming_element.end(); ++it) {
00345         ostringstream buf;
00346         buf << (*it).first;
00347         rDebugAll("elem %s claimed by p%02d", buf.str().c_str(), (*it).second);
00348     }
00349     for (unsigned int i = 0; i < proc_owning_element.size(); i++) 
00350         cout << proc_owning_element[i] << " "; cout << endl;
00351 #endif
00352     
00353     // Calculate number of elements per processor and global ID offset for each processor
00354     elem_counts.clear();
00355     elem_counts.resize(mpi_size);
00356     id_t element_counter = 0;
00357     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00358         elem_counts[i_proc] = 0;
00359         for (int j_elem = 0; j_elem < recvcounts[i_proc]; j_elem++) {            
00360             if (proc_owning_element[element_counter] == i_proc)
00361                 elem_counts[i_proc] ++;
00362             element_counter ++;
00363         }
00364     }
00365     elem_displs.resize(mpi_size);
00366     elem_displs[0] = 0;
00367     for (int i = 1; i < mpi_size; i++)
00368         elem_displs[i] = elem_displs[i-1] + elem_counts[i-1];
00369     int num_global_ids = elem_displs[mpi_size - 1] + elem_counts[mpi_size - 1];
00370 
00371 #if 0
00372     cout << "Recvcounts: "; for(int i = 0; i < mpi_size; i++) cout << recvcounts[i] << " "; cout << "." << endl;
00373     cout << "Elements_per_proc: "; for(int i = 0; i < mpi_size; i++) cout << elem_counts[i] << " "; cout << "." << endl;
00374     cout << "Offsets: "; for(int i = 0; i < mpi_size; i++) cout << elem_displs[i] << " "; cout << "." << endl;
00375 #endif
00376     
00377     // Assign local ID's to local elements in recvbuf in a consecutive manner
00378     std::vector<id_t> unmoved_local_ids(recvbuf_size);    
00379     element_counter = 0;
00380     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00381         int id_counter = 0;
00382         for (int j_elems = 0; j_elems < recvcounts[i_proc]; j_elems++) {
00383             if (proc_owning_element[element_counter] == i_proc) {
00384                 unmoved_local_ids[element_counter] = id_counter;
00385                 id_counter++;
00386             } else {
00387                 unmoved_local_ids[element_counter] = mesh::ID_NONE;
00388             }
00389             element_counter++;
00390         }
00391         assert(id_counter == elem_counts[i_proc]);
00392     }
00393     assert (element_counter == recvbuf_size);
00394     
00395     // Assign global ID's of local elements in recvbuf (store in gids vector)
00396     gids.resize(recvbuf_size);
00397     element_counter = 0;
00398     int nof_assigned_elements = 0;
00399     std::vector<id_t> unassigned_elements;
00400     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00401         for (int j_elems = 0; j_elems < recvcounts[i_proc]; j_elems++) {
00402             if (unmoved_local_ids[element_counter] != mesh::ID_NONE) {
00403                 gids[element_counter] = unmoved_local_ids[element_counter] + elem_displs[i_proc];
00404                 nof_assigned_elements++;
00405             } else {
00406                 gids[element_counter] = mesh::ID_NONE;
00407                 unassigned_elements.push_back(element_counter);
00408             }
00409         element_counter++;
00410         }
00411     }
00412     assert (element_counter == recvbuf_size);
00413     
00414     // Assign gids of remote elements in recvbuf (using binary search)
00415     for(std::vector<id_t>::iterator it = unassigned_elements.begin(); it != unassigned_elements.end(); ++it) {
00416        //for (typename std::vector<T>::iterator it = recvbuf.begin(); it != recvbuf.end(); ++it) {
00417         T elem = recvbuf[*it];
00418         int owner = proc_owning_element[*it];
00419         typename std::vector<T>::iterator search_start_point = recvbuf.begin() + recvbuf_displs[owner];
00420         typename std::vector<T>::iterator search_end_point = search_start_point + recvcounts[owner];
00421         std::pair<typename std::vector<T>::iterator, typename std::vector<T>::iterator> result = equal_range(search_start_point, search_end_point, elem);
00422         assert(result.second - result.first == 1); // Want to find exactly one element.
00423         gids[*it] = gids[result.first - recvbuf.begin()];
00424     }    
00425 #if 0
00426     element_counter = 0;
00427     for (int i_proc = 0; i_proc < mpi_size; i_proc++) {
00428         for (int j_elems = 0; j_elems < recvcounts[i_proc]; j_elems++) {
00429             if (mpi_rank == 1)
00430                 rDebugAll("iproc=%02d, gids[%2d]=%2d", i_proc, element_counter, gids[element_counter]);
00431             element_counter ++;
00432         }
00433     }    
00434 #endif
00435     if (recvbuf_displs[mpi_rank] != 0) {
00436         for (int i = 0; i < recvcounts[mpi_rank]; ++ i)
00437             gids[i] = gids[i + recvbuf_displs[mpi_rank]];
00438         gids.resize(recvcounts[mpi_rank]);
00439     }
00440             
00441     return num_global_ids;
00442 }
00443 
00455 int set_ownership(const std::vector<id_t>& gids, std::vector<int>& owned_by, MPI_Comm comm);
00456 
00457 void remove_gids(std::vector<id_t> gids, std::vector<id_t> eliminated_gids, std::vector<id_t> map_elimated);
00458 
00476 void compute_mgid_map(id_t num_global_gids,
00477                       const std::vector<id_t>& gids,
00478                       std::vector<id_t>& eliminated_gids,
00479                       id_t* num_global_mgids,
00480                       std::map<id_t,id_t>& mgid_map,
00481                       MPI_Comm comm);
00482 
00490 int set_counts_displs(int my_count, 
00491                       std::vector<int>& counts, 
00492                       std::vector<int>& displs, 
00493                       MPI_Comm comm);
00494                       
00495 } // namespace parallel
00496 
00497 std::ostream& operator << (std::ostream& ostr, const utility::triple<mesh::id_t, mesh::id_t, mesh::id_t>& x);
00498 
00499 std::ostream& operator << (std::ostream& ostr, const std::pair<mesh::id_t, mesh::id_t>& x);
00500 
00501 #endif

Generated on Fri Oct 26 13:35:13 2007 for FEMAXX (Finite Element Maxwell Eigensolver) by  doxygen 1.4.7