28 #ifdef DEAL_II_WITH_MPI
36 #ifdef DEAL_II_WITH_METIS
43 #ifdef DEAL_II_TRILINOS_WITH_ZOLTAN
44 # include <zoltan_cpp.h>
58 const std::vector<unsigned int> &cell_weights,
59 const unsigned int n_partitions,
60 std::vector<unsigned int> & partition_indices)
64 #ifndef DEAL_II_WITH_METIS
65 (void)sparsity_pattern;
68 (void)partition_indices;
77 idx_t n =
static_cast<signed int>(sparsity_pattern.
n_rows()),
80 static_cast<int>(n_partitions),
92 idx_t options[METIS_NOPTIONS];
93 METIS_SetDefaultOptions(options);
97 std::vector<idx_t> int_rowstart(1);
98 int_rowstart.reserve(sparsity_pattern.
n_rows() + 1);
99 std::vector<idx_t> int_colnums;
105 col < sparsity_pattern.
end(row);
107 int_colnums.push_back(col->column());
108 int_rowstart.push_back(int_colnums.size());
111 std::vector<idx_t> int_partition_indices(sparsity_pattern.
n_rows());
114 std::vector<idx_t> int_cell_weights;
115 if (cell_weights.size() > 0)
117 Assert(cell_weights.size() == sparsity_pattern.
n_rows(),
119 sparsity_pattern.
n_rows()));
120 int_cell_weights.resize(cell_weights.size());
123 int_cell_weights.begin());
127 idx_t *
const p_int_cell_weights =
128 (cell_weights.size() > 0 ? int_cell_weights.data() :
nullptr);
138 ierr = METIS_PartGraphRecursive(&n,
150 int_partition_indices.data());
154 ierr = METIS_PartGraphKway(&n,
166 int_partition_indices.data());
174 int_partition_indices.end(),
175 partition_indices.begin());
181 #ifdef DEAL_II_TRILINOS_WITH_ZOLTAN
184 get_number_of_objects(
void *data,
int *ierr)
195 get_object_list(
void *data,
198 ZOLTAN_ID_PTR globalID,
199 ZOLTAN_ID_PTR localID,
211 auto n_dofs = graph->
n_rows();
213 for (
unsigned int i = 0; i < n_dofs; i++)
222 get_num_edges_list(
void *data,
226 ZOLTAN_ID_PTR globalID,
237 for (
int i = 0; i < num_obj; ++i)
240 numEdges[i] = graph->
row_length(globalID[i]) - 1;
249 get_edge_list(
void *data,
256 ZOLTAN_ID_PTR nborGID,
265 ZOLTAN_ID_PTR nextNborGID = nborGID;
266 int * nextNborProc = nborProc;
270 i < static_cast<SparsityPattern::size_type>(num_obj);
278 if (i != col->column())
283 *nextNborGID++ = col->column();
293 const std::vector<unsigned int> &cell_weights,
294 const unsigned int n_partitions,
295 std::vector<unsigned int> & partition_indices)
299 #ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
300 (void)sparsity_pattern;
303 (void)partition_indices;
308 cell_weights.size() == 0,
310 "The cell weighting functionality for Zoltan has not yet been implemented."));
314 std::unique_ptr<Zoltan> zz =
315 std_cxx14::make_unique<Zoltan>(MPI_COMM_SELF);
319 zz->Set_Param(
"DEBUG_LEVEL",
"0");
323 zz->Set_Param(
"NUM_LOCAL_PARTS",
339 zz->Set_Param(
"PHG_EDGE_SIZE_THRESHOLD",
"0.5");
346 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
347 zz->Set_Obj_List_Fn(get_object_list, &graph);
348 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
349 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
353 int num_gid_entries = 1;
354 int num_lid_entries = 1;
356 ZOLTAN_ID_PTR import_global_ids =
nullptr;
357 ZOLTAN_ID_PTR import_local_ids =
nullptr;
358 int * import_procs =
nullptr;
359 int * import_to_part =
nullptr;
361 ZOLTAN_ID_PTR export_global_ids =
nullptr;
362 ZOLTAN_ID_PTR export_local_ids =
nullptr;
363 int * export_procs =
nullptr;
364 int * export_to_part =
nullptr;
367 const int rc = zz->LB_Partition(changes,
388 std::fill(partition_indices.begin(), partition_indices.end(), 0);
392 for (
int i = 0; i < num_export; i++)
393 partition_indices[export_local_ids[i]] = export_to_part[i];
401 const unsigned int n_partitions,
402 std::vector<unsigned int> &partition_indices,
405 std::vector<unsigned int> cell_weights;
418 const std::vector<unsigned int> &cell_weights,
419 const unsigned int n_partitions,
420 std::vector<unsigned int> & partition_indices,
429 Assert(partition_indices.size() == sparsity_pattern.
n_rows(),
431 sparsity_pattern.
n_rows()));
434 if (n_partitions == 1 || (sparsity_pattern.
n_rows() == 1))
436 std::fill_n(partition_indices.begin(), partition_indices.size(), 0
U);
441 partition_metis(sparsity_pattern,
446 partition_zoltan(sparsity_pattern,
457 std::vector<unsigned int> &color_indices)
461 #ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
462 (void)sparsity_pattern;
468 std::unique_ptr<Zoltan> zz = std_cxx14::make_unique<Zoltan>(MPI_COMM_SELF);
472 zz->Set_Param(
"DEBUG_LEVEL",
"0");
473 zz->Set_Param(
"COLORING_PROBLEM",
"DISTANCE-1");
474 zz->Set_Param(
"NUM_GID_ENTRIES",
"1");
475 zz->Set_Param(
"NUM_LID_ENTRIES",
"1");
476 zz->Set_Param(
"OBJ_WEIGHT_DIM",
"0");
477 zz->Set_Param(
"RECOLORING_NUM_OF_ITERATIONS",
"0");
484 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
485 zz->Set_Obj_List_Fn(get_object_list, &graph);
486 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
487 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
490 int num_gid_entries = 1;
491 const int num_objects = graph.
n_rows();
494 std::vector<ZOLTAN_ID_TYPE> global_ids(num_objects);
495 std::vector<int> color_exp(num_objects);
498 for (
int i = 0; i < num_objects; i++)
502 int rc = zz->Color(num_gid_entries,
512 color_indices.resize(num_objects);
513 Assert(color_exp.size() == color_indices.size(),
516 std::copy(color_exp.begin(), color_exp.end(), color_indices.begin());
518 unsigned int n_colors =
519 *(std::max_element(color_indices.begin(), color_indices.end()));
535 const std::vector<DynamicSparsityPattern::size_type> &new_indices)
545 if (sparsity.
row_length(row) < min_coordination)
548 starting_point = row;
573 return starting_point;
582 std::vector<DynamicSparsityPattern::size_type> & new_indices,
583 const std::vector<DynamicSparsityPattern::size_type> &starting_indices)
591 "You can't specify more starting indices than there are rows"));
595 "Only valid for sparsity patterns which store all rows."));
596 for (
const auto starting_index : starting_indices)
598 (void)starting_index;
600 ExcMessage(
"Invalid starting index: All starting indices need "
601 "to be between zero and the number of rows in the "
602 "sparsity pattern."));
607 std::vector<DynamicSparsityPattern::size_type> last_round_dofs(
611 std::fill(new_indices.begin(),
617 if (last_round_dofs.empty())
618 last_round_dofs.push_back(
627 new_indices[last_round_dofs[i]] = next_free_number++;
633 std::vector<DynamicSparsityPattern::size_type> next_round_dofs;
636 for (
const auto dof : last_round_dofs)
638 j < sparsity.
end(dof);
640 next_round_dofs.push_back(j->column());
643 std::sort(next_round_dofs.begin(), next_round_dofs.end());
646 std::vector<DynamicSparsityPattern::size_type>::iterator end_sorted;
648 std::unique(next_round_dofs.begin(), next_round_dofs.end());
649 next_round_dofs.erase(end_sorted, next_round_dofs.end());
652 for (
int s = next_round_dofs.size() - 1; s >= 0; --s)
654 next_round_dofs.erase(next_round_dofs.begin() + s);
660 if (next_round_dofs.empty())
662 if (std::find(new_indices.begin(),
673 Assert(starting_indices.empty(),
674 ExcMessage(
"The input graph appears to have more than one "
675 "component, but as stated in the documentation "
676 "we only want to reorder such graphs if no "
677 "starting indices are given. The function was "
678 "called with starting indices, however."))
680 next_round_dofs.push_back(
689 std::multimap<DynamicSparsityPattern::size_type, int>
690 dofs_by_coordination;
699 const std::pair<const DynamicSparsityPattern::size_type, int>
700 new_entry(coordination, next_round_dof);
701 dofs_by_coordination.insert(new_entry);
705 std::multimap<DynamicSparsityPattern::size_type, int>::iterator i;
706 for (i = dofs_by_coordination.begin(); i != dofs_by_coordination.end();
708 new_indices[i->second] = next_free_number++;
711 last_round_dofs = next_round_dofs;
717 Assert((std::find(new_indices.begin(),
720 (next_free_number == sparsity.
n_rows()),
731 std::vector<DynamicSparsityPattern::size_type> &renumbering)
738 "Only valid for sparsity patterns which store all rows."));
740 std::vector<types::global_dof_index> touched_nodes(
742 std::vector<unsigned int> row_lengths(connectivity.
n_rows());
743 std::set<types::global_dof_index> current_neighbors;
744 std::vector<std::vector<types::global_dof_index>> groups;
754 row_lengths[row] = connectivity.
row_length(row);
757 std::vector<unsigned int> n_remaining_neighbors(row_lengths);
770 std::pair<types::global_dof_index, types::global_dof_index>
775 if (row_lengths[i] < min_neighbors.second)
777 min_neighbors = std::make_pair(i, n_remaining_neighbors[i]);
778 if (n_remaining_neighbors[i] <= 1)
786 current_neighbors.clear();
787 current_neighbors.insert(min_neighbors.first);
788 while (!current_neighbors.empty())
794 for (
const auto current_neighbor : current_neighbors)
796 Assert(touched_nodes[current_neighbor] ==
799 if (n_remaining_neighbors[current_neighbor] <
800 min_neighbors.second)
802 std::make_pair(current_neighbor,
803 n_remaining_neighbors[current_neighbor]);
810 min_neighbors.second;
811 for (
const auto current_neighbor : current_neighbors)
812 if (n_remaining_neighbors[current_neighbor] == best_row_length)
813 if (row_lengths[current_neighbor] > min_neighbors.second)
815 std::make_pair(current_neighbor,
816 row_lengths[current_neighbor]);
820 groups.emplace_back();
821 std::vector<types::global_dof_index> &next_group = groups.back();
823 next_group.push_back(min_neighbors.first);
824 touched_nodes[min_neighbors.first] = groups.size() - 1;
826 connectivity.
begin(min_neighbors.first);
827 it != connectivity.
end(min_neighbors.first);
831 next_group.push_back(it->column());
832 touched_nodes[it->column()] = groups.size() - 1;
840 for (
const auto index : next_group)
843 connectivity.
begin(index);
844 it != connectivity.
end(index);
847 if (touched_nodes[it->column()] ==
849 current_neighbors.insert(it->column());
850 n_remaining_neighbors[it->column()]--;
852 current_neighbors.erase(index);
863 if (groups.size() < connectivity.
n_rows())
871 connectivity.
begin(groups[i][col]);
872 it != connectivity.
end(groups[i][col]);
874 connectivity_next.
add(i, touched_nodes[it->column()]);
877 std::vector<types::global_dof_index> renumbering_next(groups.size());
884 col < groups[renumbering_next[i]].size();
886 renumbering[count] = groups[renumbering_next[i]][col];
895 renumbering[count] = groups[i][col];
903 std::vector<DynamicSparsityPattern::size_type> &renumbering)
914 #ifdef DEAL_II_WITH_MPI
918 const std::vector<IndexSet> &owned_rows_per_processor,
924 owned_rows_per_processor[myid],
933 const IndexSet & locally_owned_rows,
935 const IndexSet & locally_relevant_rows)
938 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
941 IndexSet requested_rows(locally_relevant_rows);
944 std::vector<unsigned int> index_owner =
959 rows_data[index_owner[i]].push_back(row);
963 const auto rows_data_received =
970 for (
const auto &data : rows_data_received)
972 for (
const auto &row : data.second)
981 send_data[data.first].push_back(row);
982 send_data[data.first].push_back(rlen);
984 send_data[data.first].push_back(
990 const auto received_data =
994 for (
const auto &data : received_data)
996 const auto &recv_buf = data.second;
997 auto ptr = recv_buf.begin();
998 const auto end = recv_buf.end();
1001 const auto row = *(ptr++);
1004 const auto n_entries = *(ptr++);
1026 const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
1031 std::vector<DynamicSparsityPattern::size_type> start_index(
1032 rows_per_cpu.size() + 1);
1035 start_index[i + 1] = start_index[i] + rows_per_cpu[i];
1037 IndexSet owned(start_index.back());
1038 owned.
add_range(start_index[myid], start_index[myid] + rows_per_cpu[myid]);
1047 const IndexSet & locally_owned_rows,
1049 const IndexSet & locally_relevant_rows)
1051 IndexSet requested_rows(locally_relevant_rows);
1054 std::vector<unsigned int> index_owner =
1060 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
1062 map_vec_t send_data;
1078 send_data[index_owner[i]].push_back(row);
1079 send_data[index_owner[i]].push_back(rlen);
1084 send_data[index_owner[i]].push_back(column);
1091 for (
const auto &data : receive_data)
1093 const auto &recv_buf = data.second;
1094 auto ptr = recv_buf.begin();
1095 const auto end = recv_buf.end();
1098 const auto row = *(ptr++);
1100 const auto n_entries = *(ptr++);
1114 const std::vector<IndexSet> &owned_set_per_cpu,
1120 owned_set_per_cpu[myid],
1129 const IndexSet & locally_owned_rows,
1131 const IndexSet &locally_relevant_rows)
1135 std::vector<BlockDynamicSparsityPattern::size_type>>;
1136 map_vec_t send_data;
1138 IndexSet requested_rows(locally_relevant_rows);
1141 std::vector<unsigned int> index_owner =
1160 std::vector<BlockDynamicSparsityPattern::size_type> &dst =
1161 send_data[index_owner[i]];
1163 dst.push_back(rlen);
1170 dst.push_back(column);
1174 unsigned int num_receive = 0;
1176 std::vector<unsigned int> send_to;
1177 send_to.reserve(send_data.size());
1178 for (
const auto &sparsity_line : send_data)
1179 send_to.push_back(sparsity_line.first);
1186 std::vector<MPI_Request> requests(send_data.size());
1198 unsigned int idx = 0;
1199 for (
const auto &sparsity_line : send_data)
1203 sparsity_line.second.size(),
1205 sparsity_line.first,
1215 std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
1216 for (
unsigned int index = 0; index < num_receive; ++index)
1219 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &status);
1226 recv_buf.resize(len);
1227 ierr = MPI_Recv(recv_buf.data(),
1236 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1237 ptr = recv_buf.begin();
1238 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1239 end = recv_buf.end();
1245 for (
unsigned int c = 0; c < num; ++c)
1257 if (requests.size())
1260 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);