Reference documentation for deal.II version 8.4.2
partitioner.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2015 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 #include <deal.II/base/partitioner.h>
17 
18 DEAL_II_NAMESPACE_OPEN
19 
20 namespace Utilities
21 {
22  namespace MPI
23  {
25  :
26  global_size (0),
27  local_range_data (std::pair<types::global_dof_index, types::global_dof_index> (0, 0)),
28  n_ghost_indices_data (0),
29  n_import_indices_data (0),
30  my_pid (0),
31  n_procs (1),
32  communicator (MPI_COMM_SELF),
33  have_ghost_indices (false)
34  {}
35 
36 
37 
38 
39  Partitioner::Partitioner (const unsigned int size)
40  :
41  global_size (size),
43  local_range_data (std::pair<types::global_dof_index, types::global_dof_index> (0, size)),
46  my_pid (0),
47  n_procs (1),
48  communicator (MPI_COMM_SELF),
49  have_ghost_indices (false)
50  {
54  }
55 
56 
57 
58  Partitioner::Partitioner (const IndexSet &locally_owned_indices,
59  const IndexSet &ghost_indices_in,
60  const MPI_Comm communicator_in)
61  :
62  global_size (static_cast<types::global_dof_index>(locally_owned_indices.size())),
65  my_pid (0),
66  n_procs (1),
67  communicator (communicator_in),
68  have_ghost_indices (false)
69  {
70  set_owned_indices (locally_owned_indices);
71  set_ghost_indices (ghost_indices_in);
72  }
73 
74 
75 
76  Partitioner::Partitioner (const IndexSet &locally_owned_indices,
77  const MPI_Comm communicator_in)
78  :
79  global_size (static_cast<types::global_dof_index>(locally_owned_indices.size())),
82  my_pid (0),
83  n_procs (1),
84  communicator (communicator_in),
85  have_ghost_indices (false)
86  {
87  set_owned_indices (locally_owned_indices);
88  }
89 
90 
91 
92  void
93  Partitioner::set_owned_indices (const IndexSet &locally_owned_indices)
94  {
96  {
99  }
100  else
101  {
102  my_pid = 0;
103  n_procs = 1;
104  }
105 
106  // set the local range
107  Assert (locally_owned_indices.is_contiguous() == true,
108  ExcMessage ("The index set specified in locally_owned_indices "
109  "is not contiguous."));
110  locally_owned_indices.compress();
111  if (locally_owned_indices.n_elements()>0)
112  local_range_data = std::pair<types::global_dof_index, types::global_dof_index>
113  (locally_owned_indices.nth_index_in_set(0),
114  locally_owned_indices.nth_index_in_set(0) +
115  locally_owned_indices.n_elements());
117  static_cast<types::global_dof_index>(std::numeric_limits<unsigned int>::max()),
118  ExcMessage("Index overflow: This class supports at most 2^32-1 locally owned vector entries"));
119  locally_owned_range_data.set_size (locally_owned_indices.size());
122 
123  ghost_indices_data.set_size (locally_owned_indices.size());
124  }
125 
126 
127 
128  void
129  Partitioner::set_ghost_indices (const IndexSet &ghost_indices_in)
130  {
131  // Set ghost indices from input. To be sure that no entries from the
132  // locally owned range are present, subtract the locally owned indices
133  // in any case.
134  Assert (ghost_indices_in.n_elements() == 0 ||
135  ghost_indices_in.size() == locally_owned_range_data.size(),
136  ExcDimensionMismatch (ghost_indices_in.size(),
138 
139  ghost_indices_data = ghost_indices_in;
145  static_cast<types::global_dof_index>(std::numeric_limits<unsigned int>::max()),
146  ExcMessage("Index overflow: This class supports at most 2^32-1 ghost elements"));
148 
150  Utilities::MPI::sum(n_ghost_indices_data, communicator) > 0;
151 
152  // In the rest of this function, we determine the point-to-point
153  // communication pattern of the partitioner. We make up a list with both
154  // the processors the ghost indices actually belong to, and the indices
155  // that are locally held but ghost indices of other processors. This
156  // allows then to import and export data very easily.
157 
158  // find out the end index for each processor and communicate it (this
159  // implies the start index for the next processor)
160 #ifdef DEAL_II_WITH_MPI
161  if (n_procs < 2)
162  {
163  Assert (ghost_indices_data.n_elements() == 0, ExcInternalError());
164  Assert (n_import_indices_data == 0, ExcInternalError());
165  Assert (n_ghost_indices_data == 0, ExcInternalError());
166  return;
167  }
168 
169  std::vector<types::global_dof_index> first_index (n_procs+1);
170  // Allow non-zero start index for the vector. send this data to all
171  // processors
172  first_index[0] = local_range_data.first;
173  MPI_Bcast(&first_index[0], 1, DEAL_II_DOF_INDEX_MPI_TYPE,
174  0, communicator);
175 
176  // Get the end-of-local_range for all processors
177  MPI_Allgather(&local_range_data.second, 1,
178  DEAL_II_DOF_INDEX_MPI_TYPE, &first_index[1], 1,
179  DEAL_II_DOF_INDEX_MPI_TYPE, communicator);
180  first_index[n_procs] = global_size;
181 
182  // fix case when there are some processors without any locally owned
183  // indices: then there might be a zero in some entries
184  if (global_size > 0)
185  {
186  unsigned int first_proc_with_nonzero_dofs = 0;
187  for (unsigned int i=0; i<n_procs; ++i)
188  if (first_index[i+1]>0)
189  {
190  first_proc_with_nonzero_dofs = i;
191  break;
192  }
193  for (unsigned int i=first_proc_with_nonzero_dofs+1; i<n_procs; ++i)
194  if (first_index[i] == 0)
195  first_index[i] = first_index[i-1];
196 
197  // correct if our processor has a wrong local range
198  if (first_index[my_pid] != local_range_data.first)
199  {
200  Assert(local_range_data.first == local_range_data.second,
201  ExcInternalError());
202  local_range_data.first = local_range_data.second = first_index[my_pid];
203  }
204  }
205 
206  // Allocate memory for data that will be exported
207  std::vector<types::global_dof_index> expanded_ghost_indices (n_ghost_indices_data);
208  unsigned int n_ghost_targets = 0;
209  if (n_ghost_indices_data > 0)
210  {
211  // Create first a vector of ghost_targets from the list of ghost
212  // indices and then push back new values. When we are done, copy the
213  // data to that field of the partitioner. This way, the variable
214  // ghost_targets will have exactly the size we need, whereas the
215  // vector filled with push_back might actually be too long.
216  unsigned int current_proc = 0;
217  ghost_indices_data.fill_index_vector (expanded_ghost_indices);
218  types::global_dof_index current_index = expanded_ghost_indices[0];
219  while (current_index >= first_index[current_proc+1])
220  current_proc++;
221  std::vector<std::pair<unsigned int, unsigned int> > ghost_targets_temp
222  (1, std::pair<unsigned int, unsigned int>(current_proc, 0));
223  n_ghost_targets++;
224 
225  for (unsigned int iterator=1; iterator<n_ghost_indices_data; ++iterator)
226  {
227  current_index = expanded_ghost_indices[iterator];
228  while (current_index >= first_index[current_proc+1])
229  current_proc++;
230  AssertIndexRange (current_proc, n_procs);
231  if ( ghost_targets_temp[n_ghost_targets-1].first < current_proc)
232  {
233  ghost_targets_temp[n_ghost_targets-1].second =
234  iterator - ghost_targets_temp[n_ghost_targets-1].second;
235  ghost_targets_temp.push_back(std::pair<unsigned int,
236  unsigned int>(current_proc,iterator));
237  n_ghost_targets++;
238  }
239  }
240  ghost_targets_temp[n_ghost_targets-1].second =
241  n_ghost_indices_data - ghost_targets_temp[n_ghost_targets-1].second;
242  ghost_targets_data = ghost_targets_temp;
243  }
244  // find the processes that want to import to me
245  {
246  std::vector<int> send_buffer (n_procs, 0);
247  std::vector<int> receive_buffer (n_procs, 0);
248  for (unsigned int i=0; i<n_ghost_targets; i++)
249  send_buffer[ghost_targets_data[i].first] = ghost_targets_data[i].second;
250 
251  MPI_Alltoall (&send_buffer[0], 1, MPI_INT, &receive_buffer[0], 1,
252  MPI_INT, communicator);
253 
254  // allocate memory for import data
255  std::vector<std::pair<unsigned int,unsigned int> > import_targets_temp;
257  for (unsigned int i=0; i<n_procs; i++)
258  if (receive_buffer[i] > 0)
259  {
260  n_import_indices_data += receive_buffer[i];
261  import_targets_temp.push_back(std::pair<unsigned int,
262  unsigned int> (i, receive_buffer[i]));
263  }
264  import_targets_data = import_targets_temp;
265  }
266 
267  // send and receive indices for import data. non-blocking receives and
268  // blocking sends
269  std::vector<types::global_dof_index> expanded_import_indices (n_import_indices_data);
270  {
271  unsigned int current_index_start = 0;
272  std::vector<MPI_Request> import_requests (import_targets_data.size());
273  for (unsigned int i=0; i<import_targets_data.size(); i++)
274  {
275  MPI_Irecv (&expanded_import_indices[current_index_start],
276  import_targets_data[i].second,
277  DEAL_II_DOF_INDEX_MPI_TYPE,
278  import_targets_data[i].first, import_targets_data[i].first,
279  communicator, &import_requests[i]);
280  current_index_start += import_targets_data[i].second;
281  }
282  AssertDimension (current_index_start, n_import_indices_data);
283 
284  // use blocking send
285  current_index_start = 0;
286  for (unsigned int i=0; i<n_ghost_targets; i++)
287  {
288  MPI_Send (&expanded_ghost_indices[current_index_start],
289  ghost_targets_data[i].second, DEAL_II_DOF_INDEX_MPI_TYPE,
290  ghost_targets_data[i].first, my_pid,
291  communicator);
292  current_index_start += ghost_targets_data[i].second;
293  }
294  AssertDimension (current_index_start, n_ghost_indices_data);
295 
296  if (import_requests.size()>0)
297  MPI_Waitall (import_requests.size(), &import_requests[0],
298  MPI_STATUSES_IGNORE);
299 
300  // transform import indices to local index space and compress
301  // contiguous indices in form of ranges
302  {
304  std::vector<std::pair<unsigned int,unsigned int> > compressed_import_indices;
305  for (unsigned int i=0; i<n_import_indices_data; i++)
306  {
307  Assert (expanded_import_indices[i] >= local_range_data.first &&
308  expanded_import_indices[i] < local_range_data.second,
309  ExcIndexRange(expanded_import_indices[i], local_range_data.first,
310  local_range_data.second));
311  types::global_dof_index new_index = (expanded_import_indices[i] -
312  local_range_data.first);
314  ExcNotImplemented());
315  if (new_index == last_index+1)
316  compressed_import_indices.back().second++;
317  else
318  {
319  compressed_import_indices.push_back
320  (std::pair<unsigned int,unsigned int>(new_index,new_index+1));
321  }
322  last_index = new_index;
323  }
324  import_indices_data = compressed_import_indices;
325 
326  // sanity check
327 #ifdef DEBUG
328  const types::global_dof_index n_local_dofs = local_range_data.second-local_range_data.first;
329  for (unsigned int i=0; i<import_indices_data.size(); ++i)
330  {
331  AssertIndexRange (import_indices_data[i].first, n_local_dofs);
332  AssertIndexRange (import_indices_data[i].second-1, n_local_dofs);
333  }
334 #endif
335  }
336  }
337 #endif
338  }
339 
340 
341 
342  bool
344  {
345  // if the partitioner points to the same memory location as the calling
346  // processor
347  if (&part == this)
348  return true;
349 #ifdef DEAL_II_WITH_MPI
351  {
352  int communicators_same = 0;
353  MPI_Comm_compare (part.communicator, communicator,
354  &communicators_same);
355  if (!(communicators_same == MPI_IDENT ||
356  communicators_same == MPI_CONGRUENT))
357  return false;
358  }
359 #endif
360  return (global_size == part.global_size &&
363  }
364 
365 
366 
367  bool
369  {
370  return Utilities::MPI::min(static_cast<int>(is_compatible(part)),
371  communicator) == 1;
372  }
373 
374 
375 
376  std::size_t
378  {
379  std::size_t memory = (3*sizeof(types::global_dof_index)+4*sizeof(unsigned int)+
380  sizeof(MPI_Comm));
386  return memory;
387  }
388 
389  } // end of namespace MPI
390 
391 } // end of namespace Utilities
392 
393 
394 DEAL_II_NAMESPACE_CLOSE
std::vector< std::pair< unsigned int, unsigned int > > import_indices_data
Definition: partitioner.h:317
bool is_globally_compatible(const Partitioner &part) const
Definition: partitioner.cc:368
static const unsigned int invalid_unsigned_int
Definition: types.h:164
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1052
bool is_compatible(const Partitioner &part) const
Definition: partitioner.cc:343
size_type nth_index_in_set(const unsigned int local_index) const
Definition: index_set.h:1432
::ExceptionBase & ExcMessage(std::string arg1)
#define AssertIndexRange(index, range)
Definition: exceptions.h:1081
unsigned int n_ghost_indices_data
Definition: partitioner.h:303
STL namespace.
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
bool job_supports_mpi() DEAL_II_DEPRECATED
Definition: utilities.cc:705
void set_owned_indices(const IndexSet &locally_owned_indices)
Definition: partitioner.cc:93
size_type size() const
Definition: index_set.h:1247
Definition: types.h:30
T sum(const T &t, const MPI_Comm &mpi_communicator)
Definition: mpi.h:611
unsigned int global_dof_index
Definition: types.h:88
void subtract_set(const IndexSet &other)
Definition: index_set.cc:269
const MPI_Comm communicator
Definition: partitioner.h:344
#define Assert(cond, exc)
Definition: exceptions.h:294
const types::global_dof_index global_size
Definition: partitioner.h:280
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:99
void fill_index_vector(std::vector< size_type > &indices) const
Definition: index_set.cc:461
void add_range(const size_type begin, const size_type end)
Definition: index_set.cc:86
void set_size(const size_type size)
Definition: index_set.h:1234
std_cxx11::enable_if< std_cxx11::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
Definition: mpi.h:55
types::global_dof_index size() const
void compress() const
Definition: index_set.h:1256
std::size_t memory_consumption() const
Definition: partitioner.cc:377
bool is_contiguous() const
Definition: index_set.h:1370
T min(const T &t, const MPI_Comm &mpi_communicator)
Definition: mpi.h:722
std::vector< std::pair< unsigned int, unsigned int > > import_targets_data
Definition: partitioner.h:329
std::vector< std::pair< unsigned int, unsigned int > > ghost_targets_data
Definition: partitioner.h:309
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:108
std::pair< types::global_dof_index, types::global_dof_index > local_range_data
Definition: partitioner.h:291
const types::global_dof_index invalid_dof_index
Definition: types.h:178
bool job_supports_mpi()
Definition: mpi.h:750
unsigned int n_import_indices_data
Definition: partitioner.h:323
size_type n_elements() const
Definition: index_set.h:1380
void set_ghost_indices(const IndexSet &ghost_indices)
Definition: partitioner.cc:129