17 #include <deal.II/base/exceptions.h> 18 #include <deal.II/base/std_cxx14/memory.h> 20 #include <deal.II/lac/exceptions.h> 21 #include <deal.II/lac/sparsity_pattern.h> 22 #include <deal.II/lac/sparsity_tools.h> 28 #ifdef DEAL_II_WITH_MPI 29 # include <deal.II/base/mpi.h> 30 # include <deal.II/base/utilities.h> 32 # include <deal.II/lac/block_sparsity_pattern.h> 33 # include <deal.II/lac/dynamic_sparsity_pattern.h> 36 #ifdef DEAL_II_WITH_METIS 43 #ifdef DEAL_II_TRILINOS_WITH_ZOLTAN 44 # include <zoltan_cpp.h> 50 DEAL_II_NAMESPACE_OPEN
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),
89 nparts = std::min(n, nparts);
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());
121 std::copy(cell_weights.begin(),
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());
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 =
315 std_cxx14::make_unique<Zoltan>(MPI_COMM_SELF);
319 zz->Set_Param(
"DEBUG_LEVEL",
"0");
323 zz->Set_Param(
"NUM_LOCAL_PARTS",
324 std::to_string(n_partitions));
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(), 0U);
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()));
533 find_unnumbered_starting_index(
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(
619 internal::find_unnumbered_starting_index(sparsity, new_indices));
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(
681 internal::find_unnumbered_starting_index(sparsity,
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)
908 internal::reorder_hierarchical(connectivity, renumbering);
914 #ifdef DEAL_II_WITH_MPI 918 const std::vector<IndexSet> &owned,
919 const MPI_Comm & mpi_comm,
926 for (
const auto &
set : owned)
930 Assert(owned[myid].is_ascending_and_one_to_one(mpi_comm),
933 std::vector<DynamicSparsityPattern::size_type> start_index(owned.size() +
937 start_index[i + 1] = start_index[i] + owned[i].n_elements();
940 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
943 IndexSet requested_rows(ghost_range);
950 unsigned int cpu_rank = 0;
951 for (
const auto &row : requested_rows)
954 while (row >= start_index[cpu_rank + 1])
961 rows_data[cpu_rank].push_back(row);
966 const auto rows_data_received =
973 for (
const auto &data : rows_data_received)
975 for (
const auto &row : data.second)
984 send_data[data.first].push_back(row);
985 send_data[data.first].push_back(rlen);
987 send_data[data.first].push_back(
993 const auto received_data =
997 for (
const auto &data : received_data)
999 const auto &recv_buf = data.second;
1000 auto ptr = recv_buf.begin();
1001 const auto end = recv_buf.end();
1004 const auto row = *(ptr++);
1007 const auto n_entries = *(ptr++);
1029 const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
1030 const MPI_Comm & mpi_comm,
1034 std::vector<DynamicSparsityPattern::size_type> start_index(
1035 rows_per_cpu.size() + 1);
1038 start_index[i + 1] = start_index[i] + rows_per_cpu[i];
1040 IndexSet owned(start_index.back());
1041 owned.
add_range(start_index[myid], start_index[myid] + rows_per_cpu[myid]);
1043 IndexSet myrange_non_owned(myrange);
1047 std::map<unsigned int, std::vector<DynamicSparsityPattern::size_type>>;
1049 map_vec_t send_data;
1052 unsigned int dest_cpu = 0;
1053 for (
const auto &row : myrange_non_owned)
1056 while (row >= start_index[dest_cpu + 1])
1069 send_data[dest_cpu].push_back(row);
1070 send_data[dest_cpu].push_back(rlen);
1075 send_data[dest_cpu].push_back(column);
1083 for (
const auto &data : receive_data)
1085 const auto &recv_buf = data.second;
1086 auto ptr = recv_buf.begin();
1087 const auto end = recv_buf.end();
1090 const auto row = *(ptr++);
1092 const auto n_entries = *(ptr++);
1104 const std::vector<IndexSet> &owned_set_per_cpu,
1105 const MPI_Comm & mpi_comm,
1112 std::vector<BlockDynamicSparsityPattern::size_type>>;
1113 map_vec_t send_data;
1116 unsigned int dest_cpu = 0;
1121 row_idx < n_local_rel_rows;
1130 while (!owned_set_per_cpu[dest_cpu].is_element(row))
1133 if (dest_cpu == owned_set_per_cpu.size())
1138 if (dest_cpu == myid)
1148 std::vector<BlockDynamicSparsityPattern::size_type> &dst =
1149 send_data[dest_cpu];
1151 dst.push_back(rlen);
1158 dst.push_back(column);
1163 unsigned int num_receive = 0;
1165 std::vector<unsigned int> send_to;
1166 send_to.reserve(send_data.size());
1167 for (
const auto &sparsity_line : send_data)
1168 send_to.push_back(sparsity_line.first);
1175 std::vector<MPI_Request> requests(send_data.size());
1180 unsigned int idx = 0;
1181 for (
const auto &sparsity_line : send_data)
1184 MPI_Isend(DEAL_II_MPI_CONST_CAST(sparsity_line.second.data()),
1185 sparsity_line.second.size(),
1186 DEAL_II_DOF_INDEX_MPI_TYPE,
1187 sparsity_line.first,
1197 std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
1198 for (
unsigned int index = 0; index < num_receive; ++index)
1202 int ierr = MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, mpi_comm, &status);
1206 ierr = MPI_Get_count(&status, DEAL_II_DOF_INDEX_MPI_TYPE, &len);
1208 recv_buf.resize(len);
1209 ierr = MPI_Recv(recv_buf.data(),
1211 DEAL_II_DOF_INDEX_MPI_TYPE,
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())
1242 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
1249 DEAL_II_NAMESPACE_CLOSE
const types::global_dof_index invalid_size_type
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_unique_and_sorted=false)
size_type column_number(const size_type row, const unsigned int index) const
#define AssertDimension(dim1, dim2)
void clear_row(const size_type row)
size_type nth_index_in_set(const unsigned int local_index) const
size_type column_number(const size_type row, const size_type index) const
void add(const size_type i, const size_type j)
static ::ExceptionBase & ExcMETISNotInstalled()
unsigned int compute_n_point_to_point_communications(const MPI_Comm &mpi_comm, const std::vector< unsigned int > &destinations)
#define AssertThrow(cond, exc)
static ::ExceptionBase & ExcNotCompressed()
static ::ExceptionBase & ExcMessage(std::string arg1)
static ::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
void add(const size_type i, const size_type j)
void subtract_set(const IndexSet &other)
SparsityPatternBase::size_type size_type
#define Assert(cond, exc)
static ::ExceptionBase & ExcInvalidArraySize(int arg1, int arg2)
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
const IndexSet & row_index_set() const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
std::vector< unsigned int > invert_permutation(const std::vector< unsigned int > &permutation)
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
std::size_t n_nonzero_elements() const
bool exists(const size_type i, const size_type j) const
void add_range(const size_type begin, const size_type end)
static ::ExceptionBase & ExcNotQuadratic()
unsigned int global_dof_index
types::global_dof_index size_type
static ::ExceptionBase & ExcZOLTANNotInstalled()
#define AssertThrowMPI(error_code)
bool is_compressed() const
size_type row_length(const size_type row) const
unsigned int row_length(const size_type row) const
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
static ::ExceptionBase & ExcNotImplemented()
const types::global_dof_index invalid_dof_index
types::global_dof_index size_type
std::map< unsigned int, T > some_to_some(const MPI_Comm &comm, const std::map< unsigned int, T > &objects_to_send)
unsigned int row_length(const size_type row) const
size_type n_elements() const
static ::ExceptionBase & ExcMETISError(int arg1)
static ::ExceptionBase & ExcInternalError()