Reference documentation for deal.II version 8.4.2
sparsity_tools.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
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>
21 
22 #include <algorithm>
23 #include <functional>
24 #include <set>
25 
26 #ifdef DEAL_II_WITH_MPI
27 #include <deal.II/base/utilities.h>
28 #include <deal.II/lac/dynamic_sparsity_pattern.h>
29 #include <deal.II/lac/block_sparsity_pattern.h>
30 #endif
31 
32 #ifdef DEAL_II_WITH_METIS
33 DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
34 extern "C"
35 {
36 #include <metis.h>
37 }
39 #endif
40 
41 
42 DEAL_II_NAMESPACE_OPEN
43 
44 namespace SparsityTools
45 {
46 
47  void partition (const SparsityPattern &sparsity_pattern,
48  const unsigned int n_partitions,
49  std::vector<unsigned int> &partition_indices)
50  {
51  Assert (sparsity_pattern.n_rows()==sparsity_pattern.n_cols(),
52  ExcNotQuadratic());
53  Assert (sparsity_pattern.is_compressed(),
54  SparsityPattern::ExcNotCompressed());
55 
56  Assert (n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
57  Assert (partition_indices.size() == sparsity_pattern.n_rows(),
58  ExcInvalidArraySize (partition_indices.size(),
59  sparsity_pattern.n_rows()));
60 
61  // check for an easy return
62  if (n_partitions == 1 || (sparsity_pattern.n_rows()==1))
63  {
64  std::fill_n (partition_indices.begin(), partition_indices.size(), 0U);
65  return;
66  }
67 
68  // Make sure that METIS is actually
69  // installed and detected
70 #ifndef DEAL_II_WITH_METIS
71  (void)sparsity_pattern;
72  AssertThrow (false, ExcMETISNotInstalled());
73 #else
74 
75  // generate the data structures for
76  // METIS. Note that this is particularly
77  // simple, since METIS wants exactly our
78  // compressed row storage format. we only
79  // have to set up a few auxiliary arrays
80  idx_t
81  n = static_cast<signed int>(sparsity_pattern.n_rows()),
82  ncon = 1, // number of balancing constraints (should be >0)
83  nparts = static_cast<int>(n_partitions), // number of subdomains to create
84  dummy; // the numbers of edges cut by the
85  // resulting partition
86 
87  // We can not partition n items into more than n parts. METIS will
88  // generate non-sensical output (everything is owned by a single process)
89  // and complain with a message (but won't return an error code!):
90  // ***Cannot bisect a graph with 0 vertices!
91  // ***You are trying to partition a graph into too many parts!
92  nparts = std::min(n, nparts);
93 
94  // use default options for METIS
95  idx_t options[METIS_NOPTIONS];
96  METIS_SetDefaultOptions (options);
97 
98  // one more nuisance: we have to copy our own data to arrays that store
99  // signed integers :-(
100  std::vector<idx_t> int_rowstart(1);
101  int_rowstart.reserve(sparsity_pattern.n_rows()+1);
102  std::vector<idx_t> int_colnums;
103  int_colnums.reserve(sparsity_pattern.n_nonzero_elements());
104  for (SparsityPattern::size_type row=0; row<sparsity_pattern.n_rows(); ++row)
105  {
106  for (SparsityPattern::iterator col=sparsity_pattern.begin(row);
107  col < sparsity_pattern.end(row); ++col)
108  int_colnums.push_back(col->column());
109  int_rowstart.push_back(int_colnums.size());
110  }
111 
112  std::vector<idx_t> int_partition_indices (sparsity_pattern.n_rows());
113 
114  // Make use of METIS' error code.
115  int ierr;
116 
117  // Select which type of partitioning to create
118 
119  // Use recursive if the number of partitions is less than or equal to 8
120  if (nparts <= 8)
121  ierr = METIS_PartGraphRecursive(&n, &ncon, &int_rowstart[0], &int_colnums[0],
122  NULL, NULL, NULL,
123  &nparts,NULL,NULL,&options[0],
124  &dummy,&int_partition_indices[0]);
125 
126  // Otherwise use kway
127  else
128  ierr = METIS_PartGraphKway(&n, &ncon, &int_rowstart[0], &int_colnums[0],
129  NULL, NULL, NULL,
130  &nparts,NULL,NULL,&options[0],
131  &dummy,&int_partition_indices[0]);
132 
133  // If metis returns normally, an error code METIS_OK=1 is returned from
134  // the above functions (see metish.h)
135  AssertThrow (ierr == 1, ExcMETISError (ierr));
136 
137  // now copy back generated indices into the output array
138  std::copy (int_partition_indices.begin(),
139  int_partition_indices.end(),
140  partition_indices.begin());
141 #endif
142  }
143 
144 
145  namespace internal
146  {
153  find_unnumbered_starting_index (const DynamicSparsityPattern &sparsity,
154  const std::vector<DynamicSparsityPattern::size_type> &new_indices)
155  {
157  DynamicSparsityPattern::size_type min_coordination = sparsity.n_rows();
158  for (DynamicSparsityPattern::size_type row=0; row<sparsity.n_rows(); ++row)
159  // look over all as-yet unnumbered indices
160  if (new_indices[row] == numbers::invalid_size_type)
161  {
162  if (sparsity.row_length(row) < min_coordination)
163  {
164  min_coordination = sparsity.row_length(row);
165  starting_point = row;
166  }
167  }
168 
169  // now we still have to care for the case that no unnumbered dof has a
170  // coordination number less than sparsity.n_rows(). this rather exotic
171  // case only happens if we only have one cell, as far as I can see,
172  // but there may be others as well.
173  //
174  // if that should be the case, we can chose an arbitrary dof as
175  // starting point, e.g. the first unnumbered one
176  if (starting_point == numbers::invalid_size_type)
177  {
178  for (DynamicSparsityPattern::size_type i=0; i<new_indices.size(); ++i)
179  if (new_indices[i] == numbers::invalid_size_type)
180  {
181  starting_point = i;
182  break;
183  }
184 
185  Assert (starting_point != numbers::invalid_size_type,
186  ExcInternalError());
187  }
188 
189  return starting_point;
190  }
191  }
192 
193 
194 
195  void
197  std::vector<DynamicSparsityPattern::size_type> &new_indices,
198  const std::vector<DynamicSparsityPattern::size_type> &starting_indices)
199  {
200  Assert (sparsity.n_rows() == sparsity.n_cols(),
201  ExcDimensionMismatch (sparsity.n_rows(), sparsity.n_cols()));
202  Assert (sparsity.n_rows() == new_indices.size(),
203  ExcDimensionMismatch (sparsity.n_rows(), new_indices.size()));
204  Assert (starting_indices.size() <= sparsity.n_rows(),
205  ExcMessage ("You can't specify more starting indices than there are rows"));
206  Assert (sparsity.row_index_set().size() == 0 ||
207  sparsity.row_index_set().size() == sparsity.n_rows(),
208  ExcMessage("Only valid for sparsity patterns which store all rows."));
209  for (SparsityPattern::size_type i=0; i<starting_indices.size(); ++i)
210  Assert (starting_indices[i] < sparsity.n_rows(),
211  ExcMessage ("Invalid starting index"));
212 
213  // store the indices of the dofs renumbered in the last round. Default to
214  // starting points
215  std::vector<DynamicSparsityPattern::size_type> last_round_dofs (starting_indices);
216 
217  // initialize the new_indices array with invalid values
218  std::fill (new_indices.begin(), new_indices.end(),
220 
221  // delete disallowed elements
222  for (DynamicSparsityPattern::size_type i=0; i<last_round_dofs.size(); ++i)
223  if ((last_round_dofs[i]==numbers::invalid_size_type) ||
224  (last_round_dofs[i]>=sparsity.n_rows()))
225  last_round_dofs[i] = numbers::invalid_size_type;
226 
227  std::remove_if (last_round_dofs.begin(), last_round_dofs.end(),
228  std::bind2nd(std::equal_to<DynamicSparsityPattern::size_type>(),
230 
231  // now if no valid points remain: find dof with lowest coordination number
232  if (last_round_dofs.empty())
233  last_round_dofs
234  .push_back (internal::find_unnumbered_starting_index (sparsity,
235  new_indices));
236 
237  // store next free dof index
238  DynamicSparsityPattern::size_type next_free_number = 0;
239 
240  // enumerate the first round dofs
241  for (DynamicSparsityPattern::size_type i=0; i!=last_round_dofs.size(); ++i)
242  new_indices[last_round_dofs[i]] = next_free_number++;
243 
244  // now do as many steps as needed to renumber all dofs
245  while (true)
246  {
247  // store the indices of the dofs to be renumbered in the next round
248  std::vector<DynamicSparsityPattern::size_type> next_round_dofs;
249 
250  // find all neighbors of the dofs numbered in the last round
251  for (DynamicSparsityPattern::size_type i=0; i<last_round_dofs.size(); ++i)
252  for (DynamicSparsityPattern::iterator j=sparsity.begin(last_round_dofs[i]);
253  j<sparsity.end(last_round_dofs[i]); ++j)
254  next_round_dofs.push_back (j->column());
255 
256  // sort dof numbers
257  std::sort (next_round_dofs.begin(), next_round_dofs.end());
258 
259  // delete multiple entries
260  std::vector<DynamicSparsityPattern::size_type>::iterator end_sorted;
261  end_sorted = std::unique (next_round_dofs.begin(), next_round_dofs.end());
262  next_round_dofs.erase (end_sorted, next_round_dofs.end());
263 
264  // eliminate dofs which are already numbered
265  for (int s=next_round_dofs.size()-1; s>=0; --s)
266  if (new_indices[next_round_dofs[s]] != numbers::invalid_size_type)
267  next_round_dofs.erase (next_round_dofs.begin() + s);
268 
269  // check whether there are any new dofs in the list. if there are
270  // none, then we have completely numbered the current component of the
271  // graph. check if there are as yet unnumbered components of the graph
272  // that we would then have to do next
273  if (next_round_dofs.empty())
274  {
275  if (std::find (new_indices.begin(), new_indices.end(),
277  ==
278  new_indices.end())
279  // no unnumbered indices, so we can leave now
280  break;
281 
282  // otherwise find a valid starting point for the next component of
283  // the graph and continue with numbering that one. we only do so
284  // if no starting indices were provided by the user (see the
285  // documentation of this function) so produce an error if we got
286  // here and starting indices were given
287  Assert (starting_indices.empty(),
288  ExcMessage ("The input graph appears to have more than one "
289  "component, but as stated in the documentation "
290  "we only want to reorder such graphs if no "
291  "starting indices are given. The function was "
292  "called with starting indices, however."))
293 
294  next_round_dofs
295  .push_back (internal::find_unnumbered_starting_index (sparsity,
296  new_indices));
297  }
298 
299 
300 
301  // store for each coordination number the dofs with these coordination
302  // number
303  std::multimap<DynamicSparsityPattern::size_type, int> dofs_by_coordination;
304 
305  // find coordination number for each of these dofs
306  for (std::vector<DynamicSparsityPattern::size_type>::iterator s=next_round_dofs.begin();
307  s!=next_round_dofs.end(); ++s)
308  {
309  const DynamicSparsityPattern::size_type coordination = sparsity.row_length(*s);
310 
311  // insert this dof at its coordination number
312  const std::pair<const DynamicSparsityPattern::size_type, int> new_entry (coordination, *s);
313  dofs_by_coordination.insert (new_entry);
314  }
315 
316  // assign new DoF numbers to the elements of the present front:
317  std::multimap<DynamicSparsityPattern::size_type, int>::iterator i;
318  for (i = dofs_by_coordination.begin(); i!=dofs_by_coordination.end(); ++i)
319  new_indices[i->second] = next_free_number++;
320 
321  // after that: copy this round's dofs for the next round
322  last_round_dofs = next_round_dofs;
323  }
324 
325  // test for all indices numbered. this mostly tests whether the
326  // front-marching-algorithm (which Cuthill-McKee actually is) has reached
327  // all points.
328  Assert ((std::find (new_indices.begin(), new_indices.end(), numbers::invalid_size_type)
329  ==
330  new_indices.end())
331  &&
332  (next_free_number == sparsity.n_rows()),
333  ExcInternalError());
334  }
335 
336 
337 
338  void
340  std::vector<SparsityPattern::size_type> &new_indices,
341  const std::vector<SparsityPattern::size_type> &starting_indices)
342  {
343  DynamicSparsityPattern dsp(sparsity.n_rows(), sparsity.n_cols());
344  for (unsigned int row=0; row<sparsity.n_rows(); ++row)
345  {
346  for (SparsityPattern::iterator it=sparsity.begin(row); it!=sparsity.end(row)
347  && it->is_valid_entry() ; ++it)
348  dsp.add(row, it->column());
349  }
350  reorder_Cuthill_McKee(dsp, new_indices, starting_indices);
351  }
352 
353 
354 
355  namespace internal
356  {
357  void
358  reorder_hierarchical (const DynamicSparsityPattern &connectivity,
359  std::vector<DynamicSparsityPattern::size_type> &renumbering)
360  {
361  AssertDimension (connectivity.n_rows(), connectivity.n_cols());
362  AssertDimension (connectivity.n_rows(), renumbering.size());
363  Assert (connectivity.row_index_set().size() == 0 ||
364  connectivity.row_index_set().size() == connectivity.n_rows(),
365  ExcMessage("Only valid for sparsity patterns which store all rows."));
366 
367  std::vector<types::global_dof_index> touched_nodes(connectivity.n_rows(),
369  std::vector<unsigned int> row_lengths(connectivity.n_rows());
370  std::set<types::global_dof_index> current_neighbors;
371  std::vector<std::vector<types::global_dof_index> > groups;
372 
373  // First collect the number of neighbors for each node. We use this
374  // field to find next nodes with the minimum number of non-touched
375  // neighbors in the field n_remaining_neighbors, so we will count down
376  // on this field. We also cache the row lengths because we need this
377  // data frequently and getting it from the sparsity pattern is more
378  // expensive.
379  for (types::global_dof_index row=0; row<connectivity.n_rows(); ++row)
380  {
381  row_lengths[row] = connectivity.row_length(row);
382  Assert(row_lengths[row] > 0, ExcInternalError());
383  }
384  std::vector<unsigned int> n_remaining_neighbors(row_lengths);
385 
386  // This outer loop is typically traversed only once, unless the global
387  // graph is not connected
388  while (true)
389  {
390  // Find cell with the minimal number of neighbors (typically a
391  // corner node when based on FEM meshes). If no cell is left, we are
392  // done. Together with the outer while loop, this loop can possibly
393  // be of quadratic complexity in the number of disconnected
394  // partitions, i.e. up to connectivity.n_rows() in the worst case,
395  // but that is not the usual use case of this loop and thus not
396  // optimized for.
397  std::pair<types::global_dof_index,types::global_dof_index> min_neighbors
399  for (types::global_dof_index i=0; i<touched_nodes.size(); ++i)
400  if (touched_nodes[i] == numbers::invalid_dof_index)
401  if (row_lengths[i] < min_neighbors.second)
402  {
403  min_neighbors = std::make_pair(i, n_remaining_neighbors[i]);
404  if (n_remaining_neighbors[i] <= 1)
405  break;
406  }
407  if (min_neighbors.first == numbers::invalid_dof_index)
408  break;
409 
410  Assert(min_neighbors.second > 0, ExcInternalError());
411 
412  current_neighbors.clear();
413  current_neighbors.insert(min_neighbors.first);
414  while (!current_neighbors.empty())
415  {
416  // Find node with minimum number of untouched neighbors among the
417  // next set of possible neighbors
418  min_neighbors = std::make_pair (numbers::invalid_dof_index,
420  for (std::set<types::global_dof_index>::iterator it=current_neighbors.begin();
421  it != current_neighbors.end(); ++it)
422  {
423  Assert (touched_nodes[*it] == numbers::invalid_dof_index,
424  ExcInternalError());
425  if (n_remaining_neighbors[*it] < min_neighbors.second)
426  min_neighbors = std::make_pair(*it, n_remaining_neighbors[*it]);
427  }
428 
429  // Among the set of nodes with the minimal number of neighbors,
430  // choose the one with the largest number of touched neighbors,
431  // i.e., the one with the largest row length
432  const types::global_dof_index best_row_length = min_neighbors.second;
433  for (std::set<types::global_dof_index>::iterator it=current_neighbors.begin();
434  it != current_neighbors.end(); ++it)
435  if (n_remaining_neighbors[*it] == best_row_length)
436  if (row_lengths[*it] > min_neighbors.second)
437  min_neighbors = std::make_pair(*it, row_lengths[*it]);
438 
439  // Add the pivot and all direct neighbors of the pivot node not
440  // yet touched to the list of new entries.
441  groups.push_back(std::vector<types::global_dof_index>());
442  std::vector<types::global_dof_index> &next_group = groups.back();
443 
444  next_group.push_back(min_neighbors.first);
445  touched_nodes[min_neighbors.first] = groups.size()-1;
447  = connectivity.begin(min_neighbors.first);
448  it != connectivity.end(min_neighbors.first); ++it)
449  if (touched_nodes[it->column()] == numbers::invalid_dof_index)
450  {
451  next_group.push_back(it->column());
452  touched_nodes[it->column()] = groups.size()-1;
453  }
454 
455  // Add all neighbors of the current list not yet touched to the
456  // set of possible next pivots. The added node is no longer a
457  // valid neighbor (here we assume symmetry of the
458  // connectivity). Delete the entries of the current list from
459  // the set of possible next pivots.
460  for (unsigned int i=0; i<next_group.size(); ++i)
461  {
463  = connectivity.begin(next_group[i]);
464  it != connectivity.end(next_group[i]); ++it)
465  {
466  if (touched_nodes[it->column()] == numbers::invalid_dof_index)
467  current_neighbors.insert(it->column());
468  n_remaining_neighbors[it->column()]--;
469  }
470  current_neighbors.erase(next_group[i]);
471  }
472  }
473  }
474 
475  // Sanity check: for all nodes, there should not be any neighbors left
476  for (types::global_dof_index row=0; row<connectivity.n_rows(); ++row)
477  Assert(n_remaining_neighbors[row] == 0, ExcInternalError());
478 
479  // If the number of groups is smaller than the number of nodes, we
480  // continue by recursively calling this method
481  if (groups.size() < connectivity.n_rows())
482  {
483  // Form the connectivity of the groups
484  DynamicSparsityPattern connectivity_next(groups.size(),
485  groups.size());
486  for (types::global_dof_index i=0; i<groups.size(); ++i)
487  for (types::global_dof_index col=0; col<groups[i].size(); ++col)
489  = connectivity.begin(groups[i][col]);
490  it != connectivity.end(groups[i][col]); ++it)
491  connectivity_next.add(i, touched_nodes[it->column()]);
492 
493  // Recursively call the reordering
494  std::vector<types::global_dof_index> renumbering_next(groups.size());
495  reorder_hierarchical(connectivity_next, renumbering_next);
496 
497  // Renumber the indices group by group according to the incoming
498  // ordering for the groups
499  for (types::global_dof_index i=0,count=0; i<groups.size(); ++i)
500  for (types::global_dof_index col=0; col<groups[renumbering_next[i]].size(); ++col, ++count)
501  renumbering[count] = groups[renumbering_next[i]][col];
502  }
503  else
504  {
505  // All groups should have size one and no more recursion is possible,
506  // so use the numbering of the groups
507  for (types::global_dof_index i=0,count=0; i<groups.size(); ++i)
508  for (types::global_dof_index col=0; col<groups[i].size(); ++col, ++count)
509  renumbering[count] = groups[i][col];
510  }
511  }
512  }
513 
514  void
516  std::vector<DynamicSparsityPattern::size_type> &renumbering)
517  {
518  // the internal renumbering keeps the numbering the wrong way around (but
519  // we cannot invert the numbering inside that method because it is used
520  // recursively), so invert it here
521  internal::reorder_hierarchical(connectivity, renumbering);
522  renumbering = Utilities::invert_permutation(renumbering);
523  }
524 
525 
526 
527 #ifdef DEAL_II_WITH_MPI
530  const std::vector<DynamicSparsityPattern::size_type> &rows_per_cpu,
531  const MPI_Comm &mpi_comm,
532  const IndexSet &myrange)
533  {
534  const unsigned int myid = Utilities::MPI::this_mpi_process(mpi_comm);
535  std::vector<DynamicSparsityPattern::size_type> start_index(rows_per_cpu.size()+1);
536  start_index[0]=0;
537  for (DynamicSparsityPattern::size_type i=0; i<rows_per_cpu.size(); ++i)
538  start_index[i+1]=start_index[i]+rows_per_cpu[i];
539 
540  typedef std::map<DynamicSparsityPattern::size_type,
541  std::vector<DynamicSparsityPattern::size_type> >
542  map_vec_t;
543 
544  map_vec_t send_data;
545 
546  {
547  unsigned int dest_cpu=0;
548 
549  DynamicSparsityPattern::size_type n_local_rel_rows = myrange.n_elements();
550  for (DynamicSparsityPattern::size_type row_idx=0; row_idx<n_local_rel_rows; ++row_idx)
551  {
552  DynamicSparsityPattern::size_type row=myrange.nth_index_in_set(row_idx);
553 
554  //calculate destination CPU
555  while (row>=start_index[dest_cpu+1])
556  ++dest_cpu;
557 
558  //skip myself
559  if (dest_cpu==myid)
560  {
561  row_idx+=rows_per_cpu[myid]-1;
562  continue;
563  }
564 
565  DynamicSparsityPattern::size_type rlen = dsp.row_length(row);
566 
567  //skip empty lines
568  if (!rlen)
569  continue;
570 
571  //save entries
572  std::vector<DynamicSparsityPattern::size_type> &dst = send_data[dest_cpu];
573 
574  dst.push_back(rlen); // number of entries
575  dst.push_back(row); // row index
576  for (DynamicSparsityPattern::size_type c=0; c<rlen; ++c)
577  {
578  //columns
579  DynamicSparsityPattern::size_type column = dsp.column_number(row, c);
580  dst.push_back(column);
581  }
582  }
583 
584  }
585 
586  unsigned int num_receive=0;
587  {
588  std::vector<unsigned int> send_to;
589  send_to.reserve(send_data.size());
590  for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it)
591  send_to.push_back(it->first);
592 
593  num_receive =
595  compute_point_to_point_communication_pattern(mpi_comm, send_to).size();
596  }
597 
598  std::vector<MPI_Request> requests(send_data.size());
599 
600 
601  // send data
602  {
603  unsigned int idx=0;
604  for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it, ++idx)
605  MPI_Isend(&(it->second[0]),
606  it->second.size(),
607  DEAL_II_DOF_INDEX_MPI_TYPE,
608  it->first,
609  124,
610  mpi_comm,
611  &requests[idx]);
612  }
613 
614  {
615  //receive
616  std::vector<DynamicSparsityPattern::size_type> recv_buf;
617  for (unsigned int index=0; index<num_receive; ++index)
618  {
619  MPI_Status status;
620  int len;
621  MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, mpi_comm, &status);
622  Assert (status.MPI_TAG==124, ExcInternalError());
623 
624  MPI_Get_count(&status, DEAL_II_DOF_INDEX_MPI_TYPE, &len);
625  recv_buf.resize(len);
626  MPI_Recv(&recv_buf[0], len, DEAL_II_DOF_INDEX_MPI_TYPE, status.MPI_SOURCE,
627  status.MPI_TAG, mpi_comm, &status);
628 
629  std::vector<DynamicSparsityPattern::size_type>::const_iterator ptr = recv_buf.begin();
630  std::vector<DynamicSparsityPattern::size_type>::const_iterator end = recv_buf.end();
631  while (ptr!=end)
632  {
633  DynamicSparsityPattern::size_type num=*(ptr++);
634  Assert(ptr!=end, ExcInternalError());
635  DynamicSparsityPattern::size_type row=*(ptr++);
636  for (unsigned int c=0; c<num; ++c)
637  {
638  Assert(ptr!=end, ExcInternalError());
639  dsp.add(row, *ptr);
640  ptr++;
641  }
642  }
643  Assert(ptr==end, ExcInternalError());
644  }
645  }
646 
647  // complete all sends, so that we can safely destroy the buffers.
648  if (requests.size())
649  MPI_Waitall(requests.size(), &requests[0], MPI_STATUSES_IGNORE);
650 
651  }
652 
654  const std::vector<IndexSet> &owned_set_per_cpu,
655  const MPI_Comm &mpi_comm,
656  const IndexSet &myrange)
657  {
658  const unsigned int myid = Utilities::MPI::this_mpi_process(mpi_comm);
659 
661  std::vector<BlockDynamicSparsityPattern::size_type> >
662  map_vec_t;
663  map_vec_t send_data;
664 
665  {
666  unsigned int dest_cpu=0;
667 
668  BlockDynamicSparsityPattern::size_type n_local_rel_rows = myrange.n_elements();
669  for (BlockDynamicSparsityPattern::size_type row_idx=0; row_idx<n_local_rel_rows; ++row_idx)
670  {
671  BlockDynamicSparsityPattern::size_type row=myrange.nth_index_in_set(row_idx);
672 
673  // calculate destination CPU, note that we start the search
674  // at last destination cpu, because even if the owned ranges
675  // are not contiguous, they hopefully consist of large blocks
676  while (!owned_set_per_cpu[dest_cpu].is_element(row))
677  {
678  ++dest_cpu;
679  if (dest_cpu==owned_set_per_cpu.size()) // wrap around
680  dest_cpu=0;
681  }
682 
683  //skip myself
684  if (dest_cpu==myid)
685  continue;
686 
687  BlockDynamicSparsityPattern::size_type rlen = dsp.row_length(row);
688 
689  //skip empty lines
690  if (!rlen)
691  continue;
692 
693  //save entries
694  std::vector<BlockDynamicSparsityPattern::size_type> &dst = send_data[dest_cpu];
695 
696  dst.push_back(rlen); // number of entries
697  dst.push_back(row); // row index
698  for (BlockDynamicSparsityPattern::size_type c=0; c<rlen; ++c)
699  {
700  //columns
701  BlockDynamicSparsityPattern::size_type column = dsp.column_number(row, c);
702  dst.push_back(column);
703  }
704  }
705 
706  }
707 
708  unsigned int num_receive=0;
709  {
710  std::vector<unsigned int> send_to;
711  send_to.reserve(send_data.size());
712  for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it)
713  send_to.push_back(it->first);
714 
715  num_receive =
717  compute_point_to_point_communication_pattern(mpi_comm, send_to).size();
718  }
719 
720  std::vector<MPI_Request> requests(send_data.size());
721 
722 
723  // send data
724  {
725  unsigned int idx=0;
726  for (map_vec_t::iterator it=send_data.begin(); it!=send_data.end(); ++it, ++idx)
727  MPI_Isend(&(it->second[0]),
728  it->second.size(),
729  DEAL_II_DOF_INDEX_MPI_TYPE,
730  it->first,
731  124,
732  mpi_comm,
733  &requests[idx]);
734  }
735 
736  {
737  //receive
738  std::vector<BlockDynamicSparsityPattern::size_type> recv_buf;
739  for (unsigned int index=0; index<num_receive; ++index)
740  {
741  MPI_Status status;
742  int len;
743  MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, mpi_comm, &status);
744  Assert (status.MPI_TAG==124, ExcInternalError());
745 
746  MPI_Get_count(&status, DEAL_II_DOF_INDEX_MPI_TYPE, &len);
747  recv_buf.resize(len);
748  MPI_Recv(&recv_buf[0], len, DEAL_II_DOF_INDEX_MPI_TYPE, status.MPI_SOURCE,
749  status.MPI_TAG, mpi_comm, &status);
750 
751  std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator ptr = recv_buf.begin();
752  std::vector<BlockDynamicSparsityPattern::size_type>::const_iterator end = recv_buf.end();
753  while (ptr!=end)
754  {
755  BlockDynamicSparsityPattern::size_type num=*(ptr++);
756  Assert(ptr!=end, ExcInternalError());
757  BlockDynamicSparsityPattern::size_type row=*(ptr++);
758  for (unsigned int c=0; c<num; ++c)
759  {
760  Assert(ptr!=end, ExcInternalError());
761  dsp.add(row, *ptr);
762  ptr++;
763  }
764  }
765  Assert(ptr==end, ExcInternalError());
766  }
767  }
768 
769  // complete all sends, so that we can safely destroy the buffers.
770  if (requests.size())
771  MPI_Waitall(requests.size(), &requests[0], MPI_STATUSES_IGNORE);
772  }
773 #endif
774 }
775 
776 DEAL_II_NAMESPACE_CLOSE
const types::global_dof_index invalid_size_type
Definition: types.h:173
size_type column_number(const size_type row, const unsigned int index) const
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1052
size_type nth_index_in_set(const unsigned int local_index) const
Definition: index_set.h:1432
size_type column_number(const size_type row, const size_type index) const
void add(const size_type i, const size_type j)
::ExceptionBase & ExcMessage(std::string arg1)
void reorder_Cuthill_McKee(const DynamicSparsityPattern &sparsity, std::vector< DynamicSparsityPattern::size_type > &new_indices, const std::vector< DynamicSparsityPattern::size_type > &starting_indices=std::vector< DynamicSparsityPattern::size_type >())
iterator end() const
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
size_type n_cols() const
bool is_compressed() const
types::global_dof_index size_type
size_type size() const
Definition: index_set.h:1247
size_type n_rows() const
void partition(const SparsityPattern &sparsity_pattern, const unsigned int n_partitions, std::vector< unsigned int > &partition_indices)
void add(const size_type i, const size_type j)
void distribute_sparsity_pattern(DynamicSparsityPattern &dsp, const std::vector< DynamicSparsityPattern::size_type > &rows_per_cpu, const MPI_Comm &mpi_comm, const IndexSet &myrange)
unsigned int global_dof_index
Definition: types.h:88
#define Assert(cond, exc)
Definition: exceptions.h:294
const IndexSet & row_index_set() const
std::vector< unsigned int > invert_permutation(const std::vector< unsigned int > &permutation)
Definition: utilities.cc:483
size_type n_nonzero_elements() const
void reorder_hierarchical(const DynamicSparsityPattern &sparsity, std::vector< DynamicSparsityPattern::size_type > &new_indices)
types::global_dof_index size_type
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)
Definition: mpi.cc:108
iterator begin() const
const types::global_dof_index invalid_dof_index
Definition: types.h:178
std::vector< unsigned int > compute_point_to_point_communication_pattern(const MPI_Comm &mpi_comm, const std::vector< unsigned int > &destinations)
Definition: mpi.cc:126
size_type n_elements() const
Definition: index_set.h:1380