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(
626 new_indices[last_round_dofs[i]] = next_free_number++;
632 std::vector<DynamicSparsityPattern::size_type> next_round_dofs;
635 for (
const auto dof : last_round_dofs)
637 j < sparsity.
end(dof);
639 next_round_dofs.push_back(j->column());
642 std::sort(next_round_dofs.begin(), next_round_dofs.end());
645 std::vector<DynamicSparsityPattern::size_type>::iterator end_sorted;
647 std::unique(next_round_dofs.begin(), next_round_dofs.end());
648 next_round_dofs.erase(end_sorted, next_round_dofs.end());
651 for (
int s = next_round_dofs.size() - 1; s >= 0; --s)
653 next_round_dofs.erase(next_round_dofs.begin() + s);
659 if (next_round_dofs.empty())
661 if (std::find(new_indices.begin(),
672 Assert(starting_indices.empty(),
673 ExcMessage(
"The input graph appears to have more than one "
674 "component, but as stated in the documentation "
675 "we only want to reorder such graphs if no "
676 "starting indices are given. The function was "
677 "called with starting indices, however."))
679 next_round_dofs.push_back(
688 std::multimap<DynamicSparsityPattern::size_type, int>
689 dofs_by_coordination;
698 const std::pair<const DynamicSparsityPattern::size_type, int>
699 new_entry(coordination, next_round_dof);
700 dofs_by_coordination.insert(new_entry);
704 std::multimap<DynamicSparsityPattern::size_type, int>::iterator i;
705 for (i = dofs_by_coordination.begin(); i != dofs_by_coordination.end();
707 new_indices[i->second] = next_free_number++;
710 last_round_dofs = next_round_dofs;
716 Assert((std::find(new_indices.begin(),
719 (next_free_number == sparsity.
n_rows()),
730 std::vector<DynamicSparsityPattern::size_type> &renumbering)
737 "Only valid for sparsity patterns which store all rows."));
739 std::vector<types::global_dof_index> touched_nodes(
741 std::vector<unsigned int> row_lengths(connectivity.
n_rows());
742 std::set<types::global_dof_index> current_neighbors;
743 std::vector<std::vector<types::global_dof_index>> groups;
753 row_lengths[row] = connectivity.
row_length(row);
756 std::vector<unsigned int> n_remaining_neighbors(row_lengths);
769 std::pair<types::global_dof_index, types::global_dof_index>
774 if (row_lengths[i] < min_neighbors.second)
776 min_neighbors = std::make_pair(i, n_remaining_neighbors[i]);
777 if (n_remaining_neighbors[i] <= 1)
785 current_neighbors.clear();
786 current_neighbors.insert(min_neighbors.first);
787 while (!current_neighbors.empty())
793 for (
const auto current_neighbor : current_neighbors)
795 Assert(touched_nodes[current_neighbor] ==
798 if (n_remaining_neighbors[current_neighbor] <
799 min_neighbors.second)
801 std::make_pair(current_neighbor,
802 n_remaining_neighbors[current_neighbor]);
809 min_neighbors.second;
810 for (
const auto current_neighbor : current_neighbors)
811 if (n_remaining_neighbors[current_neighbor] == best_row_length)
812 if (row_lengths[current_neighbor] > min_neighbors.second)
814 std::make_pair(current_neighbor,
815 row_lengths[current_neighbor]);
819 groups.emplace_back();
820 std::vector<types::global_dof_index> &next_group = groups.back();
822 next_group.push_back(min_neighbors.first);
823 touched_nodes[min_neighbors.first] = groups.size() - 1;
825 connectivity.
begin(min_neighbors.first);
826 it != connectivity.
end(min_neighbors.first);
830 next_group.push_back(it->column());
831 touched_nodes[it->column()] = groups.size() - 1;
839 for (
const auto index : next_group)
842 connectivity.
begin(index);
843 it != connectivity.
end(index);
846 if (touched_nodes[it->column()] ==
848 current_neighbors.insert(it->column());
849 n_remaining_neighbors[it->column()]--;
851 current_neighbors.erase(index);
862 if (groups.size() < connectivity.
n_rows())
870 connectivity.
begin(groups[i][col]);
871 it != connectivity.
end(groups[i][col]);
873 connectivity_next.
add(i, touched_nodes[it->column()]);
876 std::vector<types::global_dof_index> renumbering_next(groups.size());
883 col < groups[renumbering_next[i]].size();
885 renumbering[count] = groups[renumbering_next[i]][col];
894 renumbering[count] = groups[i][col];
902 std::vector<DynamicSparsityPattern::size_type> &renumbering)
913#ifdef DEAL_II_WITH_MPI
917 const IndexSet & locally_owned_rows,
919 const IndexSet & locally_relevant_rows)
922 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
925 IndexSet requested_rows(locally_relevant_rows);
928 std::vector<unsigned int> index_owner =
943 rows_data[index_owner[i]].push_back(row);
947 const auto rows_data_received =
954 for (
const auto &data : rows_data_received)
956 for (
const auto &row : data.second)
965 send_data[data.first].push_back(row);
966 send_data[data.first].push_back(rlen);
968 send_data[data.first].push_back(
974 const auto received_data =
978 for (
const auto &data : received_data)
980 const auto &recv_buf = data.second;
981 auto ptr = recv_buf.begin();
982 const auto end = recv_buf.end();
985 const auto row = *(ptr++);
988 const auto n_entries = *(ptr++);
1010 const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
1015 std::vector<DynamicSparsityPattern::size_type> start_index(
1016 rows_per_cpu.size() + 1);
1019 start_index[i + 1] = start_index[i] + rows_per_cpu[i];
1021 IndexSet owned(start_index.back());
1022 owned.
add_range(start_index[myid], start_index[myid] + rows_per_cpu[myid]);
1031 const IndexSet & locally_owned_rows,
1033 const IndexSet & locally_relevant_rows)
1035 IndexSet requested_rows(locally_relevant_rows);
1038 std::vector<unsigned int> index_owner =
1044 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
1046 map_vec_t send_data;
1062 send_data[index_owner[i]].push_back(row);
1063 send_data[index_owner[i]].push_back(rlen);
1068 send_data[index_owner[i]].push_back(column);
1075 for (
const auto &data : receive_data)
1077 const auto &recv_buf = data.second;
1078 auto ptr = recv_buf.begin();
1079 const auto end = recv_buf.end();
1082 const auto row = *(ptr++);
1084 const auto n_entries = *(ptr++);
1098 const std::vector<IndexSet> &owned_set_per_cpu,
1104 owned_set_per_cpu[myid],
1113 const IndexSet & locally_owned_rows,
1115 const IndexSet &locally_relevant_rows)
1119 std::vector<BlockDynamicSparsityPattern::size_type>>;
1120 map_vec_t send_data;
1122 IndexSet requested_rows(locally_relevant_rows);
1125 std::vector<unsigned int> index_owner =
1144 std::vector<BlockDynamicSparsityPattern::size_type> &dst =
1145 send_data[index_owner[i]];
1147 dst.push_back(rlen);
1154 dst.push_back(column);
1158 unsigned int num_receive = 0;
1160 std::vector<unsigned int> send_to;
1161 send_to.reserve(send_data.size());
1162 for (
const auto &sparsity_line : send_data)
1163 send_to.push_back(sparsity_line.first);
1170 std::vector<MPI_Request> requests(send_data.size());
1182 unsigned int idx = 0;
1183 for (
const auto &sparsity_line : send_data)
1185 const int ierr = MPI_Isend(sparsity_line.second.data(),
1186 sparsity_line.second.size(),
1188 sparsity_line.first,
1198 std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
1199 for (
unsigned int index = 0; index < num_receive; ++index)
1202 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag, mpi_comm, &status);
1209 recv_buf.resize(len);
1210 ierr = MPI_Recv(recv_buf.data(),
1219 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1220 ptr = recv_buf.begin();
1221 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator
1222 end = recv_buf.end();
1228 for (
unsigned int c = 0; c < num; ++c)
1240 if (requests.size() > 0)
1243 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
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
std::size_t n_nonzero_elements() const
unsigned int row_length(const size_type row) const
bool exists(const size_type i, const size_type j) const
bool is_compressed() const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcMETISNotInstalled()
size_type column_number(const size_type row, const unsigned int index) const
static ::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
static ::ExceptionBase & ExcNotCompressed()
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 & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_unique_and_sorted=false)
types::global_dof_index size_type
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)
unsigned int row_length(const size_type row) const
void add(const size_type i, const size_type j)
void add(const size_type i, const size_type j)
std::vector< unsigned int > compute_index_owner(const IndexSet &owned_indices, const IndexSet &indices_to_look_up, const MPI_Comm &comm)
unsigned int compute_n_point_to_point_communications(const MPI_Comm &mpi_comm, const std::vector< unsigned int > &destinations)
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
std::map< unsigned int, T > some_to_some(const MPI_Comm &comm, const std::map< unsigned int, T > &objects_to_send)
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