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;
76 idx_t n =
static_cast<signed int>(sparsity_pattern.
n_rows());
91 idx_t options[METIS_NOPTIONS];
92 METIS_SetDefaultOptions(options);
96 std::vector<idx_t> int_rowstart(1);
97 int_rowstart.reserve(sparsity_pattern.
n_rows() + 1);
98 std::vector<idx_t> int_colnums;
104 col < sparsity_pattern.
end(row);
106 int_colnums.push_back(col->column());
107 int_rowstart.push_back(int_colnums.size());
110 std::vector<idx_t> int_partition_indices(sparsity_pattern.
n_rows());
113 std::vector<idx_t> int_cell_weights;
114 if (cell_weights.size() > 0)
116 Assert(cell_weights.size() == sparsity_pattern.
n_rows(),
118 sparsity_pattern.
n_rows()));
119 int_cell_weights.resize(cell_weights.size());
120 std::copy(cell_weights.begin(),
122 int_cell_weights.begin());
126 idx_t *
const p_int_cell_weights =
127 (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());
173 std::copy(int_partition_indices.begin(),
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 = std::make_unique<Zoltan>(MPI_COMM_SELF);
318 zz->Set_Param(
"DEBUG_LEVEL",
"0");
322 zz->Set_Param(
"NUM_LOCAL_PARTS",
323 std::to_string(n_partitions));
338 zz->Set_Param(
"PHG_EDGE_SIZE_THRESHOLD",
"0.5");
345 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
346 zz->Set_Obj_List_Fn(get_object_list, &graph);
347 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
348 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
352 int num_gid_entries = 1;
353 int num_lid_entries = 1;
355 ZOLTAN_ID_PTR import_global_ids =
nullptr;
356 ZOLTAN_ID_PTR import_local_ids =
nullptr;
357 int * import_procs =
nullptr;
358 int * import_to_part =
nullptr;
360 ZOLTAN_ID_PTR export_global_ids =
nullptr;
361 ZOLTAN_ID_PTR export_local_ids =
nullptr;
362 int * export_procs =
nullptr;
363 int * export_to_part =
nullptr;
366 const int rc = zz->LB_Partition(changes,
387 std::fill(partition_indices.begin(), partition_indices.end(), 0);
391 for (
int i = 0; i < num_export; ++i)
392 partition_indices[export_local_ids[i]] = export_to_part[i];
400 const unsigned int n_partitions,
401 std::vector<unsigned int> &partition_indices,
404 std::vector<unsigned int> cell_weights;
417 const std::vector<unsigned int> &cell_weights,
418 const unsigned int n_partitions,
419 std::vector<unsigned int> & partition_indices,
428 Assert(partition_indices.size() == sparsity_pattern.
n_rows(),
430 sparsity_pattern.
n_rows()));
433 if (n_partitions == 1 || (sparsity_pattern.
n_rows() == 1))
435 std::fill_n(partition_indices.begin(), partition_indices.size(), 0U);
440 partition_metis(sparsity_pattern,
445 partition_zoltan(sparsity_pattern,
456 std::vector<unsigned int> &color_indices)
460#ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
461 (void)sparsity_pattern;
467 std::unique_ptr<Zoltan> zz = std::make_unique<Zoltan>(MPI_COMM_SELF);
471 zz->Set_Param(
"DEBUG_LEVEL",
"0");
472 zz->Set_Param(
"COLORING_PROBLEM",
"DISTANCE-1");
473 zz->Set_Param(
"NUM_GID_ENTRIES",
"1");
474 zz->Set_Param(
"NUM_LID_ENTRIES",
"1");
475 zz->Set_Param(
"OBJ_WEIGHT_DIM",
"0");
476 zz->Set_Param(
"RECOLORING_NUM_OF_ITERATIONS",
"0");
483 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
484 zz->Set_Obj_List_Fn(get_object_list, &graph);
485 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
486 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
489 int num_gid_entries = 1;
490 const int num_objects = graph.
n_rows();
493 std::vector<ZOLTAN_ID_TYPE> global_ids(num_objects);
494 std::vector<int> color_exp(num_objects);
497 for (
int i = 0; i < num_objects; ++i)
501 int rc = zz->Color(num_gid_entries,
511 color_indices.resize(num_objects);
512 Assert(color_exp.size() == color_indices.size(),
515 std::copy(color_exp.begin(), color_exp.end(), color_indices.begin());
517 unsigned int n_colors =
518 *(std::max_element(color_indices.begin(), color_indices.end()));
534 const std::vector<DynamicSparsityPattern::size_type> &new_indices)
544 if (sparsity.
row_length(row) < min_coordination)
547 starting_point = row;
572 return starting_point;
581 std::vector<DynamicSparsityPattern::size_type> & new_indices,
582 const std::vector<DynamicSparsityPattern::size_type> &starting_indices)
590 "You can't specify more starting indices than there are rows"));
594 "Only valid for sparsity patterns which store all rows."));
595 for (
const auto starting_index : starting_indices)
597 (void)starting_index;
599 ExcMessage(
"Invalid starting index: All starting indices need "
600 "to be between zero and the number of rows in the "
601 "sparsity pattern."));
606 std::vector<DynamicSparsityPattern::size_type> last_round_dofs(
610 std::fill(new_indices.begin(),
616 if (last_round_dofs.empty())
617 last_round_dofs.push_back(
624 for (
const auto &last_round_dof : last_round_dofs)
625 new_indices[last_round_dof] = next_free_number++;
631 std::vector<DynamicSparsityPattern::size_type> next_round_dofs;
634 for (
const auto dof : last_round_dofs)
636 j < sparsity.
end(dof);
638 next_round_dofs.push_back(j->column());
641 std::sort(next_round_dofs.begin(), next_round_dofs.end());
644 std::vector<DynamicSparsityPattern::size_type>::iterator end_sorted;
646 std::unique(next_round_dofs.begin(), next_round_dofs.end());
647 next_round_dofs.erase(end_sorted, next_round_dofs.end());
650 for (
int s = next_round_dofs.size() - 1; s >= 0; --s)
652 next_round_dofs.erase(next_round_dofs.begin() + s);
658 if (next_round_dofs.empty())
660 if (std::find(new_indices.begin(),
671 Assert(starting_indices.empty(),
672 ExcMessage(
"The input graph appears to have more than one "
673 "component, but as stated in the documentation "
674 "we only want to reorder such graphs if no "
675 "starting indices are given. The function was "
676 "called with starting indices, however."))
678 next_round_dofs.push_back(
687 std::multimap<DynamicSparsityPattern::size_type, int>
688 dofs_by_coordination;
697 const std::pair<const DynamicSparsityPattern::size_type, int>
698 new_entry(coordination, next_round_dof);
699 dofs_by_coordination.insert(new_entry);
703 std::multimap<DynamicSparsityPattern::size_type, int>::iterator i;
704 for (i = dofs_by_coordination.begin(); i != dofs_by_coordination.end();
706 new_indices[i->second] = next_free_number++;
709 last_round_dofs = next_round_dofs;
715 Assert((std::find(new_indices.begin(),
718 (next_free_number == sparsity.
n_rows()),
729 std::vector<DynamicSparsityPattern::size_type> &renumbering)
736 "Only valid for sparsity patterns which store all rows."));
738 std::vector<types::global_dof_index> touched_nodes(
740 std::vector<unsigned int> row_lengths(connectivity.
n_rows());
741 std::set<types::global_dof_index> current_neighbors;
742 std::vector<std::vector<types::global_dof_index>> groups;
752 row_lengths[row] = connectivity.
row_length(row);
755 std::vector<unsigned int> n_remaining_neighbors(row_lengths);
768 std::pair<types::global_dof_index, types::global_dof_index>
773 if (row_lengths[i] < min_neighbors.second)
775 min_neighbors = std::make_pair(i, n_remaining_neighbors[i]);
776 if (n_remaining_neighbors[i] <= 1)
784 current_neighbors.clear();
785 current_neighbors.insert(min_neighbors.first);
786 while (!current_neighbors.empty())
792 for (
const auto current_neighbor : current_neighbors)
794 Assert(touched_nodes[current_neighbor] ==
797 if (n_remaining_neighbors[current_neighbor] <
798 min_neighbors.second)
800 std::make_pair(current_neighbor,
801 n_remaining_neighbors[current_neighbor]);
808 min_neighbors.second;
809 for (
const auto current_neighbor : current_neighbors)
810 if (n_remaining_neighbors[current_neighbor] == best_row_length)
811 if (row_lengths[current_neighbor] > min_neighbors.second)
813 std::make_pair(current_neighbor,
814 row_lengths[current_neighbor]);
818 groups.emplace_back();
819 std::vector<types::global_dof_index> &next_group = groups.back();
821 next_group.push_back(min_neighbors.first);
822 touched_nodes[min_neighbors.first] = groups.size() - 1;
824 connectivity.
begin(min_neighbors.first);
825 it != connectivity.
end(min_neighbors.first);
829 next_group.push_back(it->column());
830 touched_nodes[it->column()] = groups.size() - 1;
838 for (
const auto index : next_group)
841 connectivity.
begin(index);
842 it != connectivity.
end(index);
845 if (touched_nodes[it->column()] ==
847 current_neighbors.insert(it->column());
848 n_remaining_neighbors[it->column()]--;
850 current_neighbors.erase(index);
861 if (groups.size() < connectivity.
n_rows())
869 connectivity.
begin(groups[i][col]);
870 it != connectivity.
end(groups[i][col]);
872 connectivity_next.
add(i, touched_nodes[it->column()]);
875 std::vector<types::global_dof_index> renumbering_next(groups.size());
882 col < groups[renumbering_next[i]].size();
884 renumbering[count] = groups[renumbering_next[i]][col];
893 renumbering[count] = groups[i][col];
901 std::vector<DynamicSparsityPattern::size_type> &renumbering)
912#ifdef DEAL_II_WITH_MPI
916 const IndexSet & locally_owned_rows,
918 const IndexSet & locally_relevant_rows)
921 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
924 IndexSet requested_rows(locally_relevant_rows);
927 std::vector<unsigned int> index_owner =
942 rows_data[index_owner[i]].push_back(row);
946 const auto rows_data_received =
953 for (
const auto &data : rows_data_received)
955 for (
const auto &row : data.second)
964 send_data[data.first].push_back(row);
965 send_data[data.first].push_back(rlen);
967 send_data[data.first].push_back(
973 const auto received_data =
977 for (
const auto &data : received_data)
979 const auto &recv_buf = data.second;
980 auto ptr = recv_buf.begin();
981 const auto end = recv_buf.end();
984 const auto row = *(ptr++);
987 const auto n_entries = *(ptr++);
1009 const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
1014 std::vector<DynamicSparsityPattern::size_type> start_index(
1015 rows_per_cpu.size() + 1);
1018 start_index[i + 1] = start_index[i] + rows_per_cpu[i];
1020 IndexSet owned(start_index.back());
1021 owned.
add_range(start_index[myid], start_index[myid] + rows_per_cpu[myid]);
1030 const IndexSet & locally_owned_rows,
1032 const IndexSet & locally_relevant_rows)
1034 IndexSet requested_rows(locally_relevant_rows);
1037 std::vector<unsigned int> index_owner =
1043 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
1045 map_vec_t send_data;
1061 send_data[index_owner[i]].push_back(row);
1062 send_data[index_owner[i]].push_back(rlen);
1067 send_data[index_owner[i]].push_back(column);
1074 for (
const auto &data : receive_data)
1076 const auto &recv_buf = data.second;
1077 auto ptr = recv_buf.begin();
1078 const auto end = recv_buf.end();
1081 const auto row = *(ptr++);
1083 const auto n_entries = *(ptr++);
1097 const std::vector<IndexSet> &owned_set_per_cpu,
1103 owned_set_per_cpu[myid],
1112 const IndexSet & locally_owned_rows,
1114 const IndexSet &locally_relevant_rows)
1118 std::vector<BlockDynamicSparsityPattern::size_type>>;
1119 map_vec_t send_data;
1121 IndexSet requested_rows(locally_relevant_rows);
1124 std::vector<unsigned int> index_owner =
1143 std::vector<BlockDynamicSparsityPattern::size_type> &dst =
1144 send_data[index_owner[i]];
1146 dst.push_back(rlen);
1153 dst.push_back(column);
1157 unsigned int num_receive = 0;
1159 std::vector<unsigned int> send_to;
1160 send_to.reserve(send_data.size());
1161 for (
const auto &sparsity_line : send_data)
1162 send_to.push_back(sparsity_line.first);
1169 std::vector<MPI_Request> requests(send_data.size());
1181 unsigned int idx = 0;
1182 for (
const auto &sparsity_line : send_data)
1184 const int ierr = MPI_Isend(sparsity_line.second.data(),
1185 sparsity_line.second.size(),
1187 sparsity_line.first,
1197 std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
1198 for (
unsigned int index = 0; index < num_receive; ++index)
1201 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &status);
1208 recv_buf.resize(len);
1209 ierr = MPI_Recv(recv_buf.data(),
1218 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1219 ptr = recv_buf.begin();
1220 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1221 end = recv_buf.end();
1227 for (
unsigned int c = 0; c < num; ++c)
1239 if (requests.size() > 0)
1242 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
size_type column_number(const size_type row, const unsigned int index) const
unsigned int row_length(const size_type row) const
void add(const size_type i, const size_type j)
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_unique_and_sorted=false)
const IndexSet & row_index_set() const
size_type row_length(const size_type row) const
size_type column_number(const size_type row, const size_type index) const
void clear_row(const size_type row)
void add(const size_type i, const size_type j)
size_type n_elements() const
void subtract_set(const IndexSet &other)
void add_range(const size_type begin, const size_type end)
size_type nth_index_in_set(const size_type local_index) const
types::global_dof_index size_type
bool is_compressed() const
std::size_t n_nonzero_elements() const
bool exists(const size_type i, const size_type j) const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
unsigned int row_length(const size_type row) const
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcMETISNotInstalled()
static ::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
static ::ExceptionBase & ExcMETISError(int arg1)
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrowMPI(error_code)
static ::ExceptionBase & ExcInvalidArraySize(int arg1, int arg2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcNotQuadratic()
static ::ExceptionBase & ExcZOLTANNotInstalled()
static ::ExceptionBase & ExcNotCompressed()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::map< unsigned int, T > some_to_some(const MPI_Comm comm, const std::map< unsigned int, T > &objects_to_send)
std::vector< unsigned int > compute_index_owner(const IndexSet &owned_indices, const IndexSet &indices_to_look_up, const MPI_Comm comm)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
unsigned int compute_n_point_to_point_communications(const MPI_Comm mpi_comm, const std::vector< unsigned int > &destinations)
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
const types::global_dof_index invalid_dof_index
const types::global_dof_index invalid_size_type
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
#define DEAL_II_DOF_INDEX_MPI_TYPE