18 #include <flecsi-config.h> 28 #if !defined(FLECSI_ENABLE_MPI) 29 #error FLECSI_ENABLE_MPI not defined! This file depends on MPI! 38 inline log::devel_tag dcrs_utils_tag(
"dcrs_utils");
41 namespace unstructured_impl {
52 template<
size_t DIMENSION,
size_t MESH_DIMENSION>
53 inline std::set<size_t>
55 std::set<size_t> indices;
63 MPI_Comm_size(MPI_COMM_WORLD, &size);
64 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
73 flog(info) <<
"quot: " << quot <<
" rem: " << rem << std::endl;
77 size_t init_indices = quot + ((size_t(rank) >= (size - rem)) ? 1 : 0);
80 for(
int r(0); r < rank; ++r) {
81 offset += quot + ((size_t(r) >= (size - rem)) ? 1 : 0);
84 flog(info) <<
"offset: " << offset << std::endl;
86 for(
size_t i(0); i < init_indices; ++i) {
87 indices.insert(offset + i);
88 flog(info) <<
"inserting: " << offset + i << std::endl;
112 template<std::size_t DIMENSION,
113 std::size_t FROM_DIMENSION = DIMENSION,
114 std::size_t TO_DIMENSION = DIMENSION,
115 std::size_t THRU_DIMENSION = DIMENSION - 1>
121 MPI_Comm_size(MPI_COMM_WORLD, &size);
122 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
133 size_t init_indices = quot + ((size_t(rank) >= (size - rem)) ? 1 : 0);
137 dcrs.distribution.push_back(0);
140 for(
int r(0); r < size; ++r) {
141 const size_t indices = quot + ((size_t(r) >= (size - rem)) ? 1 : 0);
142 dcrs.distribution.push_back(dcrs.distribution[r] + indices);
150 dcrs.offsets.push_back(0);
154 using cellid = size_t;
155 using vertexid = size_t;
159 std::map<vertexid, std::vector<cellid>> vertex2cells;
160 std::map<cellid, std::vector<cellid>> cell2cells;
163 for(
size_t cell(0); cell < md.
num_entities(FROM_DIMENSION); ++cell) {
164 std::map<cellid, size_t> cell_counts;
166 for(
auto vertex : md.
entities(FROM_DIMENSION, 0, cell)) {
169 vertex2cells[vertex].push_back(cell);
173 for(
auto other : vertex2cells[vertex]) {
175 cell_counts[other] += 1;
179 for(
auto count : cell_counts) {
180 if(count.second > THRU_DIMENSION) {
183 cell2cells[cell].push_back(count.first);
184 cell2cells[count.first].push_back(cell);
190 for(
size_t i(0); i < init_indices; ++i) {
191 auto cell = dcrs.distribution[rank] + i;
193 for(
auto n : cell2cells[cell]) {
194 dcrs.indices.push_back(n);
197 dcrs.offsets.push_back(dcrs.offsets[i] + cell2cells[cell].size());
206 template<std::size_t DIMENSION,
207 std::size_t FROM_DIMENSION = DIMENSION,
208 std::size_t TO_DIMENSION = DIMENSION,
209 std::size_t THRU_DIMENSION = DIMENSION - 1>
216 MPI_Comm_size(MPI_COMM_WORLD, &size);
217 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
228 size_t init_indices = quot + ((size_t(rank) >= (size - rem)) ? 1 : 0);
231 dcrs.distribution.push_back(0);
234 for(
int r(0); r < size; ++r) {
235 const size_t indices = quot + ((size_t(r) >= (size - rem)) ? 1 : 0);
236 dcrs.distribution.push_back(dcrs.distribution[r] + indices);
244 dcrs.offsets.push_back(0);
248 using cellid = size_t;
252 std::map<cellid, std::vector<cellid>> cell2other;
256 for(
size_t cell(dcrs.distribution[rank]); cell < dcrs.distribution[rank + 1];
258 auto & this_cell2other = cell2other[cell];
260 for(
auto vertex : md.
entities(FROM_DIMENSION, THRU_DIMENSION, cell)) {
262 for(
auto other : md.
entities(THRU_DIMENSION, TO_DIMENSION, vertex)) {
264 if(FROM_DIMENSION == TO_DIMENSION) {
266 this_cell2other.push_back(other);
269 this_cell2other.push_back(other);
276 for(
size_t i(0); i < init_indices; ++i) {
277 auto cell = dcrs.distribution[rank] + i;
278 auto & this_cell2other = cell2other.at(cell);
280 std::sort(this_cell2other.begin(), this_cell2other.end());
281 auto last = std::unique(this_cell2other.begin(), this_cell2other.end());
282 auto first = this_cell2other.begin();
283 auto size = std::distance(first, last);
285 for(
auto it = first; it != last; ++it) {
286 dcrs.indices.push_back(*it);
289 dcrs.offsets.push_back(dcrs.offsets[i] + size);
294 template<
typename SEND_TYPE,
typename ID_TYPE,
typename RECV_TYPE>
296 alltoallv(
const SEND_TYPE & sendbuf,
297 const ID_TYPE & sendcounts,
298 const ID_TYPE & senddispls,
300 const ID_TYPE & recvcounts,
301 const ID_TYPE & recvdispls,
302 decltype(MPI_COMM_WORLD) comm) {
304 const auto mpi_send_t =
306 const auto mpi_recv_t =
309 auto num_ranks = sendcounts.size();
312 std::vector<MPI_Request> requests;
313 requests.reserve(2 * num_ranks);
318 for(
size_t rank = 0; rank < num_ranks; ++rank) {
319 auto count = recvcounts[rank];
321 auto buf = recvbuf.data() + recvdispls[rank];
322 requests.resize(requests.size() + 1);
323 auto & my_request = requests.back();
325 MPI_Irecv(buf, count, mpi_recv_t, rank, tag, comm, &my_request);
326 if(ret != MPI_SUCCESS)
332 for(
size_t rank = 0; rank < num_ranks; ++rank) {
333 auto count = sendcounts[rank];
335 auto buf = sendbuf.data() + senddispls[rank];
336 requests.resize(requests.size() + 1);
337 auto & my_request = requests.back();
339 MPI_Isend(buf, count, mpi_send_t, rank, tag, comm, &my_request);
340 if(ret != MPI_SUCCESS)
346 std::vector<MPI_Status> status(requests.size());
347 auto ret = MPI_Waitall(requests.size(), requests.data(), status.data());
355 template<
typename T,
typename Vector>
358 auto it = std::upper_bound(distribution.begin(), distribution.end(), i);
359 flog_assert(it != distribution.end(),
"invalid iterator");
360 return std::distance(distribution.begin(), it) - 1;
366 template<
typename Vector>
370 size_t quot = nelem / npart;
371 size_t rem = nelem % npart;
373 dist.reserve(npart + 1);
379 for(
size_t r(0); r < npart; ++r) {
380 const size_t indices = quot + ((r >= (npart - rem)) ? 1 : 0);
381 dist.push_back(dist[r] + indices);
388 template<std::
size_t MESH_DIMENSION>
391 size_t from_dimension,
393 size_t min_connections,
398 MPI_Comm_size(MPI_COMM_WORLD, &size);
399 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
415 dcrs.distribution.resize(size + 1);
416 dcrs.distribution[0] = 0;
418 MPI_Allgather(&num_cells,
421 dcrs.distribution.data() + 1,
426 for(
int i = 0; i < size; ++i)
427 dcrs.distribution[i + 1] += dcrs.distribution[i];
430 auto cells_start = dcrs.distribution[rank];
437 const auto & vertex_local_to_global = md.local_to_global(to_dimension);
439 size_t max_global_vert_id{0};
440 for(
auto v : vertex_local_to_global)
441 max_global_vert_id = std::max(max_global_vert_id, v);
446 &max_global_vert_id, &tot_verts, 1, mpi_size_t, MPI_MAX, MPI_COMM_WORLD);
449 decltype(dcrs.distribution) vert_dist;
457 std::map<size_t, std::vector<size_t>> vertex2cell;
458 const auto & cells2vertex = md.entities_crs(from_dimension, to_dimension);
461 for(
size_t ic = 0; ic < num_cells; ++ic) {
462 auto cell = cells_start + ic;
463 for(
auto i = cells2vertex.offsets[ic]; i < cells2vertex.offsets[ic + 1];
465 auto iv = cells2vertex.indices[i];
466 auto vertex = vertex_local_to_global[iv];
467 vertex2cell[vertex].emplace_back(cell);
472 auto remove_duplicates = [](
auto & vertex2cell) {
473 for(
auto & vertex_cells : vertex2cell) {
474 auto v = vertex_cells.first;
475 auto & cells = vertex_cells.second;
476 std::sort(cells.begin(), cells.end());
477 auto first = cells.begin();
478 auto last = std::unique(first, cells.end());
479 cells.erase(last, cells.end());
483 remove_duplicates(vertex2cell);
491 std::vector<size_t> sendcounts(size, 0);
494 for(
const auto & vs_pair : vertex2cell) {
495 size_t global_id = vs_pair.first;
498 if(r !=
size_t(rank)) {
499 auto n = 2 + vs_pair.second.size();
505 std::vector<size_t> senddispls(size + 1);
507 for(
int r = 0; r < size; ++r) {
508 senddispls[r + 1] = senddispls[r] + sendcounts[r];
513 std::vector<size_t> sendbuf(senddispls[size]);
515 for(
const auto & vs_pair : vertex2cell) {
516 size_t global_id = vs_pair.first;
519 if(r !=
size_t(rank)) {
521 auto offset = senddispls[r] + sendcounts[r];
523 sendbuf[offset++] = global_id;
524 sendbuf[offset++] = vs_pair.second.size();
525 for(
auto v : vs_pair.second)
526 sendbuf[offset++] = v;
528 auto n = 2 + vs_pair.second.size();
533 std::vector<size_t> recvcounts(size, 0);
534 auto ret = MPI_Alltoall(sendcounts.data(),
542 if(ret != MPI_SUCCESS)
543 flog_error(
"Error communicating vertex counts");
546 std::vector<size_t> recvdispls(size + 1);
548 for(
int r = 0; r < size; ++r)
549 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
550 std::vector<size_t> recvbuf(recvdispls[size]);
553 ret = alltoallv(sendbuf,
561 if(ret != MPI_SUCCESS)
569 std::map<size_t, std::vector<size_t>> vertex2rank;
571 for(
int r = 0; r < size; ++r) {
572 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1];) {
574 auto vertex = recvbuf[i];
577 vertex2rank[vertex].emplace_back(r);
578 flog_assert(i < recvdispls[r + 1],
"invalid index");
582 for(
size_t j = 0; j < n; ++j) {
583 flog_assert(i < recvdispls[r + 1],
"invalid index");
584 auto cell = recvbuf[i];
587 vertex2cell[vertex].emplace_back(cell);
593 remove_duplicates(vertex2cell);
602 std::fill(sendcounts.begin(), sendcounts.end(), 0);
603 for(
const auto & vertex_pair : vertex2rank) {
604 auto vertex = vertex_pair.first;
605 for(
auto r : vertex_pair.second) {
606 if(r !=
size_t(rank)) {
608 const auto & cells = vertex2cell.at(vertex);
610 auto n = 2 + cells.size();
618 for(
int r = 0; r < size; ++r)
619 senddispls[r + 1] = senddispls[r] + sendcounts[r];
623 sendbuf.resize(senddispls[size]);
626 std::fill(sendcounts.begin(), sendcounts.end(), 0);
627 for(
const auto & vertex_pair : vertex2rank) {
628 auto vertex = vertex_pair.first;
629 for(
auto r : vertex_pair.second) {
630 if(r !=
size_t(rank)) {
631 auto j = senddispls[r] + sendcounts[r];
633 const auto & cells = vertex2cell.at(vertex);
635 sendbuf[j++] = vertex;
636 sendbuf[j++] = cells.size();
640 sendcounts[r] = j - senddispls[r];
646 std::fill(recvcounts.begin(), recvcounts.end(), 0);
647 ret = MPI_Alltoall(sendcounts.data(),
655 if(ret != MPI_SUCCESS)
656 flog_error(
"Error communicating back vertex counts");
660 for(
int r = 0; r < size; ++r)
661 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
665 recvbuf.resize(recvdispls.at(size));
668 ret = alltoallv(sendbuf,
676 if(ret != MPI_SUCCESS)
677 flog_error(
"Error communicating new vertices");
683 for(
int r = 0; r < size; ++r) {
684 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1];) {
686 auto vertex = recvbuf[i];
690 vertex2rank[vertex].emplace_back(r);
691 flog_assert(i < recvdispls[r + 1],
"invalid index");
696 for(
size_t j = 0; j < n; ++j) {
697 flog_assert(i < recvdispls[r + 1],
"invalid index");
698 auto cell = recvbuf[i];
701 vertex2cell[vertex].emplace_back(cell);
707 remove_duplicates(vertex2cell);
714 dcrs.offsets.reserve(num_cells);
715 dcrs.indices.reserve(from_dimension * from_dimension * num_cells);
716 dcrs.offsets.push_back(0);
718 std::map<size_t, size_t> cell_counts;
720 for(
size_t ic = 0; ic < num_cells; ++ic) {
721 auto cell = cells_start + ic;
726 auto start = cells2vertex.offsets[ic];
727 auto end = cells2vertex.offsets[ic + 1];
728 for(
auto i =
start; i < end; ++i) {
729 auto iv = cells2vertex.indices[i];
730 auto vertex = vertex_local_to_global[iv];
732 for(
auto other : vertex2cell.at(vertex)) {
735 cell_counts[other] += 1;
740 int num_connections{0};
742 for(
auto count : cell_counts) {
743 if(count.second >= min_connections) {
744 dcrs.indices.emplace_back(count.first);
749 dcrs.offsets.emplace_back(dcrs.offsets.back() + num_connections);
757 template<std::
size_t DIMENSION>
760 const std::vector<size_t> & partitioning,
764 int comm_size, comm_rank;
766 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
767 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
778 std::vector<size_t> sendcounts(comm_size, 0);
779 std::vector<size_t> senddispls(comm_size + 1);
780 std::vector<byte_t> sendbuf;
781 std::vector<size_t> erase_local_ids;
784 auto num_elements = dcrs.size();
787 for(
int rank(0); rank < comm_size; ++rank) {
790 auto start_buf = sendbuf.size();
793 for(
size_t local_id(0); local_id < num_elements && rank != comm_rank;
797 auto global_id = dcrs.distribution[comm_rank] + local_id;
801 if(partitioning[local_id] ==
size_t(comm_rank)) {
806 else if(partitioning[local_id] ==
size_t(rank)) {
808 erase_local_ids.emplace_back(local_id);
810 cast_insert(&global_id, 1, sendbuf);
812 auto start = dcrs.offsets[local_id];
813 auto num_offsets = dcrs.offsets[local_id + 1] -
start;
814 cast_insert(&num_offsets, 1, sendbuf);
815 cast_insert(&dcrs.indices[
start], num_offsets, sendbuf);
817 md.pack(dimension, local_id, sendbuf);
822 sendcounts[rank] = sendbuf.size() - start_buf;
823 senddispls[rank + 1] = senddispls[rank] + sendcounts[rank];
831 if(erase_local_ids.size()) {
834 std::sort(erase_local_ids.begin(), erase_local_ids.end());
835 auto last = std::unique(erase_local_ids.begin(), erase_local_ids.end());
836 flog_assert(last == erase_local_ids.end(),
"duplicate ids to delete");
839 dcrs.
erase(erase_local_ids);
842 md.erase(dimension, erase_local_ids);
845 num_elements -= erase_local_ids.size();
855 std::vector<size_t> recvcounts(comm_size, 0);
857 auto ret = MPI_Alltoall(sendcounts.data(),
865 if(ret != MPI_SUCCESS)
866 flog_error(
"Error communicating vertex counts");
869 std::vector<size_t> recvdispls(comm_size + 1);
871 for(
int r = 0; r < comm_size; ++r)
872 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
873 std::vector<byte_t> recvbuf(recvdispls[comm_size]);
876 ret = alltoallv(sendbuf,
884 if(ret != MPI_SUCCESS)
892 for(
int rank(0); rank < comm_size; ++rank) {
894 auto start = recvdispls[rank];
895 auto end = recvdispls[rank + 1];
896 const auto * buffer = &recvbuf[
start];
897 const auto * buffer_end = &recvbuf[end];
903 for(
size_t i =
start; i < end;) {
906 const auto * buffer_start = buffer;
909 auto local_id = num_elements++;
913 uncast(buffer, 1, &global_id);
916 auto last = dcrs.offsets[local_id];
919 uncast(buffer, 1, &num_offsets);
920 dcrs.offsets.emplace_back(last + num_offsets);
922 dcrs.indices.resize(dcrs.indices.size() + num_offsets);
923 uncast(buffer, num_offsets, &dcrs.indices[last]);
926 md.unpack(dimension, local_id, buffer);
929 i += std::distance(buffer_start, buffer);
934 flog_assert(buffer == buffer_end,
"Unpacking mismatch");
939 "Mismatch in the final number of elements after migration");
942 "At least one rank has an empty primary coloring. Please either " 943 "increase the problem size or use fewer ranks");
946 dcrs.distribution.clear();
947 dcrs.distribution.resize(comm_size + 1);
948 dcrs.distribution[0] = 0;
950 MPI_Allgather(&num_elements,
953 dcrs.distribution.data() + 1,
958 for(
int i = 0; i < comm_size; ++i)
959 dcrs.distribution[i + 1] += dcrs.distribution[i];
967 int comm_size, comm_rank;
968 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
969 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
976 auto start = dcrs.distribution[comm_rank];
977 auto end = dcrs.distribution[comm_rank + 1] - 1;
978 auto num_entities = end -
start + 1;
982 std::set<size_t> shared_ranks;
984 for(
size_t local_id = 0; local_id < num_entities; ++local_id) {
987 auto global_id = start + local_id;
989 shared_ranks.clear();
991 for(
auto i = dcrs.offsets[local_id]; i < dcrs.offsets[local_id + 1]; ++i) {
993 auto neighbor = dcrs.indices[i];
994 auto rank =
rank_owner(dcrs.distribution, neighbor);
997 if(rank !=
size_t(comm_rank)) {
1000 auto ghost_id = neighbor - dcrs.distribution[rank];
1001 auto e =
entity_info(neighbor, rank, ghost_id, comm_rank);
1003 auto it = entities.ghost.find(e);
1005 if(it == entities.ghost.end()) {
1006 entities.ghost.emplace(e);
1011 shared_ranks.emplace(rank);
1016 if(shared_ranks.empty()) {
1017 entities.exclusive.emplace(
entity_info(global_id, comm_rank, local_id));
1021 entities.shared.emplace(
1022 entity_info(global_id, comm_rank, local_id, shared_ranks));
1023 color_info.
shared_users.insert(shared_ranks.begin(), shared_ranks.end());
1028 color_info.
exclusive = entities.exclusive.size();
1029 color_info.
shared = entities.shared.size();
1030 color_info.
ghost = entities.ghost.size();
1036 #if 0 // FIXME: DO WE NEED THIS? 1038 color_entities(
const util::crs & cells2entity,
1039 const std::vector<size_t> & local2global,
1040 const std::map<size_t, size_t> & global2local,
1044 size_t & connectivity_counts) {
1046 int comm_size, comm_rank;
1047 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
1048 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
1058 auto num_ents = local2global.size();
1059 std::vector<bool> exclusive(num_ents,
true);
1062 std::vector<size_t> potential_shared;
1065 for(
const auto & c : cells.shared) {
1066 auto start = cells2entity.offsets[c.offset];
1067 auto end = cells2entity.offsets[c.offset + 1];
1068 for(
size_t i =
start; i < end; ++i) {
1069 auto local_id = cells2entity.indices[i];
1070 exclusive[local_id] =
false;
1071 potential_shared.emplace_back(local_id);
1076 auto remove_unique = [](
auto & list) {
1077 std::sort(list.begin(), list.end());
1078 auto last = std::unique(list.begin(), list.end());
1079 list.erase(last, list.end());
1081 remove_unique(potential_shared);
1088 std::vector<size_t> sendcounts(comm_size, 0);
1089 std::vector<size_t> senddispls(comm_size + 1);
1091 for(
const auto & c : cells.shared) {
1093 auto start = cells2entity.offsets[c.offset];
1094 auto end = cells2entity.offsets[c.offset + 1];
1095 auto n = end -
start;
1097 for(
auto r : c.shared) {
1100 sendcounts[r] += 1 + n;
1106 for(
size_t r = 0; r < comm_size; ++r)
1107 senddispls[r + 1] = senddispls[r] + sendcounts[r];
1110 std::vector<size_t> sendbuf(senddispls[comm_size]);
1111 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1113 for(
const auto & c : cells.shared) {
1115 auto start = cells2entity.offsets[c.offset];
1116 auto end = cells2entity.offsets[c.offset + 1];
1117 auto n = end -
start;
1119 for(
auto r : c.shared) {
1121 if(r != comm_rank) {
1123 auto j = senddispls[r] + sendcounts[r];
1125 for(
auto i = start; i < end; ++i) {
1126 auto local_id = cells2entity.indices[i];
1127 auto global_id = local2global[local_id];
1128 sendbuf[j++] = global_id;
1131 sendcounts[r] = j - senddispls[r];
1141 std::vector<size_t> recvcounts(comm_size);
1142 auto ret = MPI_Alltoall(sendcounts.data(), 1, mpi_size_t, recvcounts.data(),
1143 1, mpi_size_t, MPI_COMM_WORLD);
1144 if(ret != MPI_SUCCESS)
1145 flog_error(
"Error communicating vertex counts");
1148 std::vector<size_t> recvdispls(comm_size + 1);
1150 for(
size_t r = 0; r < comm_size; ++r)
1151 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
1152 std::vector<size_t> recvbuf(recvdispls[comm_size]);
1155 connectivity_counts = cells2entity.indices.size();
1158 ret = alltoallv(sendbuf, sendcounts, senddispls, recvbuf, recvcounts,
1159 recvdispls, MPI_COMM_WORLD);
1160 if(ret != MPI_SUCCESS)
1168 std::vector<size_t> potential_ghost;
1170 for(
size_t r = 0; r < comm_size; ++r) {
1171 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1];) {
1173 auto n = recvbuf[i];
1175 connectivity_counts += n;
1177 for(
auto j = 0; j < n; ++j, ++i) {
1179 auto ent_global_id = recvbuf[i];
1182 potential_ghost.emplace_back(ent_global_id);
1188 remove_unique(potential_ghost);
1195 size_t max_global_ent_id{0};
1196 for(
auto v : local2global)
1197 max_global_ent_id = std::max(max_global_ent_id, v);
1202 &max_global_ent_id, &tot_ents, 1, mpi_size_t, MPI_MAX, MPI_COMM_WORLD);
1205 std::vector<size_t> ent_dist;
1206 subdivide(tot_ents, comm_size, ent_dist);
1217 std::vector<size_t> ghost_ranks;
1218 owner_t(
size_t r,
size_t id) : rank(r), local_id(
id) {}
1220 std::map<size_t, owner_t> entities2rank;
1224 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1226 for(
auto local_id : potential_shared) {
1227 auto global_id = local2global[local_id];
1231 if(rank != comm_rank)
1232 sendcounts[rank] += 2;
1237 for(
size_t r = 0; r < comm_size; ++r)
1238 senddispls[r + 1] = senddispls[r] + sendcounts[r];
1242 sendbuf.resize(senddispls[comm_size]);
1243 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1245 for(
const auto & local_id : potential_shared) {
1246 auto global_id = local2global[local_id];
1250 if(rank != comm_rank) {
1251 auto i = senddispls[rank] + sendcounts[rank];
1252 sendbuf[i] = global_id;
1253 sendbuf[i + 1] = local_id;
1254 sendcounts[rank] += 2;
1258 entities2rank.emplace(global_id, owner_t{rank, local_id});
1263 ret = MPI_Alltoall(sendcounts.data(), 1, mpi_size_t, recvcounts.data(), 1,
1264 mpi_size_t, MPI_COMM_WORLD);
1265 if(ret != MPI_SUCCESS)
1266 flog_error(
"Error communicating vertex counts");
1270 for(
size_t r = 0; r < comm_size; ++r)
1271 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
1274 recvbuf.resize(recvdispls[comm_size]);
1277 ret = alltoallv(sendbuf, sendcounts, senddispls, recvbuf, recvcounts,
1278 recvdispls, MPI_COMM_WORLD);
1279 if(ret != MPI_SUCCESS)
1283 for(
size_t r = 0; r < comm_size; ++r) {
1284 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1]; i += 2) {
1285 auto global_id = recvbuf[i];
1286 auto local_id = recvbuf[i + 1];
1287 auto res = entities2rank.emplace(global_id, owner_t{r, local_id});
1288 if(!res.second && r < res.first->second.rank) {
1289 res.first->second = {r, local_id};
1300 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1302 for(
auto global_id : potential_ghost) {
1306 if(rank != comm_rank)
1312 for(
size_t r = 0; r < comm_size; ++r)
1313 senddispls[r + 1] = senddispls[r] + sendcounts[r];
1317 sendbuf.resize(senddispls[comm_size]);
1318 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1320 for(
const auto & global_id : potential_ghost) {
1324 if(rank != comm_rank) {
1325 auto i = senddispls[rank] + sendcounts[rank];
1326 sendbuf[i] = global_id;
1331 auto & owner = entities2rank.at(global_id);
1332 if(owner.rank != rank) {
1333 owner.ghost_ranks.emplace_back(rank);
1339 ret = MPI_Alltoall(sendcounts.data(), 1, mpi_size_t, recvcounts.data(), 1,
1340 mpi_size_t, MPI_COMM_WORLD);
1341 if(ret != MPI_SUCCESS)
1342 flog_error(
"Error communicating vertex counts");
1346 for(
size_t r = 0; r < comm_size; ++r)
1347 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
1350 recvbuf.resize(recvdispls[comm_size]);
1353 ret = alltoallv(sendbuf, sendcounts, senddispls, recvbuf, recvcounts,
1354 recvdispls, MPI_COMM_WORLD);
1355 if(ret != MPI_SUCCESS)
1359 for(
size_t r = 0; r < comm_size; ++r) {
1360 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1]; i++) {
1361 auto global_id = recvbuf[i];
1363 auto & owner = entities2rank.at(global_id);
1364 if(owner.rank != r) {
1365 owner.ghost_ranks.emplace_back(r);
1373 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1376 std::vector<size_t> ranks;
1377 for(
const auto & pair : entities2rank) {
1378 const auto owner = pair.second;
1380 ranks.assign(owner.ghost_ranks.begin(), owner.ghost_ranks.end());
1381 ranks.push_back(owner.rank);
1383 auto n = 4 + owner.ghost_ranks.size();
1384 for(
auto rank : ranks) {
1385 if(rank != comm_rank)
1386 sendcounts[rank] += n;
1392 for(
size_t r = 0; r < comm_size; ++r)
1393 senddispls[r + 1] = senddispls[r] + sendcounts[r];
1397 sendbuf.resize(senddispls[comm_size]);
1398 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1400 for(
const auto & pair : entities2rank) {
1401 auto global_id = pair.first;
1402 const auto owner = pair.second;
1404 ranks.assign(owner.ghost_ranks.begin(), owner.ghost_ranks.end());
1405 ranks.push_back(owner.rank);
1407 auto n = 4 + owner.ghost_ranks.size();
1408 for(
auto rank : ranks) {
1410 if(rank != comm_rank) {
1411 auto i = senddispls[rank] + sendcounts[rank];
1412 sendbuf[i++] = global_id;
1413 sendbuf[i++] = owner.rank;
1414 sendbuf[i++] = owner.local_id;
1415 sendbuf[i++] = owner.ghost_ranks.size();
1416 for(
auto r : owner.ghost_ranks)
1418 sendcounts[rank] += n;
1424 ret = MPI_Alltoall(sendcounts.data(), 1, mpi_size_t, recvcounts.data(), 1,
1425 mpi_size_t, MPI_COMM_WORLD);
1426 if(ret != MPI_SUCCESS)
1427 flog_error(
"Error communicating vertex counts");
1431 for(
size_t r = 0; r < comm_size; ++r)
1432 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
1435 recvbuf.resize(recvdispls[comm_size]);
1438 ret = alltoallv(sendbuf, sendcounts, senddispls, recvbuf, recvcounts,
1439 recvdispls, MPI_COMM_WORLD);
1440 if(ret != MPI_SUCCESS)
1444 for(
size_t r = 0; r < comm_size; ++r) {
1445 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1];) {
1446 auto global_id = recvbuf[i];
1448 auto rank = recvbuf[i];
1450 auto local_id = recvbuf[i];
1452 auto num_shared = recvbuf[i];
1454 auto it = entities2rank.emplace(global_id, owner_t{rank, local_id});
1456 "did not insert vertex, which means multiple owners sent it");
1457 for(
size_t j = 0; j < num_shared; ++j, ++i) {
1458 it.first->second.ghost_ranks.emplace_back(recvbuf[i]);
1468 for(
size_t local_id = 0; local_id < num_ents; ++local_id) {
1469 if(exclusive[local_id]) {
1470 auto global_id = local2global[local_id];
1471 entities.exclusive.emplace(global_id, comm_rank, local_id);
1476 for(
const auto pair : entities2rank) {
1477 auto global_id = pair.first;
1478 auto owner = pair.second;
1480 if(owner.rank == comm_rank) {
1481 flog_assert(owner.ghost_ranks.size(),
"shared/ghost has no ghost ranks!");
1482 auto it = entities.shared.emplace(
1483 global_id, owner.rank, owner.local_id, owner.ghost_ranks);
1485 it.first->shared.begin(), it.first->shared.end());
1489 auto is_ghost = std::binary_search(
1490 potential_ghost.begin(), potential_ghost.end(), global_id);
1498 color_info.
exclusive = entities.exclusive.size();
1499 color_info.
shared = entities.shared.size();
1500 color_info.
ghost = entities.ghost.size();
1507 template<std::
size_t MESH_DIMENSION>
1511 std::vector<size_t> & local2global,
1512 std::map<size_t, size_t> & global2local) {
1514 int comm_size, comm_rank;
1515 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
1516 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
1526 const auto & vertex_local2global = md.local_to_global(0);
1528 size_t max_global_vert_id{0};
1529 for(
auto v : vertex_local2global)
1530 max_global_vert_id = std::max(max_global_vert_id, v);
1533 size_t tot_verts{0};
1535 &max_global_vert_id, &tot_verts, 1, mpi_size_t, MPI_MAX, MPI_COMM_WORLD);
1538 std::vector<size_t> vert_dist;
1539 subdivide(tot_verts, comm_size, vert_dist);
1547 const auto & entities2vertex = md.entities_crs(dimension, 0);
1550 std::map<std::vector<size_t>,
size_t> entities;
1553 std::vector<size_t> sorted_vs;
1556 auto add_to_map = [&](
const auto & vs,
auto & vertices2id,
auto id) {
1557 sorted_vs.assign(vs.begin(), vs.end());
1558 std::sort(sorted_vs.begin(), sorted_vs.end());
1559 auto res = vertices2id.emplace(sorted_vs,
id);
1564 std::vector<size_t> sendcounts(comm_size, 0);
1565 std::vector<size_t> senddispls(comm_size + 1);
1568 std::vector<size_t> global_vs;
1570 for(
const auto & vs : entities2vertex) {
1573 global_vs.reserve(vs.size());
1575 global_vs.emplace_back(vertex_local2global.at(v));
1577 auto it = std::min_element(global_vs.begin(), global_vs.end());
1580 if(r !=
size_t(comm_rank))
1581 sendcounts[r] += 1 + vs.size();
1586 for(
int r = 0; r < comm_size; ++r)
1587 senddispls[r + 1] = senddispls[r] + sendcounts[r];
1590 std::vector<size_t> sendbuf(senddispls[comm_size]);
1591 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1593 for(
const auto & vs : entities2vertex) {
1596 global_vs.reserve(vs.size());
1598 global_vs.emplace_back(vertex_local2global.at(v));
1600 auto it = std::min_element(global_vs.begin(), global_vs.end());
1603 if(r !=
size_t(comm_rank)) {
1605 auto j = senddispls[r] + sendcounts[r];
1606 sendbuf[j++] = vs.size();
1607 for(
auto v : global_vs)
1610 sendcounts[r] = j - senddispls[r];
1614 add_to_map(global_vs, entities, entities.size());
1623 std::vector<size_t> recvcounts(comm_size);
1624 auto ret = MPI_Alltoall(sendcounts.data(),
1632 if(ret != MPI_SUCCESS)
1633 flog_error(
"Error communicating vertex counts");
1636 std::vector<size_t> recvdispls(comm_size + 1);
1638 for(
int r = 0; r < comm_size; ++r)
1639 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
1640 std::vector<size_t> recvbuf(recvdispls[comm_size]);
1643 ret = alltoallv(sendbuf,
1651 if(ret != MPI_SUCCESS)
1658 using pointer_t = std::decay_t<decltype(entities.begin())>;
1661 std::map<size_t, std::vector<pointer_t>> rank_edges;
1663 for(
int r = 0; r < comm_size; ++r) {
1664 auto & rank_data = rank_edges[r];
1665 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1];) {
1666 auto n = recvbuf[i];
1667 auto vs = util::make_array_ref(&recvbuf[i + 1], n);
1668 auto it = add_to_map(vs, entities, entities.size());
1669 rank_data.emplace_back(it);
1674 std::sort(rank_data.begin(),
1676 [](
const auto & a,
const auto & b) {
return a->second < b->second; });
1677 auto last = std::unique(rank_data.begin(), rank_data.end());
1678 rank_data.erase(last, rank_data.end());
1685 size_t my_edges{entities.size()};
1687 std::vector<size_t> edge_dist(comm_size + 1);
1691 &my_edges, 1, mpi_size_t, &edge_dist[1], 1, mpi_size_t, MPI_COMM_WORLD);
1693 for(
int r = 0; r < comm_size; ++r)
1694 edge_dist[r + 1] += edge_dist[r];
1697 for(
auto & pair : entities)
1698 pair.second += edge_dist[comm_rank];
1705 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1709 for(
int r = 0; r < comm_size; ++r) {
1713 for(
auto edge : rank_edges.at(r)) {
1714 auto global_id = edge->second;
1715 auto n = edge->first.size();
1716 sendcounts[r] += 2 + n;
1717 sendbuf.emplace_back(global_id);
1718 sendbuf.emplace_back(n);
1719 for(
auto v : edge->first)
1720 sendbuf.emplace_back(v);
1726 for(
int r = 0; r < comm_size; ++r)
1727 senddispls[r + 1] = senddispls[r] + sendcounts[r];
1734 ret = MPI_Alltoall(sendcounts.data(),
1742 if(ret != MPI_SUCCESS)
1743 flog_error(
"Error communicating vertex counts");
1747 for(
int r = 0; r < comm_size; ++r)
1748 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
1750 recvbuf.resize(recvdispls[comm_size]);
1753 ret = alltoallv(sendbuf,
1761 if(ret != MPI_SUCCESS)
1768 for(
int r = 0; r < comm_size; ++r) {
1769 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1];) {
1770 auto global_id = recvbuf[i];
1771 auto n = recvbuf[i + 1];
1772 auto vs = util::make_array_ref(&recvbuf[i + 2], n);
1774 add_to_map(vs, entities, global_id);
1782 for(
const auto & vs : entities2vertex) {
1785 global_vs.reserve(vs.size());
1788 global_vs.emplace_back(vertex_local2global.at(v));
1791 std::sort(global_vs.begin(), global_vs.end());
1792 auto it = entities.find(global_vs);
1793 flog_assert(it != entities.end(),
"messed up setting entity ids");
1796 auto global_id = it->second;
1797 global2local.emplace(global_id, local2global.size());
1798 local2global.emplace_back(global_id);
1807 const std::vector<size_t> & local2global,
1809 std::vector<size_t> & from_ids,
1812 int comm_size, comm_rank;
1813 MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
1814 MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
1824 std::vector<size_t> sendcounts(comm_size, 0);
1825 std::vector<size_t> senddispls(comm_size + 1);
1827 for(
const auto & e : from_entities.shared) {
1829 auto start = from2to.offsets[e.offset];
1830 auto end = from2to.offsets[e.offset + 1];
1831 auto n = end -
start;
1833 for(
auto r : e.shared) {
1836 if(r !=
size_t(comm_rank))
1837 sendcounts[r] += 2 + n;
1843 for(
int r = 0; r < comm_size; ++r)
1844 senddispls[r + 1] = senddispls[r] + sendcounts[r];
1847 std::vector<size_t> sendbuf(senddispls[comm_size]);
1848 std::fill(sendcounts.begin(), sendcounts.end(), 0);
1850 for(
const auto & e : from_entities.shared) {
1852 auto start = from2to.offsets[e.offset];
1853 auto end = from2to.offsets[e.offset + 1];
1854 auto n = end -
start;
1856 for(
auto r : e.shared) {
1858 if(r !=
size_t(comm_rank)) {
1860 auto j = senddispls[r] + sendcounts[r];
1861 sendbuf[j++] = e.id;
1863 for(
auto i = start; i < end; ++i) {
1864 auto local_id = from2to.indices[i];
1865 auto global_id = local2global[local_id];
1866 sendbuf[j++] = global_id;
1869 sendcounts[r] = j - senddispls[r];
1879 std::vector<size_t> recvcounts(comm_size);
1880 auto ret = MPI_Alltoall(sendcounts.data(),
1888 if(ret != MPI_SUCCESS)
1889 flog_error(
"Error communicating vertex counts");
1892 std::vector<size_t> recvdispls(comm_size + 1);
1894 for(
int r = 0; r < comm_size; ++r)
1895 recvdispls[r + 1] = recvdispls[r] + recvcounts[r];
1896 std::vector<size_t> recvbuf(recvdispls[comm_size]);
1899 ret = alltoallv(sendbuf,
1907 if(ret != MPI_SUCCESS)
1914 connectivity.
clear();
1915 connectivity.offsets.emplace_back(0);
1918 for(
int r = 0; r < comm_size; ++r) {
1919 for(
size_t i = recvdispls[r]; i < recvdispls[r + 1];) {
1921 auto global_id = recvbuf[i];
1922 from_ids.emplace_back(global_id);
1925 size_t n = recvbuf[i];
1928 for(
size_t j = 0; j < n; ++j, ++i) {
1930 auto ent_global_id = recvbuf[i];
1933 connectivity.indices.emplace_back(ent_global_id);
1936 connectivity.offsets.emplace_back(connectivity.offsets.back() + n);
1941 template<std::
size_t MESH_DIMENSION>
1944 size_t from_dimension,
1945 size_t to_dimension,
1947 std::vector<size_t> & from_ids,
1950 const auto & to_local2global = md.local_to_global(to_dimension);
1951 const auto & from2to = md.entities_crs(from_dimension, to_dimension);
1954 from2to, to_local2global, from_entities, from_ids, connectivity);
size_t shared
The number of shared indices.
Definition: coloring_types.hh:35
Definition: definition.hh:35
void clear()
clears the current storage
Definition: crs.hh:112
size_t exclusive
The number of exclusive indices.
Definition: coloring_types.hh:32
unsigned char byte_t
a byte type used for migrating data
Definition: parallel_definition.hh:31
void migrate(size_t dimension, const std::vector< size_t > &partitioning, util::dcrs &dcrs, parallel_definition< DIMENSION > &md)
Migrate pieces of a mesh from one processor to another.
Definition: dcrs_utils.hh:759
#define flog(severity)
Definition: flog.hh:136
util::dcrs make_dcrs(const definition< DIMENSION > &md)
Definition: dcrs_utils.hh:117
void make_dcrs_distributed(const parallel_definition< MESH_DIMENSION > &md, size_t from_dimension, size_t to_dimension, size_t min_connections, util::dcrs &dcrs)
Create distributed CRS representation of the graph.
Definition: dcrs_utils.hh:390
#define flog_assert(test, message)
Definition: flog.hh:411
void make_dcrs_have_connectivity(const definition< DIMENSION > &md, util::dcrs &dcrs)
Create distributed CRS representation of the graph.
Definition: dcrs_utils.hh:211
size_t ghost
The number of ghost indices.
Definition: coloring_types.hh:38
std::set< size_t > shared_users
The aggregate set of colors that depend on our shared indices.
Definition: coloring_types.hh:41
virtual std::vector< size_t > entities(size_t from_dimension, size_t to_dimension, size_t id) const =0
int start(const std::function< int()> &action)
Definition: execution.hh:69
void match_ids(const parallel_definition< MESH_DIMENSION > &md, size_t dimension, std::vector< size_t > &local2global, std::map< size_t, size_t > &global2local)
Color an auxiliary index space like vertices or edges.
Definition: dcrs_utils.hh:1509
std::set< size_t > ghost_owners
The aggregate set of colors that we depend on for ghosts.
Definition: coloring_types.hh:44
Definition: index_coloring.hh:28
T rank_owner(const Vector &distribution, T i)
Simple utility for determining which rank owns an id.
Definition: dcrs_utils.hh:357
void erase(const std::vector< size_t > &ids)
erase a bunch of ids
Definition: crs.hh:65
#define flog_error(message)
Definition: flog.hh:247
virtual size_t num_entities(size_t dimension) const =0
Definition: parallel_definition.hh:27
std::set< size_t > naive_coloring(definition< MESH_DIMENSION > &md)
Definition: dcrs_utils.hh:54
Definition: mpi_type_traits.hh:38
Definition: coloring_types.hh:29
void ghost_connectivity(const util::crs &from2to, const std::vector< size_t > &local2global, const index_coloring &from_entities, std::vector< size_t > &from_ids, util::crs &connectivity)
Color an auxiliary index space like vertices or edges.
Definition: dcrs_utils.hh:1806
void subdivide(size_t nelem, size_t npart, Vector &dist)
A simple utility for subdividing an index space into several parts.
Definition: dcrs_utils.hh:368
Definition: coloring_types.hh:73
Definition: control.hh:31