17 #include <deal.II/base/exceptions.h> 18 #include <deal.II/lac/exceptions.h> 19 #include <deal.II/lac/sparsity_pattern.h> 20 #include <deal.II/lac/sparsity_tools.h> 25 #include <deal.II/base/std_cxx14/memory.h> 27 #ifdef DEAL_II_WITH_MPI 28 #include <deal.II/base/utilities.h> 29 #include <deal.II/base/mpi.h> 30 #include <deal.II/lac/dynamic_sparsity_pattern.h> 31 #include <deal.II/lac/block_sparsity_pattern.h> 34 #ifdef DEAL_II_WITH_METIS 41 #ifdef DEAL_II_TRILINOS_WITH_ZOLTAN 42 #include <zoltan_cpp.h> 48 DEAL_II_NAMESPACE_OPEN
56 const std::vector<unsigned int> &cell_weights,
57 const unsigned int n_partitions,
58 std::vector<unsigned int> &partition_indices)
62 #ifndef DEAL_II_WITH_METIS 63 (void) sparsity_pattern;
66 (void) partition_indices;
76 n =
static_cast<signed int>(sparsity_pattern.
n_rows()),
78 nparts = static_cast<int>(n_partitions),
87 nparts = std::min(n, nparts);
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;
102 col < sparsity_pattern.
end(row); ++col)
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 int_cell_weights.resize(cell_weights.size());
116 std::copy (cell_weights.begin(),
118 int_cell_weights.begin());
122 idx_t *
const p_int_cell_weights = (cell_weights.size() > 0 ? int_cell_weights.data() :
nullptr);
132 ierr = METIS_PartGraphRecursive(&n, &ncon, int_rowstart.data(), int_colnums.data(),
133 p_int_cell_weights,
nullptr,
nullptr,
134 &nparts,
nullptr,
nullptr,options,
135 &dummy,int_partition_indices.data());
139 ierr = METIS_PartGraphKway(&n, &ncon, int_rowstart.data(), int_colnums.data(),
140 p_int_cell_weights,
nullptr,
nullptr,
141 &nparts,
nullptr,
nullptr,options,
142 &dummy,int_partition_indices.data());
149 std::copy (int_partition_indices.begin(),
150 int_partition_indices.end(),
151 partition_indices.begin());
157 #ifdef DEAL_II_TRILINOS_WITH_ZOLTAN 159 int get_number_of_objects(
void *data,
int *ierr)
169 void get_object_list(
void *data,
int ,
int ,
170 ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
171 int ,
float * ,
int *ierr)
180 auto n_dofs = graph->
n_rows();
182 for (
unsigned int i=0; i < n_dofs; i++)
190 void get_num_edges_list(
void *data,
int ,
int ,
192 ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR ,
193 int *numEdges,
int *ierr)
201 for (
int i=0; i<num_obj; ++i)
204 numEdges[i] = graph->
row_length(globalID[i])-1;
212 void get_edge_list(
void *data,
int ,
int ,
213 int num_obj, ZOLTAN_ID_PTR , ZOLTAN_ID_PTR ,
215 ZOLTAN_ID_PTR nborGID,
int *nborProc,
216 int ,
float * ,
int *ierr)
221 ZOLTAN_ID_PTR nextNborGID = nborGID;
222 int *nextNborProc = nborProc;
229 col < graph->
end(i); ++col )
231 if ( i != col->column() )
236 *nextNborGID++ = col->column();
245 const std::vector<unsigned int> &cell_weights,
246 const unsigned int n_partitions,
247 std::vector<unsigned int> &partition_indices)
251 #ifndef DEAL_II_TRILINOS_WITH_ZOLTAN 252 (void) sparsity_pattern;
255 (void) partition_indices;
259 Assert(cell_weights.size() == 0,
260 ExcMessage(
"The cell weighting functionality for Zoltan has not yet been implemented."));
264 std::unique_ptr<Zoltan> zz = std_cxx14::make_unique<Zoltan>(MPI_COMM_SELF);
268 zz->Set_Param(
"DEBUG_LEVEL",
"0" );
269 zz->Set_Param(
"LB_METHOD",
"GRAPH" );
270 zz->Set_Param(
"NUM_LOCAL_PARTS", std::to_string(n_partitions) );
285 zz->Set_Param(
"PHG_EDGE_SIZE_THRESHOLD",
"0.5" );
292 zz->Set_Num_Obj_Fn(get_number_of_objects, &graph);
293 zz->Set_Obj_List_Fn(get_object_list, &graph);
294 zz->Set_Num_Edges_Multi_Fn(get_num_edges_list, &graph);
295 zz->Set_Edge_List_Multi_Fn(get_edge_list, &graph);
299 int num_gid_entries=1;
300 int num_lid_entries=1;
302 ZOLTAN_ID_PTR import_global_ids=
nullptr;
303 ZOLTAN_ID_PTR import_local_ids=
nullptr;
304 int *import_procs=
nullptr;
305 int *import_to_part=
nullptr;
307 ZOLTAN_ID_PTR export_global_ids=
nullptr;
308 ZOLTAN_ID_PTR export_local_ids=
nullptr;
309 int *export_procs=
nullptr;
310 int *export_to_part=
nullptr;
313 const int rc = zz->LB_Partition (changes,
333 std::fill(partition_indices.begin(), partition_indices.end(), 0);
336 for (
int i=0; i < num_export; i++)
337 partition_indices[export_local_ids[i]] = export_to_part[i];
344 const unsigned int n_partitions,
345 std::vector<unsigned int> &partition_indices,
349 std::vector<unsigned int> cell_weights;
352 partition(sparsity_pattern, cell_weights, n_partitions,
353 partition_indices, partitioner);
358 const std::vector<unsigned int> &cell_weights,
359 const unsigned int n_partitions,
360 std::vector<unsigned int> &partition_indices,
370 Assert (partition_indices.size() == sparsity_pattern.
n_rows(),
372 sparsity_pattern.
n_rows()));
375 if (n_partitions == 1 || (sparsity_pattern.
n_rows()==1))
377 std::fill_n (partition_indices.begin(), partition_indices.size(), 0U);
382 partition_metis(sparsity_pattern, cell_weights, n_partitions, partition_indices);
384 partition_zoltan(sparsity_pattern, cell_weights, n_partitions, partition_indices);
391 std::vector<unsigned int> &color_indices)
395 #ifndef DEAL_II_TRILINOS_WITH_ZOLTAN 396 (void) sparsity_pattern;
397 (void) color_indices;
402 std::unique_ptr<Zoltan> zz = std_cxx14::make_unique<Zoltan> (MPI_COMM_SELF);
406 zz->Set_Param (
"DEBUG_LEVEL",
"0" );
407 zz->Set_Param (
"COLORING_PROBLEM",
"DISTANCE-1");
408 zz->Set_Param (
"NUM_GID_ENTRIES",
"1");
409 zz->Set_Param (
"NUM_LID_ENTRIES",
"1");
410 zz->Set_Param (
"OBJ_WEIGHT_DIM",
"0");
411 zz->Set_Param (
"RECOLORING_NUM_OF_ITERATIONS",
"0");
418 zz->Set_Num_Obj_Fn (get_number_of_objects, &graph);
419 zz->Set_Obj_List_Fn (get_object_list, &graph);
420 zz->Set_Num_Edges_Multi_Fn (get_num_edges_list, &graph);
421 zz->Set_Edge_List_Multi_Fn (get_edge_list, &graph);
424 int num_gid_entries=1;
425 const int num_objects = graph.
n_rows();
428 std::vector<ZOLTAN_ID_TYPE> global_ids (num_objects);
429 std::vector<int> color_exp (num_objects);
432 for (
int i=0; i < num_objects; i++)
436 int rc = zz->Color (num_gid_entries,
447 color_indices.resize(num_objects);
448 Assert (color_exp.size() == color_indices.size(),
451 std::copy (color_exp.begin(), color_exp.end(), color_indices.begin());
453 unsigned int n_colors = *(std::max_element (color_indices.begin(),
454 color_indices.end()));
469 const std::vector<DynamicSparsityPattern::size_type> &new_indices)
477 if (sparsity.
row_length(row) < min_coordination)
480 starting_point = row;
504 return starting_point;
512 std::vector<DynamicSparsityPattern::size_type> &new_indices,
513 const std::vector<DynamicSparsityPattern::size_type> &starting_indices)
520 ExcMessage (
"You can't specify more starting indices than there are rows"));
523 ExcMessage(
"Only valid for sparsity patterns which store all rows."));
526 ExcMessage (
"Invalid starting index: All starting indices need " 527 "to be between zero and the number of rows in the " 528 "sparsity pattern."));
532 std::vector<DynamicSparsityPattern::size_type> last_round_dofs (starting_indices);
535 std::fill (new_indices.begin(), new_indices.end(),
539 if (last_round_dofs.empty())
541 .push_back (internal::find_unnumbered_starting_index (sparsity,
549 new_indices[last_round_dofs[i]] = next_free_number++;
555 std::vector<DynamicSparsityPattern::size_type> next_round_dofs;
560 j<sparsity.
end(last_round_dofs[i]); ++j)
561 next_round_dofs.push_back (j->column());
564 std::sort (next_round_dofs.begin(), next_round_dofs.end());
567 std::vector<DynamicSparsityPattern::size_type>::iterator end_sorted;
568 end_sorted = std::unique (next_round_dofs.begin(), next_round_dofs.end());
569 next_round_dofs.erase (end_sorted, next_round_dofs.end());
572 for (
int s=next_round_dofs.size()-1; s>=0; --s)
574 next_round_dofs.erase (next_round_dofs.begin() + s);
580 if (next_round_dofs.empty())
582 if (std::find (new_indices.begin(), new_indices.end(),
594 Assert (starting_indices.empty(),
595 ExcMessage (
"The input graph appears to have more than one " 596 "component, but as stated in the documentation " 597 "we only want to reorder such graphs if no " 598 "starting indices are given. The function was " 599 "called with starting indices, however."))
602 .push_back (internal::find_unnumbered_starting_index (sparsity,
610 std::multimap<DynamicSparsityPattern::size_type, int> dofs_by_coordination;
613 for (std::vector<DynamicSparsityPattern::size_type>::iterator s=next_round_dofs.begin();
614 s!=next_round_dofs.end(); ++s)
619 const std::pair<const DynamicSparsityPattern::size_type, int> new_entry (coordination, *s);
620 dofs_by_coordination.insert (new_entry);
624 std::multimap<DynamicSparsityPattern::size_type, int>::iterator i;
625 for (i = dofs_by_coordination.begin(); i!=dofs_by_coordination.end(); ++i)
626 new_indices[i->second] = next_free_number++;
629 last_round_dofs = next_round_dofs;
639 (next_free_number == sparsity.
n_rows()),
649 std::vector<DynamicSparsityPattern::size_type> &renumbering)
655 ExcMessage(
"Only valid for sparsity patterns which store all rows."));
657 std::vector<types::global_dof_index> touched_nodes(connectivity.
n_rows(),
659 std::vector<unsigned int> row_lengths(connectivity.
n_rows());
660 std::set<types::global_dof_index> current_neighbors;
661 std::vector<std::vector<types::global_dof_index> > groups;
671 row_lengths[row] = connectivity.
row_length(row);
674 std::vector<unsigned int> n_remaining_neighbors(row_lengths);
687 std::pair<types::global_dof_index,types::global_dof_index> min_neighbors
691 if (row_lengths[i] < min_neighbors.second)
693 min_neighbors = std::make_pair(i, n_remaining_neighbors[i]);
694 if (n_remaining_neighbors[i] <= 1)
702 current_neighbors.clear();
703 current_neighbors.insert(min_neighbors.first);
704 while (!current_neighbors.empty())
710 for (std::set<types::global_dof_index>::iterator it=current_neighbors.begin();
711 it != current_neighbors.end(); ++it)
715 if (n_remaining_neighbors[*it] < min_neighbors.second)
716 min_neighbors = std::make_pair(*it, n_remaining_neighbors[*it]);
723 for (std::set<types::global_dof_index>::iterator it=current_neighbors.begin();
724 it != current_neighbors.end(); ++it)
725 if (n_remaining_neighbors[*it] == best_row_length)
726 if (row_lengths[*it] > min_neighbors.second)
727 min_neighbors = std::make_pair(*it, row_lengths[*it]);
731 groups.emplace_back();
732 std::vector<types::global_dof_index> &next_group = groups.back();
734 next_group.push_back(min_neighbors.first);
735 touched_nodes[min_neighbors.first] = groups.size()-1;
737 = connectivity.
begin(min_neighbors.first);
738 it != connectivity.
end(min_neighbors.first); ++it)
741 next_group.push_back(it->column());
742 touched_nodes[it->column()] = groups.size()-1;
750 for (
unsigned int i=0; i<next_group.size(); ++i)
753 = connectivity.
begin(next_group[i]);
754 it != connectivity.
end(next_group[i]); ++it)
757 current_neighbors.insert(it->column());
758 n_remaining_neighbors[it->column()]--;
760 current_neighbors.erase(next_group[i]);
771 if (groups.size() < connectivity.
n_rows())
779 = connectivity.
begin(groups[i][col]);
780 it != connectivity.
end(groups[i][col]); ++it)
781 connectivity_next.
add(i, touched_nodes[it->column()]);
784 std::vector<types::global_dof_index> renumbering_next(groups.size());
791 renumbering[count] = groups[renumbering_next[i]][col];
799 renumbering[count] = groups[i][col];
806 std::vector<DynamicSparsityPattern::size_type> &renumbering)
811 internal::reorder_hierarchical(connectivity, renumbering);
817 #ifdef DEAL_II_WITH_MPI 820 const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
821 const MPI_Comm &mpi_comm,
825 std::vector<DynamicSparsityPattern::size_type> start_index(rows_per_cpu.size()+1);
828 start_index[i+1]=start_index[i]+rows_per_cpu[i];
831 std::vector<DynamicSparsityPattern::size_type> >
837 unsigned int dest_cpu=0;
845 while (row>=start_index[dest_cpu+1])
851 row_idx+=rows_per_cpu[myid]-1;
862 std::vector<DynamicSparsityPattern::size_type> &dst = send_data[dest_cpu];
870 dst.push_back(column);
876 unsigned int num_receive=0;
878 std::vector<unsigned int> send_to;
879 send_to.reserve(send_data.size());
880 for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it)
881 send_to.push_back(it->first);
888 std::vector<MPI_Request> requests(send_data.size());
894 for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it, ++idx)
896 const int ierr = MPI_Isend(&(it->second[0]),
898 DEAL_II_DOF_INDEX_MPI_TYPE,
909 std::vector<DynamicSparsityPattern::size_type> recv_buf;
910 for (
unsigned int index=0; index<num_receive; ++index)
914 int ierr = MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, mpi_comm, &status);
918 ierr = MPI_Get_count(&status, DEAL_II_DOF_INDEX_MPI_TYPE, &len);
920 recv_buf.resize(len);
921 ierr = MPI_Recv(recv_buf.data(), len, DEAL_II_DOF_INDEX_MPI_TYPE, status.MPI_SOURCE,
922 status.MPI_TAG, mpi_comm, &status);
925 std::vector<DynamicSparsityPattern::size_type>::const_iterator ptr = recv_buf.begin();
926 std::vector<DynamicSparsityPattern::size_type>::const_iterator end = recv_buf.end();
932 for (
unsigned int c=0; c<num; ++c)
946 const int ierr = MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
953 const std::vector<IndexSet> &owned_set_per_cpu,
954 const MPI_Comm &mpi_comm,
960 std::vector<BlockDynamicSparsityPattern::size_type> >
965 unsigned int dest_cpu=0;
975 while (!owned_set_per_cpu[dest_cpu].is_element(row))
978 if (dest_cpu==owned_set_per_cpu.size())
993 std::vector<BlockDynamicSparsityPattern::size_type> &dst = send_data[dest_cpu];
1001 dst.push_back(column);
1007 unsigned int num_receive=0;
1009 std::vector<unsigned int> send_to;
1010 send_to.reserve(send_data.size());
1011 for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it)
1012 send_to.push_back(it->first);
1019 std::vector<MPI_Request> requests(send_data.size());
1025 for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it, ++idx)
1027 const int ierr = MPI_Isend(&(it->second[0]),
1029 DEAL_II_DOF_INDEX_MPI_TYPE,
1040 std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
1041 for (
unsigned int index=0; index<num_receive; ++index)
1045 int ierr = MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, mpi_comm, &status);
1049 ierr = MPI_Get_count(&status, DEAL_II_DOF_INDEX_MPI_TYPE, &len);
1051 recv_buf.resize(len);
1052 ierr = MPI_Recv(recv_buf.data(), len, DEAL_II_DOF_INDEX_MPI_TYPE, status.MPI_SOURCE,
1053 status.MPI_TAG, mpi_comm, &status);
1056 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator ptr = recv_buf.begin();
1057 std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator end = recv_buf.end();
1063 for (
unsigned int c=0; c<num; ++c)
1075 if (requests.size())
1077 const int ierr = MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
1084 DEAL_II_NAMESPACE_CLOSE
const types::global_dof_index invalid_size_type
size_type column_number(const size_type row, const unsigned int index) const
#define AssertDimension(dim1, dim2)
std::size_t n_nonzero_elements() const
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()
bool exists(const size_type i, const size_type j) const
#define AssertThrow(cond, exc)
bool is_compressed() const
types::global_dof_index size_type
types::global_dof_index size_type
static ::ExceptionBase & ExcNotCompressed()
static ::ExceptionBase & ExcMessage(std::string arg1)
static ::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
void add(const size_type i, const size_type j)
unsigned int global_dof_index
#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)
static ::ExceptionBase & ExcNotQuadratic()
static ::ExceptionBase & ExcZOLTANNotInstalled()
types::global_dof_index size_type
#define AssertThrowMPI(error_code)
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)
const types::global_dof_index invalid_dof_index
std::vector< unsigned int > compute_point_to_point_communication_pattern(const MPI_Comm &mpi_comm, const std::vector< unsigned int > &destinations)
size_type n_elements() const
static ::ExceptionBase & ExcMETISError(int arg1)
unsigned int row_length(const size_type row) const
static ::ExceptionBase & ExcInternalError()