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
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
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
00089 std::sort(elements.begin(), elements.end());
00090
00091
00092
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
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
00115
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
00127
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
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
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
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
00210 for(std::vector<id_t>::iterator it = unassigned_elements.begin(); it != unassigned_elements.end(); ++it) {
00211
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);
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
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
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
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
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
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
00321 std::sort(elements.begin(), elements.end());
00322
00323
00324
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
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
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
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
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
00415 for(std::vector<id_t>::iterator it = unassigned_elements.begin(); it != unassigned_elements.end(); ++it) {
00416
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);
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 }
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