25#ifdef DEAL_II_WITH_MPI
33#ifdef DEAL_II_WITH_METIS
40#ifdef DEAL_II_TRILINOS_WITH_ZOLTAN
41# include <zoltan_cpp.h>
55 const std::vector<unsigned int> &cell_weights,
56 const unsigned int n_partitions,
57 std::vector<unsigned int> &partition_indices)
61#ifndef DEAL_II_WITH_METIS
62 (void)sparsity_pattern;
65 (void)partition_indices;
73 idx_t n =
static_cast<signed int>(sparsity_pattern.
n_rows());
88 idx_t options[METIS_NOPTIONS];
89 METIS_SetDefaultOptions(options);
93 std::vector<idx_t> int_rowstart(1);
94 int_rowstart.reserve(sparsity_pattern.
n_rows() + 1);
95 std::vector<idx_t> int_colnums;
101 col < sparsity_pattern.
end(row);
103 int_colnums.push_back(col->column());
104 int_rowstart.push_back(int_colnums.size());
107 std::vector<idx_t> int_partition_indices(sparsity_pattern.
n_rows());
110 std::vector<idx_t> int_cell_weights;
111 if (cell_weights.size() > 0)
113 Assert(cell_weights.size() == sparsity_pattern.
n_rows(),
115 sparsity_pattern.
n_rows()));
116 int_cell_weights.resize(cell_weights.size());
117 std::copy(cell_weights.begin(),
119 int_cell_weights.begin());
123 idx_t *
const p_int_cell_weights =
124 (cell_weights.size() > 0 ? int_cell_weights.data() :
nullptr);
135 ierr = METIS_PartGraphRecursive(&n,
147 int_partition_indices.data());
151 ierr = METIS_PartGraphKway(&n,
163 int_partition_indices.data());
170 std::copy(int_partition_indices.begin(),
171 int_partition_indices.end(),
172 partition_indices.begin());
178#ifdef DEAL_II_TRILINOS_WITH_ZOLTAN
181 get_number_of_objects(
void *
data,
int *ierr)
192 get_object_list(
void *
data,
195 ZOLTAN_ID_PTR globalID,
196 ZOLTAN_ID_PTR localID,
208 auto n_dofs = graph->
n_rows();
210 for (
unsigned int i = 0; i < n_dofs; ++i)
219 get_num_edges_list(
void *
data,
223 ZOLTAN_ID_PTR globalID,
234 for (
int i = 0; i < num_obj; ++i)
237 numEdges[i] = graph->
row_length(globalID[i]) - 1;
246 get_edge_list(
void *
data,
253 ZOLTAN_ID_PTR nborGID,
262 ZOLTAN_ID_PTR nextNborGID = nborGID;
263 int *nextNborProc = nborProc;
267 i < static_cast<SparsityPattern::size_type>(num_obj);
275 if (i != col->column())
280 *nextNborGID++ = col->column();
290 const std::vector<unsigned int> &cell_weights,
291 const unsigned int n_partitions,
292 std::vector<unsigned int> &partition_indices)
296#ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
297 (void)sparsity_pattern;
300 (void)partition_indices;
305 cell_weights.empty(),
307 "The cell weighting functionality for Zoltan has not yet been implemented."));
310 std::unique_ptr<Zoltan> zz = std::make_unique<Zoltan>(MPI_COMM_SELF);
314 zz->Set_Param(
"DEBUG_LEVEL",
"0");
318 zz->Set_Param(
"NUM_LOCAL_PARTS",
319 std::to_string(n_partitions));
334 zz->Set_Param(
"PHG_EDGE_SIZE_THRESHOLD",
"0.5");
341 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
342 zz->Set_Obj_List_Fn(get_object_list, &graph);
343 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
344 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
348 int num_gid_entries = 1;
349 int num_lid_entries = 1;
351 ZOLTAN_ID_PTR import_global_ids =
nullptr;
352 ZOLTAN_ID_PTR import_local_ids =
nullptr;
353 int *import_procs =
nullptr;
354 int *import_to_part =
nullptr;
356 ZOLTAN_ID_PTR export_global_ids =
nullptr;
357 ZOLTAN_ID_PTR export_local_ids =
nullptr;
358 int *export_procs =
nullptr;
359 int *export_to_part =
nullptr;
362 const int rc = zz->LB_Partition(changes,
382 std::fill(partition_indices.begin(), partition_indices.end(), 0);
386 for (
int i = 0; i < num_export; ++i)
387 partition_indices[export_local_ids[i]] = export_to_part[i];
395 const unsigned int n_partitions,
396 std::vector<unsigned int> &partition_indices,
399 std::vector<unsigned int> cell_weights;
412 const std::vector<unsigned int> &cell_weights,
413 const unsigned int n_partitions,
414 std::vector<unsigned int> &partition_indices,
423 Assert(partition_indices.size() == sparsity_pattern.
n_rows(),
425 sparsity_pattern.
n_rows()));
428 if (n_partitions == 1 || (sparsity_pattern.
n_rows() == 1))
430 std::fill_n(partition_indices.begin(), partition_indices.size(), 0U);
435 partition_metis(sparsity_pattern,
440 partition_zoltan(sparsity_pattern,
451 std::vector<unsigned int> &color_indices)
455#ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
456 (void)sparsity_pattern;
462 std::unique_ptr<Zoltan> zz = std::make_unique<Zoltan>(MPI_COMM_SELF);
466 zz->Set_Param(
"DEBUG_LEVEL",
"0");
467 zz->Set_Param(
"COLORING_PROBLEM",
"DISTANCE-1");
468 zz->Set_Param(
"NUM_GID_ENTRIES",
"1");
469 zz->Set_Param(
"NUM_LID_ENTRIES",
"1");
470 zz->Set_Param(
"OBJ_WEIGHT_DIM",
"0");
471 zz->Set_Param(
"RECOLORING_NUM_OF_ITERATIONS",
"0");
478 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
479 zz->Set_Obj_List_Fn(get_object_list, &graph);
480 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
481 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
484 int num_gid_entries = 1;
485 const int num_objects = graph.
n_rows();
488 std::vector<ZOLTAN_ID_TYPE> global_ids(num_objects);
489 std::vector<int> color_exp(num_objects);
492 for (
int i = 0; i < num_objects; ++i)
496 int rc = zz->Color(num_gid_entries,
504 color_indices.resize(num_objects);
505 Assert(color_exp.size() == color_indices.size(),
508 std::copy(color_exp.begin(), color_exp.end(), color_indices.begin());
510 unsigned int n_colors =
511 *(std::max_element(color_indices.begin(), color_indices.end()));
527 const std::vector<DynamicSparsityPattern::size_type> &new_indices)
537 if (sparsity.
row_length(row) < min_coordination)
540 starting_point = row;
565 return starting_point;
574 std::vector<DynamicSparsityPattern::size_type> &new_indices,
575 const std::vector<DynamicSparsityPattern::size_type> &starting_indices)
583 "You can't specify more starting indices than there are rows"));
587 "Only valid for sparsity patterns which store all rows."));
588 for (
const auto starting_index : starting_indices)
590 (void)starting_index;
592 ExcMessage(
"Invalid starting index: All starting indices need "
593 "to be between zero and the number of rows in the "
594 "sparsity pattern."));
599 std::vector<DynamicSparsityPattern::size_type> last_round_dofs(
603 std::fill(new_indices.begin(),
609 if (last_round_dofs.empty())
610 last_round_dofs.push_back(
617 for (
const auto &last_round_dof : last_round_dofs)
618 new_indices[last_round_dof] = next_free_number++;
621 std::vector<DynamicSparsityPattern::size_type> next_round_dofs;
625 std::vector<std::pair<unsigned int, DynamicSparsityPattern::size_type>>
626 dofs_by_coordination;
631 next_round_dofs.clear();
634 for (
const auto dof : last_round_dofs)
636 const unsigned int row_length = sparsity.
row_length(dof);
637 for (
unsigned int i = 0; i < row_length; ++i)
643 next_round_dofs.push_back(column);
648 new_indices[column] = 0;
657 if (next_round_dofs.empty())
659 if (std::find(new_indices.begin(),
670 Assert(starting_indices.empty(),
671 ExcMessage(
"The input graph appears to have more than one "
672 "component, but as stated in the documentation "
673 "we only want to reorder such graphs if no "
674 "starting indices are given. The function was "
675 "called with starting indices, however."));
677 next_round_dofs.push_back(
683 dofs_by_coordination.clear();
685 dofs_by_coordination.emplace_back(sparsity.
row_length(next_round_dof),
687 std::sort(dofs_by_coordination.begin(), dofs_by_coordination.end());
690 for (
const auto &i : dofs_by_coordination)
691 new_indices[i.second] = next_free_number++;
694 last_round_dofs.swap(next_round_dofs);
700 Assert((std::find(new_indices.begin(),
703 (next_free_number == sparsity.
n_rows()),
714 std::vector<DynamicSparsityPattern::size_type> &renumbering)
721 "Only valid for sparsity patterns which store all rows."));
738 std::vector<types::global_dof_index> touched_nodes(n_nodes, unseen_node);
740 std::vector<unsigned int> row_lengths(n_nodes);
741 std::vector<types::global_dof_index> current_neighbors;
742 std::vector<types::global_dof_index> group_starts(1);
743 std::vector<types::global_dof_index> group_indices;
744 group_indices.reserve(n_nodes);
754 row_lengths[row] = connectivity.
row_length(row);
757 std::vector<unsigned int> n_remaining_neighbors(row_lengths);
775 if (touched_nodes[i] == unseen_node)
776 if (row_lengths[i] < candidate_valence)
779 candidate_valence = n_remaining_neighbors[i];
780 if (candidate_valence <= 1)
788 current_neighbors = {candidate_index};
789 touched_nodes[candidate_index] = available_node;
807 unsigned int candidate_row_length = 0;
808 const unsigned int loop_length = current_neighbors.size();
809 unsigned int write_index = 0;
810 for (
unsigned int i = 0; i < loop_length; ++i)
813 Assert(touched_nodes[node] != unseen_node,
815 if (touched_nodes[node] == available_node)
817 current_neighbors[write_index] = node;
819 if (n_remaining_neighbors[node] < candidate_valence ||
820 (n_remaining_neighbors[node] == candidate_valence &&
821 (row_lengths[node] > candidate_row_length ||
822 (row_lengths[node] == candidate_row_length &&
823 node < candidate_index))))
825 candidate_index = node;
826 candidate_valence = n_remaining_neighbors[node];
827 candidate_row_length = row_lengths[node];
831 current_neighbors.resize(write_index);
836 Assert(touched_nodes[node] == available_node,
841 if (current_neighbors.empty())
846 group_indices.push_back(candidate_index);
847 touched_nodes[candidate_index] = group_starts.size() - 1;
848 const auto end_it = connectivity.
end(candidate_index);
849 for (
auto it = connectivity.
begin(candidate_index); it != end_it;
851 if (touched_nodes[it->column()] >= available_node)
853 group_indices.push_back(it->column());
854 touched_nodes[it->column()] = group_starts.size() - 1;
856 group_starts.push_back(group_indices.size());
865 group_starts[group_starts.size() - 2];
866 index < group_starts.back();
869 auto it = connectivity.
begin(group_indices[index]);
870 const auto end_row = connectivity.
end(group_indices[index]);
871 for (; it != end_row; ++it)
873 if (touched_nodes[it->column()] == unseen_node)
875 current_neighbors.push_back(it->column());
876 touched_nodes[it->column()] = available_node;
878 n_remaining_neighbors[it->column()]--;
890 const unsigned int n_groups = group_starts.size() - 1;
891 if (n_groups < n_nodes)
897 index < group_starts[row + 1];
900 auto it = connectivity.
begin(group_indices[index]);
901 const auto end_it = connectivity.
end(group_indices[index]);
902 for (; it != end_it; ++it)
903 connectivity_next.
add(row, touched_nodes[it->column()]);
907 std::vector<types::global_dof_index> renumbering_next(n_groups);
914 group_starts[renumbering_next[row]];
915 index < group_starts[renumbering_next[row] + 1];
917 renumbering[c] = group_indices[index];
925 renumbering[c++] = i;
933 std::vector<DynamicSparsityPattern::size_type> &renumbering)
944#ifdef DEAL_II_WITH_MPI
950 const IndexSet &locally_relevant_rows)
953 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
956 IndexSet requested_rows(locally_relevant_rows);
959 std::vector<unsigned int> index_owner =
974 rows_data[index_owner[i]].push_back(row);
978 const auto rows_data_received =
985 for (
const auto &
data : rows_data_received)
987 for (
const auto &row :
data.second)
996 send_data[
data.first].push_back(row);
997 send_data[
data.first].push_back(rlen);
999 send_data[
data.first].push_back(
1005 const auto received_data =
1009 for (
const auto &
data : received_data)
1011 const auto &recv_buf =
data.second;
1012 auto ptr = recv_buf.begin();
1013 const auto end = recv_buf.end();
1016 const auto row = *(ptr++);
1019 const auto n_entries = *(ptr++);
1041 const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
1046 std::vector<DynamicSparsityPattern::size_type> start_index(
1047 rows_per_cpu.size() + 1);
1050 start_index[i + 1] = start_index[i] + rows_per_cpu[i];
1052 IndexSet owned(start_index.back());
1053 owned.
add_range(start_index[myid], start_index[myid] + rows_per_cpu[myid]);
1062 const IndexSet &locally_owned_rows,
1064 const IndexSet &locally_relevant_rows)
1069 "The DynamicSparsityPattern must be initialized with an IndexSet that contains locally relevant indices."));
1071 IndexSet requested_rows(locally_relevant_rows);
1074 std::vector<unsigned int> index_owner =
1080 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
1082 map_vec_t send_data;
1098 send_data[index_owner[i]].push_back(row);
1099 send_data[index_owner[i]].push_back(rlen);
1104 send_data[index_owner[i]].push_back(column);
1111 for (
const auto &
data : receive_data)
1113 const auto &recv_buf =
data.second;
1114 auto ptr = recv_buf.begin();
1115 const auto end = recv_buf.end();
1118 const auto row = *(ptr++);
1120 const auto n_entries = *(ptr++);
1134 const std::vector<IndexSet> &owned_set_per_cpu,
1140 owned_set_per_cpu[myid],
1149 const IndexSet &locally_owned_rows,
1151 const IndexSet &locally_relevant_rows)
1155 std::vector<BlockDynamicSparsityPattern::size_type>>;
1156 map_vec_t send_data;
1158 IndexSet requested_rows(locally_relevant_rows);
1161 std::vector<unsigned int> index_owner =
1180 std::vector<BlockDynamicSparsityPattern::size_type> &dst =
1181 send_data[index_owner[i]];
1183 dst.push_back(rlen);
1190 dst.push_back(column);
1194 unsigned int num_receive = 0;
1196 std::vector<unsigned int> send_to;
1197 send_to.reserve(send_data.size());
1198 for (
const auto &sparsity_line : send_data)
1199 send_to.push_back(sparsity_line.first);
1206 std::vector<MPI_Request> requests(send_data.size());
1218 unsigned int idx = 0;
1219 for (
const auto &sparsity_line : send_data)
1221 const int ierr = MPI_Isend(
1222 sparsity_line.second.data(),
1223 sparsity_line.second.size(),
1224 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
1225 sparsity_line.first,
1235 std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
1236 for (
unsigned int index = 0; index < num_receive; ++index)
1239 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &status);
1243 ierr = MPI_Get_count(
1245 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
1249 recv_buf.resize(len);
1253 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
1260 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1261 ptr = recv_buf.begin();
1262 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1263 end = recv_buf.end();
1269 for (
unsigned int c = 0; c < num; ++c)
1281 if (requests.size() > 0)
1284 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
constexpr bool running_in_debug_mode()
#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::vector< index_type > data
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)
constexpr types::global_dof_index invalid_dof_index
constexpr types::global_dof_index invalid_size_type
constexpr unsigned int invalid_unsigned_int
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)