27#ifdef DEAL_II_WITH_MPI
35#ifdef DEAL_II_WITH_METIS
42#ifdef DEAL_II_TRILINOS_WITH_ZOLTAN
43# include <zoltan_cpp.h>
57 const std::vector<unsigned int> &cell_weights,
58 const unsigned int n_partitions,
59 std::vector<unsigned int> &partition_indices)
63#ifndef DEAL_II_WITH_METIS
64 (void)sparsity_pattern;
67 (void)partition_indices;
75 idx_t n =
static_cast<signed int>(sparsity_pattern.
n_rows());
90 idx_t options[METIS_NOPTIONS];
91 METIS_SetDefaultOptions(options);
95 std::vector<idx_t> int_rowstart(1);
96 int_rowstart.reserve(sparsity_pattern.
n_rows() + 1);
97 std::vector<idx_t> int_colnums;
103 col < sparsity_pattern.
end(row);
105 int_colnums.push_back(col->column());
106 int_rowstart.push_back(int_colnums.size());
109 std::vector<idx_t> int_partition_indices(sparsity_pattern.
n_rows());
112 std::vector<idx_t> int_cell_weights;
113 if (cell_weights.size() > 0)
115 Assert(cell_weights.size() == sparsity_pattern.
n_rows(),
117 sparsity_pattern.
n_rows()));
118 int_cell_weights.resize(cell_weights.size());
119 std::copy(cell_weights.begin(),
121 int_cell_weights.begin());
125 idx_t *
const p_int_cell_weights =
126 (cell_weights.size() > 0 ? int_cell_weights.data() :
nullptr);
137 ierr = METIS_PartGraphRecursive(&n,
149 int_partition_indices.data());
153 ierr = METIS_PartGraphKway(&n,
165 int_partition_indices.data());
172 std::copy(int_partition_indices.begin(),
173 int_partition_indices.end(),
174 partition_indices.begin());
180#ifdef DEAL_II_TRILINOS_WITH_ZOLTAN
183 get_number_of_objects(
void *
data,
int *ierr)
194 get_object_list(
void *
data,
197 ZOLTAN_ID_PTR globalID,
198 ZOLTAN_ID_PTR localID,
210 auto n_dofs = graph->
n_rows();
212 for (
unsigned int i = 0; i < n_dofs; ++i)
221 get_num_edges_list(
void *
data,
225 ZOLTAN_ID_PTR globalID,
236 for (
int i = 0; i < num_obj; ++i)
239 numEdges[i] = graph->
row_length(globalID[i]) - 1;
248 get_edge_list(
void *
data,
255 ZOLTAN_ID_PTR nborGID,
264 ZOLTAN_ID_PTR nextNborGID = nborGID;
265 int *nextNborProc = nborProc;
269 i < static_cast<SparsityPattern::size_type>(num_obj);
277 if (i != col->column())
282 *nextNborGID++ = col->column();
292 const std::vector<unsigned int> &cell_weights,
293 const unsigned int n_partitions,
294 std::vector<unsigned int> &partition_indices)
298#ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
299 (void)sparsity_pattern;
302 (void)partition_indices;
307 cell_weights.empty(),
309 "The cell weighting functionality for Zoltan has not yet been implemented."));
313 std::unique_ptr<Zoltan> zz = std::make_unique<Zoltan>(MPI_COMM_SELF);
317 zz->Set_Param(
"DEBUG_LEVEL",
"0");
321 zz->Set_Param(
"NUM_LOCAL_PARTS",
322 std::to_string(n_partitions));
337 zz->Set_Param(
"PHG_EDGE_SIZE_THRESHOLD",
"0.5");
344 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
345 zz->Set_Obj_List_Fn(get_object_list, &graph);
346 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
347 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
351 int num_gid_entries = 1;
352 int num_lid_entries = 1;
354 ZOLTAN_ID_PTR import_global_ids =
nullptr;
355 ZOLTAN_ID_PTR import_local_ids =
nullptr;
356 int *import_procs =
nullptr;
357 int *import_to_part =
nullptr;
359 ZOLTAN_ID_PTR export_global_ids =
nullptr;
360 ZOLTAN_ID_PTR export_local_ids =
nullptr;
361 int *export_procs =
nullptr;
362 int *export_to_part =
nullptr;
365 const int rc = zz->LB_Partition(changes,
386 std::fill(partition_indices.begin(), partition_indices.end(), 0);
390 for (
int i = 0; i < num_export; ++i)
391 partition_indices[export_local_ids[i]] = export_to_part[i];
399 const unsigned int n_partitions,
400 std::vector<unsigned int> &partition_indices,
403 std::vector<unsigned int> cell_weights;
416 const std::vector<unsigned int> &cell_weights,
417 const unsigned int n_partitions,
418 std::vector<unsigned int> &partition_indices,
427 Assert(partition_indices.size() == sparsity_pattern.
n_rows(),
429 sparsity_pattern.
n_rows()));
432 if (n_partitions == 1 || (sparsity_pattern.
n_rows() == 1))
434 std::fill_n(partition_indices.begin(), partition_indices.size(), 0U);
439 partition_metis(sparsity_pattern,
444 partition_zoltan(sparsity_pattern,
455 std::vector<unsigned int> &color_indices)
459#ifndef DEAL_II_TRILINOS_WITH_ZOLTAN
460 (void)sparsity_pattern;
466 std::unique_ptr<Zoltan> zz = std::make_unique<Zoltan>(MPI_COMM_SELF);
470 zz->Set_Param(
"DEBUG_LEVEL",
"0");
471 zz->Set_Param(
"COLORING_PROBLEM",
"DISTANCE-1");
472 zz->Set_Param(
"NUM_GID_ENTRIES",
"1");
473 zz->Set_Param(
"NUM_LID_ENTRIES",
"1");
474 zz->Set_Param(
"OBJ_WEIGHT_DIM",
"0");
475 zz->Set_Param(
"RECOLORING_NUM_OF_ITERATIONS",
"0");
482 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
483 zz->Set_Obj_List_Fn(get_object_list, &graph);
484 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
485 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
488 int num_gid_entries = 1;
489 const int num_objects = graph.
n_rows();
492 std::vector<ZOLTAN_ID_TYPE> global_ids(num_objects);
493 std::vector<int> color_exp(num_objects);
496 for (
int i = 0; i < num_objects; ++i)
500 int rc = zz->Color(num_gid_entries,
510 color_indices.resize(num_objects);
511 Assert(color_exp.size() == color_indices.size(),
514 std::copy(color_exp.begin(), color_exp.end(), color_indices.begin());
516 unsigned int n_colors =
517 *(std::max_element(color_indices.begin(), color_indices.end()));
533 const std::vector<DynamicSparsityPattern::size_type> &new_indices)
543 if (sparsity.
row_length(row) < min_coordination)
546 starting_point = row;
571 return starting_point;
580 std::vector<DynamicSparsityPattern::size_type> &new_indices,
581 const std::vector<DynamicSparsityPattern::size_type> &starting_indices)
589 "You can't specify more starting indices than there are rows"));
593 "Only valid for sparsity patterns which store all rows."));
594 for (
const auto starting_index : starting_indices)
596 (void)starting_index;
598 ExcMessage(
"Invalid starting index: All starting indices need "
599 "to be between zero and the number of rows in the "
600 "sparsity pattern."));
605 std::vector<DynamicSparsityPattern::size_type> last_round_dofs(
609 std::fill(new_indices.begin(),
615 if (last_round_dofs.empty())
616 last_round_dofs.push_back(
623 for (
const auto &last_round_dof : last_round_dofs)
624 new_indices[last_round_dof] = next_free_number++;
627 std::vector<DynamicSparsityPattern::size_type> next_round_dofs;
631 std::vector<std::pair<unsigned int, DynamicSparsityPattern::size_type>>
632 dofs_by_coordination;
637 next_round_dofs.clear();
640 for (
const auto dof : last_round_dofs)
642 const unsigned int row_length = sparsity.
row_length(dof);
643 for (
unsigned int i = 0; i < row_length; ++i)
649 next_round_dofs.push_back(column);
654 new_indices[column] = 0;
663 if (next_round_dofs.empty())
665 if (std::find(new_indices.begin(),
676 Assert(starting_indices.empty(),
677 ExcMessage(
"The input graph appears to have more than one "
678 "component, but as stated in the documentation "
679 "we only want to reorder such graphs if no "
680 "starting indices are given. The function was "
681 "called with starting indices, however."));
683 next_round_dofs.push_back(
689 dofs_by_coordination.clear();
691 dofs_by_coordination.emplace_back(sparsity.
row_length(next_round_dof),
693 std::sort(dofs_by_coordination.begin(), dofs_by_coordination.end());
696 for (
const auto &i : dofs_by_coordination)
697 new_indices[i.second] = next_free_number++;
700 last_round_dofs.swap(next_round_dofs);
706 Assert((std::find(new_indices.begin(),
709 (next_free_number == sparsity.
n_rows()),
720 std::vector<DynamicSparsityPattern::size_type> &renumbering)
727 "Only valid for sparsity patterns which store all rows."));
744 std::vector<types::global_dof_index> touched_nodes(n_nodes, unseen_node);
746 std::vector<unsigned int> row_lengths(n_nodes);
747 std::vector<types::global_dof_index> current_neighbors;
748 std::vector<types::global_dof_index> group_starts(1);
749 std::vector<types::global_dof_index> group_indices;
750 group_indices.reserve(n_nodes);
760 row_lengths[row] = connectivity.
row_length(row);
763 std::vector<unsigned int> n_remaining_neighbors(row_lengths);
781 if (touched_nodes[i] == unseen_node)
782 if (row_lengths[i] < candidate_valence)
785 candidate_valence = n_remaining_neighbors[i];
786 if (candidate_valence <= 1)
794 current_neighbors = {candidate_index};
795 touched_nodes[candidate_index] = available_node;
813 unsigned int candidate_row_length = 0;
814 const unsigned int loop_length = current_neighbors.size();
815 unsigned int write_index = 0;
816 for (
unsigned int i = 0; i < loop_length; ++i)
819 Assert(touched_nodes[node] != unseen_node,
821 if (touched_nodes[node] == available_node)
823 current_neighbors[write_index] = node;
825 if (n_remaining_neighbors[node] < candidate_valence ||
826 (n_remaining_neighbors[node] == candidate_valence &&
827 (row_lengths[node] > candidate_row_length ||
828 (row_lengths[node] == candidate_row_length &&
829 node < candidate_index))))
831 candidate_index = node;
832 candidate_valence = n_remaining_neighbors[node];
833 candidate_row_length = row_lengths[node];
837 current_neighbors.resize(write_index);
841 Assert(touched_nodes[node] == available_node,
846 if (current_neighbors.empty())
851 group_indices.push_back(candidate_index);
852 touched_nodes[candidate_index] = group_starts.size() - 1;
853 const auto end_it = connectivity.
end(candidate_index);
854 for (
auto it = connectivity.
begin(candidate_index); it != end_it;
856 if (touched_nodes[it->column()] >= available_node)
858 group_indices.push_back(it->column());
859 touched_nodes[it->column()] = group_starts.size() - 1;
861 group_starts.push_back(group_indices.size());
870 group_starts[group_starts.size() - 2];
871 index < group_starts.back();
874 auto it = connectivity.
begin(group_indices[index]);
875 const auto end_row = connectivity.
end(group_indices[index]);
876 for (; it != end_row; ++it)
878 if (touched_nodes[it->column()] == unseen_node)
880 current_neighbors.push_back(it->column());
881 touched_nodes[it->column()] = available_node;
883 n_remaining_neighbors[it->column()]--;
895 const unsigned int n_groups = group_starts.size() - 1;
896 if (n_groups < n_nodes)
902 index < group_starts[row + 1];
905 auto it = connectivity.
begin(group_indices[index]);
906 const auto end_it = connectivity.
end(group_indices[index]);
907 for (; it != end_it; ++it)
908 connectivity_next.
add(row, touched_nodes[it->column()]);
912 std::vector<types::global_dof_index> renumbering_next(n_groups);
919 group_starts[renumbering_next[row]];
920 index < group_starts[renumbering_next[row] + 1];
922 renumbering[c] = group_indices[index];
930 renumbering[c++] = i;
938 std::vector<DynamicSparsityPattern::size_type> &renumbering)
949#ifdef DEAL_II_WITH_MPI
955 const IndexSet &locally_relevant_rows)
958 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
961 IndexSet requested_rows(locally_relevant_rows);
964 std::vector<unsigned int> index_owner =
979 rows_data[index_owner[i]].push_back(row);
983 const auto rows_data_received =
990 for (
const auto &
data : rows_data_received)
992 for (
const auto &row :
data.second)
1001 send_data[
data.first].push_back(row);
1002 send_data[
data.first].push_back(rlen);
1004 send_data[
data.first].push_back(
1010 const auto received_data =
1014 for (
const auto &
data : received_data)
1016 const auto &recv_buf =
data.second;
1017 auto ptr = recv_buf.begin();
1018 const auto end = recv_buf.end();
1021 const auto row = *(ptr++);
1024 const auto n_entries = *(ptr++);
1046 const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
1051 std::vector<DynamicSparsityPattern::size_type> start_index(
1052 rows_per_cpu.size() + 1);
1055 start_index[i + 1] = start_index[i] + rows_per_cpu[i];
1057 IndexSet owned(start_index.back());
1058 owned.
add_range(start_index[myid], start_index[myid] + rows_per_cpu[myid]);
1067 const IndexSet &locally_owned_rows,
1069 const IndexSet &locally_relevant_rows)
1074 "The DynamicSparsityPattern must be initialized with an IndexSet that contains locally relevant indices."));
1076 IndexSet requested_rows(locally_relevant_rows);
1079 std::vector<unsigned int> index_owner =
1085 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
1087 map_vec_t send_data;
1103 send_data[index_owner[i]].push_back(row);
1104 send_data[index_owner[i]].push_back(rlen);
1109 send_data[index_owner[i]].push_back(column);
1116 for (
const auto &
data : receive_data)
1118 const auto &recv_buf =
data.second;
1119 auto ptr = recv_buf.begin();
1120 const auto end = recv_buf.end();
1123 const auto row = *(ptr++);
1125 const auto n_entries = *(ptr++);
1139 const std::vector<IndexSet> &owned_set_per_cpu,
1145 owned_set_per_cpu[myid],
1154 const IndexSet &locally_owned_rows,
1156 const IndexSet &locally_relevant_rows)
1160 std::vector<BlockDynamicSparsityPattern::size_type>>;
1161 map_vec_t send_data;
1163 IndexSet requested_rows(locally_relevant_rows);
1166 std::vector<unsigned int> index_owner =
1185 std::vector<BlockDynamicSparsityPattern::size_type> &dst =
1186 send_data[index_owner[i]];
1188 dst.push_back(rlen);
1195 dst.push_back(column);
1199 unsigned int num_receive = 0;
1201 std::vector<unsigned int> send_to;
1202 send_to.reserve(send_data.size());
1203 for (
const auto &sparsity_line : send_data)
1204 send_to.push_back(sparsity_line.first);
1211 std::vector<MPI_Request> requests(send_data.size());
1223 unsigned int idx = 0;
1224 for (
const auto &sparsity_line : send_data)
1226 const int ierr = MPI_Isend(sparsity_line.second.data(),
1227 sparsity_line.second.size(),
1229 sparsity_line.first,
1239 std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
1240 for (
unsigned int index = 0; index < num_receive; ++index)
1243 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &status);
1250 recv_buf.resize(len);
1251 ierr = MPI_Recv(recv_buf.data(),
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
#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)
static const unsigned int invalid_unsigned_int
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